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,191 @@
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.handleRunCommand = handleRunCommand;
7
+ exports.attachRunEvidence = attachRunEvidence;
8
+ exports.readScriptedProviderSteps = readScriptedProviderSteps;
9
+ exports.readFakeShellFixtures = readFakeShellFixtures;
10
+ exports.parseRunMaxSteps = parseRunMaxSteps;
11
+ const node_fs_1 = __importDefault(require("node:fs"));
12
+ const workspace_1 = require("../core/workspace");
13
+ const policy_1 = require("../policy/policy");
14
+ const evidence_1 = require("../agent/evidence");
15
+ const loop_1 = require("../agent/loop");
16
+ const scripted_provider_1 = require("../providers/scripted-provider");
17
+ const run_scaffold_1 = require("./run-scaffold");
18
+ const args_1 = require("./args");
19
+ async function handleRunCommand(input) {
20
+ const sub = input.args[1];
21
+ if (sub === 'scaffold') {
22
+ const report = (0, run_scaffold_1.scaffoldRunScenario)(input.projectRoot, {
23
+ taskId: (0, args_1.getRequiredStringOption)(input.args, '--task'),
24
+ command: (0, args_1.getRequiredStringOption)(input.args, '--command'),
25
+ stdout: (0, args_1.getStringOption)(input.args, '--stdout', 'scaffolded fake-shell output') ?? 'scaffolded fake-shell output',
26
+ stderr: (0, args_1.getStringOption)(input.args, '--stderr', '') ?? '',
27
+ exitCode: (0, args_1.getIntegerOption)(input.args, '--exit-code', { fallback: 0, min: 0, max: 255 }) ?? 0
28
+ });
29
+ if (input.jsonOutput) {
30
+ console.log(JSON.stringify(report, null, 2));
31
+ }
32
+ else {
33
+ console.log(`[HADARA] Run scenario scaffolded: ${report.scriptPath}`);
34
+ console.log(`[HADARA] Fake shell fixtures: ${report.fixturesPath}`);
35
+ }
36
+ return true;
37
+ }
38
+ const taskId = (0, args_1.getStringOption)(input.args, '--task');
39
+ const mode = (0, policy_1.parsePermissionMode)((0, args_1.getStringOption)(input.args, '--mode', 'assisted') ?? 'assisted');
40
+ const request = extractRunRequest(input.args) || (taskId ? `Run task ${taskId}` : 'Run HADARA deterministic harness task.');
41
+ let result;
42
+ try {
43
+ const scriptPath = (0, args_1.getRequiredStringOption)(input.args, '--script');
44
+ const maxSteps = parseRunMaxSteps(input.args);
45
+ const fixturesPath = (0, args_1.getStringOption)(input.args, '--fake-shell-fixtures');
46
+ const script = readScriptedProviderSteps(input.projectRoot, scriptPath);
47
+ const fakeShellFixtures = fixturesPath ? readFakeShellFixtures(input.projectRoot, fixturesPath) : {};
48
+ result = await (0, loop_1.runAgentLoop)({
49
+ taskId,
50
+ request,
51
+ provider: new scripted_provider_1.ScriptedProvider(script),
52
+ mode,
53
+ maxSteps,
54
+ fakeShellFixtures
55
+ });
56
+ }
57
+ catch (error) {
58
+ if (!input.jsonOutput)
59
+ throw error;
60
+ result = createRunErrorReport({ taskId, request, mode, error });
61
+ }
62
+ result = attachRunEvidence(input.projectRoot, result);
63
+ if (input.jsonOutput) {
64
+ console.log(JSON.stringify(result, null, 2));
65
+ }
66
+ else if (result.ok) {
67
+ console.log(`[HADARA] Agent loop passed: ${result.finalResponse ?? ''}`);
68
+ }
69
+ else {
70
+ console.log('[HADARA] Agent loop failed.');
71
+ for (const issue of result.issues) {
72
+ console.log(`- ${issue.code}: ${issue.message}${issue.step ? ` (step ${issue.step})` : ''}`);
73
+ }
74
+ }
75
+ if (!result.ok)
76
+ process.exitCode = 6;
77
+ return true;
78
+ }
79
+ function attachRunEvidence(projectRoot, result) {
80
+ try {
81
+ const evidence = (0, evidence_1.attachAgentLoopEvidence)(projectRoot, result);
82
+ if (evidence.length === 0)
83
+ return result;
84
+ return {
85
+ ...result,
86
+ evidence: [...(result.evidence ?? []), ...evidence]
87
+ };
88
+ }
89
+ catch (error) {
90
+ return {
91
+ ...result,
92
+ ok: false,
93
+ issues: [
94
+ ...result.issues,
95
+ {
96
+ severity: 'error',
97
+ code: 'AGENT_LOOP_EVIDENCE_FAILED',
98
+ message: error instanceof Error ? error.message : String(error)
99
+ }
100
+ ]
101
+ };
102
+ }
103
+ }
104
+ function extractRunRequest(args) {
105
+ const optionsWithValues = new Set(['--project', '--task', '--script', '--fake-shell-fixtures', '--mode', '--max-steps']);
106
+ const requestParts = [];
107
+ for (let index = 1; index < args.length; index += 1) {
108
+ const value = args[index];
109
+ if (value === '--json')
110
+ continue;
111
+ if (optionsWithValues.has(value)) {
112
+ index += 1;
113
+ continue;
114
+ }
115
+ if (value.startsWith('--'))
116
+ continue;
117
+ requestParts.push(value);
118
+ }
119
+ return requestParts.join(' ').trim();
120
+ }
121
+ function readScriptedProviderSteps(projectRoot, scriptPath) {
122
+ const parsed = readJsonFile(projectRoot, scriptPath);
123
+ if (!Array.isArray(parsed))
124
+ throw new Error('run --script must point to a JSON array');
125
+ return parsed.map((item, index) => {
126
+ if (!item || typeof item !== 'object') {
127
+ throw new Error(`run --script item ${index + 1} must be an object`);
128
+ }
129
+ const record = item;
130
+ if (typeof record.response !== 'string') {
131
+ throw new Error(`run --script item ${index + 1} requires a string response`);
132
+ }
133
+ return {
134
+ response: record.response,
135
+ ...(typeof record.match === 'string' ? { match: record.match } : {}),
136
+ ...(isScriptedFinishReason(record.finishReason) ? { finishReason: record.finishReason } : {})
137
+ };
138
+ });
139
+ }
140
+ function readFakeShellFixtures(projectRoot, fixturesPath) {
141
+ const parsed = readJsonFile(projectRoot, fixturesPath);
142
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
143
+ throw new Error('run --fake-shell-fixtures must point to a JSON object');
144
+ }
145
+ const fixtures = {};
146
+ for (const [command, value] of Object.entries(parsed)) {
147
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
148
+ throw new Error(`fake shell fixture for ${command} must be an object`);
149
+ }
150
+ const record = value;
151
+ if (typeof record.exitCode !== 'number') {
152
+ throw new Error(`fake shell fixture for ${command} requires numeric exitCode`);
153
+ }
154
+ fixtures[command] = {
155
+ exitCode: record.exitCode,
156
+ ...(typeof record.stdout === 'string' ? { stdout: record.stdout } : {}),
157
+ ...(typeof record.stderr === 'string' ? { stderr: record.stderr } : {})
158
+ };
159
+ }
160
+ return fixtures;
161
+ }
162
+ function readJsonFile(projectRoot, filePath) {
163
+ const resolvedFile = (0, workspace_1.resolveProjectFile)(projectRoot, filePath);
164
+ return JSON.parse(node_fs_1.default.readFileSync(resolvedFile.absolutePath, 'utf8'));
165
+ }
166
+ function parseRunMaxSteps(args) {
167
+ return (0, args_1.getIntegerOption)(args, '--max-steps', { fallback: 6, min: 1, max: 32 }) ?? 6;
168
+ }
169
+ function createRunErrorReport(input) {
170
+ const code = input.error instanceof workspace_1.WorkspaceFileError ? input.error.code : 'RUN_INPUT_INVALID';
171
+ const message = input.error instanceof Error ? input.error.message : String(input.error);
172
+ return {
173
+ schemaVersion: 'hadara.agent.loop.v1',
174
+ command: 'agent.loop',
175
+ ok: false,
176
+ ...(input.taskId ? { taskId: input.taskId } : {}),
177
+ mode: input.mode,
178
+ request: input.request,
179
+ steps: [],
180
+ issues: [
181
+ {
182
+ severity: 'error',
183
+ code,
184
+ message
185
+ }
186
+ ]
187
+ };
188
+ }
189
+ function isScriptedFinishReason(value) {
190
+ return value === 'stop' || value === 'length' || value === 'tool_call' || value === 'error';
191
+ }
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleSmokeCommand = handleSmokeCommand;
4
+ const clean_checkout_smoke_1 = require("../services/clean-checkout-smoke");
5
+ const feature_smoke_1 = require("../services/feature-smoke");
6
+ const args_1 = require("./args");
7
+ function handleSmokeCommand(input) {
8
+ if (input.args[0] !== 'smoke')
9
+ return false;
10
+ if (input.args[1] === 'clean-checkout') {
11
+ const report = (0, clean_checkout_smoke_1.createCleanCheckoutSmokeReport)({
12
+ paths: input.paths,
13
+ execute: (0, args_1.getFlag)(input.args, '--execute'),
14
+ workspace: (0, args_1.getStringOption)(input.args, '--workspace'),
15
+ keepTemp: (0, args_1.getFlag)(input.args, '--keep-temp'),
16
+ taskId: (0, args_1.getStringOption)(input.args, '--task'),
17
+ attachEvidence: (0, args_1.getFlag)(input.args, '--attach-evidence'),
18
+ noEvidence: (0, args_1.getFlag)(input.args, '--no-evidence'),
19
+ timeoutSeconds: (0, args_1.getIntegerOption)(input.args, '--timeout', { min: 1 })
20
+ });
21
+ if (input.jsonOutput) {
22
+ console.log(JSON.stringify(report, null, 2));
23
+ }
24
+ else {
25
+ console.log(`${report.ok ? 'passed' : 'failed'} | smoke clean-checkout | ${report.mode}`);
26
+ for (const step of report.steps) {
27
+ console.log(`${step.status} | ${step.command} | ${step.summary}`);
28
+ }
29
+ for (const issue of report.issues) {
30
+ console.log(`${issue.severity} | ${issue.code} | ${issue.message}`);
31
+ }
32
+ }
33
+ if (!report.ok)
34
+ process.exitCode = 6;
35
+ return true;
36
+ }
37
+ if (input.args[1] !== 'run')
38
+ return false;
39
+ const report = (0, feature_smoke_1.createFeatureSmokeReport)({
40
+ profile: (0, args_1.getStringOption)(input.args, '--profile', 'core'),
41
+ paths: input.paths
42
+ });
43
+ if (input.jsonOutput) {
44
+ console.log(JSON.stringify(report, null, 2));
45
+ }
46
+ else {
47
+ console.log(`${report.ok ? 'passed' : 'failed'} | smoke run | profile ${report.profile}`);
48
+ for (const step of report.steps) {
49
+ console.log(`${step.status} | ${step.command} | ${step.summary}`);
50
+ }
51
+ for (const issue of report.issues) {
52
+ console.log(`${issue.severity} | ${issue.code} | ${issue.message}`);
53
+ }
54
+ }
55
+ if (!report.ok)
56
+ process.exitCode = 6;
57
+ return true;
58
+ }
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatOpsStatusReport = exports.createOpsStatusReport = void 0;
4
+ var operations_status_service_1 = require("../services/operations-status-service");
5
+ Object.defineProperty(exports, "createOpsStatusReport", { enumerable: true, get: function () { return operations_status_service_1.createOpsStatusReport; } });
6
+ Object.defineProperty(exports, "formatOpsStatusReport", { enumerable: true, get: function () { return operations_status_service_1.formatOpsStatusReport; } });
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleStatusCommand = handleStatusCommand;
4
+ exports.handleOpsCommand = handleOpsCommand;
5
+ const operations_status_service_1 = require("../services/operations-status-service");
6
+ function handleStatusCommand(input) {
7
+ if (input.args[0] !== 'status')
8
+ return false;
9
+ printStatus(input.projectRoot, input.jsonOutput);
10
+ return true;
11
+ }
12
+ function handleOpsCommand(input) {
13
+ if (input.args[0] !== 'ops' || input.args[1] !== 'status')
14
+ return false;
15
+ printStatus(input.projectRoot, input.jsonOutput);
16
+ return true;
17
+ }
18
+ function printStatus(projectRoot, jsonOutput) {
19
+ const report = (0, operations_status_service_1.createOpsStatusReport)(projectRoot);
20
+ if (jsonOutput) {
21
+ console.log(JSON.stringify(report, null, 2));
22
+ }
23
+ else {
24
+ console.log((0, operations_status_service_1.formatOpsStatusReport)(report));
25
+ }
26
+ }
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatTaskListReport = exports.createTaskShowReport = exports.createTaskReadReport = exports.createTaskListReport = void 0;
4
+ var task_read_model_1 = require("../services/task-read-model");
5
+ Object.defineProperty(exports, "createTaskListReport", { enumerable: true, get: function () { return task_read_model_1.createTaskListReport; } });
6
+ Object.defineProperty(exports, "createTaskReadReport", { enumerable: true, get: function () { return task_read_model_1.createTaskReadReport; } });
7
+ Object.defineProperty(exports, "createTaskShowReport", { enumerable: true, get: function () { return task_read_model_1.createTaskShowReport; } });
8
+ Object.defineProperty(exports, "formatTaskListReport", { enumerable: true, get: function () { return task_read_model_1.formatTaskListReport; } });
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleTaskCommand = handleTaskCommand;
4
+ exports.extractTaskCreateTitle = extractTaskCreateTitle;
5
+ const task_capsule_1 = require("../task/task-capsule");
6
+ const task_json_1 = require("./task-json");
7
+ function handleTaskCommand(input) {
8
+ const sub = input.args[1];
9
+ if (sub === 'create') {
10
+ const title = extractTaskCreateTitle(input.args);
11
+ if (!title)
12
+ throw new Error('task create requires a title');
13
+ const task = (0, task_capsule_1.createTaskCapsule)(input.projectRoot, title);
14
+ console.log(`[HADARA] Created ${task.id}: ${task.title}`);
15
+ console.log(task.dir);
16
+ return true;
17
+ }
18
+ if (sub === 'list') {
19
+ const report = (0, task_json_1.createTaskListReport)(input.projectRoot);
20
+ if (input.jsonOutput) {
21
+ console.log(JSON.stringify(report, null, 2));
22
+ }
23
+ else {
24
+ console.log((0, task_json_1.formatTaskListReport)(report));
25
+ }
26
+ return true;
27
+ }
28
+ if (sub === 'show') {
29
+ const id = input.args[2];
30
+ if (!id)
31
+ throw new Error('task show requires <task-id>');
32
+ const report = (0, task_json_1.createTaskShowReport)(input.projectRoot, id);
33
+ if (input.jsonOutput) {
34
+ console.log(JSON.stringify(report, null, 2));
35
+ }
36
+ else if (report.ok && report.task) {
37
+ console.log(report.task.taskMarkdown);
38
+ }
39
+ else {
40
+ console.log(`[HADARA] Task not found: ${id}`);
41
+ }
42
+ if (!report.ok)
43
+ process.exitCode = 6;
44
+ return true;
45
+ }
46
+ return false;
47
+ }
48
+ function extractTaskCreateTitle(args) {
49
+ const optionsWithValues = new Set(['--project']);
50
+ const titleParts = [];
51
+ for (let index = 2; index < args.length; index += 1) {
52
+ const value = args[index];
53
+ if (value === '--json')
54
+ continue;
55
+ if (optionsWithValues.has(value)) {
56
+ index += 1;
57
+ continue;
58
+ }
59
+ if (value.startsWith('--'))
60
+ continue;
61
+ titleParts.push(value);
62
+ }
63
+ return titleParts.join(' ').trim();
64
+ }
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleToolsCommand = handleToolsCommand;
4
+ const tools_list_1 = require("../services/tools-list");
5
+ function handleToolsCommand(input) {
6
+ const sub = input.args[1];
7
+ if (sub !== 'list')
8
+ return false;
9
+ const report = (0, tools_list_1.createToolsListReport)();
10
+ if (input.jsonOutput) {
11
+ console.log(JSON.stringify(report, null, 2));
12
+ }
13
+ else {
14
+ for (const surface of report.surfaces.cli) {
15
+ console.log(`cli | ${surface.category} | ${surface.readOnly ? 'read-only' : 'writes-or-executes'} | ${surface.name}`);
16
+ }
17
+ for (const surface of report.surfaces.mcp) {
18
+ console.log(`mcp | ${surface.category} | ${surface.readOnly ? 'read-only' : 'writes'} | ${surface.name}`);
19
+ }
20
+ for (const disabled of report.disabled) {
21
+ console.log(`disabled | ${disabled.category} | ${disabled.name} | ${disabled.reason}`);
22
+ }
23
+ }
24
+ return true;
25
+ }
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleTuiCommand = handleTuiCommand;
4
+ const args_1 = require("./args");
5
+ const read_model_1 = require("../tui/read-model");
6
+ const snapshot_1 = require("../tui/snapshot");
7
+ const terminal_1 = require("../tui/terminal");
8
+ const theme_1 = require("../tui/theme");
9
+ function handleTuiCommand(input) {
10
+ if (input.args[0] !== 'tui')
11
+ return false;
12
+ const sub = input.args[1];
13
+ if (sub && sub !== '--snapshot' && sub !== '--compact' && sub !== '--json' && sub !== '--cache' && sub !== '--no-cache' && !sub.startsWith('--'))
14
+ return false;
15
+ const widthPolicy = (0, args_1.getFlag)(input.args, '--compact') ? 'compact' : undefined;
16
+ const width = (0, args_1.getIntegerOption)(input.args, '--width', { min: 20, max: 300 });
17
+ const height = (0, args_1.getIntegerOption)(input.args, '--height', { min: 10, max: 120 });
18
+ const cacheEnabled = (0, args_1.getFlag)(input.args, '--cache') && !(0, args_1.getFlag)(input.args, '--no-cache');
19
+ const theme = (0, args_1.getFlag)(input.args, '--no-color') ? 'none' : (0, theme_1.normalizeTuiThemeName)((0, args_1.getStringOption)(input.args, '--theme'), 'hadara');
20
+ const output = input.output ?? process.stdout;
21
+ const terminalInput = input.input ?? process.stdin;
22
+ if ((0, args_1.getFlag)(input.args, '--snapshot')) {
23
+ const snapshot = (0, snapshot_1.renderTuiSnapshot)((0, read_model_1.createTuiReadModel)(input.projectRoot), { width, height, widthPolicy, theme: (0, args_1.getFlag)(input.args, '--color') ? theme : 'none' });
24
+ if (input.jsonOutput) {
25
+ output.write(`${JSON.stringify({ schemaVersion: 'hadara.tui.snapshot.cli.v1', command: 'tui.snapshot', ok: true, text: snapshot.text }, null, 2)}\n`);
26
+ }
27
+ else {
28
+ output.write(snapshot.text);
29
+ }
30
+ return true;
31
+ }
32
+ if (!terminalInput.isTTY) {
33
+ if (input.jsonOutput) {
34
+ output.write(`${JSON.stringify(createTuiCliError('TUI_REQUIRES_TTY', 'TUI requires an interactive terminal. Use hadara tui --snapshot.'), null, 2)}\n`);
35
+ }
36
+ else {
37
+ output.write('[HADARA] TUI requires an interactive terminal. Use hadara tui --snapshot for a read-only smoke render.\n');
38
+ }
39
+ process.exitCode = 1;
40
+ return true;
41
+ }
42
+ let cleanup = () => undefined;
43
+ const session = (0, terminal_1.createTuiTerminalSession)({
44
+ projectRoot: input.projectRoot,
45
+ input: terminalInput,
46
+ output,
47
+ width,
48
+ height,
49
+ widthPolicy,
50
+ theme,
51
+ cache: { enabled: cacheEnabled },
52
+ asyncLoading: input.input ? false : true,
53
+ onStop: () => cleanup()
54
+ });
55
+ cleanup = () => {
56
+ process.off('SIGINT', cleanup);
57
+ process.off('exit', cleanup);
58
+ session.stop();
59
+ };
60
+ process.once('SIGINT', cleanup);
61
+ process.once('exit', cleanup);
62
+ session.start();
63
+ return true;
64
+ }
65
+ function createTuiCliError(code, message) {
66
+ return {
67
+ schemaVersion: 'hadara.tui.cli.error.v1',
68
+ command: 'tui',
69
+ ok: false,
70
+ issues: [{ severity: 'error', code, message }]
71
+ };
72
+ }
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleWriteCommand = handleWriteCommand;
4
+ const write_preflight_1 = require("../services/write-preflight");
5
+ function handleWriteCommand(input) {
6
+ if (input.args[0] !== 'write')
7
+ return false;
8
+ const sub = input.args[1];
9
+ if (sub !== 'preflight')
10
+ return false;
11
+ const report = (0, write_preflight_1.createWritePreflightReport)(input.projectRoot, input.args.slice(2));
12
+ if (input.jsonOutput) {
13
+ console.log(JSON.stringify(report, null, 2));
14
+ }
15
+ else {
16
+ console.log(`[HADARA] Write preflight for ${report.command}: ${report.ok ? 'ok' : 'not ok'}`);
17
+ for (const writePath of report.writes) {
18
+ console.log(`- ${writePath}`);
19
+ }
20
+ for (const issue of report.issues) {
21
+ console.log(`[${issue.severity}] ${issue.code}: ${issue.message}`);
22
+ }
23
+ }
24
+ if (!report.ok)
25
+ process.exitCode = 6;
26
+ return true;
27
+ }
@@ -0,0 +1,41 @@
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.writeAuditEvent = writeAuditEvent;
7
+ const node_path_1 = __importDefault(require("node:path"));
8
+ const fs_1 = require("./fs");
9
+ const redaction_1 = require("./redaction");
10
+ const events_1 = require("./events");
11
+ function writeAuditEvent(auditDir, event) {
12
+ (0, fs_1.ensureDir)(auditDir);
13
+ const day = new Date().toISOString().slice(0, 10);
14
+ const filePath = node_path_1.default.join(auditDir, `${day}.jsonl`);
15
+ const time = new Date().toISOString();
16
+ const structuredEvent = (0, events_1.createHadaraEvent)({
17
+ time,
18
+ level: auditRiskToEventLevel(event.risk),
19
+ actor: event.actor,
20
+ eventType: event.event_type,
21
+ taskId: event.task_id,
22
+ summary: event.summary,
23
+ payload: event.payload
24
+ });
25
+ const sanitized = {
26
+ time,
27
+ ...event,
28
+ summary: (0, redaction_1.redactSecrets)(event.summary),
29
+ payload: structuredEvent.payload,
30
+ event: structuredEvent
31
+ };
32
+ (0, fs_1.writeJsonl)(filePath, sanitized);
33
+ return filePath;
34
+ }
35
+ function auditRiskToEventLevel(risk) {
36
+ if (risk === 'blocked')
37
+ return 'error';
38
+ if (risk === 'high')
39
+ return 'warn';
40
+ return 'info';
41
+ }
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HadaraEventSchemaError = void 0;
4
+ exports.createHadaraEvent = createHadaraEvent;
5
+ exports.assertHadaraEventSchema = assertHadaraEventSchema;
6
+ exports.serializeHadaraEvent = serializeHadaraEvent;
7
+ exports.sanitizePayload = sanitizePayload;
8
+ const redaction_1 = require("./redaction");
9
+ const schema_1 = require("./schema");
10
+ class HadaraEventSchemaError extends Error {
11
+ constructor(message) {
12
+ super(message);
13
+ this.name = 'HadaraEventSchemaError';
14
+ }
15
+ }
16
+ exports.HadaraEventSchemaError = HadaraEventSchemaError;
17
+ function createHadaraEvent(input, options = {}) {
18
+ const event = {
19
+ schemaVersion: 'hadara.event.v1',
20
+ time: input.time ?? new Date().toISOString(),
21
+ level: input.level ?? 'info',
22
+ eventType: input.eventType,
23
+ actor: input.actor,
24
+ summary: (0, redaction_1.redactSecrets)(input.summary)
25
+ };
26
+ if (input.taskId)
27
+ event.taskId = input.taskId;
28
+ const payload = sanitizePayload(input.payload);
29
+ if (payload !== undefined)
30
+ event.payload = payload;
31
+ return options.assertSchema ? assertHadaraEventSchema(event) : event;
32
+ }
33
+ function assertHadaraEventSchema(event) {
34
+ const result = (0, schema_1.validateSchema)('hadara.event.v1', event);
35
+ if (!result.ok) {
36
+ const firstIssue = result.issues[0];
37
+ throw new HadaraEventSchemaError(firstIssue
38
+ ? `HADARA event failed schema validation: ${firstIssue.path} ${firstIssue.code} ${firstIssue.message}`
39
+ : 'HADARA event failed schema validation.');
40
+ }
41
+ return event;
42
+ }
43
+ function serializeHadaraEvent(event) {
44
+ return JSON.stringify(event);
45
+ }
46
+ function sanitizePayload(value) {
47
+ if (value === undefined)
48
+ return undefined;
49
+ const seen = new WeakSet();
50
+ const serialized = JSON.stringify(value, (_key, current) => {
51
+ if (typeof current === 'bigint')
52
+ return current.toString();
53
+ if (typeof current !== 'object' || current === null)
54
+ return current;
55
+ if (seen.has(current))
56
+ return '[Circular]';
57
+ seen.add(current);
58
+ return current;
59
+ });
60
+ if (serialized === undefined)
61
+ return undefined;
62
+ return JSON.parse((0, redaction_1.redactSecrets)(serialized));
63
+ }
@@ -0,0 +1,44 @@
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.ensureDir = ensureDir;
7
+ exports.writeFileIfMissing = writeFileIfMissing;
8
+ exports.appendLine = appendLine;
9
+ exports.readTextIfExists = readTextIfExists;
10
+ exports.writeJsonl = writeJsonl;
11
+ exports.slugify = slugify;
12
+ const node_fs_1 = __importDefault(require("node:fs"));
13
+ const node_path_1 = __importDefault(require("node:path"));
14
+ function ensureDir(dir) {
15
+ node_fs_1.default.mkdirSync(dir, { recursive: true });
16
+ }
17
+ function writeFileIfMissing(filePath, content) {
18
+ ensureDir(node_path_1.default.dirname(filePath));
19
+ if (node_fs_1.default.existsSync(filePath))
20
+ return false;
21
+ node_fs_1.default.writeFileSync(filePath, content, 'utf8');
22
+ return true;
23
+ }
24
+ function appendLine(filePath, line) {
25
+ ensureDir(node_path_1.default.dirname(filePath));
26
+ node_fs_1.default.appendFileSync(filePath, `${line}\n`, 'utf8');
27
+ }
28
+ function readTextIfExists(filePath) {
29
+ if (!node_fs_1.default.existsSync(filePath))
30
+ return null;
31
+ return node_fs_1.default.readFileSync(filePath, 'utf8');
32
+ }
33
+ function writeJsonl(filePath, event) {
34
+ appendLine(filePath, JSON.stringify(event));
35
+ }
36
+ function slugify(input) {
37
+ return input
38
+ .normalize('NFKD')
39
+ .replace(/[\u0300-\u036f]/g, '')
40
+ .toLowerCase()
41
+ .replace(/[^a-z0-9가-힣]+/g, '-')
42
+ .replace(/^-+|-+$/g, '')
43
+ .slice(0, 64) || 'task';
44
+ }