@gobi-ai/cli 0.3.3 → 0.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.
@@ -46,16 +46,31 @@ export function registerBrainCommand(program) {
46
46
  .command("ask")
47
47
  .description("Ask a brain a question. Creates a targeted session (1:1 conversation).")
48
48
  .requiredOption("--vault-slug <vaultSlug>", "Slug of the brain/vault to ask")
49
- .requiredOption("--space-slug <spaceSlug>", "Space slug where the brain belongs")
50
- .requiredOption("--question <question>", "The question to ask (markdown supported)")
49
+ .option("--question <question>", "The question to ask (markdown supported)")
50
+ .option("--rich-text <richText>", "Rich-text JSON array (e.g. [{\"type\":\"text\",\"text\":\"hello\"}])")
51
51
  .option("--mode <mode>", 'Session mode: "auto" or "manual"')
52
52
  .action(async (opts) => {
53
- const spaceSlug = opts.spaceSlug;
53
+ if (!opts.question && !opts.richText) {
54
+ throw new Error("Provide either --question or --rich-text.");
55
+ }
56
+ if (opts.question && opts.richText) {
57
+ throw new Error("--question and --rich-text are mutually exclusive.");
58
+ }
54
59
  const body = {
55
60
  vaultSlug: opts.vaultSlug,
56
- spaceSlug,
57
- question: opts.question,
58
61
  };
62
+ if (opts.question != null)
63
+ body.question = opts.question;
64
+ if (opts.richText != null) {
65
+ let parsed;
66
+ try {
67
+ parsed = JSON.parse(opts.richText);
68
+ }
69
+ catch {
70
+ throw new Error("Invalid --rich-text JSON.");
71
+ }
72
+ body.richText = parsed;
73
+ }
59
74
  if (opts.mode != null)
60
75
  body.mode = opts.mode;
61
76
  const resp = (await apiPost(`/session/targeted`, body));
@@ -1,9 +1,9 @@
1
- import { apiGet, apiPost, apiPatch } from "../client.js";
1
+ import { apiGet, apiPost } from "../client.js";
2
2
  import { isJsonMode, jsonOut, unwrapResp } from "./utils.js";
3
3
  export function registerSessionsCommand(program) {
4
4
  const sessions = program
5
5
  .command("session")
6
- .description("Session commands (get, list, reply, update).");
6
+ .description("Session commands (get, list, reply).");
7
7
  // ── Get ──
8
8
  sessions
9
9
  .command("get <sessionId>")
@@ -50,15 +50,12 @@ export function registerSessionsCommand(program) {
50
50
  sessions
51
51
  .command("list")
52
52
  .description("List all sessions you are part of, sorted by most recent activity.")
53
- .option("--space-slug <spaceSlug>", "Filter by space slug")
54
53
  .option("--limit <number>", "Items per page", "20")
55
54
  .option("--cursor <string>", "Pagination cursor from previous response")
56
55
  .action(async (opts) => {
57
56
  const query = { limit: parseInt(opts.limit, 10) };
58
57
  if (opts.cursor)
59
58
  query.cursor = opts.cursor;
60
- if (opts.spaceSlug)
61
- query.spaceSlug = opts.spaceSlug;
62
59
  const resp = (await apiGet(`/session/my-sessions`, query));
63
60
  const items = (resp.data || []);
64
61
  const pagination = (resp.pagination || {});
@@ -95,11 +92,30 @@ export function registerSessionsCommand(program) {
95
92
  sessions
96
93
  .command("reply <sessionId>")
97
94
  .description("Send a human reply to a session you are a member of.")
98
- .requiredOption("--content <content>", "Reply content (markdown supported)")
95
+ .option("--content <content>", "Reply content (markdown supported)")
96
+ .option("--rich-text <richText>", "Rich-text JSON array (e.g. [{\"type\":\"text\",\"text\":\"hello\"}])")
99
97
  .action(async (sessionId, opts) => {
100
- const resp = (await apiPost(`/session/${sessionId}/reply`, {
101
- content: opts.content,
102
- }));
98
+ if (!opts.content && !opts.richText) {
99
+ throw new Error("Provide either --content or --rich-text.");
100
+ }
101
+ if (opts.content && opts.richText) {
102
+ throw new Error("--content and --rich-text are mutually exclusive.");
103
+ }
104
+ const body = {};
105
+ if (opts.richText != null) {
106
+ let parsed;
107
+ try {
108
+ parsed = JSON.parse(opts.richText);
109
+ }
110
+ catch {
111
+ throw new Error("Invalid --rich-text JSON.");
112
+ }
113
+ body.richText = parsed;
114
+ }
115
+ else {
116
+ body.content = opts.content;
117
+ }
118
+ const resp = (await apiPost(`/session/${sessionId}/reply`, body));
103
119
  const msg = unwrapResp(resp);
104
120
  if (isJsonMode(sessions)) {
105
121
  jsonOut(msg);
@@ -110,31 +126,4 @@ export function registerSessionsCommand(program) {
110
126
  ` Source: ${msg.source}\n` +
111
127
  ` Created: ${msg.createdAt}`);
112
128
  });
113
- // ── Update ──
114
- sessions
115
- .command("update <sessionId>")
116
- .description('Update a session. "auto" lets the AI respond automatically; "manual" requires human replies.')
117
- .option("--mode <mode>", 'Session mode: "auto" or "manual"')
118
- .action(async (sessionId, opts) => {
119
- if (!opts.mode) {
120
- throw new Error("Provide at least one option to update (e.g. --mode).");
121
- }
122
- const body = {};
123
- if (opts.mode != null) {
124
- if (opts.mode !== "auto" && opts.mode !== "manual") {
125
- throw new Error('Invalid mode. Must be "auto" or "manual".');
126
- }
127
- body.mode = opts.mode;
128
- }
129
- const resp = (await apiPatch(`/session/${sessionId}`, body));
130
- const data = unwrapResp(resp);
131
- if (isJsonMode(sessions)) {
132
- jsonOut(data);
133
- return;
134
- }
135
- const session = (data.session || data);
136
- console.log(`Session updated!\n` +
137
- ` ID: ${session.id}\n` +
138
- ` Mode: ${session.mode}`);
139
- });
140
129
  }
@@ -1,11 +1,33 @@
1
1
  import { apiGet, apiPost, apiPatch, apiDelete } from "../client.js";
2
2
  import { selectSpace, writeSpaceSetting } from "./init.js";
3
3
  import { isJsonMode, jsonOut, resolveSpaceSlug, unwrapResp } from "./utils.js";
4
- export function registerAstraCommand(program) {
4
+ export function registerSpaceCommand(program) {
5
5
  const space = program
6
6
  .command("space")
7
7
  .description("Space commands (threads, replies).")
8
8
  .option("--space-slug <slug>", "Space slug (overrides .gobi/settings.yaml)");
9
+ // ── List spaces ──
10
+ space
11
+ .command("list")
12
+ .description("List spaces you are a member of.")
13
+ .action(async () => {
14
+ const resp = (await apiGet("/spaces"));
15
+ const items = (resp.data || []);
16
+ if (isJsonMode(space)) {
17
+ jsonOut(items);
18
+ return;
19
+ }
20
+ if (!items.length) {
21
+ console.log("No spaces found.");
22
+ return;
23
+ }
24
+ const lines = [];
25
+ for (const s of items) {
26
+ const desc = s.description ? ` - ${s.description}` : "";
27
+ lines.push(`- [${s.slug}] ${s.name}${desc}`);
28
+ }
29
+ console.log(`Spaces (${items.length}):\n` + lines.join("\n"));
30
+ });
9
31
  // ── Warp (space selection) ──
10
32
  space
11
33
  .command("warp")
package/dist/errors.js CHANGED
@@ -1,24 +1,24 @@
1
- export class AstraError extends Error {
1
+ export class GobiError extends Error {
2
2
  code;
3
3
  constructor(message, code) {
4
4
  super(message);
5
5
  this.code = code;
6
- this.name = "AstraError";
6
+ this.name = "GobiError";
7
7
  }
8
8
  }
9
- export class NotAuthenticatedError extends AstraError {
9
+ export class NotAuthenticatedError extends GobiError {
10
10
  constructor() {
11
11
  super("Not authenticated. Use 'gobi auth login' to begin the login flow.", "NOT_AUTHENTICATED");
12
12
  this.name = "NotAuthenticatedError";
13
13
  }
14
14
  }
15
- export class TokenRefreshError extends AstraError {
15
+ export class TokenRefreshError extends GobiError {
16
16
  constructor(detail) {
17
17
  super(`Failed to refresh access token: ${detail}. Please run 'gobi auth login' to re-authenticate.`, "TOKEN_REFRESH_FAILED");
18
18
  this.name = "TokenRefreshError";
19
19
  }
20
20
  }
21
- export class ApiError extends AstraError {
21
+ export class ApiError extends GobiError {
22
22
  status;
23
23
  endpoint;
24
24
  constructor(status, endpoint, body) {
@@ -37,7 +37,7 @@ export class ApiError extends AstraError {
37
37
  this.name = "ApiError";
38
38
  }
39
39
  }
40
- export class DeviceCodeError extends AstraError {
40
+ export class DeviceCodeError extends GobiError {
41
41
  constructor(detail) {
42
42
  super(`Device code flow error: ${detail}`, "DEVICE_CODE_ERROR");
43
43
  this.name = "DeviceCodeError";
package/dist/main.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import { createRequire } from "module";
2
2
  import { Command } from "commander";
3
3
  import { initCredentials } from "./auth/manager.js";
4
- import { ApiError, AstraError } from "./errors.js";
4
+ import { ApiError, GobiError } from "./errors.js";
5
5
  import { registerAuthCommand } from "./commands/auth.js";
6
6
  import { registerInitCommand, printContext } from "./commands/init.js";
7
- import { registerAstraCommand } from "./commands/astra.js";
7
+ import { registerSpaceCommand } from "./commands/space.js";
8
8
  import { registerBrainCommand } from "./commands/brain.js";
9
9
  import { registerSessionsCommand } from "./commands/sessions.js";
10
10
  const require = createRequire(import.meta.url);
@@ -27,7 +27,7 @@ export async function cli() {
27
27
  // Register all command groups
28
28
  registerAuthCommand(program);
29
29
  registerInitCommand(program);
30
- registerAstraCommand(program);
30
+ registerSpaceCommand(program);
31
31
  registerBrainCommand(program);
32
32
  registerSessionsCommand(program);
33
33
  // Propagate helpWidth to all subcommands
@@ -66,7 +66,7 @@ export async function cli() {
66
66
  console.error(`Error: API error (HTTP ${err.status}): ${err.message}${hint}`);
67
67
  process.exit(1);
68
68
  }
69
- else if (err instanceof AstraError) {
69
+ else if (err instanceof GobiError) {
70
70
  if (isJson) {
71
71
  console.log(JSON.stringify({ success: false, error: err.message }));
72
72
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gobi-ai/cli",
3
- "version": "0.3.3",
3
+ "version": "0.3.6",
4
4
  "description": "CLI client for the Gobi collaborative knowledge platform",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -38,6 +38,7 @@
38
38
  "start": "node dist/index.js",
39
39
  "test": "node --test dist/*.test.js",
40
40
  "generate-skill-docs": "npm run build && npx tsx skills/gobi-cli/scripts/generate-docs.ts",
41
+ "prepare": "npm run build",
41
42
  "prepublishOnly": "npm run build"
42
43
  },
43
44
  "dependencies": {