overlord-cli 0.2605160931.0 → 0.2605161310.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.
@@ -2,6 +2,9 @@
2
2
 
3
3
  import { spawnSync } from 'node:child_process';
4
4
  import { createRequire } from 'node:module';
5
+ import fs from 'node:fs';
6
+ import os from 'node:os';
7
+ import path from 'node:path';
5
8
 
6
9
  const require = createRequire(import.meta.url);
7
10
  const cliPackage = require('../../package.json');
@@ -50,6 +53,41 @@ export async function fetchLatestCliVersion({
50
53
  }
51
54
  }
52
55
 
56
+ function pruneOldCliVersions() {
57
+ const cliInstallRoot = path.join(os.homedir(), '.ovld', 'cli');
58
+ if (!fs.existsSync(cliInstallRoot)) return;
59
+
60
+ let entries;
61
+ try {
62
+ entries = fs.readdirSync(cliInstallRoot);
63
+ } catch {
64
+ return;
65
+ }
66
+
67
+ const versionDirs = entries
68
+ .filter(name => name.startsWith('overlord-cli-'))
69
+ .flatMap(name => {
70
+ const dirPath = path.join(cliInstallRoot, name);
71
+ try {
72
+ const stat = fs.statSync(dirPath);
73
+ if (!stat.isDirectory()) return [];
74
+ return [{ dirPath, mtime: stat.mtimeMs }];
75
+ } catch {
76
+ return [];
77
+ }
78
+ });
79
+
80
+ // Sort newest-first, keep current + 1 previous, delete the rest
81
+ versionDirs.sort((a, b) => b.mtime - a.mtime);
82
+ for (const { dirPath } of versionDirs.slice(2)) {
83
+ try {
84
+ fs.rmSync(dirPath, { recursive: true, force: true });
85
+ } catch {
86
+ // Best-effort cleanup
87
+ }
88
+ }
89
+ }
90
+
53
91
  export async function checkForCliUpdate(options = {}) {
54
92
  const currentVersion = options.currentVersion ?? CURRENT_CLI_VERSION;
55
93
  const latestVersion = await fetchLatestCliVersion(options);
@@ -115,5 +153,7 @@ export async function runCliUpdateCommand({
115
153
  logger.log('Overlord CLI update complete. Run `ovld version` to confirm the installed version.');
116
154
  }
117
155
 
156
+ pruneOldCliVersions();
157
+
118
158
  return { alreadyLatest: false, currentVersion, latestVersion, result };
119
159
  }
@@ -1035,6 +1035,42 @@ async function protocolAsk(args) {
1035
1035
  console.log(JSON.stringify(data, null, 2));
1036
1036
  }
1037
1037
 
1038
+ // ---------------------------------------------------------------------------
1039
+ // request-approval-gate
1040
+ // ---------------------------------------------------------------------------
1041
+
1042
+ async function protocolRequestApprovalGate(args) {
1043
+ const flags = parseFlags(args);
1044
+ const { sessionKey, ticketId } = resolveSessionFlags(flags);
1045
+ if (!sessionKey) throw new Error('--session-key is required (or set SESSION_KEY)');
1046
+ if (!ticketId) throw new Error('--ticket-id is required (or set TICKET_ID)');
1047
+ const reason = flags['reason-file']
1048
+ ? await readTextFileOrStdin(String(flags['reason-file']), '--reason-file')
1049
+ : requireFlag(flags, 'reason', undefined);
1050
+
1051
+ const { platformUrl, bearerToken, localSecret, organizationId } =
1052
+ await resolveProtocolAuthForFlags(flags, ticketId);
1053
+ const timeoutMs = resolveTimeout(flags);
1054
+
1055
+ const body = {
1056
+ sessionKey,
1057
+ ticketId,
1058
+ reason,
1059
+ ...(flags['objective-id'] ? { objectiveId: String(flags['objective-id']) } : {})
1060
+ };
1061
+
1062
+ const data = await apiPost(
1063
+ platformUrl,
1064
+ bearerToken,
1065
+ localSecret,
1066
+ organizationId,
1067
+ '/api/protocol/request-approval-gate',
1068
+ body,
1069
+ timeoutMs
1070
+ );
1071
+ console.log(JSON.stringify(data, null, 2));
1072
+ }
1073
+
1038
1074
  // ---------------------------------------------------------------------------
1039
1075
  // permission-request
1040
1076
  // ---------------------------------------------------------------------------
@@ -2238,6 +2274,7 @@ Subcommands:
2238
2274
  update Post progress, activity events, and optional change rationales
2239
2275
  record-change-rationales Persist structured change rationales without a progress update
2240
2276
  ask Post a blocking question and move the ticket to review
2277
+ request-approval-gate Flip auto_advance=false on the next queued future objective
2241
2278
  permission-request Notify Overlord that the agent is requesting tool permission
2242
2279
  hook-event Record a lifecycle hook event without a session key
2243
2280
  read-context Read shared persistent context for this ticket
@@ -2779,6 +2816,10 @@ EOF
2779
2816
  await protocolAsk(args);
2780
2817
  return;
2781
2818
  }
2819
+ if (subcommand === 'request-approval-gate') {
2820
+ await protocolRequestApprovalGate(args);
2821
+ return;
2822
+ }
2782
2823
  if (subcommand === 'permission-request') {
2783
2824
  await protocolPermissionRequest(args);
2784
2825
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "overlord-cli",
3
- "version": "0.2605160931.0",
3
+ "version": "0.2605161310.0",
4
4
  "description": "Overlord CLI — launch AI agents on tickets from anywhere",
5
5
  "homepage": "https://www.ovld.ai/docs/",
6
6
  "type": "module",
@@ -292,6 +292,31 @@ const tools = [
292
292
  }),
293
293
  subcommand: 'ask'
294
294
  },
295
+ {
296
+ name: 'request_approval_gate',
297
+ description:
298
+ 'Flip auto_advance=false on the next queued future objective so a human must approve before it runs.',
299
+ inputSchema: {
300
+ type: 'object',
301
+ properties: {
302
+ session_key: { type: 'string' },
303
+ ticket_id: {
304
+ type: 'string',
305
+ description: 'Ticket identifier (e.g. 1:899). Also accepts UUID.'
306
+ },
307
+ reason: { type: 'string' },
308
+ objective_id: { type: 'string' }
309
+ },
310
+ required: ['session_key', 'ticket_id', 'reason']
311
+ },
312
+ toCliFlags: args => ({
313
+ 'session-key': args.session_key,
314
+ 'ticket-id': args.ticket_id,
315
+ reason: args.reason,
316
+ 'objective-id': args.objective_id
317
+ }),
318
+ subcommand: 'request-approval-gate'
319
+ },
295
320
  {
296
321
  name: 'read_context',
297
322
  description: 'Read persistent shared context entries for a ticket.',