@kynetic-ai/spec 0.1.2 → 0.4.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 +250 -17
- package/dist/acp/client.d.ts +18 -4
- package/dist/acp/client.d.ts.map +1 -1
- package/dist/acp/client.js +44 -26
- package/dist/acp/client.js.map +1 -1
- package/dist/acp/framing.d.ts +2 -2
- package/dist/acp/framing.d.ts.map +1 -1
- package/dist/acp/framing.js +37 -29
- package/dist/acp/framing.js.map +1 -1
- package/dist/acp/index.d.ts +6 -7
- package/dist/acp/index.d.ts.map +1 -1
- package/dist/acp/index.js +3 -3
- package/dist/acp/index.js.map +1 -1
- package/dist/acp/types.d.ts +5 -5
- package/dist/acp/types.d.ts.map +1 -1
- package/dist/acp/types.js +18 -18
- package/dist/acp/types.js.map +1 -1
- package/dist/agents/adapters.d.ts.map +1 -1
- package/dist/agents/adapters.js +24 -13
- package/dist/agents/adapters.js.map +1 -1
- package/dist/agents/index.d.ts +2 -2
- package/dist/agents/index.js +2 -2
- package/dist/agents/spawner.d.ts +4 -4
- package/dist/agents/spawner.d.ts.map +1 -1
- package/dist/agents/spawner.js +6 -6
- package/dist/agents/spawner.js.map +1 -1
- package/dist/cli/batch-context.d.ts +43 -0
- package/dist/cli/batch-context.d.ts.map +1 -0
- package/dist/cli/batch-context.js +93 -0
- package/dist/cli/batch-context.js.map +1 -0
- package/dist/cli/batch-exec.d.ts +107 -0
- package/dist/cli/batch-exec.d.ts.map +1 -0
- package/dist/cli/batch-exec.js +706 -0
- package/dist/cli/batch-exec.js.map +1 -0
- package/dist/cli/batch.d.ts +4 -2
- package/dist/cli/batch.d.ts.map +1 -1
- package/dist/cli/batch.js +15 -14
- package/dist/cli/batch.js.map +1 -1
- package/dist/cli/command-annotations.d.ts +23 -0
- package/dist/cli/command-annotations.d.ts.map +1 -0
- package/dist/cli/command-annotations.js +27 -0
- package/dist/cli/command-annotations.js.map +1 -0
- package/dist/cli/commands/agents.d.ts +46 -0
- package/dist/cli/commands/agents.d.ts.map +1 -0
- package/dist/cli/commands/agents.js +377 -0
- package/dist/cli/commands/agents.js.map +1 -0
- package/dist/cli/commands/batch.d.ts +20 -0
- package/dist/cli/commands/batch.d.ts.map +1 -0
- package/dist/cli/commands/batch.js +214 -0
- package/dist/cli/commands/batch.js.map +1 -0
- package/dist/cli/commands/clone-for-testing.d.ts +1 -1
- package/dist/cli/commands/clone-for-testing.d.ts.map +1 -1
- package/dist/cli/commands/clone-for-testing.js +37 -47
- package/dist/cli/commands/clone-for-testing.js.map +1 -1
- package/dist/cli/commands/derive.d.ts +1 -1
- package/dist/cli/commands/derive.d.ts.map +1 -1
- package/dist/cli/commands/derive.js +141 -88
- package/dist/cli/commands/derive.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts +11 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +152 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/export.d.ts +12 -0
- package/dist/cli/commands/export.d.ts.map +1 -0
- package/dist/cli/commands/export.js +134 -0
- package/dist/cli/commands/export.js.map +1 -0
- package/dist/cli/commands/help.d.ts +1 -1
- package/dist/cli/commands/help.d.ts.map +1 -1
- package/dist/cli/commands/help.js +163 -37
- package/dist/cli/commands/help.js.map +1 -1
- package/dist/cli/commands/inbox.d.ts +1 -1
- package/dist/cli/commands/inbox.d.ts.map +1 -1
- package/dist/cli/commands/inbox.js +178 -56
- package/dist/cli/commands/inbox.js.map +1 -1
- package/dist/cli/commands/index.d.ts +31 -19
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +31 -19
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/init.d.ts +5 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +108 -57
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/item.d.ts +1 -1
- package/dist/cli/commands/item.d.ts.map +1 -1
- package/dist/cli/commands/item.js +557 -274
- package/dist/cli/commands/item.js.map +1 -1
- package/dist/cli/commands/link.d.ts +1 -1
- package/dist/cli/commands/link.d.ts.map +1 -1
- package/dist/cli/commands/link.js +55 -46
- package/dist/cli/commands/link.js.map +1 -1
- package/dist/cli/commands/log.d.ts +1 -1
- package/dist/cli/commands/log.d.ts.map +1 -1
- package/dist/cli/commands/log.js +58 -51
- package/dist/cli/commands/log.js.map +1 -1
- package/dist/cli/commands/merge-driver.d.ts +19 -0
- package/dist/cli/commands/merge-driver.d.ts.map +1 -0
- package/dist/cli/commands/merge-driver.js +398 -0
- package/dist/cli/commands/merge-driver.js.map +1 -0
- package/dist/cli/commands/meta.d.ts +1 -1
- package/dist/cli/commands/meta.d.ts.map +1 -1
- package/dist/cli/commands/meta.js +534 -399
- package/dist/cli/commands/meta.js.map +1 -1
- package/dist/cli/commands/module.d.ts +1 -1
- package/dist/cli/commands/module.d.ts.map +1 -1
- package/dist/cli/commands/module.js +30 -25
- package/dist/cli/commands/module.js.map +1 -1
- package/dist/cli/commands/plan-import.d.ts +11 -0
- package/dist/cli/commands/plan-import.d.ts.map +1 -0
- package/dist/cli/commands/plan-import.js +547 -0
- package/dist/cli/commands/plan-import.js.map +1 -0
- package/dist/cli/commands/plan.d.ts +10 -0
- package/dist/cli/commands/plan.d.ts.map +1 -0
- package/dist/cli/commands/plan.js +421 -0
- package/dist/cli/commands/plan.js.map +1 -0
- package/dist/cli/commands/ralph.d.ts +1 -1
- package/dist/cli/commands/ralph.d.ts.map +1 -1
- package/dist/cli/commands/ralph.js +1109 -170
- package/dist/cli/commands/ralph.js.map +1 -1
- package/dist/cli/commands/refs.d.ts +13 -0
- package/dist/cli/commands/refs.d.ts.map +1 -0
- package/dist/cli/commands/refs.js +283 -0
- package/dist/cli/commands/refs.js.map +1 -0
- package/dist/cli/commands/search.d.ts +1 -1
- package/dist/cli/commands/search.d.ts.map +1 -1
- package/dist/cli/commands/search.js +199 -37
- package/dist/cli/commands/search.js.map +1 -1
- package/dist/cli/commands/serve.d.ts +10 -0
- package/dist/cli/commands/serve.d.ts.map +1 -0
- package/dist/cli/commands/serve.js +491 -0
- package/dist/cli/commands/serve.js.map +1 -0
- package/dist/cli/commands/session.d.ts +25 -6
- package/dist/cli/commands/session.d.ts.map +1 -1
- package/dist/cli/commands/session.js +810 -127
- package/dist/cli/commands/session.js.map +1 -1
- package/dist/cli/commands/setup-seeding.d.ts +81 -0
- package/dist/cli/commands/setup-seeding.d.ts.map +1 -0
- package/dist/cli/commands/setup-seeding.js +292 -0
- package/dist/cli/commands/setup-seeding.js.map +1 -0
- package/dist/cli/commands/setup.d.ts +77 -3
- package/dist/cli/commands/setup.d.ts.map +1 -1
- package/dist/cli/commands/setup.js +1267 -274
- package/dist/cli/commands/setup.js.map +1 -1
- package/dist/cli/commands/shadow.d.ts +1 -1
- package/dist/cli/commands/shadow.d.ts.map +1 -1
- package/dist/cli/commands/shadow.js +70 -50
- package/dist/cli/commands/shadow.js.map +1 -1
- package/dist/cli/commands/skill-crud.d.ts +58 -0
- package/dist/cli/commands/skill-crud.d.ts.map +1 -0
- package/dist/cli/commands/skill-crud.js +753 -0
- package/dist/cli/commands/skill-crud.js.map +1 -0
- package/dist/cli/commands/skill-diff.d.ts +27 -0
- package/dist/cli/commands/skill-diff.d.ts.map +1 -0
- package/dist/cli/commands/skill-diff.js +840 -0
- package/dist/cli/commands/skill-diff.js.map +1 -0
- package/dist/cli/commands/skill-install.d.ts +56 -0
- package/dist/cli/commands/skill-install.d.ts.map +1 -0
- package/dist/cli/commands/skill-install.js +509 -0
- package/dist/cli/commands/skill-install.js.map +1 -0
- package/dist/cli/commands/skill.d.ts +20 -0
- package/dist/cli/commands/skill.d.ts.map +1 -0
- package/dist/cli/commands/skill.js +36 -0
- package/dist/cli/commands/skill.js.map +1 -0
- package/dist/cli/commands/task.d.ts +1 -1
- package/dist/cli/commands/task.d.ts.map +1 -1
- package/dist/cli/commands/task.js +584 -350
- package/dist/cli/commands/task.js.map +1 -1
- package/dist/cli/commands/tasks.d.ts +26 -1
- package/dist/cli/commands/tasks.d.ts.map +1 -1
- package/dist/cli/commands/tasks.js +225 -122
- package/dist/cli/commands/tasks.js.map +1 -1
- package/dist/cli/commands/trait.d.ts +1 -1
- package/dist/cli/commands/trait.d.ts.map +1 -1
- package/dist/cli/commands/trait.js +166 -101
- package/dist/cli/commands/trait.js.map +1 -1
- package/dist/cli/commands/triage.d.ts +7 -0
- package/dist/cli/commands/triage.d.ts.map +1 -0
- package/dist/cli/commands/triage.js +483 -0
- package/dist/cli/commands/triage.js.map +1 -0
- package/dist/cli/commands/util.d.ts +7 -0
- package/dist/cli/commands/util.d.ts.map +1 -0
- package/dist/cli/commands/util.js +30 -0
- package/dist/cli/commands/util.js.map +1 -0
- package/dist/cli/commands/validate.d.ts +1 -1
- package/dist/cli/commands/validate.d.ts.map +1 -1
- package/dist/cli/commands/validate.js +264 -83
- package/dist/cli/commands/validate.js.map +1 -1
- package/dist/cli/commands/workflow.d.ts +16 -0
- package/dist/cli/commands/workflow.d.ts.map +1 -0
- package/dist/cli/commands/workflow.js +851 -0
- package/dist/cli/commands/workflow.js.map +1 -0
- package/dist/cli/exit-codes.d.ts +7 -0
- package/dist/cli/exit-codes.d.ts.map +1 -1
- package/dist/cli/exit-codes.js +26 -18
- package/dist/cli/exit-codes.js.map +1 -1
- package/dist/cli/help/content.d.ts.map +1 -1
- package/dist/cli/help/content.js +86 -71
- package/dist/cli/help/content.js.map +1 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +131 -19
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/introspection.d.ts +6 -2
- package/dist/cli/introspection.d.ts.map +1 -1
- package/dist/cli/introspection.js +11 -8
- package/dist/cli/introspection.js.map +1 -1
- package/dist/cli/output.d.ts +64 -4
- package/dist/cli/output.d.ts.map +1 -1
- package/dist/cli/output.js +237 -85
- package/dist/cli/output.js.map +1 -1
- package/dist/cli/parse-utils.d.ts +21 -0
- package/dist/cli/parse-utils.d.ts.map +1 -0
- package/dist/cli/parse-utils.js +32 -0
- package/dist/cli/parse-utils.js.map +1 -0
- package/dist/cli/pid-utils.d.ts +72 -0
- package/dist/cli/pid-utils.d.ts.map +1 -0
- package/dist/cli/pid-utils.js +174 -0
- package/dist/cli/pid-utils.js.map +1 -0
- package/dist/cli/suggest.d.ts.map +1 -1
- package/dist/cli/suggest.js +1 -2
- package/dist/cli/suggest.js.map +1 -1
- package/dist/cli/validators.d.ts +43 -0
- package/dist/cli/validators.d.ts.map +1 -0
- package/dist/cli/validators.js +84 -0
- package/dist/cli/validators.js.map +1 -0
- package/dist/daemon/index.ts +52 -0
- package/dist/daemon/middleware/project-context.ts +126 -0
- package/dist/daemon/pid.ts +179 -0
- package/dist/daemon/project-context.ts +343 -0
- package/dist/daemon/routes/inbox.ts +164 -0
- package/dist/daemon/routes/items.ts +322 -0
- package/dist/daemon/routes/meta.ts +118 -0
- package/dist/daemon/routes/projects.ts +162 -0
- package/dist/daemon/routes/tasks.ts +327 -0
- package/dist/daemon/routes/triage.ts +402 -0
- package/dist/daemon/routes/validation.ts +248 -0
- package/dist/daemon/server.ts +408 -0
- package/dist/daemon/watcher.ts +195 -0
- package/dist/daemon/websocket/handler.ts +138 -0
- package/dist/daemon/websocket/heartbeat.ts +71 -0
- package/dist/daemon/websocket/pubsub.ts +125 -0
- package/dist/daemon/websocket/types.ts +66 -0
- package/dist/export/html.d.ts +19 -0
- package/dist/export/html.d.ts.map +1 -0
- package/dist/export/html.js +239 -0
- package/dist/export/html.js.map +1 -0
- package/dist/export/index.d.ts +10 -0
- package/dist/export/index.d.ts.map +1 -0
- package/dist/export/index.js +10 -0
- package/dist/export/index.js.map +1 -0
- package/dist/export/json.d.ts +24 -0
- package/dist/export/json.d.ts.map +1 -0
- package/dist/export/json.js +198 -0
- package/dist/export/json.js.map +1 -0
- package/dist/export/triage.d.ts +51 -0
- package/dist/export/triage.d.ts.map +1 -0
- package/dist/export/triage.js +83 -0
- package/dist/export/triage.js.map +1 -0
- package/dist/export/types.d.ts +122 -0
- package/dist/export/types.d.ts.map +1 -0
- package/dist/export/types.js +9 -0
- package/dist/export/types.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/lib/claude-plugin-registry.d.ts +66 -0
- package/dist/lib/claude-plugin-registry.d.ts.map +1 -0
- package/dist/lib/claude-plugin-registry.js +318 -0
- package/dist/lib/claude-plugin-registry.js.map +1 -0
- package/dist/merge/arrays.d.ts +87 -0
- package/dist/merge/arrays.d.ts.map +1 -0
- package/dist/merge/arrays.js +164 -0
- package/dist/merge/arrays.js.map +1 -0
- package/dist/merge/file-type.d.ts +32 -0
- package/dist/merge/file-type.d.ts.map +1 -0
- package/dist/merge/file-type.js +70 -0
- package/dist/merge/file-type.js.map +1 -0
- package/dist/merge/index.d.ts +14 -0
- package/dist/merge/index.d.ts.map +1 -0
- package/dist/merge/index.js +11 -0
- package/dist/merge/index.js.map +1 -0
- package/dist/merge/objects.d.ts +46 -0
- package/dist/merge/objects.d.ts.map +1 -0
- package/dist/merge/objects.js +193 -0
- package/dist/merge/objects.js.map +1 -0
- package/dist/merge/parse.d.ts +23 -0
- package/dist/merge/parse.d.ts.map +1 -0
- package/dist/merge/parse.js +78 -0
- package/dist/merge/parse.js.map +1 -0
- package/dist/merge/resolve.d.ts +66 -0
- package/dist/merge/resolve.d.ts.map +1 -0
- package/dist/merge/resolve.js +189 -0
- package/dist/merge/resolve.js.map +1 -0
- package/dist/merge/types.d.ts +82 -0
- package/dist/merge/types.d.ts.map +1 -0
- package/dist/merge/types.js +8 -0
- package/dist/merge/types.js.map +1 -0
- package/dist/parser/agent-data-sections.d.ts +53 -0
- package/dist/parser/agent-data-sections.d.ts.map +1 -0
- package/dist/parser/agent-data-sections.js +118 -0
- package/dist/parser/agent-data-sections.js.map +1 -0
- package/dist/parser/alignment.d.ts +4 -4
- package/dist/parser/alignment.d.ts.map +1 -1
- package/dist/parser/alignment.js +27 -22
- package/dist/parser/alignment.js.map +1 -1
- package/dist/parser/assess.d.ts +5 -5
- package/dist/parser/assess.d.ts.map +1 -1
- package/dist/parser/assess.js +36 -32
- package/dist/parser/assess.js.map +1 -1
- package/dist/parser/config.d.ts +457 -0
- package/dist/parser/config.d.ts.map +1 -0
- package/dist/parser/config.js +373 -0
- package/dist/parser/config.js.map +1 -0
- package/dist/parser/convention-validation.d.ts +1 -1
- package/dist/parser/convention-validation.d.ts.map +1 -1
- package/dist/parser/convention-validation.js +21 -16
- package/dist/parser/convention-validation.js.map +1 -1
- package/dist/parser/coverage-cache.d.ts +49 -0
- package/dist/parser/coverage-cache.d.ts.map +1 -0
- package/dist/parser/coverage-cache.js +123 -0
- package/dist/parser/coverage-cache.js.map +1 -0
- package/dist/parser/daemon-status.d.ts +37 -0
- package/dist/parser/daemon-status.d.ts.map +1 -0
- package/dist/parser/daemon-status.js +67 -0
- package/dist/parser/daemon-status.js.map +1 -0
- package/dist/parser/doctor.d.ts +107 -0
- package/dist/parser/doctor.d.ts.map +1 -0
- package/dist/parser/doctor.js +366 -0
- package/dist/parser/doctor.js.map +1 -0
- package/dist/parser/fix.d.ts +1 -1
- package/dist/parser/fix.d.ts.map +1 -1
- package/dist/parser/fix.js +31 -27
- package/dist/parser/fix.js.map +1 -1
- package/dist/parser/index.d.ts +16 -11
- package/dist/parser/index.d.ts.map +1 -1
- package/dist/parser/index.js +16 -11
- package/dist/parser/index.js.map +1 -1
- package/dist/parser/items.d.ts +8 -2
- package/dist/parser/items.d.ts.map +1 -1
- package/dist/parser/items.js +71 -35
- package/dist/parser/items.js.map +1 -1
- package/dist/parser/meta.d.ts +167 -9
- package/dist/parser/meta.d.ts.map +1 -1
- package/dist/parser/meta.js +379 -46
- package/dist/parser/meta.js.map +1 -1
- package/dist/parser/plan-document.d.ts +197 -0
- package/dist/parser/plan-document.d.ts.map +1 -0
- package/dist/parser/plan-document.js +341 -0
- package/dist/parser/plan-document.js.map +1 -0
- package/dist/parser/plans.d.ts +59 -0
- package/dist/parser/plans.d.ts.map +1 -0
- package/dist/parser/plans.js +239 -0
- package/dist/parser/plans.js.map +1 -0
- package/dist/parser/refs.d.ts +22 -9
- package/dist/parser/refs.d.ts.map +1 -1
- package/dist/parser/refs.js +102 -50
- package/dist/parser/refs.js.map +1 -1
- package/dist/parser/setup-status.d.ts +71 -0
- package/dist/parser/setup-status.d.ts.map +1 -0
- package/dist/parser/setup-status.js +269 -0
- package/dist/parser/setup-status.js.map +1 -0
- package/dist/parser/shadow.d.ts +150 -19
- package/dist/parser/shadow.d.ts.map +1 -1
- package/dist/parser/shadow.js +548 -187
- package/dist/parser/shadow.js.map +1 -1
- package/dist/parser/skill-render.d.ts +317 -0
- package/dist/parser/skill-render.d.ts.map +1 -0
- package/dist/parser/skill-render.js +943 -0
- package/dist/parser/skill-render.js.map +1 -0
- package/dist/parser/traits.d.ts +3 -3
- package/dist/parser/traits.d.ts.map +1 -1
- package/dist/parser/traits.js +2 -2
- package/dist/parser/traits.js.map +1 -1
- package/dist/parser/validate-skills.d.ts +32 -0
- package/dist/parser/validate-skills.d.ts.map +1 -0
- package/dist/parser/validate-skills.js +202 -0
- package/dist/parser/validate-skills.js.map +1 -0
- package/dist/parser/validate.d.ts +45 -3
- package/dist/parser/validate.d.ts.map +1 -1
- package/dist/parser/validate.js +622 -105
- package/dist/parser/validate.js.map +1 -1
- package/dist/parser/yaml.d.ts +83 -19
- package/dist/parser/yaml.d.ts.map +1 -1
- package/dist/parser/yaml.js +478 -173
- package/dist/parser/yaml.js.map +1 -1
- package/dist/ralph/cli-renderer.d.ts +8 -1
- package/dist/ralph/cli-renderer.d.ts.map +1 -1
- package/dist/ralph/cli-renderer.js +105 -34
- package/dist/ralph/cli-renderer.js.map +1 -1
- package/dist/ralph/events.d.ts +10 -10
- package/dist/ralph/events.d.ts.map +1 -1
- package/dist/ralph/events.js +301 -98
- package/dist/ralph/events.js.map +1 -1
- package/dist/ralph/index.d.ts +5 -2
- package/dist/ralph/index.d.ts.map +1 -1
- package/dist/ralph/index.js +9 -3
- package/dist/ralph/index.js.map +1 -1
- package/dist/ralph/loop-errors.d.ts +83 -0
- package/dist/ralph/loop-errors.d.ts.map +1 -0
- package/dist/ralph/loop-errors.js +150 -0
- package/dist/ralph/loop-errors.js.map +1 -0
- package/dist/ralph/subagent.d.ts +94 -0
- package/dist/ralph/subagent.d.ts.map +1 -0
- package/dist/ralph/subagent.js +193 -0
- package/dist/ralph/subagent.js.map +1 -0
- package/dist/ralph/wrap-up.d.ts +125 -0
- package/dist/ralph/wrap-up.d.ts.map +1 -0
- package/dist/ralph/wrap-up.js +270 -0
- package/dist/ralph/wrap-up.js.map +1 -0
- package/dist/schema/batch.d.ts +97 -0
- package/dist/schema/batch.d.ts.map +1 -0
- package/dist/schema/batch.js +24 -0
- package/dist/schema/batch.js.map +1 -0
- package/dist/schema/common.d.ts +8 -2
- package/dist/schema/common.d.ts.map +1 -1
- package/dist/schema/common.js +42 -31
- package/dist/schema/common.js.map +1 -1
- package/dist/schema/inbox.d.ts +12 -12
- package/dist/schema/inbox.js +4 -4
- package/dist/schema/inbox.js.map +1 -1
- package/dist/schema/index.d.ts +8 -5
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +8 -5
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/meta.d.ts +1454 -27
- package/dist/schema/meta.d.ts.map +1 -1
- package/dist/schema/meta.js +198 -21
- package/dist/schema/meta.js.map +1 -1
- package/dist/schema/plan.d.ts +285 -0
- package/dist/schema/plan.d.ts.map +1 -0
- package/dist/schema/plan.js +81 -0
- package/dist/schema/plan.js.map +1 -0
- package/dist/schema/spec.d.ts +72 -33
- package/dist/schema/spec.d.ts.map +1 -1
- package/dist/schema/spec.js +22 -9
- package/dist/schema/spec.js.map +1 -1
- package/dist/schema/task.d.ts +172 -161
- package/dist/schema/task.d.ts.map +1 -1
- package/dist/schema/task.js +21 -12
- package/dist/schema/task.js.map +1 -1
- package/dist/schema/triage.d.ts +266 -0
- package/dist/schema/triage.d.ts.map +1 -0
- package/dist/schema/triage.js +134 -0
- package/dist/schema/triage.js.map +1 -0
- package/dist/sessions/index.d.ts +2 -2
- package/dist/sessions/index.d.ts.map +1 -1
- package/dist/sessions/index.js +3 -3
- package/dist/sessions/index.js.map +1 -1
- package/dist/sessions/store.d.ts +241 -1
- package/dist/sessions/store.d.ts.map +1 -1
- package/dist/sessions/store.js +810 -31
- package/dist/sessions/store.js.map +1 -1
- package/dist/sessions/types.d.ts +10 -10
- package/dist/sessions/types.d.ts.map +1 -1
- package/dist/sessions/types.js +10 -9
- package/dist/sessions/types.js.map +1 -1
- package/dist/strings/errors.d.ts +55 -0
- package/dist/strings/errors.d.ts.map +1 -1
- package/dist/strings/errors.js +138 -106
- package/dist/strings/errors.js.map +1 -1
- package/dist/strings/guidance.d.ts.map +1 -1
- package/dist/strings/guidance.js +16 -16
- package/dist/strings/guidance.js.map +1 -1
- package/dist/strings/index.d.ts +4 -4
- package/dist/strings/index.d.ts.map +1 -1
- package/dist/strings/index.js +4 -4
- package/dist/strings/index.js.map +1 -1
- package/dist/strings/labels.d.ts +4 -0
- package/dist/strings/labels.d.ts.map +1 -1
- package/dist/strings/labels.js +45 -41
- package/dist/strings/labels.js.map +1 -1
- package/dist/strings/validation.d.ts.map +1 -1
- package/dist/strings/validation.js +71 -71
- package/dist/strings/validation.js.map +1 -1
- package/dist/triage/actions.d.ts +27 -0
- package/dist/triage/actions.d.ts.map +1 -0
- package/dist/triage/actions.js +95 -0
- package/dist/triage/actions.js.map +1 -0
- package/dist/triage/constants.d.ts +6 -0
- package/dist/triage/constants.d.ts.map +1 -0
- package/dist/triage/constants.js +7 -0
- package/dist/triage/constants.js.map +1 -0
- package/dist/triage/index.d.ts +3 -0
- package/dist/triage/index.d.ts.map +1 -0
- package/dist/triage/index.js +3 -0
- package/dist/triage/index.js.map +1 -0
- package/dist/utils/commit.d.ts +1 -1
- package/dist/utils/commit.d.ts.map +1 -1
- package/dist/utils/commit.js +28 -26
- package/dist/utils/commit.js.map +1 -1
- package/dist/utils/git.d.ts +1 -1
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +40 -38
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/grep.js +11 -11
- package/dist/utils/grep.js.map +1 -1
- package/dist/utils/index.d.ts +7 -7
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +4 -4
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/time.d.ts.map +1 -1
- package/dist/utils/time.js +10 -10
- package/dist/utils/time.js.map +1 -1
- package/package.json +28 -5
- package/plugin/.claude-plugin/marketplace.json +17 -0
- package/plugin/.claude-plugin/plugin.json +5 -0
- package/plugin/plugins/kspec/skills/create-workflow/SKILL.md +235 -0
- package/plugin/plugins/kspec/skills/help/SKILL.md +42 -0
- package/plugin/plugins/kspec/skills/observations/SKILL.md +143 -0
- package/plugin/plugins/kspec/skills/plan/SKILL.md +343 -0
- package/plugin/plugins/kspec/skills/reflect/SKILL.md +161 -0
- package/plugin/plugins/kspec/skills/review/SKILL.md +193 -0
- package/plugin/plugins/kspec/skills/task-work/SKILL.md +303 -0
- package/plugin/plugins/kspec/skills/triage/SKILL.md +206 -0
- package/plugin/plugins/kspec/skills/triage/docs/automation.md +120 -0
- package/plugin/plugins/kspec/skills/triage/docs/inbox.md +144 -0
- package/plugin/plugins/kspec/skills/triage/docs/observations.md +85 -0
- package/plugin/plugins/kspec/skills/triage-automation/SKILL.md +140 -0
- package/plugin/plugins/kspec/skills/triage-inbox/SKILL.md +232 -0
- package/plugin/plugins/kspec/skills/writing-specs/SKILL.md +340 -0
- package/templates/agents-sections/01-quick-start.md +22 -0
- package/templates/agents-sections/02-shadow-branch.md +34 -0
- package/templates/agents-sections/03-task-lifecycle.md +48 -0
- package/templates/agents-sections/04-pr-workflow.md +17 -0
- package/templates/agents-sections/05-commit-convention.md +27 -0
- package/templates/agents-sections/06-ralph-loop.md +45 -0
- package/templates/hooks/pre-commit +34 -0
- package/templates/skills/create-workflow/SKILL.md +228 -0
- package/templates/skills/help/SKILL.md +37 -0
- package/templates/skills/manifest.yaml +60 -0
- package/templates/skills/observations/SKILL.md +137 -0
- package/templates/skills/plan/SKILL.md +336 -0
- package/templates/skills/reflect/SKILL.md +155 -0
- package/templates/skills/review/SKILL.md +186 -0
- package/templates/skills/task-work/SKILL.md +296 -0
- package/templates/skills/triage/SKILL.md +199 -0
- package/templates/skills/triage/docs/automation.md +120 -0
- package/templates/skills/triage/docs/inbox.md +144 -0
- package/templates/skills/triage/docs/observations.md +85 -0
- package/templates/skills/triage-automation/SKILL.md +134 -0
- package/templates/skills/triage-inbox/SKILL.md +225 -0
- package/templates/skills/writing-specs/SKILL.md +333 -0
|
@@ -7,54 +7,64 @@
|
|
|
7
7
|
* AC-agent-1: kspec meta agents outputs table
|
|
8
8
|
* AC-agent-2: kspec meta agents --json outputs JSON
|
|
9
9
|
*/
|
|
10
|
-
import chalk from
|
|
11
|
-
import Table from
|
|
12
|
-
import { ulid } from
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
10
|
+
import chalk from "chalk";
|
|
11
|
+
import Table from "cli-table3";
|
|
12
|
+
import { ulid } from "ulid";
|
|
13
|
+
import { markMutating } from "../command-annotations.js";
|
|
14
|
+
import { createObservation, createTask, deleteInboxItem, deleteMetaItem, findInboxItemByRef, getMetaStats, initContext, loadAllItems, loadAllTasks, loadInboxItems, loadMetaContext, loadSessionContext, ReferenceIndex, resolveMetaRef, saveMetaItem, saveObservation, saveSessionContext, saveTask, } from "../../parser/index.js";
|
|
15
|
+
import { commitIfShadow } from "../../parser/shadow.js";
|
|
16
|
+
import { normalizeRefInput } from "../../schema/index.js";
|
|
17
|
+
import { z } from "zod";
|
|
18
|
+
import { WorkflowStepSchema, } from "../../schema/index.js";
|
|
19
|
+
import { errors } from "../../strings/errors.js";
|
|
20
|
+
import { executeBatchOperation, formatBatchOutput } from "../batch.js";
|
|
21
|
+
import { EXIT_CODES } from "../exit-codes.js";
|
|
22
|
+
import { error, isJsonMode, output, success } from "../output.js";
|
|
23
|
+
import { parseTagsArray } from "../parse-utils.js";
|
|
24
|
+
import { parseIntOption } from "../validators.js";
|
|
18
25
|
/**
|
|
19
|
-
* Resolve a meta reference to its ULID
|
|
20
|
-
*
|
|
26
|
+
* Resolve a meta reference to its ULID and type.
|
|
27
|
+
* Wrapper around resolveMetaRef for backward compatibility with existing call sites.
|
|
28
|
+
* AC: @skill-meta-integration ac-4 - skills included in resolution
|
|
21
29
|
*/
|
|
22
30
|
function resolveMetaRefToUlid(ref, metaCtx) {
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return null;
|
|
31
|
+
const result = resolveMetaRef(metaCtx, ref);
|
|
32
|
+
if (!result)
|
|
33
|
+
return null;
|
|
34
|
+
return { ulid: result.ulid, type: result.type };
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Batch-compatible resolver for observations.
|
|
38
|
+
* Returns null instead of calling process.exit() to allow partial failure handling.
|
|
39
|
+
* AC: @trait-multi-ref-batch ac-2, ac-8 - Partial failure handling and ref resolution
|
|
40
|
+
*/
|
|
41
|
+
function resolveObservationRefForBatch(ref, observations) {
|
|
42
|
+
const normalizedRef = ref.startsWith("@") ? ref.substring(1) : ref;
|
|
43
|
+
const observation = observations.find((o) => o._ulid.startsWith(normalizedRef));
|
|
44
|
+
if (!observation) {
|
|
45
|
+
return { item: null, error: `Observation not found: ${ref}` };
|
|
46
|
+
}
|
|
47
|
+
return { item: observation };
|
|
41
48
|
}
|
|
42
49
|
/**
|
|
43
50
|
* Format meta show output
|
|
51
|
+
* AC: @skill-meta-integration ac-3 - skill count included in summary
|
|
44
52
|
*/
|
|
45
53
|
function formatMetaShow(meta) {
|
|
46
54
|
const stats = getMetaStats(meta);
|
|
47
55
|
if (!meta.manifest) {
|
|
48
|
-
console.log(chalk.yellow(
|
|
49
|
-
console.log(chalk.gray(
|
|
56
|
+
console.log(chalk.yellow("No meta manifest found (kynetic.meta.yaml)"));
|
|
57
|
+
console.log(chalk.gray("Create one to define agents, workflows, conventions, observations, and skills"));
|
|
50
58
|
return;
|
|
51
59
|
}
|
|
52
|
-
console.log(chalk.bold(
|
|
53
|
-
console.log(chalk.gray(
|
|
60
|
+
console.log(chalk.bold("Meta-Spec Summary"));
|
|
61
|
+
console.log(chalk.gray("─".repeat(40)));
|
|
54
62
|
console.log(`Agents: ${stats.agents}`);
|
|
55
63
|
console.log(`Workflows: ${stats.workflows}`);
|
|
56
64
|
console.log(`Conventions: ${stats.conventions}`);
|
|
57
65
|
console.log(`Observations: ${stats.observations} (${stats.unresolvedObservations} unresolved)`);
|
|
66
|
+
// AC: @skill-meta-integration ac-3 - include skill count
|
|
67
|
+
console.log(`Skills: ${stats.skills}`);
|
|
58
68
|
}
|
|
59
69
|
/**
|
|
60
70
|
* Format agents table output
|
|
@@ -62,36 +72,37 @@ function formatMetaShow(meta) {
|
|
|
62
72
|
*/
|
|
63
73
|
function formatAgents(agents) {
|
|
64
74
|
if (agents.length === 0) {
|
|
65
|
-
console.log(chalk.yellow(
|
|
75
|
+
console.log(chalk.yellow("No agents defined"));
|
|
66
76
|
return;
|
|
67
77
|
}
|
|
68
78
|
const table = new Table({
|
|
69
|
-
head: [chalk.bold(
|
|
79
|
+
head: [chalk.bold("ID"), chalk.bold("Name"), chalk.bold("Capabilities")],
|
|
70
80
|
style: {
|
|
71
81
|
head: [],
|
|
72
82
|
border: [],
|
|
73
83
|
},
|
|
74
84
|
});
|
|
75
85
|
for (const agent of agents) {
|
|
76
|
-
table.push([
|
|
77
|
-
agent.id,
|
|
78
|
-
agent.name,
|
|
79
|
-
agent.capabilities.join(', '),
|
|
80
|
-
]);
|
|
86
|
+
table.push([agent.id, agent.name, agent.capabilities.join(", ")]);
|
|
81
87
|
}
|
|
82
88
|
console.log(table.toString());
|
|
83
89
|
}
|
|
84
90
|
/**
|
|
85
91
|
* Format workflows table output
|
|
86
|
-
* AC-workflow-1: outputs table with columns: ID, Trigger, Steps (count)
|
|
92
|
+
* AC-workflow-1: outputs table with columns: ID, Trigger, Steps (count), Mode
|
|
87
93
|
*/
|
|
88
94
|
function formatWorkflows(workflows) {
|
|
89
95
|
if (workflows.length === 0) {
|
|
90
|
-
console.log(chalk.yellow(
|
|
96
|
+
console.log(chalk.yellow("No workflows defined"));
|
|
91
97
|
return;
|
|
92
98
|
}
|
|
93
99
|
const table = new Table({
|
|
94
|
-
head: [
|
|
100
|
+
head: [
|
|
101
|
+
chalk.bold("ID"),
|
|
102
|
+
chalk.bold("Trigger"),
|
|
103
|
+
chalk.bold("Steps"),
|
|
104
|
+
chalk.bold("Mode"),
|
|
105
|
+
],
|
|
95
106
|
style: {
|
|
96
107
|
head: [],
|
|
97
108
|
border: [],
|
|
@@ -102,6 +113,7 @@ function formatWorkflows(workflows) {
|
|
|
102
113
|
workflow.id,
|
|
103
114
|
workflow.trigger,
|
|
104
115
|
workflow.steps.length.toString(),
|
|
116
|
+
workflow.mode || "interactive",
|
|
105
117
|
]);
|
|
106
118
|
}
|
|
107
119
|
console.log(table.toString());
|
|
@@ -109,23 +121,32 @@ function formatWorkflows(workflows) {
|
|
|
109
121
|
/**
|
|
110
122
|
* Format workflows verbose output
|
|
111
123
|
* AC-workflow-2: outputs each workflow with full step list
|
|
124
|
+
* AC: @loop-mode-workflows ac-3 (shows based_on field)
|
|
112
125
|
*/
|
|
113
126
|
function formatWorkflowsVerbose(workflows) {
|
|
114
127
|
if (workflows.length === 0) {
|
|
115
|
-
console.log(chalk.yellow(
|
|
128
|
+
console.log(chalk.yellow("No workflows defined"));
|
|
116
129
|
return;
|
|
117
130
|
}
|
|
118
131
|
for (const workflow of workflows) {
|
|
119
132
|
console.log(chalk.bold(`${workflow.id} - ${workflow.trigger}`));
|
|
133
|
+
// Show mode if it's loop (skip for interactive as it's default)
|
|
134
|
+
if (workflow.mode === "loop") {
|
|
135
|
+
console.log(chalk.cyan(`Mode: ${workflow.mode}`));
|
|
136
|
+
}
|
|
137
|
+
// AC: @loop-mode-workflows ac-3 - Show based_on reference
|
|
138
|
+
if (workflow.based_on) {
|
|
139
|
+
console.log(chalk.cyan(`Based on: ${workflow.based_on}`));
|
|
140
|
+
}
|
|
120
141
|
if (workflow.description) {
|
|
121
142
|
console.log(chalk.gray(workflow.description));
|
|
122
143
|
}
|
|
123
|
-
console.log(chalk.gray(
|
|
144
|
+
console.log(chalk.gray("─".repeat(60)));
|
|
124
145
|
for (const step of workflow.steps) {
|
|
125
146
|
const prefix = {
|
|
126
|
-
check: chalk.yellow(
|
|
127
|
-
action: chalk.blue(
|
|
128
|
-
decision: chalk.magenta(
|
|
147
|
+
check: chalk.yellow("[check]"),
|
|
148
|
+
action: chalk.blue("[action]"),
|
|
149
|
+
decision: chalk.magenta("[decision]"),
|
|
129
150
|
}[step.type];
|
|
130
151
|
console.log(`${prefix} ${step.content}`);
|
|
131
152
|
if (step.on_fail) {
|
|
@@ -137,7 +158,7 @@ function formatWorkflowsVerbose(workflows) {
|
|
|
137
158
|
}
|
|
138
159
|
}
|
|
139
160
|
}
|
|
140
|
-
console.log(
|
|
161
|
+
console.log("");
|
|
141
162
|
}
|
|
142
163
|
}
|
|
143
164
|
/**
|
|
@@ -146,11 +167,11 @@ function formatWorkflowsVerbose(workflows) {
|
|
|
146
167
|
*/
|
|
147
168
|
function formatConventions(conventions) {
|
|
148
169
|
if (conventions.length === 0) {
|
|
149
|
-
console.log(chalk.yellow(
|
|
170
|
+
console.log(chalk.yellow("No conventions defined"));
|
|
150
171
|
return;
|
|
151
172
|
}
|
|
152
173
|
const table = new Table({
|
|
153
|
-
head: [chalk.bold(
|
|
174
|
+
head: [chalk.bold("Domain"), chalk.bold("Rules"), chalk.bold("Validation")],
|
|
154
175
|
style: {
|
|
155
176
|
head: [],
|
|
156
177
|
border: [],
|
|
@@ -160,7 +181,7 @@ function formatConventions(conventions) {
|
|
|
160
181
|
table.push([
|
|
161
182
|
convention.domain,
|
|
162
183
|
convention.rules.length.toString(),
|
|
163
|
-
convention.validation ?
|
|
184
|
+
convention.validation ? "yes" : "no",
|
|
164
185
|
]);
|
|
165
186
|
}
|
|
166
187
|
console.log(table.toString());
|
|
@@ -171,20 +192,20 @@ function formatConventions(conventions) {
|
|
|
171
192
|
*/
|
|
172
193
|
function formatConventionDetail(convention) {
|
|
173
194
|
console.log(chalk.bold(`${convention.domain} Convention`));
|
|
174
|
-
console.log(chalk.gray(
|
|
175
|
-
console.log(chalk.bold(
|
|
195
|
+
console.log(chalk.gray("─".repeat(60)));
|
|
196
|
+
console.log(chalk.bold("\nRules:"));
|
|
176
197
|
for (const rule of convention.rules) {
|
|
177
198
|
console.log(` • ${rule}`);
|
|
178
199
|
}
|
|
179
200
|
if (convention.examples && convention.examples.length > 0) {
|
|
180
|
-
console.log(chalk.bold(
|
|
201
|
+
console.log(chalk.bold("\nExamples:"));
|
|
181
202
|
for (const example of convention.examples) {
|
|
182
203
|
console.log(chalk.green(` ✓ ${example.good}`));
|
|
183
204
|
console.log(chalk.red(` ✗ ${example.bad}`));
|
|
184
205
|
}
|
|
185
206
|
}
|
|
186
207
|
if (convention.validation) {
|
|
187
|
-
console.log(chalk.bold(
|
|
208
|
+
console.log(chalk.bold("\nValidation:"));
|
|
188
209
|
console.log(` Type: ${convention.validation.type}`);
|
|
189
210
|
if (convention.validation.pattern) {
|
|
190
211
|
console.log(` Pattern: ${convention.validation.pattern}`);
|
|
@@ -193,39 +214,69 @@ function formatConventionDetail(convention) {
|
|
|
193
214
|
console.log(` Message: ${convention.validation.message}`);
|
|
194
215
|
}
|
|
195
216
|
}
|
|
196
|
-
console.log(
|
|
217
|
+
console.log("");
|
|
197
218
|
}
|
|
198
219
|
/**
|
|
199
220
|
* Format observations table output
|
|
200
221
|
* AC-obs-2: outputs table with columns: ID, Type, Workflow, Created, Content (truncated)
|
|
222
|
+
* AC: @obs-list-display ac-1 - When --all flag used, show Resolved column with ✓/✗
|
|
201
223
|
*/
|
|
202
224
|
function formatObservations(observations, showResolved) {
|
|
203
|
-
const filtered = showResolved
|
|
225
|
+
const filtered = showResolved
|
|
226
|
+
? observations
|
|
227
|
+
: observations.filter((o) => !o.resolved);
|
|
204
228
|
if (filtered.length === 0) {
|
|
205
|
-
console.log(chalk.yellow(showResolved ?
|
|
229
|
+
console.log(chalk.yellow(showResolved ? "No observations found" : "No unresolved observations"));
|
|
206
230
|
return;
|
|
207
231
|
}
|
|
232
|
+
// AC: @obs-list-display ac-1 - Include Resolved column when showing all observations
|
|
233
|
+
const headers = showResolved
|
|
234
|
+
? [
|
|
235
|
+
chalk.bold("ID"),
|
|
236
|
+
chalk.bold("Type"),
|
|
237
|
+
chalk.bold("Resolved"),
|
|
238
|
+
chalk.bold("Workflow"),
|
|
239
|
+
chalk.bold("Created"),
|
|
240
|
+
chalk.bold("Content"),
|
|
241
|
+
]
|
|
242
|
+
: [
|
|
243
|
+
chalk.bold("ID"),
|
|
244
|
+
chalk.bold("Type"),
|
|
245
|
+
chalk.bold("Workflow"),
|
|
246
|
+
chalk.bold("Created"),
|
|
247
|
+
chalk.bold("Content"),
|
|
248
|
+
];
|
|
249
|
+
const colWidths = showResolved
|
|
250
|
+
? [10, 10, 10, 20, 12, 40]
|
|
251
|
+
: [10, 10, 20, 12, 50];
|
|
208
252
|
const table = new Table({
|
|
209
|
-
head:
|
|
210
|
-
chalk.bold('ID'),
|
|
211
|
-
chalk.bold('Type'),
|
|
212
|
-
chalk.bold('Workflow'),
|
|
213
|
-
chalk.bold('Created'),
|
|
214
|
-
chalk.bold('Content'),
|
|
215
|
-
],
|
|
253
|
+
head: headers,
|
|
216
254
|
style: {
|
|
217
255
|
head: [],
|
|
218
256
|
border: [],
|
|
219
257
|
},
|
|
220
|
-
colWidths
|
|
258
|
+
colWidths,
|
|
221
259
|
wordWrap: true,
|
|
222
260
|
});
|
|
223
261
|
for (const obs of filtered) {
|
|
224
262
|
const id = obs._ulid.substring(0, 8);
|
|
225
|
-
const workflow = obs.workflow_ref ||
|
|
226
|
-
const created = new Date(obs.created_at).toISOString().split(
|
|
227
|
-
|
|
228
|
-
|
|
263
|
+
const workflow = obs.workflow_ref || "-";
|
|
264
|
+
const created = new Date(obs.created_at).toISOString().split("T")[0];
|
|
265
|
+
// Adjust content truncation based on available column width
|
|
266
|
+
const maxContentLen = showResolved ? 37 : 47;
|
|
267
|
+
const content = obs.content.length > maxContentLen
|
|
268
|
+
? `${obs.content.substring(0, maxContentLen)}...`
|
|
269
|
+
: obs.content;
|
|
270
|
+
// AC: @obs-list-display ac-1 - Show ✓ for resolved, ✗ for unresolved
|
|
271
|
+
if (showResolved) {
|
|
272
|
+
const resolvedIndicator = obs.resolved
|
|
273
|
+
? chalk.green("✓")
|
|
274
|
+
: chalk.red("✗");
|
|
275
|
+
table.push([id, obs.type, resolvedIndicator, workflow, created, content]);
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
table.push([id, obs.type, workflow, created, content]);
|
|
279
|
+
}
|
|
229
280
|
}
|
|
230
281
|
console.log(table.toString());
|
|
231
282
|
}
|
|
@@ -234,12 +285,12 @@ function formatObservations(observations, showResolved) {
|
|
|
234
285
|
*/
|
|
235
286
|
export function registerMetaCommands(program) {
|
|
236
287
|
const meta = program
|
|
237
|
-
.command(
|
|
238
|
-
.description(
|
|
288
|
+
.command("meta")
|
|
289
|
+
.description("Meta-spec commands (agents, workflows, conventions, observations)");
|
|
239
290
|
// AC-meta-manifest-1: kspec meta show outputs summary with counts
|
|
240
291
|
meta
|
|
241
|
-
.command(
|
|
242
|
-
.description(
|
|
292
|
+
.command("show")
|
|
293
|
+
.description("Display meta-spec summary")
|
|
243
294
|
.action(async () => {
|
|
244
295
|
try {
|
|
245
296
|
const ctx = await initContext();
|
|
@@ -261,8 +312,8 @@ export function registerMetaCommands(program) {
|
|
|
261
312
|
});
|
|
262
313
|
// AC-agent-1, AC-agent-2: kspec meta agents
|
|
263
314
|
meta
|
|
264
|
-
.command(
|
|
265
|
-
.description(
|
|
315
|
+
.command("agents")
|
|
316
|
+
.description("List agents defined in meta-spec")
|
|
266
317
|
.action(async () => {
|
|
267
318
|
try {
|
|
268
319
|
const ctx = await initContext();
|
|
@@ -291,10 +342,12 @@ export function registerMetaCommands(program) {
|
|
|
291
342
|
}
|
|
292
343
|
});
|
|
293
344
|
// AC-workflow-1, AC-workflow-2, AC-workflow-4: kspec meta workflows
|
|
345
|
+
// AC: @loop-mode-workflows ac-1 (--tag loop filtering)
|
|
294
346
|
meta
|
|
295
|
-
.command(
|
|
296
|
-
.description(
|
|
297
|
-
.option(
|
|
347
|
+
.command("workflows")
|
|
348
|
+
.description("List workflows defined in meta-spec")
|
|
349
|
+
.option("--verbose", "Show full workflow details with all steps")
|
|
350
|
+
.option("--tag <tag>", "Filter workflows by tag (e.g., --tag loop)")
|
|
298
351
|
.action(async (options) => {
|
|
299
352
|
try {
|
|
300
353
|
const ctx = await initContext();
|
|
@@ -303,13 +356,29 @@ export function registerMetaCommands(program) {
|
|
|
303
356
|
process.exit(EXIT_CODES.ERROR);
|
|
304
357
|
}
|
|
305
358
|
const metaCtx = await loadMetaContext(ctx);
|
|
306
|
-
|
|
359
|
+
let workflows = metaCtx.workflows || [];
|
|
360
|
+
// AC: @loop-mode-workflows ac-1 - Filter by tag
|
|
361
|
+
if (options.tag) {
|
|
362
|
+
workflows = workflows.filter((w) => {
|
|
363
|
+
// Match by explicit tags array or by mode field (for "loop" tag)
|
|
364
|
+
const tags = w.tags || [];
|
|
365
|
+
if (tags.includes(options.tag))
|
|
366
|
+
return true;
|
|
367
|
+
// Special case: --tag loop also matches mode: loop
|
|
368
|
+
if (options.tag === "loop" && w.mode === "loop")
|
|
369
|
+
return true;
|
|
370
|
+
return false;
|
|
371
|
+
});
|
|
372
|
+
}
|
|
307
373
|
// AC-workflow-4: JSON output includes full workflow details
|
|
308
374
|
output(workflows.map((workflow) => ({
|
|
309
375
|
id: workflow.id,
|
|
310
376
|
trigger: workflow.trigger,
|
|
311
377
|
description: workflow.description,
|
|
312
378
|
steps: workflow.steps,
|
|
379
|
+
mode: workflow.mode || "interactive",
|
|
380
|
+
based_on: workflow.based_on,
|
|
381
|
+
tags: workflow.tags || [],
|
|
313
382
|
})),
|
|
314
383
|
// AC-workflow-1 (table) or AC-workflow-2 (verbose)
|
|
315
384
|
() => {
|
|
@@ -328,9 +397,9 @@ export function registerMetaCommands(program) {
|
|
|
328
397
|
});
|
|
329
398
|
// AC-conv-1, AC-conv-2, AC-conv-5: kspec meta conventions
|
|
330
399
|
meta
|
|
331
|
-
.command(
|
|
332
|
-
.description(
|
|
333
|
-
.option(
|
|
400
|
+
.command("conventions")
|
|
401
|
+
.description("List conventions defined in meta-spec")
|
|
402
|
+
.option("--domain <domain>", "Filter by specific domain")
|
|
334
403
|
.action(async (options) => {
|
|
335
404
|
try {
|
|
336
405
|
const ctx = await initContext();
|
|
@@ -367,9 +436,10 @@ export function registerMetaCommands(program) {
|
|
|
367
436
|
}
|
|
368
437
|
});
|
|
369
438
|
// meta-get-cmd: kspec meta get <ref>
|
|
439
|
+
// AC: @skill-meta-integration ac-1 - skills can be retrieved by id
|
|
370
440
|
meta
|
|
371
|
-
.command(
|
|
372
|
-
.description(
|
|
441
|
+
.command("get <ref>")
|
|
442
|
+
.description("Get a meta item by reference (agent, workflow, convention, observation, or skill)")
|
|
373
443
|
.action(async (ref) => {
|
|
374
444
|
try {
|
|
375
445
|
const ctx = await initContext();
|
|
@@ -378,54 +448,17 @@ export function registerMetaCommands(program) {
|
|
|
378
448
|
process.exit(EXIT_CODES.ERROR);
|
|
379
449
|
}
|
|
380
450
|
const metaCtx = await loadMetaContext(ctx);
|
|
381
|
-
//
|
|
382
|
-
const
|
|
383
|
-
|
|
384
|
-
const agents = metaCtx.agents || [];
|
|
385
|
-
const workflows = metaCtx.workflows || [];
|
|
386
|
-
const conventions = metaCtx.conventions || [];
|
|
387
|
-
const observations = metaCtx.observations || [];
|
|
388
|
-
// Try to find by ID or ULID prefix
|
|
389
|
-
let found = null;
|
|
390
|
-
let itemType = '';
|
|
391
|
-
// Check agents (by id or ULID)
|
|
392
|
-
const agent = agents.find((a) => a.id === normalizedRef || a._ulid.startsWith(normalizedRef));
|
|
393
|
-
if (agent) {
|
|
394
|
-
found = agent;
|
|
395
|
-
itemType = 'agent';
|
|
396
|
-
}
|
|
397
|
-
// Check workflows (by id or ULID)
|
|
398
|
-
if (!found) {
|
|
399
|
-
const workflow = workflows.find((w) => w.id === normalizedRef || w._ulid.startsWith(normalizedRef));
|
|
400
|
-
if (workflow) {
|
|
401
|
-
found = workflow;
|
|
402
|
-
itemType = 'workflow';
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
// Check conventions (by domain or ULID)
|
|
406
|
-
if (!found) {
|
|
407
|
-
const convention = conventions.find((c) => c.domain === normalizedRef || c._ulid.startsWith(normalizedRef));
|
|
408
|
-
if (convention) {
|
|
409
|
-
found = convention;
|
|
410
|
-
itemType = 'convention';
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
// Check observations (by ULID)
|
|
414
|
-
if (!found) {
|
|
415
|
-
const observation = observations.find((o) => o._ulid.startsWith(normalizedRef));
|
|
416
|
-
if (observation) {
|
|
417
|
-
found = observation;
|
|
418
|
-
itemType = 'observation';
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
if (!found) {
|
|
451
|
+
// AC: @skill-meta-integration ac-1 - Use unified resolver
|
|
452
|
+
const resolved = resolveMetaRef(metaCtx, ref);
|
|
453
|
+
if (!resolved) {
|
|
422
454
|
error(errors.reference.metaNotFound(ref));
|
|
423
455
|
process.exit(EXIT_CODES.ERROR);
|
|
424
456
|
}
|
|
457
|
+
const { item: found, type: itemType } = resolved;
|
|
425
458
|
// Output the item
|
|
426
459
|
output(found, () => {
|
|
427
460
|
console.log(chalk.bold(`${itemType.charAt(0).toUpperCase() + itemType.slice(1)}: ${ref}`));
|
|
428
|
-
console.log(chalk.gray(
|
|
461
|
+
console.log(chalk.gray("─".repeat(60)));
|
|
429
462
|
console.log(JSON.stringify(found, null, 2));
|
|
430
463
|
});
|
|
431
464
|
}
|
|
@@ -435,10 +468,11 @@ export function registerMetaCommands(program) {
|
|
|
435
468
|
}
|
|
436
469
|
});
|
|
437
470
|
// meta-list-cmd: kspec meta list
|
|
471
|
+
// AC: @skill-meta-integration ac-2 - skills can be filtered with --type skill
|
|
438
472
|
meta
|
|
439
|
-
.command(
|
|
440
|
-
.description(
|
|
441
|
-
.option(
|
|
473
|
+
.command("list")
|
|
474
|
+
.description("List all meta items")
|
|
475
|
+
.option("--type <type>", "Filter by type (agent, workflow, convention, observation, skill)")
|
|
442
476
|
.action(async (options) => {
|
|
443
477
|
try {
|
|
444
478
|
const ctx = await initContext();
|
|
@@ -449,58 +483,69 @@ export function registerMetaCommands(program) {
|
|
|
449
483
|
const metaCtx = await loadMetaContext(ctx);
|
|
450
484
|
const items = [];
|
|
451
485
|
// Add agents
|
|
452
|
-
if (!options.type || options.type ===
|
|
486
|
+
if (!options.type || options.type === "agent") {
|
|
453
487
|
for (const agent of metaCtx.agents || []) {
|
|
454
488
|
items.push({
|
|
455
489
|
id: agent.id,
|
|
456
|
-
type:
|
|
490
|
+
type: "agent",
|
|
457
491
|
context: agent.name,
|
|
458
492
|
ulid: agent._ulid,
|
|
459
493
|
});
|
|
460
494
|
}
|
|
461
495
|
}
|
|
462
496
|
// Add workflows
|
|
463
|
-
if (!options.type || options.type ===
|
|
497
|
+
if (!options.type || options.type === "workflow") {
|
|
464
498
|
for (const workflow of metaCtx.workflows || []) {
|
|
465
499
|
items.push({
|
|
466
500
|
id: workflow.id,
|
|
467
|
-
type:
|
|
501
|
+
type: "workflow",
|
|
468
502
|
context: workflow.trigger,
|
|
469
503
|
ulid: workflow._ulid,
|
|
470
504
|
});
|
|
471
505
|
}
|
|
472
506
|
}
|
|
473
507
|
// Add conventions
|
|
474
|
-
if (!options.type || options.type ===
|
|
508
|
+
if (!options.type || options.type === "convention") {
|
|
475
509
|
for (const convention of metaCtx.conventions || []) {
|
|
476
510
|
items.push({
|
|
477
511
|
id: convention.domain,
|
|
478
|
-
type:
|
|
512
|
+
type: "convention",
|
|
479
513
|
context: `${convention.rules.length} rules`,
|
|
480
514
|
ulid: convention._ulid,
|
|
481
515
|
});
|
|
482
516
|
}
|
|
483
517
|
}
|
|
484
518
|
// Add observations
|
|
485
|
-
if (!options.type || options.type ===
|
|
519
|
+
if (!options.type || options.type === "observation") {
|
|
486
520
|
for (const observation of metaCtx.observations || []) {
|
|
487
521
|
const ulidPrefix = observation._ulid.substring(0, 8);
|
|
488
522
|
items.push({
|
|
489
523
|
id: ulidPrefix,
|
|
490
|
-
type:
|
|
491
|
-
context: `${observation.type} ${observation.resolved ?
|
|
524
|
+
type: "observation",
|
|
525
|
+
context: `${observation.type} ${observation.resolved ? "(resolved)" : ""}`,
|
|
492
526
|
ulid: observation._ulid,
|
|
493
527
|
});
|
|
494
528
|
}
|
|
495
529
|
}
|
|
530
|
+
// AC: @skill-meta-integration ac-2 - Add skills
|
|
531
|
+
if (!options.type || options.type === "skill") {
|
|
532
|
+
for (const skill of metaCtx.skills || []) {
|
|
533
|
+
items.push({
|
|
534
|
+
id: skill.id,
|
|
535
|
+
type: "skill",
|
|
536
|
+
context: skill.name || skill.description || skill.origin,
|
|
537
|
+
ulid: skill._ulid,
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
}
|
|
496
541
|
// Output
|
|
497
542
|
output(items, () => {
|
|
498
543
|
if (items.length === 0) {
|
|
499
|
-
console.log(chalk.yellow(
|
|
544
|
+
console.log(chalk.yellow("No meta items found"));
|
|
500
545
|
return;
|
|
501
546
|
}
|
|
502
547
|
const table = new Table({
|
|
503
|
-
head: [chalk.bold(
|
|
548
|
+
head: [chalk.bold("ID"), chalk.bold("Type"), chalk.bold("Context")],
|
|
504
549
|
style: {
|
|
505
550
|
head: [],
|
|
506
551
|
border: [],
|
|
@@ -519,13 +564,12 @@ export function registerMetaCommands(program) {
|
|
|
519
564
|
});
|
|
520
565
|
// AC-obs-1: kspec meta observe <type> <content>
|
|
521
566
|
// AC: @meta-observe-cmd from-inbox-conversion
|
|
522
|
-
meta
|
|
523
|
-
.
|
|
524
|
-
.
|
|
525
|
-
.option(
|
|
526
|
-
.option(
|
|
527
|
-
.option(
|
|
528
|
-
.option('--type <type>', 'Override type when using --from-inbox (defaults to idea)')
|
|
567
|
+
markMutating(meta.command("observe [type] [content]"))
|
|
568
|
+
.description("Create an observation (friction, success, question, idea)")
|
|
569
|
+
.option("--workflow <ref>", "Reference to workflow this observation relates to")
|
|
570
|
+
.option("--author <author>", "Author of the observation")
|
|
571
|
+
.option("--from-inbox <ref>", "Convert inbox item to observation")
|
|
572
|
+
.option("--type <type>", "Override type when using --from-inbox (defaults to idea)")
|
|
529
573
|
.action(async (type, content, options) => {
|
|
530
574
|
try {
|
|
531
575
|
const ctx = await initContext();
|
|
@@ -546,51 +590,65 @@ export function registerMetaCommands(program) {
|
|
|
546
590
|
// Use inbox item content
|
|
547
591
|
const observationContent = item.text;
|
|
548
592
|
// Type defaults to 'idea' but can be overridden with --type flag
|
|
549
|
-
const observationType = (options.type ||
|
|
593
|
+
const observationType = (options.type || "idea");
|
|
550
594
|
// Validate observation type
|
|
551
|
-
const validTypes = [
|
|
595
|
+
const validTypes = [
|
|
596
|
+
"friction",
|
|
597
|
+
"success",
|
|
598
|
+
"question",
|
|
599
|
+
"idea",
|
|
600
|
+
];
|
|
552
601
|
if (!validTypes.includes(observationType)) {
|
|
553
602
|
error(errors.validation.invalidObservationType(observationType));
|
|
554
|
-
console.log(`Valid types: ${validTypes.join(
|
|
603
|
+
console.log(`Valid types: ${validTypes.join(", ")}`);
|
|
555
604
|
process.exit(EXIT_CODES.ERROR);
|
|
556
605
|
}
|
|
557
606
|
// Create observation
|
|
558
607
|
const observation = createObservation(observationType, observationContent, {
|
|
559
608
|
workflow_ref: options.workflow,
|
|
560
609
|
author: options.author,
|
|
610
|
+
configAuthor: ctx.config?.identity?.author,
|
|
561
611
|
});
|
|
562
612
|
// Save observation
|
|
563
613
|
await saveObservation(ctx, observation);
|
|
564
614
|
// Delete inbox item
|
|
565
615
|
const deleted = await deleteInboxItem(ctx, item._ulid);
|
|
566
616
|
if (!deleted) {
|
|
567
|
-
error(
|
|
617
|
+
error("Failed to delete inbox item after creating observation");
|
|
568
618
|
process.exit(EXIT_CODES.ERROR);
|
|
569
619
|
}
|
|
570
|
-
await commitIfShadow(ctx.shadow,
|
|
620
|
+
await commitIfShadow(ctx.shadow, "meta-observe-from-inbox", observation._ulid.substring(0, 8), `Convert inbox item to ${observationType} observation`);
|
|
571
621
|
// Return observation ref
|
|
572
622
|
output(observation, () => success(`Created observation: ${observation._ulid.substring(0, 8)}`));
|
|
573
623
|
return;
|
|
574
624
|
}
|
|
575
625
|
// Standard observe flow (without --from-inbox)
|
|
576
626
|
if (!type || !content) {
|
|
577
|
-
error(
|
|
627
|
+
error("Type and content are required when not using --from-inbox");
|
|
578
628
|
process.exit(EXIT_CODES.ERROR);
|
|
579
629
|
}
|
|
580
630
|
// Validate observation type
|
|
581
|
-
const validTypes = [
|
|
631
|
+
const validTypes = [
|
|
632
|
+
"friction",
|
|
633
|
+
"success",
|
|
634
|
+
"question",
|
|
635
|
+
"idea",
|
|
636
|
+
];
|
|
582
637
|
if (!validTypes.includes(type)) {
|
|
583
638
|
error(errors.validation.invalidObservationType(type));
|
|
584
|
-
console.log(`Valid types: ${validTypes.join(
|
|
639
|
+
console.log(`Valid types: ${validTypes.join(", ")}`);
|
|
585
640
|
process.exit(EXIT_CODES.ERROR);
|
|
586
641
|
}
|
|
587
642
|
// Create observation
|
|
588
643
|
const observation = createObservation(type, content, {
|
|
589
644
|
workflow_ref: options.workflow,
|
|
590
645
|
author: options.author,
|
|
646
|
+
configAuthor: ctx.config?.identity?.author,
|
|
591
647
|
});
|
|
592
648
|
// Save to manifest
|
|
593
649
|
await saveObservation(ctx, observation);
|
|
650
|
+
// AC: @trait-shadow-commit ac-1
|
|
651
|
+
await commitIfShadow(ctx.shadow, "meta-observe", observation._ulid.substring(0, 8), type);
|
|
594
652
|
// AC-obs-1: outputs "OK Created observation: <ULID-prefix>"
|
|
595
653
|
// In JSON mode, return the created observation object
|
|
596
654
|
output(observation, () => success(`Created observation: ${observation._ulid.substring(0, 8)}`));
|
|
@@ -601,14 +659,16 @@ export function registerMetaCommands(program) {
|
|
|
601
659
|
}
|
|
602
660
|
});
|
|
603
661
|
// AC-obs-2, AC-obs-5: kspec meta observations
|
|
662
|
+
// AC: @observation-content-search ac-search-flag, ac-regex-support, ac-combined-filters
|
|
604
663
|
meta
|
|
605
|
-
.command(
|
|
606
|
-
.description(
|
|
607
|
-
.option(
|
|
608
|
-
.option(
|
|
609
|
-
.option(
|
|
610
|
-
.option(
|
|
611
|
-
.option(
|
|
664
|
+
.command("observations")
|
|
665
|
+
.description("List observations (shows unresolved by default)")
|
|
666
|
+
.option("--type <type>", "Filter by observation type (friction/success/question/idea)")
|
|
667
|
+
.option("--workflow <ref>", "Filter by workflow reference")
|
|
668
|
+
.option("--all", "Include resolved observations")
|
|
669
|
+
.option("--promoted", "Show only observations promoted to tasks")
|
|
670
|
+
.option("--pending-resolution", "Show observations with completed tasks awaiting resolution")
|
|
671
|
+
.option("--search <pattern>", "Search observations by regex pattern (matches content)")
|
|
612
672
|
.action(async (options) => {
|
|
613
673
|
try {
|
|
614
674
|
const ctx = await initContext();
|
|
@@ -641,7 +701,18 @@ export function registerMetaCommands(program) {
|
|
|
641
701
|
return false;
|
|
642
702
|
const item = taskResult.item;
|
|
643
703
|
// Type guard: check if item is a task (has status and depends_on properties)
|
|
644
|
-
return
|
|
704
|
+
return ("status" in item &&
|
|
705
|
+
"depends_on" in item &&
|
|
706
|
+
item.status === "completed");
|
|
707
|
+
});
|
|
708
|
+
}
|
|
709
|
+
// AC: @observation-content-search ac-search-flag, ac-regex-support, ac-combined-filters, ac-search-all-fields
|
|
710
|
+
// Apply --search filter using regex pattern (consistent with kspec search behavior)
|
|
711
|
+
if (options.search) {
|
|
712
|
+
const { grepItem } = await import("../../utils/grep.js");
|
|
713
|
+
observations = observations.filter((obs) => {
|
|
714
|
+
const match = grepItem(obs, options.search);
|
|
715
|
+
return match !== null;
|
|
645
716
|
});
|
|
646
717
|
}
|
|
647
718
|
// AC-obs-5: JSON output includes full observation objects
|
|
@@ -667,12 +738,11 @@ export function registerMetaCommands(program) {
|
|
|
667
738
|
}
|
|
668
739
|
});
|
|
669
740
|
// AC-obs-3, AC-obs-6, AC-obs-8: kspec meta promote
|
|
670
|
-
meta
|
|
671
|
-
.
|
|
672
|
-
.
|
|
673
|
-
.
|
|
674
|
-
.option(
|
|
675
|
-
.option('--force', 'Force promotion even if observation is resolved')
|
|
741
|
+
markMutating(meta.command("promote <ref>"))
|
|
742
|
+
.description("Promote observation to a task")
|
|
743
|
+
.requiredOption("--title <title>", "Task title")
|
|
744
|
+
.option("--priority <priority>", "Task priority (1-5)", "2")
|
|
745
|
+
.option("--force", "Force promotion even if observation is resolved")
|
|
676
746
|
.action(async (ref, options) => {
|
|
677
747
|
try {
|
|
678
748
|
const ctx = await initContext();
|
|
@@ -681,14 +751,17 @@ export function registerMetaCommands(program) {
|
|
|
681
751
|
process.exit(EXIT_CODES.ERROR);
|
|
682
752
|
}
|
|
683
753
|
const metaCtx = await loadMetaContext(ctx);
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
const observation = observations.find((o) => o._ulid.startsWith(normalizedRef));
|
|
688
|
-
if (!observation) {
|
|
754
|
+
// Use unified resolver - promotes only observations
|
|
755
|
+
const resolved = resolveMetaRef(metaCtx, ref);
|
|
756
|
+
if (!resolved) {
|
|
689
757
|
error(errors.reference.observationNotFound(ref));
|
|
690
758
|
process.exit(EXIT_CODES.ERROR);
|
|
691
759
|
}
|
|
760
|
+
if (resolved.type !== "observation") {
|
|
761
|
+
error(`Cannot promote ${resolved.type}. Only observations can be promoted to tasks.`);
|
|
762
|
+
process.exit(EXIT_CODES.ERROR);
|
|
763
|
+
}
|
|
764
|
+
const observation = resolved.item;
|
|
692
765
|
// AC-obs-6: Check if already promoted
|
|
693
766
|
if (observation.promoted_to) {
|
|
694
767
|
error(errors.conflict.observationAlreadyPromoted(observation.promoted_to));
|
|
@@ -699,21 +772,33 @@ export function registerMetaCommands(program) {
|
|
|
699
772
|
error(errors.operation.cannotPromoteResolved);
|
|
700
773
|
process.exit(EXIT_CODES.ERROR);
|
|
701
774
|
}
|
|
775
|
+
// Validate priority
|
|
776
|
+
const priorityResult = parseIntOption(options.priority, {
|
|
777
|
+
min: 1,
|
|
778
|
+
max: 5,
|
|
779
|
+
name: "Priority",
|
|
780
|
+
});
|
|
781
|
+
if (!priorityResult.ok) {
|
|
782
|
+
error(priorityResult.error);
|
|
783
|
+
process.exit(EXIT_CODES.VALIDATION_FAILED);
|
|
784
|
+
}
|
|
702
785
|
// AC-obs-3: Create task with title, description from observation, meta_ref, and origin
|
|
703
786
|
const task = createTask({
|
|
704
787
|
title: options.title,
|
|
705
788
|
description: observation.content,
|
|
706
|
-
priority:
|
|
789
|
+
priority: priorityResult.value,
|
|
707
790
|
meta_ref: observation.workflow_ref,
|
|
708
|
-
origin:
|
|
791
|
+
origin: "observation_promotion",
|
|
709
792
|
});
|
|
710
793
|
// Save task
|
|
711
794
|
await saveTask(ctx, task);
|
|
712
|
-
await commitIfShadow(ctx.shadow,
|
|
795
|
+
await commitIfShadow(ctx.shadow, "task-add", task.slugs[0] || task._ulid.slice(0, 8), task.title);
|
|
713
796
|
const taskRef = `@${task._ulid.substring(0, 8)}`;
|
|
714
797
|
// Update observation with promoted_to field
|
|
715
798
|
observation.promoted_to = taskRef;
|
|
716
799
|
await saveObservation(ctx, observation);
|
|
800
|
+
// AC: @trait-shadow-commit ac-1
|
|
801
|
+
await commitIfShadow(ctx.shadow, "observation-promote", observation._ulid.substring(0, 8));
|
|
717
802
|
// AC-obs-3: outputs "OK Created task: <ULID-prefix>"
|
|
718
803
|
// In JSON mode, return the created task object
|
|
719
804
|
output(task, () => success(`Created task: ${taskRef.substring(0, 9)}`));
|
|
@@ -724,10 +809,16 @@ export function registerMetaCommands(program) {
|
|
|
724
809
|
}
|
|
725
810
|
});
|
|
726
811
|
// AC-obs-4, AC-obs-7, AC-obs-9: kspec meta resolve
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
.description(
|
|
730
|
-
.
|
|
812
|
+
// AC: @trait-multi-ref-batch - Batch support with --refs flag
|
|
813
|
+
markMutating(meta.command("resolve [ref] [resolution]"))
|
|
814
|
+
.description("Resolve an observation (or multiple with --refs)")
|
|
815
|
+
.option("--refs <refs...>", "Resolve multiple observations by ref")
|
|
816
|
+
.option("--resolution <text>", "Resolution text (required for batch mode unless observations have promoted tasks)")
|
|
817
|
+
.addHelpText("after", `
|
|
818
|
+
Examples:
|
|
819
|
+
$ kspec meta resolve @obs-ref "Fixed in PR #123"
|
|
820
|
+
$ kspec meta resolve --refs @obs1 @obs2 --resolution "Resolved in batch"`)
|
|
821
|
+
.action(async (ref, resolutionArg, options) => {
|
|
731
822
|
try {
|
|
732
823
|
const ctx = await initContext();
|
|
733
824
|
if (!ctx.manifestPath) {
|
|
@@ -736,69 +827,100 @@ export function registerMetaCommands(program) {
|
|
|
736
827
|
}
|
|
737
828
|
const metaCtx = await loadMetaContext(ctx);
|
|
738
829
|
const observations = metaCtx.observations || [];
|
|
739
|
-
//
|
|
740
|
-
const
|
|
741
|
-
const
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
830
|
+
// Load tasks/items for auto-resolution from promoted tasks
|
|
831
|
+
const tasks = await loadAllTasks(ctx);
|
|
832
|
+
const items = await loadAllItems(ctx);
|
|
833
|
+
const index = new ReferenceIndex(tasks, items);
|
|
834
|
+
// Resolution can come from positional arg or --resolution flag
|
|
835
|
+
const resolution = resolutionArg || options.resolution;
|
|
836
|
+
// AC: @trait-multi-ref-batch ac-8 - Deduplicate refs
|
|
837
|
+
const refsFlag = options.refs
|
|
838
|
+
? [...new Set(options.refs)]
|
|
839
|
+
: undefined;
|
|
840
|
+
// AC: @trait-multi-ref-batch ac-1, ac-2, ac-3, ac-4, ac-5
|
|
841
|
+
const result = await executeBatchOperation({
|
|
842
|
+
positionalRef: ref,
|
|
843
|
+
refsFlag,
|
|
844
|
+
context: { ctx, observations, tasks, items, index, resolution },
|
|
845
|
+
items: observations,
|
|
846
|
+
index: index,
|
|
847
|
+
resolveRef: (refStr, obsList) => {
|
|
848
|
+
return resolveObservationRefForBatch(refStr, obsList);
|
|
849
|
+
},
|
|
850
|
+
executeOperation: async (observation, { ctx, tasks, items, index, resolution }) => {
|
|
851
|
+
// AC-obs-7: Check if already resolved
|
|
852
|
+
if (observation.resolved) {
|
|
853
|
+
const resolvedDate = new Date(observation.resolved_at)
|
|
854
|
+
.toISOString()
|
|
855
|
+
.split("T")[0];
|
|
856
|
+
const resolutionText = observation.resolution || "";
|
|
857
|
+
const truncated = resolutionText.length > 50
|
|
858
|
+
? `${resolutionText.substring(0, 50)}...`
|
|
859
|
+
: resolutionText;
|
|
860
|
+
return {
|
|
861
|
+
success: false,
|
|
862
|
+
error: `Already resolved on ${resolvedDate}: ${truncated}`,
|
|
863
|
+
};
|
|
864
|
+
}
|
|
865
|
+
// AC-obs-9: Auto-populate resolution from task completion if promoted
|
|
866
|
+
let finalResolution = resolution;
|
|
867
|
+
if (!finalResolution && observation.promoted_to) {
|
|
868
|
+
const taskResult = index.resolve(observation.promoted_to);
|
|
869
|
+
if (taskResult.ok) {
|
|
870
|
+
const item = taskResult.item;
|
|
871
|
+
// Type guard: ensure this is a task
|
|
872
|
+
if ("status" in item && "depends_on" in item) {
|
|
873
|
+
const task = item;
|
|
874
|
+
if (task.status === "completed" && task.closed_reason) {
|
|
875
|
+
finalResolution = `Resolved via task ${observation.promoted_to}: ${task.closed_reason}`;
|
|
876
|
+
}
|
|
877
|
+
else if (task.status === "completed") {
|
|
878
|
+
finalResolution = `Resolved via task ${observation.promoted_to}`;
|
|
879
|
+
}
|
|
880
|
+
else {
|
|
881
|
+
return {
|
|
882
|
+
success: false,
|
|
883
|
+
error: `Task ${observation.promoted_to} is not completed yet`,
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
else {
|
|
888
|
+
return {
|
|
889
|
+
success: false,
|
|
890
|
+
error: `Reference ${observation.promoted_to} is not a task`,
|
|
891
|
+
};
|
|
892
|
+
}
|
|
774
893
|
}
|
|
775
894
|
else {
|
|
776
|
-
|
|
777
|
-
|
|
895
|
+
return {
|
|
896
|
+
success: false,
|
|
897
|
+
error: `Task ${observation.promoted_to} not found`,
|
|
898
|
+
};
|
|
778
899
|
}
|
|
779
900
|
}
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
901
|
+
if (!finalResolution) {
|
|
902
|
+
return {
|
|
903
|
+
success: false,
|
|
904
|
+
error: "Resolution text required",
|
|
905
|
+
};
|
|
783
906
|
}
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
success(`Resolved: ${observation._ulid.substring(0, 8)}`);
|
|
907
|
+
// AC-obs-4: Update observation
|
|
908
|
+
observation.resolved = true;
|
|
909
|
+
observation.resolution = finalResolution;
|
|
910
|
+
observation.resolved_at = new Date().toISOString();
|
|
911
|
+
observation.resolved_by = observation.author;
|
|
912
|
+
await saveObservation(ctx, observation);
|
|
913
|
+
// AC: @trait-shadow-commit ac-1
|
|
914
|
+
await commitIfShadow(ctx.shadow, "observation-resolve", observation._ulid.substring(0, 8));
|
|
915
|
+
return {
|
|
916
|
+
success: true,
|
|
917
|
+
message: `Resolved: ${observation._ulid.substring(0, 8)}`,
|
|
918
|
+
};
|
|
919
|
+
},
|
|
920
|
+
getUlid: (obs) => obs._ulid,
|
|
921
|
+
});
|
|
922
|
+
// AC: @trait-multi-ref-batch ac-5, ac-7 - Output formatting
|
|
923
|
+
formatBatchOutput(result, "Resolve");
|
|
802
924
|
}
|
|
803
925
|
catch (err) {
|
|
804
926
|
error(errors.failures.resolveObservation, err);
|
|
@@ -806,23 +928,31 @@ export function registerMetaCommands(program) {
|
|
|
806
928
|
}
|
|
807
929
|
});
|
|
808
930
|
// Meta add command - create new meta items
|
|
809
|
-
meta
|
|
810
|
-
.
|
|
811
|
-
.
|
|
812
|
-
.option(
|
|
813
|
-
.option(
|
|
814
|
-
.option(
|
|
815
|
-
.option(
|
|
816
|
-
.option(
|
|
817
|
-
.option(
|
|
818
|
-
.option(
|
|
819
|
-
.option(
|
|
820
|
-
.option(
|
|
931
|
+
markMutating(meta.command("add <type>"))
|
|
932
|
+
.description("Create a new meta item (agent, workflow, or convention)")
|
|
933
|
+
.option("--id <id>", "Semantic ID (required for agents and workflows)")
|
|
934
|
+
.option("--domain <domain>", "Domain (required for conventions)")
|
|
935
|
+
.option("--name <name>", "Name (for agents)")
|
|
936
|
+
.option("--trigger <trigger>", "Trigger (for workflows)")
|
|
937
|
+
.option("--description <desc>", "Description")
|
|
938
|
+
.option("--capability <cap...>", "Capabilities (for agents)")
|
|
939
|
+
.option("--tool <tool...>", "Tools (for agents)")
|
|
940
|
+
.option("--convention <conv...>", "Convention references (for agents)")
|
|
941
|
+
.option("--rule <rule...>", "Rules (for conventions)")
|
|
942
|
+
.option("--steps <json>", "Workflow steps as JSON array (for workflows)")
|
|
943
|
+
.option("--mode <mode>", "Workflow mode: interactive (default) or loop (for workflows)")
|
|
944
|
+
.option("--based-on <ref>", "Base workflow reference (for loop workflows)")
|
|
945
|
+
.option("--tag <tag...>", "Tags for the workflow (for workflows)")
|
|
946
|
+
.addHelpText("after", `
|
|
947
|
+
Examples:
|
|
948
|
+
$ kspec meta add agent --id my-agent --name "My Agent" --capability search code
|
|
949
|
+
$ kspec meta add convention --domain testing --rule "Always test" --rule "Use mocks"
|
|
950
|
+
$ kspec meta add workflow --id my-flow --trigger manual --tag automation ci`)
|
|
821
951
|
.action(async (type, options) => {
|
|
822
952
|
try {
|
|
823
953
|
const ctx = await initContext();
|
|
824
954
|
// Validate type
|
|
825
|
-
const validTypes = [
|
|
955
|
+
const validTypes = ["agent", "workflow", "convention"];
|
|
826
956
|
if (!validTypes.includes(type)) {
|
|
827
957
|
error(errors.validation.invalidType(type, validTypes));
|
|
828
958
|
process.exit(EXIT_CODES.ERROR);
|
|
@@ -831,7 +961,7 @@ export function registerMetaCommands(program) {
|
|
|
831
961
|
const itemUlid = ulid();
|
|
832
962
|
// Create the item based on type
|
|
833
963
|
let item;
|
|
834
|
-
if (type ===
|
|
964
|
+
if (type === "agent") {
|
|
835
965
|
// Validate required fields
|
|
836
966
|
if (!options.id) {
|
|
837
967
|
error(errors.validation.agentRequiresId);
|
|
@@ -845,13 +975,13 @@ export function registerMetaCommands(program) {
|
|
|
845
975
|
_ulid: itemUlid,
|
|
846
976
|
id: options.id,
|
|
847
977
|
name: options.name,
|
|
848
|
-
description: options.description ||
|
|
978
|
+
description: options.description || "",
|
|
849
979
|
capabilities: options.capability || [],
|
|
850
980
|
tools: options.tool || [],
|
|
851
981
|
conventions: options.convention || [],
|
|
852
982
|
};
|
|
853
983
|
}
|
|
854
|
-
else if (type ===
|
|
984
|
+
else if (type === "workflow") {
|
|
855
985
|
// Validate required fields
|
|
856
986
|
if (!options.id) {
|
|
857
987
|
error(errors.validation.workflowRequiresId);
|
|
@@ -861,12 +991,50 @@ export function registerMetaCommands(program) {
|
|
|
861
991
|
error(errors.validation.workflowRequiresTrigger);
|
|
862
992
|
process.exit(EXIT_CODES.ERROR);
|
|
863
993
|
}
|
|
994
|
+
// Parse and validate --steps if provided
|
|
995
|
+
let steps = [];
|
|
996
|
+
if (options.steps) {
|
|
997
|
+
// AC: @meta-add-cmd ac-2 - Parse JSON
|
|
998
|
+
let parsedSteps;
|
|
999
|
+
try {
|
|
1000
|
+
parsedSteps = JSON.parse(options.steps);
|
|
1001
|
+
}
|
|
1002
|
+
catch (err) {
|
|
1003
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1004
|
+
error(errors.validation.invalidStepsJson(message));
|
|
1005
|
+
process.exit(EXIT_CODES.ERROR);
|
|
1006
|
+
}
|
|
1007
|
+
// AC: @meta-add-cmd ac-3 - Verify it's an array
|
|
1008
|
+
if (!Array.isArray(parsedSteps)) {
|
|
1009
|
+
error(errors.validation.stepsNotArray);
|
|
1010
|
+
process.exit(EXIT_CODES.ERROR);
|
|
1011
|
+
}
|
|
1012
|
+
// AC: @meta-add-cmd ac-4 - Validate with schema
|
|
1013
|
+
const result = z.array(WorkflowStepSchema).safeParse(parsedSteps);
|
|
1014
|
+
if (!result.success) {
|
|
1015
|
+
const issues = result.error.issues
|
|
1016
|
+
.map((i) => `${i.path.join(".")}: ${i.message}`)
|
|
1017
|
+
.join("; ");
|
|
1018
|
+
error(errors.validation.invalidStepsSchema(issues));
|
|
1019
|
+
process.exit(EXIT_CODES.ERROR);
|
|
1020
|
+
}
|
|
1021
|
+
steps = result.data;
|
|
1022
|
+
}
|
|
1023
|
+
// Validate mode if provided
|
|
1024
|
+
const validModes = ["interactive", "loop"];
|
|
1025
|
+
if (options.mode && !validModes.includes(options.mode)) {
|
|
1026
|
+
error(`Invalid mode: ${options.mode}. Valid modes: ${validModes.join(", ")}`);
|
|
1027
|
+
process.exit(EXIT_CODES.ERROR);
|
|
1028
|
+
}
|
|
864
1029
|
item = {
|
|
865
1030
|
_ulid: itemUlid,
|
|
866
1031
|
id: options.id,
|
|
867
1032
|
trigger: options.trigger,
|
|
868
|
-
description: options.description ||
|
|
869
|
-
steps
|
|
1033
|
+
description: options.description || "",
|
|
1034
|
+
steps,
|
|
1035
|
+
...(options.mode && { mode: options.mode }),
|
|
1036
|
+
...(options.basedOn && { based_on: options.basedOn }),
|
|
1037
|
+
...(options.tag && options.tag.length > 0 && { tags: parseTagsArray(options.tag) }),
|
|
870
1038
|
};
|
|
871
1039
|
}
|
|
872
1040
|
else {
|
|
@@ -884,12 +1052,14 @@ export function registerMetaCommands(program) {
|
|
|
884
1052
|
}
|
|
885
1053
|
// Save the item
|
|
886
1054
|
await saveMetaItem(ctx, item, type);
|
|
1055
|
+
// AC: @trait-shadow-commit ac-1
|
|
1056
|
+
await commitIfShadow(ctx.shadow, `meta-add-${type}`, itemUlid.substring(0, 8), "id" in item ? item.id : "domain" in item ? item.domain : undefined);
|
|
887
1057
|
if (isJsonMode()) {
|
|
888
1058
|
// In JSON mode, output the item data directly
|
|
889
1059
|
console.log(JSON.stringify(item, null, 2));
|
|
890
1060
|
}
|
|
891
1061
|
else {
|
|
892
|
-
const idOrDomain =
|
|
1062
|
+
const idOrDomain = "id" in item ? item.id : "domain" in item ? item.domain : itemUlid;
|
|
893
1063
|
success(`Created ${type}: ${idOrDomain} (@${itemUlid.substring(0, 8)})`);
|
|
894
1064
|
}
|
|
895
1065
|
}
|
|
@@ -899,55 +1069,35 @@ export function registerMetaCommands(program) {
|
|
|
899
1069
|
}
|
|
900
1070
|
});
|
|
901
1071
|
// Meta set command - update existing meta items
|
|
902
|
-
meta
|
|
903
|
-
.
|
|
904
|
-
.
|
|
905
|
-
.option(
|
|
906
|
-
.option(
|
|
907
|
-
.option(
|
|
908
|
-
.option(
|
|
909
|
-
.option(
|
|
910
|
-
.option(
|
|
911
|
-
.option('--add-rule <rule>', 'Add rule (for conventions)')
|
|
1072
|
+
markMutating(meta.command("set <ref>"))
|
|
1073
|
+
.description("Update an existing meta item")
|
|
1074
|
+
.option("--name <name>", "Update name (for agents)")
|
|
1075
|
+
.option("--description <desc>", "Update description")
|
|
1076
|
+
.option("--trigger <trigger>", "Update trigger (for workflows)")
|
|
1077
|
+
.option("--add-capability <cap>", "Add capability (for agents)")
|
|
1078
|
+
.option("--add-tool <tool>", "Add tool (for agents)")
|
|
1079
|
+
.option("--add-convention <conv>", "Add convention reference (for agents)")
|
|
1080
|
+
.option("--add-rule <rule>", "Add rule (for conventions)")
|
|
912
1081
|
.action(async (ref, options) => {
|
|
913
1082
|
try {
|
|
914
1083
|
const ctx = await initContext();
|
|
915
1084
|
const metaCtx = await loadMetaContext(ctx);
|
|
916
|
-
//
|
|
917
|
-
const
|
|
918
|
-
|
|
919
|
-
let itemType = null;
|
|
920
|
-
// Search in agents
|
|
921
|
-
const agents = metaCtx.manifest?.agents || [];
|
|
922
|
-
const agent = agents.find((a) => a.id === normalizedRef || a._ulid.startsWith(normalizedRef));
|
|
923
|
-
if (agent) {
|
|
924
|
-
found = agent;
|
|
925
|
-
itemType = 'agent';
|
|
926
|
-
}
|
|
927
|
-
// Search in workflows
|
|
928
|
-
if (!found) {
|
|
929
|
-
const workflows = metaCtx.manifest?.workflows || [];
|
|
930
|
-
const workflow = workflows.find((w) => w.id === normalizedRef || w._ulid.startsWith(normalizedRef));
|
|
931
|
-
if (workflow) {
|
|
932
|
-
found = workflow;
|
|
933
|
-
itemType = 'workflow';
|
|
934
|
-
}
|
|
935
|
-
}
|
|
936
|
-
// Search in conventions
|
|
937
|
-
if (!found) {
|
|
938
|
-
const conventions = metaCtx.manifest?.conventions || [];
|
|
939
|
-
const convention = conventions.find((c) => c.domain === normalizedRef || c._ulid.startsWith(normalizedRef));
|
|
940
|
-
if (convention) {
|
|
941
|
-
found = convention;
|
|
942
|
-
itemType = 'convention';
|
|
943
|
-
}
|
|
944
|
-
}
|
|
945
|
-
if (!found || !itemType) {
|
|
1085
|
+
// Use unified resolver
|
|
1086
|
+
const resolved = resolveMetaRef(metaCtx, ref);
|
|
1087
|
+
if (!resolved) {
|
|
946
1088
|
error(errors.reference.metaNotFound(ref));
|
|
947
1089
|
process.exit(EXIT_CODES.ERROR);
|
|
948
1090
|
}
|
|
1091
|
+
// meta set only supports agent, workflow, convention
|
|
1092
|
+
// Skills have their own `kspec skill set` command
|
|
1093
|
+
const { item, type: itemType } = resolved;
|
|
1094
|
+
if (itemType !== "agent" && itemType !== "workflow" && itemType !== "convention") {
|
|
1095
|
+
error(`Cannot use 'meta set' with ${itemType}. Use 'kspec ${itemType === "skill" ? "skill" : "meta"} ${itemType === "observation" ? "resolve" : "set"} ${ref}' instead.`);
|
|
1096
|
+
process.exit(EXIT_CODES.ERROR);
|
|
1097
|
+
}
|
|
1098
|
+
const found = item;
|
|
949
1099
|
// Update fields based on type
|
|
950
|
-
if (itemType ===
|
|
1100
|
+
if (itemType === "agent") {
|
|
951
1101
|
const item = found;
|
|
952
1102
|
if (options.name)
|
|
953
1103
|
item.name = options.name;
|
|
@@ -969,7 +1119,7 @@ export function registerMetaCommands(program) {
|
|
|
969
1119
|
}
|
|
970
1120
|
}
|
|
971
1121
|
}
|
|
972
|
-
else if (itemType ===
|
|
1122
|
+
else if (itemType === "workflow") {
|
|
973
1123
|
const item = found;
|
|
974
1124
|
if (options.trigger)
|
|
975
1125
|
item.trigger = options.trigger;
|
|
@@ -987,14 +1137,16 @@ export function registerMetaCommands(program) {
|
|
|
987
1137
|
}
|
|
988
1138
|
// Save the updated item
|
|
989
1139
|
await saveMetaItem(ctx, found, itemType);
|
|
1140
|
+
// AC: @trait-shadow-commit ac-1
|
|
1141
|
+
await commitIfShadow(ctx.shadow, `meta-set-${itemType}`, found._ulid.substring(0, 8));
|
|
990
1142
|
if (isJsonMode()) {
|
|
991
1143
|
// In JSON mode, output the item data directly
|
|
992
1144
|
console.log(JSON.stringify(found, null, 2));
|
|
993
1145
|
}
|
|
994
1146
|
else {
|
|
995
|
-
const idOrDomain = itemType ===
|
|
1147
|
+
const idOrDomain = itemType === "agent"
|
|
996
1148
|
? found.id
|
|
997
|
-
: itemType ===
|
|
1149
|
+
: itemType === "workflow"
|
|
998
1150
|
? found.id
|
|
999
1151
|
: found.domain;
|
|
1000
1152
|
success(`Updated ${itemType}: ${idOrDomain}`);
|
|
@@ -1006,60 +1158,40 @@ export function registerMetaCommands(program) {
|
|
|
1006
1158
|
}
|
|
1007
1159
|
});
|
|
1008
1160
|
// Meta delete command - delete meta items
|
|
1009
|
-
meta
|
|
1010
|
-
.
|
|
1011
|
-
.
|
|
1012
|
-
.option('--confirm', 'Skip confirmation prompt')
|
|
1161
|
+
markMutating(meta.command("delete <ref>"))
|
|
1162
|
+
.description("Delete a meta item")
|
|
1163
|
+
.option("--confirm", "Skip confirmation prompt")
|
|
1013
1164
|
.action(async (ref, options) => {
|
|
1014
1165
|
try {
|
|
1015
1166
|
const ctx = await initContext();
|
|
1016
1167
|
const metaCtx = await loadMetaContext(ctx);
|
|
1017
|
-
//
|
|
1018
|
-
const
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
// Search in agents
|
|
1023
|
-
const agents = metaCtx.manifest?.agents || [];
|
|
1024
|
-
const agent = agents.find((a) => a.id === normalizedRef || a._ulid.startsWith(normalizedRef));
|
|
1025
|
-
if (agent) {
|
|
1026
|
-
itemType = 'agent';
|
|
1027
|
-
itemUlid = agent._ulid;
|
|
1028
|
-
itemLabel = `agent ${agent.id}`;
|
|
1029
|
-
}
|
|
1030
|
-
// Search in workflows
|
|
1031
|
-
if (!itemType) {
|
|
1032
|
-
const workflows = metaCtx.manifest?.workflows || [];
|
|
1033
|
-
const workflow = workflows.find((w) => w.id === normalizedRef || w._ulid.startsWith(normalizedRef));
|
|
1034
|
-
if (workflow) {
|
|
1035
|
-
itemType = 'workflow';
|
|
1036
|
-
itemUlid = workflow._ulid;
|
|
1037
|
-
itemLabel = `workflow ${workflow.id}`;
|
|
1038
|
-
}
|
|
1168
|
+
// Use unified resolver
|
|
1169
|
+
const resolved = resolveMetaRef(metaCtx, ref);
|
|
1170
|
+
if (!resolved) {
|
|
1171
|
+
error(errors.reference.metaNotFound(ref));
|
|
1172
|
+
process.exit(EXIT_CODES.ERROR);
|
|
1039
1173
|
}
|
|
1040
|
-
//
|
|
1041
|
-
if (
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
if (convention) {
|
|
1045
|
-
itemType = 'convention';
|
|
1046
|
-
itemUlid = convention._ulid;
|
|
1047
|
-
itemLabel = `convention ${convention.domain}`;
|
|
1048
|
-
}
|
|
1174
|
+
// meta delete does not support skills - they use `kspec skill delete`
|
|
1175
|
+
if (resolved.type === "skill") {
|
|
1176
|
+
error(`Cannot use 'meta delete' with skills. Use 'kspec skill delete ${ref}' instead.`);
|
|
1177
|
+
process.exit(EXIT_CODES.ERROR);
|
|
1049
1178
|
}
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
itemLabel = `observation ${observation._ulid.substring(0, 8)}`;
|
|
1058
|
-
}
|
|
1179
|
+
const itemType = resolved.type;
|
|
1180
|
+
const itemUlid = resolved.ulid;
|
|
1181
|
+
// Build human-readable label for the item
|
|
1182
|
+
let itemLabel;
|
|
1183
|
+
const item = resolved.item;
|
|
1184
|
+
if (itemType === "agent" && "id" in item) {
|
|
1185
|
+
itemLabel = `agent ${item.id}`;
|
|
1059
1186
|
}
|
|
1060
|
-
if (
|
|
1061
|
-
|
|
1062
|
-
|
|
1187
|
+
else if (itemType === "workflow" && "id" in item) {
|
|
1188
|
+
itemLabel = `workflow ${item.id}`;
|
|
1189
|
+
}
|
|
1190
|
+
else if (itemType === "convention" && "domain" in item) {
|
|
1191
|
+
itemLabel = `convention ${item.domain}`;
|
|
1192
|
+
}
|
|
1193
|
+
else {
|
|
1194
|
+
itemLabel = `observation ${itemUlid.substring(0, 8)}`;
|
|
1063
1195
|
}
|
|
1064
1196
|
// Check for dangling references (unless --confirm is used to override)
|
|
1065
1197
|
if (!options.confirm) {
|
|
@@ -1076,12 +1208,12 @@ export function registerMetaCommands(program) {
|
|
|
1076
1208
|
if (referencingTasks.length > 0) {
|
|
1077
1209
|
const taskRefs = referencingTasks
|
|
1078
1210
|
.map((t) => `@${t.slugs?.[0] || t._ulid.substring(0, 8)}`)
|
|
1079
|
-
.join(
|
|
1211
|
+
.join(", ");
|
|
1080
1212
|
error(errors.operation.cannotDeleteReferencedByTasks(itemLabel, referencingTasks.length, taskRefs));
|
|
1081
1213
|
process.exit(EXIT_CODES.ERROR);
|
|
1082
1214
|
}
|
|
1083
1215
|
// Check observations with workflow_ref (only for workflows)
|
|
1084
|
-
if (itemType ===
|
|
1216
|
+
if (itemType === "workflow") {
|
|
1085
1217
|
const observations = metaCtx.observations || [];
|
|
1086
1218
|
const referencingObservations = observations.filter((o) => {
|
|
1087
1219
|
if (!o.workflow_ref)
|
|
@@ -1094,7 +1226,7 @@ export function registerMetaCommands(program) {
|
|
|
1094
1226
|
if (referencingObservations.length > 0) {
|
|
1095
1227
|
const obsRefs = referencingObservations
|
|
1096
1228
|
.map((o) => `@${o._ulid.substring(0, 8)}`)
|
|
1097
|
-
.join(
|
|
1229
|
+
.join(", ");
|
|
1098
1230
|
error(errors.operation.cannotDeleteReferencedByObservations(itemLabel, referencingObservations.length, obsRefs));
|
|
1099
1231
|
process.exit(EXIT_CODES.ERROR);
|
|
1100
1232
|
}
|
|
@@ -1109,6 +1241,8 @@ export function registerMetaCommands(program) {
|
|
|
1109
1241
|
error(errors.operation.deleteItemFailed(itemLabel));
|
|
1110
1242
|
process.exit(EXIT_CODES.ERROR);
|
|
1111
1243
|
}
|
|
1244
|
+
// AC: @trait-shadow-commit ac-1
|
|
1245
|
+
await commitIfShadow(ctx.shadow, `meta-delete-${itemType}`, itemUlid.substring(0, 8));
|
|
1112
1246
|
success(`Deleted ${itemLabel}`);
|
|
1113
1247
|
}
|
|
1114
1248
|
catch (err) {
|
|
@@ -1117,10 +1251,9 @@ export function registerMetaCommands(program) {
|
|
|
1117
1251
|
}
|
|
1118
1252
|
});
|
|
1119
1253
|
// meta-focus-cmd: kspec meta focus [ref]
|
|
1120
|
-
meta
|
|
1121
|
-
.
|
|
1122
|
-
.
|
|
1123
|
-
.option('--clear', 'Clear current focus')
|
|
1254
|
+
markMutating(meta.command("focus [ref]"))
|
|
1255
|
+
.description("Get or set session focus")
|
|
1256
|
+
.option("--clear", "Clear current focus")
|
|
1124
1257
|
.action(async (ref, options) => {
|
|
1125
1258
|
try {
|
|
1126
1259
|
const ctx = await initContext();
|
|
@@ -1133,7 +1266,7 @@ export function registerMetaCommands(program) {
|
|
|
1133
1266
|
if (options.clear) {
|
|
1134
1267
|
sessionCtx.focus = null;
|
|
1135
1268
|
await saveSessionContext(ctx, sessionCtx);
|
|
1136
|
-
output({ focus: null }, () => success(
|
|
1269
|
+
output({ focus: null }, () => success("Cleared session focus"));
|
|
1137
1270
|
return;
|
|
1138
1271
|
}
|
|
1139
1272
|
// Show current focus
|
|
@@ -1143,13 +1276,13 @@ export function registerMetaCommands(program) {
|
|
|
1143
1276
|
console.log(`Current focus: ${sessionCtx.focus}`);
|
|
1144
1277
|
}
|
|
1145
1278
|
else {
|
|
1146
|
-
console.log(chalk.yellow(
|
|
1279
|
+
console.log(chalk.yellow("No focus set"));
|
|
1147
1280
|
}
|
|
1148
1281
|
});
|
|
1149
1282
|
return;
|
|
1150
1283
|
}
|
|
1151
1284
|
// Set focus to ref
|
|
1152
|
-
sessionCtx.focus = ref
|
|
1285
|
+
sessionCtx.focus = normalizeRefInput(ref);
|
|
1153
1286
|
await saveSessionContext(ctx, sessionCtx);
|
|
1154
1287
|
output({ focus: sessionCtx.focus }, () => success(`Set focus to: ${sessionCtx.focus}`));
|
|
1155
1288
|
}
|
|
@@ -1159,9 +1292,8 @@ export function registerMetaCommands(program) {
|
|
|
1159
1292
|
}
|
|
1160
1293
|
});
|
|
1161
1294
|
// meta-thread-cmd: kspec meta thread <action> [text]
|
|
1162
|
-
meta
|
|
1163
|
-
.
|
|
1164
|
-
.description('Manage active threads')
|
|
1295
|
+
markMutating(meta.command("thread <action> [text]"))
|
|
1296
|
+
.description("Manage active threads")
|
|
1165
1297
|
.action(async (action, text) => {
|
|
1166
1298
|
try {
|
|
1167
1299
|
const ctx = await initContext();
|
|
@@ -1171,13 +1303,13 @@ export function registerMetaCommands(program) {
|
|
|
1171
1303
|
}
|
|
1172
1304
|
const sessionCtx = await loadSessionContext(ctx);
|
|
1173
1305
|
// List threads
|
|
1174
|
-
if (action ===
|
|
1306
|
+
if (action === "list") {
|
|
1175
1307
|
output({ threads: sessionCtx.threads }, () => {
|
|
1176
1308
|
if (sessionCtx.threads.length === 0) {
|
|
1177
|
-
console.log(chalk.yellow(
|
|
1309
|
+
console.log(chalk.yellow("No active threads"));
|
|
1178
1310
|
}
|
|
1179
1311
|
else {
|
|
1180
|
-
console.log(
|
|
1312
|
+
console.log("Active threads:");
|
|
1181
1313
|
sessionCtx.threads.forEach((thread, idx) => {
|
|
1182
1314
|
console.log(` ${idx + 1}. ${thread}`);
|
|
1183
1315
|
});
|
|
@@ -1186,16 +1318,16 @@ export function registerMetaCommands(program) {
|
|
|
1186
1318
|
return;
|
|
1187
1319
|
}
|
|
1188
1320
|
// Clear all threads
|
|
1189
|
-
if (action ===
|
|
1321
|
+
if (action === "clear") {
|
|
1190
1322
|
sessionCtx.threads = [];
|
|
1191
1323
|
await saveSessionContext(ctx, sessionCtx);
|
|
1192
|
-
output({ threads: [] }, () => success(
|
|
1324
|
+
output({ threads: [] }, () => success("Cleared all threads"));
|
|
1193
1325
|
return;
|
|
1194
1326
|
}
|
|
1195
1327
|
// Add thread
|
|
1196
|
-
if (action ===
|
|
1328
|
+
if (action === "add") {
|
|
1197
1329
|
if (!text) {
|
|
1198
|
-
error(
|
|
1330
|
+
error("Thread text is required for add action");
|
|
1199
1331
|
process.exit(EXIT_CODES.ERROR);
|
|
1200
1332
|
}
|
|
1201
1333
|
sessionCtx.threads.push(text);
|
|
@@ -1204,13 +1336,15 @@ export function registerMetaCommands(program) {
|
|
|
1204
1336
|
return;
|
|
1205
1337
|
}
|
|
1206
1338
|
// Remove thread by index (1-based)
|
|
1207
|
-
if (action ===
|
|
1339
|
+
if (action === "remove") {
|
|
1208
1340
|
if (!text) {
|
|
1209
|
-
error(
|
|
1341
|
+
error("Index is required for remove action");
|
|
1210
1342
|
process.exit(EXIT_CODES.ERROR);
|
|
1211
1343
|
}
|
|
1212
1344
|
const index = parseInt(text, 10);
|
|
1213
|
-
if (isNaN(index) ||
|
|
1345
|
+
if (Number.isNaN(index) ||
|
|
1346
|
+
index < 1 ||
|
|
1347
|
+
index > sessionCtx.threads.length) {
|
|
1214
1348
|
error(`Invalid index: ${text}. Must be between 1 and ${sessionCtx.threads.length}`);
|
|
1215
1349
|
process.exit(EXIT_CODES.ERROR);
|
|
1216
1350
|
}
|
|
@@ -1229,9 +1363,8 @@ export function registerMetaCommands(program) {
|
|
|
1229
1363
|
}
|
|
1230
1364
|
});
|
|
1231
1365
|
// meta-question-cmd: kspec meta question <action> [text]
|
|
1232
|
-
meta
|
|
1233
|
-
.
|
|
1234
|
-
.description('Manage open questions')
|
|
1366
|
+
markMutating(meta.command("question <action> [text]"))
|
|
1367
|
+
.description("Manage open questions")
|
|
1235
1368
|
.action(async (action, text) => {
|
|
1236
1369
|
try {
|
|
1237
1370
|
const ctx = await initContext();
|
|
@@ -1241,13 +1374,13 @@ export function registerMetaCommands(program) {
|
|
|
1241
1374
|
}
|
|
1242
1375
|
const sessionCtx = await loadSessionContext(ctx);
|
|
1243
1376
|
// List questions
|
|
1244
|
-
if (action ===
|
|
1377
|
+
if (action === "list") {
|
|
1245
1378
|
output({ questions: sessionCtx.open_questions }, () => {
|
|
1246
1379
|
if (sessionCtx.open_questions.length === 0) {
|
|
1247
|
-
console.log(chalk.yellow(
|
|
1380
|
+
console.log(chalk.yellow("No open questions"));
|
|
1248
1381
|
}
|
|
1249
1382
|
else {
|
|
1250
|
-
console.log(
|
|
1383
|
+
console.log("Open questions:");
|
|
1251
1384
|
sessionCtx.open_questions.forEach((question, idx) => {
|
|
1252
1385
|
console.log(` ${idx + 1}. ${question}`);
|
|
1253
1386
|
});
|
|
@@ -1256,16 +1389,16 @@ export function registerMetaCommands(program) {
|
|
|
1256
1389
|
return;
|
|
1257
1390
|
}
|
|
1258
1391
|
// Clear all questions
|
|
1259
|
-
if (action ===
|
|
1392
|
+
if (action === "clear") {
|
|
1260
1393
|
sessionCtx.open_questions = [];
|
|
1261
1394
|
await saveSessionContext(ctx, sessionCtx);
|
|
1262
|
-
output({ questions: [] }, () => success(
|
|
1395
|
+
output({ questions: [] }, () => success("Cleared all questions"));
|
|
1263
1396
|
return;
|
|
1264
1397
|
}
|
|
1265
1398
|
// Add question
|
|
1266
|
-
if (action ===
|
|
1399
|
+
if (action === "add") {
|
|
1267
1400
|
if (!text) {
|
|
1268
|
-
error(
|
|
1401
|
+
error("Question text is required for add action");
|
|
1269
1402
|
process.exit(EXIT_CODES.ERROR);
|
|
1270
1403
|
}
|
|
1271
1404
|
sessionCtx.open_questions.push(text);
|
|
@@ -1274,13 +1407,15 @@ export function registerMetaCommands(program) {
|
|
|
1274
1407
|
return;
|
|
1275
1408
|
}
|
|
1276
1409
|
// Remove question by index (1-based)
|
|
1277
|
-
if (action ===
|
|
1410
|
+
if (action === "remove") {
|
|
1278
1411
|
if (!text) {
|
|
1279
|
-
error(
|
|
1412
|
+
error("Index is required for remove action");
|
|
1280
1413
|
process.exit(EXIT_CODES.ERROR);
|
|
1281
1414
|
}
|
|
1282
1415
|
const index = parseInt(text, 10);
|
|
1283
|
-
if (isNaN(index) ||
|
|
1416
|
+
if (Number.isNaN(index) ||
|
|
1417
|
+
index < 1 ||
|
|
1418
|
+
index > sessionCtx.open_questions.length) {
|
|
1284
1419
|
error(`Invalid index: ${text}. Must be between 1 and ${sessionCtx.open_questions.length}`);
|
|
1285
1420
|
process.exit(EXIT_CODES.ERROR);
|
|
1286
1421
|
}
|
|
@@ -1300,9 +1435,9 @@ export function registerMetaCommands(program) {
|
|
|
1300
1435
|
});
|
|
1301
1436
|
// meta-context-cmd: kspec meta context
|
|
1302
1437
|
meta
|
|
1303
|
-
.command(
|
|
1304
|
-
.description(
|
|
1305
|
-
.option(
|
|
1438
|
+
.command("context")
|
|
1439
|
+
.description("Show full session context")
|
|
1440
|
+
.option("--clear", "Clear all session context")
|
|
1306
1441
|
.action(async (options) => {
|
|
1307
1442
|
try {
|
|
1308
1443
|
const ctx = await initContext();
|
|
@@ -1322,7 +1457,7 @@ export function registerMetaCommands(program) {
|
|
|
1322
1457
|
threads: [],
|
|
1323
1458
|
open_questions: [],
|
|
1324
1459
|
updated_at: sessionCtx.updated_at,
|
|
1325
|
-
}, () => success(
|
|
1460
|
+
}, () => success("Cleared all session context"));
|
|
1326
1461
|
return;
|
|
1327
1462
|
}
|
|
1328
1463
|
// Show full session context
|
|
@@ -1332,38 +1467,38 @@ export function registerMetaCommands(program) {
|
|
|
1332
1467
|
open_questions: sessionCtx.open_questions,
|
|
1333
1468
|
updated_at: sessionCtx.updated_at,
|
|
1334
1469
|
}, () => {
|
|
1335
|
-
console.log(chalk.bold(
|
|
1336
|
-
console.log(chalk.gray(
|
|
1470
|
+
console.log(chalk.bold("Session Context"));
|
|
1471
|
+
console.log(chalk.gray("─".repeat(60)));
|
|
1337
1472
|
// Focus
|
|
1338
|
-
console.log(chalk.bold(
|
|
1473
|
+
console.log(chalk.bold("\nFocus:"));
|
|
1339
1474
|
if (sessionCtx.focus) {
|
|
1340
1475
|
console.log(` ${sessionCtx.focus}`);
|
|
1341
1476
|
}
|
|
1342
1477
|
else {
|
|
1343
|
-
console.log(chalk.gray(
|
|
1478
|
+
console.log(chalk.gray(" (none)"));
|
|
1344
1479
|
}
|
|
1345
1480
|
// Active threads
|
|
1346
|
-
console.log(chalk.bold(
|
|
1481
|
+
console.log(chalk.bold("\nActive Threads:"));
|
|
1347
1482
|
if (sessionCtx.threads.length > 0) {
|
|
1348
1483
|
sessionCtx.threads.forEach((thread, idx) => {
|
|
1349
1484
|
console.log(` ${idx + 1}. ${thread}`);
|
|
1350
1485
|
});
|
|
1351
1486
|
}
|
|
1352
1487
|
else {
|
|
1353
|
-
console.log(chalk.gray(
|
|
1488
|
+
console.log(chalk.gray(" (none)"));
|
|
1354
1489
|
}
|
|
1355
1490
|
// Open questions
|
|
1356
|
-
console.log(chalk.bold(
|
|
1491
|
+
console.log(chalk.bold("\nOpen Questions:"));
|
|
1357
1492
|
if (sessionCtx.open_questions.length > 0) {
|
|
1358
1493
|
sessionCtx.open_questions.forEach((question, idx) => {
|
|
1359
1494
|
console.log(` ${idx + 1}. ${question}`);
|
|
1360
1495
|
});
|
|
1361
1496
|
}
|
|
1362
1497
|
else {
|
|
1363
|
-
console.log(chalk.gray(
|
|
1498
|
+
console.log(chalk.gray(" (none)"));
|
|
1364
1499
|
}
|
|
1365
1500
|
// Last updated
|
|
1366
|
-
console.log(chalk.bold(
|
|
1501
|
+
console.log(chalk.bold("\nLast Updated:"));
|
|
1367
1502
|
const updatedDate = new Date(sessionCtx.updated_at);
|
|
1368
1503
|
console.log(` ${updatedDate.toISOString()}`);
|
|
1369
1504
|
console.log(chalk.gray(` (${updatedDate.toLocaleString()})`));
|