overlord-cli 0.2608180731.0 → 0.2608181022.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
|
@@ -18952,7 +18952,7 @@ function withWorktreeFields(input, branch) {
|
|
|
18952
18952
|
cycle: Number.isFinite(cycleMatch) && cycleMatch > 1 ? cycleMatch : 1
|
|
18953
18953
|
};
|
|
18954
18954
|
}
|
|
18955
|
-
function
|
|
18955
|
+
function planSharedMissionBranch(input) {
|
|
18956
18956
|
const baseBranch = canonicalMissionBranch(input.mission);
|
|
18957
18957
|
const allRefs = refSet([...input.refs.local, ...input.refs.remote]);
|
|
18958
18958
|
const mergedRefs = refSet(input.refs.merged);
|
|
@@ -18982,6 +18982,46 @@ function planMissionBranch(input) {
|
|
|
18982
18982
|
}
|
|
18983
18983
|
return { action: "new_cycle", ...withWorktreeFields(input, candidate), from: input.base };
|
|
18984
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
|
+
}
|
|
18985
19025
|
var TITLE_SLUG_MAX;
|
|
18986
19026
|
var init_branch_planning = __esm({
|
|
18987
19027
|
"src/branch-planning.ts"() {
|
|
@@ -19230,6 +19270,48 @@ function resolveLaunchResourceKey({
|
|
|
19230
19270
|
}
|
|
19231
19271
|
return deriveProjectResourceKey({ directoryPath: options.workingDirectory });
|
|
19232
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
|
+
}
|
|
19233
19315
|
async function prepareMissionBranch({
|
|
19234
19316
|
runtime,
|
|
19235
19317
|
options
|
|
@@ -19256,6 +19338,7 @@ async function prepareMissionBranch({
|
|
|
19256
19338
|
const overrideBranch = overrideFlag || missionOverrideBranch(mission);
|
|
19257
19339
|
const projectSlug = await resolveMissionProjectSlug({ runtime, mission });
|
|
19258
19340
|
const resourceKey = resolveLaunchResourceKey({ mission, options });
|
|
19341
|
+
const isolation = await resolveBranchIsolation({ runtime, mission, options, useWorktree });
|
|
19259
19342
|
const decision = planMissionBranch({
|
|
19260
19343
|
mission: {
|
|
19261
19344
|
title: typeof mission.title === "string" ? mission.title : "mission",
|
|
@@ -19267,8 +19350,10 @@ async function prepareMissionBranch({
|
|
|
19267
19350
|
base,
|
|
19268
19351
|
refs,
|
|
19269
19352
|
worktreeRoot: resolveWorktreeRoot(),
|
|
19270
|
-
overrideBranch
|
|
19353
|
+
overrideBranch,
|
|
19354
|
+
isolation
|
|
19271
19355
|
});
|
|
19356
|
+
const isolated = Boolean(isolation) && !overrideBranch;
|
|
19272
19357
|
if (useWorktree) {
|
|
19273
19358
|
ensureWorktree(gitRoot, decision);
|
|
19274
19359
|
return {
|
|
@@ -19279,7 +19364,8 @@ async function prepareMissionBranch({
|
|
|
19279
19364
|
worktreePath: decision.worktreePath,
|
|
19280
19365
|
resourceKey,
|
|
19281
19366
|
action: decision.action,
|
|
19282
|
-
cycle: decision.cycle
|
|
19367
|
+
cycle: decision.cycle,
|
|
19368
|
+
isolated
|
|
19283
19369
|
}
|
|
19284
19370
|
};
|
|
19285
19371
|
}
|
|
@@ -19292,15 +19378,19 @@ async function prepareMissionBranch({
|
|
|
19292
19378
|
worktreePath: gitRoot,
|
|
19293
19379
|
resourceKey,
|
|
19294
19380
|
action: decision.action,
|
|
19295
|
-
cycle: decision.cycle
|
|
19381
|
+
cycle: decision.cycle,
|
|
19382
|
+
isolated: false
|
|
19296
19383
|
}
|
|
19297
19384
|
};
|
|
19298
19385
|
}
|
|
19386
|
+
var PARALLEL_BLOCKING_OBJECTIVE_STATES, DEFAULT_PRIMARY_RESOURCE_KEY;
|
|
19299
19387
|
var init_branch_preparation = __esm({
|
|
19300
19388
|
"src/branch-preparation.ts"() {
|
|
19301
19389
|
"use strict";
|
|
19302
19390
|
init_project_resource_key();
|
|
19303
19391
|
init_branch_planning();
|
|
19392
|
+
PARALLEL_BLOCKING_OBJECTIVE_STATES = ["launching", "executing", "pending_delivery"];
|
|
19393
|
+
DEFAULT_PRIMARY_RESOURCE_KEY = "primary";
|
|
19304
19394
|
}
|
|
19305
19395
|
});
|
|
19306
19396
|
|
|
@@ -20708,7 +20798,7 @@ Subcommands:
|
|
|
20708
20798
|
search-missions Find missions by keyword, status, or project
|
|
20709
20799
|
discuss-objective Mark a draft objective as submitted (does not start execution)
|
|
20710
20800
|
add-objectives Append ordered objectives to an existing mission
|
|
20711
|
-
update-objective Set auto-advance on an
|
|
20801
|
+
update-objective Set auto-advance and/or instruction text on an objective
|
|
20712
20802
|
create Create a draft mission without attaching
|
|
20713
20803
|
prompt Create a mission and attach to it immediately
|
|
20714
20804
|
record-work Record completed-from-chat work as a review mission (no attach)
|
|
@@ -20833,12 +20923,17 @@ add-objectives:
|
|
|
20833
20923
|
|
|
20834
20924
|
update-objective:
|
|
20835
20925
|
Purpose:
|
|
20836
|
-
Turn auto-advance on or off
|
|
20926
|
+
Turn auto-advance on or off and/or edit instruction text on an existing objective.
|
|
20837
20927
|
Required:
|
|
20838
20928
|
--objective-id <id>
|
|
20839
|
-
|
|
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.
|
|
20840
20935
|
Returns:
|
|
20841
|
-
The updated objective JSON, including autoAdvance.
|
|
20936
|
+
The updated objective JSON, including autoAdvance and instructionText.
|
|
20842
20937
|
|
|
20843
20938
|
create:
|
|
20844
20939
|
Purpose:
|