hadara 0.3.4-rc.0 → 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.
Files changed (83) hide show
  1. package/README.md +29 -29
  2. package/dist/cli/dashboard.js +16 -4
  3. package/dist/cli/docs.js +50 -0
  4. package/dist/cli/doctor.js +74 -3
  5. package/dist/cli/evidence-json.js +3 -0
  6. package/dist/cli/evidence.js +72 -0
  7. package/dist/cli/help.js +4 -3
  8. package/dist/cli/init.js +608 -122
  9. package/dist/cli/legacy-boundary.js +77 -0
  10. package/dist/cli/main.js +28 -0
  11. package/dist/cli/package-smoke.js +1 -0
  12. package/dist/cli/release-artifact.js +10 -1
  13. package/dist/cli/release-publish.js +9 -0
  14. package/dist/cli/task.js +142 -24
  15. package/dist/cli/validation.js +81 -0
  16. package/dist/context/context-pack.js +113 -19
  17. package/dist/context/session-start.js +61 -21
  18. package/dist/context/task-extractors.js +3 -2
  19. package/dist/core/schema.js +14 -0
  20. package/dist/core/timing.js +12 -0
  21. package/dist/dev/docker-check.js +3 -2
  22. package/dist/evidence/evidence.js +134 -11
  23. package/dist/evidence/semantics.js +3 -1
  24. package/dist/handoff/handoff-stale-problems.js +6 -1
  25. package/dist/handoff/handoff-suggestion.js +7 -1
  26. package/dist/handoff/handoff.js +1 -0
  27. package/dist/harness/validate.js +434 -72
  28. package/dist/schemas/close-source.schema.json +33 -0
  29. package/dist/schemas/docs-inbox.schema.json +50 -0
  30. package/dist/schemas/docs-read-map.schema.json +83 -0
  31. package/dist/schemas/docs-register.schema.json +70 -0
  32. package/dist/schemas/evidence-projection.schema.json +35 -0
  33. package/dist/schemas/schema-index.json +51 -2
  34. package/dist/schemas/task-audit-close.schema.json +7 -0
  35. package/dist/schemas/task-close.schema.json +4 -0
  36. package/dist/schemas/task-finalize.schema.json +40 -1
  37. package/dist/schemas/task-status.schema.json +117 -0
  38. package/dist/schemas/task-workbench.schema.json +97 -2
  39. package/dist/schemas/validation-run.schema.json +103 -0
  40. package/dist/services/capability-registry.js +216 -51
  41. package/dist/services/ci-gate.js +5 -2
  42. package/dist/services/clean-checkout-smoke.js +4 -2
  43. package/dist/services/dashboard-bootstrap.js +19 -4
  44. package/dist/services/dashboard-cache.js +2 -0
  45. package/dist/services/dashboard-task-detail.js +43 -13
  46. package/dist/services/dashboard-timeline.js +2 -2
  47. package/dist/services/docs-registry.js +485 -30
  48. package/dist/services/evidence-lint.js +9 -3
  49. package/dist/services/lifecycle-guide.js +11 -12
  50. package/dist/services/operational-debt.js +8 -14
  51. package/dist/services/operations-status-service.js +7 -1
  52. package/dist/services/package-recycle.js +101 -45
  53. package/dist/services/package-smoke.js +7 -2
  54. package/dist/services/proof-status.js +2 -0
  55. package/dist/services/protocol-consistency.js +13 -6
  56. package/dist/services/protocol-migration.js +2 -1
  57. package/dist/services/release-artifact.js +3 -2
  58. package/dist/services/release-closeout.js +2 -1
  59. package/dist/services/release-diagnostics.js +5 -4
  60. package/dist/services/release-dry-run.js +3 -2
  61. package/dist/services/state-projection.js +31 -16
  62. package/dist/services/task-read-model.js +7 -7
  63. package/dist/services/task-workbench.js +598 -29
  64. package/dist/services/validation-run.js +333 -0
  65. package/dist/services/workbench-next-actions.js +31 -20
  66. package/dist/services/write-preflight.js +2 -20
  67. package/dist/task/acceptance.js +27 -5
  68. package/dist/task/authoring-guidance.js +76 -0
  69. package/dist/task/lifecycle-next-actions.js +0 -1
  70. package/dist/task/task-capsule.js +24 -18
  71. package/dist/task/task-close-repair-plan.js +3 -2
  72. package/dist/task/task-close.js +319 -39
  73. package/dist/task/task-complete-flow.js +4 -3
  74. package/dist/task/task-create.js +1 -0
  75. package/dist/task/task-finalize.js +161 -28
  76. package/dist/task/task-finish.js +36 -8
  77. package/dist/task/task-lifecycle.js +8 -3
  78. package/dist/task/task-templates.js +5 -24
  79. package/dist/task/task-upgrade-scaffold.js +11 -60
  80. package/dist/tui/constants.js +1 -7
  81. package/dist/tui/read-model.js +6 -4
  82. package/dist/tui/snapshot.js +14 -2
  83. package/package.json +1 -1
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.createLegacyMutationBlockedReport = createLegacyMutationBlockedReport;
7
+ exports.printLegacyMutationBlockedReport = printLegacyMutationBlockedReport;
8
+ const node_fs_1 = __importDefault(require("node:fs"));
9
+ const node_path_1 = __importDefault(require("node:path"));
10
+ function createLegacyMutationBlockedReport(projectRoot, command) {
11
+ const scaffoldPath = node_path_1.default.join(projectRoot, '.hadara', 'scaffold.json');
12
+ if (!node_fs_1.default.existsSync(scaffoldPath)) {
13
+ return report(command, null, {
14
+ severity: 'error',
15
+ code: 'HADARA_PROTOCOL_MISSING',
16
+ path: '.hadara/scaffold.json',
17
+ message: 'This project does not declare HADARA protocol metadata. 0.4 mutation commands are disabled.'
18
+ });
19
+ }
20
+ try {
21
+ const parsed = JSON.parse(node_fs_1.default.readFileSync(scaffoldPath, 'utf8'));
22
+ if (parsed.hadaraProtocol === '0.4')
23
+ return null;
24
+ return report(command, typeof parsed.hadaraProtocol === 'string' ? parsed.hadaraProtocol : null, {
25
+ severity: 'error',
26
+ code: 'HADARA_PROTOCOL_UNSUPPORTED',
27
+ path: '.hadara/scaffold.json',
28
+ message: `.hadara/scaffold.json must declare hadaraProtocol "0.4" before running 0.4 mutation commands.`
29
+ });
30
+ }
31
+ catch (error) {
32
+ return report(command, null, {
33
+ severity: 'error',
34
+ code: 'HADARA_PROTOCOL_UNSUPPORTED',
35
+ path: '.hadara/scaffold.json',
36
+ message: `.hadara/scaffold.json could not be parsed: ${error instanceof Error ? error.message : String(error)}`
37
+ });
38
+ }
39
+ }
40
+ function printLegacyMutationBlockedReport(report, jsonOutput) {
41
+ if (jsonOutput) {
42
+ console.log(JSON.stringify(report, null, 2));
43
+ return;
44
+ }
45
+ console.log(`[HADARA] ${report.command} blocked: legacy or unsupported HADARA project`);
46
+ for (const issue of report.issues)
47
+ console.log(`[${issue.severity}] ${issue.code}: ${issue.message}`);
48
+ }
49
+ function report(command, detectedProtocol, issue) {
50
+ return {
51
+ schemaVersion: 'hadara.legacyProjectBoundary.v1',
52
+ command,
53
+ ok: false,
54
+ mutationAllowed: false,
55
+ detectedProtocol,
56
+ supportedProtocol: '0.4',
57
+ issues: [
58
+ issue,
59
+ {
60
+ severity: 'error',
61
+ code: 'HADARA_LEGACY_PROJECT_MUTATION_BLOCKED',
62
+ path: '.hadara/scaffold.json',
63
+ message: `${command} is a 0.4 mutation command and will not write into a legacy or unsupported project.`
64
+ }
65
+ ],
66
+ nextActions: [
67
+ {
68
+ label: 'Use the previous HADARA line for this project',
69
+ command: 'npx hadara@0.3.3 doctor --json'
70
+ },
71
+ {
72
+ label: 'Initialize a new HADARA 0.4 project',
73
+ command: 'hadara init --json'
74
+ }
75
+ ]
76
+ };
77
+ }
package/dist/cli/main.js CHANGED
@@ -34,11 +34,33 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  };
35
35
  })();
36
36
  Object.defineProperty(exports, "__esModule", { value: true });
37
+ exports.normalizeGlobalArgs = normalizeGlobalArgs;
38
+ exports.main = main;
37
39
  const paths_1 = require("../core/paths");
38
40
  const args_1 = require("./args");
39
41
  const errors_1 = require("./errors");
40
42
  const help_1 = require("./help");
43
+ const GLOBAL_FLAGS = new Set(['--json']);
44
+ const GLOBAL_OPTIONS_WITH_VALUES = new Set(['--project']);
45
+ function normalizeGlobalArgs(args) {
46
+ let commandIndex = -1;
47
+ for (let index = 0; index < args.length; index += 1) {
48
+ const value = args[index];
49
+ if (GLOBAL_FLAGS.has(value) || value === '--help' || value === '-h')
50
+ continue;
51
+ if (GLOBAL_OPTIONS_WITH_VALUES.has(value)) {
52
+ index += 1;
53
+ continue;
54
+ }
55
+ commandIndex = index;
56
+ break;
57
+ }
58
+ if (commandIndex <= 0)
59
+ return args;
60
+ return [args[commandIndex], ...args.slice(commandIndex + 1), ...args.slice(0, commandIndex)];
61
+ }
41
62
  async function main(args = process.argv.slice(2)) {
63
+ args = normalizeGlobalArgs(args);
42
64
  const command = args[0];
43
65
  if (!command || command === '--help' || command === '-h') {
44
66
  console.log((0, help_1.renderDefaultHelp)());
@@ -101,6 +123,12 @@ async function main(args = process.argv.slice(2)) {
101
123
  return;
102
124
  break;
103
125
  }
126
+ case 'validation': {
127
+ const { handleValidationCommand } = await Promise.resolve().then(() => __importStar(require('./validation')));
128
+ if (handleValidationCommand({ args, projectRoot: paths.projectRoot, jsonOutput }))
129
+ return;
130
+ break;
131
+ }
104
132
  case 'proof': {
105
133
  const { handleProofCommand } = await Promise.resolve().then(() => __importStar(require('./proof')));
106
134
  if (handleProofCommand({ args, projectRoot: paths.projectRoot, jsonOutput }))
@@ -18,6 +18,7 @@ function handlePackageCommand(input) {
18
18
  attachEvidence: (0, args_1.getFlag)(input.args, '--attach-evidence'),
19
19
  noEvidence: (0, args_1.getFlag)(input.args, '--no-evidence'),
20
20
  keepTemp: (0, args_1.getFlag)(input.args, '--keep-temp'),
21
+ includeGraph: (0, args_1.getFlag)(input.args, '--include-graph'),
21
22
  timeoutSeconds: (0, args_1.getIntegerOption)(input.args, '--timeout', { min: 1 })
22
23
  });
23
24
  if (input.jsonOutput) {
@@ -5,9 +5,18 @@ const evidence_1 = require("../evidence/evidence");
5
5
  const release_artifact_evidence_1 = require("../services/release-artifact-evidence");
6
6
  const release_artifact_1 = require("../services/release-artifact");
7
7
  const args_1 = require("./args");
8
+ const legacy_boundary_1 = require("./legacy-boundary");
8
9
  function handleReleaseArtifactCommand(input) {
9
10
  if (input.args[0] !== 'release' || input.args[1] !== 'artifact')
10
11
  return false;
12
+ if ((0, args_1.getFlag)(input.args, '--execute')) {
13
+ const legacyReport = (0, legacy_boundary_1.createLegacyMutationBlockedReport)(input.paths.projectRoot, 'release.artifact');
14
+ if (legacyReport) {
15
+ (0, legacy_boundary_1.printLegacyMutationBlockedReport)(legacyReport, input.jsonOutput);
16
+ process.exitCode = 6;
17
+ return true;
18
+ }
19
+ }
11
20
  const report = (0, release_artifact_1.createReleaseArtifactReport)({
12
21
  paths: input.paths,
13
22
  execute: (0, args_1.getFlag)(input.args, '--execute'),
@@ -29,7 +38,7 @@ function handleReleaseArtifactCommand(input) {
29
38
  })
30
39
  : undefined;
31
40
  if (input.jsonOutput) {
32
- console.log(JSON.stringify(attachment ? { ...report, attachedEvidence: attachment } : report, null, 2));
41
+ console.log(JSON.stringify(attachment && taskId ? { ...report, taskId, attachedEvidence: attachment } : report, null, 2));
33
42
  }
34
43
  else {
35
44
  console.log(`${report.ok ? 'passed' : 'failed'} | release artifact | ${report.output.retention}`);
@@ -3,10 +3,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.handleReleasePublishCommand = handleReleasePublishCommand;
4
4
  const release_publish_1 = require("../services/release-publish");
5
5
  const args_1 = require("./args");
6
+ const legacy_boundary_1 = require("./legacy-boundary");
6
7
  function handleReleasePublishCommand(input) {
7
8
  if (input.args[0] !== 'release' || input.args[1] !== 'publish')
8
9
  return false;
9
10
  const mode = parseMode(input.args);
11
+ if (mode === 'execute') {
12
+ const legacyReport = (0, legacy_boundary_1.createLegacyMutationBlockedReport)(input.paths.projectRoot, 'release.publish');
13
+ if (legacyReport) {
14
+ (0, legacy_boundary_1.printLegacyMutationBlockedReport)(legacyReport, input.jsonOutput);
15
+ process.exitCode = 6;
16
+ return true;
17
+ }
18
+ }
10
19
  const report = (0, release_publish_1.createReleasePublishReport)({
11
20
  projectRoot: input.paths.projectRoot,
12
21
  auditDir: input.paths.auditDir,
package/dist/cli/task.js CHANGED
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.handleTaskCommand = handleTaskCommand;
4
4
  exports.extractTaskCreateTitle = extractTaskCreateTitle;
5
5
  const task_close_1 = require("../task/task-close");
6
- const task_close_repair_plan_1 = require("../task/task-close-repair-plan");
7
6
  const task_complete_flow_1 = require("../task/task-complete-flow");
8
7
  const task_create_1 = require("../task/task-create");
9
8
  const task_finalize_1 = require("../task/task-finalize");
@@ -13,12 +12,17 @@ const task_finish_1 = require("../task/task-finish");
13
12
  const task_next_1 = require("../task/task-next");
14
13
  const task_upgrade_scaffold_1 = require("../task/task-upgrade-scaffold");
15
14
  const task_workbench_1 = require("../services/task-workbench");
15
+ const timing_1 = require("../core/timing");
16
16
  const actor_1 = require("./actor");
17
17
  const args_1 = require("./args");
18
+ const legacy_boundary_1 = require("./legacy-boundary");
18
19
  const task_json_1 = require("./task-json");
19
20
  function handleTaskCommand(input) {
21
+ const timer = (0, timing_1.startMonotonicTimer)();
20
22
  const sub = input.args[1];
21
23
  if (sub === 'create') {
24
+ if (blockLegacyMutation(input, 'task.create'))
25
+ return true;
22
26
  const title = extractTaskCreateTitle(input.args);
23
27
  if (!title)
24
28
  throw new Error('task create requires a title');
@@ -44,9 +48,9 @@ function handleTaskCommand(input) {
44
48
  return true;
45
49
  }
46
50
  if (sub === 'show') {
47
- const id = input.args[2];
48
- if (!id)
49
- throw new Error('task show requires <task-id>');
51
+ const id = (0, args_1.getStringOption)(input.args, '--task') ?? input.args[2];
52
+ if (!id || id.startsWith('--'))
53
+ throw new Error('task show requires --task <task-id>');
50
54
  const report = (0, task_json_1.createTaskShowReport)(input.projectRoot, id);
51
55
  if (input.jsonOutput) {
52
56
  console.log(JSON.stringify(report, null, 2));
@@ -74,6 +78,8 @@ function handleTaskCommand(input) {
74
78
  return true;
75
79
  }
76
80
  if (sub === 'upgrade-scaffold') {
81
+ if ((0, args_1.getFlag)(input.args, '--execute') && blockLegacyMutation(input, 'task.upgrade-scaffold'))
82
+ return true;
77
83
  const id = (0, args_1.getStringOption)(input.args, '--task') ?? input.args[2];
78
84
  if (!id || id.startsWith('--'))
79
85
  throw new Error('task upgrade-scaffold requires --task <task-id>');
@@ -91,6 +97,8 @@ function handleTaskCommand(input) {
91
97
  return true;
92
98
  }
93
99
  if (sub === 'close') {
100
+ if ((0, args_1.getFlag)(input.args, '--execute') && blockLegacyMutation(input, 'task.close'))
101
+ return true;
94
102
  const id = (0, args_1.getStringOption)(input.args, '--task') ?? input.args[2];
95
103
  if (!id || id.startsWith('--'))
96
104
  throw new Error('task close requires --task <task-id>');
@@ -112,14 +120,56 @@ function handleTaskCommand(input) {
112
120
  process.exitCode = 6;
113
121
  return true;
114
122
  }
115
- if (sub === 'status') {
123
+ if (sub === 'close-source') {
116
124
  const id = (0, args_1.getStringOption)(input.args, '--task') ?? input.args[2];
117
125
  if (!id || id.startsWith('--'))
118
- throw new Error('task status requires --task <task-id>');
119
- const report = (0, task_workbench_1.createTaskWorkbenchReport)(input.projectRoot, id);
126
+ throw new Error('task close-source requires --task <task-id>');
127
+ const report = (0, task_close_1.createTaskCloseSourceReport)(input.projectRoot, id);
120
128
  if (input.jsonOutput) {
121
129
  console.log(JSON.stringify(report, null, 2));
122
130
  }
131
+ else {
132
+ console.log(`[HADARA] task close-source ${id}: ${report.ok ? 'ok' : 'issues'}`);
133
+ console.log(`sourceHash\t${report.sourceHash}`);
134
+ for (const unit of report.sourceUnits)
135
+ console.log(`${unit.closeSourceRole}\t${unit.kind}\t${unit.path}\t${unit.selector ?? ''}\t${unit.sha256}`);
136
+ for (const issue of report.issues)
137
+ console.log(`[${issue.severity}] ${issue.code}: ${issue.message}`);
138
+ }
139
+ if (!report.ok)
140
+ process.exitCode = 6;
141
+ return true;
142
+ }
143
+ if (sub === 'status') {
144
+ const summaryJsonOutput = (0, args_1.getFlag)(input.args, '--summary-json');
145
+ const id = (0, args_1.getStringOption)(input.args, '--task') ?? input.args[2];
146
+ if (!id || id.startsWith('--')) {
147
+ const report = (0, task_workbench_1.createTaskStatusSelectionReport)(input.projectRoot);
148
+ attachCliDiagnostics(report, timer, 'task.status');
149
+ if (summaryJsonOutput) {
150
+ console.log(JSON.stringify(createTaskStatusSummaryReport(report), null, 2));
151
+ }
152
+ else if (input.jsonOutput) {
153
+ console.log(JSON.stringify(report, null, 2));
154
+ }
155
+ else {
156
+ console.log((0, task_workbench_1.formatTaskStatusSelectionReport)(report));
157
+ }
158
+ if (!report.ok)
159
+ process.exitCode = 6;
160
+ return true;
161
+ }
162
+ const detail = (0, args_1.getStringOption)(input.args, '--detail');
163
+ if (detail && detail !== 'fast' && detail !== 'full')
164
+ throw new Error('task status --detail must be fast or full');
165
+ const report = (0, task_workbench_1.createTaskWorkbenchReport)(input.projectRoot, id, new Date(), { detail: detail === 'full' ? 'full' : 'fast' });
166
+ attachCliDiagnostics(report, timer, 'task.status');
167
+ if (summaryJsonOutput) {
168
+ console.log(JSON.stringify(createTaskStatusSummaryReport(report), null, 2));
169
+ }
170
+ else if (input.jsonOutput) {
171
+ console.log(JSON.stringify(report, null, 2));
172
+ }
123
173
  else {
124
174
  console.log((0, task_workbench_1.formatTaskWorkbenchReport)(report));
125
175
  }
@@ -128,6 +178,8 @@ function handleTaskCommand(input) {
128
178
  return true;
129
179
  }
130
180
  if (sub === 'complete') {
181
+ if ((0, args_1.getFlag)(input.args, '--execute') && blockLegacyMutation(input, 'task.complete'))
182
+ return true;
131
183
  const id = (0, args_1.getStringOption)(input.args, '--task') ?? input.args[2];
132
184
  if (!id || id.startsWith('--'))
133
185
  throw new Error('task complete requires --task <task-id>');
@@ -143,14 +195,19 @@ function handleTaskCommand(input) {
143
195
  return true;
144
196
  }
145
197
  if (sub === 'finalize') {
198
+ if ((0, args_1.getFlag)(input.args, '--execute') && blockLegacyMutation(input, 'task.finalize'))
199
+ return true;
146
200
  const id = (0, args_1.getStringOption)(input.args, '--task') ?? input.args[2];
147
201
  if (!id || id.startsWith('--'))
148
202
  throw new Error('task finalize requires --task <task-id>');
203
+ const executeRequested = (0, args_1.getFlag)(input.args, '--execute');
149
204
  const report = (0, task_finalize_1.createTaskFinalizeReport)(input.projectRoot, id, {
150
- executeRequested: (0, args_1.getFlag)(input.args, '--execute'),
205
+ executeRequested,
151
206
  planHash: (0, args_1.getStringOption)(input.args, '--plan-hash'),
152
- actor: (0, actor_1.getActorContextOption)(input.args)
207
+ actor: (0, actor_1.getActorContextOption)(input.args),
208
+ onProgress: executeRequested ? createTaskFinalizeProgressWriter(id) : undefined
153
209
  });
210
+ attachCliDiagnostics(report, timer, 'task.finalize');
154
211
  if (input.jsonOutput) {
155
212
  console.log(JSON.stringify(report, null, 2));
156
213
  }
@@ -176,22 +233,9 @@ function handleTaskCommand(input) {
176
233
  process.exitCode = 6;
177
234
  return true;
178
235
  }
179
- if (sub === 'close-repair-plan') {
180
- const id = (0, args_1.getStringOption)(input.args, '--task') ?? input.args[2];
181
- if (!id || id.startsWith('--'))
182
- throw new Error('task close-repair-plan requires --task <task-id>');
183
- const report = (0, task_close_repair_plan_1.createTaskCloseRepairPlanReport)(input.projectRoot, id, { actor: (0, actor_1.getActorContextOption)(input.args) });
184
- if (input.jsonOutput) {
185
- console.log(JSON.stringify(report, null, 2));
186
- }
187
- else {
188
- console.log((0, task_close_repair_plan_1.formatTaskCloseRepairPlanReport)(report));
189
- }
190
- if (!report.ok)
191
- process.exitCode = 6;
192
- return true;
193
- }
194
236
  if (sub === 'finish') {
237
+ if ((0, args_1.getFlag)(input.args, '--execute') && blockLegacyMutation(input, 'task.finish'))
238
+ return true;
195
239
  const id = (0, args_1.getStringOption)(input.args, '--task') ?? input.args[2];
196
240
  if (!id || id.startsWith('--'))
197
241
  throw new Error('task finish requires --task <task-id>');
@@ -245,6 +289,80 @@ function handleTaskCommand(input) {
245
289
  }
246
290
  return false;
247
291
  }
292
+ function createTaskStatusSummaryReport(report) {
293
+ if (report.schemaVersion === 'hadara.task.status.v1') {
294
+ return {
295
+ schemaVersion: 'hadara.task.status.summary.v1',
296
+ command: 'task.status',
297
+ ok: report.ok,
298
+ mode: 'select-work',
299
+ phase: report.loop.phase,
300
+ recommendations: report.summary.recommendations,
301
+ ...(report.loop.primaryNextAction ? { primaryNextAction: report.loop.primaryNextAction } : {}),
302
+ ...(report.diagnostics ? { diagnostics: report.diagnostics } : {}),
303
+ issues: report.issues
304
+ };
305
+ }
306
+ return {
307
+ schemaVersion: 'hadara.task.status.summary.v1',
308
+ command: 'task.status',
309
+ ok: report.ok,
310
+ mode: 'selected-task',
311
+ taskId: report.taskId,
312
+ task: {
313
+ title: report.task.title,
314
+ capsule: report.task.capsule,
315
+ taskStatus: report.task.taskStatus,
316
+ taskBoardStatus: report.task.taskBoardStatus
317
+ },
318
+ phase: report.loop.phase,
319
+ readiness: {
320
+ status: report.state.readiness.status,
321
+ ready: report.state.ready,
322
+ closeProofValid: report.state.readiness.closeProofValid,
323
+ summary: report.state.readiness.summary
324
+ },
325
+ counts: {
326
+ blockers: report.summary.blockers,
327
+ warnings: report.summary.warnings,
328
+ evidenceRecords: report.summary.evidenceRecords,
329
+ validationChecks: report.sources.evidenceList.validationAttempts?.checks ?? 0,
330
+ unresolvedValidation: report.sources.evidenceList.validationAttempts?.unresolvedFailedOrBlocked ?? 0,
331
+ nextActions: report.summary.nextActions
332
+ },
333
+ ...(report.loop.primaryNextAction ? { primaryNextAction: report.loop.primaryNextAction } : {}),
334
+ ...(report.diagnostics ? { diagnostics: report.diagnostics } : {}),
335
+ issues: report.issues
336
+ };
337
+ }
338
+ function createTaskFinalizeProgressWriter(taskId) {
339
+ return (event) => {
340
+ const ok = event.ok === undefined ? '' : ` ok=${event.ok}`;
341
+ process.stderr.write(`[HADARA] task finalize ${taskId}: ${event.step} ${event.phase}${ok} - ${event.summary}\n`);
342
+ };
343
+ }
344
+ function attachCliDiagnostics(report, timer, commandPath) {
345
+ const durationMs = timer.elapsedMs();
346
+ const slowThresholdMs = 10000;
347
+ const slow = durationMs >= slowThresholdMs;
348
+ report.diagnostics = {
349
+ generatedBy: 'cli',
350
+ commandPath,
351
+ durationMs,
352
+ slowThresholdMs,
353
+ slow,
354
+ ...(slow ? { note: 'This command was slow enough to affect interactive agent UX; prefer narrower diagnostics or progress-aware follow-up work if this repeats.' } : {})
355
+ };
356
+ return report;
357
+ }
358
+ function blockLegacyMutation(input, command) {
359
+ const report = (0, legacy_boundary_1.createLegacyMutationBlockedReport)(input.projectRoot, command);
360
+ if (!report)
361
+ return false;
362
+ (0, legacy_boundary_1.printLegacyMutationBlockedReport)(report, input.jsonOutput);
363
+ process.exitCode = 6;
364
+ return true;
365
+ }
248
366
  function extractTaskCreateTitle(args) {
249
367
  const explicitTitle = (0, args_1.getStringOption)(args, '--title');
250
368
  if (explicitTitle)
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleValidationCommand = handleValidationCommand;
4
+ const validation_run_1 = require("../services/validation-run");
5
+ const args_1 = require("./args");
6
+ const legacy_boundary_1 = require("./legacy-boundary");
7
+ function handleValidationCommand(input) {
8
+ const sub = input.args[1];
9
+ if (sub !== 'run')
10
+ return false;
11
+ if (blockLegacyMutation(input, 'validation.run'))
12
+ return true;
13
+ const separator = input.args.indexOf('--');
14
+ const commandArgs = separator >= 0 ? input.args.slice(separator + 1) : [];
15
+ const optionArgs = separator >= 0 ? input.args.slice(0, separator) : input.args;
16
+ const taskId = (0, args_1.getRequiredStringOption)(optionArgs, '--task');
17
+ const check = (0, args_1.getRequiredStringOption)(optionArgs, '--check');
18
+ const report = (0, validation_run_1.createValidationRunReport)(input.projectRoot, {
19
+ taskId,
20
+ check,
21
+ argv: commandArgs,
22
+ tags: resolutionTagsFromArgs(optionArgs),
23
+ timeoutMs: (0, args_1.getIntegerOption)(optionArgs, '--timeout-ms', { min: 1, max: 3_600_000 }),
24
+ updateTask: (0, args_1.getFlag)(optionArgs, '--update-task')
25
+ });
26
+ if (input.jsonOutput) {
27
+ console.log(JSON.stringify(report, null, 2));
28
+ }
29
+ else {
30
+ console.log(`[HADARA] validation run ${taskId}: ${report.result}`);
31
+ console.log(`[HADARA] child command`);
32
+ console.log(`command=${report.argv.join(' ')}`);
33
+ console.log(`exitCode=${report.execution.exitCode ?? 'null'} signal=${report.execution.signal ?? 'null'} durationMs=${report.execution.durationMs}`);
34
+ console.log(`stdoutHash=${report.execution.stdoutHash}`);
35
+ console.log(`stderrHash=${report.execution.stderrHash}`);
36
+ console.log(`childOutput=not printed; stdout/stderr hashes are recorded in HADARA evidence`);
37
+ console.log(`[HADARA] evidence`);
38
+ if (report.evidence)
39
+ console.log(`id=${report.evidence.id}`);
40
+ console.log(`result=${report.result}`);
41
+ console.log(`taskValidationRow=${report.taskValidationRow.mode}${report.taskValidationRow.updated ? ' updated' : ' not-updated'}`);
42
+ console.log(`acceptanceRows=not-updated`);
43
+ for (const issue of report.issues)
44
+ console.log(`[${issue.severity}] ${issue.code}: ${issue.message}`);
45
+ if (report.nextActions.length > 0)
46
+ console.log(`[HADARA] next actions`);
47
+ for (const action of report.nextActions)
48
+ console.log(`${action.id}=${action.command ?? action.message}`);
49
+ }
50
+ if (!report.ok)
51
+ process.exitCode = 6;
52
+ return true;
53
+ }
54
+ function blockLegacyMutation(input, command) {
55
+ const report = (0, legacy_boundary_1.createLegacyMutationBlockedReport)(input.projectRoot, command);
56
+ if (!report)
57
+ return false;
58
+ (0, legacy_boundary_1.printLegacyMutationBlockedReport)(report, input.jsonOutput);
59
+ process.exitCode = 6;
60
+ return true;
61
+ }
62
+ function resolutionTagsFromArgs(args) {
63
+ const tags = [];
64
+ for (const id of getRepeatedStringOptions(args, '--resolves'))
65
+ tags.push(`resolves:${id}`);
66
+ for (const id of getRepeatedStringOptions(args, '--supersedes'))
67
+ tags.push(`supersedes:${id}`);
68
+ return tags.length > 0 ? tags : undefined;
69
+ }
70
+ function getRepeatedStringOptions(args, option) {
71
+ const values = [];
72
+ for (let index = 0; index < args.length; index += 1) {
73
+ if (args[index] !== option)
74
+ continue;
75
+ const value = args[index + 1];
76
+ if (!value || value.startsWith('--'))
77
+ throw new Error(`missing value for ${option}`);
78
+ values.push(value);
79
+ }
80
+ return values;
81
+ }