hadara 0.3.0-rc.0 → 0.3.0-rc.1
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/README.md +20 -5
- package/dist/cli/protocol.js +37 -0
- package/dist/core/schema.js +2 -0
- package/dist/schemas/protocol-migration.schema.json +111 -0
- package/dist/schemas/schema-index.json +7 -0
- package/dist/services/capability-registry.js +25 -0
- package/dist/services/protocol-migration.js +396 -0
- package/dist/services/release-artifact.js +3 -3
- package/dist/task/task-finish.js +7 -0
- package/package.json +26 -2
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
</p>
|
|
6
6
|
|
|
7
7
|
<p align="center">
|
|
8
|
-
<img alt="
|
|
8
|
+
<img alt="Published npm release" src="https://img.shields.io/badge/npm-0.3.0--rc.0-blue">
|
|
9
9
|
<img alt="Node.js" src="https://img.shields.io/badge/node-%3E%3D22-brightgreen">
|
|
10
10
|
<img alt="License" src="https://img.shields.io/badge/license-MIT-lightgrey">
|
|
11
11
|
</p>
|
|
@@ -20,7 +20,13 @@ This repository is both the HADARA source checkout and the HADARA protocol works
|
|
|
20
20
|
|
|
21
21
|
## Release Status
|
|
22
22
|
|
|
23
|
-
Current release candidate:
|
|
23
|
+
Current release candidate prepared for operator publish:
|
|
24
|
+
|
|
25
|
+
```text
|
|
26
|
+
hadara@0.3.0-rc.1
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Current published npm release:
|
|
24
30
|
|
|
25
31
|
```text
|
|
26
32
|
hadara@0.3.0-rc.0
|
|
@@ -28,7 +34,7 @@ hadara@0.3.0-rc.0
|
|
|
28
34
|
|
|
29
35
|
The 0.3.0 line is the Phase 7 Surface Refactor. It organizes HADARA's existing task, evidence, proof, lifecycle, release, and document surfaces so agents can distinguish primary lifecycle commands, diagnostics, advanced surfaces, canonical documents, historical documents, and safe Markdown update boundaries.
|
|
30
36
|
|
|
31
|
-
Phase 7.x labels are internal implementation phases, not npm release-candidate labels. Publishing `0.3.0-rc.
|
|
37
|
+
Phase 7.x labels are internal implementation phases, not npm release-candidate labels. Publishing `0.3.0-rc.1` or any later release still requires the approval-gated release path and explicit operator confirmation.
|
|
32
38
|
|
|
33
39
|
| Surface | Status |
|
|
34
40
|
|---|---|
|
|
@@ -36,7 +42,8 @@ Phase 7.x labels are internal implementation phases, not npm release-candidate l
|
|
|
36
42
|
| `hadara@0.2.0-rc.1` | Previous published npm RC. |
|
|
37
43
|
| `hadara@0.2.0-rc.2` | Previous published npm RC. |
|
|
38
44
|
| `hadara@0.2.0-rc.3` | Previous published npm RC. |
|
|
39
|
-
| `hadara@0.3.0-rc.0` | Current
|
|
45
|
+
| `hadara@0.3.0-rc.0` | Current published npm RC; package metadata lacks the intended discovery fields. |
|
|
46
|
+
| `hadara@0.3.0-rc.1` | Current publish candidate; T-0301 prepares the operator-confirmed npm publish path. |
|
|
40
47
|
| GitHub Release | Secondary target, approval-gated. |
|
|
41
48
|
| Docker image | Deferred. |
|
|
42
49
|
| PyPI/Python package | `hadara==0.2.0rc1` published preview bridge. |
|
|
@@ -48,7 +55,7 @@ No release command should publish, create a GitHub Release, build Docker images,
|
|
|
48
55
|
|
|
49
56
|
Requires Node.js 22.
|
|
50
57
|
|
|
51
|
-
Install
|
|
58
|
+
Install the latest published RC before the T-0301 publish step:
|
|
52
59
|
|
|
53
60
|
```bash
|
|
54
61
|
npm install -g hadara@0.3.0-rc.0
|
|
@@ -63,6 +70,14 @@ npx hadara@0.3.0-rc.0 help
|
|
|
63
70
|
npx hadara@0.3.0-rc.0 doctor --json
|
|
64
71
|
```
|
|
65
72
|
|
|
73
|
+
After the T-0301 npm publish helper verifies `hadara@0.3.0-rc.1` on the registry, install the new RC:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npm install -g hadara@0.3.0-rc.1
|
|
77
|
+
hadara help
|
|
78
|
+
hadara doctor --json
|
|
79
|
+
```
|
|
80
|
+
|
|
66
81
|
## What HADARA Gives You
|
|
67
82
|
|
|
68
83
|
| Capability | Purpose |
|
package/dist/cli/protocol.js
CHANGED
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.handleProtocolCommand = handleProtocolCommand;
|
|
4
4
|
const protocol_consistency_1 = require("../services/protocol-consistency");
|
|
5
|
+
const protocol_migration_1 = require("../services/protocol-migration");
|
|
5
6
|
const protocol_remediation_1 = require("../services/protocol-remediation");
|
|
6
7
|
const args_1 = require("./args");
|
|
7
8
|
function handleProtocolCommand(input) {
|
|
8
9
|
const sub = input.args[1];
|
|
10
|
+
if (sub === 'migrate')
|
|
11
|
+
return handleProtocolMigrateCommand(input);
|
|
9
12
|
if (sub === 'remediate')
|
|
10
13
|
return handleProtocolRemediateCommand(input);
|
|
11
14
|
if (sub !== 'doctor')
|
|
@@ -62,6 +65,40 @@ function handleProtocolCommand(input) {
|
|
|
62
65
|
process.exitCode = 6;
|
|
63
66
|
return true;
|
|
64
67
|
}
|
|
68
|
+
function handleProtocolMigrateCommand(input) {
|
|
69
|
+
const target = (0, args_1.getStringOption)(input.args, '--target', '0.3.0') ?? '0.3.0';
|
|
70
|
+
if (target !== '0.3.0')
|
|
71
|
+
throw new args_1.CliArgsError('CLI_OPTION_INVALID_VALUE', `unsupported protocol migration target: ${target}`);
|
|
72
|
+
const profile = (0, args_1.getStringOption)(input.args, '--profile');
|
|
73
|
+
if (profile !== undefined && profile !== 'basic' && profile !== 'standard' && profile !== 'governed' && profile !== 'hadara-dev') {
|
|
74
|
+
throw new args_1.CliArgsError('CLI_OPTION_INVALID_VALUE', `unsupported HADARA profile: ${profile}`);
|
|
75
|
+
}
|
|
76
|
+
const report = (0, protocol_migration_1.createProtocolMigrationReport)({
|
|
77
|
+
projectRoot: input.projectRoot,
|
|
78
|
+
target,
|
|
79
|
+
mode: (0, args_1.getFlag)(input.args, '--execute') ? 'execute' : 'dry-run',
|
|
80
|
+
beforeHash: (0, args_1.getStringOption)(input.args, '--before-hash'),
|
|
81
|
+
taskId: (0, args_1.getStringOption)(input.args, '--task'),
|
|
82
|
+
profile
|
|
83
|
+
});
|
|
84
|
+
if (input.jsonOutput) {
|
|
85
|
+
console.log(JSON.stringify(report, null, 2));
|
|
86
|
+
}
|
|
87
|
+
else if (report.ok) {
|
|
88
|
+
console.log(`[HADARA] Protocol migration ${report.mode}: ${target}`);
|
|
89
|
+
for (const action of report.actions) {
|
|
90
|
+
console.log(`- ${action.status}: ${action.summary}${action.path ? ` (${action.path})` : ''}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
console.log(`[HADARA] Protocol migration failed: ${target}`);
|
|
95
|
+
for (const issue of report.issues)
|
|
96
|
+
console.log(`- ${issue.code}: ${issue.message}${issue.path ? ` (${issue.path})` : ''}`);
|
|
97
|
+
}
|
|
98
|
+
if (!report.ok)
|
|
99
|
+
process.exitCode = 6;
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
65
102
|
function handleProtocolRemediateCommand(input) {
|
|
66
103
|
const fix = (0, args_1.getStringOption)(input.args, '--fix');
|
|
67
104
|
if (!fix)
|
package/dist/core/schema.js
CHANGED
|
@@ -37,6 +37,7 @@ const package_smoke_schema_json_1 = __importDefault(require("../schemas/package-
|
|
|
37
37
|
const plan_context_schema_json_1 = __importDefault(require("../schemas/plan-context.schema.json"));
|
|
38
38
|
const private_evidence_schema_json_1 = __importDefault(require("../schemas/private-evidence.schema.json"));
|
|
39
39
|
const protocol_consistency_schema_json_1 = __importDefault(require("../schemas/protocol-consistency.schema.json"));
|
|
40
|
+
const protocol_migration_schema_json_1 = __importDefault(require("../schemas/protocol-migration.schema.json"));
|
|
40
41
|
const protocol_remediation_schema_json_1 = __importDefault(require("../schemas/protocol-remediation.schema.json"));
|
|
41
42
|
const provider_call_schema_json_1 = __importDefault(require("../schemas/provider-call.schema.json"));
|
|
42
43
|
const provider_config_schema_json_1 = __importDefault(require("../schemas/provider-config.schema.json"));
|
|
@@ -101,6 +102,7 @@ const registeredSchemas = {
|
|
|
101
102
|
'hadara.plan_context.v1': plan_context_schema_json_1.default,
|
|
102
103
|
'hadara.privateEvidence.v1': private_evidence_schema_json_1.default,
|
|
103
104
|
'hadara.protocol.consistency.v1': protocol_consistency_schema_json_1.default,
|
|
105
|
+
'hadara.protocol.migration.v1': protocol_migration_schema_json_1.default,
|
|
104
106
|
'hadara.protocol.remediation.v1': protocol_remediation_schema_json_1.default,
|
|
105
107
|
'hadara.provider.call.v1': provider_call_schema_json_1.default,
|
|
106
108
|
'hadara.provider.config.v1': provider_config_schema_json_1.default,
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "hadara.protocol.migration.v1",
|
|
4
|
+
"x-hadara-schema-id": "hadara.protocol.migration.v1",
|
|
5
|
+
"title": "HADARA Protocol Migration Report",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"additionalProperties": true,
|
|
8
|
+
"required": ["schemaVersion", "command", "ok", "mode", "target", "scope", "projectRoot", "detection", "summary", "actions", "issues"],
|
|
9
|
+
"properties": {
|
|
10
|
+
"schemaVersion": { "const": "hadara.protocol.migration.v1" },
|
|
11
|
+
"command": { "const": "protocol.migrate" },
|
|
12
|
+
"ok": { "type": "boolean" },
|
|
13
|
+
"mode": { "type": "string", "enum": ["dry-run", "execute"] },
|
|
14
|
+
"target": {
|
|
15
|
+
"type": "object",
|
|
16
|
+
"additionalProperties": true,
|
|
17
|
+
"required": ["protocolVersion"],
|
|
18
|
+
"properties": {
|
|
19
|
+
"protocolVersion": { "const": "0.3.0" }
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"scope": {
|
|
23
|
+
"type": "object",
|
|
24
|
+
"additionalProperties": true,
|
|
25
|
+
"required": ["kind", "taskId"],
|
|
26
|
+
"properties": {
|
|
27
|
+
"kind": { "type": "string", "enum": ["project", "task"] },
|
|
28
|
+
"taskId": {
|
|
29
|
+
"anyOf": [
|
|
30
|
+
{ "type": "string", "pattern": "^T-[0-9]{4,}$" },
|
|
31
|
+
{ "type": "null" }
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"projectRoot": { "type": "string", "minLength": 1 },
|
|
37
|
+
"detection": {
|
|
38
|
+
"type": "object",
|
|
39
|
+
"additionalProperties": true,
|
|
40
|
+
"required": ["scaffoldGeneration", "profile", "docsRegistryPresent", "docsRegistryValid", "commandSurfaceDocPresent", "requiredReadingManaged", "managedSectionsPresent", "taskCapsulePresent"],
|
|
41
|
+
"properties": {
|
|
42
|
+
"scaffoldGeneration": { "type": "string", "enum": ["pre-0.3", "0.3", "partial-0.3", "unknown"] },
|
|
43
|
+
"profile": { "type": "string", "enum": ["basic", "standard", "governed", "hadara-dev"] },
|
|
44
|
+
"docsRegistryPresent": { "type": "boolean" },
|
|
45
|
+
"docsRegistryValid": { "type": "boolean" },
|
|
46
|
+
"commandSurfaceDocPresent": { "type": "boolean" },
|
|
47
|
+
"requiredReadingManaged": { "type": "boolean" },
|
|
48
|
+
"managedSectionsPresent": { "type": "boolean" },
|
|
49
|
+
"taskCapsulePresent": {
|
|
50
|
+
"anyOf": [
|
|
51
|
+
{ "type": "boolean" },
|
|
52
|
+
{ "type": "null" }
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"summary": {
|
|
58
|
+
"type": "object",
|
|
59
|
+
"additionalProperties": true,
|
|
60
|
+
"required": ["planned", "changed", "skipped", "beforeHash"],
|
|
61
|
+
"properties": {
|
|
62
|
+
"planned": { "type": "integer" },
|
|
63
|
+
"changed": { "type": "integer" },
|
|
64
|
+
"skipped": { "type": "integer" },
|
|
65
|
+
"beforeHash": {
|
|
66
|
+
"anyOf": [
|
|
67
|
+
{ "type": "string", "pattern": "^[a-f0-9]{64}$" },
|
|
68
|
+
{ "type": "null" }
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"actions": {
|
|
74
|
+
"type": "array",
|
|
75
|
+
"items": { "$ref": "#/$defs/action" }
|
|
76
|
+
},
|
|
77
|
+
"issues": {
|
|
78
|
+
"type": "array",
|
|
79
|
+
"items": { "$ref": "#/$defs/issue" }
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
"$defs": {
|
|
83
|
+
"action": {
|
|
84
|
+
"type": "object",
|
|
85
|
+
"additionalProperties": true,
|
|
86
|
+
"required": ["id", "path", "status", "summary"],
|
|
87
|
+
"properties": {
|
|
88
|
+
"id": { "type": "string", "minLength": 1 },
|
|
89
|
+
"path": { "type": "string", "minLength": 1 },
|
|
90
|
+
"status": { "type": "string", "enum": ["planned", "created", "updated", "skipped"] },
|
|
91
|
+
"summary": { "type": "string", "minLength": 1 },
|
|
92
|
+
"before": { "type": "string" },
|
|
93
|
+
"after": { "type": "string" },
|
|
94
|
+
"expectedBeforeExists": { "type": "boolean" },
|
|
95
|
+
"expectedBeforeHash": { "type": "string", "pattern": "^[a-f0-9]{64}$" },
|
|
96
|
+
"afterHash": { "type": "string", "pattern": "^[a-f0-9]{64}$" }
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"issue": {
|
|
100
|
+
"type": "object",
|
|
101
|
+
"additionalProperties": true,
|
|
102
|
+
"required": ["severity", "code", "message"],
|
|
103
|
+
"properties": {
|
|
104
|
+
"severity": { "type": "string", "enum": ["error", "warning", "info"] },
|
|
105
|
+
"code": { "type": "string", "minLength": 1, "pattern": "^[A-Z0-9_:-]+$" },
|
|
106
|
+
"message": { "type": "string", "minLength": 1 },
|
|
107
|
+
"path": { "type": "string", "minLength": 1 }
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
@@ -197,6 +197,13 @@
|
|
|
197
197
|
"owner": "protocol/remediation",
|
|
198
198
|
"notes": "Documents dry-run-first protocol remediation plans, report-level before-hash guards, and bounded execute reports."
|
|
199
199
|
},
|
|
200
|
+
{
|
|
201
|
+
"id": "hadara.protocol.migration.v1",
|
|
202
|
+
"path": "src/schemas/protocol-migration.schema.json",
|
|
203
|
+
"status": "fixture",
|
|
204
|
+
"owner": "protocol/migration",
|
|
205
|
+
"notes": "Documents dry-run-first 0.3 protocol migration plans for existing project and selected Task Capsule scopes."
|
|
206
|
+
},
|
|
200
207
|
{
|
|
201
208
|
"id": "hadara.task.upgrade_scaffold.v1",
|
|
202
209
|
"path": "src/schemas/task-upgrade-scaffold.schema.json",
|
|
@@ -701,6 +701,31 @@ exports.HADARA_COMMAND_REGISTRY = [
|
|
|
701
701
|
related: ['protocol.doctor', 'task.upgrade-scaffold'],
|
|
702
702
|
conflictsWith: []
|
|
703
703
|
}),
|
|
704
|
+
commandEntry({
|
|
705
|
+
id: 'protocol.migrate',
|
|
706
|
+
command: 'hadara protocol migrate --target 0.3.0 [--task <task-id>] [--profile basic|standard|governed|hadara-dev] [--execute --before-hash <hash>] [--json]',
|
|
707
|
+
summary: 'Preview or apply the 0.3 protocol migration for existing HADARA projects or selected Task Capsules.',
|
|
708
|
+
canonical: true,
|
|
709
|
+
appearsInDefaultHelp: false,
|
|
710
|
+
family: 'docs-governance',
|
|
711
|
+
scope: 'project',
|
|
712
|
+
lifecycleStage: 'work',
|
|
713
|
+
requiredness: 'conditional',
|
|
714
|
+
writeBoundary: 'shared-doc-write',
|
|
715
|
+
readOnly: false,
|
|
716
|
+
risk: 'medium',
|
|
717
|
+
actor: 'operator',
|
|
718
|
+
status: 'stable',
|
|
719
|
+
schemaVersion: 'hadara.protocol.migration.v1',
|
|
720
|
+
since: '0.3.0-rc.1',
|
|
721
|
+
docs: ['docs/specs/0.3.0/rc1/00_Protocol_Migration_for_0_3_Adoption.md', 'docs/IMPLEMENTATION_SOP.md'],
|
|
722
|
+
examples: [
|
|
723
|
+
example('Preview project migration', 'hadara protocol migrate --target 0.3.0 --json', 'When upgrading a pre-0.3 initialized HADARA project.'),
|
|
724
|
+
example('Preview task migration', 'hadara protocol migrate --target 0.3.0 --task T-0001 --json', 'When migrating one selected older Task Capsule.')
|
|
725
|
+
],
|
|
726
|
+
related: ['protocol.doctor', 'docs.doctor', 'docs.managed.list', 'init.upgrade'],
|
|
727
|
+
conflictsWith: []
|
|
728
|
+
}),
|
|
704
729
|
commandEntry({
|
|
705
730
|
id: 'docs.list',
|
|
706
731
|
command: 'hadara docs list [--status <status>] [--read-when <read-when>] [--json]',
|
|
@@ -0,0 +1,396 @@
|
|
|
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.createProtocolMigrationReport = createProtocolMigrationReport;
|
|
7
|
+
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
8
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const task_capsule_1 = require("../task/task-capsule");
|
|
11
|
+
const capability_registry_1 = require("./capability-registry");
|
|
12
|
+
const docs_registry_1 = require("./docs-registry");
|
|
13
|
+
const managed_sections_1 = require("./managed-sections");
|
|
14
|
+
function createProtocolMigrationReport(input) {
|
|
15
|
+
const issues = [];
|
|
16
|
+
const actions = [];
|
|
17
|
+
const profile = input.profile ?? detectProfile(input.projectRoot);
|
|
18
|
+
const detection = detectMigrationState(input.projectRoot, profile, input.taskId);
|
|
19
|
+
if (input.taskId) {
|
|
20
|
+
planTaskScopedMigration(input, actions, issues);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
planProjectScopedMigration(input.projectRoot, profile, actions, issues);
|
|
24
|
+
}
|
|
25
|
+
const beforeHash = createPlanHash(actions);
|
|
26
|
+
if (input.mode === 'execute' && beforeHash)
|
|
27
|
+
validateBeforeHash(input.beforeHash, beforeHash, issues);
|
|
28
|
+
if (input.mode === 'execute' && issues.every((issue) => issue.severity !== 'error')) {
|
|
29
|
+
applyMigrationActions(input.projectRoot, actions, issues);
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
schemaVersion: 'hadara.protocol.migration.v1',
|
|
33
|
+
command: 'protocol.migrate',
|
|
34
|
+
ok: issues.every((issue) => issue.severity !== 'error'),
|
|
35
|
+
mode: input.mode,
|
|
36
|
+
target: { protocolVersion: input.target },
|
|
37
|
+
scope: { kind: input.taskId ? 'task' : 'project', taskId: input.taskId ?? null },
|
|
38
|
+
projectRoot: input.projectRoot,
|
|
39
|
+
detection,
|
|
40
|
+
summary: {
|
|
41
|
+
planned: actions.filter((action) => action.status === 'planned').length,
|
|
42
|
+
changed: actions.filter((action) => action.status === 'created' || action.status === 'updated').length,
|
|
43
|
+
skipped: actions.filter((action) => action.status === 'skipped').length,
|
|
44
|
+
beforeHash
|
|
45
|
+
},
|
|
46
|
+
actions,
|
|
47
|
+
issues
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function planProjectScopedMigration(projectRoot, profile, actions, issues) {
|
|
51
|
+
planWrite(projectRoot, actions, 'protocol-version', '.hadara/protocol-version.json', JSON.stringify({
|
|
52
|
+
schemaVersion: 'hadara.protocol.version.v1',
|
|
53
|
+
protocolVersion: '0.3.0',
|
|
54
|
+
source: 'protocol.migrate'
|
|
55
|
+
}, null, 2) + '\n', 'Record the project protocol version marker for 0.3.0 migration.');
|
|
56
|
+
const seed = (0, docs_registry_1.createSeedDocumentRegistry)(profile);
|
|
57
|
+
const registry = mergeExistingRegistry(projectRoot, seed, issues);
|
|
58
|
+
planWrite(projectRoot, actions, 'docs-registry-json', docs_registry_1.DOCS_REGISTRY_PATH, (0, docs_registry_1.registryJson)(registry), 'Insert or update the 0.3 docs registry seed.');
|
|
59
|
+
planWrite(projectRoot, actions, 'doc-registry-markdown', 'docs/DOC_REGISTRY.md', (0, docs_registry_1.renderDocRegistryMarkdown)(registry), 'Create managed docs registry Markdown summary.');
|
|
60
|
+
planWrite(projectRoot, actions, 'command-surface-doc', 'docs/COMMAND_SURFACE.md', renderCommandSurfaceDoc(), 'Create command surface documentation from the command registry.');
|
|
61
|
+
const sopAfterRows = planRequiredReadingRows(projectRoot, actions, issues);
|
|
62
|
+
planSopRequiredReadingMarkers(projectRoot, actions, issues, sopAfterRows);
|
|
63
|
+
}
|
|
64
|
+
function planTaskScopedMigration(input, actions, issues) {
|
|
65
|
+
const task = (0, task_capsule_1.listTaskCapsules)(input.projectRoot).find((candidate) => candidate.id === input.taskId);
|
|
66
|
+
if (!task) {
|
|
67
|
+
issues.push({ severity: 'error', code: 'PROTOCOL_MIGRATION_TASK_NOT_FOUND', message: `Task Capsule not found: ${input.taskId}` });
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const relativeTaskPath = toPortablePath(node_path_1.default.relative(input.projectRoot, task.dir));
|
|
71
|
+
planEnsureMissingFile(input.projectRoot, actions, 'task-evidence-jsonl', `${relativeTaskPath}/evidence.jsonl`, `Create missing evidence JSONL index for ${task.id}.`, `${relativeTaskPath}/evidence.jsonl already exists; protocol migration preserves existing evidence history.`);
|
|
72
|
+
planTaskStatusHistoryMarkers(input.projectRoot, `${relativeTaskPath}/TASK.md`, actions, issues);
|
|
73
|
+
}
|
|
74
|
+
function mergeExistingRegistry(projectRoot, seed, issues) {
|
|
75
|
+
const registryPath = node_path_1.default.join(projectRoot, docs_registry_1.DOCS_REGISTRY_PATH);
|
|
76
|
+
if (!node_fs_1.default.existsSync(registryPath))
|
|
77
|
+
return seed;
|
|
78
|
+
try {
|
|
79
|
+
const existing = JSON.parse(node_fs_1.default.readFileSync(registryPath, 'utf8'));
|
|
80
|
+
const existingPaths = new Set(existing.documents.map((doc) => doc.path));
|
|
81
|
+
const missing = seed.documents.filter((doc) => !existingPaths.has(doc.path));
|
|
82
|
+
return {
|
|
83
|
+
...existing,
|
|
84
|
+
schemaVersion: 'hadara.docs.registry.v1',
|
|
85
|
+
registryVersion: Math.max(existing.registryVersion ?? 1, seed.registryVersion),
|
|
86
|
+
projectProfile: seed.projectProfile,
|
|
87
|
+
documents: [...existing.documents, ...missing]
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
issues.push({
|
|
92
|
+
severity: 'warning',
|
|
93
|
+
code: 'PROTOCOL_MIGRATION_REGISTRY_INVALID_JSON',
|
|
94
|
+
path: docs_registry_1.DOCS_REGISTRY_PATH,
|
|
95
|
+
message: `Existing docs registry could not be parsed and would be replaced by the ${seed.projectProfile} seed: ${error instanceof Error ? error.message : String(error)}`
|
|
96
|
+
});
|
|
97
|
+
return seed;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function planRequiredReadingRows(projectRoot, actions, issues) {
|
|
101
|
+
const relativePath = 'docs/IMPLEMENTATION_SOP.md';
|
|
102
|
+
const current = readIfExists(node_path_1.default.join(projectRoot, relativePath));
|
|
103
|
+
if (!current) {
|
|
104
|
+
actions.push({ id: 'required-reading-cleanup', path: relativePath, status: 'skipped', summary: `${relativePath} is missing; Required Reading cleanup skipped.` });
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
if (!current.includes('| Document | When to Read | Purpose |')) {
|
|
108
|
+
issues.push({ severity: 'warning', code: 'PROTOCOL_MIGRATION_REQUIRED_READING_TABLE_MISSING', path: relativePath, message: 'SOP Required Reading table was not found.' });
|
|
109
|
+
actions.push({ id: 'required-reading-cleanup', path: relativePath, status: 'skipped', summary: `${relativePath} has no canonical Required Reading table.` });
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
let next = current;
|
|
113
|
+
const rows = [
|
|
114
|
+
['`docs/DOC_REGISTRY.md`', 'Docs governance or migration work', 'Readable projection of the 0.3 document registry.'],
|
|
115
|
+
['`docs/COMMAND_SURFACE.md`', 'Command surface, lifecycle, or migration work', 'Registry-backed command portfolio and lifecycle entry points.']
|
|
116
|
+
];
|
|
117
|
+
for (const row of rows) {
|
|
118
|
+
if (!next.includes(row[0]))
|
|
119
|
+
next = insertTableRow(next, '| Document | When to Read | Purpose |', formatTableRow(row));
|
|
120
|
+
}
|
|
121
|
+
if (next === current) {
|
|
122
|
+
actions.push({ id: 'required-reading-cleanup', path: relativePath, status: 'skipped', summary: `${relativePath} already includes 0.3 docs governance rows.` });
|
|
123
|
+
return current;
|
|
124
|
+
}
|
|
125
|
+
addPlannedAction(actions, {
|
|
126
|
+
id: 'required-reading-cleanup',
|
|
127
|
+
path: relativePath,
|
|
128
|
+
before: current,
|
|
129
|
+
after: next,
|
|
130
|
+
expectedBeforeExists: true
|
|
131
|
+
}, 'Add 0.3 docs governance rows to SOP Required Reading.');
|
|
132
|
+
return next;
|
|
133
|
+
}
|
|
134
|
+
function planSopRequiredReadingMarkers(projectRoot, actions, issues, plannedBase) {
|
|
135
|
+
const relativePath = 'docs/IMPLEMENTATION_SOP.md';
|
|
136
|
+
const current = plannedBase ?? readIfExists(node_path_1.default.join(projectRoot, relativePath));
|
|
137
|
+
if (!current || current.includes('hadara:managed:start required-reading')) {
|
|
138
|
+
actions.push({
|
|
139
|
+
id: 'managed-required-reading-marker',
|
|
140
|
+
path: relativePath,
|
|
141
|
+
status: 'skipped',
|
|
142
|
+
summary: current ? `${relativePath} already has a managed Required Reading marker.` : `${relativePath} is missing; managed marker skipped.`
|
|
143
|
+
});
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const replaced = wrapContiguousTable(current, '| Document | When to Read | Purpose |', 'required-reading', {
|
|
147
|
+
schema: 'hadara.managedSection.v1',
|
|
148
|
+
owner: 'protocol.migrate',
|
|
149
|
+
kind: 'markdown-table',
|
|
150
|
+
mode: 'insert-row',
|
|
151
|
+
version: 1,
|
|
152
|
+
required: true,
|
|
153
|
+
closeSourceRole: 'included'
|
|
154
|
+
});
|
|
155
|
+
if (!replaced) {
|
|
156
|
+
issues.push({ severity: 'warning', code: 'PROTOCOL_MIGRATION_MANAGED_MARKER_UNSUPPORTED', path: relativePath, message: 'Could not safely wrap the SOP Required Reading table in managed markers.' });
|
|
157
|
+
actions.push({ id: 'managed-required-reading-marker', path: relativePath, status: 'skipped', summary: `${relativePath} Required Reading table could not be safely wrapped.` });
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
addPlannedAction(actions, {
|
|
161
|
+
id: 'managed-required-reading-marker',
|
|
162
|
+
path: relativePath,
|
|
163
|
+
before: current,
|
|
164
|
+
after: replaced,
|
|
165
|
+
expectedBeforeExists: true
|
|
166
|
+
}, 'Insert managed section markers around SOP Required Reading.');
|
|
167
|
+
}
|
|
168
|
+
function planTaskStatusHistoryMarkers(projectRoot, relativePath, actions, issues) {
|
|
169
|
+
const current = readIfExists(node_path_1.default.join(projectRoot, relativePath));
|
|
170
|
+
if (!current) {
|
|
171
|
+
actions.push({ id: 'task-status-history-marker', path: relativePath, status: 'skipped', summary: `${relativePath} is missing.` });
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
if (current.includes('hadara:managed:start task-status-history')) {
|
|
175
|
+
actions.push({ id: 'task-status-history-marker', path: relativePath, status: 'skipped', summary: `${relativePath} already has managed task status history markers.` });
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
const replaced = wrapContiguousTable(current, '| Time | Status | Reason | Evidence |', 'task-status-history', {
|
|
179
|
+
schema: 'hadara.managedSection.v1',
|
|
180
|
+
owner: 'task.finish',
|
|
181
|
+
kind: 'markdown-table',
|
|
182
|
+
mode: 'update-row',
|
|
183
|
+
version: 1,
|
|
184
|
+
required: true,
|
|
185
|
+
closeSourceRole: 'included'
|
|
186
|
+
});
|
|
187
|
+
if (!replaced) {
|
|
188
|
+
issues.push({ severity: 'warning', code: 'PROTOCOL_MIGRATION_TASK_STATUS_TABLE_MISSING', path: relativePath, message: 'Could not find the Task Status History table to wrap.' });
|
|
189
|
+
actions.push({ id: 'task-status-history-marker', path: relativePath, status: 'skipped', summary: `${relativePath} has no canonical status-history table.` });
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
addPlannedAction(actions, {
|
|
193
|
+
id: 'task-status-history-marker',
|
|
194
|
+
path: relativePath,
|
|
195
|
+
before: current,
|
|
196
|
+
after: replaced,
|
|
197
|
+
expectedBeforeExists: true
|
|
198
|
+
}, 'Insert managed section markers around task status history.');
|
|
199
|
+
}
|
|
200
|
+
function planWrite(projectRoot, actions, id, relativePath, content, summary) {
|
|
201
|
+
const absolutePath = node_path_1.default.join(projectRoot, relativePath);
|
|
202
|
+
const exists = node_fs_1.default.existsSync(absolutePath);
|
|
203
|
+
const current = readIfExists(absolutePath);
|
|
204
|
+
if (exists && current === content) {
|
|
205
|
+
actions.push({ id, path: relativePath, status: 'skipped', summary: `${relativePath} already matches the 0.3 migration output.` });
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
addPlannedAction(actions, {
|
|
209
|
+
id,
|
|
210
|
+
path: relativePath,
|
|
211
|
+
before: current,
|
|
212
|
+
after: content,
|
|
213
|
+
expectedBeforeExists: exists
|
|
214
|
+
}, summary);
|
|
215
|
+
}
|
|
216
|
+
function planEnsureMissingFile(projectRoot, actions, id, relativePath, createSummary, existsSummary) {
|
|
217
|
+
if (node_fs_1.default.existsSync(node_path_1.default.join(projectRoot, relativePath))) {
|
|
218
|
+
actions.push({ id, path: relativePath, status: 'skipped', summary: existsSummary });
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
addPlannedAction(actions, {
|
|
222
|
+
id,
|
|
223
|
+
path: relativePath,
|
|
224
|
+
before: '',
|
|
225
|
+
after: '',
|
|
226
|
+
expectedBeforeExists: false
|
|
227
|
+
}, createSummary);
|
|
228
|
+
}
|
|
229
|
+
function addPlannedAction(actions, write, summary) {
|
|
230
|
+
actions.push({
|
|
231
|
+
id: write.id,
|
|
232
|
+
path: write.path,
|
|
233
|
+
status: 'planned',
|
|
234
|
+
summary,
|
|
235
|
+
before: write.before,
|
|
236
|
+
after: write.after,
|
|
237
|
+
expectedBeforeExists: write.expectedBeforeExists,
|
|
238
|
+
expectedBeforeHash: hashContent(write.before),
|
|
239
|
+
afterHash: hashContent(write.after)
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
function applyMigrationActions(projectRoot, actions, issues) {
|
|
243
|
+
for (const action of actions) {
|
|
244
|
+
if (action.status !== 'planned' || action.after === undefined || action.expectedBeforeHash === undefined)
|
|
245
|
+
continue;
|
|
246
|
+
const absolutePath = node_path_1.default.join(projectRoot, action.path);
|
|
247
|
+
const currentExists = node_fs_1.default.existsSync(absolutePath);
|
|
248
|
+
const current = readIfExists(absolutePath);
|
|
249
|
+
if (currentExists !== (action.expectedBeforeExists ?? false) || hashContent(current) !== action.expectedBeforeHash) {
|
|
250
|
+
action.status = 'skipped';
|
|
251
|
+
issues.push({ severity: 'error', code: 'PROTOCOL_MIGRATION_WRITE_CONFLICT', path: action.path, message: `${action.path} changed after dry-run planning; rerun migration dry-run.` });
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
const tmp = node_path_1.default.join(node_path_1.default.dirname(absolutePath), `.hadara-migrate-${process.pid}-${Date.now()}-${node_path_1.default.basename(absolutePath)}`);
|
|
255
|
+
try {
|
|
256
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(absolutePath), { recursive: true });
|
|
257
|
+
node_fs_1.default.writeFileSync(tmp, action.after, { encoding: 'utf8', flag: 'wx' });
|
|
258
|
+
node_fs_1.default.renameSync(tmp, absolutePath);
|
|
259
|
+
action.status = currentExists ? 'updated' : 'created';
|
|
260
|
+
}
|
|
261
|
+
catch (error) {
|
|
262
|
+
if (node_fs_1.default.existsSync(tmp))
|
|
263
|
+
node_fs_1.default.rmSync(tmp, { force: true });
|
|
264
|
+
action.status = 'skipped';
|
|
265
|
+
issues.push({ severity: 'error', code: 'PROTOCOL_MIGRATION_ATOMIC_WRITE_FAILED', path: action.path, message: `Could not write ${action.path}: ${error instanceof Error ? error.message : String(error)}` });
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
function validateBeforeHash(beforeHash, expected, issues) {
|
|
270
|
+
if (!beforeHash) {
|
|
271
|
+
issues.push({ severity: 'error', code: 'PROTOCOL_MIGRATION_BEFORE_HASH_REQUIRED', message: `Execute mode requires --before-hash ${expected} from the reviewed dry-run report.` });
|
|
272
|
+
}
|
|
273
|
+
else if (beforeHash !== expected) {
|
|
274
|
+
issues.push({ severity: 'error', code: 'PROTOCOL_MIGRATION_BEFORE_HASH_MISMATCH', message: 'The supplied --before-hash does not match the current migration plan; rerun dry-run.' });
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
function detectMigrationState(projectRoot, profile, taskId) {
|
|
278
|
+
const registryPresent = node_fs_1.default.existsSync(node_path_1.default.join(projectRoot, docs_registry_1.DOCS_REGISTRY_PATH));
|
|
279
|
+
const registryValid = registryPresent && canParseJson(node_path_1.default.join(projectRoot, docs_registry_1.DOCS_REGISTRY_PATH));
|
|
280
|
+
const commandSurfaceDocPresent = node_fs_1.default.existsSync(node_path_1.default.join(projectRoot, 'docs/COMMAND_SURFACE.md'));
|
|
281
|
+
const sop = readIfExists(node_path_1.default.join(projectRoot, 'docs/IMPLEMENTATION_SOP.md'));
|
|
282
|
+
const requiredReadingManaged = sop.includes('hadara:managed:start required-reading');
|
|
283
|
+
const managedSectionsPresent = ['docs/TASK_BOARD.md', 'docs/PROJECT_STATE.md', 'docs/AGENT_HANDOFF.md', 'docs/IMPLEMENTATION_SOP.md', 'docs/DOC_REGISTRY.md']
|
|
284
|
+
.some((target) => readIfExists(node_path_1.default.join(projectRoot, target)).includes('hadara:managed:start'));
|
|
285
|
+
const taskCapsulePresent = taskId ? (0, task_capsule_1.listTaskCapsules)(projectRoot).some((candidate) => candidate.id === taskId) : null;
|
|
286
|
+
const migratedSignals = [registryPresent, registryValid, commandSurfaceDocPresent, requiredReadingManaged, managedSectionsPresent].filter(Boolean).length;
|
|
287
|
+
const scaffoldGeneration = migratedSignals >= 4 ? '0.3' : migratedSignals > 0 ? 'partial-0.3' : node_fs_1.default.existsSync(node_path_1.default.join(projectRoot, 'AGENTS.md')) ? 'pre-0.3' : 'unknown';
|
|
288
|
+
return {
|
|
289
|
+
scaffoldGeneration,
|
|
290
|
+
profile,
|
|
291
|
+
docsRegistryPresent: registryPresent,
|
|
292
|
+
docsRegistryValid: registryValid,
|
|
293
|
+
commandSurfaceDocPresent,
|
|
294
|
+
requiredReadingManaged,
|
|
295
|
+
managedSectionsPresent,
|
|
296
|
+
taskCapsulePresent
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
function detectProfile(projectRoot) {
|
|
300
|
+
const state = readIfExists(node_path_1.default.join(projectRoot, 'docs/PROJECT_STATE.md'));
|
|
301
|
+
const declared = state.match(/\|\s*HADARA Profile\s*\|\s*(basic|standard|governed|hadara-dev)\s*\|/)?.[1];
|
|
302
|
+
if (declared === 'basic' || declared === 'standard' || declared === 'governed' || declared === 'hadara-dev')
|
|
303
|
+
return declared;
|
|
304
|
+
if (node_fs_1.default.existsSync(node_path_1.default.join(projectRoot, 'docs/SECURITY_MODEL.md')))
|
|
305
|
+
return 'governed';
|
|
306
|
+
if (node_fs_1.default.existsSync(node_path_1.default.join(projectRoot, 'docs/ARCHITECTURE.md')))
|
|
307
|
+
return 'standard';
|
|
308
|
+
return 'basic';
|
|
309
|
+
}
|
|
310
|
+
function renderCommandSurfaceDoc() {
|
|
311
|
+
const rows = capability_registry_1.HADARA_COMMAND_REGISTRY
|
|
312
|
+
.filter((entry) => entry.canonical && entry.status === 'stable')
|
|
313
|
+
.map((entry) => formatTableRow([
|
|
314
|
+
`\`${entry.id}\``,
|
|
315
|
+
`\`${entry.command.replace(/\|/g, '/')}\``,
|
|
316
|
+
entry.family,
|
|
317
|
+
entry.requiredness,
|
|
318
|
+
entry.writeBoundary
|
|
319
|
+
]));
|
|
320
|
+
const table = ['| ID | Command | Family | Requiredness | Write Boundary |', '|---|---|---|---|---|', ...rows].join('\n');
|
|
321
|
+
return [
|
|
322
|
+
'# COMMAND_SURFACE',
|
|
323
|
+
'',
|
|
324
|
+
'This document is generated from the HADARA command registry by `hadara protocol migrate`.',
|
|
325
|
+
'',
|
|
326
|
+
(0, managed_sections_1.managedSectionBlock)('command-surface-registry', {
|
|
327
|
+
schema: 'hadara.managedSection.v1',
|
|
328
|
+
owner: 'protocol.migrate',
|
|
329
|
+
kind: 'markdown-table',
|
|
330
|
+
mode: 'replace',
|
|
331
|
+
version: 1,
|
|
332
|
+
required: true,
|
|
333
|
+
closeSourceRole: 'included'
|
|
334
|
+
}, table),
|
|
335
|
+
''
|
|
336
|
+
].join('\n');
|
|
337
|
+
}
|
|
338
|
+
function wrapContiguousTable(content, header, sectionId, metadata) {
|
|
339
|
+
const lines = content.split('\n');
|
|
340
|
+
const start = lines.findIndex((line) => line.trim() === header);
|
|
341
|
+
if (start < 0)
|
|
342
|
+
return null;
|
|
343
|
+
let end = start;
|
|
344
|
+
while (end < lines.length && lines[end].startsWith('|'))
|
|
345
|
+
end += 1;
|
|
346
|
+
const body = lines.slice(start, end).join('\n');
|
|
347
|
+
const block = (0, managed_sections_1.managedSectionBlock)(sectionId, metadata, body);
|
|
348
|
+
lines.splice(start, end - start, ...block.split('\n'));
|
|
349
|
+
return lines.join('\n');
|
|
350
|
+
}
|
|
351
|
+
function insertTableRow(content, header, row) {
|
|
352
|
+
const lines = content.split('\n');
|
|
353
|
+
const headerIndex = lines.findIndex((line) => line.trim() === header);
|
|
354
|
+
if (headerIndex < 0)
|
|
355
|
+
return content;
|
|
356
|
+
let insertAt = headerIndex + 2;
|
|
357
|
+
while (insertAt < lines.length && lines[insertAt].startsWith('|'))
|
|
358
|
+
insertAt += 1;
|
|
359
|
+
lines.splice(insertAt, 0, row);
|
|
360
|
+
return lines.join('\n');
|
|
361
|
+
}
|
|
362
|
+
function formatTableRow(cells) {
|
|
363
|
+
return `| ${cells.map((cell) => cell.replace(/\|/g, '/')).join(' | ')} |`;
|
|
364
|
+
}
|
|
365
|
+
function createPlanHash(actions) {
|
|
366
|
+
const planned = actions
|
|
367
|
+
.filter((action) => action.status === 'planned')
|
|
368
|
+
.map((action) => ({
|
|
369
|
+
id: action.id,
|
|
370
|
+
path: action.path,
|
|
371
|
+
expectedBeforeExists: action.expectedBeforeExists ?? null,
|
|
372
|
+
expectedBeforeHash: action.expectedBeforeHash ?? null,
|
|
373
|
+
afterHash: action.afterHash ?? null
|
|
374
|
+
}));
|
|
375
|
+
if (planned.length === 0)
|
|
376
|
+
return null;
|
|
377
|
+
return hashContent(JSON.stringify(planned));
|
|
378
|
+
}
|
|
379
|
+
function hashContent(content) {
|
|
380
|
+
return node_crypto_1.default.createHash('sha256').update(content).digest('hex');
|
|
381
|
+
}
|
|
382
|
+
function readIfExists(absolutePath) {
|
|
383
|
+
return node_fs_1.default.existsSync(absolutePath) ? node_fs_1.default.readFileSync(absolutePath, 'utf8') : '';
|
|
384
|
+
}
|
|
385
|
+
function canParseJson(absolutePath) {
|
|
386
|
+
try {
|
|
387
|
+
JSON.parse(node_fs_1.default.readFileSync(absolutePath, 'utf8'));
|
|
388
|
+
return true;
|
|
389
|
+
}
|
|
390
|
+
catch {
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
function toPortablePath(value) {
|
|
395
|
+
return value.replace(/\\/g, '/');
|
|
396
|
+
}
|
|
@@ -30,11 +30,11 @@ const RELEASE_PACKAGE_KEYWORDS = [
|
|
|
30
30
|
];
|
|
31
31
|
const RELEASE_PACKAGE_REPOSITORY = {
|
|
32
32
|
type: 'git',
|
|
33
|
-
url: 'git+https://github.com/ictseoyoungmin/HADARA
|
|
33
|
+
url: 'git+https://github.com/ictseoyoungmin/HADARA.git'
|
|
34
34
|
};
|
|
35
|
-
const RELEASE_PACKAGE_HOMEPAGE = 'https://github.com/ictseoyoungmin/HADARA
|
|
35
|
+
const RELEASE_PACKAGE_HOMEPAGE = 'https://github.com/ictseoyoungmin/HADARA#readme';
|
|
36
36
|
const RELEASE_PACKAGE_BUGS = {
|
|
37
|
-
url: 'https://github.com/ictseoyoungmin/HADARA
|
|
37
|
+
url: 'https://github.com/ictseoyoungmin/HADARA/issues'
|
|
38
38
|
};
|
|
39
39
|
const requiredFiles = ['package.json', 'README.md', 'LICENSE', 'dist/cli/main.js'];
|
|
40
40
|
const allowedRoots = ['dist/', 'README.md', 'LICENSE', 'package.json'];
|
package/dist/task/task-finish.js
CHANGED
|
@@ -418,6 +418,13 @@ function appendStatusHistoryDone(content) {
|
|
|
418
418
|
const prefix = content.slice(0, start);
|
|
419
419
|
const suffix = content.slice(end);
|
|
420
420
|
const row = `| ${new Date().toISOString().slice(0, 10)} | Done | Finished task capsule. | \`hadara task finish --execute\` |`;
|
|
421
|
+
const managedEnd = '<!-- hadara:managed:end task-status-history -->';
|
|
422
|
+
const managedEndIndex = section.indexOf(managedEnd);
|
|
423
|
+
if (managedEndIndex >= 0) {
|
|
424
|
+
const beforeMarker = section.slice(0, managedEndIndex).replace(/[ \t\r\n]+$/, '');
|
|
425
|
+
const afterMarker = section.slice(managedEndIndex);
|
|
426
|
+
return `${prefix}${beforeMarker}\n${row}\n${afterMarker}${suffix}`;
|
|
427
|
+
}
|
|
421
428
|
const separator = section.endsWith('\n') ? '' : '\n';
|
|
422
429
|
return `${prefix}${section}${separator}${row}\n${suffix}`;
|
|
423
430
|
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,33 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hadara",
|
|
3
|
-
"version": "0.3.0-rc.
|
|
3
|
+
"version": "0.3.0-rc.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"description": "
|
|
6
|
+
"description": "Portable AI-assisted development workbench for evidence-backed task capsules, handoffs, and release gates.",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"ai",
|
|
9
|
+
"agent",
|
|
10
|
+
"agents",
|
|
11
|
+
"coding-agent",
|
|
12
|
+
"developer-tools",
|
|
13
|
+
"cli",
|
|
14
|
+
"workflow",
|
|
15
|
+
"automation",
|
|
16
|
+
"task-management",
|
|
17
|
+
"evidence",
|
|
18
|
+
"handoff",
|
|
19
|
+
"release-management",
|
|
20
|
+
"mcp",
|
|
21
|
+
"hadara"
|
|
22
|
+
],
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/ictseoyoungmin/HADARA.git"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://github.com/ictseoyoungmin/HADARA#readme",
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/ictseoyoungmin/HADARA/issues"
|
|
30
|
+
},
|
|
7
31
|
"bin": {
|
|
8
32
|
"hadara": "./dist/cli/main.js"
|
|
9
33
|
},
|