overlord-cli 3.23.0 → 3.24.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.
@@ -189,6 +189,37 @@ function readJsonFile(filePath, label) {
189
189
  }
190
190
  }
191
191
 
192
+ async function readTextFromStdin(label) {
193
+ const chunks = [];
194
+ try {
195
+ for await (const chunk of process.stdin) {
196
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
197
+ }
198
+ } catch (err) {
199
+ throw new Error(
200
+ `${label}: could not read stdin: ${err instanceof Error ? err.message : String(err)}`
201
+ );
202
+ }
203
+ return Buffer.concat(chunks).toString('utf8');
204
+ }
205
+
206
+ async function readJsonFileOrStdin(filePath, label) {
207
+ if (filePath !== '-') {
208
+ return readJsonFile(filePath, label);
209
+ }
210
+
211
+ try {
212
+ return JSON.parse(await readTextFromStdin(label));
213
+ } catch (err) {
214
+ if (err instanceof Error && err.message.startsWith(`${label}: could not read stdin`)) {
215
+ throw err;
216
+ }
217
+ throw new Error(
218
+ `${label}: could not parse stdin: ${err instanceof Error ? err.message : String(err)}`
219
+ );
220
+ }
221
+ }
222
+
192
223
  // ---------------------------------------------------------------------------
193
224
  // changeRationales helper
194
225
  // ---------------------------------------------------------------------------
@@ -200,7 +231,10 @@ function readJsonFile(filePath, label) {
200
231
  */
201
232
  async function resolveChangeRationales(flags) {
202
233
  if (flags['change-rationales-file']) {
203
- return readJsonFile(String(flags['change-rationales-file']), '--change-rationales-file');
234
+ return await readJsonFileOrStdin(
235
+ String(flags['change-rationales-file']),
236
+ '--change-rationales-file'
237
+ );
204
238
  }
205
239
  if (flags['change-rationales-json']) {
206
240
  try {
@@ -624,7 +658,7 @@ async function protocolDeliver(args) {
624
658
  if (!sessionKey) throw new Error('--session-key is required (or set SESSION_KEY)');
625
659
  if (!ticketId) throw new Error('--ticket-id is required (or set TICKET_ID)');
626
660
  const deliverPayload = flags['payload-file']
627
- ? readJsonFile(String(flags['payload-file']), '--payload-file')
661
+ ? await readJsonFileOrStdin(String(flags['payload-file']), '--payload-file')
628
662
  : null;
629
663
  const summary = deliverPayload?.summary ??
630
664
  (flags['summary-file']
@@ -642,7 +676,7 @@ async function protocolDeliver(args) {
642
676
  throw new Error('Use either --payload-file or --artifacts-json, not both');
643
677
  }
644
678
  if (flags['artifacts-file']) {
645
- artifacts = readJsonFile(String(flags['artifacts-file']), '--artifacts-file');
679
+ artifacts = await readJsonFileOrStdin(String(flags['artifacts-file']), '--artifacts-file');
646
680
  } else if (flags['artifacts-json']) {
647
681
  try {
648
682
  artifacts = JSON.parse(String(flags['artifacts-json']));
@@ -1144,14 +1178,15 @@ deliver:
1144
1178
  --session-key <key>
1145
1179
  --ticket-id <id>
1146
1180
  --summary <text> or --summary-file <path>
1147
- or: --payload-file <path> containing { summary, artifacts, changeRationales }
1181
+ or: --payload-file <path|-> containing { summary, artifacts, changeRationales }
1148
1182
  Optional:
1149
1183
  --artifacts-json <json>
1150
- --artifacts-file <path>
1184
+ --artifacts-file <path|->
1151
1185
  --change-rationales-json <json>
1152
- --change-rationales-file <path>
1186
+ --change-rationales-file <path|->
1153
1187
  --skip-file-change-check Bypass local git vs changeRationales validation
1154
1188
  Notes:
1189
+ Use --payload-file - to read the full delivery JSON from stdin without creating a scratch file.
1155
1190
  Do not combine --payload-file with --artifacts-json/--artifacts-file or change-rationale flags.
1156
1191
  In a git workspace, deliver validates that changed files are represented by changeRationales unless skipped.
1157
1192
 
@@ -1243,6 +1278,7 @@ Examples:
1243
1278
  ovld protocol deliver --session-key <key> --ticket-id <id> --summary "Done"
1244
1279
  ovld protocol deliver --session-key <key> --ticket-id <id> --summary "Done" --artifacts-file ./artifacts.json
1245
1280
  ovld protocol deliver --session-key <key> --ticket-id <id> --payload-file ./deliver.json
1281
+ ovld protocol deliver --session-key <key> --ticket-id <id> --payload-file -
1246
1282
  ovld protocol deliver --session-key <key> --ticket-id <id> --summary "Done" --skip-file-change-check
1247
1283
  ovld protocol deliver --session-key <key> --ticket-id <id> --summary "Done" --timeout 60000
1248
1284
  `);
@@ -84,11 +84,11 @@ If you receive a prompt with a specified ticket ID, adhere to the following. If
84
84
  --change-rationales-json '[{"label":"Short reviewer title","file_path":"path/to/file.ts","summary":"What changed.","why":"Why it changed.","impact":"Behavioral impact.","hunks":[{"header":"@@ -10,6 +10,14 @@"}]}]'
85
85
  \`\`\`
86
86
 
87
- For larger or quote-sensitive deliveries, prefer a single JSON file:
87
+ For larger or quote-sensitive deliveries, prefer a single JSON payload on stdin:
88
88
  \`\`\`bash
89
- ovld protocol deliver --session-key <sessionKey> --ticket-id $TICKET_ID --payload-file ./deliver.json
89
+ ovld protocol deliver --session-key <sessionKey> --ticket-id $TICKET_ID --payload-file -
90
90
  \`\`\`
91
- Treat \`deliver.json\` as ephemeral scratch data only. Create it outside the repository when practical, never commit it, and remove it after delivery.
91
+ This avoids creating a scratch delivery file that needs cleanup. If your runtime cannot provide stdin directly, \`--payload-file ./deliver.json\` remains supported; treat that file as ephemeral scratch data, never commit it, and remove it after delivery.
92
92
 
93
93
  ## Change Rationales
94
94
 
@@ -96,7 +96,7 @@ Always include \`changeRationales\` when delivering. Optionally include them on
96
96
 
97
97
  Before delivering, make sure every meaningful git-tracked file change is represented in \`changeRationales\`; do not send \`file_changes\` as an artifact.
98
98
 
99
- These are structured protocol payloads that Overlord stores as first-class rows in the \`file_changes\` table. Prefer inline JSON or the dedicated command below. For quote-sensitive deliveries, prefer \`--payload-file\` so summary, artifacts, and change rationales stay in one JSON document, but treat that JSON as ephemeral scratch data rather than a repository artifact. Ordinary deliver artifacts should use \`next_steps\`, \`test_results\`, \`migration\`, \`note\`, \`url\`, or \`decision\`.
99
+ These are structured protocol payloads that Overlord stores as first-class rows in the \`file_changes\` table. Prefer inline JSON or the dedicated command below. For larger full delivery payloads, prefer \`--payload-file -\` so summary, artifacts, and change rationales stay in one JSON document without creating a temporary file. Ordinary deliver artifacts should use \`next_steps\`, \`test_results\`, \`migration\`, \`note\`, \`url\`, or \`decision\`.
100
100
 
101
101
  \`\`\`bash
102
102
  ovld protocol record-change-rationales --session-key <sessionKey> --ticket-id $TICKET_ID \\\\
@@ -158,11 +158,11 @@ If you receive a prompt with a specified ticket ID, adhere to the following. If
158
158
  --artifacts-json '[{"type":"next_steps","label":"Next steps","content":"..."}]' \\\\
159
159
  --change-rationales-json '[{"label":"Short reviewer title","file_path":"path/to/file.ts","summary":"What changed.","why":"Why it changed.","impact":"Behavioral impact.","hunks":[{"header":"@@ -10,6 +10,14 @@"}]}]'
160
160
  \`\`\`
161
- If you use \`--payload-file\`, \`--artifacts-file\`, or \`--change-rationales-file\` for larger JSON, treat that file as ephemeral scratch data outside the repository and remove it after delivery. Do not leave delivery JSON checked into the worktree.
161
+ For larger delivery JSON, prefer \`--payload-file -\` and stream the full payload on stdin so no scratch file needs to be created or removed. If you use \`--payload-file\`, \`--artifacts-file\`, or \`--change-rationales-file\` with a real path, treat that file as ephemeral scratch data outside the repository and remove it after delivery. Do not leave delivery JSON checked into the worktree.
162
162
 
163
163
  ## Change Rationales
164
164
 
165
- Always include \`changeRationales\` when delivering. Before delivering, make sure every meaningful git-tracked file change is represented in \`changeRationales\`; do not send \`file_changes\` as an artifact. Record only meaningful behavioral changes. Overlord stores these as structured rows in the \`file_changes\` table. If you need a JSON file for transport, keep it ephemeral and out of the repository.
165
+ Always include \`changeRationales\` when delivering. Before delivering, make sure every meaningful git-tracked file change is represented in \`changeRationales\`; do not send \`file_changes\` as an artifact. Record only meaningful behavioral changes. Overlord stores these as structured rows in the \`file_changes\` table. For larger delivery payloads, prefer \`--payload-file -\` with stdin. If you need a JSON file for transport, keep it ephemeral and out of the repository.
166
166
 
167
167
  \`\`\`bash
168
168
  ovld protocol record-change-rationales --session-key <sessionKey> --ticket-id $TICKET_ID \\\\
@@ -231,7 +231,7 @@ When done, deliver with artifacts and change rationales:
231
231
  \`\`\`bash
232
232
  ovld protocol deliver --session-key <sessionKey> --ticket-id $TICKET_ID --summary "Narrative: what you did, next steps." --artifacts-json '[{"type":"next_steps","label":"Next steps","content":"..."}]' --change-rationales-json '[{"label":"Short reviewer title","file_path":"path/to/file.ts","summary":"What changed.","why":"Why it changed.","impact":"Behavioral impact.","hunks":[{"header":"@@ -10,6 +10,14 @@"}]}]'
233
233
  \`\`\`
234
- If you use a JSON file for delivery transport, keep it ephemeral scratch data outside the repository and remove it after the protocol call.
234
+ For larger delivery JSON, prefer \`--payload-file -\` with stdin so no scratch file needs to be created or removed. If you use a JSON file for delivery transport, keep it ephemeral scratch data outside the repository and remove it after the protocol call.
235
235
 
236
236
  Rules:
237
237
  - Always attach first and deliver last.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "overlord-cli",
3
- "version": "3.23.0",
3
+ "version": "3.24.0",
4
4
  "description": "Overlord CLI — launch AI agents on tickets from anywhere",
5
5
  "type": "module",
6
6
  "bin": {
@@ -7,6 +7,27 @@ const execFileAsync = promisify(execFile);
7
7
  const OVLD_BIN = process.env.OVLD_BIN?.trim() || 'ovld';
8
8
  const PROTOCOL_VERSION = '2025-06-18';
9
9
 
10
+ function execFileWithOptionalInput(file, args, options, input) {
11
+ if (input === undefined) {
12
+ return execFileAsync(file, args, options);
13
+ }
14
+
15
+ return new Promise((resolve, reject) => {
16
+ const child = execFile(file, args, options, (error, stdout, stderr) => {
17
+ if (error) {
18
+ error.stdout = stdout;
19
+ error.stderr = stderr;
20
+ reject(error);
21
+ return;
22
+ }
23
+
24
+ resolve({ stdout, stderr });
25
+ });
26
+
27
+ child.stdin?.end(input);
28
+ });
29
+ }
30
+
10
31
  const tools = [
11
32
  {
12
33
  name: 'discover_project',
@@ -239,7 +260,8 @@ const tools = [
239
260
  },
240
261
  {
241
262
  name: 'deliver_ticket',
242
- description: 'Deliver final work back into Overlord with summary, artifacts, and change rationales.',
263
+ description:
264
+ 'Deliver final work back into Overlord with summary, artifacts, and change rationales. Large payloads are streamed to the CLI through stdin, so this tool does not create delivery scratch files.',
243
265
  inputSchema: {
244
266
  type: 'object',
245
267
  properties: {
@@ -255,11 +277,14 @@ const tools = [
255
277
  toCliFlags: args => ({
256
278
  'session-key': args.session_key,
257
279
  'ticket-id': args.ticket_id,
258
- summary: args.summary,
259
- 'artifacts-json': args.artifacts,
260
- 'change-rationales-json': args.change_rationales,
280
+ 'payload-file': '-',
261
281
  'skip-file-change-check': args.skip_file_change_check
262
282
  }),
283
+ toCliStdin: args => JSON.stringify({
284
+ summary: args.summary,
285
+ ...(Array.isArray(args.artifacts) ? { artifacts: args.artifacts } : {}),
286
+ ...(Array.isArray(args.change_rationales) ? { changeRationales: args.change_rationales } : {})
287
+ }),
263
288
  subcommand: 'deliver'
264
289
  },
265
290
  {
@@ -490,17 +515,24 @@ function cliArgsFromFlags(flags) {
490
515
  }
491
516
 
492
517
  async function runProtocol(tool, args) {
493
- const cliArgs = ['protocol', tool.subcommand, ...cliArgsFromFlags(tool.toCliFlags(args ?? {}))];
518
+ const toolArgs = args ?? {};
519
+ const cliArgs = ['protocol', tool.subcommand, ...cliArgsFromFlags(tool.toCliFlags(toolArgs))];
520
+ const stdin = typeof tool.toCliStdin === 'function' ? tool.toCliStdin(toolArgs) : undefined;
494
521
 
495
522
  try {
496
- const { stdout, stderr } = await execFileAsync(OVLD_BIN, cliArgs, {
497
- cwd: process.cwd(),
498
- env: {
499
- ...process.env,
500
- AGENT_IDENTIFIER: process.env.AGENT_IDENTIFIER ?? 'codex-overlord-plugin'
523
+ const { stdout, stderr } = await execFileWithOptionalInput(
524
+ OVLD_BIN,
525
+ cliArgs,
526
+ {
527
+ cwd: process.cwd(),
528
+ env: {
529
+ ...process.env,
530
+ AGENT_IDENTIFIER: process.env.AGENT_IDENTIFIER ?? 'codex-overlord-plugin'
531
+ },
532
+ maxBuffer: 20 * 1024 * 1024
501
533
  },
502
- maxBuffer: 20 * 1024 * 1024
503
- });
534
+ stdin
535
+ );
504
536
 
505
537
  const trimmed = stdout.trim();
506
538
  const data = trimmed ? JSON.parse(trimmed) : {};
@@ -15,7 +15,7 @@ Overlord plugin.
15
15
  and stop.
16
16
  6. Deliver last with `ovld protocol deliver`, including meaningful `changeRationales` for every
17
17
  behavioral git-tracked change.
18
- If you need `--payload-file`, `--artifacts-file`, or `--change-rationales-file`, treat that JSON as ephemeral scratch data, not as a repository file. Remove it after delivery and never commit it.
18
+ For larger delivery JSON, prefer `--payload-file -` and stream the full payload on stdin so no scratch file needs to be created or removed. If you need `--payload-file`, `--artifacts-file`, or `--change-rationales-file` with a real path, treat that JSON as ephemeral scratch data, not as a repository file. Remove it after delivery and never commit it.
19
19
 
20
20
  ## Rules
21
21