@gobi-ai/cli 1.3.6 → 1.3.8

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.
@@ -4,12 +4,12 @@
4
4
  "name": "gobi-ai"
5
5
  },
6
6
  "description": "Claude Code plugin for the Gobi collaborative knowledge platform CLI",
7
- "version": "1.3.6",
7
+ "version": "1.3.8",
8
8
  "plugins": [
9
9
  {
10
10
  "name": "gobi",
11
11
  "description": "Manage the Gobi collaborative knowledge platform from the command line. Search and ask brains, publish brain documents, create threads, manage sessions, generate images and videos.",
12
- "version": "1.3.6",
12
+ "version": "1.3.8",
13
13
  "author": {
14
14
  "name": "gobi-ai"
15
15
  },
@@ -21,7 +21,7 @@
21
21
  "./skills/gobi-brain",
22
22
  "./skills/gobi-feed",
23
23
  "./skills/gobi-notes",
24
- "./skills/gobi-proposal",
24
+ "./skills/gobi-draft",
25
25
  "./skills/gobi-media",
26
26
  "./skills/gobi-sense",
27
27
  "./skills/gobi-homepage"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "gobi",
3
3
  "description": "Manage the Gobi collaborative knowledge platform from the command line",
4
- "version": "1.3.6",
4
+ "version": "1.3.8",
5
5
  "author": {
6
6
  "name": "gobi-ai"
7
7
  },
@@ -12,7 +12,7 @@
12
12
  "./skills/gobi-brain",
13
13
  "./skills/gobi-feed",
14
14
  "./skills/gobi-notes",
15
- "./skills/gobi-proposal",
15
+ "./skills/gobi-draft",
16
16
  "./skills/gobi-media",
17
17
  "./skills/gobi-sense",
18
18
  "./skills/gobi-homepage"
package/README.md CHANGED
@@ -164,21 +164,19 @@ Times are ISO 8601 UTC (e.g. `2026-03-20T00:00:00Z`).
164
164
  `notes list` and `notes create` accept `--timezone <iana>` (default: system timezone) for day boundaries.
165
165
  `notes list` also accepts `--limit`/`--cursor` for pagination.
166
166
 
167
- ### Proposals
167
+ ### Drafts
168
168
 
169
- Proposals are authored by your agent during chat (or by external agents using `gobi proposal add` as their tool layer). The top 5 pending proposals (lowest priority first) feed the agent's system prompt every turn. Every proposal is anchored to the chat session that produced it.
169
+ Drafts are authored by your agent during chat (or by external agents using `gobi draft add` as their tool layer). Each draft carries 0–3 AI-suggested actions the user can pick from. The top 5 pending drafts (lowest priority first) feed the agent's system prompt every turn. Every draft is anchored to the chat session that produced it.
170
170
 
171
171
  | Command | Description |
172
172
  |---------|-------------|
173
- | `gobi proposal list [--limit N]` | List proposals (priority ASC, then newest first) |
174
- | `gobi proposal get <id>` | Show one proposal with its history |
175
- | `gobi proposal add <title> <content> [--session <id>] [--priority N]` | Add a proposal (use `-` for content to read from stdin). `--session` falls back to `$GOBI_SESSION_ID`. |
176
- | `gobi proposal edit <id> [--title <t>] [--content <c>]` | Update title and/or content; bumps revision (use `-` for stdin) |
177
- | `gobi proposal delete <id>` | Delete a proposal |
178
- | `gobi proposal prioritize <id> <priority>` | Set priority (lower = higher) |
179
- | `gobi proposal accept <id>` | Mark as accepted (the client posts the synthesized message into the session) |
180
- | `gobi proposal reject <id>` | Mark as rejected |
181
- | `gobi proposal revise <id> <comment>` | Mark for revision and record the user's comment |
173
+ | `gobi draft list [--limit N]` | List drafts (priority ASC, then newest first) |
174
+ | `gobi draft get <id>` | Show one draft with its history and suggested actions |
175
+ | `gobi draft add <title> <content> [--session <id>] [--priority N] [--action <label>]…` | Add a draft. Pass `--action` up to 3 times to attach AI-suggested actions. `--session` falls back to `$GOBI_SESSION_ID`. Use `-` for content to read from stdin. |
176
+ | `gobi draft delete <id>` | Delete a draft |
177
+ | `gobi draft prioritize <id> <priority>` | Set priority (lower = higher) |
178
+ | `gobi draft action <id> <index>` | Take one of the draft's suggested actions by 0-based index. Marks `actioned` and posts the synthesized message into the originating session. |
179
+ | `gobi draft revise <id> <comment> [--title <t>] [--content <c>] [--action <label>]…` | Bump revision with a comment; optionally replace title / content / actions in the same call |
182
180
 
183
181
  ### Sync
184
182
 
@@ -0,0 +1,213 @@
1
+ import { readFileSync } from "fs";
2
+ import { apiDelete, apiGet, apiPatch, apiPost } from "../client.js";
3
+ import { isJsonMode, jsonOut, unwrapResp } from "./utils.js";
4
+ function readContent(value) {
5
+ if (value === "-")
6
+ return readFileSync("/dev/stdin", "utf8");
7
+ return value;
8
+ }
9
+ function snippet(content, max = 80) {
10
+ const single = content.replace(/\s+/g, " ");
11
+ return single.length > max ? `${single.slice(0, max)}…` : single;
12
+ }
13
+ function parseActionFlags(values) {
14
+ if (!values)
15
+ return [];
16
+ return values
17
+ .map((v) => v.trim())
18
+ .filter(Boolean)
19
+ .slice(0, 3)
20
+ .map((label) => ({ label }));
21
+ }
22
+ function formatDraftLine(d) {
23
+ const status = d.status === "pending" ? "·" : "✓";
24
+ const actionCount = d.actions.length;
25
+ return `- [${status}] p${d.priority} rev${d.revision} ${d.draftId.slice(0, 8)} ${snippet(d.title)} (${actionCount} action${actionCount === 1 ? "" : "s"})`;
26
+ }
27
+ export function registerDraftCommand(program) {
28
+ // The draft command surface is designed for agent use: every subcommand
29
+ // accepts `--json` (set globally) and returns the same envelope shape, and
30
+ // the agent-authoring flow funnels through `add` + `revise` while user-
31
+ // facing decisions go through `action` and `revise` (with --comment).
32
+ const draft = program
33
+ .command("draft")
34
+ .description("Drafts authored by your agent during chat. Each carries up to 3 AI-suggested actions. Top-5 pending feed the system prompt; picking an action posts a synthesized message into the originating session.");
35
+ // ── List ──
36
+ draft
37
+ .command("list")
38
+ .description("List drafts (priority ASC, then newest first).")
39
+ .option("--limit <number>", "Max drafts to return (1-200)", "50")
40
+ .action(async (opts) => {
41
+ const params = { limit: parseInt(opts.limit, 10) };
42
+ const resp = (await apiGet("/app/drafts", params));
43
+ const items = (resp.data || []);
44
+ if (isJsonMode(draft)) {
45
+ jsonOut(items);
46
+ return;
47
+ }
48
+ if (!items.length) {
49
+ console.log("No drafts.");
50
+ return;
51
+ }
52
+ console.log(`Drafts (${items.length}):`);
53
+ for (const d of items)
54
+ console.log(formatDraftLine(d));
55
+ });
56
+ // ── Get ──
57
+ draft
58
+ .command("get <draftId>")
59
+ .description("Show one draft with its history and suggested actions.")
60
+ .action(async (draftId) => {
61
+ const resp = (await apiGet(`/app/drafts/${draftId}`));
62
+ const d = unwrapResp(resp);
63
+ if (isJsonMode(draft)) {
64
+ jsonOut(d);
65
+ return;
66
+ }
67
+ console.log(`Draft ${d.draftId}`);
68
+ console.log(` title: ${d.title}`);
69
+ console.log(` status: ${d.status}`);
70
+ console.log(` priority: ${d.priority}`);
71
+ console.log(` revision: ${d.revision}`);
72
+ console.log(` session: ${d.sessionId}`);
73
+ console.log(` created: ${d.createdAt}`);
74
+ console.log("");
75
+ console.log("Content:");
76
+ console.log(d.content);
77
+ if (d.actions.length) {
78
+ console.log("");
79
+ console.log("Suggested actions:");
80
+ d.actions.forEach((a, i) => console.log(` [${i}] ${a.label}`));
81
+ }
82
+ if (d.history.length) {
83
+ console.log("");
84
+ console.log("History:");
85
+ for (const h of d.history) {
86
+ console.log(` ${h.createdAt} rev${h.revision} ${h.type}`);
87
+ if (h.type === "created" || h.type === "revised") {
88
+ if (h.title !== undefined)
89
+ console.log(` title: ${h.title}`);
90
+ if (h.content !== undefined) {
91
+ console.log(` content: ${snippet(h.content, 200)}`);
92
+ }
93
+ if (h.actions !== undefined && h.actions.length) {
94
+ console.log(` actions: ${h.actions.map((a) => a.label).join(" | ")}`);
95
+ }
96
+ if (h.comment !== undefined)
97
+ console.log(` comment: ${h.comment}`);
98
+ }
99
+ else if (h.type === "prioritized" && h.priority !== undefined) {
100
+ console.log(` priority=${h.priority}`);
101
+ }
102
+ else if (h.type === "actioned") {
103
+ console.log(` action[${h.actionIndex}]=${h.actionLabel}`);
104
+ }
105
+ }
106
+ }
107
+ });
108
+ // ── Add ──
109
+ draft
110
+ .command("add <title> <content>")
111
+ .description("Add a draft. Pass '-' for content to read from stdin. Pass --action up to 3 times to attach AI-suggested actions. Requires a chat session — the agent runtime exports GOBI_SESSION_ID automatically; outside that, pass --session.")
112
+ .option("--session <sessionId>", "Originating chat session UUID. Falls back to $GOBI_SESSION_ID when set.")
113
+ .option("--priority <number>", "Priority (lower = higher), default 100")
114
+ .option("--action <label>", "Suggested action label (repeatable, max 3). Each label is what the user sees on the button.", (value, prev = []) => [...prev, value], [])
115
+ .action(async (title, content, opts) => {
116
+ const sessionId = opts.session || process.env.GOBI_SESSION_ID || "";
117
+ if (!sessionId) {
118
+ console.error("Error: missing session id. Pass --session <uuid> or set GOBI_SESSION_ID in the environment.");
119
+ process.exit(1);
120
+ }
121
+ const body = {
122
+ title,
123
+ content: readContent(content),
124
+ sessionId,
125
+ };
126
+ if (opts.priority)
127
+ body.priority = parseInt(opts.priority, 10);
128
+ const actions = parseActionFlags(opts.action);
129
+ if (actions.length)
130
+ body.actions = actions;
131
+ const resp = (await apiPost("/app/drafts", body));
132
+ const d = unwrapResp(resp);
133
+ if (isJsonMode(draft)) {
134
+ jsonOut(d);
135
+ return;
136
+ }
137
+ console.log(`Created ${d.draftId} (priority ${d.priority}, ${d.actions.length} action${d.actions.length === 1 ? "" : "s"}).`);
138
+ });
139
+ // ── Delete ──
140
+ draft
141
+ .command("delete <draftId>")
142
+ .description("Delete a draft.")
143
+ .action(async (draftId) => {
144
+ await apiDelete(`/app/drafts/${draftId}`);
145
+ if (isJsonMode(draft)) {
146
+ jsonOut({ deleted: draftId });
147
+ return;
148
+ }
149
+ console.log(`Deleted ${draftId}.`);
150
+ });
151
+ // ── Prioritize ──
152
+ draft
153
+ .command("prioritize <draftId> <priority>")
154
+ .description("Set priority (lower = higher). Top 5 feed the system prompt.")
155
+ .action(async (draftId, priority) => {
156
+ const resp = (await apiPatch(`/app/drafts/${draftId}/priority`, {
157
+ priority: parseInt(priority, 10),
158
+ }));
159
+ const d = unwrapResp(resp);
160
+ if (isJsonMode(draft)) {
161
+ jsonOut(d);
162
+ return;
163
+ }
164
+ console.log(`Set ${d.draftId} priority to ${d.priority}.`);
165
+ });
166
+ // ── Action ──
167
+ draft
168
+ .command("action <draftId> <actionIndex>")
169
+ .description("Take one of the draft's suggested actions by 0-based index. Marks the draft 'actioned' and the client posts the synthesized message into the originating session.")
170
+ .action(async (draftId, actionIndex) => {
171
+ const idx = parseInt(actionIndex, 10);
172
+ if (Number.isNaN(idx) || idx < 0 || idx > 2) {
173
+ console.error("Error: actionIndex must be 0, 1, or 2.");
174
+ process.exit(1);
175
+ }
176
+ const resp = (await apiPost(`/app/drafts/${draftId}/action`, {
177
+ actionIndex: idx,
178
+ }));
179
+ const d = unwrapResp(resp);
180
+ if (isJsonMode(draft)) {
181
+ jsonOut(d);
182
+ return;
183
+ }
184
+ const label = d.actions[idx]?.label ?? `action ${idx}`;
185
+ console.log(`Took action "${label}" on ${d.draftId}.`);
186
+ });
187
+ // ── Revise ──
188
+ draft
189
+ .command("revise <draftId> <comment>")
190
+ .description("Bump the draft to a new revision. Comment is required. Pass --title, --content, and/or --action to update the draft in the same call (--action repeatable, max 3, replaces all). Pass '-' for any of comment/title/content to read from stdin.")
191
+ .option("--title <title>", "Replacement title")
192
+ .option("--content <content>", "Replacement content; pass '-' to read from stdin")
193
+ .option("--action <label>", "Replacement suggested action label (repeatable, max 3). When passed, replaces the entire actions array.", (value, prev = []) => [...prev, value], [])
194
+ .action(async (draftId, comment, opts) => {
195
+ const body = {
196
+ comment: readContent(comment),
197
+ };
198
+ if (opts.title !== undefined)
199
+ body.title = opts.title;
200
+ if (opts.content !== undefined)
201
+ body.content = readContent(opts.content);
202
+ if (opts.action && opts.action.length > 0) {
203
+ body.actions = parseActionFlags(opts.action);
204
+ }
205
+ const resp = (await apiPost(`/app/drafts/${draftId}/revise`, body));
206
+ const d = unwrapResp(resp);
207
+ if (isJsonMode(draft)) {
208
+ jsonOut(d);
209
+ return;
210
+ }
211
+ console.log(`Revised ${d.draftId} → rev${d.revision}.`);
212
+ });
213
+ }
package/dist/main.js CHANGED
@@ -14,7 +14,7 @@ import { registerSenseCommand } from "./commands/sense.js";
14
14
  import { registerSyncCommand } from "./commands/sync.js";
15
15
  import { registerUpdateCommand } from "./commands/update.js";
16
16
  import { registerMediaCommand } from "./commands/media.js";
17
- import { registerProposalCommand } from "./commands/proposal.js";
17
+ import { registerDraftCommand } from "./commands/draft.js";
18
18
  const require = createRequire(import.meta.url);
19
19
  const { version } = require("../package.json");
20
20
  const SKIP_BANNER_COMMANDS = new Set(["auth", "init", "update"]);
@@ -45,7 +45,7 @@ export async function cli() {
45
45
  registerSyncCommand(program);
46
46
  registerUpdateCommand(program);
47
47
  registerMediaCommand(program);
48
- registerProposalCommand(program);
48
+ registerDraftCommand(program);
49
49
  // Propagate helpWidth to all subcommands
50
50
  const helpWidth = process.stdout.columns || 200;
51
51
  for (const cmd of program.commands) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gobi-ai/cli",
3
- "version": "1.3.6",
3
+ "version": "1.3.8",
4
4
  "description": "CLI client for the Gobi collaborative knowledge platform",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -0,0 +1,74 @@
1
+ ---
2
+ name: gobi-draft
3
+ description: >-
4
+ Gobi draft commands for managing agent-authored drafts: list, get, add,
5
+ delete, prioritize, action, revise. Each draft carries 0–3 AI-suggested
6
+ actions; the user picks one with `draft action`. The top-priority pending
7
+ drafts feed into the agent's system prompt every turn. Use when the user
8
+ wants to review, organize, or respond to drafts — or when an agent (using
9
+ gobi-cli as its tool layer) wants to record a draft it just composed.
10
+ allowed-tools: Bash(gobi:*)
11
+ metadata:
12
+ author: gobi-ai
13
+ version: "1.4.0"
14
+ ---
15
+
16
+ # gobi-draft
17
+
18
+ Gobi draft commands for managing agent-authored drafts (v1.4.0).
19
+
20
+ Requires gobi-cli installed and authenticated. See gobi-core skill for setup.
21
+
22
+ ## What is a draft?
23
+
24
+ A draft is a unit of standing guidance authored by an agent (in-process during chat, or via `gobi draft add` when the agent uses gobi-cli as its tool layer). Each draft has:
25
+
26
+ - **title** — short headline (1–200 chars)
27
+ - **content** — the draft text (markdown, 1–8000 chars)
28
+ - **actions** — 0–3 AI-suggested action labels the user can pick from (e.g. "Accept", "Reject", "Schedule for later"). The agent generates these when authoring the draft.
29
+ - **sessionId** — required; the chat session that produced the draft
30
+ - **priority** — lower number = higher priority; default `100`
31
+ - **status** — `pending` until the user picks an action, then `actioned`
32
+ - **revision** — bumped each time the draft is revised
33
+ - **history** — append-only log of `created`, `revised`, `prioritized`, and `actioned` events
34
+
35
+ The top 5 pending drafts (lowest priority first) are injected into the agent's system prompt every turn — that's how drafts turn into standing instructions.
36
+
37
+ When invoked from inside an agent run, the runtime exports `GOBI_SESSION_ID` so `gobi draft add` picks it up automatically; otherwise pass `--session <uuid>`.
38
+
39
+ ## Lifecycle
40
+
41
+ A draft is **authored** by an agent (`gobi draft add` with up to three `--action` flags). The user can then:
42
+
43
+ - **Take an action**: `gobi draft action <id> <index>` — flips status to `actioned`, the client posts the synthesized message ("Take action 'X' on draft Y") into the originating chat session.
44
+ - **Ask to revise**: `gobi draft revise <id> <comment>` — bumps revision and records the comment. The agent's next turn should produce a fresh `gobi draft revise --title --content --action ...` (or a new `add`) addressing the comment.
45
+ - **Re-prioritize / delete** as bookkeeping.
46
+
47
+ Only pending drafts can be revised. Picking an action is terminal; the agent can author a fresh draft if the user later changes their mind.
48
+
49
+ ## Important: JSON Mode
50
+
51
+ For programmatic/agent usage, always pass `--json` as a **global** option (before the subcommand):
52
+
53
+ ```bash
54
+ gobi --json draft list --limit 20
55
+ gobi --json draft add "Concise titles" "Prefer concise titles for brain updates." --action "Apply" --action "Skip" --priority 50
56
+ gobi --json draft action <draftId> 0
57
+ ```
58
+
59
+ JSON mode wraps the response as `{"success": true, "data": <draft>}` (or `{"success": false, "error": "..."}`).
60
+
61
+ ## Available Commands
62
+
63
+ - `gobi draft` — Drafts authored by your agent during chat. Each carries up to 3 AI-suggested actions. Top-5 pending feed the system prompt; picking an action posts a synthesized message into the originating session.
64
+ - `gobi draft list` — List drafts (priority ASC, then newest first).
65
+ - `gobi draft get` — Show one draft with its history and suggested actions.
66
+ - `gobi draft add` — Add a draft. Pass `--action <label>` up to 3 times to attach AI-suggested actions.
67
+ - `gobi draft delete` — Delete a draft.
68
+ - `gobi draft prioritize` — Set priority (lower = higher). Top 5 feed the system prompt.
69
+ - `gobi draft action` — Take one of the draft's suggested actions by 0-based index. Posts the synthesized message into the originating session.
70
+ - `gobi draft revise` — Bump the draft to a new revision with a comment, optionally replacing title / content / actions.
71
+
72
+ ## Reference Documentation
73
+
74
+ - [gobi draft](references/draft.md)
@@ -0,0 +1,109 @@
1
+ # gobi draft
2
+
3
+ ```
4
+ Usage: gobi draft [options] [command]
5
+
6
+ Drafts authored by your agent during chat. Each carries up to 3 AI-suggested actions. Top-5 pending feed the system prompt; picking an action posts a synthesized message into the originating session.
7
+
8
+ Options:
9
+ -h, --help display help for command
10
+
11
+ Commands:
12
+ list [options] List drafts (priority ASC, then newest first).
13
+ get <draftId> Show one draft with its history and suggested actions.
14
+ add [options] <title> <content> Add a draft. Pass '-' for content to read from stdin. Pass --action up to 3 times to attach AI-suggested actions. Requires a chat session — the agent runtime
15
+ exports GOBI_SESSION_ID automatically; outside that, pass --session.
16
+ delete <draftId> Delete a draft.
17
+ prioritize <draftId> <priority> Set priority (lower = higher). Top 5 feed the system prompt.
18
+ action <draftId> <actionIndex> Take one of the draft's suggested actions by 0-based index. Marks the draft 'actioned' and the client posts the synthesized message into the originating
19
+ session.
20
+ revise [options] <draftId> <comment> Bump the draft to a new revision. Comment is required. Pass --title, --content, and/or --action to update the draft in the same call (--action repeatable, max
21
+ 3, replaces all). Pass '-' for any of comment/title/content to read from stdin.
22
+ help [command] display help for command
23
+ ```
24
+
25
+ ## list
26
+
27
+ ```
28
+ Usage: gobi draft list [options]
29
+
30
+ List drafts (priority ASC, then newest first).
31
+
32
+ Options:
33
+ --limit <number> Max drafts to return (1-200) (default: "50")
34
+ -h, --help display help for command
35
+ ```
36
+
37
+ ## get
38
+
39
+ ```
40
+ Usage: gobi draft get [options] <draftId>
41
+
42
+ Show one draft with its history and suggested actions.
43
+
44
+ Options:
45
+ -h, --help display help for command
46
+ ```
47
+
48
+ ## add
49
+
50
+ ```
51
+ Usage: gobi draft add [options] <title> <content>
52
+
53
+ Add a draft. Pass '-' for content to read from stdin. Pass --action up to 3 times to attach AI-suggested actions. Requires a chat session — the agent runtime exports GOBI_SESSION_ID automatically;
54
+ outside that, pass --session.
55
+
56
+ Options:
57
+ --session <sessionId> Originating chat session UUID. Falls back to $GOBI_SESSION_ID when set.
58
+ --priority <number> Priority (lower = higher), default 100
59
+ --action <label> Suggested action label (repeatable, max 3). Each label is what the user sees on the button. (default: [])
60
+ -h, --help display help for command
61
+ ```
62
+
63
+ ## delete
64
+
65
+ ```
66
+ Usage: gobi draft delete [options] <draftId>
67
+
68
+ Delete a draft.
69
+
70
+ Options:
71
+ -h, --help display help for command
72
+ ```
73
+
74
+ ## prioritize
75
+
76
+ ```
77
+ Usage: gobi draft prioritize [options] <draftId> <priority>
78
+
79
+ Set priority (lower = higher). Top 5 feed the system prompt.
80
+
81
+ Options:
82
+ -h, --help display help for command
83
+ ```
84
+
85
+ ## action
86
+
87
+ ```
88
+ Usage: gobi draft action [options] <draftId> <actionIndex>
89
+
90
+ Take one of the draft's suggested actions by 0-based index. Marks the draft 'actioned' and the client posts the synthesized message into the originating session.
91
+
92
+ Options:
93
+ -h, --help display help for command
94
+ ```
95
+
96
+ ## revise
97
+
98
+ ```
99
+ Usage: gobi draft revise [options] <draftId> <comment>
100
+
101
+ Bump the draft to a new revision. Comment is required. Pass --title, --content, and/or --action to update the draft in the same call (--action repeatable, max 3, replaces all). Pass '-' for any of
102
+ comment/title/content to read from stdin.
103
+
104
+ Options:
105
+ --title <title> Replacement title
106
+ --content <content> Replacement content; pass '-' to read from stdin
107
+ --action <label> Replacement suggested action label (repeatable, max 3). When passed, replaces the entire actions array. (default: [])
108
+ -h, --help display help for command
109
+ ```
@@ -1,195 +0,0 @@
1
- import { readFileSync } from "fs";
2
- import { apiDelete, apiGet, apiPatch, apiPost } from "../client.js";
3
- import { isJsonMode, jsonOut, unwrapResp } from "./utils.js";
4
- function readContent(value) {
5
- if (value === "-")
6
- return readFileSync("/dev/stdin", "utf8");
7
- return value;
8
- }
9
- function snippet(content, max = 80) {
10
- const single = content.replace(/\s+/g, " ");
11
- return single.length > max ? `${single.slice(0, max)}…` : single;
12
- }
13
- function formatProposalLine(p) {
14
- const status = p.status === "pending" ? "·" : p.status === "accepted" ? "✓" : "✗";
15
- return `- [${status}] p${p.priority} rev${p.revision} ${p.proposalId.slice(0, 8)} ${snippet(p.title)}`;
16
- }
17
- export function registerProposalCommand(program) {
18
- const proposal = program
19
- .command("proposal")
20
- .description("Proposals authored by your agent during chat. Top-5 feed the system prompt; accept/reject/revise update state and the client posts the synthesized message into the session.");
21
- // ── List ──
22
- proposal
23
- .command("list")
24
- .description("List proposals (priority ASC, then newest first).")
25
- .option("--limit <number>", "Max proposals to return (1-200)", "50")
26
- .action(async (opts) => {
27
- const params = { limit: parseInt(opts.limit, 10) };
28
- const resp = (await apiGet("/app/proposals", params));
29
- const items = (resp.data || []);
30
- if (isJsonMode(proposal)) {
31
- jsonOut(items);
32
- return;
33
- }
34
- if (!items.length) {
35
- console.log("No proposals.");
36
- return;
37
- }
38
- console.log(`Proposals (${items.length}):`);
39
- for (const p of items)
40
- console.log(formatProposalLine(p));
41
- });
42
- // ── Get ──
43
- proposal
44
- .command("get <proposalId>")
45
- .description("Show one proposal with its history.")
46
- .action(async (proposalId) => {
47
- const resp = (await apiGet(`/app/proposals/${proposalId}`));
48
- const p = unwrapResp(resp);
49
- if (isJsonMode(proposal)) {
50
- jsonOut(p);
51
- return;
52
- }
53
- console.log(`Proposal ${p.proposalId}`);
54
- console.log(` title: ${p.title}`);
55
- console.log(` status: ${p.status}`);
56
- console.log(` priority: ${p.priority}`);
57
- console.log(` revision: ${p.revision}`);
58
- console.log(` session: ${p.sessionId}`);
59
- console.log(` created: ${p.createdAt}`);
60
- console.log("");
61
- console.log("Content:");
62
- console.log(p.content);
63
- if (p.history.length) {
64
- console.log("");
65
- console.log("History:");
66
- for (const h of p.history) {
67
- const detail = h.type === "revise_requested"
68
- ? `: ${h.comment}`
69
- : h.type === "prioritized"
70
- ? `: priority=${h.priority}`
71
- : "";
72
- console.log(` ${h.createdAt} rev${h.revision} ${h.type}${detail}`);
73
- }
74
- }
75
- });
76
- // ── Add ──
77
- proposal
78
- .command("add <title> <content>")
79
- .description("Add a proposal. Pass '-' for content to read from stdin. Requires a chat session — the agent runtime exports GOBI_SESSION_ID automatically; outside that, pass --session.")
80
- .option("--session <sessionId>", "Originating chat session UUID. Falls back to $GOBI_SESSION_ID when set.")
81
- .option("--priority <number>", "Priority (lower = higher), default 100")
82
- .action(async (title, content, opts) => {
83
- const sessionId = opts.session || process.env.GOBI_SESSION_ID || "";
84
- if (!sessionId) {
85
- console.error("Error: missing session id. Pass --session <uuid> or set GOBI_SESSION_ID in the environment.");
86
- process.exit(1);
87
- }
88
- const body = {
89
- title,
90
- content: readContent(content),
91
- sessionId,
92
- };
93
- if (opts.priority)
94
- body.priority = parseInt(opts.priority, 10);
95
- const resp = (await apiPost("/app/proposals", body));
96
- const p = unwrapResp(resp);
97
- if (isJsonMode(proposal)) {
98
- jsonOut(p);
99
- return;
100
- }
101
- console.log(`Created ${p.proposalId} (priority ${p.priority}).`);
102
- });
103
- // ── Edit content ──
104
- proposal
105
- .command("edit <proposalId>")
106
- .description("Replace proposal title and/or content (bumps revision). Pass '-' for stdin.")
107
- .option("--title <title>", "New title")
108
- .option("--content <content>", "New content; pass '-' to read from stdin")
109
- .action(async (proposalId, opts) => {
110
- const body = {};
111
- if (opts.title !== undefined)
112
- body.title = opts.title;
113
- if (opts.content !== undefined)
114
- body.content = readContent(opts.content);
115
- if (Object.keys(body).length === 0) {
116
- console.error('Error: pass --title and/or --content.');
117
- process.exit(1);
118
- }
119
- const resp = (await apiPatch(`/app/proposals/${proposalId}`, body));
120
- const p = unwrapResp(resp);
121
- if (isJsonMode(proposal)) {
122
- jsonOut(p);
123
- return;
124
- }
125
- console.log(`Updated ${p.proposalId} → rev${p.revision}.`);
126
- });
127
- // ── Delete ──
128
- proposal
129
- .command("delete <proposalId>")
130
- .description("Delete a proposal.")
131
- .action(async (proposalId) => {
132
- await apiDelete(`/app/proposals/${proposalId}`);
133
- if (isJsonMode(proposal)) {
134
- jsonOut({ deleted: proposalId });
135
- return;
136
- }
137
- console.log(`Deleted ${proposalId}.`);
138
- });
139
- // ── Prioritize ──
140
- proposal
141
- .command("prioritize <proposalId> <priority>")
142
- .description("Set priority (lower = higher). Top 5 feed the system prompt.")
143
- .action(async (proposalId, priority) => {
144
- const resp = (await apiPatch(`/app/proposals/${proposalId}/priority`, {
145
- priority: parseInt(priority, 10),
146
- }));
147
- const p = unwrapResp(resp);
148
- if (isJsonMode(proposal)) {
149
- jsonOut(p);
150
- return;
151
- }
152
- console.log(`Set ${p.proposalId} priority to ${p.priority}.`);
153
- });
154
- // ── Accept ──
155
- proposal
156
- .command("accept <proposalId>")
157
- .description("Mark the proposal accepted. The client posts the synthesized message into the session.")
158
- .action(async (proposalId) => {
159
- const resp = (await apiPost(`/app/proposals/${proposalId}/accept`));
160
- const p = unwrapResp(resp);
161
- if (isJsonMode(proposal)) {
162
- jsonOut(p);
163
- return;
164
- }
165
- console.log(`Accepted ${p.proposalId}.`);
166
- });
167
- // ── Reject ──
168
- proposal
169
- .command("reject <proposalId>")
170
- .description("Mark the proposal rejected. The client posts the synthesized message into the session.")
171
- .action(async (proposalId) => {
172
- const resp = (await apiPost(`/app/proposals/${proposalId}/reject`));
173
- const p = unwrapResp(resp);
174
- if (isJsonMode(proposal)) {
175
- jsonOut(p);
176
- return;
177
- }
178
- console.log(`Rejected ${p.proposalId}.`);
179
- });
180
- // ── Revise ──
181
- proposal
182
- .command("revise <proposalId> <comment>")
183
- .description("Mark the proposal for revision and record the user's comment. The client posts the synthesized message into the session.")
184
- .action(async (proposalId, comment) => {
185
- const resp = (await apiPost(`/app/proposals/${proposalId}/revise`, {
186
- comment: readContent(comment),
187
- }));
188
- const p = unwrapResp(resp);
189
- if (isJsonMode(proposal)) {
190
- jsonOut(p);
191
- return;
192
- }
193
- console.log(`Revision requested on ${p.proposalId}.`);
194
- });
195
- }
@@ -1,66 +0,0 @@
1
- ---
2
- name: gobi-proposal
3
- description: >-
4
- Gobi proposal commands for managing agent-authored proposals: list, get, add,
5
- edit, delete, prioritize, accept, reject, or revise. The top-priority pending
6
- proposals feed into the agent's system prompt every turn. Use when the user
7
- wants to review, organize, or respond to proposals — or when an agent (using
8
- gobi-cli as its tool layer) wants to record a proposal it just composed.
9
- allowed-tools: Bash(gobi:*)
10
- metadata:
11
- author: gobi-ai
12
- version: "1.3.6"
13
- ---
14
-
15
- # gobi-proposal
16
-
17
- Gobi proposal commands for managing agent-authored proposals (v1.3.6).
18
-
19
- Requires gobi-cli installed and authenticated. See gobi-core skill for setup.
20
-
21
- ## What is a proposal?
22
-
23
- A proposal is a unit of standing guidance authored by an agent (in-process during chat, or via `gobi proposal add` when the agent uses gobi-cli as its tool layer). Each proposal has:
24
-
25
- - **title** — short headline (1–200 chars)
26
- - **content** — the proposal text (markdown, 1–8000 chars)
27
- - **sessionId** — required; the chat session that produced the proposal
28
- - **priority** — lower number = higher priority; default `100`
29
- - **status** — `pending`, `accepted`, or `rejected`
30
- - **revision** — bumped each time the title or content is edited
31
- - **history** — append-only log of `created`, `edited`, `prioritized`, `accepted`, `rejected`, and `revise_requested` events
32
-
33
- The top 5 pending proposals (lowest priority first) are injected into the agent's system prompt every turn — that's how proposals turn into standing instructions.
34
-
35
- When invoked from inside an agent run, the runtime exports `GOBI_SESSION_ID` so `gobi proposal add` picks it up automatically; otherwise pass `--session <uuid>`.
36
-
37
- ## Lifecycle
38
-
39
- `accept`, `reject`, and `revise` update the proposal's status and history. They do **not** themselves post messages into the chat session — the client (e.g. the floating proposal bubble) opens at `proposal.sessionId` and sends the synthesized message via SSE so the user sees the agent's reply stream in. Only pending proposals can be revised.
40
-
41
- ## Important: JSON Mode
42
-
43
- For programmatic/agent usage, always pass `--json` as a **global** option (before the subcommand):
44
-
45
- ```bash
46
- gobi --json proposal list --limit 20
47
- gobi --json proposal add "Concise titles" "Prefer concise titles for brain updates." --priority 50
48
- ```
49
-
50
- JSON mode wraps the response as `{"success": true, "data": <proposal>}` (or `{"success": false, "error": "..."}`).
51
-
52
- ## Available Commands
53
-
54
- - `gobi proposal` — Proposals authored by your agent during chat. Top-5 feed the system prompt; accept/reject/revise post into the originating chat session.
55
- - `gobi proposal list` — List proposals (priority ASC, then newest first).
56
- - `gobi proposal get` — Show one proposal with its history.
57
- - `gobi proposal edit` — Replace proposal content (bumps revision). Pass '-' for stdin.
58
- - `gobi proposal delete` — Delete a proposal.
59
- - `gobi proposal prioritize` — Set priority (lower = higher). Top 5 feed the system prompt.
60
- - `gobi proposal accept` — Accept — posts "Accept your proposal X" into the originating chat session.
61
- - `gobi proposal reject` — Reject — posts "Reject your proposal X" into the originating chat session.
62
- - `gobi proposal revise` — Ask the agent to revise — posts "Update your proposal X. Here's my comment. {comment}" into the chat session.
63
-
64
- ## Reference Documentation
65
-
66
- - [gobi proposal](references/proposal.md)
@@ -1,127 +0,0 @@
1
- # gobi proposal
2
-
3
- ```
4
- Usage: gobi proposal [options] [command]
5
-
6
- Proposals authored by your agent during chat. Top-5 feed the system prompt; accept/reject/revise update state and the client posts the synthesized message into the session.
7
-
8
- Options:
9
- -h, --help display help for command
10
-
11
- Commands:
12
- list [options] List proposals (priority ASC, then newest first).
13
- get <proposalId> Show one proposal with its history.
14
- add [options] <title> <content> Add a proposal. Pass '-' for content to read from stdin. Requires a chat session — the agent runtime exports GOBI_SESSION_ID automatically; outside that, pass
15
- --session.
16
- edit [options] <proposalId> Replace proposal title and/or content (bumps revision). Pass '-' for stdin.
17
- delete <proposalId> Delete a proposal.
18
- prioritize <proposalId> <priority> Set priority (lower = higher). Top 5 feed the system prompt.
19
- accept <proposalId> Mark the proposal accepted. The client posts the synthesized message into the session.
20
- reject <proposalId> Mark the proposal rejected. The client posts the synthesized message into the session.
21
- revise <proposalId> <comment> Mark the proposal for revision and record the user's comment. The client posts the synthesized message into the session.
22
- help [command] display help for command
23
- ```
24
-
25
- ## list
26
-
27
- ```
28
- Usage: gobi proposal list [options]
29
-
30
- List proposals (priority ASC, then newest first).
31
-
32
- Options:
33
- --limit <number> Max proposals to return (1-200) (default: "50")
34
- -h, --help display help for command
35
- ```
36
-
37
- ## get
38
-
39
- ```
40
- Usage: gobi proposal get [options] <proposalId>
41
-
42
- Show one proposal with its history.
43
-
44
- Options:
45
- -h, --help display help for command
46
- ```
47
-
48
- ## add
49
-
50
- ```
51
- Usage: gobi proposal add [options] <title> <content>
52
-
53
- Add a proposal. Pass '-' for content to read from stdin. Requires a chat session — the agent runtime exports GOBI_SESSION_ID automatically; outside that, pass --session.
54
-
55
- Options:
56
- --session <sessionId> Originating chat session UUID. Falls back to $GOBI_SESSION_ID when set.
57
- --priority <number> Priority (lower = higher), default 100
58
- -h, --help display help for command
59
- ```
60
-
61
- ## edit
62
-
63
- ```
64
- Usage: gobi proposal edit [options] <proposalId>
65
-
66
- Replace proposal title and/or content (bumps revision). Pass '-' for stdin.
67
-
68
- Options:
69
- --title <title> New title
70
- --content <content> New content; pass '-' to read from stdin
71
- -h, --help display help for command
72
- ```
73
-
74
- ## delete
75
-
76
- ```
77
- Usage: gobi proposal delete [options] <proposalId>
78
-
79
- Delete a proposal.
80
-
81
- Options:
82
- -h, --help display help for command
83
- ```
84
-
85
- ## prioritize
86
-
87
- ```
88
- Usage: gobi proposal prioritize [options] <proposalId> <priority>
89
-
90
- Set priority (lower = higher). Top 5 feed the system prompt.
91
-
92
- Options:
93
- -h, --help display help for command
94
- ```
95
-
96
- ## accept
97
-
98
- ```
99
- Usage: gobi proposal accept [options] <proposalId>
100
-
101
- Mark the proposal accepted. The client posts the synthesized message into the session.
102
-
103
- Options:
104
- -h, --help display help for command
105
- ```
106
-
107
- ## reject
108
-
109
- ```
110
- Usage: gobi proposal reject [options] <proposalId>
111
-
112
- Mark the proposal rejected. The client posts the synthesized message into the session.
113
-
114
- Options:
115
- -h, --help display help for command
116
- ```
117
-
118
- ## revise
119
-
120
- ```
121
- Usage: gobi proposal revise [options] <proposalId> <comment>
122
-
123
- Mark the proposal for revision and record the user's comment. The client posts the synthesized message into the session.
124
-
125
- Options:
126
- -h, --help display help for command
127
- ```