@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.
Files changed (139) hide show
  1. package/.env.agent.template +20 -0
  2. package/README.md +46 -0
  3. package/brain/Config/agent-config.json +14 -0
  4. package/brain/Config/brain-allowlist.json +20 -0
  5. package/brain/Identity/goals.template.md +23 -0
  6. package/brain/Identity/how-i-think.md +406 -0
  7. package/brain/Identity/who-i-am.template.md +34 -0
  8. package/brain/Knowledge/BOOTSTRAP.md +66 -0
  9. package/brain/Knowledge/audit-corpus-index.json +406 -0
  10. package/brain/Knowledge/discussions.json +245 -0
  11. package/brain/Knowledge/pop.brain.brainstorms.generated.md +48 -0
  12. package/brain/Knowledge/pop.brain.brainstorms.genesis.bin +0 -0
  13. package/brain/Knowledge/pop.brain.heuristics.snapshot.bin +0 -0
  14. package/brain/Knowledge/pop.brain.projects.generated.md +16 -0
  15. package/brain/Knowledge/pop.brain.projects.genesis.bin +0 -0
  16. package/brain/Knowledge/pop.brain.retros.generated.md +91 -0
  17. package/brain/Knowledge/pop.brain.retros.genesis.bin +0 -0
  18. package/brain/Knowledge/pop.brain.shared.generated.md +3811 -0
  19. package/brain/Knowledge/pop.brain.shared.genesis.bin +0 -0
  20. package/brain/Knowledge/projects.md +181 -0
  21. package/brain/Knowledge/risk-framework.md +90 -0
  22. package/brain/Knowledge/shared.md +416 -0
  23. package/brain/Knowledge/sprint-priorities.md +439 -0
  24. package/brain/Memory/.gitkeep +0 -0
  25. package/dist/commands/agent/daily-digest.d.ts +24 -0
  26. package/dist/commands/agent/daily-digest.js +336 -0
  27. package/dist/commands/agent/delegate.d.ts +12 -0
  28. package/dist/commands/agent/delegate.js +91 -0
  29. package/dist/commands/agent/deploy-to-org.d.ts +20 -0
  30. package/dist/commands/agent/deploy-to-org.js +154 -0
  31. package/dist/commands/agent/index.d.ts +2 -0
  32. package/dist/commands/agent/index.js +27 -0
  33. package/dist/commands/agent/init.d.ts +19 -0
  34. package/dist/commands/agent/init.js +303 -0
  35. package/dist/commands/agent/onboard.d.ts +22 -0
  36. package/dist/commands/agent/onboard.js +192 -0
  37. package/dist/commands/agent/paymaster-status.d.ts +14 -0
  38. package/dist/commands/agent/paymaster-status.js +130 -0
  39. package/dist/commands/agent/register.d.ts +21 -0
  40. package/dist/commands/agent/register.js +116 -0
  41. package/dist/commands/agent/setup-sponsorship.d.ts +22 -0
  42. package/dist/commands/agent/setup-sponsorship.js +154 -0
  43. package/dist/commands/agent/status.d.ts +12 -0
  44. package/dist/commands/agent/status.js +171 -0
  45. package/dist/commands/agent/triage.d.ts +12 -0
  46. package/dist/commands/agent/triage.js +503 -0
  47. package/dist/commands/brain/advance-stage.d.ts +42 -0
  48. package/dist/commands/brain/advance-stage.js +206 -0
  49. package/dist/commands/brain/allowlist.d.ts +30 -0
  50. package/dist/commands/brain/allowlist.js +274 -0
  51. package/dist/commands/brain/append-lesson.d.ts +55 -0
  52. package/dist/commands/brain/append-lesson.js +245 -0
  53. package/dist/commands/brain/brainstorm.d.ts +154 -0
  54. package/dist/commands/brain/brainstorm.js +573 -0
  55. package/dist/commands/brain/daemon.d.ts +31 -0
  56. package/dist/commands/brain/daemon.js +348 -0
  57. package/dist/commands/brain/doctor.d.ts +27 -0
  58. package/dist/commands/brain/doctor.js +497 -0
  59. package/dist/commands/brain/edit-lesson.d.ts +51 -0
  60. package/dist/commands/brain/edit-lesson.js +248 -0
  61. package/dist/commands/brain/import-snapshot.d.ts +68 -0
  62. package/dist/commands/brain/import-snapshot.js +177 -0
  63. package/dist/commands/brain/index.d.ts +2 -0
  64. package/dist/commands/brain/index.js +67 -0
  65. package/dist/commands/brain/list.d.ts +21 -0
  66. package/dist/commands/brain/list.js +83 -0
  67. package/dist/commands/brain/migrate-projects.d.ts +44 -0
  68. package/dist/commands/brain/migrate-projects.js +209 -0
  69. package/dist/commands/brain/migrate.d.ts +74 -0
  70. package/dist/commands/brain/migrate.js +306 -0
  71. package/dist/commands/brain/new-project.d.ts +53 -0
  72. package/dist/commands/brain/new-project.js +226 -0
  73. package/dist/commands/brain/read.d.ts +24 -0
  74. package/dist/commands/brain/read.js +81 -0
  75. package/dist/commands/brain/remove-lesson.d.ts +47 -0
  76. package/dist/commands/brain/remove-lesson.js +206 -0
  77. package/dist/commands/brain/remove-project.d.ts +36 -0
  78. package/dist/commands/brain/remove-project.js +177 -0
  79. package/dist/commands/brain/retro-file-tasks.d.ts +84 -0
  80. package/dist/commands/brain/retro-file-tasks.js +372 -0
  81. package/dist/commands/brain/retro-list.d.ts +28 -0
  82. package/dist/commands/brain/retro-list.js +125 -0
  83. package/dist/commands/brain/retro-mark-change.d.ts +58 -0
  84. package/dist/commands/brain/retro-mark-change.js +176 -0
  85. package/dist/commands/brain/retro-remove.d.ts +36 -0
  86. package/dist/commands/brain/retro-remove.js +142 -0
  87. package/dist/commands/brain/retro-respond.d.ts +56 -0
  88. package/dist/commands/brain/retro-respond.js +250 -0
  89. package/dist/commands/brain/retro-show.d.ts +23 -0
  90. package/dist/commands/brain/retro-show.js +100 -0
  91. package/dist/commands/brain/retro-start.d.ts +55 -0
  92. package/dist/commands/brain/retro-start.js +311 -0
  93. package/dist/commands/brain/search.d.ts +48 -0
  94. package/dist/commands/brain/search.js +190 -0
  95. package/dist/commands/brain/snapshot.d.ts +32 -0
  96. package/dist/commands/brain/snapshot.js +243 -0
  97. package/dist/commands/brain/status.d.ts +15 -0
  98. package/dist/commands/brain/status.js +166 -0
  99. package/dist/commands/brain/subscribe.d.ts +28 -0
  100. package/dist/commands/brain/subscribe.js +90 -0
  101. package/dist/commands/brain/tag.d.ts +46 -0
  102. package/dist/commands/brain/tag.js +192 -0
  103. package/dist/index.d.ts +17 -0
  104. package/dist/index.js +22 -0
  105. package/dist/lib/brain-daemon.d.ts +126 -0
  106. package/dist/lib/brain-daemon.js +811 -0
  107. package/dist/lib/brain-membership.d.ts +58 -0
  108. package/dist/lib/brain-membership.js +115 -0
  109. package/dist/lib/brain-migrate-projects.d.ts +43 -0
  110. package/dist/lib/brain-migrate-projects.js +247 -0
  111. package/dist/lib/brain-migrate.d.ts +77 -0
  112. package/dist/lib/brain-migrate.js +328 -0
  113. package/dist/lib/brain-ops.d.ts +271 -0
  114. package/dist/lib/brain-ops.js +571 -0
  115. package/dist/lib/brain-paths.d.ts +15 -0
  116. package/dist/lib/brain-paths.js +33 -0
  117. package/dist/lib/brain-projections.d.ts +216 -0
  118. package/dist/lib/brain-projections.js +829 -0
  119. package/dist/lib/brain-schemas.d.ts +36 -0
  120. package/dist/lib/brain-schemas.js +316 -0
  121. package/dist/lib/brain-signing.d.ts +103 -0
  122. package/dist/lib/brain-signing.js +256 -0
  123. package/dist/lib/brain.d.ts +198 -0
  124. package/dist/lib/brain.js +1057 -0
  125. package/dist/pop-agent.d.ts +1 -0
  126. package/dist/pop-agent.js +18 -0
  127. package/docs/agent.md +126 -0
  128. package/docs/agents/brain-anti-entropy.md +127 -0
  129. package/docs/agents/brain-cross-device-onboarding.md +210 -0
  130. package/docs/agents/brain-cross-machine-smoke.md +241 -0
  131. package/docs/agents/brain-layer-setup.md +725 -0
  132. package/docs/agents/offboarding-protocol.md +188 -0
  133. package/docs/agents/onboarding-protocol.md +243 -0
  134. package/docs/agents/running-an-agent.md +200 -0
  135. package/docs/brain.md +560 -0
  136. package/package.json +61 -0
  137. package/scripts/apply.sh +140 -0
  138. package/scripts/onboard.sh +205 -0
  139. package/scripts/setup-agent.ts +272 -0
@@ -0,0 +1,176 @@
1
+ "use strict";
2
+ /**
3
+ * pop brain retro mark-change — manually set a proposed change's status.
4
+ *
5
+ * The retro workflow separates VOTES (discussion-level signals) from
6
+ * CHANGE STATUS (decision). Other agents respond via `pop brain retro
7
+ * respond --vote change-1=agree`, which records a vote entry in the
8
+ * discussion array — NOT a status change on the proposed change.
9
+ *
10
+ * When the retro author (or a designated file-tasks runner) decides a
11
+ * change has enough agreement, they explicitly flip its status to
12
+ * 'agreed' with this command. Then `pop brain retro file-tasks` picks
13
+ * up the change and converts it into a real on-chain task.
14
+ *
15
+ * MVP design: quorum interpretation is human-judged per the task spec
16
+ * (#344 "out of scope: cross-agent voting quorum logic"). This command
17
+ * is the escape hatch that lets operators make the call explicitly.
18
+ *
19
+ * Usage:
20
+ *
21
+ * pop brain retro mark-change retro-327-... change-1 --status agreed
22
+ * pop brain retro mark-change retro-327-... change-2 --status rejected
23
+ * pop brain retro mark-change retro-327-... change-3 --status modified
24
+ *
25
+ * Status values: proposed, agreed, modified, rejected, filed.
26
+ * Setting status to 'filed' manually is unusual — prefer `file-tasks`,
27
+ * which records the filedTaskId for you. Allowed here for emergency
28
+ * manual reconciliation.
29
+ */
30
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
31
+ if (k2 === undefined) k2 = k;
32
+ var desc = Object.getOwnPropertyDescriptor(m, k);
33
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
34
+ desc = { enumerable: true, get: function() { return m[k]; } };
35
+ }
36
+ Object.defineProperty(o, k2, desc);
37
+ }) : (function(o, m, k, k2) {
38
+ if (k2 === undefined) k2 = k;
39
+ o[k2] = m[k];
40
+ }));
41
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
42
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
43
+ }) : function(o, v) {
44
+ o["default"] = v;
45
+ });
46
+ var __importStar = (this && this.__importStar) || (function () {
47
+ var ownKeys = function(o) {
48
+ ownKeys = Object.getOwnPropertyNames || function (o) {
49
+ var ar = [];
50
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
51
+ return ar;
52
+ };
53
+ return ownKeys(o);
54
+ };
55
+ return function (mod) {
56
+ if (mod && mod.__esModule) return mod;
57
+ var result = {};
58
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
59
+ __setModuleDefault(result, mod);
60
+ return result;
61
+ };
62
+ })();
63
+ Object.defineProperty(exports, "__esModule", { value: true });
64
+ exports.retroMarkChangeHandler = void 0;
65
+ const ethers_1 = require("ethers");
66
+ const brain_1 = require("../../lib/brain");
67
+ const brain_ops_1 = require("../../lib/brain-ops");
68
+ const idempotency_1 = require("@poa-box/cli/lib/idempotency");
69
+ const output = __importStar(require("@poa-box/cli/lib/output"));
70
+ const VALID_STATUSES = [
71
+ 'proposed', 'agreed', 'modified', 'rejected', 'filed',
72
+ ];
73
+ exports.retroMarkChangeHandler = {
74
+ builder: (yargs) => yargs
75
+ .positional('retro-id', {
76
+ describe: 'The retro.id containing the change',
77
+ type: 'string',
78
+ })
79
+ .positional('change-id', {
80
+ describe: 'The proposed-change id to update',
81
+ type: 'string',
82
+ })
83
+ .option('doc', {
84
+ describe: 'Brain document ID (default: pop.brain.retros)',
85
+ type: 'string',
86
+ default: 'pop.brain.retros',
87
+ })
88
+ .option('status', {
89
+ describe: 'New status for the proposed change',
90
+ type: 'string',
91
+ choices: VALID_STATUSES,
92
+ demandOption: true,
93
+ })
94
+ .option('filed-task-id', {
95
+ describe: 'When --status=filed, record the on-chain task id on the change (optional)',
96
+ type: 'string',
97
+ })
98
+ .option('idempotency-key', { type: 'string', describe: 'Task #375 (HB#217) idempotency cache.' })
99
+ .option('no-idempotency', { type: 'boolean', default: false, describe: 'Bypass the idempotency cache.' })
100
+ .demandOption(['retro-id', 'change-id']),
101
+ handler: async (argv) => {
102
+ try {
103
+ if (argv.filedTaskId && argv.status !== 'filed') {
104
+ output.error(`--filed-task-id only makes sense with --status=filed`);
105
+ process.exitCode = 1;
106
+ return;
107
+ }
108
+ // Task #375 idempotency check, agent-scoped
109
+ const signerKey = process.env.POP_PRIVATE_KEY;
110
+ const authorScope = signerKey ? new ethers_1.ethers.Wallet(signerKey).address.toLowerCase() : 'anonymous';
111
+ const idempKey = argv.idempotencyKey || (0, idempotency_1.argvToIdempotencyString)(argv);
112
+ if (!argv.noIdempotency) {
113
+ const cached = (0, idempotency_1.checkIdempotencyCache)(authorScope, 'brain.retroMarkChange', idempKey);
114
+ if (cached) {
115
+ if (output.isJsonMode())
116
+ output.json({ status: 'ok', cached: true, ...cached });
117
+ else
118
+ console.log(` Change "${argv.changeId}" already marked (idempotency cache hit). head: ${cached.headCid}`);
119
+ return;
120
+ }
121
+ }
122
+ const result = await (0, brain_ops_1.routedDispatch)({
123
+ type: 'updateChangeStatus',
124
+ docId: argv.doc,
125
+ retroId: argv.retroId,
126
+ changeId: argv.changeId,
127
+ newStatus: argv.status,
128
+ filedTaskId: argv.filedTaskId,
129
+ });
130
+ if (!argv.noIdempotency) {
131
+ (0, idempotency_1.recordIdempotentResult)(authorScope, 'brain.retroMarkChange', idempKey, {
132
+ docId: argv.doc,
133
+ retroId: argv.retroId,
134
+ changeId: argv.changeId,
135
+ newStatus: argv.status,
136
+ headCid: result.headCid,
137
+ });
138
+ }
139
+ if (output.isJsonMode()) {
140
+ output.json({
141
+ status: 'ok',
142
+ docId: argv.doc,
143
+ retroId: argv.retroId,
144
+ changeId: argv.changeId,
145
+ newStatus: argv.status,
146
+ filedTaskId: argv.filedTaskId ?? null,
147
+ headCid: result.headCid,
148
+ envelopeAuthor: result.envelopeAuthor,
149
+ routedViaDaemon: result.routedViaDaemon,
150
+ });
151
+ }
152
+ else {
153
+ console.log('');
154
+ console.log(` Change "${argv.changeId}" in retro "${argv.retroId}" marked as ${argv.status}`);
155
+ if (argv.filedTaskId) {
156
+ console.log(` filed task: #${argv.filedTaskId}`);
157
+ }
158
+ console.log(` new head: ${result.headCid}`);
159
+ console.log(` routed: ${result.routedViaDaemon ? 'via brain daemon' : 'in-process (no daemon)'}`);
160
+ console.log('');
161
+ if (argv.status === 'agreed') {
162
+ console.log(` Next: run "pop brain retro file-tasks --retro ${argv.retroId}" to convert ` +
163
+ `this change (and any other agreed changes) into real on-chain tasks.`);
164
+ console.log('');
165
+ }
166
+ }
167
+ }
168
+ catch (err) {
169
+ output.error(err.message);
170
+ process.exitCode = 1;
171
+ }
172
+ finally {
173
+ await (0, brain_1.stopBrainNode)();
174
+ }
175
+ },
176
+ };
@@ -0,0 +1,36 @@
1
+ /**
2
+ * pop brain retro remove — soft-delete a retro from pop.brain.retros.
3
+ *
4
+ * Same tombstone pattern as remove-lesson / remove-project:
5
+ * {removed: true, removedAt, removedBy, removedReason?}. The retro
6
+ * stays in the Automerge doc (for CRDT-safe merge with concurrent
7
+ * edits) but is filtered out of the main projection and surfaced in
8
+ * a compact "## Removed retros" summary.
9
+ *
10
+ * Useful for: test retros, retros that were started in error, and
11
+ * retros where the entire window turned out to be a no-op and there's
12
+ * nothing worth shipping.
13
+ */
14
+ import type { Argv, ArgumentsCamelCase } from 'yargs';
15
+ interface RetroRemoveArgs {
16
+ doc: string;
17
+ retroId: string;
18
+ reason?: string;
19
+ 'idempotency-key'?: string;
20
+ 'no-idempotency'?: boolean;
21
+ }
22
+ export declare const retroRemoveHandler: {
23
+ builder: (yargs: Argv) => Argv<import("yargs").Defined<{
24
+ "retro-id": string | undefined;
25
+ } & {
26
+ doc: string;
27
+ } & {
28
+ reason: string | undefined;
29
+ } & {
30
+ "idempotency-key": string | undefined;
31
+ } & {
32
+ "no-idempotency": boolean;
33
+ }, "retro-id">>;
34
+ handler: (argv: ArgumentsCamelCase<RetroRemoveArgs>) => Promise<void>;
35
+ };
36
+ export {};
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+ /**
3
+ * pop brain retro remove — soft-delete a retro from pop.brain.retros.
4
+ *
5
+ * Same tombstone pattern as remove-lesson / remove-project:
6
+ * {removed: true, removedAt, removedBy, removedReason?}. The retro
7
+ * stays in the Automerge doc (for CRDT-safe merge with concurrent
8
+ * edits) but is filtered out of the main projection and surfaced in
9
+ * a compact "## Removed retros" summary.
10
+ *
11
+ * Useful for: test retros, retros that were started in error, and
12
+ * retros where the entire window turned out to be a no-op and there's
13
+ * nothing worth shipping.
14
+ */
15
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ var desc = Object.getOwnPropertyDescriptor(m, k);
18
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
19
+ desc = { enumerable: true, get: function() { return m[k]; } };
20
+ }
21
+ Object.defineProperty(o, k2, desc);
22
+ }) : (function(o, m, k, k2) {
23
+ if (k2 === undefined) k2 = k;
24
+ o[k2] = m[k];
25
+ }));
26
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
27
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
28
+ }) : function(o, v) {
29
+ o["default"] = v;
30
+ });
31
+ var __importStar = (this && this.__importStar) || (function () {
32
+ var ownKeys = function(o) {
33
+ ownKeys = Object.getOwnPropertyNames || function (o) {
34
+ var ar = [];
35
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
36
+ return ar;
37
+ };
38
+ return ownKeys(o);
39
+ };
40
+ return function (mod) {
41
+ if (mod && mod.__esModule) return mod;
42
+ var result = {};
43
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
44
+ __setModuleDefault(result, mod);
45
+ return result;
46
+ };
47
+ })();
48
+ Object.defineProperty(exports, "__esModule", { value: true });
49
+ exports.retroRemoveHandler = void 0;
50
+ const ethers_1 = require("ethers");
51
+ const brain_1 = require("../../lib/brain");
52
+ const brain_ops_1 = require("../../lib/brain-ops");
53
+ const idempotency_1 = require("@poa-box/cli/lib/idempotency");
54
+ const output = __importStar(require("@poa-box/cli/lib/output"));
55
+ exports.retroRemoveHandler = {
56
+ builder: (yargs) => yargs
57
+ .positional('retro-id', {
58
+ describe: 'The retro.id to tombstone',
59
+ type: 'string',
60
+ })
61
+ .option('doc', {
62
+ describe: 'Brain document ID (default: pop.brain.retros)',
63
+ type: 'string',
64
+ default: 'pop.brain.retros',
65
+ })
66
+ .option('reason', {
67
+ describe: 'Optional human-readable reason recorded on the tombstone',
68
+ type: 'string',
69
+ })
70
+ .option('idempotency-key', { type: 'string', describe: 'Task #375 (HB#217) idempotency cache.' })
71
+ .option('no-idempotency', { type: 'boolean', default: false, describe: 'Bypass the idempotency cache.' })
72
+ .demandOption('retro-id'),
73
+ handler: async (argv) => {
74
+ try {
75
+ const key = process.env.POP_PRIVATE_KEY;
76
+ if (!key) {
77
+ output.error('POP_PRIVATE_KEY not set — cannot record removedBy. Set the env var and retry.');
78
+ process.exitCode = 1;
79
+ return;
80
+ }
81
+ const removerAddress = new ethers_1.ethers.Wallet(key).address.toLowerCase();
82
+ const now = Math.floor(Date.now() / 1000);
83
+ // Task #375 idempotency check
84
+ const idempKey = argv.idempotencyKey || (0, idempotency_1.argvToIdempotencyString)(argv);
85
+ if (!argv.noIdempotency) {
86
+ const cached = (0, idempotency_1.checkIdempotencyCache)(removerAddress, 'brain.retroRemove', idempKey);
87
+ if (cached) {
88
+ if (output.isJsonMode())
89
+ output.json({ status: 'ok', cached: true, ...cached });
90
+ else
91
+ console.log(` Retro "${argv.retroId}" already removed (idempotency cache hit). head: ${cached.headCid}`);
92
+ return;
93
+ }
94
+ }
95
+ const result = await (0, brain_ops_1.routedDispatch)({
96
+ type: 'removeRetro',
97
+ docId: argv.doc,
98
+ retroId: argv.retroId,
99
+ removedBy: removerAddress,
100
+ removedAt: now,
101
+ removedReason: argv.reason,
102
+ });
103
+ if (!argv.noIdempotency) {
104
+ (0, idempotency_1.recordIdempotentResult)(removerAddress, 'brain.retroRemove', idempKey, {
105
+ docId: argv.doc,
106
+ retroId: argv.retroId,
107
+ headCid: result.headCid,
108
+ });
109
+ }
110
+ if (output.isJsonMode()) {
111
+ output.json({
112
+ status: 'ok',
113
+ docId: argv.doc,
114
+ retroId: argv.retroId,
115
+ removedAt: now,
116
+ removedBy: removerAddress,
117
+ removedReason: argv.reason ?? null,
118
+ headCid: result.headCid,
119
+ routedViaDaemon: result.routedViaDaemon,
120
+ });
121
+ }
122
+ else {
123
+ console.log('');
124
+ console.log(` Retro "${argv.retroId}" tombstoned in ${argv.doc}`);
125
+ console.log(` removedBy: ${removerAddress}`);
126
+ console.log(` removedAt: ${new Date(now * 1000).toISOString()}`);
127
+ if (argv.reason)
128
+ console.log(` reason: ${argv.reason}`);
129
+ console.log(` new head: ${result.headCid}`);
130
+ console.log(` routed: ${result.routedViaDaemon ? 'via brain daemon' : 'in-process (no daemon)'}`);
131
+ console.log('');
132
+ }
133
+ }
134
+ catch (err) {
135
+ output.error(err.message);
136
+ process.exitCode = 1;
137
+ }
138
+ finally {
139
+ await (0, brain_1.stopBrainNode)();
140
+ }
141
+ },
142
+ };
@@ -0,0 +1,56 @@
1
+ /**
2
+ * pop brain retro respond — append a discussion entry to an existing retro.
3
+ *
4
+ * Usage:
5
+ *
6
+ * pop brain retro respond --to retro-327-1776... \
7
+ * --message "Change 1 makes sense. Change 2 needs more research on Diamond ABI extraction."
8
+ *
9
+ * # With per-change votes:
10
+ * pop brain retro respond --to retro-327-1776... \
11
+ * --message "..." \
12
+ * --vote change-1=agree,change-2=modify
13
+ *
14
+ * The response lands in the retro's `discussion` array. The first
15
+ * response on an open retro auto-advances status from 'open' to
16
+ * 'discussed' (enforced by the respondToRetro op inside dispatchOp).
17
+ *
18
+ * Vote validation: vote change-ids must refer to real proposedChanges
19
+ * on the retro. Typos / unknown change-ids fail fast with a list of
20
+ * available change-ids in the error message.
21
+ */
22
+ import type { Argv, ArgumentsCamelCase } from 'yargs';
23
+ interface RetroRespondArgs {
24
+ doc: string;
25
+ to: string;
26
+ message?: string;
27
+ messageFile?: string;
28
+ vote?: string;
29
+ author?: string;
30
+ hb?: number;
31
+ 'idempotency-key'?: string;
32
+ 'no-idempotency'?: boolean;
33
+ }
34
+ export declare const retroRespondHandler: {
35
+ builder: (yargs: Argv) => Argv<{
36
+ doc: string;
37
+ } & {
38
+ to: string;
39
+ } & {
40
+ message: string | undefined;
41
+ } & {
42
+ "message-file": string | undefined;
43
+ } & {
44
+ vote: string | undefined;
45
+ } & {
46
+ author: string | undefined;
47
+ } & {
48
+ hb: number | undefined;
49
+ } & {
50
+ "idempotency-key": string | undefined;
51
+ } & {
52
+ "no-idempotency": boolean;
53
+ }>;
54
+ handler: (argv: ArgumentsCamelCase<RetroRespondArgs>) => Promise<void>;
55
+ };
56
+ export {};
@@ -0,0 +1,250 @@
1
+ "use strict";
2
+ /**
3
+ * pop brain retro respond — append a discussion entry to an existing retro.
4
+ *
5
+ * Usage:
6
+ *
7
+ * pop brain retro respond --to retro-327-1776... \
8
+ * --message "Change 1 makes sense. Change 2 needs more research on Diamond ABI extraction."
9
+ *
10
+ * # With per-change votes:
11
+ * pop brain retro respond --to retro-327-1776... \
12
+ * --message "..." \
13
+ * --vote change-1=agree,change-2=modify
14
+ *
15
+ * The response lands in the retro's `discussion` array. The first
16
+ * response on an open retro auto-advances status from 'open' to
17
+ * 'discussed' (enforced by the respondToRetro op inside dispatchOp).
18
+ *
19
+ * Vote validation: vote change-ids must refer to real proposedChanges
20
+ * on the retro. Typos / unknown change-ids fail fast with a list of
21
+ * available change-ids in the error message.
22
+ */
23
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
24
+ if (k2 === undefined) k2 = k;
25
+ var desc = Object.getOwnPropertyDescriptor(m, k);
26
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
27
+ desc = { enumerable: true, get: function() { return m[k]; } };
28
+ }
29
+ Object.defineProperty(o, k2, desc);
30
+ }) : (function(o, m, k, k2) {
31
+ if (k2 === undefined) k2 = k;
32
+ o[k2] = m[k];
33
+ }));
34
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
35
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
36
+ }) : function(o, v) {
37
+ o["default"] = v;
38
+ });
39
+ var __importStar = (this && this.__importStar) || (function () {
40
+ var ownKeys = function(o) {
41
+ ownKeys = Object.getOwnPropertyNames || function (o) {
42
+ var ar = [];
43
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
44
+ return ar;
45
+ };
46
+ return ownKeys(o);
47
+ };
48
+ return function (mod) {
49
+ if (mod && mod.__esModule) return mod;
50
+ var result = {};
51
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
52
+ __setModuleDefault(result, mod);
53
+ return result;
54
+ };
55
+ })();
56
+ Object.defineProperty(exports, "__esModule", { value: true });
57
+ exports.retroRespondHandler = void 0;
58
+ const fs_1 = require("fs");
59
+ const path_1 = require("path");
60
+ const ethers_1 = require("ethers");
61
+ const brain_1 = require("../../lib/brain");
62
+ const brain_ops_1 = require("../../lib/brain-ops");
63
+ const idempotency_1 = require("@poa-box/cli/lib/idempotency");
64
+ const output = __importStar(require("@poa-box/cli/lib/output"));
65
+ const VALID_VOTES = ['agree', 'modify', 'reject'];
66
+ /**
67
+ * Parse the --vote flag value. Expected shape is a comma-separated
68
+ * list of `change-id=vote` pairs, e.g. `change-1=agree,change-2=modify`.
69
+ * Returns a map of {changeId: vote}, or throws on a bad value.
70
+ */
71
+ function parseVoteFlag(raw) {
72
+ const result = {};
73
+ const pairs = raw.split(',').map(s => s.trim()).filter(Boolean);
74
+ for (const pair of pairs) {
75
+ const eq = pair.indexOf('=');
76
+ if (eq < 0) {
77
+ throw new Error(`--vote pair "${pair}" must be in "change-id=vote" format`);
78
+ }
79
+ const changeId = pair.slice(0, eq).trim();
80
+ const voteRaw = pair.slice(eq + 1).trim().toLowerCase();
81
+ if (!changeId) {
82
+ throw new Error(`--vote pair "${pair}" has empty change-id`);
83
+ }
84
+ if (!VALID_VOTES.includes(voteRaw)) {
85
+ throw new Error(`--vote pair "${pair}" has invalid vote "${voteRaw}" — must be one of: ${VALID_VOTES.join(', ')}`);
86
+ }
87
+ result[changeId] = voteRaw;
88
+ }
89
+ return result;
90
+ }
91
+ exports.retroRespondHandler = {
92
+ builder: (yargs) => yargs
93
+ .option('doc', {
94
+ describe: 'Brain document ID (default: pop.brain.retros)',
95
+ type: 'string',
96
+ default: 'pop.brain.retros',
97
+ })
98
+ .option('to', {
99
+ describe: 'The retro.id to respond to',
100
+ type: 'string',
101
+ demandOption: true,
102
+ })
103
+ .option('message', {
104
+ describe: 'The response message (inline). Use --message-file for long content.',
105
+ type: 'string',
106
+ })
107
+ .option('message-file', {
108
+ describe: 'Path to a file whose contents are the response message',
109
+ type: 'string',
110
+ })
111
+ .option('vote', {
112
+ describe: 'Per-change votes as "change-id=vote,change-id=vote" (votes: agree, modify, reject). Example: change-1=agree,change-2=modify',
113
+ type: 'string',
114
+ })
115
+ .option('author', {
116
+ describe: 'Override the author label (default: signing wallet address)',
117
+ type: 'string',
118
+ })
119
+ .option('hb', {
120
+ describe: 'Heartbeat number at response time (optional metadata)',
121
+ type: 'number',
122
+ })
123
+ .option('idempotency-key', { type: 'string', describe: 'Task #375 (HB#217) idempotency cache.' })
124
+ .option('no-idempotency', { type: 'boolean', default: false, describe: 'Bypass the idempotency cache.' })
125
+ .check((argv) => {
126
+ if (!argv.message && !argv['message-file']) {
127
+ throw new Error('Must supply --message or --message-file');
128
+ }
129
+ return true;
130
+ }),
131
+ handler: async (argv) => {
132
+ try {
133
+ // Resolve message content.
134
+ let message;
135
+ if (argv.messageFile) {
136
+ const p = (0, path_1.resolve)(argv.messageFile);
137
+ if (!(0, fs_1.existsSync)(p)) {
138
+ output.error(`--message-file not found: ${p}`);
139
+ process.exitCode = 1;
140
+ return;
141
+ }
142
+ message = (0, fs_1.readFileSync)(p, 'utf8').trim();
143
+ }
144
+ else {
145
+ message = (argv.message ?? '').trim();
146
+ }
147
+ if (!message) {
148
+ output.error('Response message is empty.');
149
+ process.exitCode = 1;
150
+ return;
151
+ }
152
+ // Resolve author.
153
+ let authorLabel;
154
+ if (argv.author) {
155
+ authorLabel = argv.author;
156
+ }
157
+ else {
158
+ const key = process.env.POP_PRIVATE_KEY;
159
+ if (!key) {
160
+ output.error('POP_PRIVATE_KEY not set — cannot derive default author. Pass --author explicitly.');
161
+ process.exitCode = 1;
162
+ return;
163
+ }
164
+ authorLabel = new ethers_1.ethers.Wallet(key).address.toLowerCase();
165
+ }
166
+ // Parse votes if provided.
167
+ let votePerChange;
168
+ if (argv.vote) {
169
+ try {
170
+ votePerChange = parseVoteFlag(argv.vote);
171
+ }
172
+ catch (err) {
173
+ output.error(err.message);
174
+ process.exitCode = 1;
175
+ return;
176
+ }
177
+ }
178
+ const now = Math.floor(Date.now() / 1000);
179
+ // Task #375 idempotency check, agent-scoped
180
+ const idempKey = argv.idempotencyKey || (0, idempotency_1.argvToIdempotencyString)(argv);
181
+ if (!argv.noIdempotency) {
182
+ const cached = (0, idempotency_1.checkIdempotencyCache)(authorLabel, 'brain.retroRespond', idempKey);
183
+ if (cached) {
184
+ if (output.isJsonMode())
185
+ output.json({ status: 'ok', cached: true, ...cached });
186
+ else
187
+ console.log(` Retro response already recorded (idempotency cache hit). head: ${cached.headCid}`);
188
+ return;
189
+ }
190
+ }
191
+ const result = await (0, brain_ops_1.routedDispatch)({
192
+ type: 'respondToRetro',
193
+ docId: argv.doc,
194
+ retroId: argv.to,
195
+ author: authorLabel,
196
+ hb: argv.hb,
197
+ message,
198
+ votePerChange,
199
+ timestamp: now,
200
+ });
201
+ if (!argv.noIdempotency) {
202
+ (0, idempotency_1.recordIdempotentResult)(authorLabel, 'brain.retroRespond', idempKey, {
203
+ docId: argv.doc,
204
+ retroId: argv.to,
205
+ headCid: result.headCid,
206
+ });
207
+ }
208
+ if (output.isJsonMode()) {
209
+ output.json({
210
+ status: 'ok',
211
+ docId: argv.doc,
212
+ retroId: argv.to,
213
+ author: authorLabel,
214
+ hb: argv.hb ?? null,
215
+ votes: votePerChange ?? null,
216
+ headCid: result.headCid,
217
+ envelopeAuthor: result.envelopeAuthor,
218
+ routedViaDaemon: result.routedViaDaemon,
219
+ });
220
+ }
221
+ else {
222
+ console.log('');
223
+ console.log(` Response appended to retro "${argv.to}"`);
224
+ console.log(` author: ${authorLabel}`);
225
+ if (argv.hb !== undefined)
226
+ console.log(` hb: #${argv.hb}`);
227
+ if (votePerChange) {
228
+ console.log(` votes:`);
229
+ for (const [changeId, vote] of Object.entries(votePerChange)) {
230
+ console.log(` - ${changeId}: ${vote}`);
231
+ }
232
+ }
233
+ console.log(` new head: ${result.headCid}`);
234
+ console.log(` routed: ${result.routedViaDaemon ? 'via brain daemon' : 'in-process (no daemon)'}`);
235
+ console.log('');
236
+ console.log(` The retro's status advances from 'open' to 'discussed' on the first ` +
237
+ `response. When proposed changes are agreed, run "pop brain retro file-tasks ` +
238
+ `--retro ${argv.to}" to convert them to on-chain tasks.`);
239
+ console.log('');
240
+ }
241
+ }
242
+ catch (err) {
243
+ output.error(err.message);
244
+ process.exitCode = 1;
245
+ }
246
+ finally {
247
+ await (0, brain_1.stopBrainNode)();
248
+ }
249
+ },
250
+ };
@@ -0,0 +1,23 @@
1
+ /**
2
+ * pop brain retro show — render a single retro as markdown.
3
+ *
4
+ * Loads the retro doc, extracts the requested retro, and runs it
5
+ * through the projection layer. Same shape + schema as projectRetros
6
+ * produces for the full doc snapshot, but scoped to one entry.
7
+ *
8
+ * Pure read path — no daemon routing required.
9
+ */
10
+ import type { Argv, ArgumentsCamelCase } from 'yargs';
11
+ interface RetroShowArgs {
12
+ retroId: string;
13
+ doc: string;
14
+ }
15
+ export declare const retroShowHandler: {
16
+ builder: (yargs: Argv) => Argv<import("yargs").Defined<{
17
+ "retro-id": string | undefined;
18
+ } & {
19
+ doc: string;
20
+ }, "retro-id">>;
21
+ handler: (argv: ArgumentsCamelCase<RetroShowArgs>) => Promise<void>;
22
+ };
23
+ export {};