hadara 0.3.3 → 0.4.0-rc.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.
Files changed (80) hide show
  1. package/README.md +26 -18
  2. package/dist/cli/dashboard.js +28 -9
  3. package/dist/cli/docs.js +50 -0
  4. package/dist/cli/evidence.js +113 -0
  5. package/dist/cli/handoff.js +13 -0
  6. package/dist/cli/help.js +4 -3
  7. package/dist/cli/init.js +615 -111
  8. package/dist/cli/legacy-boundary.js +77 -0
  9. package/dist/cli/main.js +31 -0
  10. package/dist/cli/package-smoke.js +34 -1
  11. package/dist/cli/release-artifact.js +9 -0
  12. package/dist/cli/release-closeout.js +22 -0
  13. package/dist/cli/release-publish.js +9 -0
  14. package/dist/cli/task.js +85 -21
  15. package/dist/cli/validation.js +71 -0
  16. package/dist/context/context-pack.js +204 -26
  17. package/dist/context/session-start.js +85 -6
  18. package/dist/context/task-extractors.js +3 -2
  19. package/dist/core/schema.js +22 -0
  20. package/dist/evidence/evidence.js +131 -9
  21. package/dist/evidence/semantics.js +3 -1
  22. package/dist/handoff/handoff-stale-problems.js +155 -0
  23. package/dist/handoff/handoff-suggestion.js +6 -1
  24. package/dist/harness/validate.js +316 -58
  25. package/dist/schemas/close-source.schema.json +33 -0
  26. package/dist/schemas/context-pack.schema.json +23 -0
  27. package/dist/schemas/docs-inbox.schema.json +50 -0
  28. package/dist/schemas/docs-read-map.schema.json +83 -0
  29. package/dist/schemas/docs-register.schema.json +70 -0
  30. package/dist/schemas/evidence-projection.schema.json +35 -0
  31. package/dist/schemas/evidence-summary.schema.json +73 -0
  32. package/dist/schemas/handoff-stale-problems.schema.json +64 -0
  33. package/dist/schemas/package-recycle.schema.json +150 -0
  34. package/dist/schemas/release-closeout.schema.json +39 -0
  35. package/dist/schemas/schema-index.json +79 -2
  36. package/dist/schemas/session-start.schema.json +30 -0
  37. package/dist/schemas/smoke-evidence-summary.schema.json +1 -1
  38. package/dist/schemas/task-audit-close.schema.json +7 -0
  39. package/dist/schemas/task-close.schema.json +4 -0
  40. package/dist/schemas/task-finalize.schema.json +40 -1
  41. package/dist/schemas/task-status.schema.json +117 -0
  42. package/dist/schemas/task-workbench.schema.json +97 -2
  43. package/dist/schemas/validation-run.schema.json +103 -0
  44. package/dist/services/capability-registry.js +326 -47
  45. package/dist/services/ci-gate.js +4 -2
  46. package/dist/services/dashboard-bootstrap.js +6 -6
  47. package/dist/services/dashboard-cache.js +2 -0
  48. package/dist/services/dashboard-task-detail.js +42 -13
  49. package/dist/services/dashboard-timeline.js +2 -2
  50. package/dist/services/docs-registry.js +485 -30
  51. package/dist/services/evidence-lint.js +9 -3
  52. package/dist/services/evidence-summary.js +66 -0
  53. package/dist/services/lifecycle-guide.js +11 -12
  54. package/dist/services/operational-debt.js +8 -14
  55. package/dist/services/operations-status-service.js +7 -1
  56. package/dist/services/package-recycle.js +762 -0
  57. package/dist/services/protocol-consistency.js +11 -5
  58. package/dist/services/protocol-migration.js +1 -1
  59. package/dist/services/release-closeout.js +136 -0
  60. package/dist/services/state-projection.js +31 -16
  61. package/dist/services/task-read-model.js +3 -7
  62. package/dist/services/task-workbench.js +582 -29
  63. package/dist/services/validation-run.js +325 -0
  64. package/dist/services/workbench-next-actions.js +31 -20
  65. package/dist/services/write-preflight.js +0 -7
  66. package/dist/task/authoring-guidance.js +74 -0
  67. package/dist/task/lifecycle-next-actions.js +0 -1
  68. package/dist/task/task-capsule.js +6 -11
  69. package/dist/task/task-close-repair-plan.js +3 -2
  70. package/dist/task/task-close.js +319 -39
  71. package/dist/task/task-complete-flow.js +4 -3
  72. package/dist/task/task-finalize.js +184 -20
  73. package/dist/task/task-finish.js +36 -8
  74. package/dist/task/task-lifecycle.js +14 -9
  75. package/dist/task/task-templates.js +5 -24
  76. package/dist/task/task-upgrade-scaffold.js +9 -60
  77. package/dist/tui/constants.js +1 -7
  78. package/dist/tui/read-model.js +4 -4
  79. package/dist/tui/snapshot.js +14 -2
  80. package/package.json +1 -1
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  <p align="center">
8
8
  <img alt="Stable npm release" src="https://img.shields.io/badge/npm-0.3.3-blue">
9
- <img alt="Source version" src="https://img.shields.io/badge/source-0.3.3-blue">
9
+ <img alt="Source version" src="https://img.shields.io/badge/source-0.4.0--rc.0-blue">
10
10
  <img alt="Node.js" src="https://img.shields.io/badge/node-%3E%3D22-brightgreen">
11
11
  <img alt="License" src="https://img.shields.io/badge/license-MIT-lightgrey">
12
12
  </p>
@@ -27,20 +27,27 @@ Current stable npm release:
27
27
  hadara@0.3.3
28
28
  ```
29
29
 
30
- Previous release candidate:
30
+ Current source release candidate:
31
31
 
32
32
  ```text
33
- hadara@0.3.3-rc.0
33
+ hadara@0.4.0-rc.0
34
34
  ```
35
35
 
36
- The 0.3.3 line promotes the context-routing and lifecycle release candidate after dogfood hardening. It adds project context graph, context pack/slice/session-start surfaces, explicit context cache warm paths, and makes the finalize-first lifecycle the default agent-facing task loop.
36
+ Previous published release candidate:
37
37
 
38
- Phase labels are internal implementation phases, not npm release-candidate labels. The stable `0.3.3` package is the default install target; `0.3.3-rc.0` remains the previous release candidate.
38
+ ```text
39
+ hadara@0.3.4-rc.0
40
+ ```
41
+
42
+ The 0.4.0 source line is a breaking productization release candidate after stable 0.3.3 and the published 0.3.4-rc.0 agent UX line. It keeps the context-routing and finalize-first lifecycle baseline, then simplifies new projects around a productized 0.4 scaffold, registry-backed docs read maps, a four-file Task Capsule, generated evidence projection, a normalized close-source contract, and fail-closed legacy mutation boundaries.
43
+
44
+ Phase labels are internal implementation phases, not npm release-candidate labels. The stable `0.3.3` package is the default install target; `0.4.0-rc.0` is the current source candidate and must not be treated as published until an approval-gated publish capsule completes.
39
45
 
40
46
  | Surface | Status |
41
47
  |---|---|
42
48
  | Current stable | [`hadara@0.3.3`](docs/RELEASE_NOTES.md#033) |
43
- | Previous RC | [`hadara@0.3.3-rc.0`](docs/RELEASE_NOTES.md#033-rc0) |
49
+ | Source candidate | [`hadara@0.4.0-rc.0`](docs/RELEASE_NOTES.md#040-rc0) |
50
+ | Previous RC | [`hadara@0.3.4-rc.0`](docs/RELEASE_NOTES.md#034-rc0) |
44
51
  | Previous stable | [`hadara@0.3.2`](docs/RELEASE_NOTES.md#032) |
45
52
  | Historical RCs | See [Release Notes](docs/RELEASE_NOTES.md). |
46
53
  | GitHub Release | Secondary target, approval-gated. |
@@ -48,7 +55,7 @@ Phase labels are internal implementation phases, not npm release-candidate label
48
55
  | PyPI/Python package | `hadara==0.2.0rc1` published preview bridge. |
49
56
  | Installer scripts / USB launchers | Deferred. |
50
57
 
51
- No release command should publish, create a GitHub Release, build Docker images, upload artifacts, or load token values unless an operator explicitly approves the mutation path for the active release capsule. Stable `0.3.3` is the npm package line; GitHub Release, Docker/PyPI publish, installer execution, and MCP release/package execution remain separate explicit mutations.
58
+ No release command should publish, create a GitHub Release, build Docker images, upload artifacts, or load token values unless an operator explicitly approves the mutation path for the active release capsule. Stable `0.3.3` is the npm package line until the `0.4.0-rc.0` publish capsule completes; GitHub Release, Docker/PyPI publish, installer execution, and MCP release/package execution remain separate explicit mutations.
52
59
 
53
60
  ## Install
54
61
 
@@ -69,11 +76,11 @@ npx hadara@0.3.3 help
69
76
  npx hadara@0.3.3 doctor --json
70
77
  ```
71
78
 
72
- Evaluate the previous release candidate explicitly:
79
+ After `0.4.0-rc.0` is published, evaluate it explicitly:
73
80
 
74
81
  ```bash
75
- npm install -g hadara@0.3.3-rc.0
76
- npx hadara@0.3.3-rc.0 help
82
+ npm install -g hadara@0.4.0-rc.0
83
+ npx hadara@0.4.0-rc.0 help
77
84
  ```
78
85
 
79
86
  For release or recycle evidence, prefer an isolated prefix install when PATH, global installs, or `npx` cache behavior may be stale:
@@ -109,7 +116,7 @@ Ask the CLI for the workflow before choosing commands:
109
116
  ```bash
110
117
  hadara help
111
118
  hadara help lifecycle
112
- hadara task next --json
119
+ hadara task status --json
113
120
  ```
114
121
 
115
122
  Use structured discovery when an agent or tool needs machine-readable command metadata:
@@ -122,15 +129,15 @@ hadara help command task.close
122
129
 
123
130
  ## Primary Capsule Lifecycle
124
131
 
125
- The 0.3.3 primary path is intentionally small. Agents should use `task finalize` as the default lifecycle close path:
132
+ The 0.4 primary path is intentionally small. Agents should start with compact context and use `task finalize` as the default lifecycle close path:
126
133
 
127
134
  ```bash
128
- hadara task next --json
135
+ hadara task status --json
136
+ hadara session start --task T-XXXX --json
129
137
  hadara task create "implement a focused change" --json
130
138
  hadara task status --task T-XXXX --json
131
139
  hadara evidence add-command --task T-XXXX --summary "..." --result passed --category validation --idempotency-key "command:T-XXXX:check" --json
132
140
  # Finalize Task Capsule docs and tracked state docs before closing.
133
- hadara task lifecycle --task T-XXXX --json
134
141
  hadara task finalize --task T-XXXX --json
135
142
  hadara task finalize --task T-XXXX --execute --plan-hash sha256:... --json
136
143
  hadara handoff suggest --task T-XXXX --json
@@ -154,8 +161,9 @@ Deferred Evidence v2 scope is explicit: rebuild preview/execute, `check-id`, `su
154
161
  Use read-only lifecycle diagnostics when you want a compact current-stage report, next recommended action, or close-proof repair explanation:
155
162
 
156
163
  ```bash
164
+ hadara task status --task T-XXXX --json
157
165
  hadara task complete --task T-XXXX --json
158
- hadara task lifecycle --task T-XXXX --json
166
+ hadara task lifecycle --task T-XXXX --json # compatibility
159
167
  hadara task close-repair-plan --task T-XXXX --json
160
168
  ```
161
169
 
@@ -260,7 +268,7 @@ Dashboard, TUI, Hermes, MCP, installer, package, release, and run commands stay
260
268
 
261
269
  ## Safety Boundaries
262
270
 
263
- HADARA 0.3.3 is not:
271
+ HADARA 0.4.0-rc.0 is not:
264
272
 
265
273
  - a full agent runtime;
266
274
  - Rack/enterprise behavior;
@@ -300,7 +308,7 @@ Portable/local state is not committed. Project docs, Task Capsules, and reduced
300
308
 
301
309
  `evidence.jsonl` is the canonical Task Capsule evidence source. `EVIDENCE.md` is a non-canonical human summary that can help review validation history, but it must not be treated as the source of truth for rebuild, migration, or resolution logic.
302
310
 
303
- 0.3.3 does not implement `hadara evidence rebuild --json` or an execute mode. Future rebuild work must first define whether a difference is formatting regeneration, managed-section drift, or data inconsistency before reporting `wouldChange`. Any later write-capable rebuild flow must be dry-run-first, reviewed, and before-hash guarded before it rewrites derived Markdown.
311
+ 0.4.0-rc.0 does not implement `hadara evidence rebuild --json` or an execute mode. Future rebuild work must first define whether a difference is formatting regeneration, managed-section drift, or data inconsistency before reporting `wouldChange`. Any later write-capable rebuild flow must be dry-run-first, reviewed, and before-hash guarded before it rewrites derived Markdown.
304
312
 
305
313
  ## Development / Contributing
306
314
 
@@ -313,7 +321,7 @@ hadara init --profile standard
313
321
  hadara init --profile governed
314
322
  ```
315
323
 
316
- Every profile generates `docs/TASK_WORKFLOW_COMMANDS.md` so fresh projects get the current 0.3.3 finalize-first lifecycle loop plus low-level proof-boundary reference commands.
324
+ Every profile generates the 0.4 project scaffold with compact agent entry docs, a docs registry, a workflow guide, and the current context-aware finalize-first lifecycle loop plus low-level proof-boundary reference commands.
317
325
 
318
326
  | Profile | Use When |
319
327
  |---|---|
@@ -20,7 +20,6 @@ const dashboard_heavy_projection_1 = require("../services/dashboard-heavy-projec
20
20
  const evidence_lint_1 = require("../services/evidence-lint");
21
21
  const evidence_list_1 = require("../services/evidence-list");
22
22
  const dashboard_timeline_1 = require("../services/dashboard-timeline");
23
- const operational_debt_1 = require("../services/operational-debt");
24
23
  const operations_status_service_1 = require("../services/operations-status-service");
25
24
  const task_read_model_1 = require("../services/task-read-model");
26
25
  const task_workbench_1 = require("../services/task-workbench");
@@ -93,8 +92,11 @@ function createDashboardApiResponse(projectRoot, requestUrl, method) {
93
92
  if (!url || !url.pathname.startsWith('/api/'))
94
93
  return null;
95
94
  const headOnly = normalizedMethod === 'HEAD';
96
- if (url.pathname === '/api/status')
97
- return jsonResponse((0, operations_status_service_1.createOpsStatusReport)(projectRoot), headOnly);
95
+ if (url.pathname === '/api/status') {
96
+ // Dashboard clients fetch operational debt separately; keep the status
97
+ // route cheap so a single slow debt scan cannot block first API paint.
98
+ return jsonResponse(readCachedOpsStatus(projectRoot, false, url.searchParams.get('cache') === 'bypass'), headOnly);
99
+ }
98
100
  if (url.pathname === '/api/dashboard/core') {
99
101
  const bypassProjection = url.searchParams.get('cache') === 'bypass';
100
102
  const status = bypassProjection ? null : (0, dashboard_refresh_1.createDashboardProjectionStatusReport)(projectRoot);
@@ -116,14 +118,19 @@ function createDashboardApiResponse(projectRoot, requestUrl, method) {
116
118
  return jsonResponse((0, dashboard_heavy_projection_1.createProjectedDashboardDebtReport)(projectRoot), headOnly);
117
119
  if (url.pathname === '/api/dashboard/bootstrap') {
118
120
  const selectedTaskId = url.searchParams.get('selectedTaskId')?.trim();
119
- const tier = url.searchParams.get('tier') === 'core' ? 'core' : 'full';
121
+ const tier = url.searchParams.get('tier') === 'full' ? 'full' : 'core';
120
122
  const keyParts = ['bootstrap'];
121
123
  if (tier === 'core')
122
124
  keyParts.push('core');
123
125
  if (selectedTaskId)
124
126
  keyParts.push('selected', selectedTaskId);
125
127
  const key = (0, dashboard_cache_1.createDashboardCacheKey)(projectRoot, ...keyParts);
126
- const cached = (0, dashboard_cache_1.getOrCreateCachedReport)(key, { ttlMs: dashboard_cache_1.DASHBOARD_CACHE_TTLS.bootstrap, bypass: url.searchParams.get('cache') === 'bypass' }, () => (0, dashboard_bootstrap_1.createDashboardBootstrapReport)(projectRoot, { tier, ...(selectedTaskId ? { selectedTaskId } : {}) }));
128
+ const cached = (0, dashboard_cache_1.getOrCreateCachedReport)(key, { ttlMs: dashboard_cache_1.DASHBOARD_CACHE_TTLS.bootstrap, bypass: url.searchParams.get('cache') === 'bypass' }, () => (0, dashboard_bootstrap_1.createDashboardBootstrapReport)(projectRoot, {
129
+ tier,
130
+ ...(selectedTaskId ? { selectedTaskId } : {}),
131
+ status: readCachedOpsStatus(projectRoot, tier === 'full', url.searchParams.get('cache') === 'bypass'),
132
+ tasks: readCachedTaskList(projectRoot, url.searchParams.get('cache') === 'bypass')
133
+ }));
127
134
  return jsonResponse((0, dashboard_cache_1.withDashboardCacheMetadata)(cached.value, cached.cache), headOnly);
128
135
  }
129
136
  if (url.pathname === '/api/dashboard/task-detail') {
@@ -137,11 +144,16 @@ function createDashboardApiResponse(projectRoot, requestUrl, method) {
137
144
  if (url.pathname === '/api/dashboard/cache/status')
138
145
  return jsonResponse((0, dashboard_cache_1.createDashboardCacheStatusReport)(), headOnly);
139
146
  if (url.pathname === '/api/tasks')
140
- return jsonResponse((0, task_read_model_1.createTaskListReport)(projectRoot), headOnly);
147
+ return jsonResponse(readCachedTaskList(projectRoot, url.searchParams.get('cache') === 'bypass'), headOnly);
141
148
  if (url.pathname === '/api/active-run')
142
149
  return jsonResponse((0, active_run_state_1.safeCreateActiveRunProjection)(projectRoot), headOnly);
143
- if (url.pathname === '/api/debt')
144
- return jsonResponse((0, operational_debt_1.createOperationalDebtReport)(projectRoot), headOnly);
150
+ if (url.pathname === '/api/debt') {
151
+ // Keep the legacy dashboard debt route on the same fast aggregate path as
152
+ // /api/dashboard/debt. The full operational-debt read model remains
153
+ // available through CLI/MCP surfaces; dashboard request handlers must not
154
+ // perform broad capsule scans on the hot API path.
155
+ return jsonResponse((0, dashboard_heavy_projection_1.createProjectedDashboardDebtReport)(projectRoot), headOnly);
156
+ }
145
157
  if (url.pathname === '/api/timeline') {
146
158
  const taskId = url.searchParams.get('taskId')?.trim();
147
159
  const key = taskId ? (0, dashboard_cache_1.createDashboardCacheKey)(projectRoot, 'timeline', taskId) : (0, dashboard_cache_1.createDashboardCacheKey)(projectRoot, 'timeline');
@@ -152,7 +164,8 @@ function createDashboardApiResponse(projectRoot, requestUrl, method) {
152
164
  const taskId = url.searchParams.get('taskId')?.trim();
153
165
  if (!taskId)
154
166
  return missingTaskId(headOnly);
155
- return jsonResponse((0, task_workbench_1.createTaskWorkbenchReport)(projectRoot, taskId), headOnly);
167
+ const detail = url.searchParams.get('detail') === 'full' ? 'full' : 'fast';
168
+ return jsonResponse((0, task_workbench_1.createTaskWorkbenchReport)(projectRoot, taskId, new Date(), { detail }), headOnly);
156
169
  }
157
170
  if (url.pathname === '/api/evidence-lint') {
158
171
  const taskId = url.searchParams.get('taskId')?.trim();
@@ -168,6 +181,12 @@ function createDashboardApiResponse(projectRoot, requestUrl, method) {
168
181
  }
169
182
  return notFound();
170
183
  }
184
+ function readCachedOpsStatus(projectRoot, includeDebt, bypass) {
185
+ return (0, dashboard_cache_1.getOrCreateCachedReport)((0, dashboard_cache_1.createDashboardCacheKey)(projectRoot, 'status', includeDebt ? 'full' : 'core'), { ttlMs: dashboard_cache_1.DASHBOARD_CACHE_TTLS.status, bypass }, () => (0, operations_status_service_1.createOpsStatusReport)(projectRoot, { includeDebt })).value;
186
+ }
187
+ function readCachedTaskList(projectRoot, bypass) {
188
+ return (0, dashboard_cache_1.getOrCreateCachedReport)((0, dashboard_cache_1.createDashboardCacheKey)(projectRoot, 'tasks'), { ttlMs: dashboard_cache_1.DASHBOARD_CACHE_TTLS.tasks, bypass }, () => (0, task_read_model_1.createTaskListReport)(projectRoot)).value;
189
+ }
171
190
  function missingTaskId(headOnly) {
172
191
  return jsonResponse({
173
192
  schemaVersion: 'hadara.dashboard.api.error.v1',
package/dist/cli/docs.js CHANGED
@@ -5,6 +5,7 @@ const args_1 = require("./args");
5
5
  const docs_cleanup_1 = require("../services/docs-cleanup");
6
6
  const docs_registry_1 = require("../services/docs-registry");
7
7
  const managed_sections_1 = require("../services/managed-sections");
8
+ const legacy_boundary_1 = require("./legacy-boundary");
8
9
  function handleDocsCommand(input) {
9
10
  const sub = input.args[1];
10
11
  if (sub === 'list') {
@@ -26,6 +27,39 @@ function handleDocsCommand(input) {
26
27
  printReport(report, input.jsonOutput);
27
28
  return true;
28
29
  }
30
+ if (sub === 'read-map') {
31
+ const report = (0, docs_registry_1.createDocsReadMapReport)(input.projectRoot, (0, args_1.getRequiredStringOption)(input.args, '--task'));
32
+ printReport(report, input.jsonOutput);
33
+ return true;
34
+ }
35
+ if (sub === 'inbox') {
36
+ const report = (0, docs_registry_1.createDocsInboxReport)(input.projectRoot);
37
+ printReport(report, input.jsonOutput);
38
+ return true;
39
+ }
40
+ if (sub === 'register') {
41
+ if ((0, args_1.getFlag)(input.args, '--execute') && blockLegacyMutation(input, 'docs.register'))
42
+ return true;
43
+ const report = (0, docs_registry_1.createDocsRegisterReport)(input.projectRoot, {
44
+ documentPath: (0, args_1.getRequiredStringOption)(input.args, '--path'),
45
+ title: (0, args_1.getStringOption)(input.args, '--title'),
46
+ kind: (0, args_1.getStringOption)(input.args, '--kind'),
47
+ status: (0, args_1.getStringOption)(input.args, '--status'),
48
+ readWhen: (0, args_1.getStringOption)(input.args, '--read-when'),
49
+ readTier: (0, args_1.getStringOption)(input.args, '--read-tier'),
50
+ authority: (0, args_1.getStringOption)(input.args, '--authority'),
51
+ editPolicy: (0, args_1.getStringOption)(input.args, '--edit-policy'),
52
+ activeForTasks: splitCsv((0, args_1.getStringOption)(input.args, '--active-for-task')),
53
+ driftRisk: (0, args_1.getStringOption)(input.args, '--drift'),
54
+ driftReviewRequired: (0, args_1.getFlag)(input.args, '--drift-review-required'),
55
+ driftReason: (0, args_1.getStringOption)(input.args, '--drift-reason'),
56
+ requiredReading: (0, args_1.getFlag)(input.args, '--required-reading'),
57
+ requireExists: (0, args_1.getFlag)(input.args, '--require-exists'),
58
+ mode: (0, args_1.getFlag)(input.args, '--execute') ? 'execute' : 'dry-run'
59
+ });
60
+ printReport(report, input.jsonOutput);
61
+ return true;
62
+ }
29
63
  if (sub === 'managed') {
30
64
  const managedSub = input.args[2];
31
65
  if (managedSub === 'list') {
@@ -38,6 +72,8 @@ function handleDocsCommand(input) {
38
72
  }
39
73
  }
40
74
  if (sub === 'patch') {
75
+ if ((0, args_1.getFlag)(input.args, '--execute') && blockLegacyMutation(input, 'docs.patch'))
76
+ return true;
41
77
  const report = (0, managed_sections_1.createDocsPatchPlanReport)(input.projectRoot, {
42
78
  targetPath: (0, args_1.getRequiredStringOption)(input.args, '--path'),
43
79
  sectionId: (0, args_1.getRequiredStringOption)(input.args, '--section'),
@@ -72,6 +108,14 @@ function handleDocsCommand(input) {
72
108
  }
73
109
  return false;
74
110
  }
111
+ function blockLegacyMutation(input, command) {
112
+ const report = (0, legacy_boundary_1.createLegacyMutationBlockedReport)(input.projectRoot, command);
113
+ if (!report)
114
+ return false;
115
+ (0, legacy_boundary_1.printLegacyMutationBlockedReport)(report, input.jsonOutput);
116
+ process.exitCode = 6;
117
+ return true;
118
+ }
75
119
  function printReport(report, jsonOutput) {
76
120
  if (jsonOutput) {
77
121
  console.log(JSON.stringify(report, null, 2));
@@ -79,3 +123,9 @@ function printReport(report, jsonOutput) {
79
123
  }
80
124
  console.log(JSON.stringify(report, null, 2));
81
125
  }
126
+ function splitCsv(value) {
127
+ if (value === undefined)
128
+ return undefined;
129
+ const items = value.split(',').map((item) => item.trim()).filter(Boolean);
130
+ return items.length > 0 ? items : undefined;
131
+ }
@@ -11,9 +11,15 @@ const evidence_json_1 = require("./evidence-json");
11
11
  const evidence_lint_1 = require("../services/evidence-lint");
12
12
  const evidence_list_1 = require("../services/evidence-list");
13
13
  const evidence_migration_1 = require("../services/evidence-migration");
14
+ const evidence_summary_1 = require("../services/evidence-summary");
14
15
  const args_1 = require("./args");
16
+ const legacy_boundary_1 = require("./legacy-boundary");
15
17
  function handleEvidenceCommand(input) {
16
18
  const sub = input.args[1];
19
+ if (hasHelpFlag(input.args)) {
20
+ console.log(renderEvidenceCommandHelp(sub));
21
+ return true;
22
+ }
17
23
  if (sub === 'list') {
18
24
  const taskId = (0, args_1.getRequiredStringOption)(input.args, '--task');
19
25
  const report = (0, evidence_list_1.createEvidenceListReport)(input.projectRoot, {
@@ -52,7 +58,50 @@ function handleEvidenceCommand(input) {
52
58
  process.exitCode = 6;
53
59
  return true;
54
60
  }
61
+ if (sub === 'summary') {
62
+ const taskId = (0, args_1.getRequiredStringOption)(input.args, '--task');
63
+ const report = (0, evidence_summary_1.createEvidenceSummaryReport)(input.projectRoot, {
64
+ taskId,
65
+ limit: (0, args_1.getIntegerOption)(input.args, '--limit', { min: 0, max: 500 }),
66
+ includePrivate: (0, args_1.getFlag)(input.args, '--include-private')
67
+ });
68
+ if (input.jsonOutput) {
69
+ console.log(JSON.stringify(report, null, 2));
70
+ }
71
+ else {
72
+ console.log(`[HADARA] evidence summary ${taskId}: ${report.ok ? 'ok' : 'issues'} | records ${report.summary.count} | durable ${report.summary.durableCount}`);
73
+ if (report.latest)
74
+ console.log(`latest: ${evidenceSummaryDisplay(report.latest)}`);
75
+ if (report.latestCloseEvidence)
76
+ console.log(`latest-close: ${evidenceSummaryDisplay(report.latestCloseEvidence)}`);
77
+ for (const record of report.records)
78
+ console.log(`- ${evidenceSummaryDisplay(record)}`);
79
+ for (const issue of report.issues) {
80
+ console.log(`[${issue.severity}] ${issue.code}: ${issue.message}`);
81
+ }
82
+ }
83
+ if (!report.ok)
84
+ process.exitCode = 6;
85
+ return true;
86
+ }
87
+ if (sub === 'project') {
88
+ const taskId = (0, args_1.getRequiredStringOption)(input.args, '--task');
89
+ const report = (0, evidence_1.createEvidenceProjectionReport)(input.projectRoot, taskId, (0, args_1.getFlag)(input.args, '--execute'));
90
+ if (input.jsonOutput) {
91
+ console.log(JSON.stringify(report, null, 2));
92
+ }
93
+ else {
94
+ console.log(`[HADARA] evidence project ${taskId}: ${report.ok ? 'ok' : 'issues'} | mode ${report.mode} | wouldChange ${report.wouldChange}`);
95
+ for (const issue of report.issues)
96
+ console.log(`[${issue.severity}] ${issue.code}: ${issue.message}`);
97
+ }
98
+ if (!report.ok)
99
+ process.exitCode = 6;
100
+ return true;
101
+ }
55
102
  if (sub === 'migrate') {
103
+ if ((0, args_1.getFlag)(input.args, '--execute') && blockLegacyMutation(input, 'evidence.migrate'))
104
+ return true;
56
105
  const taskId = (0, args_1.getRequiredStringOption)(input.args, '--task');
57
106
  const report = (0, evidence_migration_1.createEvidenceMigrationPreviewReport)({
58
107
  projectRoot: input.projectRoot,
@@ -76,6 +125,8 @@ function handleEvidenceCommand(input) {
76
125
  return true;
77
126
  }
78
127
  if (sub === 'add-command') {
128
+ if (blockLegacyMutation(input, 'evidence.add-command'))
129
+ return true;
79
130
  const taskId = (0, args_1.getRequiredStringOption)(input.args, '--task');
80
131
  const summary = (0, args_1.getStringOption)(input.args, '--summary') ?? 'Command completed.';
81
132
  const outcome = parseOptionalEvidenceOutcome((0, args_1.getStringOption)(input.args, '--outcome'));
@@ -131,6 +182,8 @@ function handleEvidenceCommand(input) {
131
182
  }
132
183
  if (sub !== 'collect')
133
184
  return false;
185
+ if (blockLegacyMutation(input, 'evidence.collect'))
186
+ return true;
134
187
  const taskId = (0, args_1.getRequiredStringOption)(input.args, '--task');
135
188
  const kind = parseEvidenceKind((0, args_1.getStringOption)(input.args, '--kind', 'note') ?? 'note');
136
189
  const summary = (0, args_1.getStringOption)(input.args, '--summary') ?? 'Manual evidence collection placeholder.';
@@ -163,6 +216,51 @@ function handleEvidenceCommand(input) {
163
216
  }
164
217
  return true;
165
218
  }
219
+ function hasHelpFlag(args) {
220
+ return args.includes('--help') || args.includes('-h');
221
+ }
222
+ function renderEvidenceCommandHelp(sub) {
223
+ if (sub === 'add-command') {
224
+ return [
225
+ '[HADARA] evidence add-command',
226
+ '',
227
+ 'Usage:',
228
+ ' hadara evidence add-command --task T-XXXX --summary "..." --result passed --category validation --json',
229
+ '',
230
+ 'Records an already-run command result. It does not execute shell commands.',
231
+ 'Options:',
232
+ ' --task <id> Task Capsule id.',
233
+ ' --summary <text> Human-readable result summary.',
234
+ ' --result <value> Legacy-compatible result: passed, failed, blocked, unknown.',
235
+ ' --outcome <value> Evidence v2 outcome.',
236
+ ' --category <value> Evidence v2 category.',
237
+ ' --resolves <id> Add a resolves:<id> tag. Repeatable.',
238
+ ' --supersedes <id> Add a supersedes:<id> tag. Repeatable.',
239
+ ' --idempotency-key <key> Reuse an existing keyed record instead of appending duplicates.',
240
+ ' --private Store as private evidence metadata.'
241
+ ].join('\n');
242
+ }
243
+ return [
244
+ '[HADARA] evidence',
245
+ '',
246
+ 'Usage:',
247
+ ' hadara evidence list --task T-XXXX --json',
248
+ ' hadara evidence lint --task T-XXXX --json',
249
+ ' hadara evidence summary --task T-XXXX --json',
250
+ ' hadara evidence project --task T-XXXX [--execute] --json',
251
+ ' hadara evidence add-command --task T-XXXX --summary "..." --result passed --json',
252
+ '',
253
+ 'Use `hadara help command evidence.add-command` for registry metadata.'
254
+ ].join('\n');
255
+ }
256
+ function blockLegacyMutation(input, command) {
257
+ const report = (0, legacy_boundary_1.createLegacyMutationBlockedReport)(input.projectRoot, command);
258
+ if (!report)
259
+ return false;
260
+ (0, legacy_boundary_1.printLegacyMutationBlockedReport)(report, input.jsonOutput);
261
+ process.exitCode = 6;
262
+ return true;
263
+ }
166
264
  function persistedEvidenceId(record) {
167
265
  return record.schemaVersion === 'hadara.evidence.v2' && record.id ? record.id : 'evidence.jsonl';
168
266
  }
@@ -175,6 +273,21 @@ function evidenceListCategory(record) {
175
273
  function evidenceListOutcome(record) {
176
274
  return record.outcome;
177
275
  }
276
+ function evidenceSummaryDisplay(record) {
277
+ const tags = record.tags.length > 0 ? ` | tags:${record.tags.slice(0, 3).map(compactEvidenceTag).join(',')}${record.tags.length > 3 ? ',...' : ''}` : '';
278
+ return `${record.id} | ${record.time} | ${record.category}/${record.outcome} | ${record.visibility} | ${truncateSummary(record.summary)}${tags}`;
279
+ }
280
+ function truncateSummary(value) {
281
+ const maxLength = 160;
282
+ if (value.length <= maxLength)
283
+ return value;
284
+ return `${value.slice(0, maxLength - 3)}...`;
285
+ }
286
+ function compactEvidenceTag(value) {
287
+ if (value.startsWith('idempotency:'))
288
+ return 'idempotency:*';
289
+ return truncateSummary(value);
290
+ }
178
291
  function parseEvidenceKind(value) {
179
292
  if (['test-log', 'command-log', 'diff-summary', 'screenshot', 'note'].includes(value)) {
180
293
  return value;
@@ -2,11 +2,24 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.handleHandoffCommand = handleHandoffCommand;
4
4
  const handoff_1 = require("../handoff/handoff");
5
+ const handoff_stale_problems_1 = require("../handoff/handoff-stale-problems");
5
6
  const handoff_suggestion_1 = require("../handoff/handoff-suggestion");
6
7
  const actor_1 = require("./actor");
7
8
  const args_1 = require("./args");
8
9
  function handleHandoffCommand(input) {
9
10
  const sub = input.args[1];
11
+ if (sub === 'stale-problems') {
12
+ const report = (0, handoff_stale_problems_1.createHandoffStaleProblemsReport)(input.projectRoot);
13
+ if (input.jsonOutput) {
14
+ console.log(JSON.stringify(report, null, 2));
15
+ }
16
+ else {
17
+ console.log((0, handoff_stale_problems_1.formatHandoffStaleProblemsReport)(report));
18
+ }
19
+ if (!report.ok)
20
+ process.exitCode = 6;
21
+ return true;
22
+ }
10
23
  if (sub === 'suggest') {
11
24
  const taskId = (0, args_1.getStringOption)(input.args, '--task') ?? input.args[2];
12
25
  if (!taskId || taskId.startsWith('--'))
package/dist/cli/help.js CHANGED
@@ -7,7 +7,7 @@ exports.renderCommandHelp = renderCommandHelp;
7
7
  exports.renderFamilyHelp = renderFamilyHelp;
8
8
  const capability_registry_1 = require("../services/capability-registry");
9
9
  const lifecycle_guide_1 = require("../services/lifecycle-guide");
10
- const LIFECYCLE_ORDER = ['discover', 'create', 'inspect', 'evidence', 'phase-check', 'finalize', 'handoff'];
10
+ const LIFECYCLE_ORDER = ['inspect', 'create', 'evidence', 'finalize', 'handoff'];
11
11
  function handleHelpCommand(input) {
12
12
  const topic = input.args[1];
13
13
  if (!topic) {
@@ -51,7 +51,7 @@ function renderDefaultHelp() {
51
51
  '',
52
52
  'Start:',
53
53
  ' hadara help lifecycle',
54
- ' hadara task next --json',
54
+ ' hadara task status --json',
55
55
  ' hadara task status --task T-XXXX --json',
56
56
  '',
57
57
  'Primary capsule lifecycle:',
@@ -74,7 +74,7 @@ function renderLifecycleHelp() {
74
74
  const report = (0, lifecycle_guide_1.createLifecycleGuideReport)();
75
75
  const diagnostics = (0, capability_registry_1.listCommandRegistryEntries)({ family: 'proof-diagnostics' }).filter((entry) => entry.requiredness === 'diagnostic');
76
76
  const lines = [
77
- 'HADARA 0.3.3 primary task lifecycle',
77
+ 'HADARA 0.4 primary task lifecycle',
78
78
  '',
79
79
  'Primary capsule lifecycle:'
80
80
  ];
@@ -104,6 +104,7 @@ function renderCommandHelp(id) {
104
104
  `Scope: ${entry.scope}`,
105
105
  `Lifecycle stage: ${entry.lifecycleStage}`,
106
106
  `Requiredness: ${entry.requiredness}`,
107
+ `Status: ${entry.status}`,
107
108
  `Write boundary: ${entry.writeBoundary}`,
108
109
  `Read-only: ${entry.readOnly ? 'yes' : 'no'}`,
109
110
  `Risk: ${entry.risk}`,