@odla-ai/cli 0.42.2 → 0.43.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/dist/bin.cjs +214 -66
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-K6ATAKGR.js → chunk-WDWJ7HC7.js} +182 -64
- package/dist/chunk-WDWJ7HC7.js.map +1 -0
- package/dist/{cli-4FCRBWED.js → cli-OITEPXW4.js} +2 -2
- package/dist/index.cjs +181 -63
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-K6ATAKGR.js.map +0 -1
- /package/dist/{cli-4FCRBWED.js.map → cli-OITEPXW4.js.map} +0 -0
package/dist/bin.js
CHANGED
|
@@ -174,7 +174,7 @@ function absoluteEntryPath(entryPath) {
|
|
|
174
174
|
|
|
175
175
|
// src/bin.ts
|
|
176
176
|
var argv = process.argv.slice(2);
|
|
177
|
-
requireCurrentCliForProvision(argv).then(() => requireCoherentProvisionRuntime(argv)).then(async () => (await import("./cli-
|
|
177
|
+
requireCurrentCliForProvision(argv).then(() => requireCoherentProvisionRuntime(argv)).then(async () => (await import("./cli-OITEPXW4.js")).runCli()).catch((err) => {
|
|
178
178
|
console.error(redactSecrets(`odla-ai: ${err instanceof Error ? err.message : String(err)}`));
|
|
179
179
|
process.exitCode = exitCodeFor(err);
|
|
180
180
|
});
|
|
@@ -10697,7 +10697,8 @@ Usage:
|
|
|
10697
10697
|
odla-ai pm bug list [--app <id>] [--status <s>] [--severity <s>] [--goal <id>] [--assignee <id>] [--decision <id>] [--q <text>] [--limit <n>] [--offset <n>] [--json]
|
|
10698
10698
|
odla-ai pm goal add --app <id> --title <t> [--status <s>] [--proof <text>] [--target <pct>] [--mutation-id <id>] [--json]
|
|
10699
10699
|
odla-ai pm task add --app <id> --title <t> [--column <backlog|ready|doing|review|done>] [--goal <id>|--alignment-decision <id>] [--assignee <id>] [--description <text>|--body <text>] [--acceptance <text>] [--execution <human|agent|either>] [--due <epoch-ms>] [--mutation-id <id>] [--json]
|
|
10700
|
-
odla-ai pm next --app <id> [--project <id>] [--json]
|
|
10700
|
+
odla-ai pm next --app <id> [--project <id>] [--verbose] [--json]
|
|
10701
|
+
odla-ai pm start --app <id> [<task-id>] [--goal <id>] [--verbose] [--mutation-id <id>] [--json] [claims the top Ready task in one call]
|
|
10701
10702
|
odla-ai pm watch --app <id> [--cursor <cursor>] [--entity goal|task|decision|bug] [--action created|updated|deleted|comment.created|comment.updated] [--state <state>] [--by <principalId>] [--self <principalId>] [--interval <s>] [--timeout <s>] [--json|--jsonl]
|
|
10702
10703
|
odla-ai pm task ready <id> --expected-revision <n> [--goal <id>|--alignment-decision <id>] [--description <text>|--body <text>] [--acceptance <text>] [--execution <human|agent|either>] [--mutation-id <id>] [--json]
|
|
10703
10704
|
odla-ai pm task claim <id> --expected-revision <n> [--mutation-id <id>] [--json]
|
|
@@ -10718,7 +10719,7 @@ Usage:
|
|
|
10718
10719
|
odla-ai pm <goal|task|decision|bug> comments <id> [--json]
|
|
10719
10720
|
odla-ai pm <goal|task|decision|bug> history <id> [--limit <n>] [--json]
|
|
10720
10721
|
odla-ai pm <goal|task|decision|bug> rm <id>
|
|
10721
|
-
odla-ai pm handoff --app <id> [--project <id>] [--json]
|
|
10722
|
+
odla-ai pm handoff --app <id> [--project <id>] [--verbose] [--json]
|
|
10722
10723
|
odla-ai discuss groups [--json]
|
|
10723
10724
|
odla-ai discuss list [--app <id>] [--q <text>] [--state open|resolved|all] [--mentions] [--json]
|
|
10724
10725
|
odla-ai discuss read <topic> [--limit <n> --offset <n>] [--json]
|
|
@@ -10883,6 +10884,16 @@ Commands:
|
|
|
10883
10884
|
execution contract and a reviewed revision. Any caller with PM
|
|
10884
10885
|
mutation access to that app/project may do it; claims coordinate
|
|
10885
10886
|
execution but never own or lock the PM record.
|
|
10887
|
+
To pick up work: "pm next" reads open goals, Ready candidates,
|
|
10888
|
+
and work in progress; "pm start" claims the top Ready task in
|
|
10889
|
+
one call, compare-and-swapped on the revision it just read, and
|
|
10890
|
+
returns the task, its goal, and the acceptance criteria to work
|
|
10891
|
+
against. Finish with "pm task done <id>", or hand it back with
|
|
10892
|
+
"pm task release <id> --expected-revision <n>". "pm start" never
|
|
10893
|
+
marks work Ready: that contract is reviewed separately so an
|
|
10894
|
+
agent cannot authorize its own work.
|
|
10895
|
+
Intake output is projected to the fields an executing caller
|
|
10896
|
+
acts on; --verbose returns whole records with their audit trail.
|
|
10886
10897
|
bug Intent-first alias for PM bugs. "bug report" writes to
|
|
10887
10898
|
odla PM; odla product defects do not belong in GitHub Issues.
|
|
10888
10899
|
discuss Group discussions (via @odla-ai/chat) for the apps you co-own:
|
|
@@ -11633,6 +11644,15 @@ var FIELD_MAP = {
|
|
|
11633
11644
|
execution: { key: "executionMode" },
|
|
11634
11645
|
"expected-revision": { key: "expectedRevision", num: true }
|
|
11635
11646
|
};
|
|
11647
|
+
var PmRequestError = class extends Error {
|
|
11648
|
+
constructor(status, message2) {
|
|
11649
|
+
super(message2);
|
|
11650
|
+
this.status = status;
|
|
11651
|
+
this.name = "PmRequestError";
|
|
11652
|
+
}
|
|
11653
|
+
status;
|
|
11654
|
+
};
|
|
11655
|
+
var isRevisionConflict = (error) => error instanceof PmRequestError && error.status === 409;
|
|
11636
11656
|
async function pmRequest(ctx, method, path, body) {
|
|
11637
11657
|
const response2 = await ctx.doFetch(`${ctx.platformUrl}/registry/pm${path}`, {
|
|
11638
11658
|
method,
|
|
@@ -11652,7 +11672,8 @@ async function pmRequest(ctx, method, path, body) {
|
|
|
11652
11672
|
const message2 = error.message;
|
|
11653
11673
|
if (typeof message2 === "string" && message2.length > 0) detail = message2;
|
|
11654
11674
|
}
|
|
11655
|
-
throw new
|
|
11675
|
+
throw new PmRequestError(
|
|
11676
|
+
response2.status,
|
|
11656
11677
|
`pm ${method} ${path} failed: ${detail ?? `registry returned ${response2.status}`} (${response2.status})`
|
|
11657
11678
|
);
|
|
11658
11679
|
}
|
|
@@ -11841,103 +11862,196 @@ async function pmTaskLifecycle(ctx, id2, action2, parsed) {
|
|
|
11841
11862
|
ctx.out.log(`task: ${label} \u2192 ${state2}`);
|
|
11842
11863
|
});
|
|
11843
11864
|
}
|
|
11844
|
-
async function
|
|
11865
|
+
async function pmRemove(ctx, entity, id2) {
|
|
11866
|
+
await pmRequest(ctx, "DELETE", `/${entity}/${encodeURIComponent(id2)}`);
|
|
11867
|
+
ctx.out.log(`deleted ${entity} ${id2}`);
|
|
11868
|
+
}
|
|
11869
|
+
|
|
11870
|
+
// src/pm-lean.ts
|
|
11871
|
+
var COMMON = ["id", "appId", "projectId", "title", "revision"];
|
|
11872
|
+
var PER_ENTITY = {
|
|
11873
|
+
goal: ["status", "proof", "targetPct", "currentPct"],
|
|
11874
|
+
task: [
|
|
11875
|
+
"column",
|
|
11876
|
+
"goalId",
|
|
11877
|
+
"alignmentDecisionId",
|
|
11878
|
+
"description",
|
|
11879
|
+
"acceptanceCriteria",
|
|
11880
|
+
"executionMode",
|
|
11881
|
+
"assigneeId",
|
|
11882
|
+
"claimedByPrincipalId",
|
|
11883
|
+
"dueAt"
|
|
11884
|
+
],
|
|
11885
|
+
decision: ["status", "body", "supersedesId"],
|
|
11886
|
+
bug: ["status", "severity", "description", "goalId", "assigneeId", "decisionId"]
|
|
11887
|
+
};
|
|
11888
|
+
function leanRecord(entity, record11) {
|
|
11889
|
+
const out = {};
|
|
11890
|
+
for (const key of [...COMMON, ...PER_ENTITY[entity]]) {
|
|
11891
|
+
const value2 = record11[key];
|
|
11892
|
+
if (value2 !== void 0 && value2 !== null) out[key] = value2;
|
|
11893
|
+
}
|
|
11894
|
+
return out;
|
|
11895
|
+
}
|
|
11896
|
+
function leanRecords(entity, records, verbose) {
|
|
11897
|
+
return verbose ? records : records.map((record11) => leanRecord(entity, record11));
|
|
11898
|
+
}
|
|
11899
|
+
|
|
11900
|
+
// src/pm-intake.ts
|
|
11901
|
+
var READY_COLUMN = "todo";
|
|
11902
|
+
var UNMET_GOAL_STATUS = "open";
|
|
11903
|
+
var ACTIVE_TASK_COLUMNS = "backlog,todo,doing,review";
|
|
11904
|
+
var OPEN_BUG_STATUSES = "open,triaged";
|
|
11905
|
+
var wantsVerbose = (parsed) => parsed.options.verbose === true;
|
|
11906
|
+
async function listFiltered(ctx, entity, appId, projectId, filters) {
|
|
11845
11907
|
const records = [];
|
|
11846
11908
|
for (; ; ) {
|
|
11847
|
-
const q = new URLSearchParams({
|
|
11848
|
-
app: appId,
|
|
11849
|
-
limit: "100",
|
|
11850
|
-
offset: String(records.length)
|
|
11851
|
-
});
|
|
11909
|
+
const q = new URLSearchParams({ app: appId, limit: "100", offset: String(records.length) });
|
|
11852
11910
|
if (projectId) q.set("project", projectId);
|
|
11911
|
+
for (const [key, value2] of Object.entries(filters)) q.set(key, value2);
|
|
11853
11912
|
const page2 = await pmRequest(ctx, "GET", `/${entity}?${q}`);
|
|
11854
11913
|
records.push(...page2.records);
|
|
11855
11914
|
if (records.length >= page2.total || page2.records.length === 0) return records;
|
|
11856
11915
|
}
|
|
11857
11916
|
}
|
|
11858
|
-
|
|
11917
|
+
function requireApp(ctx, parsed, command) {
|
|
11859
11918
|
const appId = stringOpt(parsed.options.app) ?? ctx.appId;
|
|
11860
|
-
|
|
11861
|
-
|
|
11919
|
+
if (!appId) throw new Error(`pm ${command} needs --app <appId>`);
|
|
11920
|
+
return { appId, projectId: stringOpt(parsed.options.project) ?? ctx.projectId };
|
|
11921
|
+
}
|
|
11922
|
+
async function pmNext(ctx, parsed) {
|
|
11923
|
+
const { appId, projectId } = requireApp(ctx, parsed, "next");
|
|
11924
|
+
const verbose = wantsVerbose(parsed);
|
|
11862
11925
|
const [goals, tasks] = await Promise.all([
|
|
11863
|
-
|
|
11864
|
-
|
|
11926
|
+
listFiltered(ctx, "goal", appId, projectId, { status: UNMET_GOAL_STATUS }),
|
|
11927
|
+
// One request for both live columns; the split below is over open work only.
|
|
11928
|
+
listFiltered(ctx, "task", appId, projectId, { column: `${READY_COLUMN},doing` })
|
|
11865
11929
|
]);
|
|
11930
|
+
const ready = tasks.filter((record11) => record11.column === READY_COLUMN);
|
|
11931
|
+
const doing = tasks.filter((record11) => record11.column === "doing");
|
|
11932
|
+
const guidance = !goals.length ? "discuss alignment with the user before creating or claiming project work" : !ready.length ? 'refine a linked Backlog task and mark it Ready with "pm task ready <id>"' : `claim the top Ready task in one call: odla-ai pm start --app ${appId}`;
|
|
11866
11933
|
const result = {
|
|
11867
11934
|
appId,
|
|
11868
11935
|
projectId,
|
|
11869
|
-
openGoals:
|
|
11870
|
-
doing:
|
|
11871
|
-
ready:
|
|
11936
|
+
openGoals: leanRecords("goal", goals, verbose),
|
|
11937
|
+
doing: leanRecords("task", doing, verbose),
|
|
11938
|
+
ready: leanRecords("task", ready, verbose),
|
|
11939
|
+
next: guidance
|
|
11872
11940
|
};
|
|
11873
11941
|
emit2(ctx, result, () => {
|
|
11874
11942
|
ctx.out.log(`${appId}: goal-aligned work intake (read only)`);
|
|
11875
|
-
for (const [label, records] of [
|
|
11876
|
-
["doing",
|
|
11877
|
-
["ready",
|
|
11878
|
-
["open goals",
|
|
11943
|
+
for (const [label, entity, records] of [
|
|
11944
|
+
["doing", "task", doing],
|
|
11945
|
+
["ready", "task", ready],
|
|
11946
|
+
["open goals", "goal", goals]
|
|
11879
11947
|
]) {
|
|
11880
11948
|
ctx.out.log(`${label}:`);
|
|
11881
11949
|
if (!records.length) ctx.out.log("- (none)");
|
|
11882
|
-
else for (const record11 of records) printRecord(
|
|
11883
|
-
ctx,
|
|
11884
|
-
label === "open goals" ? "goal" : "task",
|
|
11885
|
-
record11
|
|
11886
|
-
);
|
|
11887
|
-
}
|
|
11888
|
-
if (!result.openGoals.length) {
|
|
11889
|
-
ctx.out.log("next: discuss alignment with the user before creating or claiming project work");
|
|
11890
|
-
} else if (!result.ready.length) {
|
|
11891
|
-
ctx.out.log("next: refine a linked Backlog task and mark it Ready");
|
|
11892
|
-
} else {
|
|
11893
|
-
ctx.out.log("next: review a Ready task, then claim it with its revision");
|
|
11950
|
+
else for (const record11 of records) printRecord(ctx, entity, record11);
|
|
11894
11951
|
}
|
|
11952
|
+
ctx.out.log(`next: ${guidance}`);
|
|
11895
11953
|
});
|
|
11896
11954
|
}
|
|
11897
11955
|
async function pmHandoff(ctx, parsed) {
|
|
11898
|
-
const appId =
|
|
11899
|
-
const
|
|
11900
|
-
if (!appId) throw new Error("pm handoff needs --app <appId>");
|
|
11956
|
+
const { appId, projectId } = requireApp(ctx, parsed, "handoff");
|
|
11957
|
+
const verbose = wantsVerbose(parsed);
|
|
11901
11958
|
const [goals, tasks, bugs] = await Promise.all([
|
|
11902
|
-
|
|
11903
|
-
|
|
11904
|
-
|
|
11959
|
+
listFiltered(ctx, "goal", appId, projectId, { status: UNMET_GOAL_STATUS }),
|
|
11960
|
+
listFiltered(ctx, "task", appId, projectId, { column: ACTIVE_TASK_COLUMNS }),
|
|
11961
|
+
listFiltered(ctx, "bug", appId, projectId, { status: OPEN_BUG_STATUSES })
|
|
11905
11962
|
]);
|
|
11906
|
-
const
|
|
11963
|
+
const clean4 = !goals.length && !tasks.length && !bugs.length;
|
|
11964
|
+
const result = {
|
|
11907
11965
|
appId,
|
|
11908
11966
|
projectId,
|
|
11909
|
-
unmetGoals:
|
|
11910
|
-
activeTasks:
|
|
11911
|
-
openBugs:
|
|
11912
|
-
|
|
11913
|
-
const result = {
|
|
11914
|
-
...handoff,
|
|
11915
|
-
clean: !handoff.unmetGoals.length && !handoff.activeTasks.length && !handoff.openBugs.length
|
|
11967
|
+
unmetGoals: leanRecords("goal", goals, verbose),
|
|
11968
|
+
activeTasks: leanRecords("task", tasks, verbose),
|
|
11969
|
+
openBugs: leanRecords("bug", bugs, verbose),
|
|
11970
|
+
clean: clean4
|
|
11916
11971
|
};
|
|
11917
11972
|
emit2(ctx, result, () => {
|
|
11918
|
-
if (
|
|
11973
|
+
if (clean4) {
|
|
11919
11974
|
ctx.out.log(`${appId}: no unresolved PM work`);
|
|
11920
11975
|
return;
|
|
11921
11976
|
}
|
|
11922
11977
|
ctx.out.log(`${appId}: authoritative PM handoff`);
|
|
11923
|
-
for (const [label, records] of [
|
|
11924
|
-
["unmet goals",
|
|
11925
|
-
["active tasks",
|
|
11926
|
-
["open bugs",
|
|
11978
|
+
for (const [label, entity, records] of [
|
|
11979
|
+
["unmet goals", "goal", goals],
|
|
11980
|
+
["active tasks", "task", tasks],
|
|
11981
|
+
["open bugs", "bug", bugs]
|
|
11927
11982
|
]) {
|
|
11928
11983
|
ctx.out.log(`${label}:`);
|
|
11929
11984
|
if (!records.length) ctx.out.log("- (none)");
|
|
11930
|
-
else for (const record11 of records) printRecord(
|
|
11931
|
-
ctx,
|
|
11932
|
-
label === "unmet goals" ? "goal" : label === "active tasks" ? "task" : "bug",
|
|
11933
|
-
record11
|
|
11934
|
-
);
|
|
11985
|
+
else for (const record11 of records) printRecord(ctx, entity, record11);
|
|
11935
11986
|
}
|
|
11936
11987
|
});
|
|
11937
11988
|
}
|
|
11938
|
-
|
|
11939
|
-
|
|
11940
|
-
|
|
11989
|
+
|
|
11990
|
+
// src/pm-start.ts
|
|
11991
|
+
var getTask = async (ctx, id2) => (await pmRequest(ctx, "GET", `/task/${encodeURIComponent(id2)}`)).record;
|
|
11992
|
+
async function claimAt(ctx, task, parsed) {
|
|
11993
|
+
const res = await pmRequest(
|
|
11994
|
+
ctx,
|
|
11995
|
+
"POST",
|
|
11996
|
+
`/task/${encodeURIComponent(task.id)}/claim`,
|
|
11997
|
+
{ expectedRevision: task.revision, mutationId: writeMutationId2(parsed) }
|
|
11998
|
+
);
|
|
11999
|
+
return res.record;
|
|
12000
|
+
}
|
|
12001
|
+
async function selectTask(ctx, parsed, appId, projectId) {
|
|
12002
|
+
const named = parsed.positionals[2];
|
|
12003
|
+
if (named) return getTask(ctx, named);
|
|
12004
|
+
const goalId = stringOpt(parsed.options.goal);
|
|
12005
|
+
const ready = await listFiltered(ctx, "task", appId, projectId, {
|
|
12006
|
+
column: READY_COLUMN,
|
|
12007
|
+
...goalId ? { goalId } : {}
|
|
12008
|
+
});
|
|
12009
|
+
const candidate = ready[0];
|
|
12010
|
+
if (!candidate) {
|
|
12011
|
+
throw new Error(
|
|
12012
|
+
`no Ready task to claim in ${appId}${goalId ? ` for goal ${goalId}` : ""}. Run "odla-ai pm next --app ${appId}" to see open goals and Backlog work, then "odla-ai pm task ready <id>" once a task has a complete contract.`
|
|
12013
|
+
);
|
|
12014
|
+
}
|
|
12015
|
+
return candidate;
|
|
12016
|
+
}
|
|
12017
|
+
async function pmStart(ctx, parsed) {
|
|
12018
|
+
const appId = stringOpt(parsed.options.app) ?? ctx.appId;
|
|
12019
|
+
if (!appId) throw new Error("pm start needs --app <appId>");
|
|
12020
|
+
const projectId = stringOpt(parsed.options.project) ?? ctx.projectId;
|
|
12021
|
+
const verbose = wantsVerbose(parsed);
|
|
12022
|
+
const selected = await selectTask(ctx, parsed, appId, projectId);
|
|
12023
|
+
if (selected.column !== READY_COLUMN) {
|
|
12024
|
+
throw new Error(
|
|
12025
|
+
`task ${selected.id} is ${selected.column === "doing" ? "already claimed" : `in ${selected.column}`}, not Ready. Only Ready work can be started; run "odla-ai pm task ready ${selected.id} --expected-revision ${selected.revision}" once its goal, description, and acceptance criteria are complete.`
|
|
12026
|
+
);
|
|
12027
|
+
}
|
|
12028
|
+
let claimed;
|
|
12029
|
+
try {
|
|
12030
|
+
claimed = await claimAt(ctx, selected, parsed);
|
|
12031
|
+
} catch (error) {
|
|
12032
|
+
if (!isRevisionConflict(error)) throw error;
|
|
12033
|
+
const reloaded = await getTask(ctx, selected.id);
|
|
12034
|
+
if (reloaded.column !== READY_COLUMN) {
|
|
12035
|
+
throw new Error(
|
|
12036
|
+
`task ${selected.id} was taken while starting it (now ${reloaded.column}). Run "odla-ai pm start --app ${appId}" again to take the next Ready task.`
|
|
12037
|
+
);
|
|
12038
|
+
}
|
|
12039
|
+
claimed = await claimAt(ctx, reloaded, parsed);
|
|
12040
|
+
}
|
|
12041
|
+
const task = claimed ?? await getTask(ctx, selected.id);
|
|
12042
|
+
const goalId = typeof task.goalId === "string" ? task.goalId : void 0;
|
|
12043
|
+
const goal = goalId ? await pmRequest(ctx, "GET", `/goal/${encodeURIComponent(goalId)}`).then((res) => res.record).catch(() => null) : null;
|
|
12044
|
+
const result = {
|
|
12045
|
+
claimed: verbose ? task : leanRecord("task", task),
|
|
12046
|
+
goal: goal ? verbose ? goal : leanRecord("goal", goal) : null,
|
|
12047
|
+
next: 'work the acceptance criteria, then "odla-ai pm task done <id>" (or "odla-ai pm task release <id> --expected-revision <n>" to hand it back)'
|
|
12048
|
+
};
|
|
12049
|
+
emit2(ctx, result, () => {
|
|
12050
|
+
ctx.out.log(`claimed: ${studioRecordLink(ctx, "task", task)}`);
|
|
12051
|
+
if (goal) ctx.out.log(`goal: ${studioRecordLink(ctx, "goal", goal)}`);
|
|
12052
|
+
if (typeof task.acceptanceCriteria === "string") ctx.out.log(`acceptance: ${task.acceptanceCriteria}`);
|
|
12053
|
+
ctx.out.log(`next: ${result.next}`);
|
|
12054
|
+
});
|
|
11941
12055
|
}
|
|
11942
12056
|
|
|
11943
12057
|
// src/pm-links.ts
|
|
@@ -12411,9 +12525,13 @@ async function pmCommand(parsed, deps = {}) {
|
|
|
12411
12525
|
throw new Error(`unknown pm project action "${action3}". Try list|add|use.`);
|
|
12412
12526
|
}
|
|
12413
12527
|
if (word === "next") {
|
|
12414
|
-
assertArgs(parsed, [...COMMON_OPTIONS, "app", "project"], 2);
|
|
12528
|
+
assertArgs(parsed, [...COMMON_OPTIONS, "app", "project", "verbose"], 2);
|
|
12415
12529
|
return pmNext(await buildContext2(parsed, deps), parsed);
|
|
12416
12530
|
}
|
|
12531
|
+
if (word === "start") {
|
|
12532
|
+
assertArgs(parsed, [...COMMON_OPTIONS, "app", "project", "goal", "verbose", "mutation-id"], 3);
|
|
12533
|
+
return pmStart(await buildContext2(parsed, deps), parsed);
|
|
12534
|
+
}
|
|
12417
12535
|
if (word === "watch") {
|
|
12418
12536
|
assertArgs(parsed, [
|
|
12419
12537
|
...COMMON_OPTIONS,
|
|
@@ -12431,11 +12549,11 @@ async function pmCommand(parsed, deps = {}) {
|
|
|
12431
12549
|
return pmWatch(await buildContext2(parsed, deps), parsed).then(() => void 0);
|
|
12432
12550
|
}
|
|
12433
12551
|
if (word === "handoff") {
|
|
12434
|
-
assertArgs(parsed, [...COMMON_OPTIONS, "app", "project"], 2);
|
|
12552
|
+
assertArgs(parsed, [...COMMON_OPTIONS, "app", "project", "verbose"], 2);
|
|
12435
12553
|
return pmHandoff(await buildContext2(parsed, deps), parsed);
|
|
12436
12554
|
}
|
|
12437
12555
|
const entity = ALIASES[word];
|
|
12438
|
-
if (!entity) throw new Error(`unknown pm entity "${word}". Try "odla-ai pm bug list" (goal|task|decision|bug).`);
|
|
12556
|
+
if (!entity) throw new Error(`unknown pm entity "${word}". Try "odla-ai pm start" to claim Ready work, or "odla-ai pm bug list" (goal|task|decision|bug).`);
|
|
12439
12557
|
const requestedAction = parsed.positionals[2] ?? "list";
|
|
12440
12558
|
const action2 = canonicalAction(requestedAction);
|
|
12441
12559
|
if (!action2) throw new Error(`unknown pm action "${requestedAction}". Try list|add|get|set|done|link|ref|comment|comments|history|rm.`);
|
|
@@ -15958,4 +16076,4 @@ export {
|
|
|
15958
16076
|
isTerminalHostedSecurityStatus,
|
|
15959
16077
|
runCli
|
|
15960
16078
|
};
|
|
15961
|
-
//# sourceMappingURL=chunk-
|
|
16079
|
+
//# sourceMappingURL=chunk-WDWJ7HC7.js.map
|