@poa-box/agent 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.agent.template +20 -0
- package/README.md +46 -0
- package/brain/Config/agent-config.json +14 -0
- package/brain/Config/brain-allowlist.json +20 -0
- package/brain/Identity/goals.template.md +23 -0
- package/brain/Identity/how-i-think.md +406 -0
- package/brain/Identity/who-i-am.template.md +34 -0
- package/brain/Knowledge/BOOTSTRAP.md +66 -0
- package/brain/Knowledge/audit-corpus-index.json +406 -0
- package/brain/Knowledge/discussions.json +245 -0
- package/brain/Knowledge/pop.brain.brainstorms.generated.md +48 -0
- package/brain/Knowledge/pop.brain.brainstorms.genesis.bin +0 -0
- package/brain/Knowledge/pop.brain.heuristics.snapshot.bin +0 -0
- package/brain/Knowledge/pop.brain.projects.generated.md +16 -0
- package/brain/Knowledge/pop.brain.projects.genesis.bin +0 -0
- package/brain/Knowledge/pop.brain.retros.generated.md +91 -0
- package/brain/Knowledge/pop.brain.retros.genesis.bin +0 -0
- package/brain/Knowledge/pop.brain.shared.generated.md +3811 -0
- package/brain/Knowledge/pop.brain.shared.genesis.bin +0 -0
- package/brain/Knowledge/projects.md +181 -0
- package/brain/Knowledge/risk-framework.md +90 -0
- package/brain/Knowledge/shared.md +416 -0
- package/brain/Knowledge/sprint-priorities.md +439 -0
- package/brain/Memory/.gitkeep +0 -0
- package/dist/commands/agent/daily-digest.d.ts +24 -0
- package/dist/commands/agent/daily-digest.js +336 -0
- package/dist/commands/agent/delegate.d.ts +12 -0
- package/dist/commands/agent/delegate.js +91 -0
- package/dist/commands/agent/deploy-to-org.d.ts +20 -0
- package/dist/commands/agent/deploy-to-org.js +154 -0
- package/dist/commands/agent/index.d.ts +2 -0
- package/dist/commands/agent/index.js +27 -0
- package/dist/commands/agent/init.d.ts +19 -0
- package/dist/commands/agent/init.js +303 -0
- package/dist/commands/agent/onboard.d.ts +22 -0
- package/dist/commands/agent/onboard.js +192 -0
- package/dist/commands/agent/paymaster-status.d.ts +14 -0
- package/dist/commands/agent/paymaster-status.js +130 -0
- package/dist/commands/agent/register.d.ts +21 -0
- package/dist/commands/agent/register.js +116 -0
- package/dist/commands/agent/setup-sponsorship.d.ts +22 -0
- package/dist/commands/agent/setup-sponsorship.js +154 -0
- package/dist/commands/agent/status.d.ts +12 -0
- package/dist/commands/agent/status.js +171 -0
- package/dist/commands/agent/triage.d.ts +12 -0
- package/dist/commands/agent/triage.js +503 -0
- package/dist/commands/brain/advance-stage.d.ts +42 -0
- package/dist/commands/brain/advance-stage.js +206 -0
- package/dist/commands/brain/allowlist.d.ts +30 -0
- package/dist/commands/brain/allowlist.js +274 -0
- package/dist/commands/brain/append-lesson.d.ts +55 -0
- package/dist/commands/brain/append-lesson.js +245 -0
- package/dist/commands/brain/brainstorm.d.ts +154 -0
- package/dist/commands/brain/brainstorm.js +573 -0
- package/dist/commands/brain/daemon.d.ts +31 -0
- package/dist/commands/brain/daemon.js +348 -0
- package/dist/commands/brain/doctor.d.ts +27 -0
- package/dist/commands/brain/doctor.js +497 -0
- package/dist/commands/brain/edit-lesson.d.ts +51 -0
- package/dist/commands/brain/edit-lesson.js +248 -0
- package/dist/commands/brain/import-snapshot.d.ts +68 -0
- package/dist/commands/brain/import-snapshot.js +177 -0
- package/dist/commands/brain/index.d.ts +2 -0
- package/dist/commands/brain/index.js +67 -0
- package/dist/commands/brain/list.d.ts +21 -0
- package/dist/commands/brain/list.js +83 -0
- package/dist/commands/brain/migrate-projects.d.ts +44 -0
- package/dist/commands/brain/migrate-projects.js +209 -0
- package/dist/commands/brain/migrate.d.ts +74 -0
- package/dist/commands/brain/migrate.js +306 -0
- package/dist/commands/brain/new-project.d.ts +53 -0
- package/dist/commands/brain/new-project.js +226 -0
- package/dist/commands/brain/read.d.ts +24 -0
- package/dist/commands/brain/read.js +81 -0
- package/dist/commands/brain/remove-lesson.d.ts +47 -0
- package/dist/commands/brain/remove-lesson.js +206 -0
- package/dist/commands/brain/remove-project.d.ts +36 -0
- package/dist/commands/brain/remove-project.js +177 -0
- package/dist/commands/brain/retro-file-tasks.d.ts +84 -0
- package/dist/commands/brain/retro-file-tasks.js +372 -0
- package/dist/commands/brain/retro-list.d.ts +28 -0
- package/dist/commands/brain/retro-list.js +125 -0
- package/dist/commands/brain/retro-mark-change.d.ts +58 -0
- package/dist/commands/brain/retro-mark-change.js +176 -0
- package/dist/commands/brain/retro-remove.d.ts +36 -0
- package/dist/commands/brain/retro-remove.js +142 -0
- package/dist/commands/brain/retro-respond.d.ts +56 -0
- package/dist/commands/brain/retro-respond.js +250 -0
- package/dist/commands/brain/retro-show.d.ts +23 -0
- package/dist/commands/brain/retro-show.js +100 -0
- package/dist/commands/brain/retro-start.d.ts +55 -0
- package/dist/commands/brain/retro-start.js +311 -0
- package/dist/commands/brain/search.d.ts +48 -0
- package/dist/commands/brain/search.js +190 -0
- package/dist/commands/brain/snapshot.d.ts +32 -0
- package/dist/commands/brain/snapshot.js +243 -0
- package/dist/commands/brain/status.d.ts +15 -0
- package/dist/commands/brain/status.js +166 -0
- package/dist/commands/brain/subscribe.d.ts +28 -0
- package/dist/commands/brain/subscribe.js +90 -0
- package/dist/commands/brain/tag.d.ts +46 -0
- package/dist/commands/brain/tag.js +192 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +22 -0
- package/dist/lib/brain-daemon.d.ts +126 -0
- package/dist/lib/brain-daemon.js +811 -0
- package/dist/lib/brain-membership.d.ts +58 -0
- package/dist/lib/brain-membership.js +115 -0
- package/dist/lib/brain-migrate-projects.d.ts +43 -0
- package/dist/lib/brain-migrate-projects.js +247 -0
- package/dist/lib/brain-migrate.d.ts +77 -0
- package/dist/lib/brain-migrate.js +328 -0
- package/dist/lib/brain-ops.d.ts +271 -0
- package/dist/lib/brain-ops.js +571 -0
- package/dist/lib/brain-paths.d.ts +15 -0
- package/dist/lib/brain-paths.js +33 -0
- package/dist/lib/brain-projections.d.ts +216 -0
- package/dist/lib/brain-projections.js +829 -0
- package/dist/lib/brain-schemas.d.ts +36 -0
- package/dist/lib/brain-schemas.js +316 -0
- package/dist/lib/brain-signing.d.ts +103 -0
- package/dist/lib/brain-signing.js +256 -0
- package/dist/lib/brain.d.ts +198 -0
- package/dist/lib/brain.js +1057 -0
- package/dist/pop-agent.d.ts +1 -0
- package/dist/pop-agent.js +18 -0
- package/docs/agent.md +126 -0
- package/docs/agents/brain-anti-entropy.md +127 -0
- package/docs/agents/brain-cross-device-onboarding.md +210 -0
- package/docs/agents/brain-cross-machine-smoke.md +241 -0
- package/docs/agents/brain-layer-setup.md +725 -0
- package/docs/agents/offboarding-protocol.md +188 -0
- package/docs/agents/onboarding-protocol.md +243 -0
- package/docs/agents/running-an-agent.md +200 -0
- package/docs/brain.md +560 -0
- package/package.json +61 -0
- package/scripts/apply.sh +140 -0
- package/scripts/onboard.sh +205 -0
- package/scripts/setup-agent.ts +272 -0
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* pop brain daemon — process control for the persistent brain daemon
|
|
4
|
+
* (HB#322 architecture: go-ds-crdt-shaped rebroadcast + keepalive loop,
|
|
5
|
+
* see src/lib/brain-daemon.ts for the full design rationale).
|
|
6
|
+
*
|
|
7
|
+
* Subcommands:
|
|
8
|
+
* start spawn a detached daemon child
|
|
9
|
+
* stop signal a running daemon to shut down gracefully
|
|
10
|
+
* status print daemon stats (peer count, topics, uptime, rebroadcast
|
|
11
|
+
* counts) via IPC
|
|
12
|
+
* logs tail the daemon log file
|
|
13
|
+
* __run internal — the actual daemon entrypoint. Never call directly
|
|
14
|
+
* from the shell; start uses this.
|
|
15
|
+
*/
|
|
16
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
19
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
20
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
21
|
+
}
|
|
22
|
+
Object.defineProperty(o, k2, desc);
|
|
23
|
+
}) : (function(o, m, k, k2) {
|
|
24
|
+
if (k2 === undefined) k2 = k;
|
|
25
|
+
o[k2] = m[k];
|
|
26
|
+
}));
|
|
27
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
28
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
29
|
+
}) : function(o, v) {
|
|
30
|
+
o["default"] = v;
|
|
31
|
+
});
|
|
32
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
33
|
+
var ownKeys = function(o) {
|
|
34
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
35
|
+
var ar = [];
|
|
36
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
37
|
+
return ar;
|
|
38
|
+
};
|
|
39
|
+
return ownKeys(o);
|
|
40
|
+
};
|
|
41
|
+
return function (mod) {
|
|
42
|
+
if (mod && mod.__esModule) return mod;
|
|
43
|
+
var result = {};
|
|
44
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
45
|
+
__setModuleDefault(result, mod);
|
|
46
|
+
return result;
|
|
47
|
+
};
|
|
48
|
+
})();
|
|
49
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
+
exports.daemonHandler = void 0;
|
|
51
|
+
const child_process_1 = require("child_process");
|
|
52
|
+
const fs_1 = require("fs");
|
|
53
|
+
const brain_daemon_1 = require("../../lib/brain-daemon");
|
|
54
|
+
const brain_1 = require("../../lib/brain");
|
|
55
|
+
const output = __importStar(require("@poa-box/cli/lib/output"));
|
|
56
|
+
async function handleStart() {
|
|
57
|
+
const existing = (0, brain_daemon_1.getRunningDaemonPid)();
|
|
58
|
+
if (existing !== null) {
|
|
59
|
+
if (output.isJsonMode()) {
|
|
60
|
+
output.json({
|
|
61
|
+
status: 'already-running',
|
|
62
|
+
pid: existing,
|
|
63
|
+
pidPath: (0, brain_daemon_1.getDaemonPidPath)(),
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
console.log(`Brain daemon already running with PID ${existing}`);
|
|
68
|
+
console.log(` pid file: ${(0, brain_daemon_1.getDaemonPidPath)()}`);
|
|
69
|
+
console.log(` socket: ${(0, brain_daemon_1.getDaemonSockPath)()}`);
|
|
70
|
+
console.log(` log: ${(0, brain_daemon_1.getDaemonLogPath)()}`);
|
|
71
|
+
}
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
// Determine the path to our own CLI entrypoint so the detached child
|
|
75
|
+
// can run the __run subcommand. We use process.argv[1] when it points
|
|
76
|
+
// at dist/index.js, else fall back to the canonical path.
|
|
77
|
+
const selfScript = process.argv[1];
|
|
78
|
+
const child = (0, child_process_1.spawn)(process.execPath, // node itself
|
|
79
|
+
[selfScript, 'brain', 'daemon', '__run'], {
|
|
80
|
+
detached: true,
|
|
81
|
+
stdio: 'ignore',
|
|
82
|
+
// Forward critical env so the child has the same wallet / brain home.
|
|
83
|
+
env: process.env,
|
|
84
|
+
});
|
|
85
|
+
child.unref();
|
|
86
|
+
// Poll the PID file for up to 5s to confirm the daemon actually came up.
|
|
87
|
+
// Without this the user gets "started" for a process that crashed at init.
|
|
88
|
+
const pidPath = (0, brain_daemon_1.getDaemonPidPath)();
|
|
89
|
+
const startedAt = Date.now();
|
|
90
|
+
let pid = null;
|
|
91
|
+
while (Date.now() - startedAt < 5000) {
|
|
92
|
+
if ((0, fs_1.existsSync)(pidPath)) {
|
|
93
|
+
try {
|
|
94
|
+
pid = parseInt((0, fs_1.readFileSync)(pidPath, 'utf8').trim(), 10);
|
|
95
|
+
if (Number.isFinite(pid) && pid > 0)
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
catch { }
|
|
99
|
+
}
|
|
100
|
+
await new Promise(r => setTimeout(r, 100));
|
|
101
|
+
}
|
|
102
|
+
if (!pid) {
|
|
103
|
+
if (output.isJsonMode()) {
|
|
104
|
+
output.json({
|
|
105
|
+
status: 'error',
|
|
106
|
+
reason: 'daemon did not write PID file within 5s — check log',
|
|
107
|
+
logPath: (0, brain_daemon_1.getDaemonLogPath)(),
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
console.error(`Brain daemon failed to start within 5s.`);
|
|
112
|
+
console.error(`Check the log: ${(0, brain_daemon_1.getDaemonLogPath)()}`);
|
|
113
|
+
}
|
|
114
|
+
process.exitCode = 1;
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (output.isJsonMode()) {
|
|
118
|
+
output.json({
|
|
119
|
+
status: 'started',
|
|
120
|
+
pid,
|
|
121
|
+
pidPath,
|
|
122
|
+
sockPath: (0, brain_daemon_1.getDaemonSockPath)(),
|
|
123
|
+
logPath: (0, brain_daemon_1.getDaemonLogPath)(),
|
|
124
|
+
rebroadcastIntervalMs: brain_daemon_1.REBROADCAST_INTERVAL_MS,
|
|
125
|
+
keepaliveIntervalMs: brain_daemon_1.KEEPALIVE_INTERVAL_MS,
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
console.log(`Brain daemon started`);
|
|
130
|
+
console.log(` PID: ${pid}`);
|
|
131
|
+
console.log(` brain home: ${(0, brain_1.getBrainHome)()}`);
|
|
132
|
+
console.log(` pid file: ${pidPath}`);
|
|
133
|
+
console.log(` socket: ${(0, brain_daemon_1.getDaemonSockPath)()}`);
|
|
134
|
+
console.log(` log: ${(0, brain_daemon_1.getDaemonLogPath)()}`);
|
|
135
|
+
console.log(` rebroadcast: ${brain_daemon_1.REBROADCAST_INTERVAL_MS / 1000}s`);
|
|
136
|
+
console.log(` keepalive: ${brain_daemon_1.KEEPALIVE_INTERVAL_MS / 1000}s`);
|
|
137
|
+
console.log(``);
|
|
138
|
+
console.log(`Verify with: pop brain daemon status`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
async function handleStop() {
|
|
142
|
+
const pid = (0, brain_daemon_1.getRunningDaemonPid)();
|
|
143
|
+
if (pid === null) {
|
|
144
|
+
if (output.isJsonMode()) {
|
|
145
|
+
output.json({ status: 'not-running' });
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
console.log('Brain daemon is not running.');
|
|
149
|
+
}
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
try {
|
|
153
|
+
process.kill(pid, 'SIGTERM');
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
if (output.isJsonMode()) {
|
|
157
|
+
output.json({ status: 'error', reason: err.message, pid });
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
console.error(`Failed to signal PID ${pid}: ${err.message}`);
|
|
161
|
+
}
|
|
162
|
+
process.exitCode = 1;
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
// Wait up to 10s for the PID file to disappear (daemon's own cleanup).
|
|
166
|
+
const started = Date.now();
|
|
167
|
+
while (Date.now() - started < 10_000) {
|
|
168
|
+
if ((0, brain_daemon_1.getRunningDaemonPid)() === null)
|
|
169
|
+
break;
|
|
170
|
+
await new Promise(r => setTimeout(r, 100));
|
|
171
|
+
}
|
|
172
|
+
const stillRunning = (0, brain_daemon_1.getRunningDaemonPid)();
|
|
173
|
+
if (stillRunning !== null) {
|
|
174
|
+
if (output.isJsonMode()) {
|
|
175
|
+
output.json({
|
|
176
|
+
status: 'error',
|
|
177
|
+
reason: `daemon still running after SIGTERM + 10s — may need SIGKILL`,
|
|
178
|
+
pid: stillRunning,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
console.error(`Daemon still running after SIGTERM + 10s (PID ${stillRunning}).`);
|
|
183
|
+
console.error(`Force-kill with: kill -9 ${stillRunning}`);
|
|
184
|
+
}
|
|
185
|
+
process.exitCode = 1;
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (output.isJsonMode()) {
|
|
189
|
+
output.json({ status: 'stopped', pid });
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
console.log(`Brain daemon stopped (was PID ${pid}).`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
async function handleStatus() {
|
|
196
|
+
const pid = (0, brain_daemon_1.getRunningDaemonPid)();
|
|
197
|
+
if (pid === null) {
|
|
198
|
+
if (output.isJsonMode()) {
|
|
199
|
+
output.json({ status: 'not-running' });
|
|
200
|
+
}
|
|
201
|
+
else {
|
|
202
|
+
console.log('Brain daemon is not running.');
|
|
203
|
+
console.log('Start it with: pop brain daemon start');
|
|
204
|
+
}
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
let ipcResult;
|
|
208
|
+
try {
|
|
209
|
+
ipcResult = await (0, brain_daemon_1.sendIpcRequest)('status', {}, 3000);
|
|
210
|
+
}
|
|
211
|
+
catch (err) {
|
|
212
|
+
if (output.isJsonMode()) {
|
|
213
|
+
output.json({
|
|
214
|
+
status: 'ipc-error',
|
|
215
|
+
pid,
|
|
216
|
+
reason: err.message,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
console.error(`Daemon PID ${pid} is alive but IPC failed: ${err.message}`);
|
|
221
|
+
console.error(`Check log: ${(0, brain_daemon_1.getDaemonLogPath)()}`);
|
|
222
|
+
}
|
|
223
|
+
process.exitCode = 1;
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
if (output.isJsonMode()) {
|
|
227
|
+
output.json({
|
|
228
|
+
status: 'running',
|
|
229
|
+
pid,
|
|
230
|
+
...ipcResult,
|
|
231
|
+
});
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
const lastRebroadcast = ipcResult.lastRebroadcastAt
|
|
235
|
+
? new Date(ipcResult.lastRebroadcastAt).toISOString()
|
|
236
|
+
: 'never';
|
|
237
|
+
const lastKeepalive = ipcResult.lastKeepaliveAt
|
|
238
|
+
? new Date(ipcResult.lastKeepaliveAt).toISOString()
|
|
239
|
+
: 'never';
|
|
240
|
+
console.log(`Brain daemon running`);
|
|
241
|
+
console.log(` PID: ${pid}`);
|
|
242
|
+
console.log(` peer ID: ${ipcResult.peerId}`);
|
|
243
|
+
console.log(` uptime: ${ipcResult.uptime}s`);
|
|
244
|
+
console.log(` connections: ${ipcResult.connections}`);
|
|
245
|
+
console.log(` known peers: ${ipcResult.knownPeerCount}`);
|
|
246
|
+
console.log(` subscribed topics: ${ipcResult.topics?.length ?? 0}`);
|
|
247
|
+
if (ipcResult.topics?.length) {
|
|
248
|
+
for (const t of ipcResult.topics) {
|
|
249
|
+
console.log(` - ${t}`);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
console.log(` subscribed docs: ${ipcResult.subscribedDocs?.length ?? 0}`);
|
|
253
|
+
if (ipcResult.subscribedDocs?.length) {
|
|
254
|
+
for (const d of ipcResult.subscribedDocs) {
|
|
255
|
+
console.log(` - ${d}`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
console.log(` rebroadcast count: ${ipcResult.rebroadcastCount}`);
|
|
259
|
+
console.log(` last rebroadcast: ${lastRebroadcast}`);
|
|
260
|
+
console.log(` keepalive count: ${ipcResult.keepaliveCount}`);
|
|
261
|
+
console.log(` last keepalive: ${lastKeepalive}`);
|
|
262
|
+
console.log(` incoming announces: ${ipcResult.incomingAnnouncements}`);
|
|
263
|
+
console.log(` incoming merges: ${ipcResult.incomingMerges}`);
|
|
264
|
+
console.log(` incoming rejects: ${ipcResult.incomingRejects || 0}`);
|
|
265
|
+
console.log(` brain home: ${ipcResult.brainHome}`);
|
|
266
|
+
console.log(` log: ${ipcResult.logPath}`);
|
|
267
|
+
}
|
|
268
|
+
async function handleLogs(tail, follow) {
|
|
269
|
+
const logPath = (0, brain_daemon_1.getDaemonLogPath)();
|
|
270
|
+
if (!(0, fs_1.existsSync)(logPath)) {
|
|
271
|
+
console.error(`No daemon log at ${logPath}`);
|
|
272
|
+
process.exitCode = 1;
|
|
273
|
+
return;
|
|
274
|
+
}
|
|
275
|
+
// Minimal implementation: print last N lines. --follow uses tail -F.
|
|
276
|
+
if (follow) {
|
|
277
|
+
const { spawn: spawnFollow } = await Promise.resolve().then(() => __importStar(require('child_process')));
|
|
278
|
+
const proc = spawnFollow('tail', ['-F', '-n', String(tail), logPath], {
|
|
279
|
+
stdio: 'inherit',
|
|
280
|
+
});
|
|
281
|
+
await new Promise(r => proc.on('close', r));
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
const content = (0, fs_1.readFileSync)(logPath, 'utf8');
|
|
285
|
+
const lines = content.split('\n');
|
|
286
|
+
const slice = lines.slice(Math.max(0, lines.length - tail - 1));
|
|
287
|
+
console.log(slice.join('\n'));
|
|
288
|
+
}
|
|
289
|
+
async function handleRun() {
|
|
290
|
+
// This is the child process entrypoint. It blocks forever.
|
|
291
|
+
try {
|
|
292
|
+
await (0, brain_daemon_1.runDaemon)();
|
|
293
|
+
}
|
|
294
|
+
catch (err) {
|
|
295
|
+
// Write the error to the log file if we can; the parent process
|
|
296
|
+
// watches the PID file to detect failures.
|
|
297
|
+
const logPath = (0, brain_daemon_1.getDaemonLogPath)();
|
|
298
|
+
try {
|
|
299
|
+
const { appendFileSync } = await Promise.resolve().then(() => __importStar(require('fs')));
|
|
300
|
+
appendFileSync(logPath, `${new Date().toISOString()} FATAL ${err.stack ?? err.message}\n`);
|
|
301
|
+
}
|
|
302
|
+
catch { }
|
|
303
|
+
process.exit(1);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
exports.daemonHandler = {
|
|
307
|
+
builder: (yargs) => yargs
|
|
308
|
+
.positional('action', {
|
|
309
|
+
describe: 'Daemon action',
|
|
310
|
+
type: 'string',
|
|
311
|
+
choices: ['start', 'stop', 'status', 'logs', '__run'],
|
|
312
|
+
})
|
|
313
|
+
.option('follow', {
|
|
314
|
+
alias: 'f',
|
|
315
|
+
describe: 'Follow the log file (logs subcommand only)',
|
|
316
|
+
type: 'boolean',
|
|
317
|
+
default: false,
|
|
318
|
+
})
|
|
319
|
+
.option('tail', {
|
|
320
|
+
alias: 'n',
|
|
321
|
+
describe: 'Number of log lines to print (logs subcommand only)',
|
|
322
|
+
type: 'number',
|
|
323
|
+
default: 50,
|
|
324
|
+
}),
|
|
325
|
+
handler: async (argv) => {
|
|
326
|
+
const action = argv.action;
|
|
327
|
+
switch (action) {
|
|
328
|
+
case 'start':
|
|
329
|
+
await handleStart();
|
|
330
|
+
return;
|
|
331
|
+
case 'stop':
|
|
332
|
+
await handleStop();
|
|
333
|
+
return;
|
|
334
|
+
case 'status':
|
|
335
|
+
await handleStatus();
|
|
336
|
+
return;
|
|
337
|
+
case 'logs':
|
|
338
|
+
await handleLogs(argv.tail ?? 50, argv.follow ?? false);
|
|
339
|
+
return;
|
|
340
|
+
case '__run':
|
|
341
|
+
await handleRun();
|
|
342
|
+
return;
|
|
343
|
+
default:
|
|
344
|
+
output.error(`Unknown daemon action: ${action}`);
|
|
345
|
+
process.exitCode = 1;
|
|
346
|
+
}
|
|
347
|
+
},
|
|
348
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pop brain doctor — single-command health check for brain layer setup.
|
|
3
|
+
*
|
|
4
|
+
* Answers "is my brain setup healthy?" in one invocation. Complements
|
|
5
|
+
* `docs/agents/brain-layer-setup.md` (setup doc tells you HOW; doctor tells
|
|
6
|
+
* you IF the setup is actually working).
|
|
7
|
+
*
|
|
8
|
+
* Output shape:
|
|
9
|
+
* ✓ check name — pass
|
|
10
|
+
* ⚠ check name — warn (not fatal, but worth knowing)
|
|
11
|
+
* ✗ check name — fail (exit 1)
|
|
12
|
+
*
|
|
13
|
+
* Exit codes:
|
|
14
|
+
* 0 — all pass or pass+warn (warnings don't fail the run)
|
|
15
|
+
* 1 — any ✗ fail
|
|
16
|
+
*
|
|
17
|
+
* --json returns { checks: [{name, status, detail, elapsed?}], summary }
|
|
18
|
+
*
|
|
19
|
+
* Design: every check is self-contained and independent. A failure in
|
|
20
|
+
* one check does NOT stop later checks from running — the operator
|
|
21
|
+
* wants the full picture, not the first stumble.
|
|
22
|
+
*/
|
|
23
|
+
import type { Argv, ArgumentsCamelCase } from 'yargs';
|
|
24
|
+
export declare const doctorHandler: {
|
|
25
|
+
builder: (yargs: Argv) => Argv<{}>;
|
|
26
|
+
handler: (_argv: ArgumentsCamelCase<{}>) => Promise<void>;
|
|
27
|
+
};
|