@openlife/cli 1.7.6 → 1.7.9

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
+ }