@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
|
@@ -5,16 +5,16 @@
|
|
|
5
5
|
import * as fs from "node:fs/promises";
|
|
6
6
|
import * as path from "node:path";
|
|
7
7
|
import { markMutating } from "../command-annotations.js";
|
|
8
|
-
import { buildIndexes, createPlan, createTask, filterPlansByStatus, getAuthor, initContext,
|
|
8
|
+
import { addChildItem, addProjectLevelTraitItem, buildIndexes, createPlan, createSpecItem, createTask, findPlanByRef, filterPlansByStatus, getAuthor, initContext, loadPlans, mutatePlanAtomically, savePlan, saveTask, shortestUniqueUlid, } from "../../parser/index.js";
|
|
9
9
|
import { commitIfShadow } from "../../parser/shadow.js";
|
|
10
|
+
import { parsePlanDocument, topologicalSort, } from "../../parser/plan-document.js";
|
|
10
11
|
import { errors } from "../../strings/index.js";
|
|
11
12
|
import { fieldLabels } from "../../strings/labels.js";
|
|
12
13
|
import { formatRelativeTime as formatRelativeTimeUtil } from "../../utils/time.js";
|
|
13
14
|
import { EXIT_CODES } from "../exit-codes.js";
|
|
14
|
-
import { error, info, output, success } from "../output.js";
|
|
15
|
+
import { error, info, isJsonMode, output, success, warn } from "../output.js";
|
|
15
16
|
import { ulid } from "ulid";
|
|
16
17
|
import { registerPlanImportCommand } from "./plan-import.js";
|
|
17
|
-
import { parseIntOption } from "../validators.js";
|
|
18
18
|
/**
|
|
19
19
|
* Format relative time for display
|
|
20
20
|
*/
|
|
@@ -31,14 +31,389 @@ function resolvePlanRef(ref, plans) {
|
|
|
31
31
|
p._ulid.toLowerCase().startsWith(cleanRef.toLowerCase()) ||
|
|
32
32
|
p.slugs.includes(cleanRef));
|
|
33
33
|
if (!plan) {
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
exitDeriveWithGuidance(errors.reference.planNotFound(ref), EXIT_CODES.NOT_FOUND, "Check available plans with: kspec plan list", {
|
|
35
|
+
ref,
|
|
36
|
+
entity: "plan",
|
|
37
|
+
});
|
|
36
38
|
}
|
|
37
39
|
return plan;
|
|
38
40
|
}
|
|
39
41
|
function shortPlanRef(plan, plans) {
|
|
40
42
|
return shortestUniqueUlid(plan._ulid, plans.map((candidate) => candidate._ulid));
|
|
41
43
|
}
|
|
44
|
+
async function resolveDeriveModuleRef(ctx, plans, foundPlan, moduleOption) {
|
|
45
|
+
const moduleRef = moduleOption ?? foundPlan.module_ref ?? null;
|
|
46
|
+
if (!moduleRef) {
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
const { refIndex } = await buildIndexes(ctx, plans);
|
|
50
|
+
const moduleResult = refIndex.resolve(moduleRef);
|
|
51
|
+
if (!moduleResult.ok) {
|
|
52
|
+
exitDeriveWithGuidance(errors.reference.itemNotFound(moduleRef), EXIT_CODES.NOT_FOUND, "Check available modules with: kspec item list --type module", {
|
|
53
|
+
ref: moduleRef,
|
|
54
|
+
entity: "module",
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
const moduleItem = moduleResult.item;
|
|
58
|
+
if (moduleItem.type !== "module") {
|
|
59
|
+
exitDeriveWithGuidance(`${moduleRef} is not a module (type: ${moduleItem.type})`, EXIT_CODES.USAGE_ERROR, "Pass a module @ref from: kspec item list --type module", {
|
|
60
|
+
field: "module",
|
|
61
|
+
value: moduleItem.type,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
return moduleRef.startsWith("@") ? moduleRef : `@${moduleRef}`;
|
|
65
|
+
}
|
|
66
|
+
function slugify(title) {
|
|
67
|
+
return title
|
|
68
|
+
.toLowerCase()
|
|
69
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
70
|
+
.replace(/^-|-$/g, "")
|
|
71
|
+
.slice(0, 50);
|
|
72
|
+
}
|
|
73
|
+
function toRef(ref) {
|
|
74
|
+
return ref.startsWith("@") ? ref : `@${ref}`;
|
|
75
|
+
}
|
|
76
|
+
function canonicalRef(item) {
|
|
77
|
+
return `@${item.slugs[0] || item._ulid}`;
|
|
78
|
+
}
|
|
79
|
+
function nextUniqueSlug(baseSlug, reservedSlugs) {
|
|
80
|
+
let slug = baseSlug;
|
|
81
|
+
let counter = 1;
|
|
82
|
+
while (reservedSlugs.has(slug)) {
|
|
83
|
+
slug = `${baseSlug}-${counter}`;
|
|
84
|
+
counter++;
|
|
85
|
+
}
|
|
86
|
+
reservedSlugs.add(slug);
|
|
87
|
+
return slug;
|
|
88
|
+
}
|
|
89
|
+
function createNote(content, author) {
|
|
90
|
+
return {
|
|
91
|
+
_ulid: ulid(),
|
|
92
|
+
created_at: new Date().toISOString(),
|
|
93
|
+
author,
|
|
94
|
+
content,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function exitDeriveWithGuidance(message, exitCode, suggestion, details) {
|
|
98
|
+
if (suggestion) {
|
|
99
|
+
if (isJsonMode()) {
|
|
100
|
+
error(message, {
|
|
101
|
+
...details,
|
|
102
|
+
suggestion,
|
|
103
|
+
guidance: suggestion,
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
error(message);
|
|
108
|
+
console.error(`Suggestion: ${suggestion}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
error(message, isJsonMode() ? details : undefined);
|
|
113
|
+
}
|
|
114
|
+
process.exit(exitCode);
|
|
115
|
+
}
|
|
116
|
+
function emitDeriveResult(result) {
|
|
117
|
+
output(result, () => {
|
|
118
|
+
if (result.dry_run) {
|
|
119
|
+
console.log("Dry run - no changes made\n");
|
|
120
|
+
}
|
|
121
|
+
console.log(`Plan: ${result.plan_ref}`);
|
|
122
|
+
console.log(`Module: ${result.module_ref}`);
|
|
123
|
+
console.log(`Created specs: ${result.created_specs.length}`);
|
|
124
|
+
for (const ref of result.created_specs) {
|
|
125
|
+
console.log(` - ${ref}`);
|
|
126
|
+
}
|
|
127
|
+
console.log(`Created tasks: ${result.created_tasks.length}`);
|
|
128
|
+
for (const ref of result.created_tasks) {
|
|
129
|
+
console.log(` - ${ref}`);
|
|
130
|
+
}
|
|
131
|
+
if (result.skipped.length > 0) {
|
|
132
|
+
console.log(`Skipped: ${result.skipped.length}`);
|
|
133
|
+
for (const skipped of result.skipped) {
|
|
134
|
+
console.log(` - ${skipped.ref} (${skipped.title}): ${skipped.reason}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (result.errors.length > 0) {
|
|
138
|
+
console.log(`Errors: ${result.errors.length}`);
|
|
139
|
+
for (const err of result.errors) {
|
|
140
|
+
console.log(` - [${err.type}] ${err.message}`);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
function reportWarnings(warnings) {
|
|
146
|
+
for (const warning of warnings) {
|
|
147
|
+
warn(warning.ref ? `${warning.ref}: ${warning.message}` : warning.message);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
function normalizeSpecTraits(spec, refIndex, createdSpecs, warnings) {
|
|
151
|
+
const normalized = new Set();
|
|
152
|
+
for (const rawTrait of spec.traits || []) {
|
|
153
|
+
const traitRef = toRef(rawTrait);
|
|
154
|
+
const localTrait = createdSpecs.get(traitRef.slice(1));
|
|
155
|
+
if (localTrait?.item.type === "trait") {
|
|
156
|
+
normalized.add(localTrait.ref);
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
const resolved = refIndex.resolve(traitRef);
|
|
160
|
+
if (resolved.ok) {
|
|
161
|
+
const item = resolved.item;
|
|
162
|
+
if (item.type !== "trait") {
|
|
163
|
+
warnings.push({
|
|
164
|
+
kind: "spec",
|
|
165
|
+
ref: spec.slug ? `@${spec.slug}` : undefined,
|
|
166
|
+
message: `${traitRef} resolved to ${item.type}, not a trait. Storing normalized reference for later review.`,
|
|
167
|
+
});
|
|
168
|
+
normalized.add(traitRef);
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
normalized.add(canonicalRef(item));
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
normalized.add(traitRef);
|
|
175
|
+
}
|
|
176
|
+
return [...normalized];
|
|
177
|
+
}
|
|
178
|
+
function normalizeSpecDependencies(spec, refIndex, createdSpecs, warnings) {
|
|
179
|
+
return (spec.depends_on || []).map((rawDependency) => {
|
|
180
|
+
const dependencyRef = toRef(rawDependency);
|
|
181
|
+
const localDependency = createdSpecs.get(dependencyRef.slice(1));
|
|
182
|
+
if (localDependency) {
|
|
183
|
+
return localDependency.ref;
|
|
184
|
+
}
|
|
185
|
+
const resolved = refIndex.resolve(dependencyRef);
|
|
186
|
+
if (resolved.ok) {
|
|
187
|
+
const item = resolved.item;
|
|
188
|
+
return canonicalRef(item);
|
|
189
|
+
}
|
|
190
|
+
warnings.push({
|
|
191
|
+
kind: "spec",
|
|
192
|
+
ref: spec.slug ? `@${spec.slug}` : undefined,
|
|
193
|
+
message: `Unresolved dependency ${dependencyRef}. Keeping the reference as-is for later resolution.`,
|
|
194
|
+
});
|
|
195
|
+
return dependencyRef;
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
async function materializePlanSpecs(ctx, foundPlan, moduleRef, parsedPlan, refIndex, items, reservedSlugs, dryRun, warnings, skipped) {
|
|
199
|
+
const sortResult = topologicalSort(parsedPlan.specs);
|
|
200
|
+
if (sortResult.error) {
|
|
201
|
+
exitDeriveWithGuidance(sortResult.error.message, EXIT_CODES.USAGE_ERROR, "Fix the parent references in the plan content so they form an acyclic tree.", {
|
|
202
|
+
type: sortResult.error.type,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
const createdSpecs = new Map();
|
|
206
|
+
const materialized = [];
|
|
207
|
+
const moduleResult = refIndex.resolve(moduleRef);
|
|
208
|
+
if (!moduleResult.ok) {
|
|
209
|
+
exitDeriveWithGuidance(errors.reference.itemNotFound(moduleRef), EXIT_CODES.NOT_FOUND, "Check available modules with: kspec item list --type module", {
|
|
210
|
+
ref: moduleRef,
|
|
211
|
+
entity: "module",
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
const moduleItem = moduleResult.item;
|
|
215
|
+
for (const spec of sortResult.sorted) {
|
|
216
|
+
const localSlug = spec.slug || slugify(spec.title);
|
|
217
|
+
const itemType = (spec.type || "feature");
|
|
218
|
+
const itemSlug = nextUniqueSlug(localSlug, reservedSlugs);
|
|
219
|
+
const itemRef = `@${itemSlug}`;
|
|
220
|
+
let parent = null;
|
|
221
|
+
if (!(itemType === "trait" && !spec.parent)) {
|
|
222
|
+
if (spec.parent) {
|
|
223
|
+
const localParent = createdSpecs.get(spec.parent.startsWith("@") ? spec.parent.slice(1) : spec.parent);
|
|
224
|
+
if (localParent) {
|
|
225
|
+
parent = localParent.item;
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
const resolvedParent = refIndex.resolve(spec.parent);
|
|
229
|
+
if (!resolvedParent.ok) {
|
|
230
|
+
const reason = `Parent ${toRef(spec.parent)} not found. Use an existing @ref or add the parent spec to the plan.`;
|
|
231
|
+
warnings.push({ kind: "spec", ref: itemRef, message: reason });
|
|
232
|
+
skipped.push({
|
|
233
|
+
kind: "spec",
|
|
234
|
+
ref: itemRef,
|
|
235
|
+
title: spec.title,
|
|
236
|
+
reason,
|
|
237
|
+
});
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
parent = resolvedParent.item;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
parent = moduleItem;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
const input = {
|
|
248
|
+
title: spec.title,
|
|
249
|
+
type: itemType,
|
|
250
|
+
slugs: [itemSlug],
|
|
251
|
+
description: spec.description,
|
|
252
|
+
priority: spec.priority,
|
|
253
|
+
tags: [],
|
|
254
|
+
acceptance_criteria: spec.acceptance_criteria,
|
|
255
|
+
depends_on: normalizeSpecDependencies(spec, refIndex, createdSpecs, warnings),
|
|
256
|
+
implements: [],
|
|
257
|
+
relates_to: [],
|
|
258
|
+
tests: [],
|
|
259
|
+
traits: normalizeSpecTraits(spec, refIndex, createdSpecs, warnings),
|
|
260
|
+
notes: [],
|
|
261
|
+
};
|
|
262
|
+
const newItem = createSpecItem(input);
|
|
263
|
+
let createdItem;
|
|
264
|
+
if (dryRun) {
|
|
265
|
+
createdItem = {
|
|
266
|
+
...newItem,
|
|
267
|
+
_sourceFile: parent?._sourceFile,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
else if (itemType === "trait" && !spec.parent) {
|
|
271
|
+
const addResult = await addProjectLevelTraitItem(ctx, newItem);
|
|
272
|
+
createdItem = {
|
|
273
|
+
...addResult.item,
|
|
274
|
+
_sourceFile: ctx.manifestPath || undefined,
|
|
275
|
+
_path: addResult.path,
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
const addResult = await addChildItem(ctx, parent, newItem);
|
|
280
|
+
createdItem = {
|
|
281
|
+
...addResult.item,
|
|
282
|
+
_sourceFile: parent._sourceFile,
|
|
283
|
+
_path: addResult.path,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
const materializedSpec = {
|
|
287
|
+
localSlug,
|
|
288
|
+
ref: itemRef,
|
|
289
|
+
item: createdItem,
|
|
290
|
+
source: spec,
|
|
291
|
+
};
|
|
292
|
+
createdSpecs.set(localSlug, materializedSpec);
|
|
293
|
+
materialized.push(materializedSpec);
|
|
294
|
+
}
|
|
295
|
+
return materialized;
|
|
296
|
+
}
|
|
297
|
+
function buildTaskPlans(planRef, specItems, deriveFromSpecs, additionalTasks, refIndex, allTasks, reservedSlugs, author, warnings) {
|
|
298
|
+
const taskPlans = [];
|
|
299
|
+
const specTaskRefByLocalSlug = new Map();
|
|
300
|
+
const taskRefByLocalKey = new Map();
|
|
301
|
+
const shouldDeriveFromSpecs = deriveFromSpecs !== false;
|
|
302
|
+
if (shouldDeriveFromSpecs) {
|
|
303
|
+
for (const specItem of specItems) {
|
|
304
|
+
const taskSlug = nextUniqueSlug(slugify(`implement-${specItem.source.title}`), reservedSlugs);
|
|
305
|
+
const taskRef = `@${taskSlug}`;
|
|
306
|
+
specTaskRefByLocalSlug.set(specItem.localSlug, taskRef);
|
|
307
|
+
taskRefByLocalKey.set(specItem.localSlug, taskRef);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
for (const task of additionalTasks || []) {
|
|
311
|
+
const localKey = task.slug || slugify(task.title);
|
|
312
|
+
const taskSlug = nextUniqueSlug(task.slug || localKey, reservedSlugs);
|
|
313
|
+
taskRefByLocalKey.set(localKey, `@${taskSlug}`);
|
|
314
|
+
}
|
|
315
|
+
if (shouldDeriveFromSpecs) {
|
|
316
|
+
for (const specItem of specItems) {
|
|
317
|
+
const taskRef = specTaskRefByLocalSlug.get(specItem.localSlug);
|
|
318
|
+
const taskSlug = taskRef.slice(1);
|
|
319
|
+
const dependsOn = (specItem.item.depends_on || []).map((dependencyRef) => {
|
|
320
|
+
const localDependency = specTaskRefByLocalSlug.get(dependencyRef.slice(1));
|
|
321
|
+
return localDependency || dependencyRef;
|
|
322
|
+
});
|
|
323
|
+
const notes = specItem.source.implementation_notes
|
|
324
|
+
? [createNote(specItem.source.implementation_notes, author)]
|
|
325
|
+
: [];
|
|
326
|
+
taskPlans.push({
|
|
327
|
+
localKey: specItem.localSlug,
|
|
328
|
+
ref: taskRef,
|
|
329
|
+
input: {
|
|
330
|
+
title: `Implement ${specItem.source.title}`,
|
|
331
|
+
type: "task",
|
|
332
|
+
slugs: [taskSlug],
|
|
333
|
+
spec_ref: specItem.ref,
|
|
334
|
+
plan_ref: planRef,
|
|
335
|
+
priority: specItem.source.priority ?? 3,
|
|
336
|
+
tags: [],
|
|
337
|
+
depends_on: dependsOn,
|
|
338
|
+
notes,
|
|
339
|
+
origin: "derived",
|
|
340
|
+
derivation: "auto",
|
|
341
|
+
},
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
for (const task of additionalTasks || []) {
|
|
346
|
+
const localKey = task.slug || slugify(task.title);
|
|
347
|
+
const taskRef = taskRefByLocalKey.get(localKey);
|
|
348
|
+
const taskSlug = taskRef.slice(1);
|
|
349
|
+
const specRef = task.spec_ref
|
|
350
|
+
? (() => {
|
|
351
|
+
const localSpec = specItems.find((candidate) => candidate.localSlug ===
|
|
352
|
+
(task.spec_ref.startsWith("@")
|
|
353
|
+
? task.spec_ref.slice(1)
|
|
354
|
+
: task.spec_ref));
|
|
355
|
+
if (localSpec) {
|
|
356
|
+
return localSpec.ref;
|
|
357
|
+
}
|
|
358
|
+
const resolved = refIndex.resolve(task.spec_ref);
|
|
359
|
+
if (resolved.ok) {
|
|
360
|
+
return canonicalRef(resolved.item);
|
|
361
|
+
}
|
|
362
|
+
warnings.push({
|
|
363
|
+
kind: "task",
|
|
364
|
+
ref: taskRef,
|
|
365
|
+
message: `Unresolved spec_ref ${toRef(task.spec_ref)} on additional task. Keeping normalized reference.`,
|
|
366
|
+
});
|
|
367
|
+
return toRef(task.spec_ref);
|
|
368
|
+
})()
|
|
369
|
+
: null;
|
|
370
|
+
const dependsOn = (task.depends_on || []).map((dependencyRef) => {
|
|
371
|
+
const normalized = toRef(dependencyRef);
|
|
372
|
+
const localTaskDependency = taskRefByLocalKey.get(normalized.slice(1));
|
|
373
|
+
if (localTaskDependency) {
|
|
374
|
+
return localTaskDependency;
|
|
375
|
+
}
|
|
376
|
+
const resolved = refIndex.resolve(normalized);
|
|
377
|
+
if (resolved.ok) {
|
|
378
|
+
return canonicalRef(resolved.item);
|
|
379
|
+
}
|
|
380
|
+
warnings.push({
|
|
381
|
+
kind: "task",
|
|
382
|
+
ref: taskRef,
|
|
383
|
+
message: `Unresolved depends_on ${normalized} on additional task. Keeping normalized reference.`,
|
|
384
|
+
});
|
|
385
|
+
return normalized;
|
|
386
|
+
});
|
|
387
|
+
taskPlans.push({
|
|
388
|
+
localKey,
|
|
389
|
+
ref: taskRef,
|
|
390
|
+
input: {
|
|
391
|
+
title: task.title,
|
|
392
|
+
type: "task",
|
|
393
|
+
slugs: [taskSlug],
|
|
394
|
+
description: task.description,
|
|
395
|
+
spec_ref: specRef,
|
|
396
|
+
plan_ref: planRef,
|
|
397
|
+
priority: task.priority ?? 3,
|
|
398
|
+
tags: task.tags || [],
|
|
399
|
+
depends_on: dependsOn,
|
|
400
|
+
notes: [],
|
|
401
|
+
origin: "derived",
|
|
402
|
+
},
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
const existingTaskSlugs = new Set(allTasks.flatMap((task) => task.slugs));
|
|
406
|
+
for (const taskPlan of taskPlans) {
|
|
407
|
+
if (existingTaskSlugs.has(taskPlan.input.slugs?.[0] || "")) {
|
|
408
|
+
warnings.push({
|
|
409
|
+
kind: "task",
|
|
410
|
+
ref: taskPlan.ref,
|
|
411
|
+
message: "Task slug collided with existing work and was renumbered.",
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
return taskPlans;
|
|
416
|
+
}
|
|
42
417
|
/**
|
|
43
418
|
* Register the 'plan' command group
|
|
44
419
|
*/
|
|
@@ -158,6 +533,12 @@ Examples:
|
|
|
158
533
|
if (foundPlan.slugs.length > 0) {
|
|
159
534
|
console.log(`Slugs: ${foundPlan.slugs.join(", ")}`);
|
|
160
535
|
}
|
|
536
|
+
if (foundPlan.module_ref) {
|
|
537
|
+
console.log(`Module: ${foundPlan.module_ref}`);
|
|
538
|
+
}
|
|
539
|
+
if (foundPlan.source_path) {
|
|
540
|
+
console.log(`Source: ${foundPlan.source_path}`);
|
|
541
|
+
}
|
|
161
542
|
console.log(`${fieldLabels.created} ${foundPlan.created_at} (${formatRelativeTime(foundPlan.created_at)})`);
|
|
162
543
|
if (foundPlan.approved_at) {
|
|
163
544
|
console.log(`Approved: ${foundPlan.approved_at} (${formatRelativeTime(foundPlan.approved_at)})`);
|
|
@@ -198,6 +579,52 @@ Examples:
|
|
|
198
579
|
process.exit(EXIT_CODES.ERROR);
|
|
199
580
|
}
|
|
200
581
|
});
|
|
582
|
+
// kspec plan export <ref>
|
|
583
|
+
// AC: @plan-export ac-stdout, ac-output-file, ac-empty, ac-not-found, ac-json
|
|
584
|
+
plan
|
|
585
|
+
.command("export <ref>")
|
|
586
|
+
.description("Export stored plan content to stdout or a file")
|
|
587
|
+
.option("--output <path>", "Write plan content to the specified file")
|
|
588
|
+
.addHelpText("after", `
|
|
589
|
+
Examples:
|
|
590
|
+
$ kspec plan export @plan-ref
|
|
591
|
+
$ kspec plan export @plan-ref --output ./plan.md
|
|
592
|
+
$ kspec plan export @plan-ref --json`)
|
|
593
|
+
.action(async (ref, options) => {
|
|
594
|
+
try {
|
|
595
|
+
const ctx = await initContext();
|
|
596
|
+
const foundPlan = await findPlanByRef(ctx, ref);
|
|
597
|
+
if (!foundPlan) {
|
|
598
|
+
error(errors.reference.planNotFound(ref));
|
|
599
|
+
process.exit(EXIT_CODES.USAGE_ERROR);
|
|
600
|
+
}
|
|
601
|
+
if (foundPlan.content.length === 0) {
|
|
602
|
+
error("Plan has no content to export");
|
|
603
|
+
process.exit(EXIT_CODES.USAGE_ERROR);
|
|
604
|
+
}
|
|
605
|
+
if (isJsonMode()) {
|
|
606
|
+
output(foundPlan);
|
|
607
|
+
return;
|
|
608
|
+
}
|
|
609
|
+
if (options.output) {
|
|
610
|
+
const outputPath = path.resolve(process.cwd(), options.output);
|
|
611
|
+
try {
|
|
612
|
+
await fs.writeFile(outputPath, foundPlan.content, "utf-8");
|
|
613
|
+
}
|
|
614
|
+
catch (err) {
|
|
615
|
+
error(`Failed to write plan export file: ${options.output}`, err);
|
|
616
|
+
process.exit(EXIT_CODES.ERROR);
|
|
617
|
+
}
|
|
618
|
+
success(`Exported plan content to ${options.output}`);
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
process.stdout.write(foundPlan.content);
|
|
622
|
+
}
|
|
623
|
+
catch (err) {
|
|
624
|
+
error("Failed to export plan", err);
|
|
625
|
+
process.exit(EXIT_CODES.ERROR);
|
|
626
|
+
}
|
|
627
|
+
});
|
|
201
628
|
// kspec plan set <ref>
|
|
202
629
|
// AC: @plan-crud ac-3, ac-4
|
|
203
630
|
markMutating(plan.command("set <ref>"))
|
|
@@ -362,102 +789,125 @@ Examples:
|
|
|
362
789
|
}
|
|
363
790
|
});
|
|
364
791
|
// kspec plan derive <ref>
|
|
365
|
-
// AC: @plan-derive ac-
|
|
792
|
+
// AC: @plan-derive-enhanced ac-parse-content through ac-commit
|
|
366
793
|
markMutating(plan.command("derive <ref>"))
|
|
367
|
-
.description("
|
|
368
|
-
.option("--
|
|
369
|
-
.option("--
|
|
794
|
+
.description("Materialize plan content into specs and optional tasks")
|
|
795
|
+
.option("--module <ref>", "Module context for derivation (overrides stored plan module)")
|
|
796
|
+
.option("--tasks", "Also derive implementation tasks after creating specs")
|
|
797
|
+
.option("--dry-run", "Preview derived specs/tasks without saving changes")
|
|
370
798
|
.addHelpText("after", `
|
|
371
799
|
Examples:
|
|
372
|
-
$ kspec plan derive @plan-ref
|
|
373
|
-
$ kspec plan derive @plan-ref --
|
|
374
|
-
$ kspec plan derive @plan-ref --
|
|
800
|
+
$ kspec plan derive @plan-ref --module @core
|
|
801
|
+
$ kspec plan derive @plan-ref --tasks
|
|
802
|
+
$ kspec plan derive @plan-ref --module @core --tasks --dry-run`)
|
|
375
803
|
.action(async (ref, options) => {
|
|
376
804
|
try {
|
|
377
805
|
const ctx = await initContext();
|
|
378
806
|
const plans = await loadPlans(ctx);
|
|
379
|
-
const tasks = await loadAllTasks(ctx);
|
|
380
807
|
const foundPlan = resolvePlanRef(ref, plans);
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
808
|
+
const planRef = canonicalRef(foundPlan);
|
|
809
|
+
const author = getAuthor(ctx.config?.identity?.author);
|
|
810
|
+
if (foundPlan.status === "active") {
|
|
811
|
+
exitDeriveWithGuidance("Plan already derived. Manage specs directly via kspec item set.", EXIT_CODES.CONFLICT, `Update derived work directly, for example: kspec item set ${planRef} ...`, {
|
|
812
|
+
current_status: foundPlan.status,
|
|
813
|
+
valid_next_states: ["manage-derived-work"],
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
if (foundPlan.status !== "approved") {
|
|
817
|
+
exitDeriveWithGuidance(`Plan must be in approved status to derive (current: ${foundPlan.status})`, EXIT_CODES.CONFLICT, `Approve the plan first with: kspec plan set ${planRef} --status approved`, {
|
|
818
|
+
current_status: foundPlan.status,
|
|
819
|
+
valid_next_states: ["approved"],
|
|
820
|
+
});
|
|
385
821
|
}
|
|
386
|
-
|
|
387
|
-
if (
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
name: "Priority",
|
|
822
|
+
const moduleRef = await resolveDeriveModuleRef(ctx, plans, foundPlan, options.module);
|
|
823
|
+
if (!moduleRef) {
|
|
824
|
+
exitDeriveWithGuidance("Plan derive requires --module when the plan has no stored module ref", EXIT_CODES.USAGE_ERROR, `Re-run with a module, for example: kspec plan derive ${planRef} --module @your-module`, {
|
|
825
|
+
field: "module",
|
|
826
|
+
value: null,
|
|
392
827
|
});
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
828
|
+
}
|
|
829
|
+
const parsedPlan = parsePlanDocument(foundPlan.content);
|
|
830
|
+
const errorsList = [];
|
|
831
|
+
const warnings = [];
|
|
832
|
+
const skipped = [];
|
|
833
|
+
for (const parseError of parsedPlan.errors) {
|
|
834
|
+
if (parseError.type === "yaml") {
|
|
835
|
+
exitDeriveWithGuidance(parseError.message, EXIT_CODES.USAGE_ERROR, "Fix the YAML block in the plan document and run kspec plan derive again.", {
|
|
836
|
+
type: parseError.type,
|
|
837
|
+
});
|
|
396
838
|
}
|
|
397
|
-
|
|
398
|
-
|
|
839
|
+
errorsList.push({
|
|
840
|
+
type: parseError.type,
|
|
841
|
+
message: parseError.message,
|
|
842
|
+
});
|
|
399
843
|
}
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
return title
|
|
403
|
-
.toLowerCase()
|
|
404
|
-
.replace(/[^a-z0-9]+/g, "-")
|
|
405
|
-
.replace(/^-|-$/g, "")
|
|
406
|
-
.slice(0, 50);
|
|
407
|
-
};
|
|
408
|
-
// Generate task title and slug
|
|
409
|
-
const taskTitle = options.title || `Implement: ${foundPlan.title}`;
|
|
410
|
-
let taskSlug = generateSlug(taskTitle);
|
|
411
|
-
// Ensure slug uniqueness
|
|
412
|
-
let slugSuffix = 1;
|
|
413
|
-
const originalSlug = taskSlug;
|
|
414
|
-
while (tasks.some((t) => t.slugs.includes(taskSlug))) {
|
|
415
|
-
taskSlug = `${originalSlug}-${slugSuffix}`;
|
|
416
|
-
slugSuffix++;
|
|
844
|
+
if (parsedPlan.specs.length === 0) {
|
|
845
|
+
exitDeriveWithGuidance("No specs found in plan content. Ensure ## Specs section contains a fenced YAML code block.", EXIT_CODES.USAGE_ERROR, "Add a ## Specs section with a ```yaml fenced block, then re-run derive.");
|
|
417
846
|
}
|
|
418
|
-
|
|
419
|
-
const
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
const taskRef = `@${taskSlug}`;
|
|
436
|
-
const updatedPlan = await mutatePlanAtomically(ctx, foundPlan, (latestPlan) => {
|
|
437
|
-
const nextPlan = {
|
|
438
|
-
...latestPlan,
|
|
439
|
-
slugs: [...latestPlan.slugs],
|
|
440
|
-
derived_tasks: [...latestPlan.derived_tasks],
|
|
441
|
-
derived_specs: [...latestPlan.derived_specs],
|
|
442
|
-
notes: [...latestPlan.notes],
|
|
443
|
-
};
|
|
444
|
-
if (!nextPlan.derived_tasks.includes(taskRef)) {
|
|
445
|
-
nextPlan.derived_tasks.push(taskRef);
|
|
847
|
+
const { refIndex, items, tasks } = await buildIndexes(ctx, plans);
|
|
848
|
+
const reservedSlugs = new Set([
|
|
849
|
+
...plans.flatMap((plan) => plan.slugs),
|
|
850
|
+
...items.flatMap((item) => item.slugs),
|
|
851
|
+
...tasks.flatMap((task) => task.slugs),
|
|
852
|
+
]);
|
|
853
|
+
const materializedSpecs = await materializePlanSpecs(ctx, foundPlan, moduleRef, parsedPlan, refIndex, items, reservedSlugs, Boolean(options.dryRun), warnings, skipped);
|
|
854
|
+
const createdSpecRefs = materializedSpecs.map((item) => item.ref);
|
|
855
|
+
let taskPlans = [];
|
|
856
|
+
if (options.tasks) {
|
|
857
|
+
taskPlans = buildTaskPlans(planRef, materializedSpecs, parsedPlan.tasks.derive_from_specs, parsedPlan.tasks.additional_tasks, refIndex, tasks, reservedSlugs, author, warnings);
|
|
858
|
+
}
|
|
859
|
+
const createdTaskRefs = taskPlans.map((taskPlan) => taskPlan.ref);
|
|
860
|
+
if (!options.dryRun) {
|
|
861
|
+
for (const taskPlan of taskPlans) {
|
|
862
|
+
const newTask = createTask(taskPlan.input);
|
|
863
|
+
await saveTask(ctx, newTask);
|
|
446
864
|
}
|
|
447
|
-
|
|
448
|
-
|
|
865
|
+
const updatedPlan = await mutatePlanAtomically(ctx, foundPlan, (latestPlan) => {
|
|
866
|
+
const nextPlan = {
|
|
867
|
+
...latestPlan,
|
|
868
|
+
slugs: [...latestPlan.slugs],
|
|
869
|
+
derived_tasks: [...latestPlan.derived_tasks],
|
|
870
|
+
derived_specs: [...latestPlan.derived_specs],
|
|
871
|
+
notes: [...latestPlan.notes],
|
|
872
|
+
};
|
|
873
|
+
for (const specRef of createdSpecRefs) {
|
|
874
|
+
if (!nextPlan.derived_specs.includes(specRef)) {
|
|
875
|
+
nextPlan.derived_specs.push(specRef);
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
for (const taskRef of createdTaskRefs) {
|
|
879
|
+
if (!nextPlan.derived_tasks.includes(taskRef)) {
|
|
880
|
+
nextPlan.derived_tasks.push(taskRef);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
449
883
|
nextPlan.status = "active";
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
884
|
+
if (parsedPlan.implementationNotes?.trim()) {
|
|
885
|
+
nextPlan.notes.push(createNote(parsedPlan.implementationNotes.trim(), author));
|
|
886
|
+
}
|
|
887
|
+
return nextPlan;
|
|
888
|
+
});
|
|
889
|
+
await commitIfShadow(ctx.shadow, "plan-derive", updatedPlan.slugs[0] || updatedPlan._ulid.slice(0, 8), `${createdSpecRefs.length} specs${options.tasks ? `, ${createdTaskRefs.length} tasks` : ""}`);
|
|
890
|
+
}
|
|
891
|
+
else if (parsedPlan.implementationNotes?.trim()) {
|
|
892
|
+
warnings.push({
|
|
893
|
+
kind: "plan",
|
|
894
|
+
ref: planRef,
|
|
895
|
+
message: "Global implementation notes would be added to the plan during execution.",
|
|
896
|
+
});
|
|
897
|
+
}
|
|
898
|
+
reportWarnings(warnings);
|
|
899
|
+
emitDeriveResult({
|
|
900
|
+
dry_run: Boolean(options.dryRun),
|
|
901
|
+
plan_ref: planRef,
|
|
902
|
+
module_ref: moduleRef,
|
|
903
|
+
created_specs: createdSpecRefs,
|
|
904
|
+
created_tasks: createdTaskRefs,
|
|
905
|
+
skipped,
|
|
906
|
+
errors: errorsList,
|
|
457
907
|
});
|
|
458
908
|
}
|
|
459
909
|
catch (err) {
|
|
460
|
-
error("Failed to derive
|
|
910
|
+
error("Failed to derive plan content", err);
|
|
461
911
|
process.exit(EXIT_CODES.ERROR);
|
|
462
912
|
}
|
|
463
913
|
});
|