@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
|
@@ -0,0 +1,581 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session API Routes
|
|
3
|
+
*
|
|
4
|
+
* REST endpoints for session data:
|
|
5
|
+
* - GET /api/sessions - list sessions with summaries
|
|
6
|
+
* - GET /api/sessions/:id - get session metadata and detail
|
|
7
|
+
* - GET /api/sessions/:id/events - get session events from events.jsonl
|
|
8
|
+
* - GET /api/sessions/:id/events/:seq - get single event with blob resolution
|
|
9
|
+
*
|
|
10
|
+
* AC Coverage:
|
|
11
|
+
* - @ui-session-stream ac-1: Session events as structured blocks
|
|
12
|
+
* - @ui-session-stream ac-4: Session metadata, spec context, budget for context panel
|
|
13
|
+
* - @session-legacy-migration ac-read-fallback: Detect-and-warn on all session read endpoints
|
|
14
|
+
* - @session-summary-cache ac-cache-build: Cache built on first list request
|
|
15
|
+
* - @session-summary-cache ac-cache-invalidate: Cache refreshed via directory listing diff
|
|
16
|
+
* - @session-summary-cache ac-active-refresh: Active sessions recomputed on each request
|
|
17
|
+
* - @session-event-detail-endpoint ac-single-event-fetch: Single event by seq with blob resolution
|
|
18
|
+
* - @session-event-detail-endpoint ac-blob-resolution: Blob pointers resolved to full content
|
|
19
|
+
* - @session-event-detail-endpoint ac-not-found: 404 for missing session or seq
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { Elysia, t } from 'elysia';
|
|
23
|
+
import {
|
|
24
|
+
getSession,
|
|
25
|
+
readEvents,
|
|
26
|
+
readEventBySeq,
|
|
27
|
+
deduplicatePhasedToolCalls,
|
|
28
|
+
resolveSessionId,
|
|
29
|
+
resolveSessionBlobPointers,
|
|
30
|
+
getBudget,
|
|
31
|
+
searchSessionEvents,
|
|
32
|
+
type SessionLogSummary,
|
|
33
|
+
} from '../../sessions/store.js';
|
|
34
|
+
import {
|
|
35
|
+
countLegacySessions,
|
|
36
|
+
} from '../../sessions/legacy.js';
|
|
37
|
+
import {
|
|
38
|
+
initContext,
|
|
39
|
+
loadAllTasks,
|
|
40
|
+
loadAllItems,
|
|
41
|
+
ReferenceIndex,
|
|
42
|
+
AlignmentIndex,
|
|
43
|
+
type KspecContext,
|
|
44
|
+
} from '../../parser/index.js';
|
|
45
|
+
import { resolveRefTitle } from './ref-resolution.js';
|
|
46
|
+
import { getSessionCache } from '../../sessions/cache.js';
|
|
47
|
+
import { SessionStatusSchema } from '../../sessions/types.js';
|
|
48
|
+
import { parseTimeSpec } from '../../utils/time.js';
|
|
49
|
+
|
|
50
|
+
type SessionListQuery = {
|
|
51
|
+
status?: string | string[];
|
|
52
|
+
agent_type?: string | string[];
|
|
53
|
+
agent_id?: string | string[];
|
|
54
|
+
trigger?: string | string[];
|
|
55
|
+
task_id?: string;
|
|
56
|
+
spec_ref?: string;
|
|
57
|
+
since?: string;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
function normalizeValues(value?: string | string[]): string[] {
|
|
61
|
+
if (!value) return [];
|
|
62
|
+
return Array.isArray(value) ? value : [value];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function sortSessionSummaries(summaries: SessionLogSummary[]): SessionLogSummary[] {
|
|
66
|
+
return [...summaries].sort(
|
|
67
|
+
(a, b) => new Date(b.started_at).getTime() - new Date(a.started_at).getTime(),
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function buildTaskRefSet(task: { _ulid: string; slugs: string[] }): Set<string> {
|
|
72
|
+
const refs = new Set<string>([task._ulid, `@${task._ulid}`]);
|
|
73
|
+
for (const slug of task.slugs) {
|
|
74
|
+
refs.add(slug);
|
|
75
|
+
refs.add(`@${slug}`);
|
|
76
|
+
}
|
|
77
|
+
return refs;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function filterSessionsByTaskRefs(
|
|
81
|
+
summaries: SessionLogSummary[],
|
|
82
|
+
refs: Set<string>,
|
|
83
|
+
): SessionLogSummary[] {
|
|
84
|
+
return summaries.filter((summary) => {
|
|
85
|
+
if (!summary.task_id) return false;
|
|
86
|
+
const normalized = summary.task_id.startsWith('@')
|
|
87
|
+
? summary.task_id.slice(1)
|
|
88
|
+
: summary.task_id;
|
|
89
|
+
return refs.has(summary.task_id) || refs.has(normalized);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async function filterSessionSummaries(
|
|
94
|
+
ctx: KspecContext,
|
|
95
|
+
query: SessionListQuery,
|
|
96
|
+
): Promise<
|
|
97
|
+
| { summaries: SessionLogSummary[]; unfilteredTotal: number }
|
|
98
|
+
| {
|
|
99
|
+
error: {
|
|
100
|
+
status: number;
|
|
101
|
+
body: {
|
|
102
|
+
error: string;
|
|
103
|
+
message?: string;
|
|
104
|
+
suggestion?: string;
|
|
105
|
+
details?: Array<{ field: string; message: string }>;
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
> {
|
|
110
|
+
const validStatuses = SessionStatusSchema.options;
|
|
111
|
+
const statusValues = normalizeValues(query.status);
|
|
112
|
+
const invalidStatuses = statusValues.filter(
|
|
113
|
+
(status) => !validStatuses.includes(status as typeof validStatuses[number]),
|
|
114
|
+
);
|
|
115
|
+
if (invalidStatuses.length > 0) {
|
|
116
|
+
return {
|
|
117
|
+
error: {
|
|
118
|
+
status: 400,
|
|
119
|
+
body: {
|
|
120
|
+
error: 'invalid_filter',
|
|
121
|
+
details: [
|
|
122
|
+
{
|
|
123
|
+
field: 'status',
|
|
124
|
+
message: `Invalid status value(s): ${invalidStatuses.join(', ')}. Valid values: ${validStatuses.join(', ')}`,
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const sessionCache = getSessionCache(ctx.sessionsDir);
|
|
133
|
+
let filtered = sortSessionSummaries(await sessionCache.getAll(ctx.sessionsDir));
|
|
134
|
+
// AC: @session-filter-controls ac-filter-counts — Capture unfiltered total before applying filters
|
|
135
|
+
const unfilteredTotal = filtered.length;
|
|
136
|
+
|
|
137
|
+
if (statusValues.length > 0) {
|
|
138
|
+
filtered = filtered.filter((summary) => statusValues.includes(summary.status));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const agentTypeValues = normalizeValues(query.agent_type);
|
|
142
|
+
if (agentTypeValues.length > 0) {
|
|
143
|
+
filtered = filtered.filter((summary) => agentTypeValues.includes(summary.agent_type));
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const agentIdValues = normalizeValues(query.agent_id);
|
|
147
|
+
if (agentIdValues.length > 0) {
|
|
148
|
+
filtered = filtered.filter(
|
|
149
|
+
(summary) => summary.agent_id != null && agentIdValues.includes(summary.agent_id),
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const triggerValues = normalizeValues(query.trigger);
|
|
154
|
+
if (triggerValues.length > 0) {
|
|
155
|
+
filtered = filtered.filter((summary) => {
|
|
156
|
+
if (!summary.trigger) return false;
|
|
157
|
+
return triggerValues.some((value) => {
|
|
158
|
+
if (value === 'dispatched') return summary.trigger!.startsWith('task.');
|
|
159
|
+
return summary.trigger === value;
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
let tasks: Awaited<ReturnType<typeof loadAllTasks>> | null = null;
|
|
165
|
+
let items: Awaited<ReturnType<typeof loadAllItems>> | null = null;
|
|
166
|
+
const ensureAlignmentContext = async () => {
|
|
167
|
+
if (!tasks) tasks = await loadAllTasks(ctx);
|
|
168
|
+
if (!items) items = await loadAllItems(ctx);
|
|
169
|
+
return { tasks, items };
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
if (query.task_id) {
|
|
173
|
+
const { tasks: loadedTasks, items: loadedItems } = await ensureAlignmentContext();
|
|
174
|
+
const refIndex = new ReferenceIndex(loadedTasks, loadedItems);
|
|
175
|
+
const resolved = refIndex.resolve(
|
|
176
|
+
query.task_id.startsWith('@') ? query.task_id.slice(1) : query.task_id,
|
|
177
|
+
);
|
|
178
|
+
if (!resolved.ok) {
|
|
179
|
+
return {
|
|
180
|
+
error: {
|
|
181
|
+
status: 404,
|
|
182
|
+
body: {
|
|
183
|
+
error: 'not_found',
|
|
184
|
+
message: `Task reference "${query.task_id}" not found`,
|
|
185
|
+
suggestion: 'Use GET /api/tasks or kspec task list to find valid task references',
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const matchTask = loadedTasks.find((task) => task._ulid === resolved.ulid);
|
|
192
|
+
if (matchTask) {
|
|
193
|
+
filtered = filterSessionsByTaskRefs(filtered, buildTaskRefSet(matchTask));
|
|
194
|
+
} else {
|
|
195
|
+
filtered = [];
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (query.spec_ref) {
|
|
200
|
+
const { tasks: loadedTasks, items: loadedItems } = await ensureAlignmentContext();
|
|
201
|
+
const refIndex = new ReferenceIndex(loadedTasks, loadedItems);
|
|
202
|
+
const alignmentIndex = new AlignmentIndex(loadedTasks, loadedItems);
|
|
203
|
+
alignmentIndex.buildLinks(refIndex);
|
|
204
|
+
|
|
205
|
+
const resolved = refIndex.resolve(
|
|
206
|
+
query.spec_ref.startsWith('@') ? query.spec_ref.slice(1) : query.spec_ref,
|
|
207
|
+
);
|
|
208
|
+
if (!resolved.ok) {
|
|
209
|
+
return {
|
|
210
|
+
error: {
|
|
211
|
+
status: 404,
|
|
212
|
+
body: {
|
|
213
|
+
error: 'not_found',
|
|
214
|
+
message: `Spec reference "${query.spec_ref}" not found`,
|
|
215
|
+
suggestion: 'Use GET /api/items or kspec item list to find valid spec references',
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
const taskRefs = new Set<string>();
|
|
222
|
+
for (const task of alignmentIndex.getTasksForSpec(resolved.ulid)) {
|
|
223
|
+
for (const ref of buildTaskRefSet(task)) {
|
|
224
|
+
taskRefs.add(ref);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
filtered = filterSessionsByTaskRefs(filtered, taskRefs);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (query.since) {
|
|
231
|
+
const sinceDate = parseTimeSpec(query.since);
|
|
232
|
+
if (!sinceDate) {
|
|
233
|
+
return {
|
|
234
|
+
error: {
|
|
235
|
+
status: 400,
|
|
236
|
+
body: {
|
|
237
|
+
error: 'invalid_filter',
|
|
238
|
+
details: [
|
|
239
|
+
{
|
|
240
|
+
field: 'since',
|
|
241
|
+
message: `Invalid time value: "${query.since}". Use ISO 8601 format or a relative value like 7d, 24h, 2w, or 1m.`,
|
|
242
|
+
},
|
|
243
|
+
],
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
filtered = filtered.filter(
|
|
249
|
+
(summary) => new Date(summary.started_at).getTime() >= sinceDate.getTime(),
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return { summaries: filtered, unfilteredTotal };
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export function createSessionRoutes() {
|
|
257
|
+
return new Elysia({ prefix: '/api/sessions' })
|
|
258
|
+
|
|
259
|
+
// List all sessions with summaries, pagination, and filtering
|
|
260
|
+
// AC: @session-legacy-migration ac-read-fallback ac-list-merge — detect-and-warn for legacy sessions
|
|
261
|
+
// AC: @session-summary-cache ac-cache-build — Uses cached summaries instead of re-reading all files
|
|
262
|
+
// AC: @session-list-pagination-api ac-pagination — offset/limit pagination with total
|
|
263
|
+
// AC: @session-list-pagination-api ac-metadata-only — Only reads session.yaml, uses cache
|
|
264
|
+
// AC: @ui-api-ref-resolution ac-1 — Include task_title resolved server-side
|
|
265
|
+
.get('/', async ({ query, error: errorResponse, projectContext }) => {
|
|
266
|
+
const ctx = await initContext(projectContext.path);
|
|
267
|
+
const filteredResult = await filterSessionSummaries(ctx, query);
|
|
268
|
+
if ('error' in filteredResult) {
|
|
269
|
+
return errorResponse(filteredResult.error.status, filteredResult.error.body);
|
|
270
|
+
}
|
|
271
|
+
const filtered = filteredResult.summaries;
|
|
272
|
+
const { unfilteredTotal } = filteredResult;
|
|
273
|
+
|
|
274
|
+
// AC: @session-list-pagination-api ac-pagination — Apply pagination after filtering
|
|
275
|
+
// AC: @trait-api-endpoint ac-4 — {items, total, offset, limit} wrapper
|
|
276
|
+
const total = filtered.length;
|
|
277
|
+
const offset = Number(query.offset) || 0;
|
|
278
|
+
const limit = Number(query.limit) || total;
|
|
279
|
+
const paginated = filtered.slice(offset, offset + limit);
|
|
280
|
+
|
|
281
|
+
// AC: @ui-api-ref-resolution ac-1 — Resolve task_title for session summaries
|
|
282
|
+
let refIndex: ReferenceIndex | null = null;
|
|
283
|
+
const taskIdsPresent = paginated.some((s) => s.task_id);
|
|
284
|
+
if (taskIdsPresent) {
|
|
285
|
+
try {
|
|
286
|
+
const tasks = await loadAllTasks(ctx);
|
|
287
|
+
const items = await loadAllItems(ctx);
|
|
288
|
+
refIndex = new ReferenceIndex(tasks, items);
|
|
289
|
+
} catch {
|
|
290
|
+
// Non-critical — task_title will be null
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
const enriched = paginated.map((s) => ({
|
|
294
|
+
...s,
|
|
295
|
+
task_title: s.task_id && refIndex ? resolveRefTitle(refIndex, s.task_id) : null,
|
|
296
|
+
}));
|
|
297
|
+
|
|
298
|
+
// Detect legacy sessions and include warning in response
|
|
299
|
+
const legacyCount = await countLegacySessions(ctx.specDir);
|
|
300
|
+
|
|
301
|
+
// AC: @session-filter-controls ac-filter-counts — Include unfiltered_total in response
|
|
302
|
+
return {
|
|
303
|
+
items: enriched,
|
|
304
|
+
total,
|
|
305
|
+
unfiltered_total: unfilteredTotal,
|
|
306
|
+
offset,
|
|
307
|
+
limit,
|
|
308
|
+
...(legacyCount > 0 ? {
|
|
309
|
+
warning: `${legacyCount} legacy session(s) found in .kspec/sessions/. Run \`kspec session migrate\` to move them to .kspec-sessions/.`,
|
|
310
|
+
} : {}),
|
|
311
|
+
};
|
|
312
|
+
}, {
|
|
313
|
+
query: t.Object({
|
|
314
|
+
status: t.Optional(t.Union([t.String(), t.Array(t.String())])),
|
|
315
|
+
agent_type: t.Optional(t.Union([t.String(), t.Array(t.String())])),
|
|
316
|
+
agent_id: t.Optional(t.Union([t.String(), t.Array(t.String())])),
|
|
317
|
+
trigger: t.Optional(t.Union([t.String(), t.Array(t.String())])),
|
|
318
|
+
task_id: t.Optional(t.String()),
|
|
319
|
+
spec_ref: t.Optional(t.String()),
|
|
320
|
+
since: t.Optional(t.String()),
|
|
321
|
+
limit: t.Optional(t.String()),
|
|
322
|
+
offset: t.Optional(t.String()),
|
|
323
|
+
}),
|
|
324
|
+
})
|
|
325
|
+
|
|
326
|
+
// AC: @session-text-search ac-api-search
|
|
327
|
+
// AC: @session-text-search ac-scope-narrowing — metadata filters narrow the scanned sessions first
|
|
328
|
+
.get('/search', async ({ query, error: errorResponse, projectContext }) => {
|
|
329
|
+
const ctx = await initContext(projectContext.path);
|
|
330
|
+
const normalizedQuery = query.q.trim();
|
|
331
|
+
if (normalizedQuery.length === 0) {
|
|
332
|
+
return {
|
|
333
|
+
items: [],
|
|
334
|
+
total_sessions: 0,
|
|
335
|
+
total_matches: 0,
|
|
336
|
+
query: '',
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const filteredResult = await filterSessionSummaries(ctx, query);
|
|
341
|
+
if ('error' in filteredResult) {
|
|
342
|
+
return errorResponse(filteredResult.error.status, filteredResult.error.body);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
const limit = Number(query.limit) || 50;
|
|
346
|
+
const items = await searchSessionEvents(ctx.sessionsDir, normalizedQuery, {
|
|
347
|
+
sessionSummaries: filteredResult.summaries,
|
|
348
|
+
limit,
|
|
349
|
+
});
|
|
350
|
+
const totalMatches = items.reduce((sum, session) => sum + session.matches.length, 0);
|
|
351
|
+
|
|
352
|
+
return {
|
|
353
|
+
items,
|
|
354
|
+
total_sessions: items.length,
|
|
355
|
+
total_matches: totalMatches,
|
|
356
|
+
query: normalizedQuery,
|
|
357
|
+
};
|
|
358
|
+
}, {
|
|
359
|
+
query: t.Object({
|
|
360
|
+
q: t.String(),
|
|
361
|
+
status: t.Optional(t.Union([t.String(), t.Array(t.String())])),
|
|
362
|
+
agent_type: t.Optional(t.Union([t.String(), t.Array(t.String())])),
|
|
363
|
+
agent_id: t.Optional(t.Union([t.String(), t.Array(t.String())])),
|
|
364
|
+
trigger: t.Optional(t.Union([t.String(), t.Array(t.String())])),
|
|
365
|
+
task_id: t.Optional(t.String()),
|
|
366
|
+
spec_ref: t.Optional(t.String()),
|
|
367
|
+
since: t.Optional(t.String()),
|
|
368
|
+
limit: t.Optional(t.String()),
|
|
369
|
+
}),
|
|
370
|
+
})
|
|
371
|
+
|
|
372
|
+
// Get single session metadata
|
|
373
|
+
// AC: @ui-session-stream ac-4 — Includes spec context, budget, and task info
|
|
374
|
+
// AC: @session-legacy-migration ac-read-fallback — detect-and-warn for legacy sessions
|
|
375
|
+
.get('/:id', async ({ params, error: errorResponse, projectContext }) => {
|
|
376
|
+
const ctx = await initContext(projectContext.path);
|
|
377
|
+
|
|
378
|
+
// Resolve session ID (supports prefix matching)
|
|
379
|
+
const resolution = await resolveSessionId(ctx.sessionsDir, params.id);
|
|
380
|
+
if (!resolution.ok) {
|
|
381
|
+
if (resolution.error === 'ambiguous') {
|
|
382
|
+
return errorResponse(400, {
|
|
383
|
+
error: 'ambiguous_id',
|
|
384
|
+
message: `Ambiguous session ID: ${params.id} matches ${resolution.matches.length} sessions`,
|
|
385
|
+
suggestion: 'Provide a longer prefix to uniquely identify the session',
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
return errorResponse(404, {
|
|
389
|
+
error: 'not_found',
|
|
390
|
+
message: `Session not found: ${params.id}`,
|
|
391
|
+
suggestion: 'Use GET /api/sessions to list available sessions',
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
const sessionCache = getSessionCache(ctx.sessionsDir);
|
|
396
|
+
const detail = await sessionCache.get(ctx.sessionsDir, resolution.id);
|
|
397
|
+
if (!detail) {
|
|
398
|
+
return errorResponse(404, {
|
|
399
|
+
error: 'not_found',
|
|
400
|
+
message: `Session not found: ${params.id}`,
|
|
401
|
+
suggestion: 'Use GET /api/sessions to list available sessions',
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
const metadata = await getSession(ctx.sessionsDir, resolution.id);
|
|
406
|
+
|
|
407
|
+
// AC: @ui-session-stream ac-4 — Resolve spec context from task's spec_ref
|
|
408
|
+
// AC: @ui-api-ref-resolution ac-1 — Resolve task_title
|
|
409
|
+
let spec_context: {
|
|
410
|
+
spec_ref: string;
|
|
411
|
+
title: string;
|
|
412
|
+
acceptance_criteria: Array<{ id: string; description: string }>;
|
|
413
|
+
} | null = null;
|
|
414
|
+
let task_title: string | null = null;
|
|
415
|
+
|
|
416
|
+
if (metadata?.task_id) {
|
|
417
|
+
try {
|
|
418
|
+
const tasks = await loadAllTasks(ctx);
|
|
419
|
+
const items = await loadAllItems(ctx);
|
|
420
|
+
const index = new ReferenceIndex(tasks, items);
|
|
421
|
+
const taskResult = index.resolve(metadata.task_id);
|
|
422
|
+
if (taskResult.ok) {
|
|
423
|
+
const task = taskResult.item as { title?: string; spec_ref?: string };
|
|
424
|
+
task_title = task.title ?? null;
|
|
425
|
+
if (task.spec_ref) {
|
|
426
|
+
const specResult = index.resolve(task.spec_ref);
|
|
427
|
+
if (specResult.ok) {
|
|
428
|
+
const specItem = specResult.item as {
|
|
429
|
+
title: string;
|
|
430
|
+
acceptance_criteria?: Array<{ description?: string; given?: string }>;
|
|
431
|
+
};
|
|
432
|
+
spec_context = {
|
|
433
|
+
spec_ref: task.spec_ref,
|
|
434
|
+
title: specItem.title,
|
|
435
|
+
acceptance_criteria: (specItem.acceptance_criteria ?? []).map((ac, i) => ({
|
|
436
|
+
id: `ac-${i + 1}`,
|
|
437
|
+
description: ac.description ?? ac.given ?? '',
|
|
438
|
+
})),
|
|
439
|
+
};
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
} catch {
|
|
444
|
+
// Non-critical — spec context is optional
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// AC: @ui-session-stream ac-4 — Include budget info
|
|
449
|
+
let budget: { max_per_cycle: number; started_this_cycle: number } | null = null;
|
|
450
|
+
try {
|
|
451
|
+
budget = await getBudget(ctx.sessionsDir, resolution.id);
|
|
452
|
+
} catch {
|
|
453
|
+
// No budget configured — that's fine
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// Detect legacy sessions and include warning in response
|
|
457
|
+
const legacyCount = await countLegacySessions(ctx.specDir);
|
|
458
|
+
|
|
459
|
+
return {
|
|
460
|
+
...detail,
|
|
461
|
+
task_id: metadata?.task_id,
|
|
462
|
+
task_title,
|
|
463
|
+
agent_id: metadata?.agent_id,
|
|
464
|
+
trigger: metadata?.trigger ?? 'legacy',
|
|
465
|
+
spec_context,
|
|
466
|
+
budget,
|
|
467
|
+
...(legacyCount > 0 ? {
|
|
468
|
+
warning: `${legacyCount} legacy session(s) found in .kspec/sessions/. Run \`kspec session migrate\` to move them to .kspec-sessions/.`,
|
|
469
|
+
} : {}),
|
|
470
|
+
};
|
|
471
|
+
})
|
|
472
|
+
|
|
473
|
+
// Get session events
|
|
474
|
+
// AC: @session-legacy-migration ac-read-fallback — detect-and-warn for legacy sessions
|
|
475
|
+
.get('/:id/events', async ({ params, query, error: errorResponse, projectContext }) => {
|
|
476
|
+
const ctx = await initContext(projectContext.path);
|
|
477
|
+
|
|
478
|
+
const resolution = await resolveSessionId(ctx.sessionsDir, params.id);
|
|
479
|
+
if (!resolution.ok) {
|
|
480
|
+
if (resolution.error === 'ambiguous') {
|
|
481
|
+
return errorResponse(400, {
|
|
482
|
+
error: 'ambiguous_id',
|
|
483
|
+
message: `Ambiguous session ID: ${params.id} matches ${resolution.matches.length} sessions`,
|
|
484
|
+
suggestion: 'Provide a longer prefix to uniquely identify the session',
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
return errorResponse(404, {
|
|
488
|
+
error: 'not_found',
|
|
489
|
+
message: `Session not found: ${params.id}`,
|
|
490
|
+
suggestion: 'Use GET /api/sessions to list available sessions',
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
let events = await readEvents(ctx.sessionsDir, resolution.id);
|
|
495
|
+
|
|
496
|
+
// Deduplicate phased tool calls
|
|
497
|
+
events = deduplicatePhasedToolCalls(events);
|
|
498
|
+
|
|
499
|
+
// Filter by since_seq if provided (for incremental loading)
|
|
500
|
+
const sinceSeq = query.since_seq !== undefined ? parseInt(query.since_seq, 10) : undefined;
|
|
501
|
+
if (sinceSeq !== undefined && !isNaN(sinceSeq)) {
|
|
502
|
+
events = events.filter(e => e.seq > sinceSeq);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// Detect legacy sessions and include warning in response
|
|
506
|
+
const legacyCount = await countLegacySessions(ctx.specDir);
|
|
507
|
+
|
|
508
|
+
return {
|
|
509
|
+
events,
|
|
510
|
+
total: events.length,
|
|
511
|
+
...(legacyCount > 0 ? {
|
|
512
|
+
warning: `${legacyCount} legacy session(s) found in .kspec/sessions/. Run \`kspec session migrate\` to move them to .kspec-sessions/.`,
|
|
513
|
+
} : {}),
|
|
514
|
+
};
|
|
515
|
+
}, {
|
|
516
|
+
query: t.Object({
|
|
517
|
+
since_seq: t.Optional(t.String()),
|
|
518
|
+
}),
|
|
519
|
+
})
|
|
520
|
+
|
|
521
|
+
// Get single session event by sequence number with blob resolution
|
|
522
|
+
// AC: @session-event-detail-endpoint ac-single-event-fetch — Returns full event for seq
|
|
523
|
+
// AC: @session-event-detail-endpoint ac-blob-resolution — Blob pointers resolved to full content
|
|
524
|
+
// AC: @session-event-detail-endpoint ac-not-found — 404 for missing session or seq
|
|
525
|
+
// AC: @trait-api-endpoint ac-1 — Returns 2xx with JSON body on success
|
|
526
|
+
// AC: @trait-api-endpoint ac-2 — Returns 404 for invalid session or seq ref
|
|
527
|
+
.get('/:id/events/:seq', async ({ params, error: errorResponse, projectContext }) => {
|
|
528
|
+
const ctx = await initContext(projectContext.path);
|
|
529
|
+
|
|
530
|
+
// Resolve session ID (supports prefix matching)
|
|
531
|
+
const resolution = await resolveSessionId(ctx.sessionsDir, params.id);
|
|
532
|
+
if (!resolution.ok) {
|
|
533
|
+
if (resolution.error === 'ambiguous') {
|
|
534
|
+
return errorResponse(400, {
|
|
535
|
+
error: 'ambiguous_id',
|
|
536
|
+
message: `Ambiguous session ID: ${params.id} matches ${resolution.matches.length} sessions`,
|
|
537
|
+
suggestion: 'Provide a longer prefix to uniquely identify the session',
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
return errorResponse(404, {
|
|
541
|
+
error: 'not_found',
|
|
542
|
+
message: `Session not found: ${params.id}`,
|
|
543
|
+
suggestion: 'Use GET /api/sessions to list available sessions',
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// Parse and validate seq parameter
|
|
548
|
+
const seq = parseInt(params.seq, 10);
|
|
549
|
+
if (isNaN(seq) || seq < 0) {
|
|
550
|
+
return errorResponse(400, {
|
|
551
|
+
error: 'invalid_parameter',
|
|
552
|
+
details: [{
|
|
553
|
+
field: 'seq',
|
|
554
|
+
message: `Invalid sequence number: "${params.seq}". Must be a non-negative integer.`,
|
|
555
|
+
}],
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// Targeted single-event read
|
|
560
|
+
const event = await readEventBySeq(ctx.sessionsDir, resolution.id, seq);
|
|
561
|
+
if (!event) {
|
|
562
|
+
return errorResponse(404, {
|
|
563
|
+
error: 'not_found',
|
|
564
|
+
message: `Event with seq ${seq} not found in session ${params.id}`,
|
|
565
|
+
suggestion: 'Use GET /api/sessions/:id/events to list available events',
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
// Resolve blob pointers in event data
|
|
570
|
+
const resolvedData = await resolveSessionBlobPointers(
|
|
571
|
+
ctx.sessionsDir,
|
|
572
|
+
resolution.id,
|
|
573
|
+
event.data,
|
|
574
|
+
);
|
|
575
|
+
|
|
576
|
+
return {
|
|
577
|
+
...event,
|
|
578
|
+
data: resolvedData,
|
|
579
|
+
};
|
|
580
|
+
});
|
|
581
|
+
}
|