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.
- package/LICENSE +21 -0
- package/README.md +109 -0
- package/dist/agent/evidence.js +50 -0
- package/dist/agent/loop.js +124 -0
- package/dist/cli/args.js +70 -0
- package/dist/cli/dashboard.js +185 -0
- package/dist/cli/debt.js +41 -0
- package/dist/cli/doctor.js +68 -0
- package/dist/cli/errors.js +58 -0
- package/dist/cli/evidence-json.js +75 -0
- package/dist/cli/evidence.js +80 -0
- package/dist/cli/handoff.js +16 -0
- package/dist/cli/harness.js +57 -0
- package/dist/cli/hermes-json.js +31 -0
- package/dist/cli/hermes.js +28 -0
- package/dist/cli/init.js +142 -0
- package/dist/cli/install.js +34 -0
- package/dist/cli/main.js +216 -0
- package/dist/cli/mcp.js +15 -0
- package/dist/cli/package-smoke.js +37 -0
- package/dist/cli/policy-json.js +22 -0
- package/dist/cli/policy.js +43 -0
- package/dist/cli/release-artifact.js +47 -0
- package/dist/cli/release-dry-run.js +24 -0
- package/dist/cli/release-gate.js +28 -0
- package/dist/cli/release-publish.js +41 -0
- package/dist/cli/run-scaffold.js +68 -0
- package/dist/cli/run-state.js +41 -0
- package/dist/cli/run.js +191 -0
- package/dist/cli/smoke.js +58 -0
- package/dist/cli/status-json.js +6 -0
- package/dist/cli/status.js +26 -0
- package/dist/cli/task-json.js +8 -0
- package/dist/cli/task.js +64 -0
- package/dist/cli/tools.js +25 -0
- package/dist/cli/tui.js +72 -0
- package/dist/cli/write-preflight.js +27 -0
- package/dist/core/audit.js +41 -0
- package/dist/core/events.js +63 -0
- package/dist/core/fs.js +44 -0
- package/dist/core/paths.js +59 -0
- package/dist/core/redaction.js +178 -0
- package/dist/core/schema.js +253 -0
- package/dist/core/workspace.js +47 -0
- package/dist/evidence/evidence.js +170 -0
- package/dist/evidence/private-manifest.js +101 -0
- package/dist/handoff/handoff.js +49 -0
- package/dist/harness/replay.js +200 -0
- package/dist/harness/validate.js +465 -0
- package/dist/hermes/context-export.js +104 -0
- package/dist/index.js +29 -0
- package/dist/mcp/server.js +104 -0
- package/dist/mcp/tool-dispatch.js +159 -0
- package/dist/mcp/tool-registry.js +150 -0
- package/dist/mcp/tool-schemas.js +18 -0
- package/dist/policy/command-risk.js +39 -0
- package/dist/policy/permission-matrix.js +42 -0
- package/dist/policy/policy.js +20 -0
- package/dist/policy/preflight.js +47 -0
- package/dist/policy/presets.js +24 -0
- package/dist/policy/tokenizer.js +53 -0
- package/dist/providers/fallback-executor.js +46 -0
- package/dist/providers/mock-provider.js +49 -0
- package/dist/providers/provider-contract.js +2 -0
- package/dist/providers/provider-preparation.js +220 -0
- package/dist/providers/scripted-provider.js +69 -0
- package/dist/schemas/active-run-projection.schema.json +73 -0
- package/dist/schemas/active-run-resume.schema.json +68 -0
- package/dist/schemas/clean-checkout-smoke.schema.json +126 -0
- package/dist/schemas/context-export.schema.json +35 -0
- package/dist/schemas/event.schema.json +17 -0
- package/dist/schemas/evidence-list.schema.json +49 -0
- package/dist/schemas/feature-smoke.schema.json +67 -0
- package/dist/schemas/install-plan.schema.json +93 -0
- package/dist/schemas/package-smoke.schema.json +130 -0
- package/dist/schemas/private-evidence.schema.json +48 -0
- package/dist/schemas/provider-call.schema.json +42 -0
- package/dist/schemas/provider-config.schema.json +43 -0
- package/dist/schemas/release-artifact-manifest.schema.json +55 -0
- package/dist/schemas/release-artifact.schema.json +140 -0
- package/dist/schemas/release-dry-run.schema.json +141 -0
- package/dist/schemas/release-gate.schema.json +42 -0
- package/dist/schemas/release-publish.schema.json +114 -0
- package/dist/schemas/schema-index.json +145 -0
- package/dist/schemas/smoke-evidence-summary.schema.json +88 -0
- package/dist/schemas/tools-list.schema.json +78 -0
- package/dist/schemas/write-preflight.schema.json +47 -0
- package/dist/services/active-run-state.js +215 -0
- package/dist/services/capability-registry.js +540 -0
- package/dist/services/clean-checkout-smoke.js +393 -0
- package/dist/services/evidence-list.js +136 -0
- package/dist/services/feature-smoke.js +155 -0
- package/dist/services/harness-service.js +7 -0
- package/dist/services/install-plan.js +233 -0
- package/dist/services/operational-debt.js +767 -0
- package/dist/services/operations-status-service.js +195 -0
- package/dist/services/package-smoke.js +676 -0
- package/dist/services/policy-service.js +25 -0
- package/dist/services/project-read-model.js +101 -0
- package/dist/services/release-artifact-evidence.js +77 -0
- package/dist/services/release-artifact.js +351 -0
- package/dist/services/release-dry-run.js +253 -0
- package/dist/services/release-evidence.js +138 -0
- package/dist/services/release-publish.js +163 -0
- package/dist/services/smoke-evidence.js +104 -0
- package/dist/services/task-read-model.js +125 -0
- package/dist/services/tools-list.js +26 -0
- package/dist/services/write-preflight.js +240 -0
- package/dist/task/task-capsule.js +121 -0
- package/dist/tools/fake-shell.js +56 -0
- package/dist/tui/cache.js +341 -0
- package/dist/tui/constants.js +44 -0
- package/dist/tui/layout.js +140 -0
- package/dist/tui/markdown.js +238 -0
- package/dist/tui/read-model-worker.js +24 -0
- package/dist/tui/read-model.js +502 -0
- package/dist/tui/snapshot.js +434 -0
- package/dist/tui/state.js +229 -0
- package/dist/tui/terminal.js +475 -0
- package/dist/tui/theme.js +86 -0
- 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
|
+
}
|