@kynetic-ai/spec 0.10.0 → 0.12.0
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/README.md +55 -455
- package/dist/agent-runtime/bootstrap.d.ts +31 -0
- package/dist/agent-runtime/bootstrap.d.ts.map +1 -0
- package/dist/agent-runtime/bootstrap.js +302 -0
- package/dist/agent-runtime/bootstrap.js.map +1 -0
- package/dist/agent-runtime/dispatch.d.ts +150 -10
- package/dist/agent-runtime/dispatch.d.ts.map +1 -1
- package/dist/agent-runtime/dispatch.js +1248 -244
- package/dist/agent-runtime/dispatch.js.map +1 -1
- package/dist/agent-runtime/invocation.d.ts +28 -1
- package/dist/agent-runtime/invocation.d.ts.map +1 -1
- package/dist/agent-runtime/invocation.js +172 -60
- package/dist/agent-runtime/invocation.js.map +1 -1
- package/dist/agent-runtime/prompts.d.ts +9 -0
- package/dist/agent-runtime/prompts.d.ts.map +1 -1
- package/dist/agent-runtime/prompts.js +42 -7
- package/dist/agent-runtime/prompts.js.map +1 -1
- package/dist/agent-runtime/session-event-accumulator.d.ts +83 -0
- package/dist/agent-runtime/session-event-accumulator.d.ts.map +1 -0
- package/dist/agent-runtime/session-event-accumulator.js +203 -0
- package/dist/agent-runtime/session-event-accumulator.js.map +1 -0
- package/dist/agent-runtime/session-event-types.d.ts +67 -0
- package/dist/agent-runtime/session-event-types.d.ts.map +1 -0
- package/dist/agent-runtime/session-event-types.js +13 -0
- package/dist/agent-runtime/session-event-types.js.map +1 -0
- package/dist/agent-runtime/workspace.d.ts +244 -0
- package/dist/agent-runtime/workspace.d.ts.map +1 -0
- package/dist/agent-runtime/workspace.js +2025 -0
- package/dist/agent-runtime/workspace.js.map +1 -0
- package/dist/agents/adapters.d.ts.map +1 -1
- package/dist/agents/adapters.js +58 -13
- package/dist/agents/adapters.js.map +1 -1
- package/dist/agents/spawner.d.ts +8 -0
- package/dist/agents/spawner.d.ts.map +1 -1
- package/dist/agents/spawner.js +25 -3
- package/dist/agents/spawner.js.map +1 -1
- package/dist/cli/batch-exec.js +1 -1
- package/dist/cli/batch-exec.js.map +1 -1
- package/dist/cli/command-annotations.d.ts +15 -3
- package/dist/cli/command-annotations.d.ts.map +1 -1
- package/dist/cli/command-annotations.js +23 -3
- package/dist/cli/command-annotations.js.map +1 -1
- package/dist/cli/commands/agent.d.ts +2 -0
- package/dist/cli/commands/agent.d.ts.map +1 -1
- package/dist/cli/commands/agent.js +144 -27
- package/dist/cli/commands/agent.js.map +1 -1
- package/dist/cli/commands/agents.d.ts.map +1 -1
- package/dist/cli/commands/agents.js +5 -5
- package/dist/cli/commands/agents.js.map +1 -1
- package/dist/cli/commands/derive.d.ts.map +1 -1
- package/dist/cli/commands/derive.js +118 -3
- package/dist/cli/commands/derive.js.map +1 -1
- package/dist/cli/commands/guard.d.ts.map +1 -1
- package/dist/cli/commands/guard.js +8 -6
- package/dist/cli/commands/guard.js.map +1 -1
- package/dist/cli/commands/index.d.ts +1 -0
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +1 -0
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +20 -0
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/item.d.ts.map +1 -1
- package/dist/cli/commands/item.js +205 -47
- package/dist/cli/commands/item.js.map +1 -1
- package/dist/cli/commands/log.d.ts.map +1 -1
- package/dist/cli/commands/log.js +24 -10
- package/dist/cli/commands/log.js.map +1 -1
- package/dist/cli/commands/meta.d.ts.map +1 -1
- package/dist/cli/commands/meta.js +10 -1
- package/dist/cli/commands/meta.js.map +1 -1
- package/dist/cli/commands/plan-import.d.ts +3 -3
- package/dist/cli/commands/plan-import.d.ts.map +1 -1
- package/dist/cli/commands/plan-import.js +213 -528
- package/dist/cli/commands/plan-import.js.map +1 -1
- package/dist/cli/commands/plan.d.ts.map +1 -1
- package/dist/cli/commands/plan.js +533 -83
- package/dist/cli/commands/plan.js.map +1 -1
- package/dist/cli/commands/review.d.ts +14 -0
- package/dist/cli/commands/review.d.ts.map +1 -0
- package/dist/cli/commands/review.js +1142 -0
- package/dist/cli/commands/review.js.map +1 -0
- package/dist/cli/commands/serve.d.ts +1 -0
- package/dist/cli/commands/serve.d.ts.map +1 -1
- package/dist/cli/commands/serve.js +33 -10
- package/dist/cli/commands/serve.js.map +1 -1
- package/dist/cli/commands/session/checkpoint.d.ts +2 -4
- package/dist/cli/commands/session/checkpoint.d.ts.map +1 -1
- package/dist/cli/commands/session/checkpoint.js +6 -107
- package/dist/cli/commands/session/checkpoint.js.map +1 -1
- package/dist/cli/commands/session/commands.d.ts.map +1 -1
- package/dist/cli/commands/session/commands.js +33 -23
- package/dist/cli/commands/session/commands.js.map +1 -1
- package/dist/cli/commands/session/compact.js +4 -4
- package/dist/cli/commands/session/compact.js.map +1 -1
- package/dist/cli/commands/session/create.js +2 -2
- package/dist/cli/commands/session/create.js.map +1 -1
- package/dist/cli/commands/session/format.d.ts.map +1 -1
- package/dist/cli/commands/session/format.js +1 -6
- package/dist/cli/commands/session/format.js.map +1 -1
- package/dist/cli/commands/session/log.d.ts +32 -7
- package/dist/cli/commands/session/log.d.ts.map +1 -1
- package/dist/cli/commands/session/log.js +166 -60
- package/dist/cli/commands/session/log.js.map +1 -1
- package/dist/cli/commands/session/migrate.d.ts +9 -0
- package/dist/cli/commands/session/migrate.d.ts.map +1 -0
- package/dist/cli/commands/session/migrate.js +46 -0
- package/dist/cli/commands/session/migrate.js.map +1 -0
- package/dist/cli/commands/session/stale-close.d.ts.map +1 -1
- package/dist/cli/commands/session/stale-close.js +5 -8
- package/dist/cli/commands/session/stale-close.js.map +1 -1
- package/dist/cli/commands/session/types.d.ts +1 -1
- package/dist/cli/commands/session/types.d.ts.map +1 -1
- package/dist/cli/commands/setup.d.ts +2 -2
- package/dist/cli/commands/setup.d.ts.map +1 -1
- package/dist/cli/commands/setup.js +287 -257
- package/dist/cli/commands/setup.js.map +1 -1
- package/dist/cli/commands/shadow.d.ts.map +1 -1
- package/dist/cli/commands/shadow.js +147 -31
- package/dist/cli/commands/shadow.js.map +1 -1
- package/dist/cli/commands/skill-crud.d.ts +7 -0
- package/dist/cli/commands/skill-crud.d.ts.map +1 -1
- package/dist/cli/commands/skill-crud.js +41 -18
- package/dist/cli/commands/skill-crud.js.map +1 -1
- package/dist/cli/commands/skill-diff.d.ts.map +1 -1
- package/dist/cli/commands/skill-diff.js +29 -3
- package/dist/cli/commands/skill-diff.js.map +1 -1
- package/dist/cli/commands/skill-install.d.ts.map +1 -1
- package/dist/cli/commands/skill-install.js +5 -4
- package/dist/cli/commands/skill-install.js.map +1 -1
- package/dist/cli/commands/task.d.ts.map +1 -1
- package/dist/cli/commands/task.js +359 -49
- package/dist/cli/commands/task.js.map +1 -1
- package/dist/cli/commands/trait.d.ts.map +1 -1
- package/dist/cli/commands/trait.js +5 -27
- package/dist/cli/commands/trait.js.map +1 -1
- package/dist/cli/commands/validate.d.ts.map +1 -1
- package/dist/cli/commands/validate.js +113 -52
- package/dist/cli/commands/validate.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +69 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/output.d.ts +26 -0
- package/dist/cli/output.d.ts.map +1 -1
- package/dist/cli/output.js +108 -1
- package/dist/cli/output.js.map +1 -1
- package/dist/cli/sync-mode.d.ts +44 -0
- package/dist/cli/sync-mode.d.ts.map +1 -0
- package/dist/cli/sync-mode.js +64 -0
- package/dist/cli/sync-mode.js.map +1 -0
- package/dist/daemon/middleware/project-context.ts +25 -7
- package/dist/daemon/project-context.ts +18 -0
- package/dist/daemon/routes/agent-dispatch.ts +107 -23
- package/dist/daemon/routes/aggregation.ts +184 -0
- package/dist/daemon/routes/inbox.ts +5 -0
- package/dist/daemon/routes/items.ts +167 -0
- package/dist/daemon/routes/meta.ts +141 -1
- package/dist/daemon/routes/plans.ts +147 -0
- package/dist/daemon/routes/projects.ts +28 -6
- package/dist/daemon/routes/ref-resolution.ts +119 -0
- package/dist/daemon/routes/refs.ts +42 -0
- package/dist/daemon/routes/session-related.ts +140 -0
- package/dist/daemon/routes/sessions.ts +581 -0
- package/dist/daemon/routes/tasks.ts +257 -2
- package/dist/daemon/routes/triage.ts +40 -1
- package/dist/daemon/routes/validation.ts +1 -1
- package/dist/daemon/server.ts +165 -50
- package/dist/daemon/session-sync.ts +11 -0
- package/dist/daemon/shadow-sync.ts +11 -0
- package/dist/daemon/watcher.ts +56 -5
- package/dist/daemon/websocket/project-resolution.ts +77 -0
- package/dist/export/json.d.ts.map +1 -1
- package/dist/export/json.js +104 -1
- package/dist/export/json.js.map +1 -1
- package/dist/export/types.d.ts +52 -1
- package/dist/export/types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/parser/agent-detection.d.ts +1 -1
- package/dist/parser/agent-detection.d.ts.map +1 -1
- package/dist/parser/agent-detection.js +10 -0
- package/dist/parser/agent-detection.js.map +1 -1
- package/dist/parser/alignment.d.ts.map +1 -1
- package/dist/parser/alignment.js +4 -2
- package/dist/parser/alignment.js.map +1 -1
- package/dist/parser/config.d.ts +397 -2
- package/dist/parser/config.d.ts.map +1 -1
- package/dist/parser/config.js +125 -3
- package/dist/parser/config.js.map +1 -1
- package/dist/parser/dispatch-workspaces.d.ts +18 -0
- package/dist/parser/dispatch-workspaces.d.ts.map +1 -0
- package/dist/parser/dispatch-workspaces.js +209 -0
- package/dist/parser/dispatch-workspaces.js.map +1 -0
- package/dist/parser/doctor.d.ts.map +1 -1
- package/dist/parser/doctor.js +27 -8
- package/dist/parser/doctor.js.map +1 -1
- package/dist/parser/file-lock.d.ts.map +1 -1
- package/dist/parser/file-lock.js +9 -2
- package/dist/parser/file-lock.js.map +1 -1
- package/dist/parser/index.d.ts +6 -0
- package/dist/parser/index.d.ts.map +1 -1
- package/dist/parser/index.js +6 -0
- package/dist/parser/index.js.map +1 -1
- package/dist/parser/plans.d.ts.map +1 -1
- package/dist/parser/plans.js +1 -0
- package/dist/parser/plans.js.map +1 -1
- package/dist/parser/refs.d.ts +8 -1
- package/dist/parser/refs.d.ts.map +1 -1
- package/dist/parser/refs.js +27 -1
- package/dist/parser/refs.js.map +1 -1
- package/dist/parser/review-operations.d.ts +72 -0
- package/dist/parser/review-operations.d.ts.map +1 -0
- package/dist/parser/review-operations.js +185 -0
- package/dist/parser/review-operations.js.map +1 -0
- package/dist/parser/review-task-integration.d.ts +78 -0
- package/dist/parser/review-task-integration.d.ts.map +1 -0
- package/dist/parser/review-task-integration.js +173 -0
- package/dist/parser/review-task-integration.js.map +1 -0
- package/dist/parser/review-threads.d.ts +101 -0
- package/dist/parser/review-threads.d.ts.map +1 -0
- package/dist/parser/review-threads.js +222 -0
- package/dist/parser/review-threads.js.map +1 -0
- package/dist/parser/review-validation.d.ts +69 -0
- package/dist/parser/review-validation.d.ts.map +1 -0
- package/dist/parser/review-validation.js +207 -0
- package/dist/parser/review-validation.js.map +1 -0
- package/dist/parser/reviews.d.ts +58 -0
- package/dist/parser/reviews.d.ts.map +1 -0
- package/dist/parser/reviews.js +230 -0
- package/dist/parser/reviews.js.map +1 -0
- package/dist/parser/session-branch.d.ts +91 -0
- package/dist/parser/session-branch.d.ts.map +1 -0
- package/dist/parser/session-branch.js +565 -0
- package/dist/parser/session-branch.js.map +1 -0
- package/dist/parser/session-sync-scheduler.d.ts +53 -0
- package/dist/parser/session-sync-scheduler.d.ts.map +1 -0
- package/dist/parser/session-sync-scheduler.js +100 -0
- package/dist/parser/session-sync-scheduler.js.map +1 -0
- package/dist/parser/setup-status.d.ts +7 -1
- package/dist/parser/setup-status.d.ts.map +1 -1
- package/dist/parser/setup-status.js +104 -39
- package/dist/parser/setup-status.js.map +1 -1
- package/dist/parser/shadow-sync-scheduler.d.ts +71 -0
- package/dist/parser/shadow-sync-scheduler.d.ts.map +1 -0
- package/dist/parser/shadow-sync-scheduler.js +139 -0
- package/dist/parser/shadow-sync-scheduler.js.map +1 -0
- package/dist/parser/shadow.d.ts +121 -14
- package/dist/parser/shadow.d.ts.map +1 -1
- package/dist/parser/shadow.js +752 -27
- package/dist/parser/shadow.js.map +1 -1
- package/dist/parser/skill-render.d.ts +24 -0
- package/dist/parser/skill-render.d.ts.map +1 -1
- package/dist/parser/skill-render.js +98 -26
- package/dist/parser/skill-render.js.map +1 -1
- package/dist/parser/validate.d.ts +43 -3
- package/dist/parser/validate.d.ts.map +1 -1
- package/dist/parser/validate.js +204 -30
- package/dist/parser/validate.js.map +1 -1
- package/dist/parser/yaml.d.ts +47 -11
- package/dist/parser/yaml.d.ts.map +1 -1
- package/dist/parser/yaml.js +329 -149
- package/dist/parser/yaml.js.map +1 -1
- package/dist/review/checks.d.ts +97 -0
- package/dist/review/checks.d.ts.map +1 -0
- package/dist/review/checks.js +175 -0
- package/dist/review/checks.js.map +1 -0
- package/dist/review/index.d.ts +3 -0
- package/dist/review/index.d.ts.map +1 -0
- package/dist/review/index.js +3 -0
- package/dist/review/index.js.map +1 -0
- package/dist/review/subject-bindings.d.ts +83 -0
- package/dist/review/subject-bindings.d.ts.map +1 -0
- package/dist/review/subject-bindings.js +175 -0
- package/dist/review/subject-bindings.js.map +1 -0
- package/dist/schema/common.d.ts +26 -0
- package/dist/schema/common.d.ts.map +1 -1
- package/dist/schema/common.js +13 -0
- package/dist/schema/common.js.map +1 -1
- package/dist/schema/dispatch-workspace.d.ts +2643 -0
- package/dist/schema/dispatch-workspace.d.ts.map +1 -0
- package/dist/schema/dispatch-workspace.js +187 -0
- package/dist/schema/dispatch-workspace.js.map +1 -0
- package/dist/schema/inbox.d.ts +8 -8
- package/dist/schema/index.d.ts +2 -0
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +2 -0
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/meta.d.ts +663 -116
- package/dist/schema/meta.d.ts.map +1 -1
- package/dist/schema/meta.js +28 -0
- package/dist/schema/meta.js.map +1 -1
- package/dist/schema/plan.d.ts +30 -19
- package/dist/schema/plan.d.ts.map +1 -1
- package/dist/schema/plan.js +3 -1
- package/dist/schema/plan.js.map +1 -1
- package/dist/schema/review-records.d.ts +2676 -0
- package/dist/schema/review-records.d.ts.map +1 -0
- package/dist/schema/review-records.js +232 -0
- package/dist/schema/review-records.js.map +1 -0
- package/dist/schema/spec.d.ts +32 -14
- package/dist/schema/spec.d.ts.map +1 -1
- package/dist/schema/spec.js +5 -0
- package/dist/schema/spec.js.map +1 -1
- package/dist/schema/task.d.ts +187 -29
- package/dist/schema/task.d.ts.map +1 -1
- package/dist/schema/task.js +12 -2
- package/dist/schema/task.js.map +1 -1
- package/dist/schema/triage.d.ts +22 -22
- package/dist/sessions/cache.d.ts +119 -0
- package/dist/sessions/cache.d.ts.map +1 -0
- package/dist/sessions/cache.js +284 -0
- package/dist/sessions/cache.js.map +1 -0
- package/dist/sessions/index.d.ts +1 -0
- package/dist/sessions/index.d.ts.map +1 -1
- package/dist/sessions/index.js +2 -0
- package/dist/sessions/index.js.map +1 -1
- package/dist/sessions/legacy.d.ts +77 -0
- package/dist/sessions/legacy.d.ts.map +1 -0
- package/dist/sessions/legacy.js +146 -0
- package/dist/sessions/legacy.js.map +1 -0
- package/dist/sessions/store.d.ts +115 -71
- package/dist/sessions/store.d.ts.map +1 -1
- package/dist/sessions/store.js +357 -182
- package/dist/sessions/store.js.map +1 -1
- package/dist/sessions/types.d.ts +44 -16
- package/dist/sessions/types.d.ts.map +1 -1
- package/dist/sessions/types.js +11 -2
- package/dist/sessions/types.js.map +1 -1
- package/dist/strings/errors.d.ts +32 -0
- package/dist/strings/errors.d.ts.map +1 -1
- package/dist/strings/errors.js +17 -0
- package/dist/strings/errors.js.map +1 -1
- package/dist/strings/labels.d.ts +1 -0
- package/dist/strings/labels.d.ts.map +1 -1
- package/dist/strings/labels.js +1 -0
- package/dist/strings/labels.js.map +1 -1
- package/dist/utils/activity.d.ts +101 -0
- package/dist/utils/activity.d.ts.map +1 -0
- package/dist/utils/activity.js +408 -0
- package/dist/utils/activity.js.map +1 -0
- package/dist/utils/git.d.ts +31 -0
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +87 -0
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/web-ui/_app/immutable/assets/0.tmlwn-Ih.css +1 -0
- package/dist/web-ui/_app/immutable/assets/9.BwwJybWx.css +1 -0
- package/dist/web-ui/_app/immutable/chunks/2KqE8gtn.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/70-t_QvE.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/AiWQj974.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/B25nWFyA.js +5 -0
- package/dist/web-ui/_app/immutable/chunks/B2bcA_Q_.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/B5e5HYyB.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/B7-5z6eA.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/B7bGmhK0.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/B8tYZKAE.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/BFGAyJjD.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/BG0850zf.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/BG8eSzAd.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/BIMxXS8I.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/BSzL1fpU.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/BYtjHfeq.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/{D1ArdqNb.js → Bp5pFYXL.js} +1 -1
- package/dist/web-ui/_app/immutable/chunks/BsJFsuAT.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/BvpNHcD6.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/BypqA25-.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/C0w6WDm5.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/C5_PAZ0y.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/CDRO15Iv.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/CF1CoqD5.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/CS2sa4_m.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/CWUQwB9H.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/CY5FDdSU.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/C_7MTDoj.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/CaAJD3dl.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/{i-XnOIX0.js → ChB5iyEL.js} +1 -1
- package/dist/web-ui/_app/immutable/chunks/ChQD-6N8.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/{BCkp8Hs8.js → CqbsoCwA.js} +1 -1
- package/dist/web-ui/_app/immutable/chunks/DCeJW50p.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/DJtZNgcs.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/DKIeaprD.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/DLd2uVIA.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/DW_subyT.js +2 -0
- package/dist/web-ui/_app/immutable/chunks/DbU6lVn0.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/Dc7ZCC5m.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/Dd5umPsk.js +2 -0
- package/dist/web-ui/_app/immutable/chunks/Dg_zDpDS.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/Dgqu8Yuc.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/DmxsPZTB.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/DphTaFUB.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/DqK4iHp0.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/DqT6OH_u.js +2 -0
- package/dist/web-ui/_app/immutable/chunks/Ds9I9wQb.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/Du5ng3u4.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/DxJw79Wi.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/GFTX8GgV.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/HNjs76Zz.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/HVMjDi4_.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/P0A_fJvS.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/T3vGWjIL.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/VTmrX9Qu.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/Xvwhx_F1.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/Yyz1XMQA.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/dh5HeqUr.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/fZMteyca.js +62 -0
- package/dist/web-ui/_app/immutable/chunks/{D28BF5MJ.js → gPrj-hqC.js} +1 -1
- package/dist/web-ui/_app/immutable/chunks/htcWMiYN.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/oTsvd9y4.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/qJfLUwU4.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/xCtiO_JE.js +1 -0
- package/dist/web-ui/_app/immutable/chunks/y4GeEH6k.js +1 -0
- package/dist/web-ui/_app/immutable/entry/app.C4h_eOn6.js +2 -0
- package/dist/web-ui/_app/immutable/entry/start.CQFTf9ep.js +1 -0
- package/dist/web-ui/_app/immutable/nodes/0.Dh1xO970.js +1 -0
- package/dist/web-ui/_app/immutable/nodes/1.l75D3Opx.js +1 -0
- package/dist/web-ui/_app/immutable/nodes/10.DBidBPc-.js +1 -0
- package/dist/web-ui/_app/immutable/nodes/11.Ab0gUKWe.js +1 -0
- package/dist/web-ui/_app/immutable/nodes/12.CMsnoxfs.js +1 -0
- package/dist/web-ui/_app/immutable/nodes/13.D8YKuknB.js +1 -0
- package/dist/web-ui/_app/immutable/nodes/14.DZ0aan7y.js +1 -0
- package/dist/web-ui/_app/immutable/nodes/15.CUIKreDL.js +2 -0
- package/dist/web-ui/_app/immutable/nodes/16.BWc8--BO.js +1 -0
- package/dist/web-ui/_app/immutable/nodes/2.CDUonbuh.js +1 -0
- package/dist/web-ui/_app/immutable/nodes/3.Ctg3M00i.js +1 -0
- package/dist/web-ui/_app/immutable/nodes/4.Ci-JDwbA.js +2 -0
- package/dist/web-ui/_app/immutable/nodes/5.CTyEDAq0.js +1 -0
- package/dist/web-ui/_app/immutable/nodes/6.BTZZqsAb.js +1 -0
- package/dist/web-ui/_app/immutable/nodes/7.BI52g_Jo.js +137 -0
- package/dist/web-ui/_app/immutable/nodes/8.3hZPaB9x.js +1 -0
- package/dist/web-ui/_app/immutable/nodes/9.DS49kvwl.js +29 -0
- package/dist/web-ui/_app/version.json +1 -1
- package/dist/web-ui/favicon-192.png +0 -0
- package/dist/web-ui/favicon-32.png +0 -0
- package/dist/web-ui/favicon.ico +0 -0
- package/dist/web-ui/index.html +14 -11
- package/package.json +14 -7
- package/plugin/.claude-plugin/marketplace.json +1 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/plugins/kspec/skills/merge/SKILL.md +127 -0
- package/plugin/plugins/kspec/skills/plan/SKILL.md +55 -26
- package/plugin/plugins/kspec/skills/review/SKILL.md +350 -133
- package/plugin/plugins/kspec/skills/task-work/SKILL.md +96 -106
- package/templates/agents-sections/04-pr-workflow.md +15 -12
- package/templates/agents-sections/06-ralph-loop.md +15 -10
- package/templates/skills/manifest.yaml +25 -7
- package/templates/skills/merge/SKILL.md +120 -0
- package/templates/skills/plan/SKILL.md +55 -26
- package/templates/skills/review/SKILL.md +346 -130
- package/templates/skills/task-work/SKILL.md +93 -103
- package/dist/web-ui/_app/immutable/assets/0.BxCxvrZR.css +0 -1
- package/dist/web-ui/_app/immutable/chunks/B-CZR0q8.js +0 -1
- package/dist/web-ui/_app/immutable/chunks/B1IR5Su5.js +0 -1
- package/dist/web-ui/_app/immutable/chunks/B_Cvvtc4.js +0 -1
- package/dist/web-ui/_app/immutable/chunks/BtFaGGII.js +0 -1
- package/dist/web-ui/_app/immutable/chunks/Bu8JVsCH.js +0 -1
- package/dist/web-ui/_app/immutable/chunks/C87u-CNA.js +0 -1
- package/dist/web-ui/_app/immutable/chunks/CrFkBTYp.js +0 -1
- package/dist/web-ui/_app/immutable/chunks/D6RtLpzL.js +0 -1
- package/dist/web-ui/_app/immutable/chunks/D7FHSgx2.js +0 -1
- package/dist/web-ui/_app/immutable/chunks/DBXrsxZQ.js +0 -2
- package/dist/web-ui/_app/immutable/chunks/Da_hHMuA.js +0 -1
- package/dist/web-ui/_app/immutable/chunks/Do6LchSF.js +0 -1
- package/dist/web-ui/_app/immutable/chunks/DoNPtcAw.js +0 -1
- package/dist/web-ui/_app/immutable/chunks/DtUbXRZz.js +0 -1
- package/dist/web-ui/_app/immutable/chunks/DyFPRlLl.js +0 -1
- package/dist/web-ui/_app/immutable/chunks/DzAP8lRM.js +0 -1
- package/dist/web-ui/_app/immutable/chunks/DzVXElzN.js +0 -2
- package/dist/web-ui/_app/immutable/chunks/aoPBFken.js +0 -1
- package/dist/web-ui/_app/immutable/chunks/laxtrUO3.js +0 -1
- package/dist/web-ui/_app/immutable/chunks/q1nIWgqB.js +0 -1
- package/dist/web-ui/_app/immutable/chunks/sTLbk5Nm.js +0 -1
- package/dist/web-ui/_app/immutable/chunks/vwKgQu5P.js +0 -5
- package/dist/web-ui/_app/immutable/entry/app.BCwMcqnT.js +0 -2
- package/dist/web-ui/_app/immutable/entry/start.wKCQH-tt.js +0 -1
- package/dist/web-ui/_app/immutable/nodes/0.CjGVMG74.js +0 -1
- package/dist/web-ui/_app/immutable/nodes/1.B6_AIPan.js +0 -1
- package/dist/web-ui/_app/immutable/nodes/2.q4oCS7Ws.js +0 -1
- package/dist/web-ui/_app/immutable/nodes/3.rTKZf9o2.js +0 -1
- package/dist/web-ui/_app/immutable/nodes/4.DVIDRu1d.js +0 -1
- package/dist/web-ui/_app/immutable/nodes/5.8PtPXIOd.js +0 -1
- package/dist/web-ui/_app/immutable/nodes/6.ZZrTemy_.js +0 -1
- package/dist/web-ui/_app/immutable/nodes/7.IP-gxCxi.js +0 -1
package/dist/daemon/server.ts
CHANGED
|
@@ -16,6 +16,7 @@ import { PubSubManager } from './websocket/pubsub';
|
|
|
16
16
|
import { HeartbeatManager } from './websocket/heartbeat';
|
|
17
17
|
import { WebSocketHandler } from './websocket/handler';
|
|
18
18
|
import { handleWebSocketClose } from './websocket/lifecycle';
|
|
19
|
+
import { resolveWebSocketProject } from './websocket/project-resolution';
|
|
19
20
|
import type { ConnectionData, ConnectedEvent } from './websocket/types';
|
|
20
21
|
import { PidFileManager } from './pid';
|
|
21
22
|
import { projectContextMiddleware } from './middleware/project-context';
|
|
@@ -27,6 +28,12 @@ import { createValidationRoutes } from './routes/validation';
|
|
|
27
28
|
import { createProjectsRoutes } from './routes/projects';
|
|
28
29
|
import { createTriageRoutes } from './routes/triage';
|
|
29
30
|
import { createAgentDispatchRoutes, getDispatchEngine, stopAllEngines } from './routes/agent-dispatch';
|
|
31
|
+
import { createSessionRoutes } from './routes/sessions';
|
|
32
|
+
import { createPlansRoutes } from './routes/plans';
|
|
33
|
+
import { createAggregationRoutes } from './routes/aggregation';
|
|
34
|
+
import { createRefsRoutes } from './routes/refs';
|
|
35
|
+
import { ShadowSyncScheduler } from './shadow-sync';
|
|
36
|
+
import { SessionSyncScheduler } from './session-sync';
|
|
30
37
|
import { join } from 'path';
|
|
31
38
|
|
|
32
39
|
export interface ServerOptions {
|
|
@@ -41,10 +48,9 @@ export interface ServerOptions {
|
|
|
41
48
|
* Tries multiple locations in order:
|
|
42
49
|
* 1. Explicit webUiDir option
|
|
43
50
|
* 2. WEB_UI_DIR environment variable
|
|
44
|
-
* 3.
|
|
45
|
-
* 4. web-ui/build in current working directory
|
|
46
|
-
* 5. Bundled dist/web-ui/ relative to this module (npm package installs)
|
|
51
|
+
* 3. Bundled dist/web-ui/ relative to this module (npm package installs)
|
|
47
52
|
*
|
|
53
|
+
* AC: @daemon-web-ui-bundle ac-4, ac-5
|
|
48
54
|
* Exported for testing only.
|
|
49
55
|
*/
|
|
50
56
|
export function resolveWebUiPath(webUiDir?: string): string | null {
|
|
@@ -59,20 +65,7 @@ export function resolveWebUiPath(webUiDir?: string): string | null {
|
|
|
59
65
|
return envPath;
|
|
60
66
|
}
|
|
61
67
|
|
|
62
|
-
// 3.
|
|
63
|
-
// The daemon is spawned with cwd set to project root
|
|
64
|
-
const monorepoPath = join(process.cwd(), 'packages', 'web-ui', 'build');
|
|
65
|
-
if (existsSync(monorepoPath)) {
|
|
66
|
-
return monorepoPath;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// 4. Alternate location: web-ui/build in cwd
|
|
70
|
-
const altPath = join(process.cwd(), 'web-ui', 'build');
|
|
71
|
-
if (existsSync(altPath)) {
|
|
72
|
-
return altPath;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// 5. Bundled assets: dist/web-ui/ relative to daemon module location
|
|
68
|
+
// 3. Bundled assets: dist/web-ui/ relative to daemon module location
|
|
76
69
|
// Covers npm package installs where no local web UI build exists.
|
|
77
70
|
// import.meta.url resolves to dist/daemon/server.js → sibling is dist/web-ui/
|
|
78
71
|
const selfDir = dirname(fileURLToPath(import.meta.url));
|
|
@@ -89,6 +82,66 @@ let pubsubManager: PubSubManager;
|
|
|
89
82
|
let heartbeatManager: HeartbeatManager;
|
|
90
83
|
let wsHandler: WebSocketHandler;
|
|
91
84
|
let projectManager: import('./project-context').ProjectContextManager | undefined;
|
|
85
|
+
let shadowSyncScheduler: ShadowSyncScheduler | undefined;
|
|
86
|
+
const sessionSyncSchedulers: Map<string, SessionSyncScheduler> = new Map();
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Start a session sync scheduler for a project if it has session branch configured.
|
|
90
|
+
* Safe to call multiple times — skips if scheduler already exists for that project.
|
|
91
|
+
*/
|
|
92
|
+
async function startSessionSyncForProject(
|
|
93
|
+
projectPath: string,
|
|
94
|
+
pubsub: PubSubManager,
|
|
95
|
+
): Promise<void> {
|
|
96
|
+
if (sessionSyncSchedulers.has(projectPath)) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const { loadProjectConfig } = await import('../parser/config.js');
|
|
101
|
+
const { config } = await loadProjectConfig(projectPath);
|
|
102
|
+
const specDir = join(projectPath, config.shadow.directory);
|
|
103
|
+
|
|
104
|
+
// AC: @multi-directory-daemon ac-31, @manifest-discovery ac-6
|
|
105
|
+
// Use discovery API instead of hardcoding kynetic.yaml
|
|
106
|
+
const { findManifestInDir, readYamlFile } = await import('../parser/yaml.js');
|
|
107
|
+
const manifestPath = await findManifestInDir(specDir);
|
|
108
|
+
if (!manifestPath) {
|
|
109
|
+
// No manifest found — gracefully skip session sync for this project
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const manifest = await readYamlFile<{ sessions?: { storage?: string; branch?: string } }>(manifestPath);
|
|
113
|
+
|
|
114
|
+
if (manifest?.sessions?.storage === 'branch') {
|
|
115
|
+
const syncInterval = config.shadow.sync_interval;
|
|
116
|
+
|
|
117
|
+
if (syncInterval > 0) {
|
|
118
|
+
const { resolveSessionBranchConfig } = await import('../parser/session-branch.js');
|
|
119
|
+
const sessionConfig = resolveSessionBranchConfig(projectPath, manifest);
|
|
120
|
+
|
|
121
|
+
if (sessionConfig) {
|
|
122
|
+
const scheduler = new SessionSyncScheduler({
|
|
123
|
+
worktreeDir: sessionConfig.worktreeDir,
|
|
124
|
+
intervalSeconds: syncInterval,
|
|
125
|
+
branchName: sessionConfig.branchName,
|
|
126
|
+
pubsub,
|
|
127
|
+
});
|
|
128
|
+
scheduler.start();
|
|
129
|
+
sessionSyncSchedulers.set(projectPath, scheduler);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Stop session sync scheduler for a specific project.
|
|
137
|
+
*/
|
|
138
|
+
function stopSessionSyncForProject(projectPath: string): void {
|
|
139
|
+
const scheduler = sessionSyncSchedulers.get(projectPath);
|
|
140
|
+
if (scheduler) {
|
|
141
|
+
scheduler.stop();
|
|
142
|
+
sessionSyncSchedulers.delete(projectPath);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
92
145
|
|
|
93
146
|
/**
|
|
94
147
|
* Middleware to enforce localhost-only connections.
|
|
@@ -199,10 +252,16 @@ export async function createServer(options: ServerOptions) {
|
|
|
199
252
|
// AC-3: Enforce localhost-only connections
|
|
200
253
|
.onRequest(localhostOnly());
|
|
201
254
|
|
|
255
|
+
// Shared callback for all registration paths (middleware, projects API, WebSocket)
|
|
256
|
+
const onProjectRegistered = async (projectPath: string) => {
|
|
257
|
+
await startSessionSyncForProject(projectPath, pubsubManager);
|
|
258
|
+
};
|
|
259
|
+
|
|
202
260
|
// AC: @multi-directory-daemon ac-1, ac-2, ac-3 - Project context middleware
|
|
203
261
|
const { manager: projectContextManager, middleware: projectMiddleware } = projectContextMiddleware({
|
|
204
262
|
startupProject: startupProjectPath,
|
|
205
|
-
pubsub: pubsubManager
|
|
263
|
+
pubsub: pubsubManager,
|
|
264
|
+
onProjectRegistered,
|
|
206
265
|
});
|
|
207
266
|
|
|
208
267
|
// Store manager globally for shutdown
|
|
@@ -238,7 +297,25 @@ export async function createServer(options: ServerOptions) {
|
|
|
238
297
|
.use(createValidationRoutes())
|
|
239
298
|
|
|
240
299
|
// AC: @multi-directory-daemon ac-28, ac-29, ac-30 - Projects management endpoints
|
|
241
|
-
.use(createProjectsRoutes({
|
|
300
|
+
.use(createProjectsRoutes({
|
|
301
|
+
projectManager: projectContextManager,
|
|
302
|
+
onProjectRegistered,
|
|
303
|
+
onProjectUnregistered: (projectPath) => {
|
|
304
|
+
stopSessionSyncForProject(projectPath);
|
|
305
|
+
},
|
|
306
|
+
}))
|
|
307
|
+
|
|
308
|
+
// AC: @ui-session-stream ac-1, ac-4 - Session data endpoints
|
|
309
|
+
.use(createSessionRoutes())
|
|
310
|
+
|
|
311
|
+
// AC: @ui-plans-view ac-1 - Plans data endpoints
|
|
312
|
+
.use(createPlansRoutes())
|
|
313
|
+
|
|
314
|
+
// AC: @ui-api-aggregation ac-1, ac-2, ac-3 - Aggregation endpoints
|
|
315
|
+
.use(createAggregationRoutes())
|
|
316
|
+
|
|
317
|
+
// AC: @ui-api-ref-resolution ac-4, ac-5 - Lightweight ref index endpoint
|
|
318
|
+
.use(createRefsRoutes())
|
|
242
319
|
|
|
243
320
|
// AC: @agent-dispatch-engine ac-4 - Agent dispatch API endpoints
|
|
244
321
|
// AC: @daemon-agent-dispatch ac-3, ac-4 - Pass pubsub for WebSocket broadcast on invocation events
|
|
@@ -247,14 +324,6 @@ export async function createServer(options: ServerOptions) {
|
|
|
247
324
|
// AC-4: WebSocket endpoint for real-time updates
|
|
248
325
|
.ws<ConnectionData>('/ws', {
|
|
249
326
|
beforeHandle({ request, store }) {
|
|
250
|
-
// AC: @multi-directory-daemon ac-21, ac-22, ac-23, ac-34 - Extract and validate project binding
|
|
251
|
-
// AC: @multi-directory-daemon ac-34 - Browser WebSocket API doesn't support custom headers,
|
|
252
|
-
// so we also accept project path as query parameter
|
|
253
|
-
const url = new URL(request.url, `http://${request.headers.get('host')}`);
|
|
254
|
-
const projectPath = request.headers.get('X-Kspec-Dir')
|
|
255
|
-
|| url.searchParams.get('project')
|
|
256
|
-
|| undefined;
|
|
257
|
-
|
|
258
327
|
// IMPORTANT: Do NOT return a value from ws beforeHandle.
|
|
259
328
|
// In Elysia 1.4 with derive middleware, returning a value short-circuits
|
|
260
329
|
// the WebSocket upgrade and sends the value as an HTTP 200 response.
|
|
@@ -267,30 +336,15 @@ export async function createServer(options: ServerOptions) {
|
|
|
267
336
|
return;
|
|
268
337
|
}
|
|
269
338
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
// AC: @multi-directory-daemon ac-4 - auto-register
|
|
277
|
-
projectContext = manager.registerProject(projectPath);
|
|
278
|
-
}
|
|
279
|
-
} else {
|
|
280
|
-
// AC: @multi-directory-daemon ac-22, ac-23 - Use default or reject
|
|
281
|
-
try {
|
|
282
|
-
projectContext = manager.getProject();
|
|
283
|
-
} catch (err: unknown) {
|
|
284
|
-
// AC: @multi-directory-daemon ac-23 - Reject when no default
|
|
285
|
-
if (err instanceof Error && err.message.includes('No default project configured')) {
|
|
286
|
-
throw new Error('No project specified');
|
|
287
|
-
}
|
|
288
|
-
throw err;
|
|
289
|
-
}
|
|
290
|
-
}
|
|
339
|
+
const { resolvedPath } = resolveWebSocketProject({
|
|
340
|
+
request,
|
|
341
|
+
manager,
|
|
342
|
+
fallbackPath: startupProjectPath,
|
|
343
|
+
onProjectRegistered,
|
|
344
|
+
});
|
|
291
345
|
|
|
292
346
|
// Store resolved path for open() handler via WeakMap
|
|
293
|
-
wsProjectPaths.set(request,
|
|
347
|
+
wsProjectPaths.set(request, resolvedPath);
|
|
294
348
|
} catch (err: unknown) {
|
|
295
349
|
console.error(`[daemon] WebSocket connection rejected: ${err instanceof Error ? err.message : String(err)}`);
|
|
296
350
|
throw err;
|
|
@@ -355,7 +409,21 @@ export async function createServer(options: ServerOptions) {
|
|
|
355
409
|
|
|
356
410
|
// SPA fallback routes for client-side routing
|
|
357
411
|
// These catch paths like /tasks, /items, /inbox that don't have static files
|
|
358
|
-
const spaRoutes = [
|
|
412
|
+
const spaRoutes = [
|
|
413
|
+
'/',
|
|
414
|
+
'/tasks', '/tasks/*',
|
|
415
|
+
'/items', '/items/*',
|
|
416
|
+
'/inbox',
|
|
417
|
+
'/observations',
|
|
418
|
+
'/triage',
|
|
419
|
+
'/validate',
|
|
420
|
+
'/sessions', '/sessions/*',
|
|
421
|
+
'/agents',
|
|
422
|
+
'/specs',
|
|
423
|
+
'/workflows',
|
|
424
|
+
'/plans',
|
|
425
|
+
'/settings',
|
|
426
|
+
];
|
|
359
427
|
for (const route of spaRoutes) {
|
|
360
428
|
app.get(route, () => Bun.file(indexHtmlPath));
|
|
361
429
|
}
|
|
@@ -395,6 +463,44 @@ export async function createServer(options: ServerOptions) {
|
|
|
395
463
|
}
|
|
396
464
|
}
|
|
397
465
|
|
|
466
|
+
// AC: @config-shadow ac-12 - Start periodic shadow sync if remote tracking configured
|
|
467
|
+
if (startupProjectPath) {
|
|
468
|
+
try {
|
|
469
|
+
const { loadProjectConfig } = await import('../parser/config.js');
|
|
470
|
+
const { config } = await loadProjectConfig(startupProjectPath);
|
|
471
|
+
const syncInterval = config.shadow.sync_interval;
|
|
472
|
+
const worktreeDir = join(startupProjectPath, config.shadow.directory);
|
|
473
|
+
|
|
474
|
+
if (syncInterval > 0) {
|
|
475
|
+
shadowSyncScheduler = new ShadowSyncScheduler({
|
|
476
|
+
worktreeDir,
|
|
477
|
+
intervalSeconds: syncInterval,
|
|
478
|
+
shadowOptions: {
|
|
479
|
+
branchName: config.shadow.branch,
|
|
480
|
+
directory: config.shadow.directory,
|
|
481
|
+
remote: config.shadow.remote?.value,
|
|
482
|
+
remoteType: config.shadow.remote?.type,
|
|
483
|
+
},
|
|
484
|
+
pubsub: pubsubManager,
|
|
485
|
+
});
|
|
486
|
+
shadowSyncScheduler.start();
|
|
487
|
+
}
|
|
488
|
+
} catch (error) {
|
|
489
|
+
console.error('[daemon] Failed to initialize shadow sync scheduler:', error);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// AC: @session-branch-worktree ac-sync - Start periodic session branch sync if configured
|
|
494
|
+
// Session sync runs independently from kspec-meta sync — failures in one do not affect the other
|
|
495
|
+
if (startupProjectPath) {
|
|
496
|
+
try {
|
|
497
|
+
await startSessionSyncForProject(startupProjectPath, pubsubManager);
|
|
498
|
+
} catch (error) {
|
|
499
|
+
// Session sync init failure does not block daemon startup
|
|
500
|
+
console.error('[daemon] Failed to initialize session sync scheduler:', error);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
398
504
|
// AC: @daemon-server ac-13, ac-14 - Start heartbeat monitoring
|
|
399
505
|
heartbeatManager.start(pubsubManager.getAllConnections());
|
|
400
506
|
|
|
@@ -406,6 +512,15 @@ export async function createServer(options: ServerOptions) {
|
|
|
406
512
|
// Stop heartbeat monitoring
|
|
407
513
|
heartbeatManager.stop();
|
|
408
514
|
|
|
515
|
+
// AC: @config-shadow ac-12 - Stop shadow sync scheduler
|
|
516
|
+
shadowSyncScheduler?.stop();
|
|
517
|
+
|
|
518
|
+
// AC: @session-branch-worktree ac-sync - Stop all session sync schedulers
|
|
519
|
+
for (const scheduler of sessionSyncSchedulers.values()) {
|
|
520
|
+
scheduler.stop();
|
|
521
|
+
}
|
|
522
|
+
sessionSyncSchedulers.clear();
|
|
523
|
+
|
|
409
524
|
// AC: @agent-dispatch-engine ac-11 - Stop all dispatch engines before shutting down
|
|
410
525
|
await stopAllEngines();
|
|
411
526
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Re-export SessionSyncScheduler from its canonical location in src/parser/.
|
|
3
|
+
* The daemon server.ts imports from this file; the actual implementation
|
|
4
|
+
* lives in src/parser/session-sync-scheduler.ts so that both daemon runtime
|
|
5
|
+
* (via dist/parser/) and vitest tests can import the same production code.
|
|
6
|
+
*
|
|
7
|
+
* AC: @session-branch-worktree ac-sync
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export { SessionSyncScheduler } from '../parser/session-sync-scheduler.js';
|
|
11
|
+
export type { SessionSyncSchedulerOptions, SessionSyncPubSub } from '../parser/session-sync-scheduler.js';
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Re-export ShadowSyncScheduler from its canonical location in src/parser/.
|
|
3
|
+
* The daemon server.ts imports from this file; the actual implementation
|
|
4
|
+
* lives in src/parser/shadow-sync-scheduler.ts so that both daemon runtime
|
|
5
|
+
* (via dist/parser/) and vitest tests can import the same production code.
|
|
6
|
+
*
|
|
7
|
+
* AC: @config-shadow ac-12
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export { ShadowSyncScheduler } from '../parser/shadow-sync-scheduler.js';
|
|
11
|
+
export type { ShadowSyncSchedulerOptions, ShadowSyncPubSub } from '../parser/shadow-sync-scheduler.js';
|
package/dist/daemon/watcher.ts
CHANGED
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
* - ac-8: Fallback to Chokidar if Bun fs.watch fails
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { watch, type FSWatcher } from 'fs';
|
|
13
|
-
import { readFile } from 'fs/promises';
|
|
12
|
+
import { existsSync, watch, type FSWatcher } from 'fs';
|
|
13
|
+
import { readFile, lstat } from 'fs/promises';
|
|
14
14
|
import { parse as parseYaml } from 'yaml';
|
|
15
15
|
import chokidar, { type FSWatcher as ChokidarWatcher } from 'chokidar';
|
|
16
|
-
import { join } from 'path';
|
|
16
|
+
import { join, relative } from 'path';
|
|
17
17
|
|
|
18
18
|
export interface WatcherOptions {
|
|
19
19
|
kspecDir: string;
|
|
@@ -39,6 +39,8 @@ export class KspecWatcher {
|
|
|
39
39
|
private retryCount = 0;
|
|
40
40
|
private maxRetries = 5;
|
|
41
41
|
private baseBackoffMs = 1000;
|
|
42
|
+
private stopped = false;
|
|
43
|
+
private recoveryTimer: NodeJS.Timeout | null = null;
|
|
42
44
|
|
|
43
45
|
constructor(private options: WatcherOptions) {}
|
|
44
46
|
|
|
@@ -46,6 +48,7 @@ export class KspecWatcher {
|
|
|
46
48
|
* AC-4, AC-8: Start watching .kspec directory (with Chokidar fallback)
|
|
47
49
|
*/
|
|
48
50
|
async start(): Promise<void> {
|
|
51
|
+
this.stopped = false;
|
|
49
52
|
try {
|
|
50
53
|
// Try Bun's native fs.watch first
|
|
51
54
|
await this.startBunWatcher();
|
|
@@ -68,9 +71,14 @@ export class KspecWatcher {
|
|
|
68
71
|
if (!filename || !filename.endsWith('.yaml')) return;
|
|
69
72
|
|
|
70
73
|
const fullPath = join(this.options.kspecDir, filename);
|
|
74
|
+
// Guard against nested .kspec symlink loops (e.g. .kspec/.kspec -> .kspec)
|
|
75
|
+
if (this.isNestedKspecPath(fullPath)) return;
|
|
71
76
|
this.handleFileChange(fullPath);
|
|
72
77
|
}
|
|
73
78
|
);
|
|
79
|
+
(this.watcher as FSWatcher).on('error', (error) => {
|
|
80
|
+
void this.handleWatcherError(error);
|
|
81
|
+
});
|
|
74
82
|
|
|
75
83
|
console.log('[watcher] Watching .kspec directory with Bun fs.watch');
|
|
76
84
|
}
|
|
@@ -81,6 +89,8 @@ export class KspecWatcher {
|
|
|
81
89
|
private async startChokidarWatcher(): Promise<void> {
|
|
82
90
|
this.watcher = chokidar.watch(join(this.options.kspecDir, '**/*.yaml'), {
|
|
83
91
|
ignoreInitial: true,
|
|
92
|
+
followSymlinks: false,
|
|
93
|
+
ignored: (filePath: string) => this.isNestedKspecPath(filePath),
|
|
84
94
|
awaitWriteFinish: {
|
|
85
95
|
stabilityThreshold: 100,
|
|
86
96
|
pollInterval: 50
|
|
@@ -123,6 +133,12 @@ export class KspecWatcher {
|
|
|
123
133
|
*/
|
|
124
134
|
private async processFileChange(filePath: string): Promise<void> {
|
|
125
135
|
try {
|
|
136
|
+
if (this.isNestedKspecPath(filePath)) return;
|
|
137
|
+
|
|
138
|
+
// Skip symlinks to prevent ELOOP errors
|
|
139
|
+
const stat = await lstat(filePath);
|
|
140
|
+
if (stat.isSymbolicLink()) return;
|
|
141
|
+
|
|
126
142
|
const content = await readFile(filePath, 'utf-8');
|
|
127
143
|
|
|
128
144
|
// AC-6: Validate YAML before broadcasting
|
|
@@ -143,13 +159,35 @@ export class KspecWatcher {
|
|
|
143
159
|
}
|
|
144
160
|
}
|
|
145
161
|
|
|
162
|
+
/**
|
|
163
|
+
* Ignore only recursive ".kspec" entries inside the watched root, not the
|
|
164
|
+
* root .kspec directory itself.
|
|
165
|
+
*/
|
|
166
|
+
private isNestedKspecPath(filePath: string): boolean {
|
|
167
|
+
const relPath = relative(this.options.kspecDir, filePath);
|
|
168
|
+
if (!relPath || relPath === '' || relPath.startsWith('..')) return false;
|
|
169
|
+
|
|
170
|
+
const [firstSegment] = relPath.split(/[\\/]+/);
|
|
171
|
+
return firstSegment === '.kspec';
|
|
172
|
+
}
|
|
173
|
+
|
|
146
174
|
/**
|
|
147
175
|
* AC-7: Handle watcher errors with exponential backoff
|
|
148
176
|
*/
|
|
149
177
|
private async handleWatcherError(error: Error): Promise<void> {
|
|
178
|
+
if (this.stopped) {
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
|
|
150
182
|
this.options.onError(error);
|
|
151
183
|
|
|
184
|
+
const nodeError = error as NodeJS.ErrnoException;
|
|
152
185
|
if (this.retryCount >= this.maxRetries) {
|
|
186
|
+
if (nodeError.code === 'ENOENT' && !existsSync(this.options.kspecDir)) {
|
|
187
|
+
console.warn('[watcher] Watched .kspec directory no longer exists after recovery attempts; stopping watcher');
|
|
188
|
+
await this.stop();
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
153
191
|
console.error('[watcher] Max retries reached, giving up');
|
|
154
192
|
return;
|
|
155
193
|
}
|
|
@@ -159,29 +197,42 @@ export class KspecWatcher {
|
|
|
159
197
|
|
|
160
198
|
console.log(`[watcher] Attempting recovery in ${backoffMs}ms (attempt ${this.retryCount}/${this.maxRetries})`);
|
|
161
199
|
|
|
162
|
-
setTimeout(async () => {
|
|
200
|
+
this.recoveryTimer = setTimeout(async () => {
|
|
201
|
+
this.recoveryTimer = null;
|
|
163
202
|
try {
|
|
203
|
+
if (this.stopped) return;
|
|
164
204
|
await this.stop();
|
|
205
|
+
this.stopped = false;
|
|
165
206
|
await this.start();
|
|
166
207
|
console.log('[watcher] Recovery successful');
|
|
167
208
|
} catch (retryError) {
|
|
168
209
|
console.error('[watcher] Recovery failed:', retryError);
|
|
169
210
|
// Will retry again if under max retries
|
|
170
|
-
this.handleWatcherError(retryError as Error);
|
|
211
|
+
await this.handleWatcherError(retryError as Error);
|
|
171
212
|
}
|
|
172
213
|
}, backoffMs);
|
|
214
|
+
if (typeof this.recoveryTimer === 'object' && 'unref' in this.recoveryTimer) {
|
|
215
|
+
this.recoveryTimer.unref();
|
|
216
|
+
}
|
|
173
217
|
}
|
|
174
218
|
|
|
175
219
|
/**
|
|
176
220
|
* Stop watching
|
|
177
221
|
*/
|
|
178
222
|
async stop(): Promise<void> {
|
|
223
|
+
this.stopped = true;
|
|
224
|
+
|
|
179
225
|
// Clear all debounce timers
|
|
180
226
|
for (const timer of this.debounceTimers.values()) {
|
|
181
227
|
clearTimeout(timer);
|
|
182
228
|
}
|
|
183
229
|
this.debounceTimers.clear();
|
|
184
230
|
|
|
231
|
+
if (this.recoveryTimer) {
|
|
232
|
+
clearTimeout(this.recoveryTimer);
|
|
233
|
+
this.recoveryTimer = null;
|
|
234
|
+
}
|
|
235
|
+
|
|
185
236
|
// Close watcher
|
|
186
237
|
if (this.watcher) {
|
|
187
238
|
if (this.usingChokidar) {
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebSocket Project Resolution
|
|
3
|
+
*
|
|
4
|
+
* Extracts and resolves the project path for a WebSocket connection request.
|
|
5
|
+
* Used by the WebSocket beforeHandle hook in server.ts.
|
|
6
|
+
*
|
|
7
|
+
* Task: @01KKBD6KH5F5MVC5BXV2NQG474
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { ProjectContextManager } from '../project-context';
|
|
11
|
+
|
|
12
|
+
export interface ResolveWebSocketProjectOptions {
|
|
13
|
+
request: Request;
|
|
14
|
+
manager: ProjectContextManager;
|
|
15
|
+
fallbackPath: string;
|
|
16
|
+
onProjectRegistered?: (projectPath: string) => Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface ResolveWebSocketProjectResult {
|
|
20
|
+
resolvedPath: string;
|
|
21
|
+
wasRegistered: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Resolves the project path for a WebSocket connection request.
|
|
26
|
+
*
|
|
27
|
+
* Extracts the project path from X-Kspec-Dir header or ?project= query param,
|
|
28
|
+
* registers it if new, and fires onProjectRegistered for newly-registered projects
|
|
29
|
+
* so that session sync starts.
|
|
30
|
+
*
|
|
31
|
+
* AC: @multi-directory-daemon ac-21, ac-22, ac-23, ac-34
|
|
32
|
+
*/
|
|
33
|
+
export function resolveWebSocketProject(
|
|
34
|
+
options: ResolveWebSocketProjectOptions,
|
|
35
|
+
): ResolveWebSocketProjectResult {
|
|
36
|
+
const { request, manager, fallbackPath, onProjectRegistered } = options;
|
|
37
|
+
|
|
38
|
+
// AC: @multi-directory-daemon ac-34 - Browser WebSocket API doesn't support custom headers,
|
|
39
|
+
// so we also accept project path as query parameter
|
|
40
|
+
const url = new URL(request.url, `http://${request.headers.get('host')}`);
|
|
41
|
+
const projectPath = request.headers.get('X-Kspec-Dir')
|
|
42
|
+
|| url.searchParams.get('project')
|
|
43
|
+
|| undefined;
|
|
44
|
+
|
|
45
|
+
if (!manager) {
|
|
46
|
+
return { resolvedPath: fallbackPath, wasRegistered: false };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
let projectContext;
|
|
50
|
+
let wasRegistered = false;
|
|
51
|
+
if (projectPath) {
|
|
52
|
+
// Explicit project specified
|
|
53
|
+
// AC: @multi-directory-daemon ac-4 - auto-register
|
|
54
|
+
const result = manager.getOrRegisterProject(projectPath);
|
|
55
|
+
projectContext = result.context;
|
|
56
|
+
wasRegistered = result.wasRegistered;
|
|
57
|
+
if (result.wasRegistered && onProjectRegistered) {
|
|
58
|
+
// Start session sync for newly auto-registered project (don't block upgrade)
|
|
59
|
+
void onProjectRegistered(projectContext.path).catch((syncError) => {
|
|
60
|
+
console.error(`[daemon] Failed to start session sync for WebSocket-registered ${projectContext.path}:`, syncError);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
} else {
|
|
64
|
+
// AC: @multi-directory-daemon ac-22, ac-23 - Use default or reject
|
|
65
|
+
try {
|
|
66
|
+
projectContext = manager.getProject();
|
|
67
|
+
} catch (err: unknown) {
|
|
68
|
+
// AC: @multi-directory-daemon ac-23 - Reject when no default
|
|
69
|
+
if (err instanceof Error && err.message.includes('No default project configured')) {
|
|
70
|
+
throw new Error('No project specified');
|
|
71
|
+
}
|
|
72
|
+
throw err;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return { resolvedPath: projectContext.path, wasRegistered };
|
|
77
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../src/export/json.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"json.d.ts","sourceRoot":"","sources":["../../src/export/json.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAwBH,OAAO,KAAK,EAIV,WAAW,EAEX,aAAa,EACd,MAAM,YAAY,CAAC;AA4PpB;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,iBAAiB,UAAQ,GACxB,OAAO,CAAC,aAAa,CAAC,CA2DxB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,aAAa,GAAG,WAAW,CAezE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIjD"}
|