@opvs-ai/cli 0.14.0 → 0.15.1
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 +60 -0
- package/dist/.build-stamp.json +4 -4
- package/dist/commands/boards.d.ts +57 -0
- package/dist/commands/boards.js +546 -4
- package/dist/commands/boards.js.map +1 -1
- package/dist/commands/columns.d.ts +51 -0
- package/dist/commands/columns.js +274 -16
- package/dist/commands/columns.js.map +1 -1
- package/dist/commands/comments.js +48 -14
- package/dist/commands/comments.js.map +1 -1
- package/dist/commands/files.js +34 -0
- package/dist/commands/files.js.map +1 -1
- package/dist/commands/markers.js +53 -1
- package/dist/commands/markers.js.map +1 -1
- package/dist/commands/members.d.ts +33 -0
- package/dist/commands/members.js +96 -11
- package/dist/commands/members.js.map +1 -1
- package/dist/commands/projects.d.ts +8 -0
- package/dist/commands/projects.js +138 -6
- package/dist/commands/projects.js.map +1 -1
- package/dist/commands/stages.js +14 -3
- package/dist/commands/stages.js.map +1 -1
- package/dist/commands/tasks.js +288 -18
- package/dist/commands/tasks.js.map +1 -1
- package/dist/lib/factory-gate.d.ts +38 -0
- package/dist/lib/factory-gate.js +65 -0
- package/dist/lib/factory-gate.js.map +1 -0
- package/dist/lib/health.d.ts +54 -0
- package/dist/lib/health.js +126 -0
- package/dist/lib/health.js.map +1 -0
- package/dist/lib/options.d.ts +17 -0
- package/dist/lib/options.js +37 -0
- package/dist/lib/options.js.map +1 -1
- package/dist/lib/routing.d.ts +41 -0
- package/dist/lib/routing.js +60 -0
- package/dist/lib/routing.js.map +1 -0
- package/package.json +2 -2
package/dist/commands/files.js
CHANGED
|
@@ -84,6 +84,40 @@ export function registerFileCommands(program) {
|
|
|
84
84
|
process.exit(1);
|
|
85
85
|
}
|
|
86
86
|
});
|
|
87
|
+
// `attachFileFromUrl` (POST /tasks/{id}/files/fetch-url) had an MCP method
|
|
88
|
+
// and no CLI command (ASP-85). Distinct from `attach-url`, which stores a
|
|
89
|
+
// LINK: this stores the BYTES. `FileService.fetch_url_to_attachment` defaults
|
|
90
|
+
// file_type to attachment (verbatim); `image` runs `process_cover_image`.
|
|
91
|
+
files
|
|
92
|
+
.command("fetch-url <taskId> <url>")
|
|
93
|
+
.description("Download the file at a public http(s) URL onto a card, server-side. Stores the BYTES in your brand's file " +
|
|
94
|
+
"storage (up to 50 MB), so it survives the source going away — unlike attach-url, which keeps only a link. " +
|
|
95
|
+
"Internal, loopback and cloud-metadata addresses are refused.")
|
|
96
|
+
.option("--filename <name>", "Stored filename (default: the URL's last path segment)")
|
|
97
|
+
.option("--description <desc>", "Attachment description")
|
|
98
|
+
.option("--type <type>", "attachment (default: the original bytes, verbatim) | result | input | document | data | other | image. " +
|
|
99
|
+
"'image' RESIZES and center-crops to a 1200x675 JPEG and does not keep the original.")
|
|
100
|
+
.action(async (taskId, url, opts) => {
|
|
101
|
+
const wsSlug = program.opts().workspace;
|
|
102
|
+
try {
|
|
103
|
+
const client = createClient(wsSlug);
|
|
104
|
+
const body = { url };
|
|
105
|
+
if (opts.filename)
|
|
106
|
+
body.filename = opts.filename;
|
|
107
|
+
if (opts.description)
|
|
108
|
+
body.description = opts.description;
|
|
109
|
+
if (opts.type)
|
|
110
|
+
body.file_type = opts.type;
|
|
111
|
+
const res = await client.post(`/api/v1/board/tasks/${taskId}/files/fetch-url`, body);
|
|
112
|
+
const data = await res.json();
|
|
113
|
+
printJson(data);
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
const e = err;
|
|
117
|
+
console.error(`Error: ${e.detail || "Failed to fetch URL onto the task"}`);
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
87
121
|
files
|
|
88
122
|
.command("download <fileId>")
|
|
89
123
|
.description("Download a file")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/commands/files.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/commands/files.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/markers.js
CHANGED
|
@@ -3,6 +3,23 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { getEffectiveConfig, createClient } from "@opvs-ai/core";
|
|
5
5
|
import { buildUrl, printResponse, printJson } from "../lib/format.js";
|
|
6
|
+
import { boolFlag, oneOf } from "../lib/options.js";
|
|
7
|
+
/** `MarkerCreate.marker_type` pattern (agentboard `schemas/marker.py`). */
|
|
8
|
+
const MARKER_TYPES = ["milestone", "epic", "story", "checkpoint"];
|
|
9
|
+
// `marker_type` is read by nothing on the server but the marker service's own
|
|
10
|
+
// write — it is how the dashboard groups markers, not a behaviour.
|
|
11
|
+
const TYPE_HELP = `Kind of marker: ${MARKER_TYPES.join(" | ")}. Display grouping only — nothing on the server acts on it.`;
|
|
12
|
+
const TARGET_DATE_HELP = "Target date (YYYY-MM-DD). Informational: a missed date raises no alert and moves nothing.";
|
|
13
|
+
const BOARD_LINK_HELP = "UUID of a board-to-board link (`opvs board-links list`) this marker annotates on the board graph.";
|
|
14
|
+
const DESCRIPTION_HELP = "Marker description (max 1000 chars).";
|
|
15
|
+
/** `YYYY-MM-DD`, checked locally so a typo is one line rather than a pydantic 422. */
|
|
16
|
+
function isoDate(flag, raw) {
|
|
17
|
+
if (!/^\d{4}-\d{2}-\d{2}$/.test(raw)) {
|
|
18
|
+
console.error(`Error: ${flag} must be a date as YYYY-MM-DD (got '${raw}')`);
|
|
19
|
+
process.exit(1);
|
|
20
|
+
}
|
|
21
|
+
return raw;
|
|
22
|
+
}
|
|
6
23
|
export function registerMarkerCommands(program) {
|
|
7
24
|
const markers = program
|
|
8
25
|
.command("markers")
|
|
@@ -31,8 +48,13 @@ export function registerMarkerCommands(program) {
|
|
|
31
48
|
.requiredOption("-n, --name <name>", "Marker name")
|
|
32
49
|
.option("--color <hex>", "Color hex (e.g. '#ff0000')")
|
|
33
50
|
.option("--icon <icon>", "Icon name")
|
|
51
|
+
.option("--description <text>", DESCRIPTION_HELP)
|
|
52
|
+
.option("--type <type>", `${TYPE_HELP} Default: milestone.`)
|
|
53
|
+
.option("--target-date <date>", TARGET_DATE_HELP)
|
|
54
|
+
.option("--board-link <uuid>", BOARD_LINK_HELP)
|
|
34
55
|
.action(async (opts) => {
|
|
35
56
|
const wsSlug = program.opts().workspace;
|
|
57
|
+
const markerType = oneOf("--type", opts.type, MARKER_TYPES);
|
|
36
58
|
try {
|
|
37
59
|
const client = createClient(wsSlug);
|
|
38
60
|
const body = { name: opts.name };
|
|
@@ -40,6 +62,14 @@ export function registerMarkerCommands(program) {
|
|
|
40
62
|
body.color = opts.color;
|
|
41
63
|
if (opts.icon)
|
|
42
64
|
body.icon = opts.icon;
|
|
65
|
+
if (opts.description)
|
|
66
|
+
body.description = opts.description;
|
|
67
|
+
if (markerType)
|
|
68
|
+
body.marker_type = markerType;
|
|
69
|
+
if (opts.targetDate)
|
|
70
|
+
body.target_date = isoDate("--target-date", opts.targetDate);
|
|
71
|
+
if (opts.boardLink)
|
|
72
|
+
body.board_link_id = opts.boardLink;
|
|
43
73
|
const res = await client.post("/api/v1/board/markers", body);
|
|
44
74
|
const data = await res.json();
|
|
45
75
|
printJson(data);
|
|
@@ -74,8 +104,18 @@ export function registerMarkerCommands(program) {
|
|
|
74
104
|
.option("-n, --name <name>", "New name")
|
|
75
105
|
.option("--color <hex>", "New color hex")
|
|
76
106
|
.option("--icon <icon>", "New icon")
|
|
107
|
+
.option("--description <text>", `${DESCRIPTION_HELP} Pass '' to clear it.`)
|
|
108
|
+
.option("--type <type>", TYPE_HELP)
|
|
109
|
+
.option("--target-date <date>", `${TARGET_DATE_HELP} Pass 'none' to clear it.`)
|
|
110
|
+
.option("--board-link <uuid>", `${BOARD_LINK_HELP} Pass 'none' to detach it.`)
|
|
111
|
+
// `is_completed` is NOT NULL, so there is no clear verb — only true | false.
|
|
112
|
+
// `MarkerService.update` stamps completed_at on the false→true edge and
|
|
113
|
+
// clears it on true→false, so re-completing restarts the timestamp.
|
|
114
|
+
.option("--completed <bool>", "true | false. Marks the milestone done (stamps completed_at) or reopens it (clears completed_at, so a later " +
|
|
115
|
+
"completion records a NEW date).")
|
|
77
116
|
.action(async (markerId, opts) => {
|
|
78
117
|
const wsSlug = program.opts().workspace;
|
|
118
|
+
const markerType = oneOf("--type", opts.type, MARKER_TYPES);
|
|
79
119
|
try {
|
|
80
120
|
const client = createClient(wsSlug);
|
|
81
121
|
const body = {};
|
|
@@ -85,8 +125,20 @@ export function registerMarkerCommands(program) {
|
|
|
85
125
|
body.color = opts.color;
|
|
86
126
|
if (opts.icon)
|
|
87
127
|
body.icon = opts.icon;
|
|
128
|
+
if (opts.description !== undefined)
|
|
129
|
+
body.description = opts.description === "" ? null : opts.description;
|
|
130
|
+
if (markerType)
|
|
131
|
+
body.marker_type = markerType;
|
|
132
|
+
if (opts.targetDate !== undefined) {
|
|
133
|
+
body.target_date = opts.targetDate === "none" ? null : isoDate("--target-date", opts.targetDate);
|
|
134
|
+
}
|
|
135
|
+
if (opts.boardLink !== undefined)
|
|
136
|
+
body.board_link_id = opts.boardLink === "none" ? null : opts.boardLink;
|
|
137
|
+
const completed = boolFlag("--completed", opts.completed);
|
|
138
|
+
if (completed !== undefined)
|
|
139
|
+
body.is_completed = completed;
|
|
88
140
|
if (Object.keys(body).length === 0) {
|
|
89
|
-
console.error("Nothing to update. Provide --name, --color, or --
|
|
141
|
+
console.error("Nothing to update. Provide --name, --color, --icon, --description, --type, --target-date, --board-link, or --completed");
|
|
90
142
|
process.exit(1);
|
|
91
143
|
}
|
|
92
144
|
const res = await client.patch(`/api/v1/board/markers/${markerId}`, body);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markers.js","sourceRoot":"","sources":["../../src/commands/markers.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AACjE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"markers.js","sourceRoot":"","sources":["../../src/commands/markers.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* opvs members — board member management
|
|
3
|
+
*
|
|
4
|
+
* ── Why this file was rewritten (ASP-85) ─────────────────────────────────────
|
|
5
|
+
* `members add` sent `{user_id, role}` and `members remove` called
|
|
6
|
+
* `/members/{userId}`. The route has always taken `{member_type, member_id}`
|
|
7
|
+
* (AgentBoard `AddBoardMemberRequest`) and deletes at
|
|
8
|
+
* `/members/{member_type}/{member_id}`, so BOTH commands failed on every call —
|
|
9
|
+
* a 422 and a 404 — for as long as they had existed.
|
|
10
|
+
*
|
|
11
|
+
* ── What a role does, and does not do ───────────────────────────────────────
|
|
12
|
+
* `member_role` is read in exactly ONE place: the gateway's
|
|
13
|
+
* `_guest_role_allows` (apps/api `board.py`), and only for a membership with
|
|
14
|
+
* `is_external = true`. A member of the board's own brand is never checked
|
|
15
|
+
* against it. So `--role` caps a GUEST and is inert for everyone else — which
|
|
16
|
+
* is why the help says so rather than calling it a permission.
|
|
17
|
+
*
|
|
18
|
+
* `is_external` has no flag on purpose (surface_parity_exclusions/cli_fields.yaml).
|
|
19
|
+
* Whether a user is a guest is a fact about the user's brand, which the
|
|
20
|
+
* `by-email` route looks up and this command cannot — so `members invite`
|
|
21
|
+
* is the door for a guest, and it decides guest-ness itself.
|
|
3
22
|
*/
|
|
4
23
|
import { Command } from "commander";
|
|
24
|
+
/** `AddBoardMemberRequest.member_role` pattern (agentboard `schemas/board.py`). */
|
|
25
|
+
export declare const MEMBER_ROLES: readonly ["viewer", "commenter", "editor"];
|
|
26
|
+
/**
|
|
27
|
+
* Resolve `--user` / `--agent` to the `(member_type, member_id)` pair the route
|
|
28
|
+
* takes. Exactly one is required: two would be two members in one request the
|
|
29
|
+
* route cannot express, and none is the 422 this command used to send.
|
|
30
|
+
*/
|
|
31
|
+
export declare function memberTarget(opts: {
|
|
32
|
+
user?: string;
|
|
33
|
+
agent?: string;
|
|
34
|
+
}): {
|
|
35
|
+
member_type: string;
|
|
36
|
+
member_id: string;
|
|
37
|
+
};
|
|
5
38
|
export declare function registerMemberCommands(program: Command): void;
|
package/dist/commands/members.js
CHANGED
|
@@ -1,8 +1,59 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* opvs members — board member management
|
|
3
|
+
*
|
|
4
|
+
* ── Why this file was rewritten (ASP-85) ─────────────────────────────────────
|
|
5
|
+
* `members add` sent `{user_id, role}` and `members remove` called
|
|
6
|
+
* `/members/{userId}`. The route has always taken `{member_type, member_id}`
|
|
7
|
+
* (AgentBoard `AddBoardMemberRequest`) and deletes at
|
|
8
|
+
* `/members/{member_type}/{member_id}`, so BOTH commands failed on every call —
|
|
9
|
+
* a 422 and a 404 — for as long as they had existed.
|
|
10
|
+
*
|
|
11
|
+
* ── What a role does, and does not do ───────────────────────────────────────
|
|
12
|
+
* `member_role` is read in exactly ONE place: the gateway's
|
|
13
|
+
* `_guest_role_allows` (apps/api `board.py`), and only for a membership with
|
|
14
|
+
* `is_external = true`. A member of the board's own brand is never checked
|
|
15
|
+
* against it. So `--role` caps a GUEST and is inert for everyone else — which
|
|
16
|
+
* is why the help says so rather than calling it a permission.
|
|
17
|
+
*
|
|
18
|
+
* `is_external` has no flag on purpose (surface_parity_exclusions/cli_fields.yaml).
|
|
19
|
+
* Whether a user is a guest is a fact about the user's brand, which the
|
|
20
|
+
* `by-email` route looks up and this command cannot — so `members invite`
|
|
21
|
+
* is the door for a guest, and it decides guest-ness itself.
|
|
3
22
|
*/
|
|
4
23
|
import { getEffectiveConfig, createClient } from "@opvs-ai/core";
|
|
5
24
|
import { buildUrl, printResponse, printJson } from "../lib/format.js";
|
|
25
|
+
import { oneOf } from "../lib/options.js";
|
|
26
|
+
import { isUuid } from "../lib/board-refs.js";
|
|
27
|
+
/** `AddBoardMemberRequest.member_role` pattern (agentboard `schemas/board.py`). */
|
|
28
|
+
export const MEMBER_ROLES = ["viewer", "commenter", "editor"];
|
|
29
|
+
/** `AddBoardMemberRequest.member_type` pattern. */
|
|
30
|
+
const MEMBER_TYPES = ["user", "agent"];
|
|
31
|
+
// `_guest_role_allows`: viewer → reads; commenter → reads + POST a task comment;
|
|
32
|
+
// editor → every method. None → treated as viewer.
|
|
33
|
+
const ROLE_HELP = "Guest permission tier: viewer (read only) | commenter (read + comment) | editor (every write, including adding " +
|
|
34
|
+
"members). It caps an EXTERNAL guest only — a member of your own brand is never checked against it and keeps " +
|
|
35
|
+
"full access whatever you pass.";
|
|
36
|
+
function requireUuid(flag, raw) {
|
|
37
|
+
if (!isUuid(raw)) {
|
|
38
|
+
console.error(`Error: ${flag} must be a full UUID (got '${raw}')`);
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
return raw;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Resolve `--user` / `--agent` to the `(member_type, member_id)` pair the route
|
|
45
|
+
* takes. Exactly one is required: two would be two members in one request the
|
|
46
|
+
* route cannot express, and none is the 422 this command used to send.
|
|
47
|
+
*/
|
|
48
|
+
export function memberTarget(opts) {
|
|
49
|
+
if ((opts.user === undefined) === (opts.agent === undefined)) {
|
|
50
|
+
console.error("Error: pass exactly one of --user <uuid> or --agent <uuid>");
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
return opts.user !== undefined
|
|
54
|
+
? { member_type: "user", member_id: requireUuid("--user", opts.user) }
|
|
55
|
+
: { member_type: "agent", member_id: requireUuid("--agent", opts.agent) };
|
|
56
|
+
}
|
|
6
57
|
export function registerMemberCommands(program) {
|
|
7
58
|
const members = program
|
|
8
59
|
.command("members")
|
|
@@ -27,16 +78,20 @@ export function registerMemberCommands(program) {
|
|
|
27
78
|
});
|
|
28
79
|
members
|
|
29
80
|
.command("add <boardId>")
|
|
30
|
-
.description("Add a member to a
|
|
31
|
-
|
|
32
|
-
.option("--
|
|
81
|
+
.description("Add a user or agent of YOUR brand to a board by UUID. Grants that member access to the board, including a " +
|
|
82
|
+
"private one. To add someone outside your brand, use `opvs members invite`.")
|
|
83
|
+
.option("--user <uuid>", "User UUID to add (the id `opvs members list` shows for a user). Exactly one of --user / --agent.")
|
|
84
|
+
.option("--agent <uuid>", "Agent (persona) UUID to add. The gateway refuses (403) an agent of another brand. Exactly one of --user / --agent.")
|
|
85
|
+
.option("--role <tier>", ROLE_HELP)
|
|
33
86
|
.action(async (boardId, opts) => {
|
|
34
87
|
const wsSlug = program.opts().workspace;
|
|
88
|
+
const target = memberTarget(opts);
|
|
89
|
+
const role = oneOf("--role", opts.role, MEMBER_ROLES);
|
|
35
90
|
try {
|
|
36
91
|
const client = createClient(wsSlug);
|
|
37
|
-
const body = {
|
|
38
|
-
if (
|
|
39
|
-
body.
|
|
92
|
+
const body = { member_type: target.member_type, member_id: target.member_id };
|
|
93
|
+
if (role)
|
|
94
|
+
body.member_role = role;
|
|
40
95
|
const res = await client.post(`/api/v1/board/boards/${boardId}/members`, body);
|
|
41
96
|
const data = await res.json();
|
|
42
97
|
printJson(data);
|
|
@@ -47,15 +102,45 @@ export function registerMemberCommands(program) {
|
|
|
47
102
|
process.exit(1);
|
|
48
103
|
}
|
|
49
104
|
});
|
|
105
|
+
// Gateway-only route (`/boards/{id}/members/by-email`): it resolves the email
|
|
106
|
+
// against every OPVS user and sets the guest flag from brand membership.
|
|
107
|
+
members
|
|
108
|
+
.command("invite <boardId>")
|
|
109
|
+
.description("Add a person to a board by EMAIL. Someone outside your brand becomes an EXTERNAL GUEST of this one board, " +
|
|
110
|
+
"capped by --role; someone already in your brand is added as a normal member and --role is ignored. " +
|
|
111
|
+
"Only the brand that owns the board may invite.")
|
|
112
|
+
.requiredOption("--email <email>", "Email of an existing OPVS user (404 if nobody has it)")
|
|
113
|
+
.option("--role <tier>", `${ROLE_HELP} Default: viewer.`)
|
|
114
|
+
.action(async (boardId, opts) => {
|
|
115
|
+
const wsSlug = program.opts().workspace;
|
|
116
|
+
const role = oneOf("--role", opts.role, MEMBER_ROLES) ?? "viewer";
|
|
117
|
+
try {
|
|
118
|
+
const client = createClient(wsSlug);
|
|
119
|
+
const res = await client.post(`/api/v1/board/boards/${boardId}/members/by-email`, {
|
|
120
|
+
email: opts.email,
|
|
121
|
+
member_role: role,
|
|
122
|
+
});
|
|
123
|
+
const data = await res.json();
|
|
124
|
+
printJson(data);
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
const e = err;
|
|
128
|
+
console.error(`Error: ${e.detail || "Failed to invite member"}`);
|
|
129
|
+
process.exit(1);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
50
132
|
members
|
|
51
|
-
.command("remove <boardId> <
|
|
52
|
-
.description("Remove a
|
|
53
|
-
.
|
|
133
|
+
.command("remove <boardId> <memberId>")
|
|
134
|
+
.description("Remove a user or agent from a board. They lose access to it at once, a private board included.")
|
|
135
|
+
.option("--type <type>", "What <memberId> is: user | agent. Default: user.")
|
|
136
|
+
.action(async (boardId, memberId, opts) => {
|
|
54
137
|
const wsSlug = program.opts().workspace;
|
|
138
|
+
const type = oneOf("--type", opts.type, MEMBER_TYPES) ?? "user";
|
|
139
|
+
requireUuid("<memberId>", memberId);
|
|
55
140
|
try {
|
|
56
141
|
const client = createClient(wsSlug);
|
|
57
|
-
await client.delete(`/api/v1/board/boards/${boardId}/members/${
|
|
58
|
-
console.log(`Removed
|
|
142
|
+
await client.delete(`/api/v1/board/boards/${boardId}/members/${type}/${memberId}`);
|
|
143
|
+
console.log(`Removed ${type} ${memberId} from board ${boardId}`);
|
|
59
144
|
}
|
|
60
145
|
catch (err) {
|
|
61
146
|
const e = err;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"members.js","sourceRoot":"","sources":["../../src/commands/members.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"members.js","sourceRoot":"","sources":["../../src/commands/members.ts"],"names":[],"mappings":"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"}
|
|
@@ -16,4 +16,12 @@
|
|
|
16
16
|
* server-side from the PAT — never passed here.
|
|
17
17
|
*/
|
|
18
18
|
import { Command } from "commander";
|
|
19
|
+
/**
|
|
20
|
+
* Parse repeatable `--command-body name=path` / `--skill-body name=path` into the
|
|
21
|
+
* `{name: content}` map the bundle PATCH takes, reading each file.
|
|
22
|
+
*
|
|
23
|
+
* A path, not inline text: a body is a whole playbook or SKILL.md (up to 20,000
|
|
24
|
+
* chars, `BundleBodyText`), which no shell quotes comfortably.
|
|
25
|
+
*/
|
|
26
|
+
export declare function readBodies(flag: string, items: string[]): Record<string, string>;
|
|
19
27
|
export declare function registerProjectCommands(program: Command): void;
|
|
@@ -17,12 +17,54 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import { getEffectiveConfig, createClient } from "@opvs-ai/core";
|
|
19
19
|
import { buildUrl, printResponse, printJson } from "../lib/format.js";
|
|
20
|
+
import { healthParams, renderHealthReport, withHealthOptions } from "../lib/health.js";
|
|
21
|
+
import { buildRoutingBody, withRoutingOptions } from "../lib/routing.js";
|
|
22
|
+
import { FACTORY_PROJECT_GATE, warnIfFactoryUnresolved } from "../lib/factory-gate.js";
|
|
23
|
+
import { readFileSync } from "node:fs";
|
|
20
24
|
const BASE = "/api/v1/board/board-groups/projects";
|
|
21
25
|
/** commander repeatable-option accumulator (same shape as `create --board`). */
|
|
22
26
|
const collect = (val, acc) => {
|
|
23
27
|
acc.push(val);
|
|
24
28
|
return acc;
|
|
25
29
|
};
|
|
30
|
+
/**
|
|
31
|
+
* Parse repeatable `--command-body name=path` / `--skill-body name=path` into the
|
|
32
|
+
* `{name: content}` map the bundle PATCH takes, reading each file.
|
|
33
|
+
*
|
|
34
|
+
* A path, not inline text: a body is a whole playbook or SKILL.md (up to 20,000
|
|
35
|
+
* chars, `BundleBodyText`), which no shell quotes comfortably.
|
|
36
|
+
*/
|
|
37
|
+
export function readBodies(flag, items) {
|
|
38
|
+
const out = {};
|
|
39
|
+
for (const item of items) {
|
|
40
|
+
const eq = item.indexOf("=");
|
|
41
|
+
if (eq <= 0 || eq === item.length - 1) {
|
|
42
|
+
console.error(`Error: ${flag} expects <name>=<path> (got '${item}')`);
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
const name = item.slice(0, eq);
|
|
46
|
+
if (name in out) {
|
|
47
|
+
console.error(`Error: ${flag} names '${name}' twice`);
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
out[name] = readFileSync(item.slice(eq + 1), "utf-8");
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
console.error(`Error: ${flag} ${name}: cannot read '${item.slice(eq + 1)}' (${err.message})`);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
/** Warn for every member board a project write may have left unresolved (ASP-113). */
|
|
61
|
+
async function warnMemberBoards(client, data) {
|
|
62
|
+
const boards = data?.member_boards ?? [];
|
|
63
|
+
for (const b of boards) {
|
|
64
|
+
if (b.board_type === "factory" && b.id)
|
|
65
|
+
await warnIfFactoryUnresolved(client, b.id);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
26
68
|
export function registerProjectCommands(program) {
|
|
27
69
|
const projects = program
|
|
28
70
|
.command("projects")
|
|
@@ -74,7 +116,8 @@ export function registerProjectCommands(program) {
|
|
|
74
116
|
// repeated --board on create). Brand is injected by the proxy.
|
|
75
117
|
projects
|
|
76
118
|
.command("create")
|
|
77
|
-
.description("Create an empty project container"
|
|
119
|
+
.description("Create an empty project container. With --board, each board joins it; a board already in another active " +
|
|
120
|
+
`project becomes ambiguous. ${FACTORY_PROJECT_GATE}`)
|
|
78
121
|
.requiredOption("-n, --name <name>", "Project name")
|
|
79
122
|
.option("-b, --board <id>", "Initial member board id, repeatable (full UUID only — board_ids is not on the gateway's ref allowlist)", collect, [])
|
|
80
123
|
.action(async (opts) => {
|
|
@@ -87,6 +130,7 @@ export function registerProjectCommands(program) {
|
|
|
87
130
|
const res = await client.post(BASE, body);
|
|
88
131
|
const data = await res.json();
|
|
89
132
|
printJson(data);
|
|
133
|
+
await warnMemberBoards(client, data);
|
|
90
134
|
}
|
|
91
135
|
catch (err) {
|
|
92
136
|
const e = err;
|
|
@@ -120,6 +164,61 @@ export function registerProjectCommands(program) {
|
|
|
120
164
|
process.exit(1);
|
|
121
165
|
}
|
|
122
166
|
});
|
|
167
|
+
// ── set-routing (ASP-25, plan §C / migration 062) ───────────────────
|
|
168
|
+
// A dedicated verb rather than more flags on `update`: a routing default
|
|
169
|
+
// reaches every board in the project, the widest blast radius of the three
|
|
170
|
+
// rungs, and it deserves a command whose name says so.
|
|
171
|
+
withRoutingOptions(projects
|
|
172
|
+
.command("set-routing <id>")
|
|
173
|
+
.description("Set the project's routing defaults (model / provider / harness / claimable-by) for all its boards. Only the flags you pass change."), "project").action(async (id, opts) => {
|
|
174
|
+
const wsSlug = program.opts().workspace;
|
|
175
|
+
try {
|
|
176
|
+
const body = buildRoutingBody(opts);
|
|
177
|
+
if (Object.keys(body).length === 0) {
|
|
178
|
+
console.error("Nothing to set. Provide --model, --provider, --harness, or --claimable-by");
|
|
179
|
+
process.exit(1);
|
|
180
|
+
}
|
|
181
|
+
const client = createClient(wsSlug);
|
|
182
|
+
const res = await client.patch(`${BASE}/${id}`, body);
|
|
183
|
+
const data = (await res.json());
|
|
184
|
+
printJson({
|
|
185
|
+
id: data.id,
|
|
186
|
+
name: data.name,
|
|
187
|
+
default_model: data.default_model ?? null,
|
|
188
|
+
default_provider: data.default_provider ?? null,
|
|
189
|
+
default_harness: data.default_harness ?? null,
|
|
190
|
+
default_claimable_by: data.default_claimable_by ?? null,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
catch (err) {
|
|
194
|
+
const e = err;
|
|
195
|
+
console.error(`Error: ${e.detail || "Failed to set project routing"}`);
|
|
196
|
+
process.exit(1);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
// ── health (ASP-25, plan §J4 / §J5) ────────────────────────────────
|
|
200
|
+
withHealthOptions(projects
|
|
201
|
+
.command("health <id>")
|
|
202
|
+
.description("Project audit: bundle non-empty, member boards present, no board claimed by two projects, and every member " +
|
|
203
|
+
"board's verdict. Thresholds are forwarded to each board; an unsupplied one prints NOT CHECKED and the " +
|
|
204
|
+
"verdict reads INCOMPLETE — a project never reads healthier than its boards.")).action(async (id, opts) => {
|
|
205
|
+
const wsSlug = program.opts().workspace;
|
|
206
|
+
try {
|
|
207
|
+
const client = createClient(wsSlug);
|
|
208
|
+
const url = buildUrl(`${BASE}/${id}/health`, healthParams(opts));
|
|
209
|
+
const res = await client.get(url);
|
|
210
|
+
const report = (await res.json());
|
|
211
|
+
if (opts.json)
|
|
212
|
+
printJson(report);
|
|
213
|
+
else
|
|
214
|
+
console.log(renderHealthReport(report));
|
|
215
|
+
}
|
|
216
|
+
catch (err) {
|
|
217
|
+
const e = err;
|
|
218
|
+
console.error(`Error: ${e.detail || "Failed to get project health"}`);
|
|
219
|
+
process.exit(1);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
123
222
|
// ── set-status (manual lifecycle transition) ───────────────────────
|
|
124
223
|
// status ∈ active | on_hold | completed. On `completed` an optional
|
|
125
224
|
// --handoff free-text is stored in settings.closing_handoff.
|
|
@@ -147,8 +246,10 @@ export function registerProjectCommands(program) {
|
|
|
147
246
|
// ── archive / unarchive (container-only, orthogonal to status) ─────
|
|
148
247
|
projects
|
|
149
248
|
.command("archive <id>")
|
|
150
|
-
.description("Archive a project (hide from default list, still reachable)"
|
|
151
|
-
|
|
249
|
+
.description("Archive a project (hide from default list, still reachable). An archived project is not ACTIVE: its boards " +
|
|
250
|
+
"stop inheriting its bundle and routing defaults, and a board it was the only project of drops to none. " +
|
|
251
|
+
FACTORY_PROJECT_GATE)
|
|
252
|
+
.option("--undo", "Unarchive instead (set is_archived=false). A board that also joined another project meanwhile becomes ambiguous.")
|
|
152
253
|
.action(async (id, opts) => {
|
|
153
254
|
const wsSlug = program.opts().workspace;
|
|
154
255
|
try {
|
|
@@ -158,6 +259,7 @@ export function registerProjectCommands(program) {
|
|
|
158
259
|
});
|
|
159
260
|
const data = await res.json();
|
|
160
261
|
printJson(data);
|
|
262
|
+
await warnMemberBoards(client, data);
|
|
161
263
|
}
|
|
162
264
|
catch (err) {
|
|
163
265
|
const e = err;
|
|
@@ -168,7 +270,9 @@ export function registerProjectCommands(program) {
|
|
|
168
270
|
// ── add-board (many-to-many membership) ────────────────────────────
|
|
169
271
|
projects
|
|
170
272
|
.command("add-board <id> <board_id>")
|
|
171
|
-
.description("Add a board to a project
|
|
273
|
+
.description("Add a board to a project. Membership is many-to-many, but a board claimed by TWO active projects is " +
|
|
274
|
+
"ambiguous and inherits NEITHER project's bundle or routing defaults — check with `opvs boards projects <board>`. " +
|
|
275
|
+
FACTORY_PROJECT_GATE)
|
|
172
276
|
.action(async (id, boardId) => {
|
|
173
277
|
const wsSlug = program.opts().workspace;
|
|
174
278
|
try {
|
|
@@ -178,6 +282,7 @@ export function registerProjectCommands(program) {
|
|
|
178
282
|
});
|
|
179
283
|
const data = await res.json();
|
|
180
284
|
printJson(data);
|
|
285
|
+
await warnIfFactoryUnresolved(client, boardId);
|
|
181
286
|
}
|
|
182
287
|
catch (err) {
|
|
183
288
|
const e = err;
|
|
@@ -188,13 +293,15 @@ export function registerProjectCommands(program) {
|
|
|
188
293
|
// ── remove-board (membership only — board survives, O-P1) ──────────
|
|
189
294
|
projects
|
|
190
295
|
.command("remove-board <id> <board_id>")
|
|
191
|
-
.description("Remove a board from a project (the board itself stays live)"
|
|
296
|
+
.description("Remove a board from a project (the board itself stays live). Its cards stop inheriting this project's bundle " +
|
|
297
|
+
`and routing defaults; removing its only project leaves it in none. ${FACTORY_PROJECT_GATE}`)
|
|
192
298
|
.action(async (id, boardId) => {
|
|
193
299
|
const wsSlug = program.opts().workspace;
|
|
194
300
|
try {
|
|
195
301
|
const client = createClient(wsSlug);
|
|
196
302
|
const res = await client.delete(`${BASE}/${id}/boards/${boardId}`);
|
|
197
303
|
await printResponse(res, true);
|
|
304
|
+
await warnIfFactoryUnresolved(client, boardId);
|
|
198
305
|
}
|
|
199
306
|
catch (err) {
|
|
200
307
|
const e = err;
|
|
@@ -263,6 +370,16 @@ export function registerProjectCommands(program) {
|
|
|
263
370
|
.option("--clear-commands", "Replace commands with an empty list")
|
|
264
371
|
.option("--clear-skills", "Replace skills with an empty list")
|
|
265
372
|
.option("--clear-rules", "Replace rules with an empty list")
|
|
373
|
+
// `ProjectBundleUpdate.command_bodies` / `skill_bodies`: omitted = left
|
|
374
|
+
// alone, passed = the map is REPLACED, and bodies for names not in the
|
|
375
|
+
// resulting list are pruned server-side (`_drop_orphan_bodies`).
|
|
376
|
+
.option("--command-body <name=path>", "Inline content for a listed command, read from a file (repeatable; max 20,000 chars). Installed on the desk " +
|
|
377
|
+
"at claim time instead of the repo image's file. Passing any REPLACES the whole map — a body you leave out " +
|
|
378
|
+
"is deleted — and a body whose name is not in the commands list is dropped.", collect, [])
|
|
379
|
+
.option("--skill-body <name=path>", "Inline SKILL.md for a listed skill, read from a file (repeatable; max 20,000 chars). Same REPLACE and drop " +
|
|
380
|
+
"rules as --command-body.", collect, [])
|
|
381
|
+
.option("--clear-command-bodies", "Replace the command bodies with an empty map (names fall back to the repo image)")
|
|
382
|
+
.option("--clear-skill-bodies", "Replace the skill bodies with an empty map")
|
|
266
383
|
.action(async (id, opts) => {
|
|
267
384
|
const wsSlug = program.opts().workspace;
|
|
268
385
|
const body = {};
|
|
@@ -285,8 +402,23 @@ export function registerProjectCommands(program) {
|
|
|
285
402
|
else if (values.length > 0)
|
|
286
403
|
body[name] = values;
|
|
287
404
|
}
|
|
405
|
+
const bodyMaps = [
|
|
406
|
+
["command_bodies", "--command-body", opts.commandBody ?? [], !!opts.clearCommandBodies, "--clear-command-bodies"],
|
|
407
|
+
["skill_bodies", "--skill-body", opts.skillBody ?? [], !!opts.clearSkillBodies, "--clear-skill-bodies"],
|
|
408
|
+
];
|
|
409
|
+
for (const [name, flag, items, clear, clearFlag] of bodyMaps) {
|
|
410
|
+
if (clear && items.length > 0) {
|
|
411
|
+
console.error(`Cannot both set and clear ${name}. Drop ${clearFlag} or ${flag}.`);
|
|
412
|
+
process.exit(1);
|
|
413
|
+
return;
|
|
414
|
+
}
|
|
415
|
+
if (clear)
|
|
416
|
+
body[name] = {};
|
|
417
|
+
else if (items.length > 0)
|
|
418
|
+
body[name] = readBodies(flag, items);
|
|
419
|
+
}
|
|
288
420
|
if (Object.keys(body).length === 0) {
|
|
289
|
-
console.error("Nothing to update. Provide --command / --skill / --rule
|
|
421
|
+
console.error("Nothing to update. Provide --command / --skill / --rule / --command-body / --skill-body, or a --clear-* flag");
|
|
290
422
|
process.exit(1);
|
|
291
423
|
return;
|
|
292
424
|
}
|