@openlife/cli 1.7.6 → 1.7.7

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.
@@ -0,0 +1,181 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.parseDurationToSeconds = parseDurationToSeconds;
37
+ exports.collectLogs = collectLogs;
38
+ exports.renderLogsHuman = renderLogsHuman;
39
+ exports.renderLogsJson = renderLogsJson;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const DEFAULT_TAIL = 20;
43
+ const KNOWN_JSONL_FILES = [
44
+ 'governance-ledger.jsonl',
45
+ 'media-routing.log.jsonl',
46
+ 'capability-lifecycle.jsonl',
47
+ 'canonization-log.jsonl',
48
+ ];
49
+ function parseDurationToSeconds(input) {
50
+ const trimmed = input.trim().toLowerCase();
51
+ const m = trimmed.match(/^(\d+)\s*(s|m|h|d)$/);
52
+ if (!m)
53
+ return null;
54
+ const n = Number.parseInt(m[1], 10);
55
+ if (!Number.isFinite(n) || n < 0)
56
+ return null;
57
+ const unit = m[2];
58
+ const mult = unit === 's' ? 1 : unit === 'm' ? 60 : unit === 'h' ? 3600 : 86400;
59
+ return n * mult;
60
+ }
61
+ function entrySubsystem(filePath) {
62
+ const base = path.basename(filePath);
63
+ return base.replace(/\.log\.jsonl$/, '').replace(/\.jsonl$/, '');
64
+ }
65
+ function extractTs(parsed, fallbackMtime) {
66
+ if (!parsed)
67
+ return fallbackMtime;
68
+ if (typeof parsed.ts === 'string') {
69
+ const t = Date.parse(parsed.ts);
70
+ if (!Number.isNaN(t))
71
+ return t;
72
+ }
73
+ if (typeof parsed.ts === 'number' && Number.isFinite(parsed.ts)) {
74
+ return parsed.ts > 1e12 ? parsed.ts : parsed.ts * 1000;
75
+ }
76
+ if (typeof parsed.timestamp === 'string') {
77
+ const t = Date.parse(parsed.timestamp);
78
+ if (!Number.isNaN(t))
79
+ return t;
80
+ }
81
+ return fallbackMtime;
82
+ }
83
+ function summarizeEntry(parsed) {
84
+ if (!parsed)
85
+ return '<unparseable line>';
86
+ const candidates = [
87
+ parsed.summary,
88
+ parsed.decision?.auditSummary,
89
+ parsed.message,
90
+ parsed.action,
91
+ parsed.event,
92
+ parsed.type,
93
+ ];
94
+ for (const c of candidates) {
95
+ if (typeof c === 'string' && c.trim().length > 0) {
96
+ return c.length > 140 ? `${c.slice(0, 137)}...` : c;
97
+ }
98
+ }
99
+ // Fall back to a one-line preview of the parsed object.
100
+ const compact = JSON.stringify(parsed);
101
+ return compact.length > 140 ? `${compact.slice(0, 137)}...` : compact;
102
+ }
103
+ function listJsonlFiles(stateDir) {
104
+ if (!fs.existsSync(stateDir))
105
+ return [];
106
+ try {
107
+ const entries = fs.readdirSync(stateDir);
108
+ const found = [];
109
+ for (const e of entries) {
110
+ if (KNOWN_JSONL_FILES.includes(e) || e.endsWith('.jsonl')) {
111
+ found.push(path.join(stateDir, e));
112
+ }
113
+ }
114
+ return found;
115
+ }
116
+ catch {
117
+ return [];
118
+ }
119
+ }
120
+ function collectLogs(opts = {}) {
121
+ const root = opts.root || process.cwd();
122
+ const stateDir = process.env.OPENLIFE_STATE_DIR
123
+ ? path.resolve(process.env.OPENLIFE_STATE_DIR)
124
+ : path.join(root, '.openlife');
125
+ const files = listJsonlFiles(stateDir);
126
+ const filter = opts.filter ? opts.filter.toLowerCase() : null;
127
+ const tail = opts.tail && opts.tail > 0 ? opts.tail : DEFAULT_TAIL;
128
+ const sinceSeconds = opts.since ? parseDurationToSeconds(opts.since) : null;
129
+ const minTs = sinceSeconds !== null ? Date.now() - sinceSeconds * 1000 : null;
130
+ const out = [];
131
+ for (const fp of files) {
132
+ const subsystem = entrySubsystem(fp);
133
+ if (filter && !subsystem.toLowerCase().includes(filter))
134
+ continue;
135
+ let mtime = Date.now();
136
+ try {
137
+ mtime = fs.statSync(fp).mtimeMs;
138
+ }
139
+ catch {
140
+ continue;
141
+ }
142
+ let raw = '';
143
+ try {
144
+ raw = fs.readFileSync(fp, 'utf-8');
145
+ }
146
+ catch {
147
+ continue;
148
+ }
149
+ const lines = raw.split('\n').filter((l) => l.trim().length > 0);
150
+ for (const line of lines) {
151
+ let parsed = null;
152
+ try {
153
+ parsed = JSON.parse(line);
154
+ }
155
+ catch {
156
+ parsed = null;
157
+ }
158
+ const ts = extractTs(parsed, mtime);
159
+ if (minTs !== null && ts < minTs)
160
+ continue;
161
+ out.push({ subsystem, rawLine: line, parsed, ts });
162
+ }
163
+ }
164
+ out.sort((a, b) => a.ts - b.ts);
165
+ return out.slice(-tail);
166
+ }
167
+ function renderLogsHuman(entries) {
168
+ if (entries.length === 0)
169
+ return '(no entries match filter)';
170
+ return entries
171
+ .map((e) => {
172
+ const tsIso = new Date(e.ts).toISOString();
173
+ return `${tsIso} [${e.subsystem}] ${summarizeEntry(e.parsed)}`;
174
+ })
175
+ .join('\n');
176
+ }
177
+ function renderLogsJson(entries) {
178
+ return entries
179
+ .map((e) => JSON.stringify({ ts: new Date(e.ts).toISOString(), subsystem: e.subsystem, entry: e.parsed ?? e.rawLine }))
180
+ .join('\n');
181
+ }
@@ -0,0 +1,217 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.HEARTBEAT_STALE_S = exports.HEARTBEAT_FRESH_S = void 0;
37
+ exports.buildStatusReport = buildStatusReport;
38
+ exports.renderStatusReport = renderStatusReport;
39
+ const fs = __importStar(require("fs"));
40
+ const path = __importStar(require("path"));
41
+ // ============================================================================
42
+ // `openlife status` — consolidated runtime state report.
43
+ //
44
+ // Aggregates the 6 most operationally useful files under `.openlife/`:
45
+ // - install-manifest.json → installed profile + providers detected
46
+ // - heartbeat.json → daemon uptime + last beat timestamp
47
+ // - runtime-health.json → per-executor failure budget + cooldown
48
+ // - runtime-policy-status.json → per-executor availability decision
49
+ // - agent-queue.json → queued objectives + last flush
50
+ // - governance-ledger.jsonl → tail entry hash + chain length
51
+ //
52
+ // Computes an `overall` rollup:
53
+ // - "healthy" → daemon beat within HEARTBEAT_FRESH_S AND at least one
54
+ // executor available AND governance ledger parseable
55
+ // - "degraded" → heartbeat stale (FRESH..STALE) OR some executors down
56
+ // - "down" → heartbeat older than STALE OR all executors down
57
+ //
58
+ // Returns JSON. The CLI wrapper handles --watch (re-print every 5s).
59
+ // ============================================================================
60
+ exports.HEARTBEAT_FRESH_S = 60;
61
+ exports.HEARTBEAT_STALE_S = 300;
62
+ function readJsonSafe(filePath) {
63
+ try {
64
+ if (!fs.existsSync(filePath))
65
+ return null;
66
+ return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
67
+ }
68
+ catch {
69
+ return null;
70
+ }
71
+ }
72
+ function readJsonlTailSafe(filePath, maxLines = 1) {
73
+ try {
74
+ if (!fs.existsSync(filePath))
75
+ return { count: 0 };
76
+ const raw = fs.readFileSync(filePath, 'utf-8');
77
+ const lines = raw.split('\n').filter((l) => l.trim().length > 0);
78
+ if (lines.length === 0)
79
+ return { count: 0 };
80
+ const tail = lines.slice(-Math.max(1, maxLines));
81
+ const lastRaw = tail[tail.length - 1];
82
+ try {
83
+ return { count: lines.length, last: JSON.parse(lastRaw) };
84
+ }
85
+ catch {
86
+ return { count: lines.length };
87
+ }
88
+ }
89
+ catch {
90
+ return { count: 0 };
91
+ }
92
+ }
93
+ function readPackageVersion(packageRoot) {
94
+ const candidate = path.join(packageRoot, 'package.json');
95
+ const pkg = readJsonSafe(candidate);
96
+ return pkg?.version || '0.0.0';
97
+ }
98
+ function normalizeExecutors(policyStatus, runtimeHealth) {
99
+ const result = {};
100
+ const policy = (policyStatus?.executors ?? {});
101
+ for (const [name, raw] of Object.entries(policy)) {
102
+ const r = raw;
103
+ result[name] = {
104
+ executor: name,
105
+ available: Boolean(r.available),
106
+ reason: typeof r.reason === 'string' ? r.reason : undefined,
107
+ category: typeof r.category === 'string' ? r.category : undefined,
108
+ updatedAt: typeof r.updatedAt === 'string' ? r.updatedAt : undefined,
109
+ };
110
+ }
111
+ if (runtimeHealth) {
112
+ for (const [name, raw] of Object.entries(runtimeHealth)) {
113
+ if (name === 'type' || name === 'status' || name === 'updatedAt')
114
+ continue;
115
+ const r = raw;
116
+ const current = result[name] || { executor: name, available: true };
117
+ if (typeof r.failures === 'number')
118
+ current.failures = r.failures;
119
+ if (typeof r.until === 'string')
120
+ current.cooldownUntil = r.until;
121
+ if (!current.reason && typeof r.reason === 'string')
122
+ current.reason = r.reason;
123
+ result[name] = current;
124
+ }
125
+ }
126
+ return Object.values(result);
127
+ }
128
+ function deriveOverall(report) {
129
+ const notes = [];
130
+ const age = report.heartbeat.ageSeconds;
131
+ let heartbeatTier = 'fresh';
132
+ if (!report.heartbeat.present || age === null) {
133
+ heartbeatTier = 'dead';
134
+ notes.push('no_heartbeat');
135
+ }
136
+ else if (age > exports.HEARTBEAT_STALE_S) {
137
+ heartbeatTier = 'dead';
138
+ notes.push(`heartbeat_stale_${age}s`);
139
+ }
140
+ else if (age > exports.HEARTBEAT_FRESH_S) {
141
+ heartbeatTier = 'stale';
142
+ notes.push(`heartbeat_warning_${age}s`);
143
+ }
144
+ const executors = report.executors;
145
+ const anyExecutor = executors.length > 0;
146
+ const anyAvailable = executors.some((e) => e.available);
147
+ if (anyExecutor && !anyAvailable) {
148
+ notes.push('all_executors_down');
149
+ }
150
+ if (anyExecutor && !executors.every((e) => e.available)) {
151
+ const down = executors.filter((e) => !e.available).map((e) => e.executor);
152
+ notes.push(`executors_down:${down.join(',')}`);
153
+ }
154
+ if (!report.governance.ledgerPresent) {
155
+ notes.push('no_governance_ledger');
156
+ }
157
+ let overall;
158
+ if (heartbeatTier === 'dead' || (anyExecutor && !anyAvailable)) {
159
+ overall = 'down';
160
+ }
161
+ else if (heartbeatTier === 'stale' || (anyExecutor && !executors.every((e) => e.available))) {
162
+ overall = 'degraded';
163
+ }
164
+ else {
165
+ overall = 'healthy';
166
+ }
167
+ return { overall, notes };
168
+ }
169
+ function buildStatusReport(root = process.cwd(), packageRoot) {
170
+ const stateDir = process.env.OPENLIFE_STATE_DIR
171
+ ? path.resolve(process.env.OPENLIFE_STATE_DIR)
172
+ : path.join(root, '.openlife');
173
+ const heartbeat = readJsonSafe(path.join(stateDir, 'heartbeat.json'));
174
+ const runtimeHealth = readJsonSafe(path.join(stateDir, 'runtime-health.json'));
175
+ const policyStatus = readJsonSafe(path.join(stateDir, 'runtime-policy-status.json'));
176
+ const queue = readJsonSafe(path.join(stateDir, 'agent-queue.json'));
177
+ const manifest = readJsonSafe(path.join(stateDir, 'install-manifest.json'));
178
+ const ledgerTail = readJsonlTailSafe(path.join(stateDir, 'governance-ledger.jsonl'), 1);
179
+ const lastLedger = ledgerTail.last;
180
+ const ageSeconds = heartbeat?.ts ? Math.floor((Date.now() - heartbeat.ts) / 1000) : null;
181
+ const uptimeSeconds = heartbeat?.startedAt ? Math.floor((Date.now() - heartbeat.startedAt) / 1000) : null;
182
+ const partial = {
183
+ ts: new Date().toISOString(),
184
+ version: readPackageVersion(packageRoot || path.join(__dirname, '..', '..')),
185
+ profile: manifest?.profile ?? null,
186
+ uptimeSeconds,
187
+ heartbeat: {
188
+ present: Boolean(heartbeat),
189
+ pid: heartbeat?.pid,
190
+ host: heartbeat?.host,
191
+ ageSeconds,
192
+ fresh: ageSeconds !== null && ageSeconds <= exports.HEARTBEAT_FRESH_S,
193
+ },
194
+ governance: {
195
+ ledgerPresent: ledgerTail.count > 0,
196
+ entryCount: ledgerTail.count,
197
+ lastEntryHash: lastLedger?.entryHash,
198
+ lastEntryTs: lastLedger?.ts,
199
+ },
200
+ queue: {
201
+ depth: Array.isArray(queue?.queuedObjectives) ? queue.queuedObjectives.length : 0,
202
+ lastFlushedAt: queue?.lastFlushedAt,
203
+ },
204
+ executors: normalizeExecutors(policyStatus, runtimeHealth),
205
+ install: {
206
+ installedAt: manifest?.installedAt,
207
+ providers: manifest?.providers,
208
+ clis: manifest?.clis,
209
+ hasTelegramToken: manifest?.envChecks?.hasTelegramToken,
210
+ },
211
+ };
212
+ const { overall, notes } = deriveOverall(partial);
213
+ return { ...partial, overall, notes };
214
+ }
215
+ function renderStatusReport(report) {
216
+ return JSON.stringify(report, null, 2);
217
+ }
package/dist/index.js CHANGED
@@ -338,6 +338,50 @@ program.command('init')
338
338
  }
339
339
  });
340
340
  // ============================================================================
341
+ // OBSERVABILITY — `openlife status`, `openlife logs`
342
+ // ============================================================================
343
+ program.command('status')
344
+ .description('Consolidated runtime state (heartbeat + executors + governance + queue) as JSON')
345
+ .option('--watch', 're-print every 5 seconds (Ctrl-C to stop)', false)
346
+ .action(async (options) => {
347
+ const { buildStatusReport, renderStatusReport } = require('./cli/StatusCommand');
348
+ const printOnce = () => {
349
+ const report = buildStatusReport(process.cwd());
350
+ console.log(renderStatusReport(report));
351
+ if (report.overall !== 'healthy')
352
+ process.exitCode = 1;
353
+ };
354
+ if (!options.watch) {
355
+ printOnce();
356
+ return;
357
+ }
358
+ printOnce();
359
+ const interval = setInterval(() => {
360
+ console.log('---');
361
+ printOnce();
362
+ }, 5000);
363
+ process.on('SIGINT', () => {
364
+ clearInterval(interval);
365
+ process.exit(0);
366
+ });
367
+ });
368
+ program.command('logs')
369
+ .description('Readable tail of .openlife/*.jsonl event streams')
370
+ .option('--tail <N>', 'number of entries to show', '20')
371
+ .option('--since <duration>', 'only entries newer than e.g. 5m | 1h | 2d')
372
+ .option('--filter <subsystem>', 'match subsystem (governance, media-routing, capability-lifecycle, canonization-log)')
373
+ .option('--json', 'emit one JSON object per line instead of human-readable text', false)
374
+ .action((options) => {
375
+ const { collectLogs, renderLogsHuman, renderLogsJson } = require('./cli/LogsCommand');
376
+ const tail = Number.parseInt(options.tail || '20', 10);
377
+ const entries = collectLogs({
378
+ tail: Number.isFinite(tail) && tail > 0 ? tail : 20,
379
+ since: options.since,
380
+ filter: options.filter,
381
+ });
382
+ console.log(options.json ? renderLogsJson(entries) : renderLogsHuman(entries));
383
+ });
384
+ // ============================================================================
341
385
  // AUTENTICAÇÃO (AUTH)
342
386
  // ============================================================================
343
387
  const authCmd = program.command('auth').description('Gerencia a autenticação nativa sem uso de API Keys');
@@ -296,7 +296,32 @@ async function scenario10WithApiKeysPersists() {
296
296
  cleanup(root);
297
297
  }
298
298
  }
299
- async function scenario11ProfileBothMapsToAutonomous() {
299
+ async function scenario11AbortDoesNotPersistApiKeys() {
300
+ const root = tempRoot();
301
+ try {
302
+ const provider = new InstallWizard_1.CannedAnswerProvider([
303
+ 0, 0,
304
+ true,
305
+ 'openai-abort-test-key',
306
+ '',
307
+ '',
308
+ '',
309
+ false,
310
+ '',
311
+ false,
312
+ false,
313
+ ]);
314
+ const wizard = new InstallWizard_1.InstallWizard(root, provider);
315
+ const result = await wizard.run();
316
+ assert(result.ok === false, 'scenario11: expected ok=false');
317
+ assert(!fs.existsSync(path.join(root, '.env')), 'scenario11: aborted wizard must not write .env');
318
+ console.log('✅ scenario 11: abort after API-key collection does not persist .env');
319
+ }
320
+ finally {
321
+ cleanup(root);
322
+ }
323
+ }
324
+ async function scenario12ProfileBothMapsToAutonomous() {
300
325
  const root = tempRoot();
301
326
  try {
302
327
  // profile=both(2), claude-code, apiKeys=N, oauth=N, models='', telegram=true (autonomous path),
@@ -327,7 +352,8 @@ async function main() {
327
352
  await scenario8CustomModelChain();
328
353
  await scenario9OutOfAnswersThrows();
329
354
  await scenario10WithApiKeysPersists();
330
- await scenario11ProfileBothMapsToAutonomous();
355
+ await scenario11AbortDoesNotPersistApiKeys();
356
+ await scenario12ProfileBothMapsToAutonomous();
331
357
  console.log('');
332
358
  console.log('TEST_INSTALL_WIZARD_OK');
333
359
  }
@@ -0,0 +1,177 @@
1
+ "use strict";
2
+ // test_logs_command — verifies filter / tail / since semantics + duration
3
+ // parser of `openlife logs`.
4
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5
+ if (k2 === undefined) k2 = k;
6
+ var desc = Object.getOwnPropertyDescriptor(m, k);
7
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
8
+ desc = { enumerable: true, get: function() { return m[k]; } };
9
+ }
10
+ Object.defineProperty(o, k2, desc);
11
+ }) : (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ o[k2] = m[k];
14
+ }));
15
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
16
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
17
+ }) : function(o, v) {
18
+ o["default"] = v;
19
+ });
20
+ var __importStar = (this && this.__importStar) || (function () {
21
+ var ownKeys = function(o) {
22
+ ownKeys = Object.getOwnPropertyNames || function (o) {
23
+ var ar = [];
24
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
25
+ return ar;
26
+ };
27
+ return ownKeys(o);
28
+ };
29
+ return function (mod) {
30
+ if (mod && mod.__esModule) return mod;
31
+ var result = {};
32
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
33
+ __setModuleDefault(result, mod);
34
+ return result;
35
+ };
36
+ })();
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ const fs = __importStar(require("fs"));
39
+ const os = __importStar(require("os"));
40
+ const path = __importStar(require("path"));
41
+ const LogsCommand_1 = require("./cli/LogsCommand");
42
+ function assert(cond, msg) {
43
+ if (!cond) {
44
+ console.error(`❌ ASSERT FAILED: ${msg}`);
45
+ process.exit(1);
46
+ }
47
+ }
48
+ function tempRoot() {
49
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'openlife-logs-'));
50
+ fs.mkdirSync(path.join(root, '.openlife'), { recursive: true });
51
+ return root;
52
+ }
53
+ function cleanup(root) {
54
+ try {
55
+ fs.rmSync(root, { recursive: true, force: true });
56
+ }
57
+ catch {
58
+ // best-effort
59
+ }
60
+ }
61
+ function writeJsonl(root, filename, entries) {
62
+ fs.writeFileSync(path.join(root, '.openlife', filename), entries.map((e) => JSON.stringify(e)).join('\n') + '\n', 'utf-8');
63
+ }
64
+ function scenarioDurationParser() {
65
+ assert((0, LogsCommand_1.parseDurationToSeconds)('30s') === 30, '30s → 30');
66
+ assert((0, LogsCommand_1.parseDurationToSeconds)('5m') === 300, '5m → 300');
67
+ assert((0, LogsCommand_1.parseDurationToSeconds)('1h') === 3600, '1h → 3600');
68
+ assert((0, LogsCommand_1.parseDurationToSeconds)('2d') === 172800, '2d → 172800');
69
+ assert((0, LogsCommand_1.parseDurationToSeconds)('bogus') === null, 'bogus → null');
70
+ assert((0, LogsCommand_1.parseDurationToSeconds)('-1m') === null, 'negative → null');
71
+ console.log('✅ scenario 1: parseDurationToSeconds covers s/m/h/d + rejects garbage');
72
+ }
73
+ function scenarioTailDefault() {
74
+ const root = tempRoot();
75
+ try {
76
+ const entries = [];
77
+ const now = Date.now();
78
+ for (let i = 0; i < 50; i++) {
79
+ entries.push({ ts: new Date(now - (50 - i) * 1000).toISOString(), summary: `entry ${i}` });
80
+ }
81
+ writeJsonl(root, 'governance-ledger.jsonl', entries);
82
+ const collected = (0, LogsCommand_1.collectLogs)({ root, tail: 5 });
83
+ assert(collected.length === 5, `expected 5 entries, got ${collected.length}`);
84
+ assert(collected[collected.length - 1].parsed.summary === 'entry 49', 'last entry should be the newest');
85
+ console.log('✅ scenario 2: tail=5 returns last 5 chronological entries');
86
+ }
87
+ finally {
88
+ cleanup(root);
89
+ }
90
+ }
91
+ function scenarioFilterBySubsystem() {
92
+ const root = tempRoot();
93
+ try {
94
+ const now = Date.now();
95
+ const govEntries = [
96
+ { ts: new Date(now).toISOString(), summary: 'gov-entry' },
97
+ ];
98
+ const mediaEntries = [
99
+ { ts: new Date(now).toISOString(), summary: 'media-entry' },
100
+ ];
101
+ writeJsonl(root, 'governance-ledger.jsonl', govEntries);
102
+ writeJsonl(root, 'media-routing.log.jsonl', mediaEntries);
103
+ const govOnly = (0, LogsCommand_1.collectLogs)({ root, filter: 'governance' });
104
+ assert(govOnly.length === 1, `expected 1 governance entry, got ${govOnly.length}`);
105
+ assert(govOnly[0].subsystem === 'governance-ledger', 'subsystem should match');
106
+ const mediaOnly = (0, LogsCommand_1.collectLogs)({ root, filter: 'media' });
107
+ assert(mediaOnly.length === 1, `expected 1 media entry, got ${mediaOnly.length}`);
108
+ assert(mediaOnly[0].subsystem === 'media-routing', 'media subsystem name');
109
+ console.log('✅ scenario 3: --filter narrows by subsystem id');
110
+ }
111
+ finally {
112
+ cleanup(root);
113
+ }
114
+ }
115
+ function scenarioSinceFiltersOldEntries() {
116
+ const root = tempRoot();
117
+ try {
118
+ const now = Date.now();
119
+ const entries = [
120
+ { ts: new Date(now - 3600_000).toISOString(), summary: 'one-hour-ago' },
121
+ { ts: new Date(now - 60_000).toISOString(), summary: 'one-minute-ago' },
122
+ { ts: new Date(now - 5_000).toISOString(), summary: 'five-seconds-ago' },
123
+ ];
124
+ writeJsonl(root, 'governance-ledger.jsonl', entries);
125
+ const recent = (0, LogsCommand_1.collectLogs)({ root, since: '5m' });
126
+ assert(recent.length === 2, `expected 2 entries within 5m, got ${recent.length}`);
127
+ assert(!recent.some((e) => e.parsed.summary === 'one-hour-ago'), 'one-hour-ago should be excluded');
128
+ console.log('✅ scenario 4: --since=5m excludes older entries');
129
+ }
130
+ finally {
131
+ cleanup(root);
132
+ }
133
+ }
134
+ function scenarioRenderHumanAndJson() {
135
+ const root = tempRoot();
136
+ try {
137
+ writeJsonl(root, 'governance-ledger.jsonl', [
138
+ { ts: new Date().toISOString(), summary: 'test summary' },
139
+ ]);
140
+ const entries = (0, LogsCommand_1.collectLogs)({ root });
141
+ const human = (0, LogsCommand_1.renderLogsHuman)(entries);
142
+ assert(human.includes('[governance-ledger]'), 'human render includes subsystem');
143
+ assert(human.includes('test summary'), 'human render includes summary');
144
+ const jsonLine = (0, LogsCommand_1.renderLogsJson)(entries);
145
+ const parsed = JSON.parse(jsonLine);
146
+ assert(parsed.subsystem === 'governance-ledger', 'json render preserves subsystem');
147
+ console.log('✅ scenario 5: human + JSON renderers both produce expected shape');
148
+ }
149
+ finally {
150
+ cleanup(root);
151
+ }
152
+ }
153
+ function scenarioNoEntriesGracefullyHandled() {
154
+ const root = tempRoot();
155
+ try {
156
+ const entries = (0, LogsCommand_1.collectLogs)({ root });
157
+ assert(entries.length === 0, 'no jsonl files → empty result');
158
+ const human = (0, LogsCommand_1.renderLogsHuman)(entries);
159
+ assert(human.includes('no entries'), 'human render reports empty');
160
+ console.log('✅ scenario 6: empty state renders helpful message');
161
+ }
162
+ finally {
163
+ cleanup(root);
164
+ }
165
+ }
166
+ function main() {
167
+ console.log('🧪 test_logs_command — jsonl viewer');
168
+ scenarioDurationParser();
169
+ scenarioTailDefault();
170
+ scenarioFilterBySubsystem();
171
+ scenarioSinceFiltersOldEntries();
172
+ scenarioRenderHumanAndJson();
173
+ scenarioNoEntriesGracefullyHandled();
174
+ console.log('');
175
+ console.log('TEST_LOGS_COMMAND_OK');
176
+ }
177
+ main();
@@ -0,0 +1,218 @@
1
+ "use strict";
2
+ // test_status_command — verifies the shape and overall-derivation logic of
3
+ // `openlife status`. Uses a temp .openlife/ scratch dir so we don't rely on
4
+ // (or pollute) the maintainer's local runtime state.
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ const fs = __importStar(require("fs"));
40
+ const os = __importStar(require("os"));
41
+ const path = __importStar(require("path"));
42
+ const StatusCommand_1 = require("./cli/StatusCommand");
43
+ function assert(cond, msg) {
44
+ if (!cond) {
45
+ console.error(`❌ ASSERT FAILED: ${msg}`);
46
+ process.exit(1);
47
+ }
48
+ }
49
+ function tempRoot() {
50
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'openlife-status-'));
51
+ fs.mkdirSync(path.join(root, '.openlife'), { recursive: true });
52
+ return root;
53
+ }
54
+ function cleanup(root) {
55
+ try {
56
+ fs.rmSync(root, { recursive: true, force: true });
57
+ }
58
+ catch {
59
+ // best-effort
60
+ }
61
+ }
62
+ function writeJson(root, filename, payload) {
63
+ fs.writeFileSync(path.join(root, '.openlife', filename), JSON.stringify(payload, null, 2), 'utf-8');
64
+ }
65
+ function writeJsonl(root, filename, entries) {
66
+ fs.writeFileSync(path.join(root, '.openlife', filename), entries.map((e) => JSON.stringify(e)).join('\n') + '\n', 'utf-8');
67
+ }
68
+ function scenarioEmpty() {
69
+ const root = tempRoot();
70
+ try {
71
+ const report = (0, StatusCommand_1.buildStatusReport)(root);
72
+ assert(report.overall === 'down', 'empty state should be down (no heartbeat, no executors)');
73
+ assert(report.heartbeat.present === false, 'no heartbeat in empty state');
74
+ assert(report.governance.ledgerPresent === false, 'no governance ledger in empty state');
75
+ assert(report.executors.length === 0, 'no executors in empty state');
76
+ assert(report.notes.includes('no_heartbeat'), 'should note no_heartbeat');
77
+ console.log('✅ scenario 1: empty state → overall=down with no_heartbeat note');
78
+ }
79
+ finally {
80
+ cleanup(root);
81
+ }
82
+ }
83
+ function scenarioHealthy() {
84
+ const root = tempRoot();
85
+ try {
86
+ const now = Date.now();
87
+ writeJson(root, 'heartbeat.json', { pid: 12345, host: 'test-host', ts: now, uptime_s: 100, startedAt: now - 100_000 });
88
+ writeJson(root, 'runtime-policy-status.json', {
89
+ executors: {
90
+ openai: { executor: 'openai', available: true, reason: 'ok', updatedAt: new Date(now).toISOString() },
91
+ anthropic: { executor: 'anthropic', available: true, reason: 'ok', updatedAt: new Date(now).toISOString() },
92
+ },
93
+ });
94
+ writeJsonl(root, 'governance-ledger.jsonl', [
95
+ { index: 1, ts: new Date(now).toISOString(), entryHash: 'aaa' },
96
+ { index: 2, ts: new Date(now).toISOString(), entryHash: 'bbb' },
97
+ ]);
98
+ const report = (0, StatusCommand_1.buildStatusReport)(root);
99
+ assert(report.overall === 'healthy', `expected healthy, got ${report.overall} (notes: ${report.notes.join(',')})`);
100
+ assert(report.heartbeat.fresh === true, 'fresh heartbeat expected');
101
+ assert(report.executors.length === 2, 'two executors expected');
102
+ assert(report.executors.every((e) => e.available), 'all executors available');
103
+ assert(report.governance.entryCount === 2, 'two ledger entries expected');
104
+ assert(report.governance.lastEntryHash === 'bbb', 'last entry hash is bbb');
105
+ console.log('✅ scenario 2: healthy heartbeat + all executors + ledger → overall=healthy');
106
+ }
107
+ finally {
108
+ cleanup(root);
109
+ }
110
+ }
111
+ function scenarioDegradedOneExecutorDown() {
112
+ const root = tempRoot();
113
+ try {
114
+ const now = Date.now();
115
+ writeJson(root, 'heartbeat.json', { pid: 1, host: 'h', ts: now, uptime_s: 1, startedAt: now });
116
+ writeJson(root, 'runtime-policy-status.json', {
117
+ executors: {
118
+ openai: { executor: 'openai', available: true, reason: 'ok' },
119
+ anthropic: { executor: 'anthropic', available: false, reason: 'auth expired', category: 'auth' },
120
+ },
121
+ });
122
+ const report = (0, StatusCommand_1.buildStatusReport)(root);
123
+ assert(report.overall === 'degraded', `expected degraded, got ${report.overall}`);
124
+ assert(report.notes.some((n) => n.startsWith('executors_down:')), 'should note specific executors down');
125
+ console.log('✅ scenario 3: one executor down → overall=degraded');
126
+ }
127
+ finally {
128
+ cleanup(root);
129
+ }
130
+ }
131
+ function scenarioDownAllExecutorsDown() {
132
+ const root = tempRoot();
133
+ try {
134
+ const now = Date.now();
135
+ writeJson(root, 'heartbeat.json', { pid: 1, host: 'h', ts: now, uptime_s: 1, startedAt: now });
136
+ writeJson(root, 'runtime-policy-status.json', {
137
+ executors: {
138
+ openai: { executor: 'openai', available: false, reason: 'rate limit' },
139
+ anthropic: { executor: 'anthropic', available: false, reason: 'auth expired' },
140
+ },
141
+ });
142
+ const report = (0, StatusCommand_1.buildStatusReport)(root);
143
+ assert(report.overall === 'down', `expected down, got ${report.overall}`);
144
+ assert(report.notes.includes('all_executors_down'), 'should note all_executors_down');
145
+ console.log('✅ scenario 4: all executors down → overall=down');
146
+ }
147
+ finally {
148
+ cleanup(root);
149
+ }
150
+ }
151
+ function scenarioStaleHeartbeat() {
152
+ const root = tempRoot();
153
+ try {
154
+ const staleTs = Date.now() - (StatusCommand_1.HEARTBEAT_FRESH_S + 30) * 1000;
155
+ writeJson(root, 'heartbeat.json', { pid: 1, host: 'h', ts: staleTs, uptime_s: 9999, startedAt: staleTs - 1000 });
156
+ writeJson(root, 'runtime-policy-status.json', {
157
+ executors: { openai: { executor: 'openai', available: true, reason: 'ok' } },
158
+ });
159
+ const report = (0, StatusCommand_1.buildStatusReport)(root);
160
+ assert(report.overall === 'degraded', `expected degraded for stale beat, got ${report.overall}`);
161
+ assert(report.heartbeat.fresh === false, 'stale heartbeat is not fresh');
162
+ assert(report.notes.some((n) => n.startsWith('heartbeat_warning_')), 'should warn about stale heartbeat');
163
+ console.log('✅ scenario 5: stale heartbeat → overall=degraded with heartbeat_warning note');
164
+ }
165
+ finally {
166
+ cleanup(root);
167
+ }
168
+ }
169
+ function scenarioDeadHeartbeat() {
170
+ const root = tempRoot();
171
+ try {
172
+ const deadTs = Date.now() - (StatusCommand_1.HEARTBEAT_STALE_S + 60) * 1000;
173
+ writeJson(root, 'heartbeat.json', { pid: 1, host: 'h', ts: deadTs, uptime_s: 9999, startedAt: deadTs - 1000 });
174
+ writeJson(root, 'runtime-policy-status.json', {
175
+ executors: { openai: { executor: 'openai', available: true, reason: 'ok' } },
176
+ });
177
+ const report = (0, StatusCommand_1.buildStatusReport)(root);
178
+ assert(report.overall === 'down', `expected down for dead beat, got ${report.overall}`);
179
+ assert(report.notes.some((n) => n.startsWith('heartbeat_stale_')), 'should note heartbeat_stale_<age>s');
180
+ console.log('✅ scenario 6: dead heartbeat → overall=down');
181
+ }
182
+ finally {
183
+ cleanup(root);
184
+ }
185
+ }
186
+ function scenarioCorruptLedgerHandled() {
187
+ const root = tempRoot();
188
+ try {
189
+ const now = Date.now();
190
+ writeJson(root, 'heartbeat.json', { pid: 1, host: 'h', ts: now, uptime_s: 1, startedAt: now });
191
+ writeJson(root, 'runtime-policy-status.json', {
192
+ executors: { openai: { executor: 'openai', available: true, reason: 'ok' } },
193
+ });
194
+ // Write a corrupt last line — must not throw.
195
+ fs.writeFileSync(path.join(root, '.openlife', 'governance-ledger.jsonl'), '{"index":1,"entryHash":"good","ts":"' + new Date(now).toISOString() + '"}\n{not-valid-json\n', 'utf-8');
196
+ const report = (0, StatusCommand_1.buildStatusReport)(root);
197
+ assert(report.governance.entryCount === 2, 'should count both lines (parseability separate from count)');
198
+ // Last entry was corrupt → lastEntryHash undefined; gracefully degraded, doesn't throw.
199
+ assert(report.governance.lastEntryHash === undefined, 'corrupt last line yields no entryHash');
200
+ console.log('✅ scenario 7: corrupt ledger line handled gracefully');
201
+ }
202
+ finally {
203
+ cleanup(root);
204
+ }
205
+ }
206
+ function main() {
207
+ console.log('🧪 test_status_command — runtime state aggregator');
208
+ scenarioEmpty();
209
+ scenarioHealthy();
210
+ scenarioDegradedOneExecutorDown();
211
+ scenarioDownAllExecutorsDown();
212
+ scenarioStaleHeartbeat();
213
+ scenarioDeadHeartbeat();
214
+ scenarioCorruptLedgerHandled();
215
+ console.log('');
216
+ console.log('TEST_STATUS_COMMAND_OK');
217
+ }
218
+ main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openlife/cli",
3
- "version": "1.7.6",
3
+ "version": "1.7.7",
4
4
  "description": "OPEN-LIFE Córtex Orquestrador Dual-Core",
5
5
  "main": "dist/index.js",
6
6
  "files": [
@@ -156,8 +156,10 @@
156
156
  "test:doctor-sandbox-check": "npm run build && node dist/test_doctor_sandbox_check.js",
157
157
  "test:task-executor-sandbox-optin": "npm run build && node dist/test_task_executor_sandbox_optin.js",
158
158
  "test:forecast-brain-wiring": "npm run build && node dist/test_forecast_brain_wiring.js",
159
+ "test:status-command": "npm run build && node dist/test_status_command.js",
160
+ "test:logs-command": "npm run build && node dist/test_logs_command.js",
159
161
  "pretest:all": "node scripts/clean-test-pollution.js",
160
- "test:all": "npm run build && node dist/test_distribution_installability.js && node dist/test_orchestration_assets_lifecycle.js && node dist/test_openlife_runtime_source_truth.js && node dist/test_openlife_evolution_surface.js && node dist/test_openlife_routing_surface.js && node dist/test_openlife_auto_creator_routing.js && node dist/test_openlife_gatekeeper_routing.js && node dist/test_enterprise_agentic_core.js && node dist/test_admin_teams_networks.js && node dist/test_agent_team_skill_network.js && node dist/test_benchmark_engine.js && node dist/test_cli_service_commands.js && node dist/test_consequence_forecaster.js && node dist/test_conversation_memory.js && node dist/test_create_entities.js && node dist/test_designmd_import_registry.js && node dist/test_designmd_mode.js && node dist/test_designmd_mode_workspace.js && node dist/test_dream_organizer.js && node dist/test_dual_mode.js && node dist/test_governance.js && node dist/test_governance_advanced.js && node dist/test_install_flow.js && node dist/test_job_lifecycle.js && node dist/test_memory_orchestrator.js && node dist/test_memory_promotion.js && node dist/test_memory_retention.js && node dist/test_operating_system.js && node dist/test_optimization_loop.js && node dist/test_outcome_simulator.js && node dist/test_performance_scorecard.js && node dist/test_phase6_board.js && node dist/test_phase6_cadence.js && node dist/test_phase6_ops.js && node dist/test_release_gate.js && node dist/test_reversa_contracts_e2e.js && node dist/test_reversa_export_and_strict.js && node dist/test_reversa_full_execution.js && node dist/test_reversa_lite.js && node dist/test_runtime_policy.js && node dist/test_runtime_probe.js && node dist/test_runtime_registry.js && node dist/test_security_download_guard.js && node dist/test_service_command_surface.js && node dist/test_service_completion_policy.js && node dist/test_service_guardrails_delete.js && node dist/test_sources_import_ref.js && node dist/test_sources_scaffold.js && node dist/test_teammate_learning.js && node dist/test_telegram_delete_guardrail.js && node dist/test_daemon_sigterm.js && node dist/test_ask_exit.js && node dist/test_brain_error_diagnostics.js && node dist/test_cli_doc_parity.js && node dist/test_trigger_basic_auth.js && node dist/test_brain_fallback_chain.js && node dist/test_cli_help_surface.js && node dist/test_cli_diagnostics.js && node dist/test_cli_crud_roundtrip.js && node dist/test_subsystems_routing_governance.js && node dist/test_subsystems_org_state.js && node dist/test_subsystems_promotion_memory_assets.js && node dist/test_phase1_check_exit.js && node dist/test_install_flow_host_validation.js && node dist/test_dist_templates_layout.js && node dist/test_host_installer.js && node dist/test_host_uninstaller.js && node dist/test_install_wizard.js && node dist/test_multi_host_docs_parity.js && node dist/test_host_install_e2e.js && node dist/test_runtime_profile_oauth_only.js && node dist/test_atomic_writer.js && node dist/test_mission_checkpoint.js && node dist/test_workflow_parser.js && node dist/test_workflow_engine.js && node dist/test_workflow_e2e.js && node dist/test_distributed_lock.js && node dist/test_watchdog_heartbeat.js && node dist/test_runtime_health_backoff.js && node dist/test_queue_scheduler.js && node dist/test_squad_skill_creator.js && node dist/test_aiobuilder_cli_parity.js && node dist/test_catalog_quality.js && node dist/test_royal_stack_golden.js && node dist/test_capability_pack_schema.js && node dist/test_capability_genesis_engine.js && node dist/test_workflow_schema_backward_compat.js && node dist/test_service_mode_explicit_only.js && node dist/test_deep_research_capability.js && node dist/test_guided_creator_cli.js && node dist/test_governance_v13_policies.js && node dist/test_gateway_telegram_guardrails.js && node dist/test_cron_manager.js && node dist/test_profile_toolset_mcp.js && node dist/test_squad_skill_design_llm.js && node dist/test_workflow_condition_parser.js && node dist/test_security_download_and_scan.js && node dist/test_host_installers_gemini_codex.js && node dist/test_toolset_enforcement.js && node dist/test_creator_placeholders_completed.js && node dist/test_performance_latency.js && node dist/test_post_mission_evaluation.js && node dist/test_governance_scope_ledger.js && node dist/test_consequence_forecast_brain.js && node dist/test_remote_publish.js && node dist/test_process_sandbox.js && node dist/test_v15_e2e_integration.js && node dist/test_doctor_sandbox_check.js && node dist/test_task_executor_sandbox_optin.js && node dist/test_forecast_brain_wiring.js",
162
+ "test:all": "npm run build && node dist/test_distribution_installability.js && node dist/test_orchestration_assets_lifecycle.js && node dist/test_openlife_runtime_source_truth.js && node dist/test_openlife_evolution_surface.js && node dist/test_openlife_routing_surface.js && node dist/test_openlife_auto_creator_routing.js && node dist/test_openlife_gatekeeper_routing.js && node dist/test_enterprise_agentic_core.js && node dist/test_admin_teams_networks.js && node dist/test_agent_team_skill_network.js && node dist/test_benchmark_engine.js && node dist/test_cli_service_commands.js && node dist/test_consequence_forecaster.js && node dist/test_conversation_memory.js && node dist/test_create_entities.js && node dist/test_designmd_import_registry.js && node dist/test_designmd_mode.js && node dist/test_designmd_mode_workspace.js && node dist/test_dream_organizer.js && node dist/test_dual_mode.js && node dist/test_governance.js && node dist/test_governance_advanced.js && node dist/test_install_flow.js && node dist/test_job_lifecycle.js && node dist/test_memory_orchestrator.js && node dist/test_memory_promotion.js && node dist/test_memory_retention.js && node dist/test_operating_system.js && node dist/test_optimization_loop.js && node dist/test_outcome_simulator.js && node dist/test_performance_scorecard.js && node dist/test_phase6_board.js && node dist/test_phase6_cadence.js && node dist/test_phase6_ops.js && node dist/test_release_gate.js && node dist/test_reversa_contracts_e2e.js && node dist/test_reversa_export_and_strict.js && node dist/test_reversa_full_execution.js && node dist/test_reversa_lite.js && node dist/test_runtime_policy.js && node dist/test_runtime_probe.js && node dist/test_runtime_registry.js && node dist/test_security_download_guard.js && node dist/test_service_command_surface.js && node dist/test_service_completion_policy.js && node dist/test_service_guardrails_delete.js && node dist/test_sources_import_ref.js && node dist/test_sources_scaffold.js && node dist/test_teammate_learning.js && node dist/test_telegram_delete_guardrail.js && node dist/test_daemon_sigterm.js && node dist/test_ask_exit.js && node dist/test_brain_error_diagnostics.js && node dist/test_cli_doc_parity.js && node dist/test_trigger_basic_auth.js && node dist/test_brain_fallback_chain.js && node dist/test_cli_help_surface.js && node dist/test_cli_diagnostics.js && node dist/test_cli_crud_roundtrip.js && node dist/test_subsystems_routing_governance.js && node dist/test_subsystems_org_state.js && node dist/test_subsystems_promotion_memory_assets.js && node dist/test_phase1_check_exit.js && node dist/test_install_flow_host_validation.js && node dist/test_dist_templates_layout.js && node dist/test_host_installer.js && node dist/test_host_uninstaller.js && node dist/test_install_wizard.js && node dist/test_multi_host_docs_parity.js && node dist/test_host_install_e2e.js && node dist/test_runtime_profile_oauth_only.js && node dist/test_atomic_writer.js && node dist/test_mission_checkpoint.js && node dist/test_workflow_parser.js && node dist/test_workflow_engine.js && node dist/test_workflow_e2e.js && node dist/test_distributed_lock.js && node dist/test_watchdog_heartbeat.js && node dist/test_runtime_health_backoff.js && node dist/test_queue_scheduler.js && node dist/test_squad_skill_creator.js && node dist/test_aiobuilder_cli_parity.js && node dist/test_catalog_quality.js && node dist/test_royal_stack_golden.js && node dist/test_capability_pack_schema.js && node dist/test_capability_genesis_engine.js && node dist/test_workflow_schema_backward_compat.js && node dist/test_service_mode_explicit_only.js && node dist/test_deep_research_capability.js && node dist/test_guided_creator_cli.js && node dist/test_governance_v13_policies.js && node dist/test_gateway_telegram_guardrails.js && node dist/test_cron_manager.js && node dist/test_profile_toolset_mcp.js && node dist/test_squad_skill_design_llm.js && node dist/test_workflow_condition_parser.js && node dist/test_security_download_and_scan.js && node dist/test_host_installers_gemini_codex.js && node dist/test_toolset_enforcement.js && node dist/test_creator_placeholders_completed.js && node dist/test_performance_latency.js && node dist/test_post_mission_evaluation.js && node dist/test_governance_scope_ledger.js && node dist/test_consequence_forecast_brain.js && node dist/test_remote_publish.js && node dist/test_process_sandbox.js && node dist/test_v15_e2e_integration.js && node dist/test_doctor_sandbox_check.js && node dist/test_task_executor_sandbox_optin.js && node dist/test_forecast_brain_wiring.js && node dist/test_status_command.js && node dist/test_logs_command.js",
161
163
  "prepublishOnly": "npm run test:all"
162
164
  },
163
165
  "dependencies": {