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
@@ -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 }))
@@ -222,6 +250,9 @@ async function main(args = process.argv.slice(2)) {
222
250
  break;
223
251
  }
224
252
  case 'release': {
253
+ const { handleReleaseCloseoutCommand } = await Promise.resolve().then(() => __importStar(require('./release-closeout')));
254
+ if (handleReleaseCloseoutCommand({ args, projectRoot: paths.projectRoot, jsonOutput }))
255
+ return;
225
256
  const { handleReleaseDryRunCommand } = await Promise.resolve().then(() => __importStar(require('./release-dry-run')));
226
257
  if (handleReleaseDryRunCommand({ args, projectRoot: paths.projectRoot, jsonOutput }))
227
258
  return;
@@ -1,10 +1,43 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.handlePackageCommand = handlePackageCommand;
4
+ const package_recycle_1 = require("../services/package-recycle");
4
5
  const package_smoke_1 = require("../services/package-smoke");
5
6
  const args_1 = require("./args");
6
7
  function handlePackageCommand(input) {
7
- if (input.args[0] !== 'package' || input.args[1] !== 'smoke')
8
+ if (input.args[0] !== 'package')
9
+ return false;
10
+ if (input.args[1] === 'recycle') {
11
+ const report = (0, package_recycle_1.createPackageRecycleReport)({
12
+ paths: input.paths,
13
+ execute: (0, args_1.getFlag)(input.args, '--execute'),
14
+ packageSpecifier: (0, args_1.getStringOption)(input.args, '--package'),
15
+ expectedVersion: (0, args_1.getStringOption)(input.args, '--expected-version'),
16
+ workspace: (0, args_1.getStringOption)(input.args, '--workspace'),
17
+ taskId: (0, args_1.getStringOption)(input.args, '--task'),
18
+ attachEvidence: (0, args_1.getFlag)(input.args, '--attach-evidence'),
19
+ noEvidence: (0, args_1.getFlag)(input.args, '--no-evidence'),
20
+ keepTemp: (0, args_1.getFlag)(input.args, '--keep-temp'),
21
+ includeGraph: (0, args_1.getFlag)(input.args, '--include-graph'),
22
+ timeoutSeconds: (0, args_1.getIntegerOption)(input.args, '--timeout', { min: 1 })
23
+ });
24
+ if (input.jsonOutput) {
25
+ console.log(JSON.stringify(report, null, 2));
26
+ }
27
+ else {
28
+ console.log(`${report.ok ? 'passed' : 'failed'} | package recycle | ${report.mode}`);
29
+ for (const step of report.steps) {
30
+ console.log(`${step.status} | ${step.label} | ${step.summary}`);
31
+ }
32
+ for (const issue of report.issues) {
33
+ console.log(`${issue.severity} | ${issue.code} | ${issue.message}`);
34
+ }
35
+ }
36
+ if (!report.ok)
37
+ process.exitCode = 6;
38
+ return true;
39
+ }
40
+ if (input.args[1] !== 'smoke')
8
41
  return false;
9
42
  const options = {
10
43
  paths: input.paths,
@@ -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'),
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleReleaseCloseoutCommand = handleReleaseCloseoutCommand;
4
+ const release_closeout_1 = require("../services/release-closeout");
5
+ const args_1 = require("./args");
6
+ function handleReleaseCloseoutCommand(input) {
7
+ if (input.args[0] !== 'release' || input.args[1] !== 'closeout')
8
+ return false;
9
+ const report = (0, release_closeout_1.createReleaseCloseoutReport)(input.projectRoot, {
10
+ version: (0, args_1.getStringOption)(input.args, '--version'),
11
+ taskId: (0, args_1.getStringOption)(input.args, '--task')
12
+ });
13
+ if (input.jsonOutput) {
14
+ console.log(JSON.stringify(report, null, 2));
15
+ }
16
+ else {
17
+ console.log((0, release_closeout_1.formatReleaseCloseoutReport)(report));
18
+ }
19
+ if (!report.ok)
20
+ process.exitCode = 6;
21
+ return true;
22
+ }
@@ -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");
@@ -15,10 +14,14 @@ const task_upgrade_scaffold_1 = require("../task/task-upgrade-scaffold");
15
14
  const task_workbench_1 = require("../services/task-workbench");
16
15
  const actor_1 = require("./actor");
17
16
  const args_1 = require("./args");
17
+ const legacy_boundary_1 = require("./legacy-boundary");
18
18
  const task_json_1 = require("./task-json");
19
19
  function handleTaskCommand(input) {
20
+ const startedAtMs = Date.now();
20
21
  const sub = input.args[1];
21
22
  if (sub === 'create') {
23
+ if (blockLegacyMutation(input, 'task.create'))
24
+ return true;
22
25
  const title = extractTaskCreateTitle(input.args);
23
26
  if (!title)
24
27
  throw new Error('task create requires a title');
@@ -74,6 +77,8 @@ function handleTaskCommand(input) {
74
77
  return true;
75
78
  }
76
79
  if (sub === 'upgrade-scaffold') {
80
+ if ((0, args_1.getFlag)(input.args, '--execute') && blockLegacyMutation(input, 'task.upgrade-scaffold'))
81
+ return true;
77
82
  const id = (0, args_1.getStringOption)(input.args, '--task') ?? input.args[2];
78
83
  if (!id || id.startsWith('--'))
79
84
  throw new Error('task upgrade-scaffold requires --task <task-id>');
@@ -91,6 +96,8 @@ function handleTaskCommand(input) {
91
96
  return true;
92
97
  }
93
98
  if (sub === 'close') {
99
+ if ((0, args_1.getFlag)(input.args, '--execute') && blockLegacyMutation(input, 'task.close'))
100
+ return true;
94
101
  const id = (0, args_1.getStringOption)(input.args, '--task') ?? input.args[2];
95
102
  if (!id || id.startsWith('--'))
96
103
  throw new Error('task close requires --task <task-id>');
@@ -112,11 +119,46 @@ function handleTaskCommand(input) {
112
119
  process.exitCode = 6;
113
120
  return true;
114
121
  }
115
- if (sub === 'status') {
122
+ if (sub === 'close-source') {
116
123
  const id = (0, args_1.getStringOption)(input.args, '--task') ?? input.args[2];
117
124
  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);
125
+ throw new Error('task close-source requires --task <task-id>');
126
+ const report = (0, task_close_1.createTaskCloseSourceReport)(input.projectRoot, id);
127
+ if (input.jsonOutput) {
128
+ console.log(JSON.stringify(report, null, 2));
129
+ }
130
+ else {
131
+ console.log(`[HADARA] task close-source ${id}: ${report.ok ? 'ok' : 'issues'}`);
132
+ console.log(`sourceHash\t${report.sourceHash}`);
133
+ for (const unit of report.sourceUnits)
134
+ console.log(`${unit.closeSourceRole}\t${unit.kind}\t${unit.path}\t${unit.selector ?? ''}\t${unit.sha256}`);
135
+ for (const issue of report.issues)
136
+ console.log(`[${issue.severity}] ${issue.code}: ${issue.message}`);
137
+ }
138
+ if (!report.ok)
139
+ process.exitCode = 6;
140
+ return true;
141
+ }
142
+ if (sub === 'status') {
143
+ const id = (0, args_1.getStringOption)(input.args, '--task') ?? input.args[2];
144
+ if (!id || id.startsWith('--')) {
145
+ const report = (0, task_workbench_1.createTaskStatusSelectionReport)(input.projectRoot);
146
+ attachCliDiagnostics(report, startedAtMs, 'task.status');
147
+ if (input.jsonOutput) {
148
+ console.log(JSON.stringify(report, null, 2));
149
+ }
150
+ else {
151
+ console.log((0, task_workbench_1.formatTaskStatusSelectionReport)(report));
152
+ }
153
+ if (!report.ok)
154
+ process.exitCode = 6;
155
+ return true;
156
+ }
157
+ const detail = (0, args_1.getStringOption)(input.args, '--detail');
158
+ if (detail && detail !== 'fast' && detail !== 'full')
159
+ throw new Error('task status --detail must be fast or full');
160
+ const report = (0, task_workbench_1.createTaskWorkbenchReport)(input.projectRoot, id, new Date(), { detail: detail === 'full' ? 'full' : 'fast' });
161
+ attachCliDiagnostics(report, startedAtMs, 'task.status');
120
162
  if (input.jsonOutput) {
121
163
  console.log(JSON.stringify(report, null, 2));
122
164
  }
@@ -128,6 +170,8 @@ function handleTaskCommand(input) {
128
170
  return true;
129
171
  }
130
172
  if (sub === 'complete') {
173
+ if ((0, args_1.getFlag)(input.args, '--execute') && blockLegacyMutation(input, 'task.complete'))
174
+ return true;
131
175
  const id = (0, args_1.getStringOption)(input.args, '--task') ?? input.args[2];
132
176
  if (!id || id.startsWith('--'))
133
177
  throw new Error('task complete requires --task <task-id>');
@@ -143,14 +187,19 @@ function handleTaskCommand(input) {
143
187
  return true;
144
188
  }
145
189
  if (sub === 'finalize') {
190
+ if ((0, args_1.getFlag)(input.args, '--execute') && blockLegacyMutation(input, 'task.finalize'))
191
+ return true;
146
192
  const id = (0, args_1.getStringOption)(input.args, '--task') ?? input.args[2];
147
193
  if (!id || id.startsWith('--'))
148
194
  throw new Error('task finalize requires --task <task-id>');
195
+ const executeRequested = (0, args_1.getFlag)(input.args, '--execute');
149
196
  const report = (0, task_finalize_1.createTaskFinalizeReport)(input.projectRoot, id, {
150
- executeRequested: (0, args_1.getFlag)(input.args, '--execute'),
197
+ executeRequested,
151
198
  planHash: (0, args_1.getStringOption)(input.args, '--plan-hash'),
152
- actor: (0, actor_1.getActorContextOption)(input.args)
199
+ actor: (0, actor_1.getActorContextOption)(input.args),
200
+ onProgress: executeRequested ? createTaskFinalizeProgressWriter(id) : undefined
153
201
  });
202
+ attachCliDiagnostics(report, startedAtMs, 'task.finalize');
154
203
  if (input.jsonOutput) {
155
204
  console.log(JSON.stringify(report, null, 2));
156
205
  }
@@ -176,22 +225,9 @@ function handleTaskCommand(input) {
176
225
  process.exitCode = 6;
177
226
  return true;
178
227
  }
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
228
  if (sub === 'finish') {
229
+ if ((0, args_1.getFlag)(input.args, '--execute') && blockLegacyMutation(input, 'task.finish'))
230
+ return true;
195
231
  const id = (0, args_1.getStringOption)(input.args, '--task') ?? input.args[2];
196
232
  if (!id || id.startsWith('--'))
197
233
  throw new Error('task finish requires --task <task-id>');
@@ -245,6 +281,34 @@ function handleTaskCommand(input) {
245
281
  }
246
282
  return false;
247
283
  }
284
+ function createTaskFinalizeProgressWriter(taskId) {
285
+ return (event) => {
286
+ const ok = event.ok === undefined ? '' : ` ok=${event.ok}`;
287
+ process.stderr.write(`[HADARA] task finalize ${taskId}: ${event.step} ${event.phase}${ok} - ${event.summary}\n`);
288
+ };
289
+ }
290
+ function attachCliDiagnostics(report, startedAtMs, commandPath) {
291
+ const durationMs = Math.max(0, Date.now() - startedAtMs);
292
+ const slowThresholdMs = 10000;
293
+ const slow = durationMs >= slowThresholdMs;
294
+ report.diagnostics = {
295
+ generatedBy: 'cli',
296
+ commandPath,
297
+ durationMs,
298
+ slowThresholdMs,
299
+ slow,
300
+ ...(slow ? { note: 'This command was slow enough to affect interactive agent UX; prefer narrower diagnostics or progress-aware follow-up work if this repeats.' } : {})
301
+ };
302
+ return report;
303
+ }
304
+ function blockLegacyMutation(input, command) {
305
+ const report = (0, legacy_boundary_1.createLegacyMutationBlockedReport)(input.projectRoot, command);
306
+ if (!report)
307
+ return false;
308
+ (0, legacy_boundary_1.printLegacyMutationBlockedReport)(report, input.jsonOutput);
309
+ process.exitCode = 6;
310
+ return true;
311
+ }
248
312
  function extractTaskCreateTitle(args) {
249
313
  const explicitTitle = (0, args_1.getStringOption)(args, '--title');
250
314
  if (explicitTitle)
@@ -0,0 +1,71 @@
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
+ if (report.evidence)
32
+ console.log(`evidence=${report.evidence.id}`);
33
+ if (!report.taskValidationRow.updated)
34
+ console.log(`taskValidationRow=${report.taskValidationRow.mode}`);
35
+ for (const issue of report.issues)
36
+ console.log(`[${issue.severity}] ${issue.code}: ${issue.message}`);
37
+ for (const action of report.nextActions)
38
+ console.log(`next=${action.command ?? action.message}`);
39
+ }
40
+ if (!report.ok)
41
+ process.exitCode = 6;
42
+ return true;
43
+ }
44
+ function blockLegacyMutation(input, command) {
45
+ const report = (0, legacy_boundary_1.createLegacyMutationBlockedReport)(input.projectRoot, command);
46
+ if (!report)
47
+ return false;
48
+ (0, legacy_boundary_1.printLegacyMutationBlockedReport)(report, input.jsonOutput);
49
+ process.exitCode = 6;
50
+ return true;
51
+ }
52
+ function resolutionTagsFromArgs(args) {
53
+ const tags = [];
54
+ for (const id of getRepeatedStringOptions(args, '--resolves'))
55
+ tags.push(`resolves:${id}`);
56
+ for (const id of getRepeatedStringOptions(args, '--supersedes'))
57
+ tags.push(`supersedes:${id}`);
58
+ return tags.length > 0 ? tags : undefined;
59
+ }
60
+ function getRepeatedStringOptions(args, option) {
61
+ const values = [];
62
+ for (let index = 0; index < args.length; index += 1) {
63
+ if (args[index] !== option)
64
+ continue;
65
+ const value = args[index + 1];
66
+ if (!value || value.startsWith('--'))
67
+ throw new Error(`missing value for ${option}`);
68
+ values.push(value);
69
+ }
70
+ return values;
71
+ }