hadara 0.1.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 (121) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +109 -0
  3. package/dist/agent/evidence.js +50 -0
  4. package/dist/agent/loop.js +124 -0
  5. package/dist/cli/args.js +70 -0
  6. package/dist/cli/dashboard.js +185 -0
  7. package/dist/cli/debt.js +41 -0
  8. package/dist/cli/doctor.js +68 -0
  9. package/dist/cli/errors.js +58 -0
  10. package/dist/cli/evidence-json.js +75 -0
  11. package/dist/cli/evidence.js +80 -0
  12. package/dist/cli/handoff.js +16 -0
  13. package/dist/cli/harness.js +57 -0
  14. package/dist/cli/hermes-json.js +31 -0
  15. package/dist/cli/hermes.js +28 -0
  16. package/dist/cli/init.js +142 -0
  17. package/dist/cli/install.js +34 -0
  18. package/dist/cli/main.js +216 -0
  19. package/dist/cli/mcp.js +15 -0
  20. package/dist/cli/package-smoke.js +37 -0
  21. package/dist/cli/policy-json.js +22 -0
  22. package/dist/cli/policy.js +43 -0
  23. package/dist/cli/release-artifact.js +47 -0
  24. package/dist/cli/release-dry-run.js +24 -0
  25. package/dist/cli/release-gate.js +28 -0
  26. package/dist/cli/release-publish.js +41 -0
  27. package/dist/cli/run-scaffold.js +68 -0
  28. package/dist/cli/run-state.js +41 -0
  29. package/dist/cli/run.js +191 -0
  30. package/dist/cli/smoke.js +58 -0
  31. package/dist/cli/status-json.js +6 -0
  32. package/dist/cli/status.js +26 -0
  33. package/dist/cli/task-json.js +8 -0
  34. package/dist/cli/task.js +64 -0
  35. package/dist/cli/tools.js +25 -0
  36. package/dist/cli/tui.js +72 -0
  37. package/dist/cli/write-preflight.js +27 -0
  38. package/dist/core/audit.js +41 -0
  39. package/dist/core/events.js +63 -0
  40. package/dist/core/fs.js +44 -0
  41. package/dist/core/paths.js +59 -0
  42. package/dist/core/redaction.js +178 -0
  43. package/dist/core/schema.js +253 -0
  44. package/dist/core/workspace.js +47 -0
  45. package/dist/evidence/evidence.js +170 -0
  46. package/dist/evidence/private-manifest.js +101 -0
  47. package/dist/handoff/handoff.js +49 -0
  48. package/dist/harness/replay.js +200 -0
  49. package/dist/harness/validate.js +465 -0
  50. package/dist/hermes/context-export.js +104 -0
  51. package/dist/index.js +29 -0
  52. package/dist/mcp/server.js +104 -0
  53. package/dist/mcp/tool-dispatch.js +159 -0
  54. package/dist/mcp/tool-registry.js +150 -0
  55. package/dist/mcp/tool-schemas.js +18 -0
  56. package/dist/policy/command-risk.js +39 -0
  57. package/dist/policy/permission-matrix.js +42 -0
  58. package/dist/policy/policy.js +20 -0
  59. package/dist/policy/preflight.js +47 -0
  60. package/dist/policy/presets.js +24 -0
  61. package/dist/policy/tokenizer.js +53 -0
  62. package/dist/providers/fallback-executor.js +46 -0
  63. package/dist/providers/mock-provider.js +49 -0
  64. package/dist/providers/provider-contract.js +2 -0
  65. package/dist/providers/provider-preparation.js +220 -0
  66. package/dist/providers/scripted-provider.js +69 -0
  67. package/dist/schemas/active-run-projection.schema.json +73 -0
  68. package/dist/schemas/active-run-resume.schema.json +68 -0
  69. package/dist/schemas/clean-checkout-smoke.schema.json +126 -0
  70. package/dist/schemas/context-export.schema.json +35 -0
  71. package/dist/schemas/event.schema.json +17 -0
  72. package/dist/schemas/evidence-list.schema.json +49 -0
  73. package/dist/schemas/feature-smoke.schema.json +67 -0
  74. package/dist/schemas/install-plan.schema.json +93 -0
  75. package/dist/schemas/package-smoke.schema.json +130 -0
  76. package/dist/schemas/private-evidence.schema.json +48 -0
  77. package/dist/schemas/provider-call.schema.json +42 -0
  78. package/dist/schemas/provider-config.schema.json +43 -0
  79. package/dist/schemas/release-artifact-manifest.schema.json +55 -0
  80. package/dist/schemas/release-artifact.schema.json +140 -0
  81. package/dist/schemas/release-dry-run.schema.json +141 -0
  82. package/dist/schemas/release-gate.schema.json +42 -0
  83. package/dist/schemas/release-publish.schema.json +114 -0
  84. package/dist/schemas/schema-index.json +145 -0
  85. package/dist/schemas/smoke-evidence-summary.schema.json +88 -0
  86. package/dist/schemas/tools-list.schema.json +78 -0
  87. package/dist/schemas/write-preflight.schema.json +47 -0
  88. package/dist/services/active-run-state.js +215 -0
  89. package/dist/services/capability-registry.js +540 -0
  90. package/dist/services/clean-checkout-smoke.js +393 -0
  91. package/dist/services/evidence-list.js +136 -0
  92. package/dist/services/feature-smoke.js +155 -0
  93. package/dist/services/harness-service.js +7 -0
  94. package/dist/services/install-plan.js +233 -0
  95. package/dist/services/operational-debt.js +767 -0
  96. package/dist/services/operations-status-service.js +195 -0
  97. package/dist/services/package-smoke.js +676 -0
  98. package/dist/services/policy-service.js +25 -0
  99. package/dist/services/project-read-model.js +101 -0
  100. package/dist/services/release-artifact-evidence.js +77 -0
  101. package/dist/services/release-artifact.js +351 -0
  102. package/dist/services/release-dry-run.js +253 -0
  103. package/dist/services/release-evidence.js +138 -0
  104. package/dist/services/release-publish.js +163 -0
  105. package/dist/services/smoke-evidence.js +104 -0
  106. package/dist/services/task-read-model.js +125 -0
  107. package/dist/services/tools-list.js +26 -0
  108. package/dist/services/write-preflight.js +240 -0
  109. package/dist/task/task-capsule.js +121 -0
  110. package/dist/tools/fake-shell.js +56 -0
  111. package/dist/tui/cache.js +341 -0
  112. package/dist/tui/constants.js +44 -0
  113. package/dist/tui/layout.js +140 -0
  114. package/dist/tui/markdown.js +238 -0
  115. package/dist/tui/read-model-worker.js +24 -0
  116. package/dist/tui/read-model.js +502 -0
  117. package/dist/tui/snapshot.js +434 -0
  118. package/dist/tui/state.js +229 -0
  119. package/dist/tui/terminal.js +475 -0
  120. package/dist/tui/theme.js +86 -0
  121. package/package.json +16 -0
@@ -0,0 +1,88 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "hadara.smokeEvidenceSummary.v1",
4
+ "x-hadara-schema-id": "hadara.smokeEvidenceSummary.v1",
5
+ "title": "HADARA Smoke Evidence Summary",
6
+ "type": "object",
7
+ "additionalProperties": true,
8
+ "required": [
9
+ "schemaVersion",
10
+ "time",
11
+ "taskId",
12
+ "category",
13
+ "sourceReport",
14
+ "execution",
15
+ "steps",
16
+ "privacy",
17
+ "issues",
18
+ "rawLogsIncluded",
19
+ "privatePathsIncluded",
20
+ "rawPackageContentsIncluded"
21
+ ],
22
+ "properties": {
23
+ "schemaVersion": { "const": "hadara.smokeEvidenceSummary.v1" },
24
+ "time": { "type": "string", "minLength": 1 },
25
+ "taskId": { "type": "string", "pattern": "^T-[0-9]{4}$" },
26
+ "category": { "type": "string", "enum": ["package-smoke", "clean-checkout-smoke"] },
27
+ "sourceReport": {
28
+ "type": "object",
29
+ "additionalProperties": true,
30
+ "required": ["schemaVersion", "command", "mode", "ok"],
31
+ "properties": {
32
+ "schemaVersion": { "type": "string", "minLength": 1 },
33
+ "command": { "type": "string", "minLength": 1 },
34
+ "mode": { "type": "string", "minLength": 1 },
35
+ "ok": { "type": "boolean" }
36
+ }
37
+ },
38
+ "execution": { "type": "object", "additionalProperties": true },
39
+ "steps": {
40
+ "type": "array",
41
+ "items": { "$ref": "#/$defs/step" }
42
+ },
43
+ "privacy": {
44
+ "type": "object",
45
+ "additionalProperties": true,
46
+ "properties": {
47
+ "rawLogsIncluded": { "const": false },
48
+ "rawPackageContentsIncluded": { "const": false },
49
+ "privatePathsIncluded": { "const": false },
50
+ "environmentSecretsIncluded": { "const": false },
51
+ "privateStorePathsIncluded": { "const": false }
52
+ }
53
+ },
54
+ "issues": {
55
+ "type": "array",
56
+ "items": { "$ref": "#/$defs/issue" }
57
+ },
58
+ "rawLogsIncluded": { "const": false },
59
+ "privatePathsIncluded": { "const": false },
60
+ "rawPackageContentsIncluded": { "const": false }
61
+ },
62
+ "$defs": {
63
+ "step": {
64
+ "type": "object",
65
+ "additionalProperties": true,
66
+ "required": ["id", "label", "status", "summary"],
67
+ "properties": {
68
+ "id": { "type": "string", "minLength": 1 },
69
+ "label": { "type": "string", "minLength": 1 },
70
+ "status": { "type": "string", "enum": ["planned", "passed", "failed", "skipped"] },
71
+ "exitCode": { "type": ["integer", "null"] },
72
+ "elapsedMs": { "type": "integer" },
73
+ "summary": { "type": "string", "minLength": 1 }
74
+ }
75
+ },
76
+ "issue": {
77
+ "type": "object",
78
+ "additionalProperties": true,
79
+ "required": ["severity", "code", "message"],
80
+ "properties": {
81
+ "severity": { "type": "string", "enum": ["warning", "error"] },
82
+ "code": { "type": "string", "minLength": 1 },
83
+ "message": { "type": "string", "minLength": 1 },
84
+ "stepId": { "type": "string", "minLength": 1 }
85
+ }
86
+ }
87
+ }
88
+ }
@@ -0,0 +1,78 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "hadara.tools.list.v1",
4
+ "x-hadara-schema-id": "hadara.tools.list.v1",
5
+ "title": "HADARA Tools List Report",
6
+ "type": "object",
7
+ "additionalProperties": true,
8
+ "required": ["schemaVersion", "command", "ok", "surfaces", "disabled", "issues"],
9
+ "properties": {
10
+ "schemaVersion": { "const": "hadara.tools.list.v1" },
11
+ "command": { "const": "tools.list" },
12
+ "ok": { "const": true },
13
+ "surfaces": {
14
+ "type": "object",
15
+ "additionalProperties": true,
16
+ "required": ["cli", "mcp"],
17
+ "properties": {
18
+ "cli": {
19
+ "type": "array",
20
+ "items": { "$ref": "#/$defs/surface" }
21
+ },
22
+ "mcp": {
23
+ "type": "array",
24
+ "items": { "$ref": "#/$defs/surface" }
25
+ }
26
+ }
27
+ },
28
+ "disabled": {
29
+ "type": "array",
30
+ "items": { "$ref": "#/$defs/disabledSurface" }
31
+ },
32
+ "issues": {
33
+ "type": "array",
34
+ "items": { "$ref": "#/$defs/issue" }
35
+ }
36
+ },
37
+ "$defs": {
38
+ "surface": {
39
+ "type": "object",
40
+ "additionalProperties": true,
41
+ "required": ["name", "category", "stable", "readOnly", "enabledByDefault", "availability", "risk"],
42
+ "properties": {
43
+ "name": { "type": "string", "minLength": 1 },
44
+ "category": { "type": "string", "enum": ["read", "write", "execute", "provider", "release"] },
45
+ "stable": { "type": "boolean" },
46
+ "readOnly": { "type": "boolean" },
47
+ "enabledByDefault": { "type": "boolean" },
48
+ "availability": { "type": "string", "enum": ["default", "opt-in", "disabled", "deferred"] },
49
+ "risk": { "type": "string", "enum": ["low", "medium", "high"] },
50
+ "requiresApproval": { "type": "boolean" },
51
+ "schemaVersion": { "type": "string", "minLength": 1 },
52
+ "notes": { "type": "string", "minLength": 1 }
53
+ }
54
+ },
55
+ "disabledSurface": {
56
+ "type": "object",
57
+ "additionalProperties": true,
58
+ "required": ["name", "category", "availability", "risk", "reason"],
59
+ "properties": {
60
+ "name": { "type": "string", "minLength": 1 },
61
+ "category": { "type": "string", "enum": ["read", "write", "execute", "provider", "release"] },
62
+ "availability": { "type": "string", "enum": ["disabled", "deferred"] },
63
+ "risk": { "type": "string", "enum": ["low", "medium", "high"] },
64
+ "reason": { "type": "string", "minLength": 1 }
65
+ }
66
+ },
67
+ "issue": {
68
+ "type": "object",
69
+ "additionalProperties": true,
70
+ "required": ["severity", "code", "message"],
71
+ "properties": {
72
+ "severity": { "type": "string", "enum": ["warning", "error"] },
73
+ "code": { "type": "string", "minLength": 1 },
74
+ "message": { "type": "string", "minLength": 1 }
75
+ }
76
+ }
77
+ }
78
+ }
@@ -0,0 +1,47 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "hadara.write.preflight.v1",
4
+ "x-hadara-schema-id": "hadara.write.preflight.v1",
5
+ "title": "HADARA CLI Write Preflight Report",
6
+ "type": "object",
7
+ "additionalProperties": true,
8
+ "required": ["schemaVersion", "ok", "command", "risk", "requiresApproval", "workspaceBoundary", "writes", "issues"],
9
+ "properties": {
10
+ "schemaVersion": { "const": "hadara.write.preflight.v1" },
11
+ "ok": { "type": "boolean" },
12
+ "command": {
13
+ "type": "string",
14
+ "enum": [
15
+ "task.create",
16
+ "evidence.collect",
17
+ "handoff.update",
18
+ "run-state.start",
19
+ "run-state.update",
20
+ "run-state.complete",
21
+ "debt.add",
22
+ "debt.update",
23
+ "unknown"
24
+ ]
25
+ },
26
+ "risk": { "type": "string", "enum": ["low", "medium", "high"] },
27
+ "requiresApproval": { "type": "boolean" },
28
+ "workspaceBoundary": { "type": "string", "enum": ["project", "project+private-portable"] },
29
+ "writes": {
30
+ "type": "array",
31
+ "items": { "type": "string", "minLength": 1 }
32
+ },
33
+ "issues": {
34
+ "type": "array",
35
+ "items": {
36
+ "type": "object",
37
+ "additionalProperties": true,
38
+ "required": ["severity", "code", "message"],
39
+ "properties": {
40
+ "severity": { "type": "string", "enum": ["warning", "error"] },
41
+ "code": { "type": "string", "minLength": 1 },
42
+ "message": { "type": "string", "minLength": 1 }
43
+ }
44
+ }
45
+ }
46
+ }
47
+ }
@@ -0,0 +1,215 @@
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.activeRunManifestPath = activeRunManifestPath;
7
+ exports.activeRunManifestPortablePath = activeRunManifestPortablePath;
8
+ exports.createActiveRunManifest = createActiveRunManifest;
9
+ exports.writeActiveRunManifest = writeActiveRunManifest;
10
+ exports.readActiveRunManifest = readActiveRunManifest;
11
+ exports.createActiveRunProjection = createActiveRunProjection;
12
+ exports.safeCreateActiveRunProjection = safeCreateActiveRunProjection;
13
+ exports.createActiveRunResumeReport = createActiveRunResumeReport;
14
+ exports.assertActiveRunProjectionSchema = assertActiveRunProjectionSchema;
15
+ exports.assertActiveRunResumeSchema = assertActiveRunResumeSchema;
16
+ const node_fs_1 = __importDefault(require("node:fs"));
17
+ const node_path_1 = __importDefault(require("node:path"));
18
+ const fs_1 = require("../core/fs");
19
+ const schema_1 = require("../core/schema");
20
+ const task_capsule_1 = require("../task/task-capsule");
21
+ const project_read_model_1 = require("./project-read-model");
22
+ class ActiveRunManifestReadError extends Error {
23
+ constructor(message) {
24
+ super(message);
25
+ this.name = 'ActiveRunManifestReadError';
26
+ }
27
+ }
28
+ function activeRunManifestPath(projectRoot) {
29
+ return node_path_1.default.join(projectRoot, '.hadara', 'local', 'state', 'active-run.json');
30
+ }
31
+ function activeRunManifestPortablePath() {
32
+ return '.hadara/local/state/active-run.json';
33
+ }
34
+ function createActiveRunManifest(projectRoot, input) {
35
+ const task = (0, task_capsule_1.listTaskCapsules)(projectRoot).find((item) => item.id === input.taskId);
36
+ return {
37
+ schemaVersion: 'hadara.active_run.v1',
38
+ runId: input.runId,
39
+ taskId: input.taskId,
40
+ capsule: task ? toPortablePath(node_path_1.default.relative(projectRoot, task.dir)) : '',
41
+ status: input.status ?? 'active',
42
+ startedAt: input.startedAt,
43
+ updatedAt: input.updatedAt ?? input.startedAt,
44
+ summary: input.summary
45
+ };
46
+ }
47
+ function writeActiveRunManifest(projectRoot, manifest) {
48
+ const filePath = activeRunManifestPath(projectRoot);
49
+ (0, fs_1.ensureDir)(node_path_1.default.dirname(filePath));
50
+ node_fs_1.default.writeFileSync(filePath, `${JSON.stringify(manifest, null, 2)}\n`, 'utf8');
51
+ }
52
+ function readActiveRunManifest(projectRoot) {
53
+ const filePath = activeRunManifestPath(projectRoot);
54
+ if (!node_fs_1.default.existsSync(filePath))
55
+ return null;
56
+ let parsed;
57
+ try {
58
+ parsed = JSON.parse(node_fs_1.default.readFileSync(filePath, 'utf8'));
59
+ }
60
+ catch (error) {
61
+ const message = error instanceof Error ? error.message : String(error);
62
+ throw new ActiveRunManifestReadError(message);
63
+ }
64
+ if (!isActiveRunManifest(parsed)) {
65
+ throw new ActiveRunManifestReadError(`${activeRunManifestPortablePath()} is not a valid active run manifest.`);
66
+ }
67
+ return parsed;
68
+ }
69
+ function createActiveRunProjection(projectRoot) {
70
+ const activeRun = readActiveRunManifest(projectRoot);
71
+ const issues = [];
72
+ const task = activeRun ? (0, task_capsule_1.listTaskCapsules)(projectRoot).find((item) => item.id === activeRun.taskId) : undefined;
73
+ const canonicalCapsule = task ? toPortablePath(node_path_1.default.relative(projectRoot, task.dir)) : null;
74
+ const staleReason = activeRun ? findStaleHandoffReason(projectRoot, activeRun) : null;
75
+ const taskMissing = activeRun ? !task : false;
76
+ const capsuleMismatch = activeRun && canonicalCapsule !== null && activeRun.capsule !== canonicalCapsule;
77
+ if (staleReason) {
78
+ issues.push({
79
+ severity: 'warning',
80
+ code: 'ACTIVE_RUN_HANDOFF_STALE',
81
+ message: staleReason
82
+ });
83
+ }
84
+ if (activeRun && taskMissing) {
85
+ issues.push({
86
+ severity: 'warning',
87
+ code: 'ACTIVE_RUN_TASK_NOT_FOUND',
88
+ message: `Active run ${activeRun.taskId} has no matching Task Capsule.`
89
+ });
90
+ }
91
+ if (activeRun && capsuleMismatch) {
92
+ issues.push({
93
+ severity: 'warning',
94
+ code: 'ACTIVE_RUN_CAPSULE_MISMATCH',
95
+ message: `Active run ${activeRun.taskId} points to ${activeRun.capsule || '(empty capsule)'}, but the canonical Task Capsule path is ${canonicalCapsule}.`
96
+ });
97
+ }
98
+ const resumeCapsule = canonicalCapsule ?? activeRun?.capsule ?? '';
99
+ const report = {
100
+ schemaVersion: 'hadara.active_run.projection.v1',
101
+ command: 'active-run.projection',
102
+ ok: true,
103
+ path: activeRunManifestPortablePath(),
104
+ activeRun,
105
+ handoff: {
106
+ fresh: staleReason === null,
107
+ staleReason
108
+ },
109
+ resume: activeRun
110
+ ? {
111
+ taskId: activeRun.taskId,
112
+ capsule: resumeCapsule,
113
+ nextAction: taskMissing
114
+ ? `Resolve missing Task Capsule for ${activeRun.taskId} before resuming.`
115
+ : `Resume ${activeRun.taskId} from ${resumeCapsule || activeRunManifestPortablePath()}.`
116
+ }
117
+ : null,
118
+ issues
119
+ };
120
+ assertActiveRunProjectionSchema(report);
121
+ return report;
122
+ }
123
+ function safeCreateActiveRunProjection(projectRoot) {
124
+ try {
125
+ return createActiveRunProjection(projectRoot);
126
+ }
127
+ catch (error) {
128
+ const message = error instanceof Error ? error.message : String(error);
129
+ const code = error instanceof ActiveRunManifestReadError ? 'ACTIVE_RUN_MANIFEST_INVALID' : 'ACTIVE_RUN_REPORT_SCHEMA_INVALID';
130
+ const staleReason = error instanceof ActiveRunManifestReadError
131
+ ? `${activeRunManifestPortablePath()} could not be read.`
132
+ : `${activeRunManifestPortablePath()} produced an invalid active-run report.`;
133
+ const report = {
134
+ schemaVersion: 'hadara.active_run.projection.v1',
135
+ command: 'active-run.projection',
136
+ ok: true,
137
+ path: activeRunManifestPortablePath(),
138
+ activeRun: null,
139
+ handoff: {
140
+ fresh: false,
141
+ staleReason
142
+ },
143
+ resume: null,
144
+ issues: [
145
+ {
146
+ severity: 'warning',
147
+ code,
148
+ message
149
+ }
150
+ ]
151
+ };
152
+ assertActiveRunProjectionSchema(report);
153
+ return report;
154
+ }
155
+ }
156
+ function createActiveRunResumeReport(projectRoot) {
157
+ const projection = safeCreateActiveRunProjection(projectRoot);
158
+ const activeRun = projection.activeRun;
159
+ const taskId = activeRun?.taskId ?? null;
160
+ const capsule = projection.resume?.capsule || activeRun?.capsule || (taskId ? `tasks/${taskId}` : null);
161
+ const report = {
162
+ schemaVersion: 'hadara.active_run.resume.v1',
163
+ command: 'active-run.resume',
164
+ ok: true,
165
+ activeRun,
166
+ resumePrompt: {
167
+ summary: activeRun ? `Continue ${activeRun.taskId}: ${activeRun.summary}` : 'No active run is currently recorded.',
168
+ mustRead: activeRun
169
+ ? ['docs/AGENT_HANDOFF.md', `${capsule}/TASK.md`, `${capsule}/HANDOFF.md`]
170
+ : ['docs/AGENT_HANDOFF.md', 'docs/TASK_BOARD.md'],
171
+ nextActions: activeRun
172
+ ? [projection.resume?.nextAction ?? `Resume ${activeRun.taskId}.`, 'Run required validation before marking the task Done.']
173
+ : ['Pick or create one Task Capsule before implementation.', 'Follow docs/AGENT_HANDOFF.md for the next recommended step.'],
174
+ constraints: [
175
+ 'Do not assume multi-agent queues.',
176
+ 'Do not use MCP write tools for active-run mutation.',
177
+ 'Attach evidence before marking work Done.'
178
+ ]
179
+ },
180
+ issues: projection.issues
181
+ };
182
+ assertActiveRunResumeSchema(report);
183
+ return report;
184
+ }
185
+ function assertActiveRunProjectionSchema(report) {
186
+ (0, schema_1.assertSchema)('hadara.active_run.projection.v1', report);
187
+ }
188
+ function assertActiveRunResumeSchema(report) {
189
+ (0, schema_1.assertSchema)('hadara.active_run.resume.v1', report);
190
+ }
191
+ function findStaleHandoffReason(projectRoot, activeRun) {
192
+ const sources = (0, project_read_model_1.readProjectSources)(projectRoot);
193
+ if (!sources.handoff.exists)
194
+ return `Active run ${activeRun.taskId} exists, but docs/AGENT_HANDOFF.md is missing.`;
195
+ if (!sources.handoff.content.includes(activeRun.taskId)) {
196
+ return `Active run ${activeRun.taskId} is not mentioned in docs/AGENT_HANDOFF.md.`;
197
+ }
198
+ return null;
199
+ }
200
+ function isActiveRunManifest(value) {
201
+ if (typeof value !== 'object' || value === null)
202
+ return false;
203
+ const candidate = value;
204
+ return (candidate.schemaVersion === 'hadara.active_run.v1' &&
205
+ typeof candidate.runId === 'string' &&
206
+ typeof candidate.taskId === 'string' &&
207
+ typeof candidate.capsule === 'string' &&
208
+ (candidate.status === 'active' || candidate.status === 'paused') &&
209
+ typeof candidate.startedAt === 'string' &&
210
+ typeof candidate.updatedAt === 'string' &&
211
+ typeof candidate.summary === 'string');
212
+ }
213
+ function toPortablePath(value) {
214
+ return value.split(node_path_1.default.sep).join('/');
215
+ }