@wjarka/cezarion 0.10.0-pr30.54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +838 -0
- package/dist/agent-config/account-identity.d.ts +44 -0
- package/dist/agent-config/account-identity.js +128 -0
- package/dist/agent-config/account-identity.js.map +1 -0
- package/dist/agent-config/catalog.d.ts +72 -0
- package/dist/agent-config/catalog.js +223 -0
- package/dist/agent-config/catalog.js.map +1 -0
- package/dist/agent-config/files.d.ts +46 -0
- package/dist/agent-config/files.js +119 -0
- package/dist/agent-config/files.js.map +1 -0
- package/dist/agent-config/model-settings/claude.d.ts +2 -0
- package/dist/agent-config/model-settings/claude.js +11 -0
- package/dist/agent-config/model-settings/claude.js.map +1 -0
- package/dist/agent-config/model-settings/codex.d.ts +2 -0
- package/dist/agent-config/model-settings/codex.js +16 -0
- package/dist/agent-config/model-settings/codex.js.map +1 -0
- package/dist/agent-config/model-settings/opencode.d.ts +2 -0
- package/dist/agent-config/model-settings/opencode.js +8 -0
- package/dist/agent-config/model-settings/opencode.js.map +1 -0
- package/dist/agent-config/model-settings/pi.d.ts +12 -0
- package/dist/agent-config/model-settings/pi.js +18 -0
- package/dist/agent-config/model-settings/pi.js.map +1 -0
- package/dist/agent-config/model-settings/shared.d.ts +9 -0
- package/dist/agent-config/model-settings/shared.js +93 -0
- package/dist/agent-config/model-settings/shared.js.map +1 -0
- package/dist/agent-config/model-settings/types.d.ts +9 -0
- package/dist/agent-config/model-settings/types.js +2 -0
- package/dist/agent-config/model-settings/types.js.map +1 -0
- package/dist/agent-config/models.d.ts +9 -0
- package/dist/agent-config/models.js +32 -0
- package/dist/agent-config/models.js.map +1 -0
- package/dist/agent-config/seed.d.ts +7 -0
- package/dist/agent-config/seed.js +90 -0
- package/dist/agent-config/seed.js.map +1 -0
- package/dist/agent-config/service.d.ts +44 -0
- package/dist/agent-config/service.js +71 -0
- package/dist/agent-config/service.js.map +1 -0
- package/dist/agent-config/validate.d.ts +21 -0
- package/dist/agent-config/validate.js +76 -0
- package/dist/agent-config/validate.js.map +1 -0
- package/dist/automations/coordinator.d.ts +26 -0
- package/dist/automations/coordinator.js +66 -0
- package/dist/automations/coordinator.js.map +1 -0
- package/dist/automations/github-poller.d.ts +74 -0
- package/dist/automations/github-poller.js +234 -0
- package/dist/automations/github-poller.js.map +1 -0
- package/dist/automations/scheduler.d.ts +42 -0
- package/dist/automations/scheduler.js +192 -0
- package/dist/automations/scheduler.js.map +1 -0
- package/dist/automations/store.d.ts +65 -0
- package/dist/automations/store.js +298 -0
- package/dist/automations/store.js.map +1 -0
- package/dist/automations/task-template.d.ts +18 -0
- package/dist/automations/task-template.js +95 -0
- package/dist/automations/task-template.js.map +1 -0
- package/dist/automations/types.d.ts +255 -0
- package/dist/automations/types.js +159 -0
- package/dist/automations/types.js.map +1 -0
- package/dist/config.d.ts +77 -0
- package/dist/config.js +242 -0
- package/dist/config.js.map +1 -0
- package/dist/contract/agent-config.d.ts +153 -0
- package/dist/contract/agent-profiles.d.ts +347 -0
- package/dist/contract/automations.d.ts +935 -0
- package/dist/contract/events.d.ts +104 -0
- package/dist/contract/github.d.ts +556 -0
- package/dist/contract/health.d.ts +102 -0
- package/dist/contract/index.d.ts +16 -0
- package/dist/contract/index.js +1895 -0
- package/dist/contract/projects.d.ts +210 -0
- package/dist/contract/repo.d.ts +234 -0
- package/dist/contract/runs.d.ts +1473 -0
- package/dist/contract/skills.d.ts +232 -0
- package/dist/contract/workflows.d.ts +218 -0
- package/dist/contract/workspace.d.ts +579 -0
- package/dist/core/agent-env.d.ts +31 -0
- package/dist/core/agent-env.js +371 -0
- package/dist/core/agent-env.js.map +1 -0
- package/dist/core/agent-model-policy.d.ts +10 -0
- package/dist/core/agent-model-policy.js +36 -0
- package/dist/core/agent-model-policy.js.map +1 -0
- package/dist/core/agent-profiles.d.ts +62 -0
- package/dist/core/agent-profiles.js +90 -0
- package/dist/core/agent-profiles.js.map +1 -0
- package/dist/core/agent-runner.d.ts +211 -0
- package/dist/core/agent-runner.js +68 -0
- package/dist/core/agent-runner.js.map +1 -0
- package/dist/core/ask.d.ts +105 -0
- package/dist/core/ask.js +187 -0
- package/dist/core/ask.js.map +1 -0
- package/dist/core/backend-detect.d.ts +16 -0
- package/dist/core/backend-detect.js +155 -0
- package/dist/core/backend-detect.js.map +1 -0
- package/dist/core/claude-cli-runner.d.ts +59 -0
- package/dist/core/claude-cli-runner.js +483 -0
- package/dist/core/claude-cli-runner.js.map +1 -0
- package/dist/core/claude-ui-mapper.d.ts +80 -0
- package/dist/core/claude-ui-mapper.js +598 -0
- package/dist/core/claude-ui-mapper.js.map +1 -0
- package/dist/core/codex-app-server-runner.d.ts +41 -0
- package/dist/core/codex-app-server-runner.js +584 -0
- package/dist/core/codex-app-server-runner.js.map +1 -0
- package/dist/core/codex-app-server-transport.d.ts +35 -0
- package/dist/core/codex-app-server-transport.js +150 -0
- package/dist/core/codex-app-server-transport.js.map +1 -0
- package/dist/core/codex-model-catalog.d.ts +10 -0
- package/dist/core/codex-model-catalog.js +110 -0
- package/dist/core/codex-model-catalog.js.map +1 -0
- package/dist/core/codex-ui-mapper.d.ts +112 -0
- package/dist/core/codex-ui-mapper.js +766 -0
- package/dist/core/codex-ui-mapper.js.map +1 -0
- package/dist/core/model-identity.d.ts +125 -0
- package/dist/core/model-identity.js +132 -0
- package/dist/core/model-identity.js.map +1 -0
- package/dist/core/model-presets.d.ts +21 -0
- package/dist/core/model-presets.js +81 -0
- package/dist/core/model-presets.js.map +1 -0
- package/dist/core/ndjson.d.ts +6 -0
- package/dist/core/ndjson.js +23 -0
- package/dist/core/ndjson.js.map +1 -0
- package/dist/core/opencode-model-catalog.d.ts +32 -0
- package/dist/core/opencode-model-catalog.js +153 -0
- package/dist/core/opencode-model-catalog.js.map +1 -0
- package/dist/core/opencode-server-runner.d.ts +32 -0
- package/dist/core/opencode-server-runner.js +882 -0
- package/dist/core/opencode-server-runner.js.map +1 -0
- package/dist/core/opencode-ui-mapper.d.ts +137 -0
- package/dist/core/opencode-ui-mapper.js +800 -0
- package/dist/core/opencode-ui-mapper.js.map +1 -0
- package/dist/core/pi-model-catalog.d.ts +31 -0
- package/dist/core/pi-model-catalog.js +152 -0
- package/dist/core/pi-model-catalog.js.map +1 -0
- package/dist/core/pi-runner.d.ts +24 -0
- package/dist/core/pi-runner.js +403 -0
- package/dist/core/pi-runner.js.map +1 -0
- package/dist/core/pi-ui-mapper.d.ts +36 -0
- package/dist/core/pi-ui-mapper.js +304 -0
- package/dist/core/pi-ui-mapper.js.map +1 -0
- package/dist/core/process-usage.d.ts +66 -0
- package/dist/core/process-usage.js +193 -0
- package/dist/core/process-usage.js.map +1 -0
- package/dist/core/provider-auth.d.ts +154 -0
- package/dist/core/provider-auth.js +509 -0
- package/dist/core/provider-auth.js.map +1 -0
- package/dist/core/provider-availability.d.ts +3 -0
- package/dist/core/provider-availability.js +14 -0
- package/dist/core/provider-availability.js.map +1 -0
- package/dist/core/runner-factory.d.ts +8 -0
- package/dist/core/runner-factory.js +25 -0
- package/dist/core/runner-factory.js.map +1 -0
- package/dist/core/runner-model-catalog.d.ts +29 -0
- package/dist/core/runner-model-catalog.js +78 -0
- package/dist/core/runner-model-catalog.js.map +1 -0
- package/dist/core/secret-redaction.d.ts +37 -0
- package/dist/core/secret-redaction.js +115 -0
- package/dist/core/secret-redaction.js.map +1 -0
- package/dist/core/shell-env.d.ts +28 -0
- package/dist/core/shell-env.js +56 -0
- package/dist/core/shell-env.js.map +1 -0
- package/dist/core/tool-display.d.ts +31 -0
- package/dist/core/tool-display.js +179 -0
- package/dist/core/tool-display.js.map +1 -0
- package/dist/core/ui-events.d.ts +335 -0
- package/dist/core/ui-events.js +25 -0
- package/dist/core/ui-events.js.map +1 -0
- package/dist/core/usage-limit.d.ts +42 -0
- package/dist/core/usage-limit.js +209 -0
- package/dist/core/usage-limit.js.map +1 -0
- package/dist/core/usage.d.ts +11 -0
- package/dist/core/usage.js +15 -0
- package/dist/core/usage.js.map +1 -0
- package/dist/core/v1-text-coalescer.d.ts +36 -0
- package/dist/core/v1-text-coalescer.js +72 -0
- package/dist/core/v1-text-coalescer.js.map +1 -0
- package/dist/git-diff-base.d.ts +85 -0
- package/dist/git-diff-base.js +180 -0
- package/dist/git-diff-base.js.map +1 -0
- package/dist/git-refs.d.ts +11 -0
- package/dist/git-refs.js +14 -0
- package/dist/git-refs.js.map +1 -0
- package/dist/git-worktree.d.ts +161 -0
- package/dist/git-worktree.js +508 -0
- package/dist/git-worktree.js.map +1 -0
- package/dist/handoff.d.ts +62 -0
- package/dist/handoff.js +154 -0
- package/dist/handoff.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +680 -0
- package/dist/index.js.map +1 -0
- package/dist/install-as-command.d.ts +40 -0
- package/dist/install-as-command.js +52 -0
- package/dist/install-as-command.js.map +1 -0
- package/dist/pack-check.d.ts +17 -0
- package/dist/pack-check.js +27 -0
- package/dist/pack-check.js.map +1 -0
- package/dist/paths.d.ts +140 -0
- package/dist/paths.js +192 -0
- package/dist/paths.js.map +1 -0
- package/dist/planner.d.ts +27 -0
- package/dist/planner.js +268 -0
- package/dist/planner.js.map +1 -0
- package/dist/release/manifests.d.ts +81 -0
- package/dist/release/manifests.js +74 -0
- package/dist/release/manifests.js.map +1 -0
- package/dist/release/snapshot.d.ts +67 -0
- package/dist/release/snapshot.js +97 -0
- package/dist/release/snapshot.js.map +1 -0
- package/dist/release/stable.d.ts +38 -0
- package/dist/release/stable.js +55 -0
- package/dist/release/stable.js.map +1 -0
- package/dist/runs/agent-tmpdir.d.ts +41 -0
- package/dist/runs/agent-tmpdir.js +183 -0
- package/dist/runs/agent-tmpdir.js.map +1 -0
- package/dist/runs/auto-name.d.ts +75 -0
- package/dist/runs/auto-name.js +179 -0
- package/dist/runs/auto-name.js.map +1 -0
- package/dist/runs/event-history.d.ts +50 -0
- package/dist/runs/event-history.js +613 -0
- package/dist/runs/event-history.js.map +1 -0
- package/dist/runs/retention.d.ts +60 -0
- package/dist/runs/retention.js +86 -0
- package/dist/runs/retention.js.map +1 -0
- package/dist/runs/review-gate.d.ts +18 -0
- package/dist/runs/review-gate.js +21 -0
- package/dist/runs/review-gate.js.map +1 -0
- package/dist/runs/run-index.d.ts +19 -0
- package/dist/runs/run-index.js +43 -0
- package/dist/runs/run-index.js.map +1 -0
- package/dist/runs/store.d.ts +446 -0
- package/dist/runs/store.js +1118 -0
- package/dist/runs/store.js.map +1 -0
- package/dist/runs/task-markers.d.ts +28 -0
- package/dist/runs/task-markers.js +74 -0
- package/dist/runs/task-markers.js.map +1 -0
- package/dist/runs/task-refs.d.ts +25 -0
- package/dist/runs/task-refs.js +74 -0
- package/dist/runs/task-refs.js.map +1 -0
- package/dist/runs/ui-event-sink.d.ts +81 -0
- package/dist/runs/ui-event-sink.js +210 -0
- package/dist/runs/ui-event-sink.js.map +1 -0
- package/dist/server/app-type.d.ts +21 -0
- package/dist/server/app-type.js +2 -0
- package/dist/server/app-type.js.map +1 -0
- package/dist/server/capabilities.d.ts +70 -0
- package/dist/server/capabilities.js +152 -0
- package/dist/server/capabilities.js.map +1 -0
- package/dist/server/checkout.d.ts +128 -0
- package/dist/server/checkout.js +296 -0
- package/dist/server/checkout.js.map +1 -0
- package/dist/server/forge/github.d.ts +513 -0
- package/dist/server/forge/github.js +2364 -0
- package/dist/server/forge/github.js.map +1 -0
- package/dist/server/forge/index.d.ts +40 -0
- package/dist/server/forge/index.js +72 -0
- package/dist/server/forge/index.js.map +1 -0
- package/dist/server/forge/types.d.ts +242 -0
- package/dist/server/forge/types.js +2 -0
- package/dist/server/forge/types.js.map +1 -0
- package/dist/server/fs-browse.d.ts +105 -0
- package/dist/server/fs-browse.js +182 -0
- package/dist/server/fs-browse.js.map +1 -0
- package/dist/server/git-changes.d.ts +213 -0
- package/dist/server/git-changes.js +555 -0
- package/dist/server/git-changes.js.map +1 -0
- package/dist/server/git.d.ts +28 -0
- package/dist/server/git.js +112 -0
- package/dist/server/git.js.map +1 -0
- package/dist/server/github.d.ts +9 -0
- package/dist/server/github.js +8 -0
- package/dist/server/github.js.map +1 -0
- package/dist/server/launch-key.d.ts +7 -0
- package/dist/server/launch-key.js +33 -0
- package/dist/server/launch-key.js.map +1 -0
- package/dist/server/open-in-app.d.ts +66 -0
- package/dist/server/open-in-app.js +211 -0
- package/dist/server/open-in-app.js.map +1 -0
- package/dist/server/open-in-terminal.d.ts +70 -0
- package/dist/server/open-in-terminal.js +179 -0
- package/dist/server/open-in-terminal.js.map +1 -0
- package/dist/server/pr.d.ts +7 -0
- package/dist/server/pr.js +7 -0
- package/dist/server/pr.js.map +1 -0
- package/dist/server/project-context.d.ts +120 -0
- package/dist/server/project-context.js +182 -0
- package/dist/server/project-context.js.map +1 -0
- package/dist/server/provider-action-gate.d.ts +8 -0
- package/dist/server/provider-action-gate.js +56 -0
- package/dist/server/provider-action-gate.js.map +1 -0
- package/dist/server/provider-auth-runtime.d.ts +21 -0
- package/dist/server/provider-auth-runtime.js +66 -0
- package/dist/server/provider-auth-runtime.js.map +1 -0
- package/dist/server/server.d.ts +13138 -0
- package/dist/server/server.js +5263 -0
- package/dist/server/server.js.map +1 -0
- package/dist/server/static-ui.d.ts +49 -0
- package/dist/server/static-ui.js +92 -0
- package/dist/server/static-ui.js.map +1 -0
- package/dist/server/validators.d.ts +97 -0
- package/dist/server/validators.js +86 -0
- package/dist/server/validators.js.map +1 -0
- package/dist/server/ws.d.ts +85 -0
- package/dist/server/ws.js +218 -0
- package/dist/server/ws.js.map +1 -0
- package/dist/server/wsl.d.ts +25 -0
- package/dist/server/wsl.js +92 -0
- package/dist/server/wsl.js.map +1 -0
- package/dist/server-install/engine.d.ts +50 -0
- package/dist/server-install/engine.js +324 -0
- package/dist/server-install/engine.js.map +1 -0
- package/dist/server-install/platforms/macosx-ngrok.d.ts +6 -0
- package/dist/server-install/platforms/macosx-ngrok.js +345 -0
- package/dist/server-install/platforms/macosx-ngrok.js.map +1 -0
- package/dist/server-install/platforms/ubuntu-vps.d.ts +78 -0
- package/dist/server-install/platforms/ubuntu-vps.js +1016 -0
- package/dist/server-install/platforms/ubuntu-vps.js.map +1 -0
- package/dist/server-install/state.d.ts +52 -0
- package/dist/server-install/state.js +182 -0
- package/dist/server-install/state.js.map +1 -0
- package/dist/server-install/steps.d.ts +109 -0
- package/dist/server-install/steps.js +334 -0
- package/dist/server-install/steps.js.map +1 -0
- package/dist/server-install/strategies.d.ts +4 -0
- package/dist/server-install/strategies.js +20 -0
- package/dist/server-install/strategies.js.map +1 -0
- package/dist/server-install/types.d.ts +287 -0
- package/dist/server-install/types.js +121 -0
- package/dist/server-install/types.js.map +1 -0
- package/dist/server-install/ui.d.ts +42 -0
- package/dist/server-install/ui.js +130 -0
- package/dist/server-install/ui.js.map +1 -0
- package/dist/skills-banner.d.ts +22 -0
- package/dist/skills-banner.js +41 -0
- package/dist/skills-banner.js.map +1 -0
- package/dist/skills-remote.d.ts +84 -0
- package/dist/skills-remote.js +468 -0
- package/dist/skills-remote.js.map +1 -0
- package/dist/skills-update.d.ts +88 -0
- package/dist/skills-update.js +392 -0
- package/dist/skills-update.js.map +1 -0
- package/dist/skills.d.ts +82 -0
- package/dist/skills.js +251 -0
- package/dist/skills.js.map +1 -0
- package/dist/todos.d.ts +48 -0
- package/dist/todos.js +201 -0
- package/dist/todos.js.map +1 -0
- package/dist/ui-state.d.ts +26 -0
- package/dist/ui-state.js +38 -0
- package/dist/ui-state.js.map +1 -0
- package/dist/update-check.d.ts +12 -0
- package/dist/update-check.js +41 -0
- package/dist/update-check.js.map +1 -0
- package/dist/workflows/load.d.ts +15 -0
- package/dist/workflows/load.js +56 -0
- package/dist/workflows/load.js.map +1 -0
- package/dist/workflows/run.d.ts +758 -0
- package/dist/workflows/run.js +3389 -0
- package/dist/workflows/run.js.map +1 -0
- package/dist/workflows/types.d.ts +153 -0
- package/dist/workflows/types.js +212 -0
- package/dist/workflows/types.js.map +1 -0
- package/dist/workspace/agent-accounts.d.ts +153 -0
- package/dist/workspace/agent-accounts.js +304 -0
- package/dist/workspace/agent-accounts.js.map +1 -0
- package/dist/workspace/agent-profiles.d.ts +78 -0
- package/dist/workspace/agent-profiles.js +115 -0
- package/dist/workspace/agent-profiles.js.map +1 -0
- package/dist/workspace/config.d.ts +169 -0
- package/dist/workspace/config.js +379 -0
- package/dist/workspace/config.js.map +1 -0
- package/dist/workspace/migrations.d.ts +45 -0
- package/dist/workspace/migrations.js +147 -0
- package/dist/workspace/migrations.js.map +1 -0
- package/dist/workspace/projects-cli.d.ts +25 -0
- package/dist/workspace/projects-cli.js +172 -0
- package/dist/workspace/projects-cli.js.map +1 -0
- package/dist/workspace/projects.d.ts +109 -0
- package/dist/workspace/projects.js +250 -0
- package/dist/workspace/projects.js.map +1 -0
- package/dist/workspace/semaphore.d.ts +179 -0
- package/dist/workspace/semaphore.js +195 -0
- package/dist/workspace/semaphore.js.map +1 -0
- package/dist/workspace/ui-state.d.ts +34 -0
- package/dist/workspace/ui-state.js +53 -0
- package/dist/workspace/ui-state.js.map +1 -0
- package/package.json +70 -0
- package/scripts/check-pack.mjs +46 -0
- package/scripts/inline-contract.mjs +112 -0
- package/scripts/install-as-command.mjs +120 -0
- package/scripts/mock-claude.mjs +520 -0
- package/scripts/mock-pi-rpc.mjs +83 -0
- package/scripts/sync-readme.mjs +20 -0
- package/scripts/test-process-usage.mjs +47 -0
- package/web/dist/assets/alert-dialog-B4Ofsgv7.js +1 -0
- package/web/dist/assets/arrow-down-Dy8dup7j.js +1 -0
- package/web/dist/assets/arrow-left-BJaucbhn.js +1 -0
- package/web/dist/assets/bundle-mjs-BT31bpU6.js +1 -0
- package/web/dist/assets/centered-state-duPW0phQ.js +43 -0
- package/web/dist/assets/chevron-right-Be4A5TCS.js +1 -0
- package/web/dist/assets/chunk-BO2N2NFS-DE6qKn3r.js +131 -0
- package/web/dist/assets/collapsible-DdcNBdSk.js +1 -0
- package/web/dist/assets/commit-list-CgvN9vec.js +1 -0
- package/web/dist/assets/compare-variants-CQA2nd65.js +1 -0
- package/web/dist/assets/core-BCsw8oQw.js +12 -0
- package/web/dist/assets/css-BsVw1vtW.js +1 -0
- package/web/dist/assets/diff-B6Agp5Hl.js +3 -0
- package/web/dist/assets/diff-stat-BoXuGkgq.js +1 -0
- package/web/dist/assets/diff-view-CD8XI-fj.js +6 -0
- package/web/dist/assets/diff-woXpYk--.js +1 -0
- package/web/dist/assets/dropdown-menu-B3SYw-k5.js +1 -0
- package/web/dist/assets/editable-title-B-hjp5wl.js +1 -0
- package/web/dist/assets/ellipsis-vertical-BYwzw0xl.js +1 -0
- package/web/dist/assets/engine-javascript-FQvzRocB.js +141 -0
- package/web/dist/assets/file-BRj5eISx.js +1 -0
- package/web/dist/assets/folder-z4oT5981.js +1 -0
- package/web/dist/assets/git-toolbar-owSEkYld.js +1 -0
- package/web/dist/assets/github-Bz2VgRX3.js +1 -0
- package/web/dist/assets/go-rLFTqkRN.js +1 -0
- package/web/dist/assets/highlighted-body-OFNGDK62-BL-MfFgl.js +1 -0
- package/web/dist/assets/highlighter-CdHqIwFr.js +3 -0
- package/web/dist/assets/html-BY76lXLH.js +1 -0
- package/web/dist/assets/image-preview-h3WFluuy.js +1 -0
- package/web/dist/assets/index-BbcQNT92.css +2 -0
- package/web/dist/assets/index-EtQQQ6Kj.js +7 -0
- package/web/dist/assets/inter-latin-ext-wght-normal-DO1Apj_S.woff2 +0 -0
- package/web/dist/assets/inter-latin-wght-normal-Dx4kXJAl.woff2 +0 -0
- package/web/dist/assets/javascript-BgS3c2Ky.js +1 -0
- package/web/dist/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
- package/web/dist/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
- package/web/dist/assets/json-qhed-kSA.js +1 -0
- package/web/dist/assets/jsonc-CYpm1nAK.js +1 -0
- package/web/dist/assets/jsx-Bz0zcwM4.js +1 -0
- package/web/dist/assets/lib-BQXq3kEf.js +1 -0
- package/web/dist/assets/lib-BxQXEXDF.js +1 -0
- package/web/dist/assets/markdown-BYOwaDjH.js +1 -0
- package/web/dist/assets/markdown-DqBKYPiB.js +2 -0
- package/web/dist/assets/mermaid-GHXKKRXX-C4jxqUUb.js +1 -0
- package/web/dist/assets/new-task-form-BdJKRBJX.js +1 -0
- package/web/dist/assets/pill-BQfmfpYp.js +1 -0
- package/web/dist/assets/project-router-DxgFZY1l.js +1 -0
- package/web/dist/assets/prompt-templates-B6m16gq-.js +15 -0
- package/web/dist/assets/python-gzcpVVnB.js +1 -0
- package/web/dist/assets/react-runtime-CCIEwYL0.js +9 -0
- package/web/dist/assets/refresh-cw-mhSpxf2a.js +1 -0
- package/web/dist/assets/repo-git-CUNRxR3_.js +1 -0
- package/web/dist/assets/rolldown-runtime-QTnfLwEv.js +1 -0
- package/web/dist/assets/run-diff-DsmmDVfx.js +3 -0
- package/web/dist/assets/run-header-BkhrseLJ.js +1 -0
- package/web/dist/assets/rust-Cfkwpbl8.js +1 -0
- package/web/dist/assets/search-x-BqDMB2g8.js +1 -0
- package/web/dist/assets/shellscript-CLZ0U2zV.js +1 -0
- package/web/dist/assets/skill-empty-hint-BWEvTggc.js +1 -0
- package/web/dist/assets/skills-9oR_oHse.js +1 -0
- package/web/dist/assets/skills-DwIxnnWO.js +1 -0
- package/web/dist/assets/sparkles-DIoTQpyx.js +1 -0
- package/web/dist/assets/sql-BsFa4tDR.js +1 -0
- package/web/dist/assets/square-terminal-Cc7CuQxc.js +1 -0
- package/web/dist/assets/tab-link-D1fQgpmO.js +1 -0
- package/web/dist/assets/task-changes-BKeLlDpK.js +1 -0
- package/web/dist/assets/task-commits-gcEFZIa5.js +1 -0
- package/web/dist/assets/task-files-BGAqoXTW.js +2 -0
- package/web/dist/assets/task-thread-DT8aUYTS.js +9 -0
- package/web/dist/assets/textarea-BOVbfy5C.js +1 -0
- package/web/dist/assets/thread-loading-CypW73KD.js +1 -0
- package/web/dist/assets/toml-CcmNWLt0.js +1 -0
- package/web/dist/assets/trash-2-CJq6LHWn.js +1 -0
- package/web/dist/assets/triangle-alert-CjDFvU27.js +1 -0
- package/web/dist/assets/tsx-udAQXfEw.js +1 -0
- package/web/dist/assets/typescript-bsJCZSQ-.js +1 -0
- package/web/dist/assets/upload-CPDZlJeK.js +1 -0
- package/web/dist/assets/use-desktop-5JsLmi0a.js +1 -0
- package/web/dist/assets/use-submit-shortcut-CHVFevty.js +1 -0
- package/web/dist/assets/utils-DiO6zyJd.js +64 -0
- package/web/dist/assets/workflows-rQDFzWRt.js +11 -0
- package/web/dist/assets/yaml-rwi0_p6S.js +1 -0
- package/web/dist/assets/zoomable-image-COWqb11v.js +1 -0
- package/web/dist/index.html +80 -0
- package/web/dist/open-mercato.svg +11 -0
package/dist/skills.js
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { readdir, readFile, realpath, stat } from 'node:fs/promises';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join, resolve, basename, dirname, extname } from 'node:path';
|
|
4
|
+
import { gatedSkillsRepos } from './config.js';
|
|
5
|
+
import { getTeamSkillsCached } from './skills-remote.js';
|
|
6
|
+
import { readWorkspaceUiState } from './workspace/ui-state.js';
|
|
7
|
+
/* Precedence order — earlier dirs win name collisions. `npx skills` writes
|
|
8
|
+
the canonical copy to `.agents/skills/<name>/SKILL.md` and mirrors it into
|
|
9
|
+
each agent's dir (often as symlinks) — scanning them all and deduping by
|
|
10
|
+
name yields exactly the union of unique skills.
|
|
11
|
+
|
|
12
|
+
Exported for the drift guard in `test/unit/skill-dirs.test.ts` (#374): the
|
|
13
|
+
cockpit's empty-state hint hand-copies this list into the bundle
|
|
14
|
+
(`packages/web/src/components/skill-empty-hint.tsx`) because it runs in another
|
|
15
|
+
process, so adding a dir here without updating the hint makes the hint lie.
|
|
16
|
+
That test pins this list and says where to go. */
|
|
17
|
+
export const SKILL_DIRS = [
|
|
18
|
+
{ dir: '.ai/cezar/skills', source: 'cezar' },
|
|
19
|
+
{ dir: '.ai/skills', source: 'ai' },
|
|
20
|
+
{ dir: '.agents/skills', source: 'agents' },
|
|
21
|
+
{ dir: '.claude/skills', source: 'agents' },
|
|
22
|
+
{ dir: '.codex/skills', source: 'agents' },
|
|
23
|
+
{ dir: '.cursor/skills', source: 'agents' },
|
|
24
|
+
{ dir: '.opencode/skills', source: 'agents' },
|
|
25
|
+
];
|
|
26
|
+
/* Deliberately `homedir()` and not `agentHomePaths().claude`: these do NOT follow an
|
|
27
|
+
agent profile (`src/core/agent-profiles.ts`). A skill is CONTENT — a playbook — not
|
|
28
|
+
identity, and a second Claude login is not a second skill library. `npx skills`, which
|
|
29
|
+
writes the `~/.claude/skills` mirror, is profile-unaware for the same reason. */
|
|
30
|
+
const GLOBAL_SKILL_DIRS = [
|
|
31
|
+
{ dir: join(homedir(), '.agents/skills'), source: 'global' },
|
|
32
|
+
{ dir: join(homedir(), '.claude/skills'), source: 'global' },
|
|
33
|
+
];
|
|
34
|
+
/**
|
|
35
|
+
* Discover the merged skill catalog for a repo. Name collisions resolve
|
|
36
|
+
* local-first: `.ai/cezar/skills` → `.ai/skills` → `.agents/skills` + agent
|
|
37
|
+
* mirrors → global (`~/.agents/skills`, `~/.claude/skills`) → team repo
|
|
38
|
+
* ("the user's repo is the source of truth"). Missing directories are fine —
|
|
39
|
+
* an empty catalog is fully supported (steps fall back to their plain
|
|
40
|
+
* prompt). Team skills come from the in-process cache; the first call starts
|
|
41
|
+
* a background load so nothing here ever waits on the network.
|
|
42
|
+
*
|
|
43
|
+
* Opt-out gate: skills from a *default* (vendor) skills repo — `open-mercato/skills`
|
|
44
|
+
* for the zero-config majority, see `gatedSkillsRepos` — appear unless the user has
|
|
45
|
+
* curated them away. `importedSkills` in the GLOBAL `~/.cezar/ui-state.json` (not the
|
|
46
|
+
* per-repo file — the selection describes the person and must not depend on the launch
|
|
47
|
+
* directory, multi-project workspace) is a tri-state: ABSENT means "not curated" and
|
|
48
|
+
* every default skill shows (the historical behavior — no upgrade break for existing
|
|
49
|
+
* installs); a PRESENT array (even `[]`) means the user has taken control and only those
|
|
50
|
+
* names show. A repo that sets its own `skillsRepos` gates nothing regardless. This is the
|
|
51
|
+
* single chokepoint, so the decision is identical for every consumer — catalog, composer
|
|
52
|
+
* picker, planner, runner.
|
|
53
|
+
*/
|
|
54
|
+
export async function discoverSkills(repoRoot) {
|
|
55
|
+
const [lists, gatedRepos, uiState] = await Promise.all([
|
|
56
|
+
Promise.all([
|
|
57
|
+
...SKILL_DIRS.map(({ dir, source }) => readMarkdownSkills(resolve(repoRoot, dir), source)),
|
|
58
|
+
...GLOBAL_SKILL_DIRS.map(({ dir, source }) => readMarkdownSkills(dir, source)),
|
|
59
|
+
]),
|
|
60
|
+
gatedSkillsRepos(repoRoot),
|
|
61
|
+
readWorkspaceUiState(),
|
|
62
|
+
]);
|
|
63
|
+
const teamSkills = filterImportedTeamSkills(getTeamSkillsCached(repoRoot), gatedRepos, readImportedSkills(uiState));
|
|
64
|
+
const merged = [];
|
|
65
|
+
const seen = new Set();
|
|
66
|
+
for (const skills of [...lists, teamSkills]) {
|
|
67
|
+
for (const skill of skills) {
|
|
68
|
+
if (seen.has(skill.name))
|
|
69
|
+
continue;
|
|
70
|
+
seen.add(skill.name);
|
|
71
|
+
merged.push(skill);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
merged.sort((a, b) => a.name.localeCompare(b.name));
|
|
75
|
+
return merged;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* The imported team-skill names from a raw `ui-state.json` object, as a tri-state:
|
|
79
|
+
* `undefined` means the key is absent — "not curated", so every default skill shows
|
|
80
|
+
* (the opt-out default that keeps existing installs whole); an array (even empty) is
|
|
81
|
+
* the user's explicit selection. Defensive because the file is user-editable: a value
|
|
82
|
+
* that is not an array degrades to `undefined` (keep all — the safe, backward-compatible
|
|
83
|
+
* reading), and non-string / empty entries inside an array are dropped rather than thrown on.
|
|
84
|
+
*/
|
|
85
|
+
export function readImportedSkills(uiState) {
|
|
86
|
+
const value = uiState.importedSkills;
|
|
87
|
+
if (!Array.isArray(value))
|
|
88
|
+
return undefined;
|
|
89
|
+
return value.filter((name) => typeof name === 'string' && name.length > 0);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* The opt-out gate: keep every team skill whose repo is NOT gated (a repo with its own
|
|
93
|
+
* configured `skillsRepos` — auto-loads everything). For skills from a gated default
|
|
94
|
+
* (vendor) repo, `importedSkills === undefined` keeps them ALL (not curated — the
|
|
95
|
+
* historical behavior), while a present array keeps only the named ones. Local skills
|
|
96
|
+
* carry no `team` and are always kept. Pure so the gate is unit-testable without a
|
|
97
|
+
* network clone (the gated set is a const default otherwise).
|
|
98
|
+
*/
|
|
99
|
+
export function filterImportedTeamSkills(teamSkills, gatedRepos, importedSkills) {
|
|
100
|
+
// Not curated → the full default catalog still appears (no upgrade break).
|
|
101
|
+
if (importedSkills === undefined)
|
|
102
|
+
return [...teamSkills];
|
|
103
|
+
const imported = new Set(importedSkills);
|
|
104
|
+
return teamSkills.filter((skill) => !skill.team || !gatedRepos.has(skill.team.repo) || imported.has(skill.name));
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Walk a skills dir for entrypoints, following directory symlinks. Once a
|
|
108
|
+
* directory contains `SKILL.md`, it is one directory-based skill and its
|
|
109
|
+
* supporting Markdown (for example `references/*.md`) is not scanned. Other
|
|
110
|
+
* directories retain the legacy recursive `*.md` discovery behavior.
|
|
111
|
+
*/
|
|
112
|
+
async function skillEntryPaths(dir, depth, visited) {
|
|
113
|
+
if (depth < 0)
|
|
114
|
+
return [];
|
|
115
|
+
let real;
|
|
116
|
+
try {
|
|
117
|
+
real = await realpath(dir);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
return []; // missing dir or dangling symlink
|
|
121
|
+
}
|
|
122
|
+
if (visited.has(real))
|
|
123
|
+
return [];
|
|
124
|
+
visited.add(real);
|
|
125
|
+
let entries;
|
|
126
|
+
try {
|
|
127
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return [];
|
|
131
|
+
}
|
|
132
|
+
const skillEntry = entries.find((entry) => entry.name === 'SKILL.md');
|
|
133
|
+
if (skillEntry) {
|
|
134
|
+
const skillPath = join(dir, skillEntry.name);
|
|
135
|
+
try {
|
|
136
|
+
if ((await stat(skillPath)).isFile())
|
|
137
|
+
return [skillPath];
|
|
138
|
+
}
|
|
139
|
+
catch {
|
|
140
|
+
// A dangling or unreadable SKILL.md does not hide other valid entries.
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const paths = [];
|
|
144
|
+
for (const entry of entries) {
|
|
145
|
+
const path = join(dir, entry.name);
|
|
146
|
+
let isDir = entry.isDirectory();
|
|
147
|
+
if (entry.isSymbolicLink()) {
|
|
148
|
+
try {
|
|
149
|
+
isDir = (await stat(path)).isDirectory(); // stat follows the link
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
continue; // dangling symlink
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (isDir) {
|
|
156
|
+
paths.push(...(await skillEntryPaths(path, depth - 1, visited)));
|
|
157
|
+
}
|
|
158
|
+
else if (extname(entry.name).toLowerCase() === '.md') {
|
|
159
|
+
paths.push(path);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return paths;
|
|
163
|
+
}
|
|
164
|
+
async function readMarkdownSkills(dir, source) {
|
|
165
|
+
const paths = await skillEntryPaths(dir, 4, new Set());
|
|
166
|
+
const skills = [];
|
|
167
|
+
for (const absPath of paths) {
|
|
168
|
+
let raw;
|
|
169
|
+
try {
|
|
170
|
+
raw = await readFile(absPath, 'utf8');
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
const { frontmatter, body } = parseFrontmatter(raw);
|
|
176
|
+
const base = basename(absPath, extname(absPath));
|
|
177
|
+
// The `SKILL.md` convention names the skill after its directory.
|
|
178
|
+
const fallback = base.toLowerCase() === 'skill' ? basename(dirname(absPath)) : base;
|
|
179
|
+
const name = typeof frontmatter.name === 'string' && frontmatter.name.trim()
|
|
180
|
+
? frontmatter.name.trim()
|
|
181
|
+
: fallback;
|
|
182
|
+
const description = typeof frontmatter.description === 'string' && frontmatter.description.trim()
|
|
183
|
+
? frontmatter.description.trim()
|
|
184
|
+
: undefined;
|
|
185
|
+
const interactive = frontmatter.interactive === 'true' ? true : undefined;
|
|
186
|
+
skills.push({ name, description, interactive, body, path: absPath, source });
|
|
187
|
+
}
|
|
188
|
+
return skills;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Tiny purpose-built frontmatter parser — a leading `---\n … \n---\n` block
|
|
192
|
+
* with `key: value` lines, `key: [a, b]` inline arrays and `key:` + ` - a`
|
|
193
|
+
* block arrays. Deliberately not full YAML so we avoid a parser dependency
|
|
194
|
+
* for skill files.
|
|
195
|
+
*/
|
|
196
|
+
export function parseFrontmatter(raw) {
|
|
197
|
+
// Normalize CRLF and lone CR — otherwise frontmatter is silently dropped.
|
|
198
|
+
const text = raw.replace(/\r\n?/g, '\n');
|
|
199
|
+
if (!text.startsWith('---\n'))
|
|
200
|
+
return { frontmatter: {}, body: raw };
|
|
201
|
+
// Match the closing delimiter only on its own line so a `---` thematic
|
|
202
|
+
// break inside the body doesn't terminate the block early.
|
|
203
|
+
const end = text.indexOf('\n---\n', 4);
|
|
204
|
+
const endAtEof = text.endsWith('\n---') ? text.length - 4 : -1;
|
|
205
|
+
const closeAt = end === -1 ? endAtEof : end;
|
|
206
|
+
if (closeAt === -1)
|
|
207
|
+
return { frontmatter: {}, body: raw };
|
|
208
|
+
const block = text.slice(4, closeAt);
|
|
209
|
+
const afterDelimiter = end === -1 ? -1 : text.indexOf('\n', closeAt + 1);
|
|
210
|
+
const body = afterDelimiter === -1 ? '' : text.slice(afterDelimiter + 1);
|
|
211
|
+
const frontmatter = {};
|
|
212
|
+
const lines = block.split('\n');
|
|
213
|
+
for (let i = 0; i < lines.length; i++) {
|
|
214
|
+
const line = lines[i] ?? '';
|
|
215
|
+
if (!line.trim() || line.trim().startsWith('#'))
|
|
216
|
+
continue;
|
|
217
|
+
const m = /^([A-Za-z0-9_-]+):\s*(.*)$/.exec(line);
|
|
218
|
+
if (!m)
|
|
219
|
+
continue;
|
|
220
|
+
const key = m[1];
|
|
221
|
+
const rest = (m[2] ?? '').trim();
|
|
222
|
+
if (rest === '') {
|
|
223
|
+
const items = [];
|
|
224
|
+
while (i + 1 < lines.length && /^\s*-\s+/.test(lines[i + 1] ?? '')) {
|
|
225
|
+
items.push(stripQuotes((lines[i + 1] ?? '').replace(/^\s*-\s+/, '').trim()));
|
|
226
|
+
i++;
|
|
227
|
+
}
|
|
228
|
+
frontmatter[key] = items;
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
if (rest.startsWith('[') && rest.endsWith(']')) {
|
|
232
|
+
const inner = rest.slice(1, -1).trim();
|
|
233
|
+
frontmatter[key] = inner
|
|
234
|
+
? inner
|
|
235
|
+
.split(',')
|
|
236
|
+
.map((s) => stripQuotes(s.trim()))
|
|
237
|
+
.filter((s) => s.length > 0)
|
|
238
|
+
: [];
|
|
239
|
+
continue;
|
|
240
|
+
}
|
|
241
|
+
frontmatter[key] = stripQuotes(rest);
|
|
242
|
+
}
|
|
243
|
+
return { frontmatter, body };
|
|
244
|
+
}
|
|
245
|
+
function stripQuotes(s) {
|
|
246
|
+
if ((s.startsWith('"') && s.endsWith('"')) || (s.startsWith("'") && s.endsWith("'"))) {
|
|
247
|
+
return s.slice(1, -1);
|
|
248
|
+
}
|
|
249
|
+
return s;
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=skills.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"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"}
|
package/dist/todos.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* The global follow-up inbox (spec 007): `.ai/cezar/todos.json`, a flat JSON
|
|
4
|
+
* array agents append to (via CEZ_TODOS_FILE). Agent entries are external
|
|
5
|
+
* data — each one is zod-validated on read and malformed ones are skipped
|
|
6
|
+
* with a warning, never fatal. Server writes are serialized with an
|
|
7
|
+
* in-process lock (the janitor `withLock` pattern) and land atomically
|
|
8
|
+
* (tmp + rename, the runs.json pattern).
|
|
9
|
+
*/
|
|
10
|
+
export declare const todoSchema: z.ZodObject<{
|
|
11
|
+
id: z.ZodOptional<z.ZodString>;
|
|
12
|
+
ts: z.ZodOptional<z.ZodString>;
|
|
13
|
+
taskId: z.ZodOptional<z.ZodString>;
|
|
14
|
+
summary: z.ZodString;
|
|
15
|
+
action: z.ZodOptional<z.ZodString>;
|
|
16
|
+
prUrl: z.ZodOptional<z.ZodString>;
|
|
17
|
+
suggestedSkill: z.ZodOptional<z.ZodString>;
|
|
18
|
+
suggestedArgs: z.ZodOptional<z.ZodString>;
|
|
19
|
+
suggestedPrompt: z.ZodOptional<z.ZodString>;
|
|
20
|
+
runnable: z.ZodOptional<z.ZodBoolean>;
|
|
21
|
+
startedTaskId: z.ZodOptional<z.ZodString>;
|
|
22
|
+
}, z.core.$strip>;
|
|
23
|
+
export type TodoItem = z.infer<typeof todoSchema> & {
|
|
24
|
+
id: string;
|
|
25
|
+
};
|
|
26
|
+
export declare function todosPath(dataDir: string): string;
|
|
27
|
+
export declare function readTodos(dataDir: string): Promise<TodoItem[]>;
|
|
28
|
+
/** Check off (delete) an entry. False when the id isn't there. */
|
|
29
|
+
export declare function removeTodo(dataDir: string, id: string): Promise<boolean>;
|
|
30
|
+
/** The task text "▶ Run" turns an entry into: the suggested prompt (or the summary when the
|
|
31
|
+
* entry carries none), plus the suggested args as a trailing line. The single server-side
|
|
32
|
+
* source for `POST /api/todos/:id/start`; the cockpit's prefill copy
|
|
33
|
+
* (`packages/web/src/routes/inbox.tsx`, #374) lives in another process and cannot import this, so
|
|
34
|
+
* the two are pinned to the shared cases in `test/fixtures/todo-task-text.json`. */
|
|
35
|
+
export declare function todoTaskText(todo: Pick<TodoItem, 'summary' | 'suggestedPrompt' | 'suggestedArgs'>): string;
|
|
36
|
+
/** Record that "▶ Run" turned the entry into task `taskId`. The entry stays
|
|
37
|
+
* in the file as an audit trail; the GUI hides started entries. First start wins: an entry
|
|
38
|
+
* that already carries a `startedTaskId` is left untouched and answers false, so the
|
|
39
|
+
* best-effort `todoId` bookkeeping on `POST /api/runs` (#374) can never overwrite the audit
|
|
40
|
+
* trail — the check shares this lock, so two concurrent launches cannot both claim the entry. */
|
|
41
|
+
export declare function markStarted(dataDir: string, id: string, taskId: string): Promise<boolean>;
|
|
42
|
+
/** Subscribe to `dataDir`'s inbox changes; the watch is created on the first
|
|
43
|
+
* subscription and torn down when the last subscriber leaves. Returns the
|
|
44
|
+
* unsubscribe function (idempotent — a stale double call can never tear down
|
|
45
|
+
* a watch that later subscribers re-created). */
|
|
46
|
+
export declare function onTodosChanged(dataDir: string, cb: () => void): () => void;
|
|
47
|
+
/** Test hook: is a live watch registered for `dataDir`? */
|
|
48
|
+
export declare function todosWatchActive(dataDir: string): boolean;
|
package/dist/todos.js
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { EventEmitter } from 'node:events';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { promises as fs } from 'node:fs';
|
|
4
|
+
import { mkdirSync, watch } from 'node:fs';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
/**
|
|
8
|
+
* The global follow-up inbox (spec 007): `.ai/cezar/todos.json`, a flat JSON
|
|
9
|
+
* array agents append to (via CEZ_TODOS_FILE). Agent entries are external
|
|
10
|
+
* data — each one is zod-validated on read and malformed ones are skipped
|
|
11
|
+
* with a warning, never fatal. Server writes are serialized with an
|
|
12
|
+
* in-process lock (the janitor `withLock` pattern) and land atomically
|
|
13
|
+
* (tmp + rename, the runs.json pattern).
|
|
14
|
+
*/
|
|
15
|
+
export const todoSchema = z.object({
|
|
16
|
+
id: z.string().min(1).optional(),
|
|
17
|
+
ts: z.string().optional(),
|
|
18
|
+
taskId: z.string().optional(),
|
|
19
|
+
summary: z.string().min(1),
|
|
20
|
+
action: z.string().optional(),
|
|
21
|
+
prUrl: z.string().optional(),
|
|
22
|
+
suggestedSkill: z.string().optional(),
|
|
23
|
+
suggestedArgs: z.string().optional(),
|
|
24
|
+
suggestedPrompt: z.string().optional(),
|
|
25
|
+
/** Explicit intent; legacy entries infer it from an executable suggestion. */
|
|
26
|
+
runnable: z.boolean().optional(),
|
|
27
|
+
/** Set by the server when "▶ Run" turned this entry into a task. */
|
|
28
|
+
startedTaskId: z.string().optional(),
|
|
29
|
+
});
|
|
30
|
+
export function todosPath(dataDir) {
|
|
31
|
+
return join(dataDir, 'todos.json');
|
|
32
|
+
}
|
|
33
|
+
// ---- in-process lock (15-line port of janitor's storage.withLock) ----------
|
|
34
|
+
const locks = new Map();
|
|
35
|
+
async function withLock(key, fn) {
|
|
36
|
+
const prev = locks.get(key) ?? Promise.resolve();
|
|
37
|
+
let release = () => undefined;
|
|
38
|
+
const next = new Promise((r) => {
|
|
39
|
+
release = r;
|
|
40
|
+
});
|
|
41
|
+
locks.set(key, prev.then(() => next));
|
|
42
|
+
try {
|
|
43
|
+
await prev;
|
|
44
|
+
return await fn();
|
|
45
|
+
}
|
|
46
|
+
finally {
|
|
47
|
+
release();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
// ---- read / write -----------------------------------------------------------
|
|
51
|
+
/** Parse + validate the file. Broken JSON / non-array → []; bad entries are
|
|
52
|
+
* skipped with a warning; entries without an id get one assigned. */
|
|
53
|
+
async function readRaw(dataDir) {
|
|
54
|
+
let raw;
|
|
55
|
+
try {
|
|
56
|
+
raw = await fs.readFile(todosPath(dataDir), 'utf8');
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return { items: [], needsRewrite: false }; // no file yet — empty inbox
|
|
60
|
+
}
|
|
61
|
+
let parsed;
|
|
62
|
+
try {
|
|
63
|
+
parsed = JSON.parse(raw);
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
67
|
+
console.warn(`[cez] todos.json is not valid JSON — showing an empty inbox (${message})`);
|
|
68
|
+
return { items: [], needsRewrite: false };
|
|
69
|
+
}
|
|
70
|
+
if (!Array.isArray(parsed)) {
|
|
71
|
+
console.warn('[cez] todos.json is not a JSON array — showing an empty inbox');
|
|
72
|
+
return { items: [], needsRewrite: false };
|
|
73
|
+
}
|
|
74
|
+
const items = [];
|
|
75
|
+
let needsRewrite = false;
|
|
76
|
+
for (const entry of parsed) {
|
|
77
|
+
const result = todoSchema.safeParse(entry);
|
|
78
|
+
if (!result.success) {
|
|
79
|
+
console.warn(`[cez] skipped a malformed todos.json entry: ${result.error.issues.map((i) => i.message).join('; ')}`);
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (!result.data.id) {
|
|
83
|
+
// Agent entries arrive without ids — assign one so the GUI can address
|
|
84
|
+
// the entry; the file is rewritten (under the lock) on this read.
|
|
85
|
+
needsRewrite = true;
|
|
86
|
+
items.push({ ...result.data, id: randomUUID() });
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
items.push({ ...result.data, id: result.data.id });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return { items, needsRewrite };
|
|
93
|
+
}
|
|
94
|
+
async function writeAtomic(dataDir, items) {
|
|
95
|
+
const file = todosPath(dataDir);
|
|
96
|
+
const tmp = `${file}.tmp`;
|
|
97
|
+
await fs.mkdir(dataDir, { recursive: true });
|
|
98
|
+
await fs.writeFile(tmp, JSON.stringify(items, null, 2), 'utf8');
|
|
99
|
+
await fs.rename(tmp, file);
|
|
100
|
+
}
|
|
101
|
+
export async function readTodos(dataDir) {
|
|
102
|
+
return withLock(dataDir, async () => {
|
|
103
|
+
const { items, needsRewrite } = await readRaw(dataDir);
|
|
104
|
+
if (needsRewrite) {
|
|
105
|
+
await writeAtomic(dataDir, items).catch(() => undefined); // best effort
|
|
106
|
+
}
|
|
107
|
+
return items;
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
/** Check off (delete) an entry. False when the id isn't there. */
|
|
111
|
+
export async function removeTodo(dataDir, id) {
|
|
112
|
+
return withLock(dataDir, async () => {
|
|
113
|
+
const { items } = await readRaw(dataDir);
|
|
114
|
+
const next = items.filter((t) => t.id !== id);
|
|
115
|
+
if (next.length === items.length)
|
|
116
|
+
return false;
|
|
117
|
+
await writeAtomic(dataDir, next);
|
|
118
|
+
return true;
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
/** The task text "▶ Run" turns an entry into: the suggested prompt (or the summary when the
|
|
122
|
+
* entry carries none), plus the suggested args as a trailing line. The single server-side
|
|
123
|
+
* source for `POST /api/todos/:id/start`; the cockpit's prefill copy
|
|
124
|
+
* (`packages/web/src/routes/inbox.tsx`, #374) lives in another process and cannot import this, so
|
|
125
|
+
* the two are pinned to the shared cases in `test/fixtures/todo-task-text.json`. */
|
|
126
|
+
export function todoTaskText(todo) {
|
|
127
|
+
let task = (todo.suggestedPrompt ?? todo.summary).trim() || todo.summary;
|
|
128
|
+
if (todo.suggestedArgs)
|
|
129
|
+
task += `\n\nArguments: ${todo.suggestedArgs}`;
|
|
130
|
+
return task;
|
|
131
|
+
}
|
|
132
|
+
/** Record that "▶ Run" turned the entry into task `taskId`. The entry stays
|
|
133
|
+
* in the file as an audit trail; the GUI hides started entries. First start wins: an entry
|
|
134
|
+
* that already carries a `startedTaskId` is left untouched and answers false, so the
|
|
135
|
+
* best-effort `todoId` bookkeeping on `POST /api/runs` (#374) can never overwrite the audit
|
|
136
|
+
* trail — the check shares this lock, so two concurrent launches cannot both claim the entry. */
|
|
137
|
+
export async function markStarted(dataDir, id, taskId) {
|
|
138
|
+
return withLock(dataDir, async () => {
|
|
139
|
+
const { items } = await readRaw(dataDir);
|
|
140
|
+
const item = items.find((t) => t.id === id);
|
|
141
|
+
if (!item || item.startedTaskId)
|
|
142
|
+
return false;
|
|
143
|
+
item.startedTaskId = taskId;
|
|
144
|
+
await writeAtomic(dataDir, items);
|
|
145
|
+
return true;
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
const watches = new Map();
|
|
149
|
+
/** Start watching `dataDir` for todos.json changes (agents write it from
|
|
150
|
+
* another process). Degrades to a watcher-less entry on error. */
|
|
151
|
+
function startWatch(dataDir) {
|
|
152
|
+
const emitter = new EventEmitter();
|
|
153
|
+
emitter.setMaxListeners(100);
|
|
154
|
+
const entry = { emitter, watcher: undefined, timer: undefined };
|
|
155
|
+
try {
|
|
156
|
+
mkdirSync(dataDir, { recursive: true });
|
|
157
|
+
const watcher = watch(dataDir, (_event, filename) => {
|
|
158
|
+
if (filename && filename !== 'todos.json')
|
|
159
|
+
return;
|
|
160
|
+
if (entry.timer)
|
|
161
|
+
clearTimeout(entry.timer);
|
|
162
|
+
entry.timer = setTimeout(() => emitter.emit('changed'), 300);
|
|
163
|
+
entry.timer.unref?.();
|
|
164
|
+
});
|
|
165
|
+
watcher.on('error', () => undefined); // a dying watcher must not kill the server
|
|
166
|
+
watcher.unref?.();
|
|
167
|
+
entry.watcher = watcher;
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
171
|
+
console.warn(`[cez] todos watch unavailable — the Inbox updates on refresh only (${message})`);
|
|
172
|
+
}
|
|
173
|
+
watches.set(dataDir, entry);
|
|
174
|
+
return entry;
|
|
175
|
+
}
|
|
176
|
+
/** Subscribe to `dataDir`'s inbox changes; the watch is created on the first
|
|
177
|
+
* subscription and torn down when the last subscriber leaves. Returns the
|
|
178
|
+
* unsubscribe function (idempotent — a stale double call can never tear down
|
|
179
|
+
* a watch that later subscribers re-created). */
|
|
180
|
+
export function onTodosChanged(dataDir, cb) {
|
|
181
|
+
const entry = watches.get(dataDir) ?? startWatch(dataDir);
|
|
182
|
+
entry.emitter.on('changed', cb);
|
|
183
|
+
let unsubscribed = false;
|
|
184
|
+
return () => {
|
|
185
|
+
if (unsubscribed)
|
|
186
|
+
return;
|
|
187
|
+
unsubscribed = true;
|
|
188
|
+
entry.emitter.off('changed', cb);
|
|
189
|
+
if (entry.emitter.listenerCount('changed') > 0)
|
|
190
|
+
return;
|
|
191
|
+
if (entry.timer)
|
|
192
|
+
clearTimeout(entry.timer);
|
|
193
|
+
entry.watcher?.close();
|
|
194
|
+
watches.delete(dataDir);
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
/** Test hook: is a live watch registered for `dataDir`? */
|
|
198
|
+
export function todosWatchActive(dataDir) {
|
|
199
|
+
return watches.has(dataDir);
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=todos.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"todos.js","sourceRoot":"","sources":["../src/todos.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { UiState } from './contract/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* `.ai/cezar/ui-state.json` — small GUI preferences the cockpit persists (files, not a DB).
|
|
4
|
+
* The server owns the schema and the writes (`PUT /api/ui-state` in `src/server/server.ts`);
|
|
5
|
+
* this is the shared read path, so the CLI can honour a preference the cockpit set (#391's
|
|
6
|
+
* `dismissedSkillsBanner`) without a second notion of where the file lives.
|
|
7
|
+
*
|
|
8
|
+
* Same zero-config rule as `src/config.ts`: missing, unreadable or malformed all degrade to
|
|
9
|
+
* `{}` — an absent preference, never a throw, never a blocked startup.
|
|
10
|
+
*/
|
|
11
|
+
export declare function uiStatePath(repoRoot: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* Read `ui-state.json` on demand — never cached, never throws.
|
|
14
|
+
*
|
|
15
|
+
* Typed by the CONTRACT (`UiState`), not by a loose record: `GET /api/v1/ui-state` answers this
|
|
16
|
+
* value verbatim, so a `Record<string, unknown>` here made the route name no key at all and the
|
|
17
|
+
* per-route parity guard vacuous — the same defect `healthSnapshot` had. `UiState` is a
|
|
18
|
+
* `z.looseObject`, so the index signature (and with it the round-trip promise of
|
|
19
|
+
* BACKWARD_COMPATIBILITY.md §3) survives; what it adds is the NAMES of the keys the server knows.
|
|
20
|
+
*
|
|
21
|
+
* The cast is unchanged in kind — the file is user-editable JSON and is deliberately NOT parsed
|
|
22
|
+
* through the schema, because a single malformed pref must not discard the whole bag (§3). What
|
|
23
|
+
* the type asserts is the wire shape the route promises; the write side (`PUT /ui-state`, validated
|
|
24
|
+
* by `uiStateBody`) is what actually enforces it.
|
|
25
|
+
*/
|
|
26
|
+
export declare function readUiState(repoRoot: string): Promise<UiState>;
|
package/dist/ui-state.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* `.ai/cezar/ui-state.json` — small GUI preferences the cockpit persists (files, not a DB).
|
|
5
|
+
* The server owns the schema and the writes (`PUT /api/ui-state` in `src/server/server.ts`);
|
|
6
|
+
* this is the shared read path, so the CLI can honour a preference the cockpit set (#391's
|
|
7
|
+
* `dismissedSkillsBanner`) without a second notion of where the file lives.
|
|
8
|
+
*
|
|
9
|
+
* Same zero-config rule as `src/config.ts`: missing, unreadable or malformed all degrade to
|
|
10
|
+
* `{}` — an absent preference, never a throw, never a blocked startup.
|
|
11
|
+
*/
|
|
12
|
+
export function uiStatePath(repoRoot) {
|
|
13
|
+
return join(repoRoot, '.ai/cezar', 'ui-state.json');
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Read `ui-state.json` on demand — never cached, never throws.
|
|
17
|
+
*
|
|
18
|
+
* Typed by the CONTRACT (`UiState`), not by a loose record: `GET /api/v1/ui-state` answers this
|
|
19
|
+
* value verbatim, so a `Record<string, unknown>` here made the route name no key at all and the
|
|
20
|
+
* per-route parity guard vacuous — the same defect `healthSnapshot` had. `UiState` is a
|
|
21
|
+
* `z.looseObject`, so the index signature (and with it the round-trip promise of
|
|
22
|
+
* BACKWARD_COMPATIBILITY.md §3) survives; what it adds is the NAMES of the keys the server knows.
|
|
23
|
+
*
|
|
24
|
+
* The cast is unchanged in kind — the file is user-editable JSON and is deliberately NOT parsed
|
|
25
|
+
* through the schema, because a single malformed pref must not discard the whole bag (§3). What
|
|
26
|
+
* the type asserts is the wire shape the route promises; the write side (`PUT /ui-state`, validated
|
|
27
|
+
* by `uiStateBody`) is what actually enforces it.
|
|
28
|
+
*/
|
|
29
|
+
export async function readUiState(repoRoot) {
|
|
30
|
+
try {
|
|
31
|
+
const parsed = JSON.parse(await readFile(uiStatePath(repoRoot), 'utf8'));
|
|
32
|
+
return parsed && typeof parsed === 'object' ? parsed : {};
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return {};
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=ui-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ui-state.js","sourceRoot":"","sources":["../src/ui-state.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,OAAO,IAAI,CAAC,QAAQ,EAAE,WAAW,EAAE,eAAe,CAAC,CAAC;AACtD,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,QAAgB;IAChD,IAAI,CAAC;QACH,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QAClF,OAAO,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAE,MAAkB,CAAC,CAAC,CAAC,EAAE,CAAC;IACzE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Update discovery (#368): a best-effort, fire-and-forget check against the
|
|
3
|
+
* npm registry so the cockpit can tell the user a newer cezar exists — the
|
|
4
|
+
* root cause behind most "bug already fixed" reports is `npx` happily reusing
|
|
5
|
+
* a stale cached version forever. Silent on any failure: offline, slow
|
|
6
|
+
* registry or a weird payload must never affect startup.
|
|
7
|
+
*/
|
|
8
|
+
/** Newest published version when it's newer than `current`, else null. */
|
|
9
|
+
export declare function checkForUpdate(pkgName: string, current: string): Promise<string | null>;
|
|
10
|
+
/** Plain numeric semver compare (`1.2.10` > `1.2.9`); pre-release tags and
|
|
11
|
+
* anything unparseable compare as 0 — good enough for release-only publishes. */
|
|
12
|
+
export declare function isNewerVersion(candidate: string, current: string): boolean;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Update discovery (#368): a best-effort, fire-and-forget check against the
|
|
3
|
+
* npm registry so the cockpit can tell the user a newer cezar exists — the
|
|
4
|
+
* root cause behind most "bug already fixed" reports is `npx` happily reusing
|
|
5
|
+
* a stale cached version forever. Silent on any failure: offline, slow
|
|
6
|
+
* registry or a weird payload must never affect startup.
|
|
7
|
+
*/
|
|
8
|
+
const REGISTRY_TIMEOUT_MS = 3_000;
|
|
9
|
+
/** Newest published version when it's newer than `current`, else null. */
|
|
10
|
+
export async function checkForUpdate(pkgName, current) {
|
|
11
|
+
try {
|
|
12
|
+
const res = await fetch(`https://registry.npmjs.org/${encodeURIComponent(pkgName)}/latest`, {
|
|
13
|
+
signal: AbortSignal.timeout(REGISTRY_TIMEOUT_MS),
|
|
14
|
+
});
|
|
15
|
+
if (!res.ok)
|
|
16
|
+
return null;
|
|
17
|
+
const data = (await res.json());
|
|
18
|
+
const latest = typeof data.version === 'string' ? data.version : null;
|
|
19
|
+
return latest && isNewerVersion(latest, current) ? latest : null;
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
/** Plain numeric semver compare (`1.2.10` > `1.2.9`); pre-release tags and
|
|
26
|
+
* anything unparseable compare as 0 — good enough for release-only publishes. */
|
|
27
|
+
export function isNewerVersion(candidate, current) {
|
|
28
|
+
const parse = (v) => v
|
|
29
|
+
.split('.')
|
|
30
|
+
.slice(0, 3)
|
|
31
|
+
.map((part) => Number.parseInt(part, 10) || 0);
|
|
32
|
+
const a = parse(candidate);
|
|
33
|
+
const b = parse(current);
|
|
34
|
+
for (let i = 0; i < 3; i++) {
|
|
35
|
+
const diff = (a[i] ?? 0) - (b[i] ?? 0);
|
|
36
|
+
if (diff !== 0)
|
|
37
|
+
return diff > 0;
|
|
38
|
+
}
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=update-check.js.map
|