@neurcode-ai/cli 0.14.0 → 0.15.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/LICENSE +201 -0
- package/README.md +60 -8
- package/dist/api-client.d.ts +284 -0
- package/dist/api-client.d.ts.map +1 -1
- package/dist/api-client.js +111 -0
- package/dist/api-client.js.map +1 -1
- package/dist/commands/activate.d.ts +82 -0
- package/dist/commands/activate.d.ts.map +1 -0
- package/dist/commands/activate.js +551 -0
- package/dist/commands/activate.js.map +1 -0
- package/dist/commands/admission.d.ts +67 -0
- package/dist/commands/admission.d.ts.map +1 -0
- package/dist/commands/admission.js +350 -0
- package/dist/commands/admission.js.map +1 -0
- package/dist/commands/agent.d.ts +3 -0
- package/dist/commands/agent.d.ts.map +1 -0
- package/dist/commands/agent.js +2045 -0
- package/dist/commands/agent.js.map +1 -0
- package/dist/commands/demo.d.ts +3 -0
- package/dist/commands/demo.d.ts.map +1 -0
- package/dist/commands/demo.js +102 -0
- package/dist/commands/demo.js.map +1 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +58 -44
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/login.d.ts +1 -1
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +44 -22
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/profile.d.ts +14 -0
- package/dist/commands/profile.d.ts.map +1 -0
- package/dist/commands/profile.js +118 -0
- package/dist/commands/profile.js.map +1 -0
- package/dist/commands/quickstart.d.ts +2 -2
- package/dist/commands/quickstart.d.ts.map +1 -1
- package/dist/commands/quickstart.js +31 -30
- package/dist/commands/quickstart.js.map +1 -1
- package/dist/commands/remediate-export.d.ts +6 -1
- package/dist/commands/remediate-export.d.ts.map +1 -1
- package/dist/commands/remediate-export.js +359 -7
- package/dist/commands/remediate-export.js.map +1 -1
- package/dist/commands/replay.d.ts.map +1 -1
- package/dist/commands/replay.js +84 -0
- package/dist/commands/replay.js.map +1 -1
- package/dist/commands/run.d.ts +3 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +98 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/runtime-adapter.d.ts +8 -0
- package/dist/commands/runtime-adapter.d.ts.map +1 -0
- package/dist/commands/runtime-adapter.js +375 -0
- package/dist/commands/runtime-adapter.js.map +1 -0
- package/dist/commands/runtime-doctor.d.ts +6 -0
- package/dist/commands/runtime-doctor.d.ts.map +1 -0
- package/dist/commands/runtime-doctor.js +478 -0
- package/dist/commands/runtime-doctor.js.map +1 -0
- package/dist/commands/runtime-report.d.ts +13 -0
- package/dist/commands/runtime-report.d.ts.map +1 -0
- package/dist/commands/runtime-report.js +81 -0
- package/dist/commands/runtime-report.js.map +1 -0
- package/dist/commands/runtime-sync.d.ts +17 -0
- package/dist/commands/runtime-sync.d.ts.map +1 -0
- package/dist/commands/runtime-sync.js +656 -0
- package/dist/commands/runtime-sync.js.map +1 -0
- package/dist/commands/runtime.d.ts +16 -0
- package/dist/commands/runtime.d.ts.map +1 -0
- package/dist/commands/runtime.js +380 -0
- package/dist/commands/runtime.js.map +1 -0
- package/dist/commands/session-hook.d.ts +35 -0
- package/dist/commands/session-hook.d.ts.map +1 -0
- package/dist/commands/session-hook.js +1297 -0
- package/dist/commands/session-hook.js.map +1 -0
- package/dist/commands/session.d.ts +91 -0
- package/dist/commands/session.d.ts.map +1 -1
- package/dist/commands/session.js +1226 -0
- package/dist/commands/session.js.map +1 -1
- package/dist/commands/whoami.d.ts +7 -4
- package/dist/commands/whoami.d.ts.map +1 -1
- package/dist/commands/whoami.js +59 -34
- package/dist/commands/whoami.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +24 -5
- package/dist/config.js.map +1 -1
- package/dist/daemon/routes.d.ts.map +1 -1
- package/dist/daemon/routes.js +8 -0
- package/dist/daemon/routes.js.map +1 -1
- package/dist/daemon/server.d.ts.map +1 -1
- package/dist/daemon/server.js +88 -0
- package/dist/daemon/server.js.map +1 -1
- package/dist/governance/impact-analysis.d.ts +27 -0
- package/dist/governance/impact-analysis.d.ts.map +1 -0
- package/dist/governance/impact-analysis.js +274 -0
- package/dist/governance/impact-analysis.js.map +1 -0
- package/dist/index.js +472 -29
- package/dist/index.js.map +1 -1
- package/dist/intent-engine/matcher.d.ts.map +1 -1
- package/dist/intent-engine/matcher.js +3 -12
- package/dist/intent-engine/matcher.js.map +1 -1
- package/dist/utils/admission-artifact.d.ts +59 -0
- package/dist/utils/admission-artifact.d.ts.map +1 -0
- package/dist/utils/admission-artifact.js +410 -0
- package/dist/utils/admission-artifact.js.map +1 -0
- package/dist/utils/agent-adapter-setup.d.ts +80 -0
- package/dist/utils/agent-adapter-setup.d.ts.map +1 -0
- package/dist/utils/agent-adapter-setup.js +577 -0
- package/dist/utils/agent-adapter-setup.js.map +1 -0
- package/dist/utils/agent-guard-supervisor.d.ts +75 -0
- package/dist/utils/agent-guard-supervisor.d.ts.map +1 -0
- package/dist/utils/agent-guard-supervisor.js +388 -0
- package/dist/utils/agent-guard-supervisor.js.map +1 -0
- package/dist/utils/agent-guard.d.ts +92 -0
- package/dist/utils/agent-guard.d.ts.map +1 -0
- package/dist/utils/agent-guard.js +326 -0
- package/dist/utils/agent-guard.js.map +1 -0
- package/dist/utils/agent-session-launcher.d.ts +89 -0
- package/dist/utils/agent-session-launcher.d.ts.map +1 -0
- package/dist/utils/agent-session-launcher.js +308 -0
- package/dist/utils/agent-session-launcher.js.map +1 -0
- package/dist/utils/bash-command-analysis.d.ts +19 -0
- package/dist/utils/bash-command-analysis.d.ts.map +1 -0
- package/dist/utils/bash-command-analysis.js +295 -0
- package/dist/utils/bash-command-analysis.js.map +1 -0
- package/dist/utils/consequence-nudges.d.ts +30 -0
- package/dist/utils/consequence-nudges.d.ts.map +1 -0
- package/dist/utils/consequence-nudges.js +313 -0
- package/dist/utils/consequence-nudges.js.map +1 -0
- package/dist/utils/drift-intelligence.d.ts.map +1 -1
- package/dist/utils/drift-intelligence.js +29 -7
- package/dist/utils/drift-intelligence.js.map +1 -1
- package/dist/utils/git-coverage.d.ts +57 -0
- package/dist/utils/git-coverage.d.ts.map +1 -0
- package/dist/utils/git-coverage.js +302 -0
- package/dist/utils/git-coverage.js.map +1 -0
- package/dist/utils/gitignore.d.ts.map +1 -1
- package/dist/utils/gitignore.js +2 -1
- package/dist/utils/gitignore.js.map +1 -1
- package/dist/utils/governed-intent.d.ts +10 -0
- package/dist/utils/governed-intent.d.ts.map +1 -0
- package/dist/utils/governed-intent.js +108 -0
- package/dist/utils/governed-intent.js.map +1 -0
- package/dist/utils/hook-heartbeat.d.ts +55 -0
- package/dist/utils/hook-heartbeat.d.ts.map +1 -0
- package/dist/utils/hook-heartbeat.js +116 -0
- package/dist/utils/hook-heartbeat.js.map +1 -0
- package/dist/utils/intent-continuity.d.ts +21 -0
- package/dist/utils/intent-continuity.d.ts.map +1 -0
- package/dist/utils/intent-continuity.js +192 -0
- package/dist/utils/intent-continuity.js.map +1 -0
- package/dist/utils/messages.d.ts +1 -1
- package/dist/utils/messages.d.ts.map +1 -1
- package/dist/utils/messages.js +24 -21
- package/dist/utils/messages.js.map +1 -1
- package/dist/utils/runtime-companion.d.ts +137 -0
- package/dist/utils/runtime-companion.d.ts.map +1 -0
- package/dist/utils/runtime-companion.js +231 -0
- package/dist/utils/runtime-companion.js.map +1 -0
- package/dist/utils/runtime-connection.d.ts +46 -0
- package/dist/utils/runtime-connection.d.ts.map +1 -0
- package/dist/utils/runtime-connection.js +148 -0
- package/dist/utils/runtime-connection.js.map +1 -0
- package/dist/utils/runtime-evidence.d.ts +68 -0
- package/dist/utils/runtime-evidence.d.ts.map +1 -0
- package/dist/utils/runtime-evidence.js +248 -0
- package/dist/utils/runtime-evidence.js.map +1 -0
- package/dist/utils/runtime-live.d.ts +33 -0
- package/dist/utils/runtime-live.d.ts.map +1 -0
- package/dist/utils/runtime-live.js +361 -0
- package/dist/utils/runtime-live.js.map +1 -0
- package/dist/utils/runtime-outbox.d.ts +76 -0
- package/dist/utils/runtime-outbox.d.ts.map +1 -0
- package/dist/utils/runtime-outbox.js +410 -0
- package/dist/utils/runtime-outbox.js.map +1 -0
- package/dist/utils/runtime-receipt.d.ts +50 -0
- package/dist/utils/runtime-receipt.d.ts.map +1 -0
- package/dist/utils/runtime-receipt.js +223 -0
- package/dist/utils/runtime-receipt.js.map +1 -0
- package/dist/utils/state.d.ts +21 -0
- package/dist/utils/state.d.ts.map +1 -1
- package/dist/utils/state.js +30 -0
- package/dist/utils/state.js.map +1 -1
- package/dist/utils/structural-understanding.d.ts +334 -0
- package/dist/utils/structural-understanding.d.ts.map +1 -0
- package/dist/utils/structural-understanding.js +2316 -0
- package/dist/utils/structural-understanding.js.map +1 -0
- package/dist/utils/v0-governance.d.ts +197 -0
- package/dist/utils/v0-governance.d.ts.map +1 -0
- package/dist/utils/v0-governance.js +904 -0
- package/dist/utils/v0-governance.js.map +1 -0
- package/package.json +11 -12
|
@@ -0,0 +1,656 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.buildRuntimeEvidenceUploadBatches = buildRuntimeEvidenceUploadBatches;
|
|
4
|
+
exports.runtimeSyncCommand = runtimeSyncCommand;
|
|
5
|
+
exports.syncCommand = syncCommand;
|
|
6
|
+
const crypto_1 = require("crypto");
|
|
7
|
+
const child_process_1 = require("child_process");
|
|
8
|
+
const path_1 = require("path");
|
|
9
|
+
const fs_1 = require("fs");
|
|
10
|
+
const governance_runtime_1 = require("@neurcode-ai/governance-runtime");
|
|
11
|
+
const api_client_1 = require("../api-client");
|
|
12
|
+
const config_1 = require("../config");
|
|
13
|
+
const runtime_evidence_1 = require("../utils/runtime-evidence");
|
|
14
|
+
const v0_governance_1 = require("../utils/v0-governance");
|
|
15
|
+
const runtime_connection_1 = require("../utils/runtime-connection");
|
|
16
|
+
const runtime_live_1 = require("../utils/runtime-live");
|
|
17
|
+
const runtime_outbox_1 = require("../utils/runtime-outbox");
|
|
18
|
+
const runtime_outbox_2 = require("../utils/runtime-outbox");
|
|
19
|
+
const admission_artifact_1 = require("../utils/admission-artifact");
|
|
20
|
+
let chalk;
|
|
21
|
+
try {
|
|
22
|
+
chalk = require('chalk');
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
chalk = {
|
|
26
|
+
green: (s) => s,
|
|
27
|
+
yellow: (s) => s,
|
|
28
|
+
red: (s) => s,
|
|
29
|
+
dim: (s) => s,
|
|
30
|
+
bold: (s) => s,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
const SOURCE_LIKE_KEYS = new Set([
|
|
34
|
+
'content',
|
|
35
|
+
'fileContent',
|
|
36
|
+
'file_content',
|
|
37
|
+
'sourceText',
|
|
38
|
+
'source_text',
|
|
39
|
+
'diff',
|
|
40
|
+
'diffText',
|
|
41
|
+
'diff_text',
|
|
42
|
+
'patch',
|
|
43
|
+
'before',
|
|
44
|
+
'after',
|
|
45
|
+
]);
|
|
46
|
+
const BULK_EVIDENCE_OMIT_KEYS = new Set([
|
|
47
|
+
'architectureGraph',
|
|
48
|
+
'dependencyGraph',
|
|
49
|
+
'ownershipGraph',
|
|
50
|
+
'graph',
|
|
51
|
+
'rawGraph',
|
|
52
|
+
'snapshot',
|
|
53
|
+
'rawSnapshot',
|
|
54
|
+
'environment',
|
|
55
|
+
]);
|
|
56
|
+
const BULK_UPLOAD_MAX_STRING_LENGTH = 2_000;
|
|
57
|
+
const BULK_UPLOAD_MAX_ARRAY_ITEMS = 80;
|
|
58
|
+
const BULK_UPLOAD_MAX_EVENT_ITEMS = 160;
|
|
59
|
+
const BULK_UPLOAD_TARGET_BYTES = 850_000;
|
|
60
|
+
const BULK_UPLOAD_MAX_SINGLE_SESSION_BYTES = 650_000;
|
|
61
|
+
const BULK_UPLOAD_AGGRESSIVE_MAX_STRING_LENGTH = 500;
|
|
62
|
+
const BULK_UPLOAD_AGGRESSIVE_MAX_ARRAY_ITEMS = 20;
|
|
63
|
+
const BULK_UPLOAD_AGGRESSIVE_MAX_EVENT_ITEMS = 80;
|
|
64
|
+
function sha256(input) {
|
|
65
|
+
return (0, crypto_1.createHash)('sha256').update(input).digest('hex').slice(0, 32);
|
|
66
|
+
}
|
|
67
|
+
function readJsonFile(path) {
|
|
68
|
+
try {
|
|
69
|
+
if (!(0, fs_1.existsSync)(path))
|
|
70
|
+
return null;
|
|
71
|
+
return JSON.parse((0, fs_1.readFileSync)(path, 'utf8'));
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function gitValue(repoRoot, args) {
|
|
78
|
+
try {
|
|
79
|
+
const value = (0, child_process_1.execFileSync)('git', args, {
|
|
80
|
+
cwd: repoRoot,
|
|
81
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
82
|
+
encoding: 'utf8',
|
|
83
|
+
}).trim();
|
|
84
|
+
return value || null;
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function sanitizeForUpload(value, path = 'session') {
|
|
91
|
+
if (Array.isArray(value)) {
|
|
92
|
+
return value.map((item, index) => sanitizeForUpload(item, `${path}[${index}]`));
|
|
93
|
+
}
|
|
94
|
+
if (!value || typeof value !== 'object')
|
|
95
|
+
return value;
|
|
96
|
+
const out = {};
|
|
97
|
+
for (const [key, child] of Object.entries(value)) {
|
|
98
|
+
if (SOURCE_LIKE_KEYS.has(key)) {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
out[key] = sanitizeForUpload(child, `${path}.${key}`);
|
|
102
|
+
}
|
|
103
|
+
return out;
|
|
104
|
+
}
|
|
105
|
+
const DEFAULT_BULK_COMPACTION_LIMITS = {
|
|
106
|
+
maxStringLength: BULK_UPLOAD_MAX_STRING_LENGTH,
|
|
107
|
+
maxArrayItems: BULK_UPLOAD_MAX_ARRAY_ITEMS,
|
|
108
|
+
maxEventItems: BULK_UPLOAD_MAX_EVENT_ITEMS,
|
|
109
|
+
};
|
|
110
|
+
const AGGRESSIVE_BULK_COMPACTION_LIMITS = {
|
|
111
|
+
maxStringLength: BULK_UPLOAD_AGGRESSIVE_MAX_STRING_LENGTH,
|
|
112
|
+
maxArrayItems: BULK_UPLOAD_AGGRESSIVE_MAX_ARRAY_ITEMS,
|
|
113
|
+
maxEventItems: BULK_UPLOAD_AGGRESSIVE_MAX_EVENT_ITEMS,
|
|
114
|
+
};
|
|
115
|
+
function compactStringForBulk(value, limits) {
|
|
116
|
+
if (value.length <= limits.maxStringLength)
|
|
117
|
+
return value;
|
|
118
|
+
return `${value.slice(0, limits.maxStringLength)}...[truncated ${value.length - limits.maxStringLength} chars]`;
|
|
119
|
+
}
|
|
120
|
+
function compactForBulkEvidence(value, path = 'session', limits = DEFAULT_BULK_COMPACTION_LIMITS) {
|
|
121
|
+
if (typeof value === 'string')
|
|
122
|
+
return compactStringForBulk(value, limits);
|
|
123
|
+
if (Array.isArray(value)) {
|
|
124
|
+
const maxItems = path.endsWith('.events')
|
|
125
|
+
? limits.maxEventItems
|
|
126
|
+
: limits.maxArrayItems;
|
|
127
|
+
const items = value.length > maxItems ? value.slice(-maxItems) : value;
|
|
128
|
+
const compacted = items.map((item, index) => compactForBulkEvidence(item, `${path}[${index}]`, limits));
|
|
129
|
+
if (value.length <= maxItems)
|
|
130
|
+
return compacted;
|
|
131
|
+
return [
|
|
132
|
+
{
|
|
133
|
+
truncated: true,
|
|
134
|
+
omittedItems: value.length - maxItems,
|
|
135
|
+
retainedItems: maxItems,
|
|
136
|
+
retention: path.endsWith('.events') ? 'last_events' : 'last_items',
|
|
137
|
+
},
|
|
138
|
+
...compacted,
|
|
139
|
+
];
|
|
140
|
+
}
|
|
141
|
+
if (!value || typeof value !== 'object')
|
|
142
|
+
return value;
|
|
143
|
+
const out = {};
|
|
144
|
+
for (const [key, child] of Object.entries(value)) {
|
|
145
|
+
if (SOURCE_LIKE_KEYS.has(key))
|
|
146
|
+
continue;
|
|
147
|
+
if (BULK_EVIDENCE_OMIT_KEYS.has(key)) {
|
|
148
|
+
out[`${key}Omitted`] = true;
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
out[key] = compactForBulkEvidence(child, `${path}.${key}`, limits);
|
|
152
|
+
}
|
|
153
|
+
return out;
|
|
154
|
+
}
|
|
155
|
+
function byteSize(value) {
|
|
156
|
+
return Buffer.byteLength(JSON.stringify(value), 'utf8');
|
|
157
|
+
}
|
|
158
|
+
function assertPayloadHasNoSourceKeys(value, path = 'payload') {
|
|
159
|
+
if (Array.isArray(value)) {
|
|
160
|
+
value.forEach((item, index) => assertPayloadHasNoSourceKeys(item, `${path}[${index}]`));
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if (!value || typeof value !== 'object')
|
|
164
|
+
return;
|
|
165
|
+
for (const [key, child] of Object.entries(value)) {
|
|
166
|
+
if (SOURCE_LIKE_KEYS.has(key)) {
|
|
167
|
+
throw new Error(`runtime sync payload still contains source-like key ${path}.${key}`);
|
|
168
|
+
}
|
|
169
|
+
assertPayloadHasNoSourceKeys(child, `${path}.${key}`);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
function replayStatus(session) {
|
|
173
|
+
if (!session.replayHash)
|
|
174
|
+
return 'missing';
|
|
175
|
+
return (0, governance_runtime_1.replaySession)(session).matchesOriginal ? 'verified' : 'mismatch';
|
|
176
|
+
}
|
|
177
|
+
function repoRelative(repoRoot, path) {
|
|
178
|
+
return path.replace(repoRoot, '').replace(/^\/+/, '').replace(/\\/g, '/');
|
|
179
|
+
}
|
|
180
|
+
function buildAdmissionUploadMetadata(repoRoot, session) {
|
|
181
|
+
const localPath = (0, admission_artifact_1.admissionRecordPath)(repoRoot, session.sessionId);
|
|
182
|
+
const publicPath = (0, admission_artifact_1.publicAdmissionRecordPath)(repoRoot, session.sessionId);
|
|
183
|
+
const publicPresent = (0, fs_1.existsSync)(publicPath);
|
|
184
|
+
const base = {
|
|
185
|
+
localRecord: {
|
|
186
|
+
present: false,
|
|
187
|
+
path: repoRelative(repoRoot, localPath),
|
|
188
|
+
},
|
|
189
|
+
prArtifact: {
|
|
190
|
+
present: publicPresent,
|
|
191
|
+
path: repoRelative(repoRoot, publicPath),
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
if (!(0, fs_1.existsSync)(localPath))
|
|
195
|
+
return base;
|
|
196
|
+
try {
|
|
197
|
+
const record = (0, governance_runtime_1.readSelfAttestedAdmissionRecordFromText)((0, fs_1.readFileSync)(localPath, 'utf8'));
|
|
198
|
+
if (!record) {
|
|
199
|
+
return {
|
|
200
|
+
...base,
|
|
201
|
+
localRecord: {
|
|
202
|
+
...base.localRecord,
|
|
203
|
+
present: true,
|
|
204
|
+
status: 'invalid',
|
|
205
|
+
},
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
const governedCoverageCount = record.manifest.coverage.filter((entry) => entry.classification === 'governed_prewrite' ||
|
|
209
|
+
entry.classification === 'governed_delete' ||
|
|
210
|
+
entry.classification === 'generated').length;
|
|
211
|
+
const ungovernedCoverageCount = record.manifest.coverage.filter((entry) => entry.classification === 'ungoverned').length;
|
|
212
|
+
return {
|
|
213
|
+
...base,
|
|
214
|
+
localRecord: {
|
|
215
|
+
...base.localRecord,
|
|
216
|
+
present: true,
|
|
217
|
+
status: 'valid',
|
|
218
|
+
schemaVersion: record.schemaVersion,
|
|
219
|
+
attestationKind: record.attestationKind,
|
|
220
|
+
admissionContractVersion: record.admissionContractVersion,
|
|
221
|
+
capture: {
|
|
222
|
+
mode: record.capture.mode,
|
|
223
|
+
...(record.capture.baseRef ? { baseRef: record.capture.baseRef } : {}),
|
|
224
|
+
...(record.capture.headRef ? { headRef: record.capture.headRef } : {}),
|
|
225
|
+
},
|
|
226
|
+
manifest: {
|
|
227
|
+
entryCount: record.manifest.entryCount,
|
|
228
|
+
coverageCount: record.manifest.coverage.length,
|
|
229
|
+
governedCoverageCount,
|
|
230
|
+
ungovernedCoverageCount,
|
|
231
|
+
deltaHash: record.manifest.deltaHash,
|
|
232
|
+
coverageSetHash: record.manifest.coverageSetHash,
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
catch (error) {
|
|
238
|
+
return {
|
|
239
|
+
...base,
|
|
240
|
+
localRecord: {
|
|
241
|
+
...base.localRecord,
|
|
242
|
+
present: true,
|
|
243
|
+
status: 'unreadable',
|
|
244
|
+
error: error instanceof Error ? error.message : String(error),
|
|
245
|
+
},
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
function importantApprovalContext(detail) {
|
|
250
|
+
if (!detail || typeof detail !== 'object')
|
|
251
|
+
return undefined;
|
|
252
|
+
const approvalContext = detail.approvalContext;
|
|
253
|
+
if (!approvalContext || typeof approvalContext !== 'object')
|
|
254
|
+
return undefined;
|
|
255
|
+
const ctx = approvalContext;
|
|
256
|
+
const out = {};
|
|
257
|
+
for (const key of ['blockedPath', 'approvalRequired', 'owners', 'suggestedApprovalPath', 'reason', 'policyId']) {
|
|
258
|
+
if (ctx[key] !== undefined)
|
|
259
|
+
out[key] = compactForBulkEvidence(ctx[key], `event.detail.approvalContext.${key}`, AGGRESSIVE_BULK_COMPACTION_LIMITS);
|
|
260
|
+
}
|
|
261
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
262
|
+
}
|
|
263
|
+
function compactEventForBulkSummary(event) {
|
|
264
|
+
if (!event || typeof event !== 'object')
|
|
265
|
+
return {};
|
|
266
|
+
const src = event;
|
|
267
|
+
const detail = src.detail;
|
|
268
|
+
const approvalContext = importantApprovalContext(detail);
|
|
269
|
+
const out = {};
|
|
270
|
+
for (const key of ['type', 'ts', 'filePath', 'verdict', 'decision', 'message']) {
|
|
271
|
+
if (src[key] !== undefined)
|
|
272
|
+
out[key] = compactForBulkEvidence(src[key], `event.${key}`, AGGRESSIVE_BULK_COMPACTION_LIMITS);
|
|
273
|
+
}
|
|
274
|
+
if (approvalContext)
|
|
275
|
+
out.detail = { approvalContext };
|
|
276
|
+
return out;
|
|
277
|
+
}
|
|
278
|
+
function summarizeOversizedSessionForBulk(session) {
|
|
279
|
+
const events = Array.isArray(session.events) ? session.events : [];
|
|
280
|
+
const retainedEvents = events.slice(-BULK_UPLOAD_AGGRESSIVE_MAX_EVENT_ITEMS).map(compactEventForBulkSummary);
|
|
281
|
+
return {
|
|
282
|
+
schemaVersion: session.schemaVersion,
|
|
283
|
+
sessionId: session.sessionId,
|
|
284
|
+
profileHash: session.profileHash,
|
|
285
|
+
status: session.status,
|
|
286
|
+
startedAt: session.startedAt,
|
|
287
|
+
finishedAt: session.finishedAt,
|
|
288
|
+
replayHash: session.replayHash,
|
|
289
|
+
contract: compactForBulkEvidence(session.contract || {}, 'session.contract', AGGRESSIVE_BULK_COMPACTION_LIMITS),
|
|
290
|
+
events: events.length > retainedEvents.length
|
|
291
|
+
? [
|
|
292
|
+
{
|
|
293
|
+
truncated: true,
|
|
294
|
+
omittedItems: events.length - retainedEvents.length,
|
|
295
|
+
retainedItems: retainedEvents.length,
|
|
296
|
+
retention: 'last_events',
|
|
297
|
+
reason: 'single_session_payload_budget',
|
|
298
|
+
},
|
|
299
|
+
...retainedEvents,
|
|
300
|
+
]
|
|
301
|
+
: retainedEvents,
|
|
302
|
+
uploadMetadata: {
|
|
303
|
+
...(session.uploadMetadata && typeof session.uploadMetadata === 'object' ? session.uploadMetadata : {}),
|
|
304
|
+
bulkEvidence: {
|
|
305
|
+
...(session.uploadMetadata?.bulkEvidence || {}),
|
|
306
|
+
compacted: true,
|
|
307
|
+
compactionLevel: 'event_summary',
|
|
308
|
+
maxSingleSessionBytes: BULK_UPLOAD_MAX_SINGLE_SESSION_BYTES,
|
|
309
|
+
},
|
|
310
|
+
},
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
function buildCompactUploadSession(repoRoot, record) {
|
|
314
|
+
const sanitized = sanitizeForUpload(record.session);
|
|
315
|
+
let compacted = compactForBulkEvidence(sanitized);
|
|
316
|
+
const bytesBefore = byteSize(sanitized);
|
|
317
|
+
compacted.uploadMetadata = {
|
|
318
|
+
recordPath: repoRelative(repoRoot, record.path),
|
|
319
|
+
replayStatus: replayStatus(record.session),
|
|
320
|
+
gitHead: gitValue(repoRoot, ['rev-parse', '--short=12', 'HEAD']),
|
|
321
|
+
admission: buildAdmissionUploadMetadata(repoRoot, record.session),
|
|
322
|
+
bulkEvidence: {
|
|
323
|
+
compacted: true,
|
|
324
|
+
compactionLevel: 'standard',
|
|
325
|
+
bytesBefore,
|
|
326
|
+
bytesAfter: byteSize(compacted),
|
|
327
|
+
maxEventItems: BULK_UPLOAD_MAX_EVENT_ITEMS,
|
|
328
|
+
maxArrayItems: BULK_UPLOAD_MAX_ARRAY_ITEMS,
|
|
329
|
+
maxStringLength: BULK_UPLOAD_MAX_STRING_LENGTH,
|
|
330
|
+
maxSingleSessionBytes: BULK_UPLOAD_MAX_SINGLE_SESSION_BYTES,
|
|
331
|
+
},
|
|
332
|
+
};
|
|
333
|
+
if (byteSize(compacted) > BULK_UPLOAD_MAX_SINGLE_SESSION_BYTES) {
|
|
334
|
+
compacted = compactForBulkEvidence(sanitized, 'session', AGGRESSIVE_BULK_COMPACTION_LIMITS);
|
|
335
|
+
compacted.uploadMetadata = {
|
|
336
|
+
recordPath: repoRelative(repoRoot, record.path),
|
|
337
|
+
replayStatus: replayStatus(record.session),
|
|
338
|
+
gitHead: gitValue(repoRoot, ['rev-parse', '--short=12', 'HEAD']),
|
|
339
|
+
admission: buildAdmissionUploadMetadata(repoRoot, record.session),
|
|
340
|
+
bulkEvidence: {
|
|
341
|
+
compacted: true,
|
|
342
|
+
compactionLevel: 'aggressive',
|
|
343
|
+
bytesBefore,
|
|
344
|
+
bytesAfter: byteSize(compacted),
|
|
345
|
+
maxEventItems: BULK_UPLOAD_AGGRESSIVE_MAX_EVENT_ITEMS,
|
|
346
|
+
maxArrayItems: BULK_UPLOAD_AGGRESSIVE_MAX_ARRAY_ITEMS,
|
|
347
|
+
maxStringLength: BULK_UPLOAD_AGGRESSIVE_MAX_STRING_LENGTH,
|
|
348
|
+
maxSingleSessionBytes: BULK_UPLOAD_MAX_SINGLE_SESSION_BYTES,
|
|
349
|
+
},
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
if (byteSize(compacted) > BULK_UPLOAD_MAX_SINGLE_SESSION_BYTES) {
|
|
353
|
+
compacted = summarizeOversizedSessionForBulk(compacted);
|
|
354
|
+
}
|
|
355
|
+
const metadata = compacted.uploadMetadata;
|
|
356
|
+
if (metadata?.bulkEvidence) {
|
|
357
|
+
metadata.bulkEvidence.bytesAfter = byteSize(compacted);
|
|
358
|
+
}
|
|
359
|
+
return compacted;
|
|
360
|
+
}
|
|
361
|
+
function buildUploadPayloadFromSessions(repoRoot, sessions) {
|
|
362
|
+
const profile = readJsonFile((0, path_1.join)(repoRoot, '.neurcode', 'profile.json'));
|
|
363
|
+
const freshness = (0, v0_governance_1.buildProfileFreshnessSignal)((0, v0_governance_1.getProfileStaleness)(repoRoot));
|
|
364
|
+
const remote = gitValue(repoRoot, ['config', '--get', 'remote.origin.url']);
|
|
365
|
+
const repoName = typeof profile?.repo?.name === 'string' && profile.repo.name.trim()
|
|
366
|
+
? profile.repo.name.trim()
|
|
367
|
+
: (0, path_1.basename)(repoRoot);
|
|
368
|
+
const payload = {
|
|
369
|
+
repo: {
|
|
370
|
+
name: repoName,
|
|
371
|
+
rootHash: sha256(repoRoot),
|
|
372
|
+
remoteHash: remote ? sha256(remote) : undefined,
|
|
373
|
+
profileHash: typeof profile?.profileHash === 'string' ? profile.profileHash : undefined,
|
|
374
|
+
topologyHash: typeof profile?.topology?.hash === 'string' ? profile.topology.hash : undefined,
|
|
375
|
+
profileFreshness: {
|
|
376
|
+
...freshness,
|
|
377
|
+
profilePath: '.neurcode/profile.json',
|
|
378
|
+
},
|
|
379
|
+
source: 'local',
|
|
380
|
+
},
|
|
381
|
+
generatedAt: new Date().toISOString(),
|
|
382
|
+
sessions,
|
|
383
|
+
};
|
|
384
|
+
assertPayloadHasNoSourceKeys(payload);
|
|
385
|
+
return payload;
|
|
386
|
+
}
|
|
387
|
+
function buildRuntimeEvidenceUploadBatches(repoRoot, records) {
|
|
388
|
+
const compactSessions = records.map((record) => buildCompactUploadSession(repoRoot, record));
|
|
389
|
+
const batches = [];
|
|
390
|
+
let current = [];
|
|
391
|
+
for (const session of compactSessions) {
|
|
392
|
+
const candidate = buildUploadPayloadFromSessions(repoRoot, [...current, session]);
|
|
393
|
+
if (current.length > 0 && byteSize(candidate) > BULK_UPLOAD_TARGET_BYTES) {
|
|
394
|
+
batches.push(buildUploadPayloadFromSessions(repoRoot, current));
|
|
395
|
+
current = [session];
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
current = candidate.sessions;
|
|
399
|
+
}
|
|
400
|
+
if (current.length > 0)
|
|
401
|
+
batches.push(buildUploadPayloadFromSessions(repoRoot, current));
|
|
402
|
+
return batches;
|
|
403
|
+
}
|
|
404
|
+
function summarizeUploadBatches(payloads) {
|
|
405
|
+
return payloads.map((payload, index) => ({
|
|
406
|
+
index: index + 1,
|
|
407
|
+
sessions: payload.sessions.length,
|
|
408
|
+
bytes: byteSize(payload),
|
|
409
|
+
}));
|
|
410
|
+
}
|
|
411
|
+
function aggregateRuntimeEvidenceResponses(responses) {
|
|
412
|
+
const first = responses[0];
|
|
413
|
+
if (!first) {
|
|
414
|
+
return {
|
|
415
|
+
ok: true,
|
|
416
|
+
batchId: '',
|
|
417
|
+
repo: { id: '', name: '', repoKey: '' },
|
|
418
|
+
uploaded: 0,
|
|
419
|
+
skipped: 0,
|
|
420
|
+
failed: 0,
|
|
421
|
+
sessions: [],
|
|
422
|
+
privacy: {
|
|
423
|
+
sourceUploaded: false,
|
|
424
|
+
uploadedFields: ['file paths', 'owners', 'verdicts', 'timestamps', 'contracts', 'replay hashes'],
|
|
425
|
+
},
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
const uploaded = responses.reduce((sum, response) => sum + response.uploaded, 0);
|
|
429
|
+
const skipped = responses.reduce((sum, response) => sum + response.skipped, 0);
|
|
430
|
+
const failed = responses.reduce((sum, response) => sum + response.failed, 0);
|
|
431
|
+
return {
|
|
432
|
+
ok: responses.every((response) => response.ok),
|
|
433
|
+
batchId: responses.map((response) => response.batchId).filter(Boolean).join(','),
|
|
434
|
+
repo: first.repo,
|
|
435
|
+
uploaded,
|
|
436
|
+
skipped,
|
|
437
|
+
failed,
|
|
438
|
+
sessions: responses.flatMap((response) => response.sessions),
|
|
439
|
+
privacy: first.privacy,
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
async function runtimeSyncCommand(options = {}) {
|
|
443
|
+
let repoRootForStatus = null;
|
|
444
|
+
if (options.runtime !== true) {
|
|
445
|
+
const message = 'Only runtime sync is supported in V0.3. Run `neurcode sync --runtime`.';
|
|
446
|
+
if (options.json) {
|
|
447
|
+
console.log(JSON.stringify({ ok: false, error: message }, null, 2));
|
|
448
|
+
}
|
|
449
|
+
else {
|
|
450
|
+
console.error(chalk.yellow(message));
|
|
451
|
+
}
|
|
452
|
+
process.exitCode = 2;
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
try {
|
|
456
|
+
if (options.since) {
|
|
457
|
+
(0, runtime_evidence_1.parseSinceDuration)(options.since);
|
|
458
|
+
}
|
|
459
|
+
const repoRoot = (0, v0_governance_1.resolveRepoRoot)(options.dir || process.cwd());
|
|
460
|
+
repoRootForStatus = repoRoot;
|
|
461
|
+
const requeuedDeadLetters = options.retryDeadLetters
|
|
462
|
+
? (0, runtime_outbox_2.retryRuntimeDeadLetters)(repoRoot)
|
|
463
|
+
: 0;
|
|
464
|
+
const allRecords = (0, runtime_evidence_1.listRuntimeSessions)(repoRoot, { since: options.since });
|
|
465
|
+
const finishedRecords = options.includeActive
|
|
466
|
+
? allRecords
|
|
467
|
+
: allRecords.filter((record) => record.session.status === 'finished');
|
|
468
|
+
const validRecords = [];
|
|
469
|
+
const skipped = [];
|
|
470
|
+
for (const record of finishedRecords) {
|
|
471
|
+
const status = replayStatus(record.session);
|
|
472
|
+
if (status === 'mismatch') {
|
|
473
|
+
skipped.push({ sessionId: record.session.sessionId, reason: 'replayHash mismatch' });
|
|
474
|
+
continue;
|
|
475
|
+
}
|
|
476
|
+
validRecords.push(record);
|
|
477
|
+
}
|
|
478
|
+
const uploadPayloads = buildRuntimeEvidenceUploadBatches(repoRoot, validRecords);
|
|
479
|
+
const dryRunPayload = uploadPayloads.length <= 1
|
|
480
|
+
? uploadPayloads[0] || buildUploadPayloadFromSessions(repoRoot, [])
|
|
481
|
+
: {
|
|
482
|
+
...buildUploadPayloadFromSessions(repoRoot, []),
|
|
483
|
+
sessions: uploadPayloads.flatMap((payload) => payload.sessions),
|
|
484
|
+
};
|
|
485
|
+
assertPayloadHasNoSourceKeys(dryRunPayload);
|
|
486
|
+
if (options.dryRun) {
|
|
487
|
+
const liveTransport = (0, runtime_outbox_1.inspectRuntimeOutbox)(repoRoot);
|
|
488
|
+
const result = {
|
|
489
|
+
ok: true,
|
|
490
|
+
dryRun: true,
|
|
491
|
+
repoRoot,
|
|
492
|
+
endpoint: '/api/v1/runtime/evidence',
|
|
493
|
+
selected: validRecords.length,
|
|
494
|
+
skipped: skipped.length + (allRecords.length - finishedRecords.length),
|
|
495
|
+
skippedDetails: [
|
|
496
|
+
...skipped,
|
|
497
|
+
...allRecords
|
|
498
|
+
.filter((record) => record.session.status !== 'finished' && !options.includeActive)
|
|
499
|
+
.map((record) => ({ sessionId: record.session.sessionId, reason: 'active session not uploaded by default' })),
|
|
500
|
+
],
|
|
501
|
+
privacy: {
|
|
502
|
+
sourceUploaded: false,
|
|
503
|
+
uploadedFields: ['file paths', 'owners', 'verdicts', 'timestamps', 'contracts', 'replay hashes'],
|
|
504
|
+
},
|
|
505
|
+
payload: dryRunPayload,
|
|
506
|
+
uploadBatches: summarizeUploadBatches(uploadPayloads),
|
|
507
|
+
liveTransport,
|
|
508
|
+
requeuedDeadLetters,
|
|
509
|
+
};
|
|
510
|
+
if (options.json) {
|
|
511
|
+
console.log(JSON.stringify(result, null, 2));
|
|
512
|
+
}
|
|
513
|
+
else {
|
|
514
|
+
console.log('');
|
|
515
|
+
console.log(chalk.bold('Runtime evidence sync dry run'));
|
|
516
|
+
console.log(chalk.dim('-'.repeat(72)));
|
|
517
|
+
console.log(`Repo: ${repoRoot}`);
|
|
518
|
+
console.log(`Endpoint: /api/v1/runtime/evidence`);
|
|
519
|
+
console.log(`Selected: ${validRecords.length}`);
|
|
520
|
+
console.log(`Skipped: ${result.skipped}`);
|
|
521
|
+
console.log(chalk.dim('Privacy: source code is not uploaded; session evidence only.'));
|
|
522
|
+
console.log('');
|
|
523
|
+
}
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
const liveTransport = await (0, runtime_live_1.flushRuntimeLiveOutbox)(repoRoot, {
|
|
527
|
+
maxEvents: 100,
|
|
528
|
+
timeoutMs: 1_500,
|
|
529
|
+
force: true,
|
|
530
|
+
});
|
|
531
|
+
if (validRecords.length === 0) {
|
|
532
|
+
(0, runtime_connection_1.updateRuntimeConnection)(repoRoot, (connection) => ({
|
|
533
|
+
...connection,
|
|
534
|
+
autoSync: {
|
|
535
|
+
...connection.autoSync,
|
|
536
|
+
lastAttemptAt: new Date().toISOString(),
|
|
537
|
+
lastStatus: 'skipped',
|
|
538
|
+
lastUploaded: 0,
|
|
539
|
+
lastSkipped: skipped.length + (allRecords.length - finishedRecords.length),
|
|
540
|
+
lastFailed: 0,
|
|
541
|
+
lastError: undefined,
|
|
542
|
+
},
|
|
543
|
+
}));
|
|
544
|
+
if (options.json) {
|
|
545
|
+
console.log(JSON.stringify({
|
|
546
|
+
ok: true,
|
|
547
|
+
uploaded: 0,
|
|
548
|
+
skipped: skipped.length,
|
|
549
|
+
failed: 0,
|
|
550
|
+
liveTransport,
|
|
551
|
+
requeuedDeadLetters,
|
|
552
|
+
message: 'No finished runtime sessions to upload.',
|
|
553
|
+
}, null, 2));
|
|
554
|
+
}
|
|
555
|
+
else {
|
|
556
|
+
console.log(chalk.yellow('No finished runtime sessions to upload.'));
|
|
557
|
+
console.log(chalk.dim(`Live transport: ${liveTransport.delivered} delivered, ${liveTransport.pending} queued.`));
|
|
558
|
+
if (skipped.length > 0) {
|
|
559
|
+
for (const item of skipped)
|
|
560
|
+
console.log(chalk.dim(` skipped ${item.sessionId}: ${item.reason}`));
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
return;
|
|
564
|
+
}
|
|
565
|
+
const config = (0, config_1.loadConfig)();
|
|
566
|
+
if (!config.apiKey) {
|
|
567
|
+
config.apiKey = (0, config_1.requireApiKey)(config.orgId);
|
|
568
|
+
}
|
|
569
|
+
const client = new api_client_1.ApiClient(config);
|
|
570
|
+
const responses = [];
|
|
571
|
+
for (const payload of uploadPayloads) {
|
|
572
|
+
responses.push(await client.uploadRuntimeEvidence(payload));
|
|
573
|
+
}
|
|
574
|
+
const response = aggregateRuntimeEvidenceResponses(responses);
|
|
575
|
+
(0, runtime_connection_1.updateRuntimeConnection)(repoRoot, (connection) => ({
|
|
576
|
+
...connection,
|
|
577
|
+
autoSync: {
|
|
578
|
+
...connection.autoSync,
|
|
579
|
+
lastAttemptAt: new Date().toISOString(),
|
|
580
|
+
lastSyncedAt: response.failed > 0 ? connection.autoSync.lastSyncedAt : new Date().toISOString(),
|
|
581
|
+
lastStatus: response.failed > 0 ? 'failed' : 'ok',
|
|
582
|
+
lastUploaded: response.uploaded,
|
|
583
|
+
lastSkipped: response.skipped + skipped.length,
|
|
584
|
+
lastFailed: response.failed,
|
|
585
|
+
lastError: response.failed > 0 ? `${response.failed} runtime session upload failed` : undefined,
|
|
586
|
+
},
|
|
587
|
+
}));
|
|
588
|
+
if (options.json) {
|
|
589
|
+
console.log(JSON.stringify({
|
|
590
|
+
...response,
|
|
591
|
+
endpoint: `${config.apiUrl?.replace(/\/$/, '')}/api/v1/runtime/evidence`,
|
|
592
|
+
localSkipped: skipped,
|
|
593
|
+
liveTransport,
|
|
594
|
+
requeuedDeadLetters,
|
|
595
|
+
}, null, 2));
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
console.log('');
|
|
599
|
+
console.log(chalk.bold('Runtime evidence synced'));
|
|
600
|
+
console.log(chalk.dim('-'.repeat(72)));
|
|
601
|
+
console.log(`Endpoint: ${config.apiUrl?.replace(/\/$/, '')}/api/v1/runtime/evidence`);
|
|
602
|
+
console.log(`Repo: ${response.repo.name}`);
|
|
603
|
+
console.log(`Uploaded: ${chalk.green(String(response.uploaded))}`);
|
|
604
|
+
console.log(`Skipped: ${chalk.yellow(String(response.skipped + skipped.length))}`);
|
|
605
|
+
console.log(`Failed: ${response.failed > 0 ? chalk.red(String(response.failed)) : '0'}`);
|
|
606
|
+
console.log(`Live: ${liveTransport.delivered} delivered · ${liveTransport.pending} queued`);
|
|
607
|
+
if (requeuedDeadLetters > 0) {
|
|
608
|
+
console.log(`DLQ: ${chalk.yellow(String(requeuedDeadLetters))} event${requeuedDeadLetters === 1 ? '' : 's'} requeued`);
|
|
609
|
+
}
|
|
610
|
+
console.log(chalk.dim('Privacy: no source code, diffs, or file contents were uploaded.'));
|
|
611
|
+
console.log('');
|
|
612
|
+
}
|
|
613
|
+
catch (error) {
|
|
614
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
615
|
+
if (repoRootForStatus) {
|
|
616
|
+
(0, runtime_connection_1.updateRuntimeConnection)(repoRootForStatus, (connection) => ({
|
|
617
|
+
...connection,
|
|
618
|
+
autoSync: {
|
|
619
|
+
...connection.autoSync,
|
|
620
|
+
lastAttemptAt: new Date().toISOString(),
|
|
621
|
+
lastStatus: 'failed',
|
|
622
|
+
lastError: message,
|
|
623
|
+
},
|
|
624
|
+
}));
|
|
625
|
+
}
|
|
626
|
+
if (options.json) {
|
|
627
|
+
console.log(JSON.stringify({ ok: false, error: message }, null, 2));
|
|
628
|
+
}
|
|
629
|
+
else {
|
|
630
|
+
console.error(chalk.red(`Runtime evidence sync failed: ${message}`));
|
|
631
|
+
}
|
|
632
|
+
process.exitCode = 1;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
function syncCommand(program) {
|
|
636
|
+
program
|
|
637
|
+
.command('sync')
|
|
638
|
+
.description('Sync local runtime governance evidence to Neurcode')
|
|
639
|
+
.option('--runtime', 'Sync local in-flow governance session records')
|
|
640
|
+
.option('--dry-run', 'Build and validate the upload payload without sending it')
|
|
641
|
+
.option('--since <duration>', 'Limit to sessions with events in the window, e.g. 24h, 7d, 2w')
|
|
642
|
+
.option('--include-active', 'Include active sessions; by default only finished sessions upload')
|
|
643
|
+
.option('--retry-dead-letters', 'Requeue bounded live-transport dead letters before syncing')
|
|
644
|
+
.option('--dir <path>', 'Repository root (default: current directory)')
|
|
645
|
+
.option('--json', 'Output machine-readable JSON')
|
|
646
|
+
.action((options) => runtimeSyncCommand({
|
|
647
|
+
runtime: options.runtime === true,
|
|
648
|
+
dryRun: options.dryRun === true,
|
|
649
|
+
since: options.since,
|
|
650
|
+
includeActive: options.includeActive === true,
|
|
651
|
+
retryDeadLetters: options.retryDeadLetters === true,
|
|
652
|
+
dir: options.dir,
|
|
653
|
+
json: options.json === true,
|
|
654
|
+
}));
|
|
655
|
+
}
|
|
656
|
+
//# sourceMappingURL=runtime-sync.js.map
|