@gobi-ai/cli 1.3.4 → 1.3.6
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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +27 -13
- package/dist/commands/brain.js +3 -78
- package/dist/commands/global.js +203 -0
- package/dist/commands/proposal.js +36 -19
- package/dist/commands/space.js +89 -1
- package/dist/main.js +2 -0
- package/package.json +1 -1
- package/skills/gobi-brain/SKILL.md +7 -10
- package/skills/gobi-brain/references/brain.md +7 -51
- package/skills/gobi-core/references/space.md +4 -1
- package/skills/gobi-proposal/SKILL.md +10 -7
- package/skills/gobi-proposal/references/proposal.md +18 -15
- package/skills/gobi-space/SKILL.md +31 -6
- package/skills/gobi-space/references/global.md +82 -0
- package/skills/gobi-space/references/space.md +39 -1
|
@@ -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.
|
|
7
|
+
"version": "1.3.6",
|
|
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.
|
|
12
|
+
"version": "1.3.6",
|
|
13
13
|
"author": {
|
|
14
14
|
"name": "gobi-ai"
|
|
15
15
|
},
|
package/README.md
CHANGED
|
@@ -78,15 +78,15 @@ Public brains are accessible at `https://gobispace.com/@{vaultSlug}`.
|
|
|
78
78
|
|
|
79
79
|
`brain ask` also accepts `--rich-text <json>` (mutually exclusive with `--question`) and `--mode <auto|manual>`.
|
|
80
80
|
|
|
81
|
-
###
|
|
81
|
+
### Spaces
|
|
82
|
+
|
|
83
|
+
> Space and member administration (creating spaces, inviting/approving members, joining/leaving) is web-UI only and not available in the CLI.
|
|
82
84
|
|
|
83
85
|
| Command | Description |
|
|
84
86
|
|---------|-------------|
|
|
85
|
-
| `gobi
|
|
86
|
-
| `gobi
|
|
87
|
-
| `gobi
|
|
88
|
-
|
|
89
|
-
`post-update` and `edit-update` accept `--auto-attachments` to upload wiki-linked `[[files]]` before posting.
|
|
87
|
+
| `gobi space get [spaceSlug]` | Show space details (uses current space if slug omitted) |
|
|
88
|
+
| `gobi space messages` | Unified message feed (threads + replies, newest first) |
|
|
89
|
+
| `gobi space ancestors <threadId>` | Walk a thread/reply's lineage from root → immediate parent |
|
|
90
90
|
|
|
91
91
|
### Feed
|
|
92
92
|
|
|
@@ -102,6 +102,8 @@ Public brains are accessible at `https://gobispace.com/@{vaultSlug}`.
|
|
|
102
102
|
|
|
103
103
|
### Threads
|
|
104
104
|
|
|
105
|
+
> **Migration note:** Brain-update commands have been removed. To post user-level content, use `gobi global create-thread` (global space) or `gobi space create-thread` (a specific space).
|
|
106
|
+
|
|
105
107
|
| Command | Description |
|
|
106
108
|
|---------|-------------|
|
|
107
109
|
| `gobi space list-threads` | List threads in the current space |
|
|
@@ -118,6 +120,18 @@ Public brains are accessible at `https://gobispace.com/@{vaultSlug}`.
|
|
|
118
120
|
| `gobi space edit-reply <replyId> --content <c>` | Edit a reply |
|
|
119
121
|
| `gobi space delete-reply <replyId>` | Delete a reply |
|
|
120
122
|
|
|
123
|
+
### Global thread space
|
|
124
|
+
|
|
125
|
+
The global thread space is a slugless message feed visible across all spaces.
|
|
126
|
+
|
|
127
|
+
| Command | Description |
|
|
128
|
+
|---------|-------------|
|
|
129
|
+
| `gobi global messages` | List the global unified message feed (newest first) |
|
|
130
|
+
| `gobi global get-thread <id>` | Get a global thread and its direct replies |
|
|
131
|
+
| `gobi global ancestors <id>` | Walk a global thread/reply's lineage |
|
|
132
|
+
| `gobi global create-thread [--title <t>] (--content <c> \| --rich-text <json>)` | Create a thread in the global space |
|
|
133
|
+
| `gobi global reply <threadId> (--content <c> \| --rich-text <json>)` | Reply to a global thread |
|
|
134
|
+
|
|
121
135
|
### Sessions
|
|
122
136
|
|
|
123
137
|
| Command | Description |
|
|
@@ -152,19 +166,19 @@ Times are ISO 8601 UTC (e.g. `2026-03-20T00:00:00Z`).
|
|
|
152
166
|
|
|
153
167
|
### Proposals
|
|
154
168
|
|
|
155
|
-
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.
|
|
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.
|
|
156
170
|
|
|
157
171
|
| Command | Description |
|
|
158
172
|
|---------|-------------|
|
|
159
173
|
| `gobi proposal list [--limit N]` | List proposals (priority ASC, then newest first) |
|
|
160
174
|
| `gobi proposal get <id>` | Show one proposal with its history |
|
|
161
|
-
| `gobi proposal add <content> [--session <id>] [--priority N]` | Add a proposal (use `-` for stdin) |
|
|
162
|
-
| `gobi proposal edit <id> <content
|
|
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) |
|
|
163
177
|
| `gobi proposal delete <id>` | Delete a proposal |
|
|
164
178
|
| `gobi proposal prioritize <id> <priority>` | Set priority (lower = higher) |
|
|
165
|
-
| `gobi proposal accept <id>` |
|
|
166
|
-
| `gobi proposal reject <id>` |
|
|
167
|
-
| `gobi proposal revise <id> <comment>` |
|
|
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 |
|
|
168
182
|
|
|
169
183
|
### Sync
|
|
170
184
|
|
|
@@ -191,7 +205,7 @@ Proposals are authored by your agent during chat (or by external agents using `g
|
|
|
191
205
|
|--------|-------|-------------|
|
|
192
206
|
| `--json` | All commands | Output results as JSON |
|
|
193
207
|
| `--space-slug <slug>` | `space` commands | Override the default space (from `.gobi/settings.yaml`) |
|
|
194
|
-
| `--vault-slug <slug>` | Per-command | Override the default vault; available on `
|
|
208
|
+
| `--vault-slug <slug>` | Per-command | Override the default vault; available on `space create-thread`, `space edit-thread`, `space edit-reply` |
|
|
195
209
|
|
|
196
210
|
## Configuration
|
|
197
211
|
|
package/dist/commands/brain.js
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "fs";
|
|
2
2
|
import { join } from "path";
|
|
3
|
-
import { apiGet, apiPost
|
|
3
|
+
import { apiGet, apiPost } from "../client.js";
|
|
4
4
|
import { WEBDRIVE_BASE_URL } from "../constants.js";
|
|
5
5
|
import { getValidToken } from "../auth/manager.js";
|
|
6
6
|
import { getVaultSlug } from "./init.js";
|
|
7
|
-
import { isJsonMode, jsonOut,
|
|
8
|
-
import { extractWikiLinks, uploadAttachments } from "../attachments.js";
|
|
7
|
+
import { isJsonMode, jsonOut, unwrapResp } from "./utils.js";
|
|
9
8
|
export function registerBrainCommand(program) {
|
|
10
9
|
const brain = program
|
|
11
10
|
.command("brain")
|
|
12
|
-
.description("Brain commands (search, ask, publish, unpublish
|
|
11
|
+
.description("Brain commands (search, ask, publish, unpublish).");
|
|
13
12
|
// ── Search ──
|
|
14
13
|
brain
|
|
15
14
|
.command("search")
|
|
@@ -139,78 +138,4 @@ export function registerBrainCommand(program) {
|
|
|
139
138
|
}
|
|
140
139
|
console.log(`Deleted BRAIN.md from vault "${vaultId}"`);
|
|
141
140
|
});
|
|
142
|
-
// ── Updates (post, edit, delete) ──
|
|
143
|
-
brain
|
|
144
|
-
.command("post-update")
|
|
145
|
-
.description("Post a brain update for a vault.")
|
|
146
|
-
.option("--vault-slug <vaultSlug>", "Vault slug (overrides .gobi/settings.yaml)")
|
|
147
|
-
.requiredOption("--title <title>", "Title of the update")
|
|
148
|
-
.requiredOption("--content <content>", "Update content (markdown supported)")
|
|
149
|
-
.option("--auto-attachments", "Upload wiki-linked [[files]] to webdrive before posting")
|
|
150
|
-
.action(async (opts) => {
|
|
151
|
-
const vaultSlug = resolveVaultSlug(opts);
|
|
152
|
-
if (opts.autoAttachments) {
|
|
153
|
-
const token = await getValidToken();
|
|
154
|
-
const links = extractWikiLinks(opts.content);
|
|
155
|
-
await uploadAttachments(vaultSlug, links, token, { addToSyncfiles: true });
|
|
156
|
-
}
|
|
157
|
-
const resp = (await apiPost(`/brain-updates/vault/${vaultSlug}`, {
|
|
158
|
-
title: opts.title,
|
|
159
|
-
content: opts.content,
|
|
160
|
-
}));
|
|
161
|
-
const u = unwrapResp(resp);
|
|
162
|
-
if (isJsonMode(brain)) {
|
|
163
|
-
jsonOut(u);
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
console.log(`Brain update posted!\n` +
|
|
167
|
-
` ID: ${u.id}\n` +
|
|
168
|
-
` Title: ${u.title}\n` +
|
|
169
|
-
` Vault: ${u.vaultSlug || vaultSlug}\n` +
|
|
170
|
-
` Created: ${u.createdAt}`);
|
|
171
|
-
});
|
|
172
|
-
brain
|
|
173
|
-
.command("edit-update <updateId>")
|
|
174
|
-
.description("Edit a published brain update. You must be the author.")
|
|
175
|
-
.option("--title <title>", "New title for the update")
|
|
176
|
-
.option("--content <content>", "New content for the update (markdown supported)")
|
|
177
|
-
.option("--vault-slug <vaultSlug>", "Vault slug for attachment uploads (overrides .gobi/settings.yaml)")
|
|
178
|
-
.option("--auto-attachments", "Upload wiki-linked [[files]] to webdrive before editing")
|
|
179
|
-
.action(async (updateId, opts) => {
|
|
180
|
-
if (!opts.title && !opts.content) {
|
|
181
|
-
throw new Error("Provide at least --title or --content to update.");
|
|
182
|
-
}
|
|
183
|
-
if (opts.autoAttachments && opts.content) {
|
|
184
|
-
const vaultSlug = resolveVaultSlug(opts);
|
|
185
|
-
const token = await getValidToken();
|
|
186
|
-
const links = extractWikiLinks(opts.content);
|
|
187
|
-
await uploadAttachments(vaultSlug, links, token, { addToSyncfiles: true });
|
|
188
|
-
}
|
|
189
|
-
const body = {};
|
|
190
|
-
if (opts.title != null)
|
|
191
|
-
body.title = opts.title;
|
|
192
|
-
if (opts.content != null)
|
|
193
|
-
body.content = opts.content;
|
|
194
|
-
const resp = (await apiPatch(`/brain-updates/${updateId}`, body));
|
|
195
|
-
const u = unwrapResp(resp);
|
|
196
|
-
if (isJsonMode(brain)) {
|
|
197
|
-
jsonOut(u);
|
|
198
|
-
return;
|
|
199
|
-
}
|
|
200
|
-
console.log(`Brain update edited!\n` +
|
|
201
|
-
` ID: ${u.id}\n` +
|
|
202
|
-
` Title: ${u.title}\n` +
|
|
203
|
-
` Updated: ${u.updatedAt}`);
|
|
204
|
-
});
|
|
205
|
-
brain
|
|
206
|
-
.command("delete-update <updateId>")
|
|
207
|
-
.description("Delete a published brain update. You must be the author.")
|
|
208
|
-
.action(async (updateId) => {
|
|
209
|
-
await apiDelete(`/brain-updates/${updateId}`);
|
|
210
|
-
if (isJsonMode(brain)) {
|
|
211
|
-
jsonOut({ id: updateId });
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
console.log(`Brain update ${updateId} deleted.`);
|
|
215
|
-
});
|
|
216
141
|
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { readFileSync } from "fs";
|
|
2
|
+
import { apiGet, 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 formatMessageLine(m) {
|
|
10
|
+
const isReply = m.parentThreadId != null;
|
|
11
|
+
const id = `[${isReply ? "r" : "t"}:${m.id}]`;
|
|
12
|
+
const kind = isReply ? "reply " : "thread";
|
|
13
|
+
const author = m.author?.name ||
|
|
14
|
+
`User ${m.authorId ?? "?"}`;
|
|
15
|
+
let label;
|
|
16
|
+
if (isReply) {
|
|
17
|
+
const text = m.content || "";
|
|
18
|
+
label = text.length > 80 ? text.slice(0, 80) + "…" : text;
|
|
19
|
+
label = label.replace(/\s+/g, " ").trim();
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
label = m.title || m.content || "";
|
|
23
|
+
}
|
|
24
|
+
return `${id} ${kind} ${author} "${label}" ${m.createdAt}`;
|
|
25
|
+
}
|
|
26
|
+
export function registerGlobalCommand(program) {
|
|
27
|
+
const global = program
|
|
28
|
+
.command("global")
|
|
29
|
+
.description("Global thread space commands (no slug; visible across all spaces).");
|
|
30
|
+
// ── Messages (unified feed) ──
|
|
31
|
+
global
|
|
32
|
+
.command("messages")
|
|
33
|
+
.description("List the global unified message feed (threads and replies, newest first).")
|
|
34
|
+
.option("--limit <number>", "Items per page", "20")
|
|
35
|
+
.option("--cursor <string>", "Pagination cursor from previous response")
|
|
36
|
+
.action(async (opts) => {
|
|
37
|
+
const params = {
|
|
38
|
+
limit: parseInt(opts.limit, 10),
|
|
39
|
+
};
|
|
40
|
+
if (opts.cursor)
|
|
41
|
+
params.cursor = opts.cursor;
|
|
42
|
+
const resp = (await apiGet(`/global/messages`, params));
|
|
43
|
+
if (isJsonMode(global)) {
|
|
44
|
+
jsonOut({
|
|
45
|
+
items: resp.data || [],
|
|
46
|
+
pagination: resp.pagination || {},
|
|
47
|
+
});
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const items = (resp.data || []);
|
|
51
|
+
const pagination = (resp.pagination || {});
|
|
52
|
+
if (!items.length) {
|
|
53
|
+
console.log("No messages found.");
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const lines = items.map(formatMessageLine);
|
|
57
|
+
const footer = pagination.hasMore ? `\n Next cursor: ${pagination.nextCursor}` : "";
|
|
58
|
+
console.log(`Global messages (${items.length} items, newest first):\n` + lines.join("\n") + footer);
|
|
59
|
+
});
|
|
60
|
+
// ── Get thread ──
|
|
61
|
+
global
|
|
62
|
+
.command("get-thread <threadId>")
|
|
63
|
+
.description("Get a global thread and its direct replies (paginated).")
|
|
64
|
+
.option("--limit <number>", "Replies per page", "20")
|
|
65
|
+
.option("--cursor <string>", "Pagination cursor from previous response")
|
|
66
|
+
.action(async (threadId, opts) => {
|
|
67
|
+
const params = {
|
|
68
|
+
limit: parseInt(opts.limit, 10),
|
|
69
|
+
};
|
|
70
|
+
if (opts.cursor)
|
|
71
|
+
params.cursor = opts.cursor;
|
|
72
|
+
const resp = (await apiGet(`/global/threads/${threadId}`, params));
|
|
73
|
+
const data = unwrapResp(resp);
|
|
74
|
+
const pagination = (resp.pagination || {});
|
|
75
|
+
if (isJsonMode(global)) {
|
|
76
|
+
jsonOut({ ...data, pagination });
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const thread = (data.thread || data);
|
|
80
|
+
const replies = (data.items || []);
|
|
81
|
+
const author = thread.author?.name ||
|
|
82
|
+
`User ${thread.authorId}`;
|
|
83
|
+
const replyLines = [];
|
|
84
|
+
for (const r of replies) {
|
|
85
|
+
const rAuthor = r.author?.name ||
|
|
86
|
+
`User ${r.authorId}`;
|
|
87
|
+
const text = r.content || "";
|
|
88
|
+
const truncated = text.length > 200 ? text.slice(0, 200) + "…" : text;
|
|
89
|
+
replyLines.push(` - ${rAuthor}: ${truncated} (${r.createdAt})`);
|
|
90
|
+
}
|
|
91
|
+
const isReply = thread.parentThreadId != null;
|
|
92
|
+
const heading = isReply
|
|
93
|
+
? `Reply [r:${thread.id}]`
|
|
94
|
+
: `Thread: ${thread.title || "(no title)"}`;
|
|
95
|
+
const output = [
|
|
96
|
+
heading,
|
|
97
|
+
`By: ${author} on ${thread.createdAt}`,
|
|
98
|
+
"",
|
|
99
|
+
thread.content,
|
|
100
|
+
"",
|
|
101
|
+
`Replies (${replies.length} items):`,
|
|
102
|
+
...replyLines,
|
|
103
|
+
...(pagination.hasMore ? [` Next cursor: ${pagination.nextCursor}`] : []),
|
|
104
|
+
].join("\n");
|
|
105
|
+
console.log(output);
|
|
106
|
+
});
|
|
107
|
+
// ── Ancestors ──
|
|
108
|
+
global
|
|
109
|
+
.command("ancestors <threadId>")
|
|
110
|
+
.description("Show the ancestor lineage of a global thread or reply (root → immediate parent).")
|
|
111
|
+
.action(async (threadId) => {
|
|
112
|
+
const resp = (await apiGet(`/global/threads/${threadId}/ancestors`));
|
|
113
|
+
const data = unwrapResp(resp);
|
|
114
|
+
const ancestors = (data.ancestors || []);
|
|
115
|
+
if (isJsonMode(global)) {
|
|
116
|
+
jsonOut({ ancestors });
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
if (!ancestors.length) {
|
|
120
|
+
console.log("No ancestors (this is a root thread).");
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const lines = [];
|
|
124
|
+
ancestors.forEach((a, i) => {
|
|
125
|
+
lines.push(`${i + 1}. ${formatMessageLine(a)}`);
|
|
126
|
+
});
|
|
127
|
+
console.log(`Ancestors (${ancestors.length} items, root first):\n` + lines.join("\n"));
|
|
128
|
+
});
|
|
129
|
+
// ── Create thread ──
|
|
130
|
+
global
|
|
131
|
+
.command("create-thread")
|
|
132
|
+
.description("Create a thread in the global space.")
|
|
133
|
+
.option("--title <title>", "Title of the thread")
|
|
134
|
+
.option("--content <content>", "Thread content (markdown supported, use \"-\" for stdin)")
|
|
135
|
+
.option("--rich-text <richText>", "Rich-text JSON array (mutually exclusive with --content)")
|
|
136
|
+
.action(async (opts) => {
|
|
137
|
+
if (!opts.content && !opts.richText) {
|
|
138
|
+
throw new Error("Provide either --content or --rich-text.");
|
|
139
|
+
}
|
|
140
|
+
if (opts.content && opts.richText) {
|
|
141
|
+
throw new Error("--content and --rich-text are mutually exclusive.");
|
|
142
|
+
}
|
|
143
|
+
const body = {};
|
|
144
|
+
if (opts.title != null)
|
|
145
|
+
body.title = opts.title;
|
|
146
|
+
if (opts.content != null)
|
|
147
|
+
body.content = readContent(opts.content);
|
|
148
|
+
if (opts.richText != null) {
|
|
149
|
+
let parsed;
|
|
150
|
+
try {
|
|
151
|
+
parsed = JSON.parse(opts.richText);
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
throw new Error("Invalid --rich-text JSON.");
|
|
155
|
+
}
|
|
156
|
+
body.richText = parsed;
|
|
157
|
+
}
|
|
158
|
+
const resp = (await apiPost(`/global/threads`, body));
|
|
159
|
+
const thread = unwrapResp(resp);
|
|
160
|
+
if (isJsonMode(global)) {
|
|
161
|
+
jsonOut(thread);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
console.log(`Global thread created!\n` +
|
|
165
|
+
` ID: ${thread.id}\n` +
|
|
166
|
+
(thread.title ? ` Title: ${thread.title}\n` : "") +
|
|
167
|
+
` Created: ${thread.createdAt}`);
|
|
168
|
+
});
|
|
169
|
+
// ── Reply ──
|
|
170
|
+
global
|
|
171
|
+
.command("reply <threadId>")
|
|
172
|
+
.description("Reply to a thread in the global space.")
|
|
173
|
+
.option("--content <content>", "Reply content (markdown supported, use \"-\" for stdin)")
|
|
174
|
+
.option("--rich-text <richText>", "Rich-text JSON array (mutually exclusive with --content)")
|
|
175
|
+
.action(async (threadId, opts) => {
|
|
176
|
+
if (!opts.content && !opts.richText) {
|
|
177
|
+
throw new Error("Provide either --content or --rich-text.");
|
|
178
|
+
}
|
|
179
|
+
if (opts.content && opts.richText) {
|
|
180
|
+
throw new Error("--content and --rich-text are mutually exclusive.");
|
|
181
|
+
}
|
|
182
|
+
const body = {};
|
|
183
|
+
if (opts.content != null)
|
|
184
|
+
body.content = readContent(opts.content);
|
|
185
|
+
if (opts.richText != null) {
|
|
186
|
+
let parsed;
|
|
187
|
+
try {
|
|
188
|
+
parsed = JSON.parse(opts.richText);
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
throw new Error("Invalid --rich-text JSON.");
|
|
192
|
+
}
|
|
193
|
+
body.richText = parsed;
|
|
194
|
+
}
|
|
195
|
+
const resp = (await apiPost(`/global/threads/${threadId}/replies`, body));
|
|
196
|
+
const reply = unwrapResp(resp);
|
|
197
|
+
if (isJsonMode(global)) {
|
|
198
|
+
jsonOut(reply);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
console.log(`Reply created!\n ID: ${reply.id}\n Created: ${reply.createdAt}`);
|
|
202
|
+
});
|
|
203
|
+
}
|
|
@@ -12,12 +12,12 @@ function snippet(content, max = 80) {
|
|
|
12
12
|
}
|
|
13
13
|
function formatProposalLine(p) {
|
|
14
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.
|
|
15
|
+
return `- [${status}] p${p.priority} rev${p.revision} ${p.proposalId.slice(0, 8)} ${snippet(p.title)}`;
|
|
16
16
|
}
|
|
17
17
|
export function registerProposalCommand(program) {
|
|
18
18
|
const proposal = program
|
|
19
19
|
.command("proposal")
|
|
20
|
-
.description("Proposals authored by your agent during chat. Top-5 feed the system prompt; accept/reject/revise
|
|
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
21
|
// ── List ──
|
|
22
22
|
proposal
|
|
23
23
|
.command("list")
|
|
@@ -51,10 +51,11 @@ export function registerProposalCommand(program) {
|
|
|
51
51
|
return;
|
|
52
52
|
}
|
|
53
53
|
console.log(`Proposal ${p.proposalId}`);
|
|
54
|
+
console.log(` title: ${p.title}`);
|
|
54
55
|
console.log(` status: ${p.status}`);
|
|
55
56
|
console.log(` priority: ${p.priority}`);
|
|
56
57
|
console.log(` revision: ${p.revision}`);
|
|
57
|
-
console.log(` session: ${p.sessionId
|
|
58
|
+
console.log(` session: ${p.sessionId}`);
|
|
58
59
|
console.log(` created: ${p.createdAt}`);
|
|
59
60
|
console.log("");
|
|
60
61
|
console.log("Content:");
|
|
@@ -74,14 +75,21 @@ export function registerProposalCommand(program) {
|
|
|
74
75
|
});
|
|
75
76
|
// ── Add ──
|
|
76
77
|
proposal
|
|
77
|
-
.command("add <content>")
|
|
78
|
-
.description("Add a proposal
|
|
79
|
-
.option("--session <sessionId>", "
|
|
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.")
|
|
80
81
|
.option("--priority <number>", "Priority (lower = higher), default 100")
|
|
81
|
-
.action(async (content, opts) => {
|
|
82
|
-
const
|
|
83
|
-
if (
|
|
84
|
-
|
|
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
|
+
};
|
|
85
93
|
if (opts.priority)
|
|
86
94
|
body.priority = parseInt(opts.priority, 10);
|
|
87
95
|
const resp = (await apiPost("/app/proposals", body));
|
|
@@ -94,12 +102,21 @@ export function registerProposalCommand(program) {
|
|
|
94
102
|
});
|
|
95
103
|
// ── Edit content ──
|
|
96
104
|
proposal
|
|
97
|
-
.command("edit <proposalId>
|
|
98
|
-
.description("Replace proposal content (bumps revision). Pass '-' for stdin.")
|
|
99
|
-
.
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
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));
|
|
103
120
|
const p = unwrapResp(resp);
|
|
104
121
|
if (isJsonMode(proposal)) {
|
|
105
122
|
jsonOut(p);
|
|
@@ -137,7 +154,7 @@ export function registerProposalCommand(program) {
|
|
|
137
154
|
// ── Accept ──
|
|
138
155
|
proposal
|
|
139
156
|
.command("accept <proposalId>")
|
|
140
|
-
.description(
|
|
157
|
+
.description("Mark the proposal accepted. The client posts the synthesized message into the session.")
|
|
141
158
|
.action(async (proposalId) => {
|
|
142
159
|
const resp = (await apiPost(`/app/proposals/${proposalId}/accept`));
|
|
143
160
|
const p = unwrapResp(resp);
|
|
@@ -150,7 +167,7 @@ export function registerProposalCommand(program) {
|
|
|
150
167
|
// ── Reject ──
|
|
151
168
|
proposal
|
|
152
169
|
.command("reject <proposalId>")
|
|
153
|
-
.description(
|
|
170
|
+
.description("Mark the proposal rejected. The client posts the synthesized message into the session.")
|
|
154
171
|
.action(async (proposalId) => {
|
|
155
172
|
const resp = (await apiPost(`/app/proposals/${proposalId}/reject`));
|
|
156
173
|
const p = unwrapResp(resp);
|
|
@@ -163,7 +180,7 @@ export function registerProposalCommand(program) {
|
|
|
163
180
|
// ── Revise ──
|
|
164
181
|
proposal
|
|
165
182
|
.command("revise <proposalId> <comment>")
|
|
166
|
-
.description(
|
|
183
|
+
.description("Mark the proposal for revision and record the user's comment. The client posts the synthesized message into the session.")
|
|
167
184
|
.action(async (proposalId, comment) => {
|
|
168
185
|
const resp = (await apiPost(`/app/proposals/${proposalId}/revise`, {
|
|
169
186
|
comment: readContent(comment),
|
package/dist/commands/space.js
CHANGED
|
@@ -9,10 +9,27 @@ function readContent(value) {
|
|
|
9
9
|
return readFileSync("/dev/stdin", "utf8");
|
|
10
10
|
return value;
|
|
11
11
|
}
|
|
12
|
+
function formatMessageLine(m) {
|
|
13
|
+
const isReply = m.parentThreadId != null;
|
|
14
|
+
const id = `[${isReply ? "r" : "t"}:${m.id}]`;
|
|
15
|
+
const kind = isReply ? "reply " : "thread";
|
|
16
|
+
const author = m.author?.name ||
|
|
17
|
+
`User ${m.authorId ?? "?"}`;
|
|
18
|
+
let label;
|
|
19
|
+
if (isReply) {
|
|
20
|
+
const text = m.content || "";
|
|
21
|
+
label = text.length > 80 ? text.slice(0, 80) + "…" : text;
|
|
22
|
+
label = label.replace(/\s+/g, " ").trim();
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
label = m.title || m.content || "";
|
|
26
|
+
}
|
|
27
|
+
return `${id} ${kind} ${author} "${label}" ${m.createdAt}`;
|
|
28
|
+
}
|
|
12
29
|
export function registerSpaceCommand(program) {
|
|
13
30
|
const space = program
|
|
14
31
|
.command("space")
|
|
15
|
-
.description("Space commands (threads, replies).")
|
|
32
|
+
.description("Space commands (threads, replies). Space and member admin is web-UI only.")
|
|
16
33
|
.option("--space-slug <slug>", "Space slug (overrides .gobi/settings.yaml)");
|
|
17
34
|
// ── List spaces ──
|
|
18
35
|
space
|
|
@@ -36,6 +53,23 @@ export function registerSpaceCommand(program) {
|
|
|
36
53
|
}
|
|
37
54
|
console.log(`Spaces (${items.length}):\n` + lines.join("\n"));
|
|
38
55
|
});
|
|
56
|
+
// ── Get space ──
|
|
57
|
+
space
|
|
58
|
+
.command("get [spaceSlug]")
|
|
59
|
+
.description("Get details for a space. Pass a slug or omit to use the current space (from .gobi/settings.yaml or --space-slug).")
|
|
60
|
+
.action(async (spaceSlug) => {
|
|
61
|
+
const slug = spaceSlug || resolveSpaceSlug(space);
|
|
62
|
+
const resp = (await apiGet(`/spaces/${slug}`));
|
|
63
|
+
const s = unwrapResp(resp);
|
|
64
|
+
if (isJsonMode(space)) {
|
|
65
|
+
jsonOut(s);
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const desc = s.description ? `\n Description: ${s.description}` : "";
|
|
69
|
+
console.log(`Space [${s.slug}] ${s.name}${desc}\n` +
|
|
70
|
+
` ID: ${s.id}\n` +
|
|
71
|
+
` Created: ${s.createdAt}`);
|
|
72
|
+
});
|
|
39
73
|
// ── Warp (space selection) ──
|
|
40
74
|
space
|
|
41
75
|
.command("warp [spaceSlug]")
|
|
@@ -126,6 +160,60 @@ export function registerSpaceCommand(program) {
|
|
|
126
160
|
lines.join("\n") +
|
|
127
161
|
footer);
|
|
128
162
|
});
|
|
163
|
+
// ── Messages (unified feed) ──
|
|
164
|
+
space
|
|
165
|
+
.command("messages")
|
|
166
|
+
.description("List the unified message feed (threads and replies, newest first) in a space.")
|
|
167
|
+
.option("--limit <number>", "Items per page", "20")
|
|
168
|
+
.option("--cursor <string>", "Pagination cursor from previous response")
|
|
169
|
+
.action(async (opts) => {
|
|
170
|
+
const spaceSlug = resolveSpaceSlug(space);
|
|
171
|
+
const params = {
|
|
172
|
+
limit: parseInt(opts.limit, 10),
|
|
173
|
+
};
|
|
174
|
+
if (opts.cursor)
|
|
175
|
+
params.cursor = opts.cursor;
|
|
176
|
+
const resp = (await apiGet(`/spaces/${spaceSlug}/messages`, params));
|
|
177
|
+
if (isJsonMode(space)) {
|
|
178
|
+
jsonOut({
|
|
179
|
+
items: resp.data || [],
|
|
180
|
+
pagination: resp.pagination || {},
|
|
181
|
+
});
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const items = (resp.data || []);
|
|
185
|
+
const pagination = (resp.pagination || {});
|
|
186
|
+
if (!items.length) {
|
|
187
|
+
console.log("No messages found.");
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const lines = items.map(formatMessageLine);
|
|
191
|
+
const footer = pagination.hasMore ? `\n Next cursor: ${pagination.nextCursor}` : "";
|
|
192
|
+
console.log(`Messages (${items.length} items, newest first):\n` + lines.join("\n") + footer);
|
|
193
|
+
});
|
|
194
|
+
// ── Ancestors ──
|
|
195
|
+
space
|
|
196
|
+
.command("ancestors <threadId>")
|
|
197
|
+
.description("Show the ancestor lineage of a thread or reply (root → immediate parent).")
|
|
198
|
+
.action(async (threadId) => {
|
|
199
|
+
const spaceSlug = resolveSpaceSlug(space);
|
|
200
|
+
const resp = (await apiGet(`/spaces/${spaceSlug}/threads/${threadId}/ancestors`));
|
|
201
|
+
const data = unwrapResp(resp);
|
|
202
|
+
const ancestors = (data.ancestors || []);
|
|
203
|
+
if (isJsonMode(space)) {
|
|
204
|
+
jsonOut({ ancestors });
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
if (!ancestors.length) {
|
|
208
|
+
console.log("No ancestors (this is a root thread).");
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
const lines = [];
|
|
212
|
+
ancestors.forEach((a, i) => {
|
|
213
|
+
lines.push(`${i + 1}. ${formatMessageLine(a)}`);
|
|
214
|
+
});
|
|
215
|
+
console.log(`Ancestors (${ancestors.length} items, root first):\n` + lines.join("\n"));
|
|
216
|
+
});
|
|
129
217
|
// ── Threads (get, list, create, edit, delete) ──
|
|
130
218
|
space
|
|
131
219
|
.command("get-thread <threadId>")
|
package/dist/main.js
CHANGED
|
@@ -5,6 +5,7 @@ import { ApiError, GobiError } from "./errors.js";
|
|
|
5
5
|
import { registerAuthCommand } from "./commands/auth.js";
|
|
6
6
|
import { registerInitCommand, printContext } from "./commands/init.js";
|
|
7
7
|
import { registerSpaceCommand } from "./commands/space.js";
|
|
8
|
+
import { registerGlobalCommand } from "./commands/global.js";
|
|
8
9
|
import { registerBrainCommand } from "./commands/brain.js";
|
|
9
10
|
import { registerFeedCommand } from "./commands/feed.js";
|
|
10
11
|
import { registerNotesCommand } from "./commands/notes.js";
|
|
@@ -35,6 +36,7 @@ export async function cli() {
|
|
|
35
36
|
registerAuthCommand(program);
|
|
36
37
|
registerInitCommand(program);
|
|
37
38
|
registerSpaceCommand(program);
|
|
39
|
+
registerGlobalCommand(program);
|
|
38
40
|
registerBrainCommand(program);
|
|
39
41
|
registerFeedCommand(program);
|
|
40
42
|
registerNotesCommand(program);
|
package/package.json
CHANGED
|
@@ -2,20 +2,18 @@
|
|
|
2
2
|
name: gobi-brain
|
|
3
3
|
description: >-
|
|
4
4
|
Gobi brain commands for knowledge management: search public brains by text
|
|
5
|
-
and semantic similarity, ask brains questions, publish/unpublish
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
their brain updates. To browse the global feed of brain updates from
|
|
9
|
-
others, see the gobi-feed skill.
|
|
5
|
+
and semantic similarity, ask brains questions, and publish/unpublish
|
|
6
|
+
BRAIN.md. Use when the user wants to search knowledge, ask a brain, or
|
|
7
|
+
publish their brain document.
|
|
10
8
|
allowed-tools: Bash(gobi:*)
|
|
11
9
|
metadata:
|
|
12
10
|
author: gobi-ai
|
|
13
|
-
version: "0.
|
|
11
|
+
version: "0.9.13"
|
|
14
12
|
---
|
|
15
13
|
|
|
16
14
|
# gobi-brain
|
|
17
15
|
|
|
18
|
-
Gobi brain commands for knowledge management (v0.
|
|
16
|
+
Gobi brain commands for knowledge management (v0.9.13).
|
|
19
17
|
|
|
20
18
|
Requires gobi-cli installed and authenticated. See gobi-core skill for setup.
|
|
21
19
|
|
|
@@ -23,6 +21,8 @@ Requires gobi-cli installed and authenticated. See gobi-core skill for setup.
|
|
|
23
21
|
|
|
24
22
|
`gobi brain` commands manage your vault's brain: search across all spaces, ask brains questions, and publish/unpublish your BRAIN.md. Public brains are accessible at `https://gobispace.com/@{vaultSlug}`.
|
|
25
23
|
|
|
24
|
+
> **Brain updates have moved to threads.** To post user-level content, use `gobi global create-thread` (global space) or `gobi space create-thread` (a specific space). See the **gobi-space** skill.
|
|
25
|
+
|
|
26
26
|
## Important: JSON Mode
|
|
27
27
|
|
|
28
28
|
For programmatic/agent usage, always pass `--json` as a **global** option (before the subcommand):
|
|
@@ -37,9 +37,6 @@ gobi --json brain search --query "machine learning"
|
|
|
37
37
|
- `gobi brain ask` — Ask a brain a question. Creates a targeted session (1:1 conversation).
|
|
38
38
|
- `gobi brain publish` — Upload BRAIN.md to the vault root on webdrive. Triggers post-processing (brain sync, metadata update, Discord notification).
|
|
39
39
|
- `gobi brain unpublish` — Delete BRAIN.md from the vault on webdrive.
|
|
40
|
-
- `gobi brain post-update` — Post a brain update for a vault.
|
|
41
|
-
- `gobi brain edit-update` — Edit a published brain update. You must be the author.
|
|
42
|
-
- `gobi brain delete-update` — Delete a published brain update. You must be the author.
|
|
43
40
|
|
|
44
41
|
## BRAIN.md Frontmatter Reference
|
|
45
42
|
|
|
@@ -3,20 +3,17 @@
|
|
|
3
3
|
```
|
|
4
4
|
Usage: gobi brain [options] [command]
|
|
5
5
|
|
|
6
|
-
Brain commands (search, ask, publish, unpublish
|
|
6
|
+
Brain commands (search, ask, publish, unpublish).
|
|
7
7
|
|
|
8
8
|
Options:
|
|
9
|
-
-h, --help
|
|
9
|
+
-h, --help display help for command
|
|
10
10
|
|
|
11
11
|
Commands:
|
|
12
|
-
search [options]
|
|
13
|
-
ask [options]
|
|
14
|
-
publish
|
|
15
|
-
unpublish
|
|
16
|
-
|
|
17
|
-
edit-update [options] <updateId> Edit a published brain update. You must be the author.
|
|
18
|
-
delete-update <updateId> Delete a published brain update. You must be the author.
|
|
19
|
-
help [command] display help for command
|
|
12
|
+
search [options] Search public brains by text and semantic similarity.
|
|
13
|
+
ask [options] Ask a brain a question. Creates a targeted session (1:1 conversation).
|
|
14
|
+
publish Upload BRAIN.md to the vault root on webdrive. Triggers post-processing (brain sync, metadata update, Discord notification).
|
|
15
|
+
unpublish Delete BRAIN.md from the vault on webdrive.
|
|
16
|
+
help [command] display help for command
|
|
20
17
|
```
|
|
21
18
|
|
|
22
19
|
## search
|
|
@@ -67,44 +64,3 @@ Delete BRAIN.md from the vault on webdrive.
|
|
|
67
64
|
Options:
|
|
68
65
|
-h, --help display help for command
|
|
69
66
|
```
|
|
70
|
-
|
|
71
|
-
## post-update
|
|
72
|
-
|
|
73
|
-
```
|
|
74
|
-
Usage: gobi brain post-update [options]
|
|
75
|
-
|
|
76
|
-
Post a brain update for a vault.
|
|
77
|
-
|
|
78
|
-
Options:
|
|
79
|
-
--vault-slug <vaultSlug> Vault slug (overrides .gobi/settings.yaml)
|
|
80
|
-
--title <title> Title of the update
|
|
81
|
-
--content <content> Update content (markdown supported)
|
|
82
|
-
--auto-attachments Upload wiki-linked [[files]] to webdrive before posting
|
|
83
|
-
-h, --help display help for command
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
## edit-update
|
|
87
|
-
|
|
88
|
-
```
|
|
89
|
-
Usage: gobi brain edit-update [options] <updateId>
|
|
90
|
-
|
|
91
|
-
Edit a published brain update. You must be the author.
|
|
92
|
-
|
|
93
|
-
Options:
|
|
94
|
-
--title <title> New title for the update
|
|
95
|
-
--content <content> New content for the update (markdown supported)
|
|
96
|
-
--vault-slug <vaultSlug> Vault slug for attachment uploads (overrides .gobi/settings.yaml)
|
|
97
|
-
--auto-attachments Upload wiki-linked [[files]] to webdrive before editing
|
|
98
|
-
-h, --help display help for command
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
## delete-update
|
|
102
|
-
|
|
103
|
-
```
|
|
104
|
-
Usage: gobi brain delete-update [options] <updateId>
|
|
105
|
-
|
|
106
|
-
Delete a published brain update. You must be the author.
|
|
107
|
-
|
|
108
|
-
Options:
|
|
109
|
-
-h, --help display help for command
|
|
110
|
-
```
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
```
|
|
4
4
|
Usage: gobi space [options] [command]
|
|
5
5
|
|
|
6
|
-
Space commands (threads, replies).
|
|
6
|
+
Space commands (threads, replies). Space and member admin is web-UI only.
|
|
7
7
|
|
|
8
8
|
Options:
|
|
9
9
|
--space-slug <slug> Space slug (overrides .gobi/settings.yaml)
|
|
@@ -11,9 +11,12 @@ Options:
|
|
|
11
11
|
|
|
12
12
|
Commands:
|
|
13
13
|
list List spaces you are a member of.
|
|
14
|
+
get [spaceSlug] Get details for a space. Pass a slug or omit to use the current space (from .gobi/settings.yaml or --space-slug).
|
|
14
15
|
warp [spaceSlug] Select the active space. Pass a slug to warp directly, or omit for interactive selection.
|
|
15
16
|
list-topics [options] List topics in a space, ordered by most recent content linkage.
|
|
16
17
|
list-topic-threads [options] <topicSlug> List threads tagged with a topic in a space (cursor-paginated).
|
|
18
|
+
messages [options] List the unified message feed (threads and replies, newest first) in a space.
|
|
19
|
+
ancestors <threadId> Show the ancestor lineage of a thread or reply (root → immediate parent).
|
|
17
20
|
get-thread [options] <threadId> Get a thread and its replies (paginated).
|
|
18
21
|
list-threads [options] List threads in a space (paginated).
|
|
19
22
|
create-thread [options] Create a thread in a space.
|
|
@@ -9,12 +9,12 @@ description: >-
|
|
|
9
9
|
allowed-tools: Bash(gobi:*)
|
|
10
10
|
metadata:
|
|
11
11
|
author: gobi-ai
|
|
12
|
-
version: "1.3.
|
|
12
|
+
version: "1.3.6"
|
|
13
13
|
---
|
|
14
14
|
|
|
15
15
|
# gobi-proposal
|
|
16
16
|
|
|
17
|
-
Gobi proposal commands for managing agent-authored proposals (v1.3.
|
|
17
|
+
Gobi proposal commands for managing agent-authored proposals (v1.3.6).
|
|
18
18
|
|
|
19
19
|
Requires gobi-cli installed and authenticated. See gobi-core skill for setup.
|
|
20
20
|
|
|
@@ -22,18 +22,21 @@ Requires gobi-cli installed and authenticated. See gobi-core skill for setup.
|
|
|
22
22
|
|
|
23
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
24
|
|
|
25
|
-
- **
|
|
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
|
|
26
28
|
- **priority** — lower number = higher priority; default `100`
|
|
27
29
|
- **status** — `pending`, `accepted`, or `rejected`
|
|
28
|
-
- **revision** — bumped each time the content is edited
|
|
29
|
-
- **sessionId** — optional; the chat session the proposal originated from
|
|
30
|
+
- **revision** — bumped each time the title or content is edited
|
|
30
31
|
- **history** — append-only log of `created`, `edited`, `prioritized`, `accepted`, `rejected`, and `revise_requested` events
|
|
31
32
|
|
|
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.
|
|
33
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
|
+
|
|
34
37
|
## Lifecycle
|
|
35
38
|
|
|
36
|
-
`accept` and `
|
|
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.
|
|
37
40
|
|
|
38
41
|
## Important: JSON Mode
|
|
39
42
|
|
|
@@ -41,7 +44,7 @@ For programmatic/agent usage, always pass `--json` as a **global** option (befor
|
|
|
41
44
|
|
|
42
45
|
```bash
|
|
43
46
|
gobi --json proposal list --limit 20
|
|
44
|
-
gobi --json proposal add "Prefer concise titles" --priority 50
|
|
47
|
+
gobi --json proposal add "Concise titles" "Prefer concise titles for brain updates." --priority 50
|
|
45
48
|
```
|
|
46
49
|
|
|
47
50
|
JSON mode wraps the response as `{"success": true, "data": <proposal>}` (or `{"success": false, "error": "..."}`).
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
```
|
|
4
4
|
Usage: gobi proposal [options] [command]
|
|
5
5
|
|
|
6
|
-
Proposals authored by your agent during chat. Top-5 feed the system prompt; accept/reject/revise
|
|
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
7
|
|
|
8
8
|
Options:
|
|
9
9
|
-h, --help display help for command
|
|
@@ -11,13 +11,14 @@ Options:
|
|
|
11
11
|
Commands:
|
|
12
12
|
list [options] List proposals (priority ASC, then newest first).
|
|
13
13
|
get <proposalId> Show one proposal with its history.
|
|
14
|
-
add [options] <content>
|
|
15
|
-
|
|
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.
|
|
16
17
|
delete <proposalId> Delete a proposal.
|
|
17
18
|
prioritize <proposalId> <priority> Set priority (lower = higher). Top 5 feed the system prompt.
|
|
18
|
-
accept <proposalId>
|
|
19
|
-
reject <proposalId>
|
|
20
|
-
revise <proposalId> <comment>
|
|
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.
|
|
21
22
|
help [command] display help for command
|
|
22
23
|
```
|
|
23
24
|
|
|
@@ -47,12 +48,12 @@ Options:
|
|
|
47
48
|
## add
|
|
48
49
|
|
|
49
50
|
```
|
|
50
|
-
Usage: gobi proposal add [options] <content>
|
|
51
|
+
Usage: gobi proposal add [options] <title> <content>
|
|
51
52
|
|
|
52
|
-
Add a proposal
|
|
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.
|
|
53
54
|
|
|
54
55
|
Options:
|
|
55
|
-
--session <sessionId>
|
|
56
|
+
--session <sessionId> Originating chat session UUID. Falls back to $GOBI_SESSION_ID when set.
|
|
56
57
|
--priority <number> Priority (lower = higher), default 100
|
|
57
58
|
-h, --help display help for command
|
|
58
59
|
```
|
|
@@ -60,12 +61,14 @@ Options:
|
|
|
60
61
|
## edit
|
|
61
62
|
|
|
62
63
|
```
|
|
63
|
-
Usage: gobi proposal edit [options] <proposalId>
|
|
64
|
+
Usage: gobi proposal edit [options] <proposalId>
|
|
64
65
|
|
|
65
|
-
Replace proposal content (bumps revision). Pass '-' for stdin.
|
|
66
|
+
Replace proposal title and/or content (bumps revision). Pass '-' for stdin.
|
|
66
67
|
|
|
67
68
|
Options:
|
|
68
|
-
|
|
69
|
+
--title <title> New title
|
|
70
|
+
--content <content> New content; pass '-' to read from stdin
|
|
71
|
+
-h, --help display help for command
|
|
69
72
|
```
|
|
70
73
|
|
|
71
74
|
## delete
|
|
@@ -95,7 +98,7 @@ Options:
|
|
|
95
98
|
```
|
|
96
99
|
Usage: gobi proposal accept [options] <proposalId>
|
|
97
100
|
|
|
98
|
-
|
|
101
|
+
Mark the proposal accepted. The client posts the synthesized message into the session.
|
|
99
102
|
|
|
100
103
|
Options:
|
|
101
104
|
-h, --help display help for command
|
|
@@ -106,7 +109,7 @@ Options:
|
|
|
106
109
|
```
|
|
107
110
|
Usage: gobi proposal reject [options] <proposalId>
|
|
108
111
|
|
|
109
|
-
|
|
112
|
+
Mark the proposal rejected. The client posts the synthesized message into the session.
|
|
110
113
|
|
|
111
114
|
Options:
|
|
112
115
|
-h, --help display help for command
|
|
@@ -117,7 +120,7 @@ Options:
|
|
|
117
120
|
```
|
|
118
121
|
Usage: gobi proposal revise [options] <proposalId> <comment>
|
|
119
122
|
|
|
120
|
-
|
|
123
|
+
Mark the proposal for revision and record the user's comment. The client posts the synthesized message into the session.
|
|
121
124
|
|
|
122
125
|
Options:
|
|
123
126
|
-h, --help display help for command
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gobi-space
|
|
3
3
|
description: >-
|
|
4
|
-
Gobi space commands for community interaction:
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
threads and replies in their Gobi community
|
|
4
|
+
Gobi space commands for community interaction: post threads and
|
|
5
|
+
replies, browse the unified message feed and topic feeds, walk reply
|
|
6
|
+
lineage, and post to the global (slugless) space. Use when the user
|
|
7
|
+
wants to read or write threads and replies in their Gobi community
|
|
8
|
+
spaces. Space and member administration is web-UI only.
|
|
8
9
|
allowed-tools: Bash(gobi:*)
|
|
9
10
|
metadata:
|
|
10
11
|
author: gobi-ai
|
|
11
|
-
version: "0.
|
|
12
|
+
version: "0.9.13"
|
|
12
13
|
---
|
|
13
14
|
|
|
14
15
|
# gobi-space
|
|
15
16
|
|
|
16
|
-
Gobi space commands for community interaction (v0.
|
|
17
|
+
Gobi space commands for community interaction (v0.9.13).
|
|
17
18
|
|
|
18
19
|
Requires gobi-cli installed and authenticated. See gobi-core skill for setup.
|
|
19
20
|
|
|
@@ -40,19 +41,43 @@ For programmatic/agent usage, always pass `--json` as a **global** option (befor
|
|
|
40
41
|
gobi --json space list-threads
|
|
41
42
|
```
|
|
42
43
|
|
|
44
|
+
> Space and member administration (creating spaces, inviting/approving members, joining/leaving) is web-UI only and not available in the CLI.
|
|
45
|
+
|
|
43
46
|
## Available Commands
|
|
44
47
|
|
|
48
|
+
### Space details
|
|
49
|
+
- `gobi space get` — Get details for a space.
|
|
50
|
+
|
|
51
|
+
### Topics
|
|
45
52
|
- `gobi space list-topics` — List topics in a space, ordered by most recent content linkage.
|
|
46
53
|
- `gobi space list-topic-threads` — List threads tagged with a topic in a space (cursor-paginated).
|
|
54
|
+
|
|
55
|
+
### Feed & lineage
|
|
56
|
+
- `gobi space messages` — List the unified message feed (threads and replies, newest first).
|
|
57
|
+
- `gobi space ancestors` — Show the ancestor lineage of a thread or reply (root → immediate parent).
|
|
58
|
+
|
|
59
|
+
### Threads
|
|
47
60
|
- `gobi space get-thread` — Get a thread and its replies (paginated).
|
|
48
61
|
- `gobi space list-threads` — List threads in a space (paginated).
|
|
49
62
|
- `gobi space create-thread` — Create a thread in a space.
|
|
50
63
|
- `gobi space edit-thread` — Edit a thread. You must be the author.
|
|
51
64
|
- `gobi space delete-thread` — Delete a thread. You must be the author.
|
|
65
|
+
|
|
66
|
+
### Replies
|
|
52
67
|
- `gobi space create-reply` — Create a reply to a thread in a space.
|
|
53
68
|
- `gobi space edit-reply` — Edit a reply. You must be the author.
|
|
54
69
|
- `gobi space delete-reply` — Delete a reply. You must be the author.
|
|
55
70
|
|
|
71
|
+
### Global thread space
|
|
72
|
+
The global thread space has no slug and is visible across all spaces.
|
|
73
|
+
|
|
74
|
+
- `gobi global messages` — List the global unified message feed (newest first).
|
|
75
|
+
- `gobi global get-thread` — Get a global thread and its direct replies.
|
|
76
|
+
- `gobi global ancestors` — Show the ancestor lineage of a global thread or reply.
|
|
77
|
+
- `gobi global create-thread` — Create a thread in the global space.
|
|
78
|
+
- `gobi global reply` — Reply to a thread in the global space.
|
|
79
|
+
|
|
56
80
|
## Reference Documentation
|
|
57
81
|
|
|
58
82
|
- [gobi space](references/space.md)
|
|
83
|
+
- [gobi global](references/global.md)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# gobi global
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
Usage: gobi global [options] [command]
|
|
5
|
+
|
|
6
|
+
Global thread space commands (no slug; visible across all spaces).
|
|
7
|
+
|
|
8
|
+
Options:
|
|
9
|
+
-h, --help display help for command
|
|
10
|
+
|
|
11
|
+
Commands:
|
|
12
|
+
messages [options] List the global unified message feed (threads and replies, newest first).
|
|
13
|
+
get-thread [options] <threadId> Get a global thread and its direct replies (paginated).
|
|
14
|
+
ancestors <threadId> Show the ancestor lineage of a global thread or reply (root → immediate parent).
|
|
15
|
+
create-thread [options] Create a thread in the global space.
|
|
16
|
+
reply [options] <threadId> Reply to a thread in the global space.
|
|
17
|
+
help [command] display help for command
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## messages
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
Usage: gobi global messages [options]
|
|
24
|
+
|
|
25
|
+
List the global unified message feed (threads and replies, newest first).
|
|
26
|
+
|
|
27
|
+
Options:
|
|
28
|
+
--limit <number> Items per page (default: "20")
|
|
29
|
+
--cursor <string> Pagination cursor from previous response
|
|
30
|
+
-h, --help display help for command
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## get-thread
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
Usage: gobi global get-thread [options] <threadId>
|
|
37
|
+
|
|
38
|
+
Get a global thread and its direct replies (paginated).
|
|
39
|
+
|
|
40
|
+
Options:
|
|
41
|
+
--limit <number> Replies per page (default: "20")
|
|
42
|
+
--cursor <string> Pagination cursor from previous response
|
|
43
|
+
-h, --help display help for command
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## ancestors
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
Usage: gobi global ancestors [options] <threadId>
|
|
50
|
+
|
|
51
|
+
Show the ancestor lineage of a global thread or reply (root → immediate parent).
|
|
52
|
+
|
|
53
|
+
Options:
|
|
54
|
+
-h, --help display help for command
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## create-thread
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
Usage: gobi global create-thread [options]
|
|
61
|
+
|
|
62
|
+
Create a thread in the global space.
|
|
63
|
+
|
|
64
|
+
Options:
|
|
65
|
+
--title <title> Title of the thread
|
|
66
|
+
--content <content> Thread content (markdown supported, use "-" for stdin)
|
|
67
|
+
--rich-text <richText> Rich-text JSON array (mutually exclusive with --content)
|
|
68
|
+
-h, --help display help for command
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## reply
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
Usage: gobi global reply [options] <threadId>
|
|
75
|
+
|
|
76
|
+
Reply to a thread in the global space.
|
|
77
|
+
|
|
78
|
+
Options:
|
|
79
|
+
--content <content> Reply content (markdown supported, use "-" for stdin)
|
|
80
|
+
--rich-text <richText> Rich-text JSON array (mutually exclusive with --content)
|
|
81
|
+
-h, --help display help for command
|
|
82
|
+
```
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
```
|
|
4
4
|
Usage: gobi space [options] [command]
|
|
5
5
|
|
|
6
|
-
Space commands (threads, replies).
|
|
6
|
+
Space commands (threads, replies). Space and member admin is web-UI only.
|
|
7
7
|
|
|
8
8
|
Options:
|
|
9
9
|
--space-slug <slug> Space slug (overrides .gobi/settings.yaml)
|
|
@@ -11,9 +11,12 @@ Options:
|
|
|
11
11
|
|
|
12
12
|
Commands:
|
|
13
13
|
list List spaces you are a member of.
|
|
14
|
+
get [spaceSlug] Get details for a space. Pass a slug or omit to use the current space (from .gobi/settings.yaml or --space-slug).
|
|
14
15
|
warp [spaceSlug] Select the active space. Pass a slug to warp directly, or omit for interactive selection.
|
|
15
16
|
list-topics [options] List topics in a space, ordered by most recent content linkage.
|
|
16
17
|
list-topic-threads [options] <topicSlug> List threads tagged with a topic in a space (cursor-paginated).
|
|
18
|
+
messages [options] List the unified message feed (threads and replies, newest first) in a space.
|
|
19
|
+
ancestors <threadId> Show the ancestor lineage of a thread or reply (root → immediate parent).
|
|
17
20
|
get-thread [options] <threadId> Get a thread and its replies (paginated).
|
|
18
21
|
list-threads [options] List threads in a space (paginated).
|
|
19
22
|
create-thread [options] Create a thread in a space.
|
|
@@ -25,6 +28,17 @@ Commands:
|
|
|
25
28
|
help [command] display help for command
|
|
26
29
|
```
|
|
27
30
|
|
|
31
|
+
## get
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
Usage: gobi space get [options] [spaceSlug]
|
|
35
|
+
|
|
36
|
+
Get details for a space. Pass a slug or omit to use the current space (from .gobi/settings.yaml or --space-slug).
|
|
37
|
+
|
|
38
|
+
Options:
|
|
39
|
+
-h, --help display help for command
|
|
40
|
+
```
|
|
41
|
+
|
|
28
42
|
## list-topics
|
|
29
43
|
|
|
30
44
|
```
|
|
@@ -50,6 +64,30 @@ Options:
|
|
|
50
64
|
-h, --help display help for command
|
|
51
65
|
```
|
|
52
66
|
|
|
67
|
+
## messages
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
Usage: gobi space messages [options]
|
|
71
|
+
|
|
72
|
+
List the unified message feed (threads and replies, newest first) in a space.
|
|
73
|
+
|
|
74
|
+
Options:
|
|
75
|
+
--limit <number> Items per page (default: "20")
|
|
76
|
+
--cursor <string> Pagination cursor from previous response
|
|
77
|
+
-h, --help display help for command
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## ancestors
|
|
81
|
+
|
|
82
|
+
```
|
|
83
|
+
Usage: gobi space ancestors [options] <threadId>
|
|
84
|
+
|
|
85
|
+
Show the ancestor lineage of a thread or reply (root → immediate parent).
|
|
86
|
+
|
|
87
|
+
Options:
|
|
88
|
+
-h, --help display help for command
|
|
89
|
+
```
|
|
90
|
+
|
|
53
91
|
## get-thread
|
|
54
92
|
|
|
55
93
|
```
|