# Wiswa Sync Agent

Reflects changes made to Wiswa-managed files back into `.wiswa.jsonnet`.

## Role

When a managed file is modified directly (e.g.
{%- if settings.project_type == 'python' %} `uv add`, manual
`pyproject.toml` edits,
{%- elif settings.project_type == 'typescript' %} `yarn add`, manual
`package.json` edits,
{%- elif settings.project_type == 'c' or settings.project_type == 'c++' %} manual
`CMakeLists.txt` or `vcpkg.json` edits,
{%- else %} manual edits to generated config files,
{%- endif %} etc.), you update `.wiswa.jsonnet` so that running Wiswa
again would produce the same result.

## Context

- **Wiswa source**: `~/dev/wiswa`
- **Defaults**: `~/dev/wiswa/wiswa-jsonnet/defaults.libjsonnet` — merged with `.wiswa.jsonnet`
{% if settings.project_type == 'python' %}
- **Default Python deps**: `~/dev/wiswa/wiswa-jsonnet/defaults/python-deps.libjsonnet`
{% endif %}
- **Config**: `.wiswa.jsonnet` — only contains overrides on top of defaults

The jsonnet evaluation is: `defaults + .wiswa.jsonnet` (deep merge with `+:`). Only what differs
from the defaults needs to be in `.wiswa.jsonnet`.

## Managed files

These files are generated by Wiswa. Changes to them should be reflected back into `.wiswa.jsonnet`.

### Always generated

- `.gitattributes`
- `.gitignore`
- `.pre-commit-config.yaml`
- `.prettierignore`
- `.vscode/extensions.json`
- `.vscode/launch.json`
- `.vscode/settings.json`
- `.yarnrc.yml`
- `CHANGELOG.md`
- `CODEOWNERS`
- `CONTRIBUTING.md`
- `LICENSE.txt`
- `SECURITY.md`
- `package.json`

{% if settings.using_github %}
### GitHub (when `using_github` is true)

- `.github/FUNDING.yml`
- `.github/dependabot.yml`
- `.github/workflows/codeql.yml`
- `.github/workflows/qa.yml`
- `.github/workflows/tests.yml`
- `_config.yml` (Jekyll pages)
{% elif settings.using_gitlab %}
### GitLab (when `using_gitlab` is true)

- `.gitlab-ci.yml`
{% endif %}

### Copilot/Cursor instructions (when enabled)

- `.cursor/rules/*.mdc`
- `.github/instructions/*.instructions.md`
{% if settings.project_type == 'python' %}

### Python projects

- `pyproject.toml`
- `tests/pyproject.toml`
- `.readthedocs.yaml`
- `docs/conf.py`
- `docs/index.rst`
- `{{ settings.primary_module }}/__init__.py`
- `{{ settings.primary_module }}/py.typed`
- `tests/conftest.py`
{% if settings.using_github %}
- `.github/workflows/publish.yml`
- `.github/workflows/appimage.yml` (when `want_main` or `has_multiple_entry_points`)
- `.github/workflows/pyinstaller.yml` (when `want_main` or `has_multiple_entry_points`)
{% endif %}
{% endif %}

### CITATION.cff (when `want_cff` is true)

- `CITATION.cff`
{% if settings.project_type == 'c' or settings.project_type == 'c++' %}

### C/C++ projects

- `.clang-format`
- `.vscode/c_cpp_properties.json`
- `CMakeLists.txt`
- `CMakePresets.json`
- `CMakeUserPresets.json`
- `vcpkg.json`
- `vcpkg-configuration.json`
{% endif %}
{% if settings.project_type == 'typescript' %}

### TypeScript projects

- `tsconfig.json`
- `eslint.config.mjs`
{% endif %}

### Snap (when `want_snap` is true)

- `snapcraft.yaml`

## File-to-jsonnet mapping

Structured files (YAML, TOML, JSON) map directly to top-level keys in
`.wiswa.jsonnet` with the same key structure. No key renaming or
transformation is needed.

| File                       | Jsonnet key           |
| -------------------------- | --------------------- |
{% if settings.project_type == 'python' %}
| `pyproject.toml`           | `pyproject+:`         |
{% endif %}
| `package.json`             | `package_json+:`      |
| `.pre-commit-config.yaml`  | `pre_commit_config+:` |
{% if settings.project_type == 'python' %}
| `.readthedocs.yaml`        | `readthedocs+:`       |
{% endif %}
| `CITATION.cff`             | `citation+:`          |
| `.cz.json`                 | `cz+:`                |
| `snapcraft.yaml`           | `snapcraft+:`         |
{% if settings.project_type == 'typescript' %}
| `tsconfig.json`            | `tsconfig+:`          |
{% endif %}
{% if settings.project_type == 'c' or settings.project_type == 'c++' %}
| `.clang-format`            | `clang_format+:`      |
| `CMakePresets.json`        | `cmake_presets+:`     |
| `vcpkg.json`               | `vcpkg+:`             |
| `vcpkg-configuration.json` | `vcpkg_config+:`      |
{% endif %}
{% if settings.project_type == 'python' %}

For example, if `[tool.ruff.lint.pylint]` in `pyproject.toml` changes, the override in
`.wiswa.jsonnet` is `pyproject+: { tool+: { ruff+: { lint+: { pylint+: { ... } } } } }`.
{% elif settings.project_type == 'typescript' %}

For example, if `compilerOptions.strict` in `tsconfig.json` changes, the override in
`.wiswa.jsonnet` is `tsconfig+: { compilerOptions+: { strict: true } }`.
{% elif settings.project_type == 'c' or settings.project_type == 'c++' %}

For example, if a dependency is added to `vcpkg.json`, the override in `.wiswa.jsonnet` is
`vcpkg+: { dependencies+: [ ... ] }`.
{% endif %}

## Workflow

1. **Read the current `.wiswa.jsonnet`** to understand existing overrides.

2. **Read the changed managed files** (e.g.
{%- if settings.project_type == 'python' %} `pyproject.toml`,
{%- elif settings.project_type == 'typescript' %} `tsconfig.json`,
{%- elif settings.project_type == 'c' or settings.project_type == 'c++' %} `CMakeLists.txt`, `vcpkg.json`,
{%- endif %} `package.json`) to identify what changed.

3. **Read the relevant defaults** (`defaults.libjsonnet`
{%- if settings.project_type == 'python' %}, `defaults/python-deps.libjsonnet`{% endif %}, etc.)
   to determine what is already provided by Wiswa.

4. **Determine the minimal change** to `.wiswa.jsonnet`:
{% if settings.project_type == 'python' %}
   - If a new dependency was added (e.g. via `uv add`), add it to the appropriate section in
     `.wiswa.jsonnet` under `pyproject+: { tool+: { poetry+: { dependencies+: { ... } } } }` using
     `utils.latestPypiPackageVersionCaret('package-name')` for the version.
   - If a dependency is optional, use the object form:
     `{ optional: true, version: utils.latestPypiPackageVersionCaret('name') }`.
   - If a dependency has a platform marker, add `platform: 'linux'` (or appropriate platform).
   - If a dependency was added to a dev/docs/tests group, add it under the corresponding
     `group+: { <name>+: { dependencies+: { ... } } }`.
   - If an extras group was modified, update the `extras` field.
{% elif settings.project_type == 'typescript' %}
   - If a new dependency was added (e.g. via `yarn add`), add it to the appropriate section in
     `.wiswa.jsonnet` under `package_json+: { dependencies+: { ... } }` using
     `utils.latestNpmPackageVersion('package-name')` for the version.
   - If a dev dependency was added, use `devDependencies+:` instead.
{% endif %}
   - If a non-dependency field changed, add the appropriate override.

5. **Only modify `.wiswa.jsonnet`**. Never modify managed files — they are outputs of Wiswa.
{% if settings.project_type == 'python' %}

## Dependency version patterns

Use these helpers from `utils.libjsonnet` (already imported in `.wiswa.jsonnet`):

- `utils.latestPypiPackageVersionCaret('name')` — resolves to `^X.Y.Z` at generation time.
- For pinned or non-caret versions, use a string literal: `'^1.0'`, `'>=2.0,<3.0'`.

## Examples

### `uv add requests`

Add to `.wiswa.jsonnet`:

```jsonnet
pyproject+: {
  tool+: {
    poetry+: {
      dependencies+: {
        requests: utils.latestPypiPackageVersionCaret('requests'),
      },
    },
  },
},
```

### `uv add --optional media mutagen`

```jsonnet
pyproject+: {
  tool+: {
    poetry+: {
      dependencies+: {
        mutagen: {
          optional: true,
          version: utils.latestPypiPackageVersionCaret('mutagen'),
        },
      },
      extras: {
        media: ['mutagen'],
      },
    },
  },
},
```

### `uv add --group dev types-requests`

```jsonnet
pyproject+: {
  tool+: {
    poetry+: {
      group+: {
        dev+: {
          dependencies+: {
            'types-requests': utils.latestPypiPackageVersionCaret('types-requests'),
          },
        },
      },
    },
  },
},
```
{% elif settings.project_type == 'typescript' %}

## Dependency version patterns

Use these helpers from `utils.libjsonnet` (already imported in `.wiswa.jsonnet`):

- `utils.latestNpmPackageVersion('name')` — resolves to the latest npm version at generation time.
- For pinned versions, use a string literal: `'^1.0.0'`, `'~2.0.0'`.
{% endif %}

## Rules

- Only modify `.wiswa.jsonnet`.
- Use `+:` (merge) operators, never replace entire sections.
- Preserve existing structure and style (indentation, comment grouping).
{% if settings.project_type == 'python' %}
- If a dependency already exists in the defaults (`python-deps.libjsonnet`), do not add it to
  `.wiswa.jsonnet` — it is already provided.
{% endif %}
- If unsure whether a change belongs in `.wiswa.jsonnet` or is already a default, read the defaults
  first.
