@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,573 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* pop brain brainstorm-* — cross-agent ideation surface commands.
|
|
4
|
+
*
|
|
5
|
+
* Task #354 phase (b) (HB#208). Forward-looking companion to
|
|
6
|
+
* pop.brain.retros (reactive session retrospectives) and
|
|
7
|
+
* pop.brain.projects (lifecycle state machine for existing projects).
|
|
8
|
+
*
|
|
9
|
+
* The brainstorm surface is the missing deliberation primitive for
|
|
10
|
+
* new ideation: agents post a theme/question, debate it via messages +
|
|
11
|
+
* ideas + per-agent votes (support/explore/oppose), and top-ranked
|
|
12
|
+
* ideas get promoted to pop.brain.projects at the `propose` stage.
|
|
13
|
+
* Promotion links back via the `promotedToProjectIds` array.
|
|
14
|
+
*
|
|
15
|
+
* All commands dispatch through routedDispatch so they work with or
|
|
16
|
+
* without the brain daemon. Schema validation (#346) catches malformed
|
|
17
|
+
* writes at applyBrainChange time.
|
|
18
|
+
*
|
|
19
|
+
* Five sub-commands registered from src/commands/brain/index.ts:
|
|
20
|
+
* pop brain brainstorm-start — open a new brainstorm
|
|
21
|
+
* pop brain brainstorm-respond — post message / add idea / cast vote
|
|
22
|
+
* pop brain brainstorm-promote — promote an idea to a brain project
|
|
23
|
+
* pop brain brainstorm-close — close a brainstorm with no promotion
|
|
24
|
+
* pop brain brainstorm-remove — soft-delete tombstone
|
|
25
|
+
*/
|
|
26
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
27
|
+
if (k2 === undefined) k2 = k;
|
|
28
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
29
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
30
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
31
|
+
}
|
|
32
|
+
Object.defineProperty(o, k2, desc);
|
|
33
|
+
}) : (function(o, m, k, k2) {
|
|
34
|
+
if (k2 === undefined) k2 = k;
|
|
35
|
+
o[k2] = m[k];
|
|
36
|
+
}));
|
|
37
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
38
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
39
|
+
}) : function(o, v) {
|
|
40
|
+
o["default"] = v;
|
|
41
|
+
});
|
|
42
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
43
|
+
var ownKeys = function(o) {
|
|
44
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
45
|
+
var ar = [];
|
|
46
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
47
|
+
return ar;
|
|
48
|
+
};
|
|
49
|
+
return ownKeys(o);
|
|
50
|
+
};
|
|
51
|
+
return function (mod) {
|
|
52
|
+
if (mod && mod.__esModule) return mod;
|
|
53
|
+
var result = {};
|
|
54
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
55
|
+
__setModuleDefault(result, mod);
|
|
56
|
+
return result;
|
|
57
|
+
};
|
|
58
|
+
})();
|
|
59
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
60
|
+
exports.brainstormRemoveHandler = exports.brainstormCloseHandler = exports.brainstormPromoteHandler = exports.brainstormRespondHandler = exports.brainstormStartHandler = void 0;
|
|
61
|
+
const ethers_1 = require("ethers");
|
|
62
|
+
const brain_1 = require("../../lib/brain");
|
|
63
|
+
const brain_ops_1 = require("../../lib/brain-ops");
|
|
64
|
+
const idempotency_1 = require("@poa-box/cli/lib/idempotency");
|
|
65
|
+
const output = __importStar(require("@poa-box/cli/lib/output"));
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
// Shared helpers
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
function resolveAuthor(argvAuthor) {
|
|
70
|
+
if (argvAuthor)
|
|
71
|
+
return argvAuthor;
|
|
72
|
+
const key = process.env.POP_PRIVATE_KEY;
|
|
73
|
+
if (!key) {
|
|
74
|
+
throw new Error('POP_PRIVATE_KEY not set — cannot derive default author. Pass --author explicitly.');
|
|
75
|
+
}
|
|
76
|
+
return new ethers_1.ethers.Wallet(key).address.toLowerCase();
|
|
77
|
+
}
|
|
78
|
+
function slugify(s) {
|
|
79
|
+
return s
|
|
80
|
+
.toLowerCase()
|
|
81
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
82
|
+
.replace(/^-+|-+$/g, '')
|
|
83
|
+
.slice(0, 60);
|
|
84
|
+
}
|
|
85
|
+
exports.brainstormStartHandler = {
|
|
86
|
+
builder: (yargs) => yargs
|
|
87
|
+
.option('doc', {
|
|
88
|
+
describe: 'Brain document ID (default: pop.brain.brainstorms)',
|
|
89
|
+
type: 'string',
|
|
90
|
+
default: 'pop.brain.brainstorms',
|
|
91
|
+
})
|
|
92
|
+
.option('title', {
|
|
93
|
+
describe: 'Short brainstorm title (used as default slug for id)',
|
|
94
|
+
type: 'string',
|
|
95
|
+
demandOption: true,
|
|
96
|
+
})
|
|
97
|
+
.option('prompt', {
|
|
98
|
+
describe: 'Longer description / question being brainstormed',
|
|
99
|
+
type: 'string',
|
|
100
|
+
demandOption: true,
|
|
101
|
+
})
|
|
102
|
+
.option('author', {
|
|
103
|
+
describe: 'Override the author address (default: signing wallet)',
|
|
104
|
+
type: 'string',
|
|
105
|
+
})
|
|
106
|
+
.option('id', {
|
|
107
|
+
describe: 'Override the auto-generated brainstorm id',
|
|
108
|
+
type: 'string',
|
|
109
|
+
})
|
|
110
|
+
.option('window-from-hb', {
|
|
111
|
+
describe: 'Starting HB number of the brainstorm window',
|
|
112
|
+
type: 'number',
|
|
113
|
+
})
|
|
114
|
+
.option('window-to-hb', {
|
|
115
|
+
describe: 'Ending HB number of the brainstorm window',
|
|
116
|
+
type: 'number',
|
|
117
|
+
})
|
|
118
|
+
.option('idempotency-key', { type: 'string', describe: 'Task #375 (HB#217) idempotency cache.' })
|
|
119
|
+
.option('no-idempotency', { type: 'boolean', default: false, describe: 'Bypass the idempotency cache.' }),
|
|
120
|
+
handler: async (argv) => {
|
|
121
|
+
try {
|
|
122
|
+
const author = resolveAuthor(argv.author);
|
|
123
|
+
const now = Math.floor(Date.now() / 1000);
|
|
124
|
+
const id = argv.id ?? `${slugify(argv.title) || 'brainstorm'}-${now}`;
|
|
125
|
+
// Task #375 idempotency check, agent-scoped
|
|
126
|
+
const idempKey = argv.idempotencyKey || (0, idempotency_1.argvToIdempotencyString)(argv);
|
|
127
|
+
if (!argv.noIdempotency) {
|
|
128
|
+
const cached = (0, idempotency_1.checkIdempotencyCache)(author, 'brain.brainstormStart', idempKey);
|
|
129
|
+
if (cached) {
|
|
130
|
+
if (output.isJsonMode())
|
|
131
|
+
output.json({ status: 'ok', cached: true, ...cached });
|
|
132
|
+
else
|
|
133
|
+
console.log(` Brainstorm already opened (idempotency cache hit). id: ${cached.brainstormId} head: ${cached.headCid}`);
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const result = await (0, brain_ops_1.routedDispatch)({
|
|
138
|
+
type: 'startBrainstorm',
|
|
139
|
+
docId: argv.doc,
|
|
140
|
+
brainstormId: id,
|
|
141
|
+
title: argv.title,
|
|
142
|
+
prompt: argv.prompt,
|
|
143
|
+
author,
|
|
144
|
+
openedAt: now,
|
|
145
|
+
windowFromHB: argv.windowFromHb,
|
|
146
|
+
windowToHB: argv.windowToHb,
|
|
147
|
+
});
|
|
148
|
+
if (!argv.noIdempotency) {
|
|
149
|
+
(0, idempotency_1.recordIdempotentResult)(author, 'brain.brainstormStart', idempKey, {
|
|
150
|
+
docId: argv.doc,
|
|
151
|
+
brainstormId: id,
|
|
152
|
+
headCid: result.headCid,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
if (output.isJsonMode()) {
|
|
156
|
+
output.json({
|
|
157
|
+
status: 'ok',
|
|
158
|
+
docId: argv.doc,
|
|
159
|
+
brainstormId: id,
|
|
160
|
+
headCid: result.headCid,
|
|
161
|
+
author,
|
|
162
|
+
routedViaDaemon: result.routedViaDaemon,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
console.log('');
|
|
167
|
+
console.log(` Brainstorm opened in ${argv.doc}`);
|
|
168
|
+
console.log(` id: ${id}`);
|
|
169
|
+
console.log(` title: ${argv.title}`);
|
|
170
|
+
console.log(` author: ${author}`);
|
|
171
|
+
console.log(` head: ${result.headCid}`);
|
|
172
|
+
console.log(` routed: ${result.routedViaDaemon ? 'via brain daemon' : 'in-process (no daemon)'}`);
|
|
173
|
+
console.log('');
|
|
174
|
+
console.log(` Other agents respond via pop brain brainstorm-respond --id ${id} ` +
|
|
175
|
+
`[--message M] [--add-idea M] [--vote idea-id=stance].`);
|
|
176
|
+
console.log('');
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
catch (err) {
|
|
180
|
+
output.error(err.message);
|
|
181
|
+
process.exitCode = 1;
|
|
182
|
+
}
|
|
183
|
+
finally {
|
|
184
|
+
await (0, brain_1.stopBrainNode)();
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
};
|
|
188
|
+
exports.brainstormRespondHandler = {
|
|
189
|
+
builder: (yargs) => yargs
|
|
190
|
+
.option('doc', {
|
|
191
|
+
type: 'string',
|
|
192
|
+
default: 'pop.brain.brainstorms',
|
|
193
|
+
})
|
|
194
|
+
.option('id', {
|
|
195
|
+
describe: 'Brainstorm id to respond to',
|
|
196
|
+
type: 'string',
|
|
197
|
+
demandOption: true,
|
|
198
|
+
})
|
|
199
|
+
.option('author', {
|
|
200
|
+
describe: 'Override the author address',
|
|
201
|
+
type: 'string',
|
|
202
|
+
})
|
|
203
|
+
.option('message', {
|
|
204
|
+
describe: 'Free-form discussion message to post',
|
|
205
|
+
type: 'string',
|
|
206
|
+
})
|
|
207
|
+
.option('add-idea', {
|
|
208
|
+
describe: 'Add a new idea with this text (id auto-generated from a slug)',
|
|
209
|
+
type: 'string',
|
|
210
|
+
})
|
|
211
|
+
.option('vote', {
|
|
212
|
+
describe: 'Cast a vote: <idea-id>=<support|explore|oppose>. Repeatable.',
|
|
213
|
+
type: 'array',
|
|
214
|
+
string: true,
|
|
215
|
+
})
|
|
216
|
+
.option('idempotency-key', { type: 'string', describe: 'Task #375 (HB#217) idempotency cache.' })
|
|
217
|
+
.option('no-idempotency', { type: 'boolean', default: false, describe: 'Bypass the idempotency cache.' })
|
|
218
|
+
.check((argv) => {
|
|
219
|
+
if (!argv.message && !argv.addIdea && (!argv.vote || argv.vote.length === 0)) {
|
|
220
|
+
throw new Error('Must supply at least one of --message / --add-idea / --vote');
|
|
221
|
+
}
|
|
222
|
+
return true;
|
|
223
|
+
}),
|
|
224
|
+
handler: async (argv) => {
|
|
225
|
+
try {
|
|
226
|
+
const author = resolveAuthor(argv.author);
|
|
227
|
+
const now = Math.floor(Date.now() / 1000);
|
|
228
|
+
// Pre-flight lookup to fail fast with candidate ids if missing
|
|
229
|
+
const { doc: currentDoc } = await (0, brain_1.openBrainDoc)(argv.doc);
|
|
230
|
+
const brainstorms = Array.isArray(currentDoc?.brainstorms) ? currentDoc.brainstorms : [];
|
|
231
|
+
const target = brainstorms.find((b) => b && b.id === argv.id);
|
|
232
|
+
if (!target) {
|
|
233
|
+
const candidates = brainstorms
|
|
234
|
+
.map((b) => b?.id)
|
|
235
|
+
.filter((id) => typeof id === 'string')
|
|
236
|
+
.slice(0, 8);
|
|
237
|
+
output.error(`Brainstorm "${argv.id}" not found in ${argv.doc}. ` +
|
|
238
|
+
`Available ids (first 8): ${candidates.join(', ') || '(none)'}`);
|
|
239
|
+
process.exitCode = 1;
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
// Parse --vote entries into { ideaId: stance }
|
|
243
|
+
const votes = {};
|
|
244
|
+
for (const entry of argv.vote ?? []) {
|
|
245
|
+
const [ideaId, stance] = entry.split('=').map((s) => s.trim());
|
|
246
|
+
if (!ideaId || !stance) {
|
|
247
|
+
throw new Error(`Malformed --vote "${entry}" — expected format <idea-id>=<stance>`);
|
|
248
|
+
}
|
|
249
|
+
if (stance !== 'support' && stance !== 'explore' && stance !== 'oppose') {
|
|
250
|
+
throw new Error(`Invalid stance "${stance}" in --vote "${entry}" — must be support|explore|oppose`);
|
|
251
|
+
}
|
|
252
|
+
votes[ideaId] = stance;
|
|
253
|
+
}
|
|
254
|
+
// If adding an idea, generate a new idea id from a slug
|
|
255
|
+
let addIdeaPayload;
|
|
256
|
+
if (argv.addIdea) {
|
|
257
|
+
const ideaId = `${slugify(argv.addIdea) || 'idea'}-${now}`;
|
|
258
|
+
addIdeaPayload = { id: ideaId, message: argv.addIdea };
|
|
259
|
+
}
|
|
260
|
+
// Task #375 idempotency check, agent-scoped
|
|
261
|
+
const idempKey = argv.idempotencyKey || (0, idempotency_1.argvToIdempotencyString)(argv);
|
|
262
|
+
if (!argv.noIdempotency) {
|
|
263
|
+
const cached = (0, idempotency_1.checkIdempotencyCache)(author, 'brain.brainstormRespond', idempKey);
|
|
264
|
+
if (cached) {
|
|
265
|
+
if (output.isJsonMode())
|
|
266
|
+
output.json({ status: 'ok', cached: true, ...cached });
|
|
267
|
+
else
|
|
268
|
+
console.log(` Brainstorm response already recorded (idempotency cache hit). head: ${cached.headCid}`);
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
const result = await (0, brain_ops_1.routedDispatch)({
|
|
273
|
+
type: 'respondToBrainstorm',
|
|
274
|
+
docId: argv.doc,
|
|
275
|
+
brainstormId: argv.id,
|
|
276
|
+
author,
|
|
277
|
+
message: argv.message,
|
|
278
|
+
addIdea: addIdeaPayload,
|
|
279
|
+
votes: Object.keys(votes).length > 0 ? votes : undefined,
|
|
280
|
+
timestamp: now,
|
|
281
|
+
});
|
|
282
|
+
if (!argv.noIdempotency) {
|
|
283
|
+
(0, idempotency_1.recordIdempotentResult)(author, 'brain.brainstormRespond', idempKey, {
|
|
284
|
+
docId: argv.doc,
|
|
285
|
+
brainstormId: argv.id,
|
|
286
|
+
headCid: result.headCid,
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
if (output.isJsonMode()) {
|
|
290
|
+
output.json({
|
|
291
|
+
status: 'ok',
|
|
292
|
+
docId: argv.doc,
|
|
293
|
+
brainstormId: argv.id,
|
|
294
|
+
ideaAdded: addIdeaPayload?.id ?? null,
|
|
295
|
+
votesCast: Object.keys(votes),
|
|
296
|
+
message: argv.message ? 'posted' : null,
|
|
297
|
+
headCid: result.headCid,
|
|
298
|
+
author,
|
|
299
|
+
routedViaDaemon: result.routedViaDaemon,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
console.log('');
|
|
304
|
+
console.log(` Responded to brainstorm "${argv.id}" in ${argv.doc}`);
|
|
305
|
+
if (argv.message)
|
|
306
|
+
console.log(` message: posted`);
|
|
307
|
+
if (addIdeaPayload)
|
|
308
|
+
console.log(` new idea: ${addIdeaPayload.id}`);
|
|
309
|
+
if (Object.keys(votes).length > 0) {
|
|
310
|
+
console.log(` votes:`);
|
|
311
|
+
for (const [ideaId, stance] of Object.entries(votes)) {
|
|
312
|
+
console.log(` ${ideaId} = ${stance}`);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
console.log(` head: ${result.headCid}`);
|
|
316
|
+
console.log('');
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
catch (err) {
|
|
320
|
+
output.error(err.message);
|
|
321
|
+
process.exitCode = 1;
|
|
322
|
+
}
|
|
323
|
+
finally {
|
|
324
|
+
await (0, brain_1.stopBrainNode)();
|
|
325
|
+
}
|
|
326
|
+
},
|
|
327
|
+
};
|
|
328
|
+
exports.brainstormPromoteHandler = {
|
|
329
|
+
builder: (yargs) => yargs
|
|
330
|
+
.option('doc', {
|
|
331
|
+
type: 'string',
|
|
332
|
+
default: 'pop.brain.brainstorms',
|
|
333
|
+
})
|
|
334
|
+
.option('id', {
|
|
335
|
+
describe: 'Brainstorm id containing the idea to promote',
|
|
336
|
+
type: 'string',
|
|
337
|
+
demandOption: true,
|
|
338
|
+
})
|
|
339
|
+
.option('idea-id', {
|
|
340
|
+
describe: 'Idea id to promote to a brain project',
|
|
341
|
+
type: 'string',
|
|
342
|
+
demandOption: true,
|
|
343
|
+
})
|
|
344
|
+
.option('project-id', {
|
|
345
|
+
describe: 'Existing pop.brain.projects id to link to (create the project via `pop brain new-project` first)',
|
|
346
|
+
type: 'string',
|
|
347
|
+
demandOption: true,
|
|
348
|
+
})
|
|
349
|
+
.option('author', {
|
|
350
|
+
describe: 'Override the author address',
|
|
351
|
+
type: 'string',
|
|
352
|
+
})
|
|
353
|
+
.option('idempotency-key', { type: 'string', describe: 'Task #375 (HB#217) idempotency cache.' })
|
|
354
|
+
.option('no-idempotency', { type: 'boolean', default: false, describe: 'Bypass the idempotency cache.' }),
|
|
355
|
+
handler: async (argv) => {
|
|
356
|
+
try {
|
|
357
|
+
const author = resolveAuthor(argv.author);
|
|
358
|
+
const now = Math.floor(Date.now() / 1000);
|
|
359
|
+
const idempKey = argv.idempotencyKey || (0, idempotency_1.argvToIdempotencyString)(argv);
|
|
360
|
+
if (!argv.noIdempotency) {
|
|
361
|
+
const cached = (0, idempotency_1.checkIdempotencyCache)(author, 'brain.brainstormPromote', idempKey);
|
|
362
|
+
if (cached) {
|
|
363
|
+
if (output.isJsonMode())
|
|
364
|
+
output.json({ status: 'ok', cached: true, ...cached });
|
|
365
|
+
else
|
|
366
|
+
console.log(` Idea already promoted (idempotency cache hit). head: ${cached.headCid}`);
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
const result = await (0, brain_ops_1.routedDispatch)({
|
|
371
|
+
type: 'promoteIdea',
|
|
372
|
+
docId: argv.doc,
|
|
373
|
+
brainstormId: argv.id,
|
|
374
|
+
ideaId: argv.ideaId,
|
|
375
|
+
promotedProjectId: argv.projectId,
|
|
376
|
+
promotedBy: author,
|
|
377
|
+
promotedAt: now,
|
|
378
|
+
});
|
|
379
|
+
if (!argv.noIdempotency) {
|
|
380
|
+
(0, idempotency_1.recordIdempotentResult)(author, 'brain.brainstormPromote', idempKey, {
|
|
381
|
+
docId: argv.doc,
|
|
382
|
+
brainstormId: argv.id,
|
|
383
|
+
ideaId: argv.ideaId,
|
|
384
|
+
headCid: result.headCid,
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
if (output.isJsonMode()) {
|
|
388
|
+
output.json({
|
|
389
|
+
status: 'ok',
|
|
390
|
+
docId: argv.doc,
|
|
391
|
+
brainstormId: argv.id,
|
|
392
|
+
ideaId: argv.ideaId,
|
|
393
|
+
promotedProjectId: argv.projectId,
|
|
394
|
+
headCid: result.headCid,
|
|
395
|
+
author,
|
|
396
|
+
routedViaDaemon: result.routedViaDaemon,
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
console.log('');
|
|
401
|
+
console.log(` Idea "${argv.ideaId}" promoted from brainstorm "${argv.id}" to project "${argv.projectId}"`);
|
|
402
|
+
console.log(` promotedBy: ${author}`);
|
|
403
|
+
console.log(` head: ${result.headCid}`);
|
|
404
|
+
console.log('');
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
catch (err) {
|
|
408
|
+
output.error(err.message);
|
|
409
|
+
process.exitCode = 1;
|
|
410
|
+
}
|
|
411
|
+
finally {
|
|
412
|
+
await (0, brain_1.stopBrainNode)();
|
|
413
|
+
}
|
|
414
|
+
},
|
|
415
|
+
};
|
|
416
|
+
exports.brainstormCloseHandler = {
|
|
417
|
+
builder: (yargs) => yargs
|
|
418
|
+
.option('doc', {
|
|
419
|
+
type: 'string',
|
|
420
|
+
default: 'pop.brain.brainstorms',
|
|
421
|
+
})
|
|
422
|
+
.option('id', {
|
|
423
|
+
describe: 'Brainstorm id to close',
|
|
424
|
+
type: 'string',
|
|
425
|
+
demandOption: true,
|
|
426
|
+
})
|
|
427
|
+
.option('reason', {
|
|
428
|
+
describe: 'Reason for closing without promoting',
|
|
429
|
+
type: 'string',
|
|
430
|
+
})
|
|
431
|
+
.option('author', {
|
|
432
|
+
type: 'string',
|
|
433
|
+
})
|
|
434
|
+
.option('idempotency-key', { type: 'string', describe: 'Task #375 (HB#217) idempotency cache.' })
|
|
435
|
+
.option('no-idempotency', { type: 'boolean', default: false, describe: 'Bypass the idempotency cache.' }),
|
|
436
|
+
handler: async (argv) => {
|
|
437
|
+
try {
|
|
438
|
+
const author = resolveAuthor(argv.author);
|
|
439
|
+
const now = Math.floor(Date.now() / 1000);
|
|
440
|
+
const idempKey = argv.idempotencyKey || (0, idempotency_1.argvToIdempotencyString)(argv);
|
|
441
|
+
if (!argv.noIdempotency) {
|
|
442
|
+
const cached = (0, idempotency_1.checkIdempotencyCache)(author, 'brain.brainstormClose', idempKey);
|
|
443
|
+
if (cached) {
|
|
444
|
+
if (output.isJsonMode())
|
|
445
|
+
output.json({ status: 'ok', cached: true, ...cached });
|
|
446
|
+
else
|
|
447
|
+
console.log(` Brainstorm "${argv.id}" already closed (idempotency cache hit). head: ${cached.headCid}`);
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
const result = await (0, brain_ops_1.routedDispatch)({
|
|
452
|
+
type: 'closeBrainstorm',
|
|
453
|
+
docId: argv.doc,
|
|
454
|
+
brainstormId: argv.id,
|
|
455
|
+
closedBy: author,
|
|
456
|
+
closedAt: now,
|
|
457
|
+
reason: argv.reason,
|
|
458
|
+
});
|
|
459
|
+
if (!argv.noIdempotency) {
|
|
460
|
+
(0, idempotency_1.recordIdempotentResult)(author, 'brain.brainstormClose', idempKey, {
|
|
461
|
+
docId: argv.doc,
|
|
462
|
+
brainstormId: argv.id,
|
|
463
|
+
headCid: result.headCid,
|
|
464
|
+
});
|
|
465
|
+
}
|
|
466
|
+
if (output.isJsonMode()) {
|
|
467
|
+
output.json({
|
|
468
|
+
status: 'ok',
|
|
469
|
+
docId: argv.doc,
|
|
470
|
+
brainstormId: argv.id,
|
|
471
|
+
headCid: result.headCid,
|
|
472
|
+
author,
|
|
473
|
+
routedViaDaemon: result.routedViaDaemon,
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
else {
|
|
477
|
+
console.log('');
|
|
478
|
+
console.log(` Brainstorm "${argv.id}" closed in ${argv.doc}`);
|
|
479
|
+
console.log(` closedBy: ${author}`);
|
|
480
|
+
if (argv.reason)
|
|
481
|
+
console.log(` reason: ${argv.reason}`);
|
|
482
|
+
console.log(` head: ${result.headCid}`);
|
|
483
|
+
console.log('');
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
catch (err) {
|
|
487
|
+
output.error(err.message);
|
|
488
|
+
process.exitCode = 1;
|
|
489
|
+
}
|
|
490
|
+
finally {
|
|
491
|
+
await (0, brain_1.stopBrainNode)();
|
|
492
|
+
}
|
|
493
|
+
},
|
|
494
|
+
};
|
|
495
|
+
exports.brainstormRemoveHandler = {
|
|
496
|
+
builder: (yargs) => yargs
|
|
497
|
+
.option('doc', {
|
|
498
|
+
type: 'string',
|
|
499
|
+
default: 'pop.brain.brainstorms',
|
|
500
|
+
})
|
|
501
|
+
.option('id', {
|
|
502
|
+
describe: 'Brainstorm id to soft-delete',
|
|
503
|
+
type: 'string',
|
|
504
|
+
demandOption: true,
|
|
505
|
+
})
|
|
506
|
+
.option('reason', {
|
|
507
|
+
describe: 'Removal reason',
|
|
508
|
+
type: 'string',
|
|
509
|
+
})
|
|
510
|
+
.option('author', {
|
|
511
|
+
type: 'string',
|
|
512
|
+
})
|
|
513
|
+
.option('idempotency-key', { type: 'string', describe: 'Task #375 (HB#217) idempotency cache.' })
|
|
514
|
+
.option('no-idempotency', { type: 'boolean', default: false, describe: 'Bypass the idempotency cache.' }),
|
|
515
|
+
handler: async (argv) => {
|
|
516
|
+
try {
|
|
517
|
+
const author = resolveAuthor(argv.author);
|
|
518
|
+
const now = Math.floor(Date.now() / 1000);
|
|
519
|
+
const idempKey = argv.idempotencyKey || (0, idempotency_1.argvToIdempotencyString)(argv);
|
|
520
|
+
if (!argv.noIdempotency) {
|
|
521
|
+
const cached = (0, idempotency_1.checkIdempotencyCache)(author, 'brain.brainstormRemove', idempKey);
|
|
522
|
+
if (cached) {
|
|
523
|
+
if (output.isJsonMode())
|
|
524
|
+
output.json({ status: 'ok', cached: true, ...cached });
|
|
525
|
+
else
|
|
526
|
+
console.log(` Brainstorm "${argv.id}" already removed (idempotency cache hit). head: ${cached.headCid}`);
|
|
527
|
+
return;
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
const result = await (0, brain_ops_1.routedDispatch)({
|
|
531
|
+
type: 'removeBrainstorm',
|
|
532
|
+
docId: argv.doc,
|
|
533
|
+
brainstormId: argv.id,
|
|
534
|
+
removedBy: author,
|
|
535
|
+
removedAt: now,
|
|
536
|
+
removedReason: argv.reason,
|
|
537
|
+
});
|
|
538
|
+
if (!argv.noIdempotency) {
|
|
539
|
+
(0, idempotency_1.recordIdempotentResult)(author, 'brain.brainstormRemove', idempKey, {
|
|
540
|
+
docId: argv.doc,
|
|
541
|
+
brainstormId: argv.id,
|
|
542
|
+
headCid: result.headCid,
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
if (output.isJsonMode()) {
|
|
546
|
+
output.json({
|
|
547
|
+
status: 'ok',
|
|
548
|
+
docId: argv.doc,
|
|
549
|
+
brainstormId: argv.id,
|
|
550
|
+
headCid: result.headCid,
|
|
551
|
+
author,
|
|
552
|
+
routedViaDaemon: result.routedViaDaemon,
|
|
553
|
+
});
|
|
554
|
+
}
|
|
555
|
+
else {
|
|
556
|
+
console.log('');
|
|
557
|
+
console.log(` Brainstorm "${argv.id}" soft-deleted in ${argv.doc}`);
|
|
558
|
+
console.log(` removedBy: ${author}`);
|
|
559
|
+
if (argv.reason)
|
|
560
|
+
console.log(` reason: ${argv.reason}`);
|
|
561
|
+
console.log(` head: ${result.headCid}`);
|
|
562
|
+
console.log('');
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
catch (err) {
|
|
566
|
+
output.error(err.message);
|
|
567
|
+
process.exitCode = 1;
|
|
568
|
+
}
|
|
569
|
+
finally {
|
|
570
|
+
await (0, brain_1.stopBrainNode)();
|
|
571
|
+
}
|
|
572
|
+
},
|
|
573
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pop brain daemon — process control for the persistent brain daemon
|
|
3
|
+
* (HB#322 architecture: go-ds-crdt-shaped rebroadcast + keepalive loop,
|
|
4
|
+
* see src/lib/brain-daemon.ts for the full design rationale).
|
|
5
|
+
*
|
|
6
|
+
* Subcommands:
|
|
7
|
+
* start spawn a detached daemon child
|
|
8
|
+
* stop signal a running daemon to shut down gracefully
|
|
9
|
+
* status print daemon stats (peer count, topics, uptime, rebroadcast
|
|
10
|
+
* counts) via IPC
|
|
11
|
+
* logs tail the daemon log file
|
|
12
|
+
* __run internal — the actual daemon entrypoint. Never call directly
|
|
13
|
+
* from the shell; start uses this.
|
|
14
|
+
*/
|
|
15
|
+
import type { Argv, ArgumentsCamelCase } from 'yargs';
|
|
16
|
+
interface DaemonArgs {
|
|
17
|
+
action: 'start' | 'stop' | 'status' | 'logs' | '__run';
|
|
18
|
+
follow?: boolean;
|
|
19
|
+
tail?: number;
|
|
20
|
+
}
|
|
21
|
+
export declare const daemonHandler: {
|
|
22
|
+
builder: (yargs: Argv) => Argv<{
|
|
23
|
+
action: "start" | "status" | "stop" | "logs" | "__run" | undefined;
|
|
24
|
+
} & {
|
|
25
|
+
follow: boolean;
|
|
26
|
+
} & {
|
|
27
|
+
tail: number;
|
|
28
|
+
}>;
|
|
29
|
+
handler: (argv: ArgumentsCamelCase<DaemonArgs>) => Promise<void>;
|
|
30
|
+
};
|
|
31
|
+
export {};
|