@odla-ai/cli 0.30.1 → 0.30.3
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 +5 -1
- package/bin/odla-ai.js +33 -0
- package/bin/workspace-build.d.ts +2 -0
- package/bin/workspace-build.js +36 -0
- package/dist/bin.cjs +58 -7
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +1 -1
- package/dist/{chunk-7V7WVTDT.js → chunk-3HFNKDZV.js} +50 -7
- package/dist/chunk-3HFNKDZV.js.map +1 -0
- package/dist/{cli-SZUWA6EF.js → cli-BGSX5Z4C.js} +2 -2
- package/dist/index.cjs +49 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +3 -2
- package/skills/odla/references/pm-work-intake.md +11 -2
- package/skills/odla/references/pm.md +35 -0
- package/dist/chunk-7V7WVTDT.js.map +0 -1
- /package/dist/{cli-SZUWA6EF.js.map → cli-BGSX5Z4C.js.map} +0 -0
package/README.md
CHANGED
|
@@ -147,7 +147,11 @@ Use `pm task ref <id>` (or the equivalent goal/decision/bug command) to print
|
|
|
147
147
|
copy-ready structured markup for Discussion. The same markup may be pasted into
|
|
148
148
|
`pm <entity> comment <id> --body "…"`; PM stores it as a structured reference,
|
|
149
149
|
and `pm <entity> comments <id>` prints copy-ready markup instead of flattening
|
|
150
|
-
the link back to a title.
|
|
150
|
+
the link back to a title. For ordinary chat and handoffs, `pm task link <id>`
|
|
151
|
+
prints a normal Markdown link to the record's durable Studio route. Successful
|
|
152
|
+
create and lifecycle commands print that title-first link directly. Lead with
|
|
153
|
+
the PM type and linked title, explain the state or next action, and keep the id
|
|
154
|
+
hidden in the URL; a bare id list is not a useful handoff.
|
|
151
155
|
|
|
152
156
|
When diagnosing a deployed app, agents can request one parseable observability
|
|
153
157
|
snapshot instead of scraping Studio or composing collector routes themselves:
|
package/bin/odla-ai.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import { spawnSync } from "node:child_process";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
6
|
+
import { workspaceBuildOrder } from "./workspace-build.js";
|
|
7
|
+
|
|
8
|
+
const packageRoot = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
9
|
+
const builtEntry = join(packageRoot, "dist", "bin.js");
|
|
10
|
+
|
|
11
|
+
if (!existsSync(builtEntry)) {
|
|
12
|
+
const workspaceRoot = join(packageRoot, "..", "..");
|
|
13
|
+
const rootManifestPath = join(workspaceRoot, "package.json");
|
|
14
|
+
const rootManifest = existsSync(rootManifestPath)
|
|
15
|
+
? JSON.parse(readFileSync(rootManifestPath, "utf8"))
|
|
16
|
+
: null;
|
|
17
|
+
if (rootManifest?.name !== "odla-ai" || rootManifest.private !== true) {
|
|
18
|
+
throw new Error("odla-ai CLI build is missing; reinstall @odla-ai/cli from npm");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
console.error("odla-ai: workspace CLI is not built; building the local monorepo first");
|
|
22
|
+
const npm = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
23
|
+
const workspaces = workspaceBuildOrder(workspaceRoot);
|
|
24
|
+
const child = spawnSync(
|
|
25
|
+
npm,
|
|
26
|
+
["run", "build", ...workspaces.map((name) => `--workspace=${name}`)],
|
|
27
|
+
{ cwd: workspaceRoot, stdio: "inherit" },
|
|
28
|
+
);
|
|
29
|
+
if (child.error) throw child.error;
|
|
30
|
+
if (child.status !== 0) process.exit(child.status ?? 1);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
await import(pathToFileURL(builtEntry).href);
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
const manifestAt = (path) => JSON.parse(readFileSync(path, "utf8"));
|
|
5
|
+
|
|
6
|
+
/** Return buildable internal dependencies in dependency-first order. */
|
|
7
|
+
export function workspaceBuildOrder(root) {
|
|
8
|
+
const rootManifest = manifestAt(join(root, "package.json"));
|
|
9
|
+
const workspaces = new Map();
|
|
10
|
+
for (const pattern of rootManifest.workspaces ?? []) {
|
|
11
|
+
if (!pattern.endsWith("/*")) continue;
|
|
12
|
+
const parent = join(root, pattern.slice(0, -2));
|
|
13
|
+
if (!existsSync(parent)) continue;
|
|
14
|
+
for (const entry of readdirSync(parent, { withFileTypes: true })) {
|
|
15
|
+
if (!entry.isDirectory()) continue;
|
|
16
|
+
const manifestPath = join(parent, entry.name, "package.json");
|
|
17
|
+
if (!existsSync(manifestPath)) continue;
|
|
18
|
+
const manifest = manifestAt(manifestPath);
|
|
19
|
+
if (manifest.name) workspaces.set(manifest.name, manifest);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const visited = new Set();
|
|
24
|
+
const order = [];
|
|
25
|
+
const visit = (name) => {
|
|
26
|
+
if (visited.has(name)) return;
|
|
27
|
+
visited.add(name);
|
|
28
|
+
const manifest = workspaces.get(name);
|
|
29
|
+
if (!manifest) return;
|
|
30
|
+
const dependencies = { ...manifest.dependencies, ...manifest.devDependencies };
|
|
31
|
+
for (const dependency of Object.keys(dependencies)) visit(dependency);
|
|
32
|
+
if (manifest.scripts?.build) order.push(name);
|
|
33
|
+
};
|
|
34
|
+
visit("@odla-ai/cli");
|
|
35
|
+
return order;
|
|
36
|
+
}
|
package/dist/bin.cjs
CHANGED
|
@@ -9608,6 +9608,7 @@ Usage:
|
|
|
9608
9608
|
odla-ai pm bug add --app <id> --title <t> (--description <text>|--body <text>) [--status <s>] [--severity <s>] [--goal <id>] [--assignee <id>] [--decision <id>] [--mutation-id <id>] [--json]
|
|
9609
9609
|
odla-ai bug report --app <id> --title <t> (--description <text>|--body <text>) [--severity <s>] [--json]
|
|
9610
9610
|
odla-ai pm <goal|task|decision|bug> get <id> [--json]
|
|
9611
|
+
odla-ai pm <goal|task|decision|bug> link <id> [--json]
|
|
9611
9612
|
odla-ai pm <goal|task|decision|bug> ref <id> [--json]
|
|
9612
9613
|
odla-ai pm goal set <id> [--title <t>|--status <s>|--proof <text>|--no-proof|--target <pct>|--no-target] [--mutation-id <id>] [--json]
|
|
9613
9614
|
odla-ai pm task set <id> [--title <t>|--column <backlog|ready|doing|review|done>|--rank <n>|--goal <id>|--no-goal|--alignment-decision <id>|--no-alignment-decision|--execution <human|agent|either>|--assignee <id>|--no-assignee|--description <text>|--body <text>|--acceptance <text>|--no-acceptance|--due <epoch-ms>|--no-due|--expected-revision <n>] [--mutation-id <id>] [--json]
|
|
@@ -10509,16 +10510,26 @@ function referenceMarkup(entity, record10) {
|
|
|
10509
10510
|
const label = (record10.title?.trim() || `${entity} ${record10.id}`).replaceAll("]", ")");
|
|
10510
10511
|
return `@[${label}](pm:${entity}/${record10.id})`;
|
|
10511
10512
|
}
|
|
10513
|
+
function studioRecordUrl(ctx, entity, id) {
|
|
10514
|
+
return new URL(
|
|
10515
|
+
`/studio/pm/${STUDIO_SECTION[entity]}/${encodeURIComponent(id)}`,
|
|
10516
|
+
ctx.platformUrl
|
|
10517
|
+
).href;
|
|
10518
|
+
}
|
|
10519
|
+
function studioRecordLink(ctx, entity, record10) {
|
|
10520
|
+
const label = (record10.title?.trim() || `${entity} ${record10.id}`).replaceAll("]", ")");
|
|
10521
|
+
return `[${label}](${studioRecordUrl(ctx, entity, record10.id)})`;
|
|
10522
|
+
}
|
|
10512
10523
|
function printRecord(ctx, entity, record10) {
|
|
10513
10524
|
ctx.out.log(
|
|
10514
|
-
`${record10.id} [${statusCol(entity, record10)}] ${record10.appId} ${
|
|
10525
|
+
`${record10.id} [${statusCol(entity, record10)}] ${record10.appId} ${studioRecordLink(ctx, entity, record10)}`
|
|
10515
10526
|
);
|
|
10516
10527
|
}
|
|
10517
10528
|
function emit2(ctx, value2, human) {
|
|
10518
10529
|
if (ctx.json) ctx.out.log(JSON.stringify(value2, null, 2));
|
|
10519
10530
|
else human();
|
|
10520
10531
|
}
|
|
10521
|
-
var DONE, writeMutationId2, FIELD_MAP;
|
|
10532
|
+
var DONE, writeMutationId2, FIELD_MAP, STUDIO_SECTION;
|
|
10522
10533
|
var init_pm_action_core = __esm({
|
|
10523
10534
|
"src/pm-action-core.ts"() {
|
|
10524
10535
|
"use strict";
|
|
@@ -10551,6 +10562,12 @@ var init_pm_action_core = __esm({
|
|
|
10551
10562
|
execution: { key: "executionMode" },
|
|
10552
10563
|
"expected-revision": { key: "expectedRevision", num: true }
|
|
10553
10564
|
};
|
|
10565
|
+
STUDIO_SECTION = {
|
|
10566
|
+
goal: "goals",
|
|
10567
|
+
task: "board",
|
|
10568
|
+
decision: "decisions",
|
|
10569
|
+
bug: "bugs"
|
|
10570
|
+
};
|
|
10554
10571
|
}
|
|
10555
10572
|
});
|
|
10556
10573
|
|
|
@@ -10596,7 +10613,8 @@ async function pmAdd(ctx, entity, parsed) {
|
|
|
10596
10613
|
input,
|
|
10597
10614
|
mutationId: writeMutationId2(parsed)
|
|
10598
10615
|
});
|
|
10599
|
-
|
|
10616
|
+
const record10 = { id: res.id, appId, title: String(input.title) };
|
|
10617
|
+
emit2(ctx, res, () => ctx.out.log(`created ${entity}: ${studioRecordLink(ctx, entity, record10)}`));
|
|
10600
10618
|
}
|
|
10601
10619
|
async function pmGet(ctx, entity, id) {
|
|
10602
10620
|
const { record: record10 } = await pmRequest(ctx, "GET", `/${entity}/${encodeURIComponent(id)}`);
|
|
@@ -10621,7 +10639,10 @@ async function pmSet(ctx, entity, id, parsed) {
|
|
|
10621
10639
|
patch: patch2,
|
|
10622
10640
|
mutationId: writeMutationId2(parsed)
|
|
10623
10641
|
});
|
|
10624
|
-
emit2(ctx, res, () =>
|
|
10642
|
+
emit2(ctx, res, () => {
|
|
10643
|
+
if (!res.record) return ctx.out.log(`updated ${entity} ${id}`);
|
|
10644
|
+
ctx.out.log(`${entity}: ${studioRecordLink(ctx, entity, res.record)} \u2192 ${statusCol(entity, res.record)}`);
|
|
10645
|
+
});
|
|
10625
10646
|
}
|
|
10626
10647
|
async function pmDone(ctx, entity, id, parsed) {
|
|
10627
10648
|
const decisionId = stringOpt(parsed.options.decision);
|
|
@@ -10631,7 +10652,11 @@ async function pmDone(ctx, entity, id, parsed) {
|
|
|
10631
10652
|
patch: patch2,
|
|
10632
10653
|
mutationId: writeMutationId2(parsed)
|
|
10633
10654
|
});
|
|
10634
|
-
emit2(ctx, res, () =>
|
|
10655
|
+
emit2(ctx, res, () => {
|
|
10656
|
+
const label = res.record ? studioRecordLink(ctx, entity, res.record) : id;
|
|
10657
|
+
const state2 = res.record ? statusCol(entity, res.record) : "done";
|
|
10658
|
+
ctx.out.log(`${entity}: ${label} \u2192 ${state2}`);
|
|
10659
|
+
});
|
|
10635
10660
|
}
|
|
10636
10661
|
async function pmTaskLifecycle(ctx, id, action2, parsed) {
|
|
10637
10662
|
const rawRevision = stringOpt(parsed.options["expected-revision"]);
|
|
@@ -10660,7 +10685,8 @@ async function pmTaskLifecycle(ctx, id, action2, parsed) {
|
|
|
10660
10685
|
);
|
|
10661
10686
|
emit2(ctx, res, () => {
|
|
10662
10687
|
const state2 = res.record ? statusCol("task", res.record) : action2;
|
|
10663
|
-
|
|
10688
|
+
const label = res.record ? studioRecordLink(ctx, "task", res.record) : id;
|
|
10689
|
+
ctx.out.log(`task: ${label} \u2192 ${state2}`);
|
|
10664
10690
|
});
|
|
10665
10691
|
}
|
|
10666
10692
|
async function allRecords(ctx, entity, appId) {
|
|
@@ -10765,6 +10791,27 @@ var init_pm_actions = __esm({
|
|
|
10765
10791
|
}
|
|
10766
10792
|
});
|
|
10767
10793
|
|
|
10794
|
+
// src/pm-links.ts
|
|
10795
|
+
async function pmLink(ctx, entity, id) {
|
|
10796
|
+
const { record: record10 } = await pmRequest(
|
|
10797
|
+
ctx,
|
|
10798
|
+
"GET",
|
|
10799
|
+
`/${entity}/${encodeURIComponent(id)}`
|
|
10800
|
+
);
|
|
10801
|
+
const url = studioRecordUrl(ctx, entity, record10.id);
|
|
10802
|
+
const markdown = studioRecordLink(ctx, entity, record10);
|
|
10803
|
+
emit2(ctx, { kind: entity, id: record10.id, label: record10.title ?? "", url, markdown }, () => {
|
|
10804
|
+
ctx.out.log(markdown);
|
|
10805
|
+
});
|
|
10806
|
+
}
|
|
10807
|
+
var init_pm_links = __esm({
|
|
10808
|
+
"src/pm-links.ts"() {
|
|
10809
|
+
"use strict";
|
|
10810
|
+
init_cjs_shims();
|
|
10811
|
+
init_pm_action_core();
|
|
10812
|
+
}
|
|
10813
|
+
});
|
|
10814
|
+
|
|
10768
10815
|
// src/pm-comments.ts
|
|
10769
10816
|
async function pmComment(ctx, entity, id, parsed) {
|
|
10770
10817
|
const body = stringOpt(parsed.options.body);
|
|
@@ -11091,7 +11138,7 @@ async function pmCommand(parsed, deps = {}) {
|
|
|
11091
11138
|
if (!entity) throw new Error(`unknown pm entity "${word}". Try "odla-ai pm bug list" (goal|task|decision|bug).`);
|
|
11092
11139
|
const requestedAction = parsed.positionals[2] ?? "list";
|
|
11093
11140
|
const action2 = canonicalAction(requestedAction);
|
|
11094
|
-
if (!action2) throw new Error(`unknown pm action "${requestedAction}". Try list|add|get|set|done|comment|comments|rm.`);
|
|
11141
|
+
if (!action2) throw new Error(`unknown pm action "${requestedAction}". Try list|add|get|set|done|link|ref|comment|comments|rm.`);
|
|
11095
11142
|
assertArgs(parsed, allowedOptions(entity, action2), 4);
|
|
11096
11143
|
if ((action2 === "ready" || action2 === "claim" || action2 === "release") && entity !== "task") {
|
|
11097
11144
|
throw new Error(`pm ${action2} is only valid for tasks`);
|
|
@@ -11115,6 +11162,8 @@ async function pmCommand(parsed, deps = {}) {
|
|
|
11115
11162
|
return pmComments(ctx, entity, requireId2(id, action2));
|
|
11116
11163
|
case "rm":
|
|
11117
11164
|
return pmRemove(ctx, entity, requireId2(id, action2));
|
|
11165
|
+
case "link":
|
|
11166
|
+
return pmLink(ctx, entity, requireId2(id, action2));
|
|
11118
11167
|
case "ref":
|
|
11119
11168
|
return pmReference(ctx, entity, requireId2(id, action2));
|
|
11120
11169
|
case "ready":
|
|
@@ -11131,6 +11180,7 @@ var init_pm_command = __esm({
|
|
|
11131
11180
|
init_argv();
|
|
11132
11181
|
init_operator_context();
|
|
11133
11182
|
init_pm_actions();
|
|
11183
|
+
init_pm_links();
|
|
11134
11184
|
init_pm_comments();
|
|
11135
11185
|
init_token();
|
|
11136
11186
|
init_pm_watch();
|
|
@@ -11155,6 +11205,7 @@ var init_pm_command = __esm({
|
|
|
11155
11205
|
ready: ["goal", "alignment-decision", "execution", "description", "desc", "body", "acceptance", "expected-revision", "mutation-id"],
|
|
11156
11206
|
claim: ["expected-revision", "mutation-id"],
|
|
11157
11207
|
release: ["expected-revision", "mutation-id"],
|
|
11208
|
+
link: [],
|
|
11158
11209
|
ref: []
|
|
11159
11210
|
};
|
|
11160
11211
|
ENTITY_OPTIONS = {
|