overlord-cli 0.2608172109.0 → 0.2608180913.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.
|
@@ -9,6 +9,6 @@
|
|
|
9
9
|
- `overlord_record_work` (hosted MCP) and `ovld protocol record-work` (CLI) record already-completed chat work as a single review-column mission with a completed objective, file-change rationales, and the standard Gemini delivery summary — no `attach`/`deliver`. Hosted MCP requires `projectId` (it never chooses a project implicitly); the CLI resolves the project from the working directory or `--project-id`. The submission format is in [record-work.md](record-work.md). The route is `POST /api/protocol/record-work`.
|
|
10
10
|
- `overlord_add_artifact` (hosted MCP) and `ovld protocol add-artifact` (CLI) create a mission artifact during a turn without delivering. Required: `missionId` / `--mission-id`, `type` / `--type`, `label` / `--label`, plus at least one of `contentText` / `--content-text`/`--content-text-file` or `externalUrl` / `--external-url`. Optional `sessionKey` / `--session-key` stamps session/objective provenance. Same service as REST `POST /api/missions/:id/artifacts`. The route is `POST /api/protocol/add-artifact`.
|
|
11
11
|
- `overlord_update_artifact` (hosted MCP) and `ovld protocol update-artifact` (CLI) revise an existing mission artifact's label, Markdown content, and/or HTTP(S) URL in place. Required: `missionId` / `--mission-id`, `artifactId` / `--artifact-id`, `expectedRevision` / `--expected-revision`. Provide at least one editable field. No session key is required. Same service as REST `PATCH /api/missions/:id/artifacts/:artifactId`. The route is `POST /api/protocol/update-artifact`.
|
|
12
|
-
- `overlord_create_mission` / `overlord_add_objectives` accept optional `autoAdvance` (boolean; default false). `overlord_update_objective` (`objectiveId`
|
|
12
|
+
- `overlord_create_mission` / `overlord_add_objectives` accept optional `autoAdvance` (boolean; default false). `overlord_update_objective` (`objectiveId` plus optional `autoAdvance` and/or `instructionText`) and `ovld protocol update-objective --objective-id <id>` with `--auto-advance|--no-auto-advance` and/or `--instruction-text|--instruction-text-file` update an existing objective. Instruction text is editable only in `draft` or `future` state. The route is `POST /api/protocol/update-objective`.
|
|
13
13
|
- Objective attachment tools follow the `<verb>_<noun>` MCP naming: `list_attachments`, `prepare_attachment_upload`, `finalize_attachment_upload`, `get_attachment_download_url`, `upload_attachment_file`. CLI commands use `attachment-*`. `mission_id` / `missionId` is optional for attachment calls when the objective or attachment id lets the server derive mission scope.
|
|
14
14
|
- "Artifacts" may be published mid-turn with `add-artifact` / `overlord_add_artifact`, revised with `update-artifact` / `overlord_update_artifact`, or attached at `deliver` time (next_steps, test_results, migration, decision, note, url) — not user-uploaded files. Files attached by users live on objectives via the attachment tools above.
|
|
@@ -198,17 +198,20 @@ const tools = [
|
|
|
198
198
|
},
|
|
199
199
|
{
|
|
200
200
|
name: 'overlord_update_objective',
|
|
201
|
-
title: 'Update objective
|
|
201
|
+
title: 'Update objective',
|
|
202
202
|
description:
|
|
203
|
-
'Turn auto-advance on or off
|
|
203
|
+
'Turn auto-advance on or off and/or edit instruction text on a draft or future objective.',
|
|
204
204
|
inputSchema: objectSchema(
|
|
205
205
|
{
|
|
206
|
-
objectiveId: stringProperty('Objective UUID.'),
|
|
206
|
+
objectiveId: stringProperty('Objective UUID or display id.'),
|
|
207
207
|
autoAdvance: booleanProperty(
|
|
208
208
|
'When true, Overlord queues the next objective after this one is delivered. When false, delivery waits for approval.'
|
|
209
|
+
),
|
|
210
|
+
instructionText: stringProperty(
|
|
211
|
+
'Replacement instruction text. Allowed only when the objective is in draft or future state; blank clears the text in those states.'
|
|
209
212
|
)
|
|
210
213
|
},
|
|
211
|
-
['objectiveId'
|
|
214
|
+
['objectiveId']
|
|
212
215
|
)
|
|
213
216
|
},
|
|
214
217
|
{
|
|
@@ -436,10 +439,15 @@ function callOverlordTool(name, args) {
|
|
|
436
439
|
});
|
|
437
440
|
}
|
|
438
441
|
if (name === 'overlord_update_objective') {
|
|
439
|
-
|
|
442
|
+
const hasAutoAdvance = typeof args.autoAdvance === 'boolean';
|
|
443
|
+
const hasInstructionText = typeof args.instructionText === 'string';
|
|
444
|
+
if (!hasAutoAdvance && !hasInstructionText) {
|
|
445
|
+
throw new Error('Provide autoAdvance and/or instructionText');
|
|
446
|
+
}
|
|
440
447
|
return runProtocol('update-objective', {
|
|
441
448
|
'objective-id': requiredString(args, 'objectiveId'),
|
|
442
|
-
...(args.autoAdvance ? { 'auto-advance': true } : { 'no-auto-advance': true })
|
|
449
|
+
...(hasAutoAdvance ? (args.autoAdvance ? { 'auto-advance': true } : { 'no-auto-advance': true }) : {}),
|
|
450
|
+
...(hasInstructionText ? { 'instruction-text': requiredString(args, 'instructionText') } : {})
|
|
443
451
|
});
|
|
444
452
|
}
|
|
445
453
|
if (name === 'overlord_attach_session') {
|
package/dist/index.js
CHANGED
|
@@ -17452,6 +17452,41 @@ var init_latch_events = __esm({
|
|
|
17452
17452
|
}
|
|
17453
17453
|
});
|
|
17454
17454
|
|
|
17455
|
+
// ../packages/core/dist/service/latch-harness-ingest.js
|
|
17456
|
+
function encodedEventSize(event) {
|
|
17457
|
+
return new TextEncoder().encode(JSON.stringify(event)).length;
|
|
17458
|
+
}
|
|
17459
|
+
function chunkLatchHarnessEventsForIngest({ events, from, maxBytes = HARNESS_EVENT_INGEST_MAX_BYTES }) {
|
|
17460
|
+
if (events.length === 0)
|
|
17461
|
+
return [];
|
|
17462
|
+
const chunks = [];
|
|
17463
|
+
let chunk = [];
|
|
17464
|
+
let chunkFrom = from;
|
|
17465
|
+
let used = 2;
|
|
17466
|
+
for (const event of events) {
|
|
17467
|
+
const size = encodedEventSize(event);
|
|
17468
|
+
const extra = (chunk.length === 0 ? 0 : 1) + size;
|
|
17469
|
+
if (chunk.length > 0 && used + extra > maxBytes) {
|
|
17470
|
+
chunks.push({ events: chunk, from: chunkFrom });
|
|
17471
|
+
chunkFrom += chunk.length;
|
|
17472
|
+
chunk = [event];
|
|
17473
|
+
used = 2 + size;
|
|
17474
|
+
continue;
|
|
17475
|
+
}
|
|
17476
|
+
chunk.push(event);
|
|
17477
|
+
used += extra;
|
|
17478
|
+
}
|
|
17479
|
+
chunks.push({ events: chunk, from: chunkFrom });
|
|
17480
|
+
return chunks;
|
|
17481
|
+
}
|
|
17482
|
+
var HARNESS_EVENT_INGEST_MAX_BYTES;
|
|
17483
|
+
var init_latch_harness_ingest = __esm({
|
|
17484
|
+
"../packages/core/dist/service/latch-harness-ingest.js"() {
|
|
17485
|
+
"use strict";
|
|
17486
|
+
HARNESS_EVENT_INGEST_MAX_BYTES = 64 * 1024;
|
|
17487
|
+
}
|
|
17488
|
+
});
|
|
17489
|
+
|
|
17455
17490
|
// ../packages/core/dist/service/util.js
|
|
17456
17491
|
function nowIso() {
|
|
17457
17492
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -18917,7 +18952,7 @@ function withWorktreeFields(input, branch) {
|
|
|
18917
18952
|
cycle: Number.isFinite(cycleMatch) && cycleMatch > 1 ? cycleMatch : 1
|
|
18918
18953
|
};
|
|
18919
18954
|
}
|
|
18920
|
-
function
|
|
18955
|
+
function planSharedMissionBranch(input) {
|
|
18921
18956
|
const baseBranch = canonicalMissionBranch(input.mission);
|
|
18922
18957
|
const allRefs = refSet([...input.refs.local, ...input.refs.remote]);
|
|
18923
18958
|
const mergedRefs = refSet(input.refs.merged);
|
|
@@ -18947,6 +18982,46 @@ function planMissionBranch(input) {
|
|
|
18947
18982
|
}
|
|
18948
18983
|
return { action: "new_cycle", ...withWorktreeFields(input, candidate), from: input.base };
|
|
18949
18984
|
}
|
|
18985
|
+
function isolationParent(sharedBranch, allRefs, base) {
|
|
18986
|
+
return allRefs.has(sharedBranch) ? sharedBranch : base;
|
|
18987
|
+
}
|
|
18988
|
+
function isolateDecision(input, shared) {
|
|
18989
|
+
const key = sanitizeBranchName(input.isolation?.objectiveKey ?? "", "");
|
|
18990
|
+
if (!key) return shared;
|
|
18991
|
+
const allRefs = refSet([...input.refs.local, ...input.refs.remote]);
|
|
18992
|
+
const mergedRefs = refSet(input.refs.merged);
|
|
18993
|
+
const checkedOutRefs = refSet(input.refs.checkedOut ?? []);
|
|
18994
|
+
const isolatedBase = sanitizeBranchName(`${shared.branch}-${key}`, shared.branch);
|
|
18995
|
+
if (isolatedBase === shared.branch) return shared;
|
|
18996
|
+
if (!allRefs.has(isolatedBase)) {
|
|
18997
|
+
return {
|
|
18998
|
+
action: "create",
|
|
18999
|
+
...withWorktreeFields(input, isolatedBase),
|
|
19000
|
+
cycle: 1,
|
|
19001
|
+
from: isolationParent(shared.branch, allRefs, input.base)
|
|
19002
|
+
};
|
|
19003
|
+
}
|
|
19004
|
+
if (!mergedRefs.has(isolatedBase)) {
|
|
19005
|
+
return { action: "reuse", ...withWorktreeFields(input, isolatedBase), cycle: 1 };
|
|
19006
|
+
}
|
|
19007
|
+
let cycle = Math.max(2, highestExistingCycle(isolatedBase, allRefs) + 1);
|
|
19008
|
+
let candidate = `${isolatedBase}-${cycle}`;
|
|
19009
|
+
while (allRefs.has(candidate) || checkedOutRefs.has(candidate) || mergedRefs.has(candidate)) {
|
|
19010
|
+
cycle += 1;
|
|
19011
|
+
candidate = `${isolatedBase}-${cycle}`;
|
|
19012
|
+
}
|
|
19013
|
+
return {
|
|
19014
|
+
action: "new_cycle",
|
|
19015
|
+
...withWorktreeFields(input, candidate),
|
|
19016
|
+
cycle,
|
|
19017
|
+
from: isolationParent(shared.branch, allRefs, input.base)
|
|
19018
|
+
};
|
|
19019
|
+
}
|
|
19020
|
+
function planMissionBranch(input) {
|
|
19021
|
+
const shared = planSharedMissionBranch(input);
|
|
19022
|
+
if (!input.isolation || input.overrideBranch) return shared;
|
|
19023
|
+
return isolateDecision(input, shared);
|
|
19024
|
+
}
|
|
18950
19025
|
var TITLE_SLUG_MAX;
|
|
18951
19026
|
var init_branch_planning = __esm({
|
|
18952
19027
|
"src/branch-planning.ts"() {
|
|
@@ -19195,6 +19270,48 @@ function resolveLaunchResourceKey({
|
|
|
19195
19270
|
}
|
|
19196
19271
|
return deriveProjectResourceKey({ directoryPath: options.workingDirectory });
|
|
19197
19272
|
}
|
|
19273
|
+
function readString(value) {
|
|
19274
|
+
return typeof value === "string" ? value.trim() : "";
|
|
19275
|
+
}
|
|
19276
|
+
async function resolveProjectPrimaryResourceKey({
|
|
19277
|
+
runtime,
|
|
19278
|
+
mission
|
|
19279
|
+
}) {
|
|
19280
|
+
const projectId = readString(mission.projectId);
|
|
19281
|
+
if (!projectId) return DEFAULT_PRIMARY_RESOURCE_KEY;
|
|
19282
|
+
try {
|
|
19283
|
+
const resources = await runtime.backend.get(
|
|
19284
|
+
`/api/projects/${encodeURIComponent(projectId)}/resources`
|
|
19285
|
+
);
|
|
19286
|
+
if (!Array.isArray(resources)) return DEFAULT_PRIMARY_RESOURCE_KEY;
|
|
19287
|
+
const primary = resources.find((resource) => resource?.isPrimary === true);
|
|
19288
|
+
return readString(primary?.resourceKey) || DEFAULT_PRIMARY_RESOURCE_KEY;
|
|
19289
|
+
} catch {
|
|
19290
|
+
return DEFAULT_PRIMARY_RESOURCE_KEY;
|
|
19291
|
+
}
|
|
19292
|
+
}
|
|
19293
|
+
async function resolveBranchIsolation({
|
|
19294
|
+
runtime,
|
|
19295
|
+
mission,
|
|
19296
|
+
options,
|
|
19297
|
+
useWorktree
|
|
19298
|
+
}) {
|
|
19299
|
+
if (!useWorktree) return null;
|
|
19300
|
+
if (mission.allowParallelObjectives !== true) return null;
|
|
19301
|
+
const objectiveId = readString(options.objectiveId);
|
|
19302
|
+
if (!objectiveId) return null;
|
|
19303
|
+
const objectives = Array.isArray(mission.objectives) ? mission.objectives : [];
|
|
19304
|
+
const self = objectives.find((candidate) => readString(candidate.id) === objectiveId);
|
|
19305
|
+
const objectiveKey = readString(self?.displayKey);
|
|
19306
|
+
if (!self || !objectiveKey) return null;
|
|
19307
|
+
const primaryResourceKey = await resolveProjectPrimaryResourceKey({ runtime, mission });
|
|
19308
|
+
const canonical = (value) => readString(value) || primaryResourceKey;
|
|
19309
|
+
const selfResourceKey = canonical(self.resourceKey);
|
|
19310
|
+
const hasLiveSibling = objectives.some(
|
|
19311
|
+
(candidate) => readString(candidate.id) !== objectiveId && PARALLEL_BLOCKING_OBJECTIVE_STATES.includes(readString(candidate.state)) && canonical(candidate.resourceKey) === selfResourceKey
|
|
19312
|
+
);
|
|
19313
|
+
return hasLiveSibling ? { objectiveKey } : null;
|
|
19314
|
+
}
|
|
19198
19315
|
async function prepareMissionBranch({
|
|
19199
19316
|
runtime,
|
|
19200
19317
|
options
|
|
@@ -19221,6 +19338,7 @@ async function prepareMissionBranch({
|
|
|
19221
19338
|
const overrideBranch = overrideFlag || missionOverrideBranch(mission);
|
|
19222
19339
|
const projectSlug = await resolveMissionProjectSlug({ runtime, mission });
|
|
19223
19340
|
const resourceKey = resolveLaunchResourceKey({ mission, options });
|
|
19341
|
+
const isolation = await resolveBranchIsolation({ runtime, mission, options, useWorktree });
|
|
19224
19342
|
const decision = planMissionBranch({
|
|
19225
19343
|
mission: {
|
|
19226
19344
|
title: typeof mission.title === "string" ? mission.title : "mission",
|
|
@@ -19232,8 +19350,10 @@ async function prepareMissionBranch({
|
|
|
19232
19350
|
base,
|
|
19233
19351
|
refs,
|
|
19234
19352
|
worktreeRoot: resolveWorktreeRoot(),
|
|
19235
|
-
overrideBranch
|
|
19353
|
+
overrideBranch,
|
|
19354
|
+
isolation
|
|
19236
19355
|
});
|
|
19356
|
+
const isolated = Boolean(isolation) && !overrideBranch;
|
|
19237
19357
|
if (useWorktree) {
|
|
19238
19358
|
ensureWorktree(gitRoot, decision);
|
|
19239
19359
|
return {
|
|
@@ -19244,7 +19364,8 @@ async function prepareMissionBranch({
|
|
|
19244
19364
|
worktreePath: decision.worktreePath,
|
|
19245
19365
|
resourceKey,
|
|
19246
19366
|
action: decision.action,
|
|
19247
|
-
cycle: decision.cycle
|
|
19367
|
+
cycle: decision.cycle,
|
|
19368
|
+
isolated
|
|
19248
19369
|
}
|
|
19249
19370
|
};
|
|
19250
19371
|
}
|
|
@@ -19257,15 +19378,19 @@ async function prepareMissionBranch({
|
|
|
19257
19378
|
worktreePath: gitRoot,
|
|
19258
19379
|
resourceKey,
|
|
19259
19380
|
action: decision.action,
|
|
19260
|
-
cycle: decision.cycle
|
|
19381
|
+
cycle: decision.cycle,
|
|
19382
|
+
isolated: false
|
|
19261
19383
|
}
|
|
19262
19384
|
};
|
|
19263
19385
|
}
|
|
19386
|
+
var PARALLEL_BLOCKING_OBJECTIVE_STATES, DEFAULT_PRIMARY_RESOURCE_KEY;
|
|
19264
19387
|
var init_branch_preparation = __esm({
|
|
19265
19388
|
"src/branch-preparation.ts"() {
|
|
19266
19389
|
"use strict";
|
|
19267
19390
|
init_project_resource_key();
|
|
19268
19391
|
init_branch_planning();
|
|
19392
|
+
PARALLEL_BLOCKING_OBJECTIVE_STATES = ["launching", "executing", "pending_delivery"];
|
|
19393
|
+
DEFAULT_PRIMARY_RESOURCE_KEY = "primary";
|
|
19269
19394
|
}
|
|
19270
19395
|
});
|
|
19271
19396
|
|
|
@@ -20673,7 +20798,7 @@ Subcommands:
|
|
|
20673
20798
|
search-missions Find missions by keyword, status, or project
|
|
20674
20799
|
discuss-objective Mark a draft objective as submitted (does not start execution)
|
|
20675
20800
|
add-objectives Append ordered objectives to an existing mission
|
|
20676
|
-
update-objective Set auto-advance on an
|
|
20801
|
+
update-objective Set auto-advance and/or instruction text on an objective
|
|
20677
20802
|
create Create a draft mission without attaching
|
|
20678
20803
|
prompt Create a mission and attach to it immediately
|
|
20679
20804
|
record-work Record completed-from-chat work as a review mission (no attach)
|
|
@@ -20798,12 +20923,17 @@ add-objectives:
|
|
|
20798
20923
|
|
|
20799
20924
|
update-objective:
|
|
20800
20925
|
Purpose:
|
|
20801
|
-
Turn auto-advance on or off
|
|
20926
|
+
Turn auto-advance on or off and/or edit instruction text on an existing objective.
|
|
20802
20927
|
Required:
|
|
20803
20928
|
--objective-id <id>
|
|
20804
|
-
|
|
20929
|
+
At least one of:
|
|
20930
|
+
--auto-advance or --no-auto-advance
|
|
20931
|
+
--instruction-text <text> or --instruction-text-file <path|->
|
|
20932
|
+
Rules:
|
|
20933
|
+
Instruction text may be edited only when the objective is in draft or future state.
|
|
20934
|
+
Blank instruction text is allowed in those states.
|
|
20805
20935
|
Returns:
|
|
20806
|
-
The updated objective JSON, including autoAdvance.
|
|
20936
|
+
The updated objective JSON, including autoAdvance and instructionText.
|
|
20807
20937
|
|
|
20808
20938
|
create:
|
|
20809
20939
|
Purpose:
|
|
@@ -24241,14 +24371,20 @@ async function postLatchHarnessEventsAfterLaunch({
|
|
|
24241
24371
|
from: 0
|
|
24242
24372
|
});
|
|
24243
24373
|
if (collected.events.length === 0) return;
|
|
24244
|
-
|
|
24245
|
-
|
|
24246
|
-
|
|
24247
|
-
providerSessionId,
|
|
24248
|
-
events: collected.events,
|
|
24249
|
-
from: collected.from
|
|
24250
|
-
}
|
|
24374
|
+
const chunks = chunkLatchHarnessEventsForIngest({
|
|
24375
|
+
events: collected.events,
|
|
24376
|
+
from: collected.from
|
|
24251
24377
|
});
|
|
24378
|
+
for (const chunk of chunks) {
|
|
24379
|
+
await backend.post({
|
|
24380
|
+
path: `/api/runner/requests/${requestId}/harness-events`,
|
|
24381
|
+
body: {
|
|
24382
|
+
providerSessionId,
|
|
24383
|
+
events: chunk.events,
|
|
24384
|
+
from: chunk.from
|
|
24385
|
+
}
|
|
24386
|
+
});
|
|
24387
|
+
}
|
|
24252
24388
|
} catch {
|
|
24253
24389
|
}
|
|
24254
24390
|
}
|
|
@@ -24258,6 +24394,7 @@ var init_commands = __esm({
|
|
|
24258
24394
|
"use strict";
|
|
24259
24395
|
init_dist2();
|
|
24260
24396
|
init_latch_events();
|
|
24397
|
+
init_latch_harness_ingest();
|
|
24261
24398
|
init_project_metadata();
|
|
24262
24399
|
init_local_target_mutation_runner();
|
|
24263
24400
|
init_terminal_profile_types2();
|