overlord-cli 0.2606010745.0 → 0.2606011152.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/README.md CHANGED
@@ -158,6 +158,8 @@ Devices are keyed by **(organization, user, fingerprint)** so the same physical
158
158
 
159
159
  `ovld runner start` keeps a foreground runner alive for CLI-only or remote hosts. It claims compatible execution requests for the current device and launches the assigned agent/model with `ovld launch`; `ovld runner once` claims at most one request and exits. `ovld runner status` now prints the local device record plus the active queue visible to that runner. `ovld runner clear <objective_id>` clears one queued objective, and `ovld runner clear-all` clears every active queue row visible to the caller. By default a single runner drains queued requests from **every organization you belong to**, so you do not need one runner per org. Pin it to a single org with `--organization-id <id>` or `OVERLORD_ORGANIZATION_ID`.
160
160
 
161
+ If you are troubleshooting "why is `ovld runner` randomly executing", the runner is usually claiming a request that was already queued by manual Run or auto-advance. Inspect the queue with `ovld runner status`, then clear the specific objective with `ovld runner clear 8974e557-bec4-4984-b12c-be46bd63207c` or `ovld protocol clear-execution-requests --objective-id 8974e557-bec4-4984-b12c-be46bd63207c`.
162
+
161
163
  Use `create` for future work you want to track, `prompt` for work that should start immediately, and `record-work` for work that was already completed in chat and now needs a review ticket plus feed post. Use multiple tickets when prompts represent different features or goals; use `add-objectives` or `--objectives-json '[{"objective":"Step one"},{"objective":"Step two"}]'` when prompts are sequential steps toward the same feature or goal.
162
164
 
163
165
  `ovld protocol deliver` accepts either discrete flags like `--summary` / `--artifacts-json`, an inline full payload with `--payload-json '{"summary":"...","artifacts":[...],"changeRationales":[...]}'`, or a file/stdin payload with `--payload-file <path|->`.
@@ -85,6 +85,18 @@ async function resolveProtocolMetadata(flags = {}, base = {}) {
85
85
  metadata.model = modelIdentifier;
86
86
  }
87
87
 
88
+ // Thread the originating execution request id (set by the runner via
89
+ // OVERLORD_EXECUTION_REQUEST_ID, or an explicit flag) into attach metadata so
90
+ // the server marks that exact request `launched` instead of falling back to
91
+ // matching by objective.
92
+ const executionRequestId =
93
+ (typeof flags['execution-request-id'] === 'string'
94
+ ? flags['execution-request-id'].trim()
95
+ : '') || process.env.OVERLORD_EXECUTION_REQUEST_ID?.trim();
96
+ if (executionRequestId) {
97
+ metadata.executionRequestId = executionRequestId;
98
+ }
99
+
88
100
  const snapshot = await resolveSnapshotContext(flags);
89
101
  if (snapshot) {
90
102
  metadata.snapshot = snapshot;
@@ -171,13 +171,17 @@ function resolvePinnedOrganizationId(flags) {
171
171
  const ORGANIZATION_REFRESH_MS = 60_000;
172
172
 
173
173
  /**
174
- * Resolves which organizations a poll pass should claim from.
174
+ * Resolves which organizations a fan-out pass (list / clear-all) should act on.
175
175
  *
176
176
  * - When the user pins an org (`--organization-id` flag or
177
- * `OVERLORD_ORGANIZATION_ID`), only that org is polled.
178
- * - Otherwise the runner discovers every org the authenticated user belongs to
179
- * and polls each one. If discovery fails or returns nothing, it falls back to
180
- * the credential default (an empty scope id) so behavior never regresses.
177
+ * `OVERLORD_ORGANIZATION_ID`), only that org is used.
178
+ * - Otherwise the runner discovers every org the authenticated user belongs to.
179
+ * If discovery fails or returns nothing, it falls back to the credential
180
+ * default (an empty scope id) so behavior never regresses.
181
+ *
182
+ * NOTE: this is for the per-org fan-out commands. The claim poll uses
183
+ * {@link createClaimOrganizationScope}, which is org-agnostic — the server's
184
+ * `claim-execution` is authoritative and spans the user's target-sharing orgs.
181
185
  */
182
186
  export function createOrganizationScope(flags, deviceFingerprint) {
183
187
  const pinned = resolvePinnedOrganizationId(flags);
@@ -211,6 +215,17 @@ export function createOrganizationScope(flags, deviceFingerprint) {
211
215
  };
212
216
  }
213
217
 
218
+ /**
219
+ * Resolves the org scope for the claim poll (G3). A pinned org still scopes the
220
+ * poll; otherwise the runner does a single org-agnostic poll (empty scope) and
221
+ * lets the server claim across every org the user belongs to that shares the
222
+ * claiming target — no org discovery or per-org looping needed.
223
+ */
224
+ export function createClaimOrganizationScope(flags) {
225
+ const pinned = resolvePinnedOrganizationId(flags);
226
+ return { pinned: Boolean(pinned), resolve: () => [pinned || ''] };
227
+ }
228
+
214
229
  function completeLaunch(requestId, deviceFingerprint) {
215
230
  protocolJson(
216
231
  'complete-execution-launch',
@@ -276,11 +291,19 @@ function normalizeRunnerTerminalProfile(value) {
276
291
  };
277
292
  }
278
293
 
279
- function buildRunnerLaunchShellCommand(args, deviceFingerprint) {
280
- return [
281
- `export OVERLORD_DEVICE_FINGERPRINT=${shellQuote(deviceFingerprint)}`,
294
+ function buildRunnerLaunchShellCommand(args, deviceFingerprint, executionRequestId) {
295
+ const lines = [`export OVERLORD_DEVICE_FINGERPRINT=${shellQuote(deviceFingerprint)}`];
296
+ // Terminal-profile launches run this generated script in a fresh shell, so the
297
+ // request id must be exported here too (the direct-spawn path inherits it via
298
+ // the child env). Without it, attach in the new terminal falls back to
299
+ // objective matching.
300
+ if (executionRequestId) {
301
+ lines.push(`export OVERLORD_EXECUTION_REQUEST_ID=${shellQuote(executionRequestId)}`);
302
+ }
303
+ lines.push(
282
304
  `exec ${shellQuote(process.execPath)} ${[OVLD_ENTRY, ...args].map(shellQuote).join(' ')}`
283
- ].join('\n');
305
+ );
306
+ return lines.join('\n');
284
307
  }
285
308
 
286
309
  function writeRunnerLaunchScript(launchCommand) {
@@ -375,7 +398,7 @@ export function buildRunnerTerminalOpenCommand(
375
398
 
376
399
  function spawnLaunchProcess(args, claim, deviceFingerprint) {
377
400
  const spawnImpl = runnerTestHooks.spawn ?? spawn;
378
- const launchCommand = buildRunnerLaunchShellCommand(args, deviceFingerprint);
401
+ const launchCommand = buildRunnerLaunchShellCommand(args, deviceFingerprint, claim.request?.id);
379
402
  const terminalCommand = buildRunnerTerminalOpenCommand(
380
403
  claim.launch?.runnerTerminalProfile,
381
404
  launchCommand,
@@ -466,7 +489,7 @@ export async function launchClaimedRequest(claim, deviceFingerprint) {
466
489
  }
467
490
 
468
491
  export async function runOnce(flags, deviceFingerprint, organizationScope) {
469
- const scope = organizationScope ?? createOrganizationScope(flags, deviceFingerprint);
492
+ const scope = organizationScope ?? createClaimOrganizationScope(flags);
470
493
  const organizationIds = scope.resolve();
471
494
 
472
495
  let launchedAny = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "overlord-cli",
3
- "version": "0.2606010745.0",
3
+ "version": "0.2606011152.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",