knowbrain-cli 0.0.1-rc.0

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/dist/kb.js ADDED
@@ -0,0 +1,2622 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli/run.ts
4
+ import { CommanderError } from "commander";
5
+
6
+ // src/http/http-error.ts
7
+ function writeCliError(stderr, err) {
8
+ stderr.write(`${JSON.stringify(err)}
9
+ `);
10
+ }
11
+
12
+ // src/cli/program.ts
13
+ import { Command } from "commander";
14
+
15
+ // src/commands/connectors/connectors.ts
16
+ import { readFile as readFile2 } from "fs/promises";
17
+ import { parse as parseYaml } from "yaml";
18
+
19
+ // ../sdk/dist/omi-sdk-error.js
20
+ var OmiSdkError = class extends Error {
21
+ code;
22
+ details;
23
+ status;
24
+ constructor(init) {
25
+ super(init.message);
26
+ this.name = "OmiSdkError";
27
+ this.code = init.code;
28
+ this.details = init.details ?? null;
29
+ if (init.status !== void 0) {
30
+ this.status = init.status;
31
+ }
32
+ }
33
+ };
34
+ function omiSdkError(init) {
35
+ return new OmiSdkError(init);
36
+ }
37
+
38
+ // ../sdk/dist/error-from-response.js
39
+ function statusFallbackCode(status) {
40
+ if (status === 404)
41
+ return "NOT_FOUND";
42
+ if (status === 409)
43
+ return "CONFLICT";
44
+ if (status === 400)
45
+ return "VALIDATION_ERROR";
46
+ return "INTERNAL";
47
+ }
48
+ async function omiSdkErrorFromResponse(res) {
49
+ const text = await res.text();
50
+ try {
51
+ const j = JSON.parse(text);
52
+ if (j && typeof j === "object" && !Array.isArray(j)) {
53
+ const o = j;
54
+ if (typeof o["code"] === "string" && typeof o["message"] === "string") {
55
+ return omiSdkError({
56
+ code: o["code"],
57
+ message: o["message"],
58
+ details: "details" in o ? o["details"] ?? null : null,
59
+ status: res.status
60
+ });
61
+ }
62
+ if (typeof o["error"] === "string") {
63
+ return omiSdkError({
64
+ code: statusFallbackCode(res.status),
65
+ message: o["error"],
66
+ details: null,
67
+ status: res.status
68
+ });
69
+ }
70
+ }
71
+ } catch {
72
+ }
73
+ return omiSdkError({
74
+ code: statusFallbackCode(res.status),
75
+ message: text.length > 0 ? text : res.statusText || `HTTP ${res.status}`,
76
+ details: null,
77
+ status: res.status
78
+ });
79
+ }
80
+
81
+ // ../../packages/core/dist/utils/kb-uri.js
82
+ function parseKbUri(uri) {
83
+ const prefix = "kb://";
84
+ const t = uri.trim();
85
+ if (!t.startsWith(prefix)) {
86
+ throw new Error(`expected kb:// URI, got: ${uri}`);
87
+ }
88
+ const rest = t.slice(prefix.length).replace(/^\/+/u, "").replace(/\/+$/u, "");
89
+ if (rest.length === 0) {
90
+ throw new Error("kb:// URI must include at least a spaceId");
91
+ }
92
+ const parts = rest.split("/");
93
+ if (parts[0].length === 0) {
94
+ throw new Error("kb:// URI must include a spaceId");
95
+ }
96
+ const spaceId = parts[0];
97
+ const path = parts.slice(2).join("/");
98
+ if (parts.length >= 2 && parts[1].length > 0) {
99
+ return { spaceId, storeId: parts[1], path };
100
+ }
101
+ return { spaceId, path };
102
+ }
103
+ function formatKbUri(spaceId, storeId, path) {
104
+ if (storeId === void 0 || storeId.length === 0) {
105
+ return `kb://${spaceId}`;
106
+ }
107
+ if (path !== void 0 && path.length > 0) {
108
+ return `kb://${spaceId}/${storeId}/${path}`;
109
+ }
110
+ return `kb://${spaceId}/${storeId}`;
111
+ }
112
+
113
+ // ../../packages/core/dist/utils/logger.js
114
+ import pino from "pino";
115
+ function resolveLevel(explicit) {
116
+ if (explicit !== void 0 && explicit !== "") {
117
+ return explicit;
118
+ }
119
+ const fromEnv = process.env["LOG_LEVEL"];
120
+ if (fromEnv !== void 0 && fromEnv !== "") {
121
+ return fromEnv;
122
+ }
123
+ return process.env["NODE_ENV"] === "production" ? "info" : "debug";
124
+ }
125
+ function usePrettyTransport() {
126
+ return process.env["LOG_PRETTY"] === "1";
127
+ }
128
+ function createOmiLogger(options) {
129
+ const level = resolveLevel(options.level);
130
+ const base = { service: options.service };
131
+ if (options.bindings) {
132
+ Object.assign(base, options.bindings);
133
+ }
134
+ const opts = { level, base };
135
+ if (usePrettyTransport()) {
136
+ opts.transport = {
137
+ target: "pino-pretty",
138
+ options: { colorize: true }
139
+ };
140
+ }
141
+ const dest = options.destination ?? "stdout";
142
+ if (dest === "stderr") {
143
+ return pino(opts, pino.destination(2));
144
+ }
145
+ return pino(opts);
146
+ }
147
+
148
+ // ../../packages/core/dist/metadata/field-role.js
149
+ var FieldRole = {
150
+ mutable: "mutable",
151
+ immutable: "immutable",
152
+ status: "status"
153
+ };
154
+
155
+ // ../../packages/core/dist/metadata/field-decorator.js
156
+ var rolesByConstructor = /* @__PURE__ */ new Map();
157
+ function ensureMap(ctor) {
158
+ let m = rolesByConstructor.get(ctor);
159
+ if (!m) {
160
+ m = /* @__PURE__ */ new Map();
161
+ rolesByConstructor.set(ctor, m);
162
+ }
163
+ return m;
164
+ }
165
+ function metadataField(role) {
166
+ return function(target, propertyKey) {
167
+ const ctor = target.constructor;
168
+ const key = typeof propertyKey === "string" ? propertyKey : String(propertyKey);
169
+ ensureMap(ctor).set(key, role);
170
+ };
171
+ }
172
+ function mutableField() {
173
+ return metadataField(FieldRole.mutable);
174
+ }
175
+ function immutableField() {
176
+ return metadataField(FieldRole.immutable);
177
+ }
178
+ function statusField() {
179
+ return metadataField(FieldRole.status);
180
+ }
181
+
182
+ // ../../packages/core/dist/metadata/space-scoped-base.js
183
+ var __decorate = function(decorators, target, key, desc) {
184
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
185
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
186
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
187
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
188
+ };
189
+ var SpaceScopedResource = class {
190
+ id;
191
+ spaceId;
192
+ name;
193
+ /** Longer label; empty string means none. */
194
+ description = "";
195
+ createdAt;
196
+ updatedAt;
197
+ };
198
+ __decorate([
199
+ immutableField()
200
+ ], SpaceScopedResource.prototype, "id", void 0);
201
+ __decorate([
202
+ immutableField()
203
+ ], SpaceScopedResource.prototype, "spaceId", void 0);
204
+ __decorate([
205
+ mutableField()
206
+ ], SpaceScopedResource.prototype, "name", void 0);
207
+ __decorate([
208
+ mutableField()
209
+ ], SpaceScopedResource.prototype, "description", void 0);
210
+ __decorate([
211
+ immutableField()
212
+ ], SpaceScopedResource.prototype, "createdAt", void 0);
213
+ __decorate([
214
+ immutableField()
215
+ ], SpaceScopedResource.prototype, "updatedAt", void 0);
216
+
217
+ // ../../packages/core/dist/connectors/resource.js
218
+ var __decorate2 = function(decorators, target, key, desc) {
219
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
220
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
221
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
222
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
223
+ };
224
+ var ConnectorResource = class extends SpaceScopedResource {
225
+ type;
226
+ config = {};
227
+ secrets = {};
228
+ targetStoreIds;
229
+ lastSyncAt;
230
+ lastSyncStatus = "ready";
231
+ };
232
+ __decorate2([
233
+ immutableField()
234
+ ], ConnectorResource.prototype, "type", void 0);
235
+ __decorate2([
236
+ mutableField()
237
+ ], ConnectorResource.prototype, "config", void 0);
238
+ __decorate2([
239
+ mutableField()
240
+ ], ConnectorResource.prototype, "secrets", void 0);
241
+ __decorate2([
242
+ immutableField()
243
+ ], ConnectorResource.prototype, "targetStoreIds", void 0);
244
+ __decorate2([
245
+ mutableField()
246
+ ], ConnectorResource.prototype, "lastSyncAt", void 0);
247
+ __decorate2([
248
+ mutableField()
249
+ ], ConnectorResource.prototype, "lastSyncStatus", void 0);
250
+
251
+ // ../../packages/core/dist/space/types.js
252
+ var __decorate3 = function(decorators, target, key, desc) {
253
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
254
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
255
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
256
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
257
+ };
258
+ var SpaceResource = class {
259
+ id;
260
+ name;
261
+ /** Longer label; empty string means none. */
262
+ description = "";
263
+ status;
264
+ createdAt;
265
+ updatedAt;
266
+ };
267
+ __decorate3([
268
+ immutableField()
269
+ ], SpaceResource.prototype, "id", void 0);
270
+ __decorate3([
271
+ mutableField()
272
+ ], SpaceResource.prototype, "name", void 0);
273
+ __decorate3([
274
+ mutableField()
275
+ ], SpaceResource.prototype, "description", void 0);
276
+ __decorate3([
277
+ statusField()
278
+ ], SpaceResource.prototype, "status", void 0);
279
+ __decorate3([
280
+ immutableField()
281
+ ], SpaceResource.prototype, "createdAt", void 0);
282
+ __decorate3([
283
+ immutableField()
284
+ ], SpaceResource.prototype, "updatedAt", void 0);
285
+
286
+ // ../../packages/core/dist/store/types.js
287
+ var __decorate4 = function(decorators, target, key, desc) {
288
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
289
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
290
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
291
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
292
+ };
293
+ var StoreResource = class extends SpaceScopedResource {
294
+ status;
295
+ /** When true, durable head cannot be updated via {@link import("./runtime.js").Store.mergeProposal}. */
296
+ readOnly = false;
297
+ };
298
+ __decorate4([
299
+ statusField()
300
+ ], StoreResource.prototype, "status", void 0);
301
+ __decorate4([
302
+ immutableField()
303
+ ], StoreResource.prototype, "readOnly", void 0);
304
+ var ProposalResource = class extends SpaceScopedResource {
305
+ storeId;
306
+ /** Optional task association for task-scoped proposal listing. */
307
+ taskId;
308
+ baseRevisionId;
309
+ workDir;
310
+ status;
311
+ };
312
+ __decorate4([
313
+ immutableField()
314
+ ], ProposalResource.prototype, "storeId", void 0);
315
+ __decorate4([
316
+ immutableField()
317
+ ], ProposalResource.prototype, "taskId", void 0);
318
+ __decorate4([
319
+ immutableField()
320
+ ], ProposalResource.prototype, "baseRevisionId", void 0);
321
+ __decorate4([
322
+ mutableField()
323
+ ], ProposalResource.prototype, "workDir", void 0);
324
+ __decorate4([
325
+ statusField()
326
+ ], ProposalResource.prototype, "status", void 0);
327
+
328
+ // ../../packages/core/dist/task/default-task.js
329
+ var DEFAULT_TASK_ID = "default";
330
+
331
+ // ../../packages/core/dist/task/resource.js
332
+ var __decorate5 = function(decorators, target, key, desc) {
333
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
334
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
335
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
336
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
337
+ };
338
+ var TaskResource = class extends SpaceScopedResource {
339
+ /** Immutable store bindings used to resolve runtime stores for this task. */
340
+ storeIds;
341
+ status;
342
+ };
343
+ __decorate5([
344
+ immutableField()
345
+ ], TaskResource.prototype, "storeIds", void 0);
346
+ __decorate5([
347
+ statusField()
348
+ ], TaskResource.prototype, "status", void 0);
349
+
350
+ // ../sdk/dist/parse-wire.js
351
+ function assertRecord(j, label) {
352
+ if (!j || typeof j !== "object" || Array.isArray(j)) {
353
+ throw omiSdkError({
354
+ code: "INTERNAL",
355
+ message: `invalid ${label}: expected object`,
356
+ details: null
357
+ });
358
+ }
359
+ return j;
360
+ }
361
+ function parseSpaceResourceWire(j) {
362
+ const o = assertRecord(j, "space resource");
363
+ const r = new SpaceResource();
364
+ r.id = String(o["id"] ?? "");
365
+ r.name = String(o["name"] ?? "");
366
+ r.description = String(o["description"] ?? "");
367
+ r.status = o["status"];
368
+ r.createdAt = new Date(String(o["createdAt"] ?? ""));
369
+ r.updatedAt = new Date(String(o["updatedAt"] ?? ""));
370
+ return r;
371
+ }
372
+ function parseStringMapWire(o, field) {
373
+ if (o === void 0 || o === null) {
374
+ return {};
375
+ }
376
+ if (typeof o !== "object" || Array.isArray(o)) {
377
+ throw omiSdkError({
378
+ code: "INTERNAL",
379
+ message: `invalid connector resource: expected object for ${field}`,
380
+ details: null
381
+ });
382
+ }
383
+ const out = {};
384
+ for (const [k, v] of Object.entries(o)) {
385
+ if (typeof v === "string") {
386
+ out[k] = v;
387
+ }
388
+ }
389
+ return out;
390
+ }
391
+ function parseConnectorResourceWire(j) {
392
+ const o = assertRecord(j, "connector resource");
393
+ const r = new ConnectorResource();
394
+ r.id = String(o["id"] ?? "");
395
+ r.spaceId = String(o["spaceId"] ?? "");
396
+ r.name = String(o["name"] ?? "");
397
+ r.description = String(o["description"] ?? "");
398
+ r.type = String(o["type"] ?? "");
399
+ r.config = parseStringMapWire(o["config"], "config");
400
+ r.secrets = parseStringMapWire(o["secrets"], "secrets");
401
+ const ids = o["targetStoreIds"];
402
+ if (!Array.isArray(ids)) {
403
+ throw omiSdkError({
404
+ code: "INTERNAL",
405
+ message: "invalid connector resource: expected targetStoreIds array",
406
+ details: null
407
+ });
408
+ }
409
+ if (ids.some((x) => typeof x !== "string")) {
410
+ throw omiSdkError({
411
+ code: "INTERNAL",
412
+ message: "invalid connector resource: expected targetStoreIds string[]",
413
+ details: null
414
+ });
415
+ }
416
+ r.targetStoreIds = ids;
417
+ const lsa = o["lastSyncAt"];
418
+ if (lsa !== void 0 && lsa !== null) {
419
+ r.lastSyncAt = new Date(String(lsa));
420
+ }
421
+ r.lastSyncStatus = String(o["lastSyncStatus"] ?? "ready");
422
+ r.createdAt = new Date(String(o["createdAt"] ?? ""));
423
+ r.updatedAt = new Date(String(o["updatedAt"] ?? ""));
424
+ return r;
425
+ }
426
+ function parseStoreResourceWire(j) {
427
+ const o = assertRecord(j, "store resource");
428
+ const r = new StoreResource();
429
+ r.id = String(o["id"] ?? "");
430
+ r.spaceId = String(o["spaceId"] ?? "");
431
+ r.name = String(o["name"] ?? "");
432
+ r.description = String(o["description"] ?? "");
433
+ r.status = o["status"];
434
+ r.readOnly = o["readOnly"] === true;
435
+ r.createdAt = new Date(String(o["createdAt"] ?? ""));
436
+ r.updatedAt = new Date(String(o["updatedAt"] ?? ""));
437
+ return r;
438
+ }
439
+ function parseTaskResourceWire(j) {
440
+ const o = assertRecord(j, "task resource");
441
+ const r = new TaskResource();
442
+ r.id = String(o["id"] ?? "");
443
+ r.spaceId = String(o["spaceId"] ?? "");
444
+ r.name = String(o["name"] ?? "");
445
+ r.description = String(o["description"] ?? "");
446
+ r.status = o["status"];
447
+ const storeIds = o["storeIds"];
448
+ if (!Array.isArray(storeIds)) {
449
+ throw omiSdkError({
450
+ code: "INTERNAL",
451
+ message: "invalid task resource: expected storeIds array",
452
+ details: null
453
+ });
454
+ }
455
+ if (storeIds.some((storeId) => typeof storeId !== "string")) {
456
+ throw omiSdkError({
457
+ code: "INTERNAL",
458
+ message: "invalid task resource: expected storeIds string[]",
459
+ details: null
460
+ });
461
+ }
462
+ r.storeIds = storeIds;
463
+ r.createdAt = new Date(String(o["createdAt"] ?? ""));
464
+ r.updatedAt = new Date(String(o["updatedAt"] ?? ""));
465
+ return r;
466
+ }
467
+ function parseProposalResourceWire(j) {
468
+ const o = assertRecord(j, "proposal resource");
469
+ const r = new ProposalResource();
470
+ r.id = String(o["id"] ?? "");
471
+ r.spaceId = String(o["spaceId"] ?? "");
472
+ r.storeId = String(o["storeId"] ?? "");
473
+ if (o["taskId"] !== void 0) {
474
+ r.taskId = String(o["taskId"]);
475
+ }
476
+ r.name = String(o["name"] ?? "");
477
+ r.description = String(o["description"] ?? "");
478
+ r.baseRevisionId = String(o["baseRevisionId"] ?? "");
479
+ r.workDir = String(o["workDir"] ?? "");
480
+ r.status = o["status"];
481
+ r.createdAt = new Date(String(o["createdAt"] ?? ""));
482
+ r.updatedAt = new Date(String(o["updatedAt"] ?? ""));
483
+ return r;
484
+ }
485
+ function parseRevisionWire(j) {
486
+ const o = assertRecord(j, "revision");
487
+ return {
488
+ revisionId: String(o["revisionId"] ?? ""),
489
+ createTime: new Date(String(o["createTime"] ?? "")),
490
+ title: String(o["title"] ?? ""),
491
+ description: String(o["description"] ?? ""),
492
+ authorName: String(o["authorName"] ?? ""),
493
+ authorEmail: String(o["authorEmail"] ?? "")
494
+ };
495
+ }
496
+ function parseProposalDiffWire(j) {
497
+ const o = assertRecord(j, "proposal diff");
498
+ if (o["format"] !== "unified") {
499
+ throw omiSdkError({
500
+ code: "INTERNAL",
501
+ message: "invalid proposal diff: expected format unified",
502
+ details: null
503
+ });
504
+ }
505
+ if (typeof o["rawUnifiedDiff"] !== "string") {
506
+ throw omiSdkError({
507
+ code: "INTERNAL",
508
+ message: "invalid proposal diff: expected rawUnifiedDiff string",
509
+ details: null
510
+ });
511
+ }
512
+ if (!Array.isArray(o["files"])) {
513
+ throw omiSdkError({
514
+ code: "INTERNAL",
515
+ message: "invalid proposal diff: expected files array",
516
+ details: null
517
+ });
518
+ }
519
+ return j;
520
+ }
521
+ function parseProposalDiffItemWire(j) {
522
+ const o = assertRecord(j, "proposal diff item");
523
+ if (!("proposal" in o) || !("diff" in o)) {
524
+ throw omiSdkError({
525
+ code: "INTERNAL",
526
+ message: "invalid proposal diff item: expected proposal and diff fields",
527
+ details: null
528
+ });
529
+ }
530
+ return {
531
+ proposal: parseProposalResourceWire(o["proposal"]),
532
+ diff: parseProposalDiffWire(o["diff"])
533
+ };
534
+ }
535
+ function parseCommandResultWire(j) {
536
+ const o = assertRecord(j, "command result");
537
+ if (typeof o["stdout"] !== "string") {
538
+ throw omiSdkError({
539
+ code: "INTERNAL",
540
+ message: "invalid command result: expected stdout string",
541
+ details: null
542
+ });
543
+ }
544
+ if (typeof o["stderr"] !== "string") {
545
+ throw omiSdkError({
546
+ code: "INTERNAL",
547
+ message: "invalid command result: expected stderr string",
548
+ details: null
549
+ });
550
+ }
551
+ if (typeof o["exitCode"] !== "number" || !Number.isFinite(o["exitCode"])) {
552
+ throw omiSdkError({
553
+ code: "INTERNAL",
554
+ message: "invalid command result: expected exitCode number",
555
+ details: null
556
+ });
557
+ }
558
+ if (typeof o["startedAt"] !== "string" || typeof o["finishedAt"] !== "string") {
559
+ throw omiSdkError({
560
+ code: "INTERNAL",
561
+ message: "invalid command result: expected startedAt/finishedAt strings",
562
+ details: null
563
+ });
564
+ }
565
+ return {
566
+ stdout: o["stdout"],
567
+ stderr: o["stderr"],
568
+ exitCode: o["exitCode"],
569
+ startedAt: o["startedAt"],
570
+ finishedAt: o["finishedAt"]
571
+ };
572
+ }
573
+ function parseMatchedContextWire(j) {
574
+ const o = assertRecord(j, "matched context");
575
+ const out = {
576
+ contextType: String(o["contextType"] ?? ""),
577
+ uri: String(o["uri"] ?? ""),
578
+ level: Number(o["level"] ?? 0),
579
+ score: Number(o["score"] ?? 0),
580
+ category: String(o["category"] ?? ""),
581
+ matchReason: String(o["matchReason"] ?? ""),
582
+ abstract: String(o["abstract"] ?? "")
583
+ };
584
+ if (o["overview"] !== void 0) {
585
+ out.overview = String(o["overview"]);
586
+ }
587
+ return out;
588
+ }
589
+ function parseMatchedContextArrayWire(j, label) {
590
+ if (!Array.isArray(j)) {
591
+ throw omiSdkError({
592
+ code: "INTERNAL",
593
+ message: `invalid ${label}: expected array`,
594
+ details: null
595
+ });
596
+ }
597
+ return j.map((item) => parseMatchedContextWire(item));
598
+ }
599
+ function parseSearchResultWire(j) {
600
+ const o = assertRecord(j, "search result");
601
+ return {
602
+ memories: parseMatchedContextArrayWire(o["memories"], "search result memories"),
603
+ resources: parseMatchedContextArrayWire(o["resources"], "search result resources"),
604
+ skills: parseMatchedContextArrayWire(o["skills"], "search result skills"),
605
+ total: Number(o["total"] ?? 0)
606
+ };
607
+ }
608
+
609
+ // ../sdk/dist/url.js
610
+ function joinBaseUrl(base, path) {
611
+ const b = base.replace(/\/$/, "");
612
+ return `${b}${path.startsWith("/") ? path : `/${path}`}`;
613
+ }
614
+
615
+ // ../sdk/dist/create-omi-sdk.js
616
+ function requireStoreScope(space) {
617
+ if (space.trim().length === 0) {
618
+ throw omiSdkError({
619
+ code: "VALIDATION_ERROR",
620
+ message: "space is required for store operations (set it when creating the SDK client)",
621
+ details: null
622
+ });
623
+ }
624
+ }
625
+ async function fetchOk(fetchFn, absoluteUrl, init) {
626
+ const res = await fetchFn(absoluteUrl, init);
627
+ if (!res.ok) {
628
+ throw await omiSdkErrorFromResponse(res);
629
+ }
630
+ return res;
631
+ }
632
+ async function readJsonBody(text, label) {
633
+ const trimmed = text.trim();
634
+ if (trimmed === "") {
635
+ throw omiSdkError({
636
+ code: "INTERNAL",
637
+ message: `empty JSON body (${label})`,
638
+ details: null
639
+ });
640
+ }
641
+ try {
642
+ return JSON.parse(trimmed);
643
+ } catch {
644
+ throw omiSdkError({
645
+ code: "INTERNAL",
646
+ message: `invalid JSON (${label})`,
647
+ details: null
648
+ });
649
+ }
650
+ }
651
+ function createOmiSdk(init) {
652
+ const fetchFn = init.fetch ?? globalThis.fetch.bind(globalThis);
653
+ const baseUrl = init.baseUrl.replace(/\/$/, "");
654
+ const space = init.space;
655
+ function abs(path) {
656
+ return joinBaseUrl(baseUrl, path);
657
+ }
658
+ function storeBase() {
659
+ requireStoreScope(space);
660
+ return `/spaces/${encodeURIComponent(space)}/stores`;
661
+ }
662
+ function taskBase() {
663
+ requireStoreScope(space);
664
+ return `/spaces/${encodeURIComponent(space)}/tasks`;
665
+ }
666
+ function connectorBase() {
667
+ requireStoreScope(space);
668
+ return `/spaces/${encodeURIComponent(space)}/connectors`;
669
+ }
670
+ const spaceApi = {
671
+ async create(input) {
672
+ const initReq = { method: "POST" };
673
+ if (input !== void 0 && Object.keys(input).length > 0) {
674
+ initReq.headers = { "content-type": "application/json" };
675
+ initReq.body = JSON.stringify(input);
676
+ }
677
+ const res = await fetchOk(fetchFn, abs("/spaces"), initReq);
678
+ const j = await readJsonBody(await res.text(), "POST /spaces");
679
+ return parseSpaceResourceWire(j);
680
+ },
681
+ async get(spaceId) {
682
+ const res = await fetchOk(fetchFn, abs(`/spaces/${encodeURIComponent(spaceId)}`), {
683
+ method: "GET"
684
+ });
685
+ const j = await readJsonBody(await res.text(), "GET /spaces/:id");
686
+ return parseSpaceResourceWire(j);
687
+ },
688
+ async list() {
689
+ const res = await fetchOk(fetchFn, abs("/spaces"), { method: "GET" });
690
+ const j = await readJsonBody(await res.text(), "GET /spaces");
691
+ const o = j;
692
+ const arr = o["spaces"];
693
+ if (!Array.isArray(arr)) {
694
+ throw omiSdkError({
695
+ code: "INTERNAL",
696
+ message: "list spaces: expected { spaces: [] }",
697
+ details: null
698
+ });
699
+ }
700
+ return arr.map((x) => parseSpaceResourceWire(x));
701
+ },
702
+ async update(spaceId, patch) {
703
+ const res = await fetchOk(fetchFn, abs(`/spaces/${encodeURIComponent(spaceId)}`), {
704
+ method: "PATCH",
705
+ headers: { "content-type": "application/json" },
706
+ body: JSON.stringify(patch)
707
+ });
708
+ const j = await readJsonBody(await res.text(), "PATCH /spaces/:id");
709
+ return parseSpaceResourceWire(j);
710
+ },
711
+ async delete(spaceId) {
712
+ await fetchOk(fetchFn, abs(`/spaces/${encodeURIComponent(spaceId)}`), {
713
+ method: "DELETE"
714
+ });
715
+ }
716
+ };
717
+ const storeApi = {
718
+ async create(input) {
719
+ const initReq = { method: "POST" };
720
+ if (input !== void 0 && Object.keys(input).length > 0) {
721
+ initReq.headers = { "content-type": "application/json" };
722
+ initReq.body = JSON.stringify(input);
723
+ }
724
+ const res = await fetchOk(fetchFn, abs(`${storeBase()}`), initReq);
725
+ const j = await readJsonBody(await res.text(), "POST .../stores");
726
+ return parseStoreResourceWire(j);
727
+ },
728
+ async get(storeId) {
729
+ const res = await fetchOk(fetchFn, abs(`${storeBase()}/${encodeURIComponent(storeId)}`), {
730
+ method: "GET"
731
+ });
732
+ const j = await readJsonBody(await res.text(), "GET .../stores/:id");
733
+ return parseStoreResourceWire(j);
734
+ },
735
+ async list() {
736
+ const res = await fetchOk(fetchFn, abs(storeBase()), { method: "GET" });
737
+ const j = await readJsonBody(await res.text(), "GET .../stores");
738
+ const o = j;
739
+ const arr = o["stores"];
740
+ if (!Array.isArray(arr)) {
741
+ throw omiSdkError({
742
+ code: "INTERNAL",
743
+ message: "list stores: expected { stores: [] }",
744
+ details: null
745
+ });
746
+ }
747
+ return arr.map((x) => parseStoreResourceWire(x));
748
+ },
749
+ async update(storeId, patch) {
750
+ const res = await fetchOk(fetchFn, abs(`${storeBase()}/${encodeURIComponent(storeId)}`), {
751
+ method: "PATCH",
752
+ headers: { "content-type": "application/json" },
753
+ body: JSON.stringify(patch)
754
+ });
755
+ const j = await readJsonBody(await res.text(), "PATCH .../stores/:id");
756
+ return parseStoreResourceWire(j);
757
+ },
758
+ async delete(storeId) {
759
+ await fetchOk(fetchFn, abs(`${storeBase()}/${encodeURIComponent(storeId)}`), {
760
+ method: "DELETE"
761
+ });
762
+ },
763
+ async waitSync(storeId) {
764
+ await fetchOk(fetchFn, abs(`${storeBase()}/${encodeURIComponent(storeId)}/wait-sync`), {
765
+ method: "POST"
766
+ });
767
+ },
768
+ async listRevisions(storeId) {
769
+ const res = await fetchOk(fetchFn, abs(`${storeBase()}/${encodeURIComponent(storeId)}/revisions`), { method: "GET" });
770
+ const j = await readJsonBody(await res.text(), "GET .../revisions");
771
+ const o = j;
772
+ const arr = o["revisions"];
773
+ if (!Array.isArray(arr)) {
774
+ throw omiSdkError({
775
+ code: "INTERNAL",
776
+ message: "list revisions: expected { revisions: [] }",
777
+ details: null
778
+ });
779
+ }
780
+ return arr.map((x) => parseRevisionWire(x));
781
+ },
782
+ async restoreRevision(storeId, revisionId) {
783
+ await fetchOk(fetchFn, abs(`${storeBase()}/${encodeURIComponent(storeId)}/revisions/${encodeURIComponent(revisionId)}/restore`), { method: "POST" });
784
+ },
785
+ async uploadFile(params) {
786
+ const q = `${storeBase()}/${encodeURIComponent(params.storeId)}/files?path=${encodeURIComponent(params.path)}`;
787
+ await fetchOk(fetchFn, abs(q), {
788
+ method: "PUT",
789
+ headers: {
790
+ "content-type": params.contentType ?? "application/octet-stream"
791
+ },
792
+ body: params.body
793
+ });
794
+ },
795
+ async downloadFile(params) {
796
+ const q = `${storeBase()}/${encodeURIComponent(params.storeId)}/files?path=${encodeURIComponent(params.path)}`;
797
+ const res = await fetchOk(fetchFn, abs(q), { method: "GET" });
798
+ return new Uint8Array(await res.arrayBuffer());
799
+ },
800
+ async deleteFile(params) {
801
+ const q = `${storeBase()}/${encodeURIComponent(params.storeId)}/files?path=${encodeURIComponent(params.path)}`;
802
+ await fetchOk(fetchFn, abs(q), { method: "DELETE" });
803
+ },
804
+ async search(query, searchOption) {
805
+ const res = await fetchOk(fetchFn, abs(`${storeBase()}/search`), {
806
+ method: "POST",
807
+ headers: { "content-type": "application/json" },
808
+ body: JSON.stringify({ query, searchOption })
809
+ });
810
+ const j = await readJsonBody(await res.text(), "POST .../stores/search");
811
+ return parseSearchResultWire(j);
812
+ }
813
+ };
814
+ const taskApi = {
815
+ async create(input) {
816
+ const initReq = { method: "POST" };
817
+ if (input !== void 0 && Object.keys(input).length > 0) {
818
+ initReq.headers = { "content-type": "application/json" };
819
+ initReq.body = JSON.stringify(input);
820
+ }
821
+ const res = await fetchOk(fetchFn, abs(taskBase()), initReq);
822
+ const j = await readJsonBody(await res.text(), "POST .../tasks");
823
+ return parseTaskResourceWire(j);
824
+ },
825
+ async get(taskId) {
826
+ const res = await fetchOk(fetchFn, abs(`${taskBase()}/${encodeURIComponent(taskId)}`), {
827
+ method: "GET"
828
+ });
829
+ const j = await readJsonBody(await res.text(), "GET .../tasks/:id");
830
+ return parseTaskResourceWire(j);
831
+ },
832
+ async list() {
833
+ const res = await fetchOk(fetchFn, abs(taskBase()), { method: "GET" });
834
+ const j = await readJsonBody(await res.text(), "GET .../tasks");
835
+ const o = j;
836
+ const arr = o["tasks"];
837
+ if (!Array.isArray(arr)) {
838
+ throw omiSdkError({
839
+ code: "INTERNAL",
840
+ message: "list tasks: expected { tasks: [] }",
841
+ details: null
842
+ });
843
+ }
844
+ return arr.map((item) => parseTaskResourceWire(item));
845
+ },
846
+ async update(taskId, patch) {
847
+ const res = await fetchOk(fetchFn, abs(`${taskBase()}/${encodeURIComponent(taskId)}`), {
848
+ method: "PATCH",
849
+ headers: { "content-type": "application/json" },
850
+ body: JSON.stringify(patch)
851
+ });
852
+ const j = await readJsonBody(await res.text(), "PATCH .../tasks/:id");
853
+ return parseTaskResourceWire(j);
854
+ },
855
+ async delete(taskId) {
856
+ await fetchOk(fetchFn, abs(`${taskBase()}/${encodeURIComponent(taskId)}`), {
857
+ method: "DELETE"
858
+ });
859
+ },
860
+ async listProposals(taskId) {
861
+ const res = await fetchOk(fetchFn, abs(`${taskBase()}/${encodeURIComponent(taskId)}/proposals`), { method: "GET" });
862
+ const j = await readJsonBody(await res.text(), "GET .../tasks/:id/proposals");
863
+ const o = j;
864
+ const arr = o["proposals"];
865
+ if (!Array.isArray(arr)) {
866
+ throw omiSdkError({
867
+ code: "INTERNAL",
868
+ message: "list proposals: expected { proposals: [] }",
869
+ details: null
870
+ });
871
+ }
872
+ return arr.map((item) => parseProposalResourceWire(item));
873
+ },
874
+ async executeShellCommand(taskId, command) {
875
+ const res = await fetchOk(fetchFn, abs(`${taskBase()}/${encodeURIComponent(taskId)}/shell`), {
876
+ method: "POST",
877
+ headers: { "content-type": "application/json" },
878
+ body: JSON.stringify(command)
879
+ });
880
+ const j = await readJsonBody(await res.text(), "POST .../tasks/:id/shell");
881
+ return parseCommandResultWire(j);
882
+ },
883
+ async diff(taskId) {
884
+ const res = await fetchOk(fetchFn, abs(`${taskBase()}/${encodeURIComponent(taskId)}/diff`), {
885
+ method: "GET"
886
+ });
887
+ const j = await readJsonBody(await res.text(), "GET .../tasks/:id/diff");
888
+ const o = j;
889
+ const arr = o["diffs"];
890
+ if (!Array.isArray(arr)) {
891
+ throw omiSdkError({
892
+ code: "INTERNAL",
893
+ message: "task diff: expected { diffs: [] }",
894
+ details: null
895
+ });
896
+ }
897
+ return arr.map((item) => parseProposalDiffItemWire(item));
898
+ },
899
+ async submit(taskId, proposalIds) {
900
+ await fetchOk(fetchFn, abs(`${taskBase()}/${encodeURIComponent(taskId)}/submit`), {
901
+ method: "POST",
902
+ headers: { "content-type": "application/json" },
903
+ body: JSON.stringify({ proposalIds })
904
+ });
905
+ },
906
+ async approve(taskId, proposalIds) {
907
+ await fetchOk(fetchFn, abs(`${taskBase()}/${encodeURIComponent(taskId)}/approve`), {
908
+ method: "POST",
909
+ headers: { "content-type": "application/json" },
910
+ body: JSON.stringify({ proposalIds })
911
+ });
912
+ },
913
+ async reject(taskId, proposalIds, reason) {
914
+ await fetchOk(fetchFn, abs(`${taskBase()}/${encodeURIComponent(taskId)}/reject`), {
915
+ method: "POST",
916
+ headers: { "content-type": "application/json" },
917
+ body: JSON.stringify({ proposalIds, reason })
918
+ });
919
+ },
920
+ async merge(taskId, proposalIds) {
921
+ const res = await fetchFn(abs(`${taskBase()}/${encodeURIComponent(taskId)}/merge`), {
922
+ method: "POST",
923
+ headers: { "content-type": "application/json" },
924
+ body: JSON.stringify({ proposalIds })
925
+ });
926
+ if (res.status === 204) {
927
+ return;
928
+ }
929
+ if (!res.ok) {
930
+ throw await omiSdkErrorFromResponse(res);
931
+ }
932
+ throw omiSdkError({
933
+ code: "INTERNAL",
934
+ message: `unexpected merge response status ${res.status}`,
935
+ details: null,
936
+ status: res.status
937
+ });
938
+ },
939
+ async stop(taskId) {
940
+ await fetchOk(fetchFn, abs(`${taskBase()}/${encodeURIComponent(taskId)}/stop`), {
941
+ method: "POST"
942
+ });
943
+ }
944
+ };
945
+ const connectorApi = {
946
+ async create(input) {
947
+ const initReq = { method: "POST" };
948
+ if (input !== void 0 && Object.keys(input).length > 0) {
949
+ initReq.headers = { "content-type": "application/json" };
950
+ initReq.body = JSON.stringify(input);
951
+ }
952
+ const res = await fetchOk(fetchFn, abs(connectorBase()), initReq);
953
+ const j = await readJsonBody(await res.text(), "POST .../connectors");
954
+ return parseConnectorResourceWire(j);
955
+ },
956
+ async get(connectorId) {
957
+ const res = await fetchOk(fetchFn, abs(`${connectorBase()}/${encodeURIComponent(connectorId)}`), { method: "GET" });
958
+ const j = await readJsonBody(await res.text(), "GET .../connectors/:id");
959
+ return parseConnectorResourceWire(j);
960
+ },
961
+ async list() {
962
+ const res = await fetchOk(fetchFn, abs(connectorBase()), { method: "GET" });
963
+ const j = await readJsonBody(await res.text(), "GET .../connectors");
964
+ const o = j;
965
+ const arr = o["connectors"];
966
+ if (!Array.isArray(arr)) {
967
+ throw omiSdkError({
968
+ code: "INTERNAL",
969
+ message: "list connectors: expected { connectors: [] }",
970
+ details: null
971
+ });
972
+ }
973
+ return arr.map((x) => parseConnectorResourceWire(x));
974
+ },
975
+ async update(connectorId, patch) {
976
+ const res = await fetchOk(fetchFn, abs(`${connectorBase()}/${encodeURIComponent(connectorId)}`), {
977
+ method: "PATCH",
978
+ headers: { "content-type": "application/json" },
979
+ body: JSON.stringify(patch)
980
+ });
981
+ const j = await readJsonBody(await res.text(), "PATCH .../connectors/:id");
982
+ return parseConnectorResourceWire(j);
983
+ },
984
+ async delete(connectorId) {
985
+ await fetchOk(fetchFn, abs(`${connectorBase()}/${encodeURIComponent(connectorId)}`), {
986
+ method: "DELETE"
987
+ });
988
+ }
989
+ };
990
+ return { spaceApi, storeApi, taskApi, connectorApi };
991
+ }
992
+
993
+ // src/auth/origin.ts
994
+ function resolveAuthOrigin(baseUrl) {
995
+ return baseUrl.replace(/\/$/, "");
996
+ }
997
+
998
+ // src/auth/credentials.ts
999
+ import { chmod, mkdir, readFile, unlink, writeFile } from "fs/promises";
1000
+ import { homedir } from "os";
1001
+ import { dirname, join } from "path";
1002
+ var CREDENTIALS_MODE = 384;
1003
+ function defaultCredentialsPath() {
1004
+ const configHome = process.env["XDG_CONFIG_HOME"] ?? join(homedir(), ".config");
1005
+ return join(configHome, "kb", "credentials.json");
1006
+ }
1007
+ function resolveCredentialsPath(options) {
1008
+ return options?.filePath ?? defaultCredentialsPath();
1009
+ }
1010
+ async function loadCredentials(options) {
1011
+ const filePath = resolveCredentialsPath(options);
1012
+ try {
1013
+ const raw = await readFile(filePath, "utf8");
1014
+ const parsed = JSON.parse(raw);
1015
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
1016
+ return null;
1017
+ }
1018
+ const o = parsed;
1019
+ if (typeof o["accessToken"] !== "string" || typeof o["expiresAt"] !== "string" || typeof o["origin"] !== "string" || typeof o["spaceId"] !== "string" || o["spaceId"].length === 0) {
1020
+ return null;
1021
+ }
1022
+ return {
1023
+ accessToken: o["accessToken"],
1024
+ expiresAt: o["expiresAt"],
1025
+ origin: o["origin"],
1026
+ spaceId: o["spaceId"]
1027
+ };
1028
+ } catch (e) {
1029
+ if (e && typeof e === "object" && "code" in e && e.code === "ENOENT") {
1030
+ return null;
1031
+ }
1032
+ throw e;
1033
+ }
1034
+ }
1035
+ async function saveCredentials(credentials, options) {
1036
+ const filePath = resolveCredentialsPath(options);
1037
+ await mkdir(dirname(filePath), { recursive: true });
1038
+ await writeFile(filePath, `${JSON.stringify(credentials)}
1039
+ `, {
1040
+ encoding: "utf8",
1041
+ mode: CREDENTIALS_MODE
1042
+ });
1043
+ await chmod(filePath, CREDENTIALS_MODE);
1044
+ }
1045
+ async function clearCredentials(options) {
1046
+ const filePath = resolveCredentialsPath(options);
1047
+ try {
1048
+ await unlink(filePath);
1049
+ } catch (e) {
1050
+ if (e && typeof e === "object" && "code" in e && e.code === "ENOENT") {
1051
+ return;
1052
+ }
1053
+ throw e;
1054
+ }
1055
+ }
1056
+ function credentialsMatchOrigin(credentials, origin) {
1057
+ return credentials.origin.replace(/\/$/, "") === origin.replace(/\/$/, "");
1058
+ }
1059
+ function isCredentialsExpired(credentials, nowMs = Date.now()) {
1060
+ const expiresAt = Date.parse(credentials.expiresAt);
1061
+ if (Number.isNaN(expiresAt)) {
1062
+ return true;
1063
+ }
1064
+ return nowMs >= expiresAt;
1065
+ }
1066
+
1067
+ // src/auth/authenticated-fetch.ts
1068
+ function createAuthenticatedFetch(ctx, options) {
1069
+ const baseFetch = ctx.deps.fetch;
1070
+ const origin = resolveAuthOrigin(ctx.baseUrl);
1071
+ return async (input, init) => {
1072
+ const credentials = await loadCredentials(options);
1073
+ const headers = new Headers(init?.headers);
1074
+ const hasValidCreds = credentials !== null && credentialsMatchOrigin(credentials, origin) && !isCredentialsExpired(credentials);
1075
+ if (hasValidCreds && credentials) {
1076
+ headers.set("Authorization", `Bearer ${credentials.accessToken}`);
1077
+ headers.set("Origin", origin);
1078
+ }
1079
+ const res = await baseFetch(input, { ...init, headers });
1080
+ if (res.status === 401) {
1081
+ const expired = credentials !== null && credentialsMatchOrigin(credentials, origin) && isCredentialsExpired(credentials);
1082
+ if (expired) {
1083
+ return new Response(
1084
+ JSON.stringify({
1085
+ code: "AUTH_EXPIRED",
1086
+ message: "Session expired. Run `kb login` to sign in again.",
1087
+ details: null
1088
+ }),
1089
+ { status: 401, headers: { "content-type": "application/json" } }
1090
+ );
1091
+ }
1092
+ if (!hasValidCreds) {
1093
+ return new Response(
1094
+ JSON.stringify({
1095
+ code: "AUTH_REQUIRED",
1096
+ message: "Authentication required. Run `kb login` to sign in.",
1097
+ details: null
1098
+ }),
1099
+ { status: 401, headers: { "content-type": "application/json" } }
1100
+ );
1101
+ }
1102
+ }
1103
+ return res;
1104
+ };
1105
+ }
1106
+
1107
+ // src/cli/api-base.ts
1108
+ var DEFAULT_API_PATH_PREFIX = "/api/knowbrain";
1109
+ function joinBaseUrl2(base, path) {
1110
+ const b = base.replace(/\/$/, "");
1111
+ return `${b}${path.startsWith("/") ? path : `/${path}`}`;
1112
+ }
1113
+ function resolveKbApiPathPrefix(env) {
1114
+ const raw = env["KB_API_PATH_PREFIX"];
1115
+ if (raw === void 0) {
1116
+ return DEFAULT_API_PATH_PREFIX;
1117
+ }
1118
+ return raw;
1119
+ }
1120
+ function resolveKbApiBaseUrl(origin, env) {
1121
+ const base = origin.replace(/\/$/, "");
1122
+ const prefix = resolveKbApiPathPrefix(env);
1123
+ if (prefix === "") {
1124
+ return base;
1125
+ }
1126
+ const normalized = prefix.startsWith("/") ? prefix : `/${prefix}`;
1127
+ if (base.endsWith(normalized)) {
1128
+ return base;
1129
+ }
1130
+ return joinBaseUrl2(base, normalized);
1131
+ }
1132
+
1133
+ // src/cli/sdk-factory.ts
1134
+ function createKbSdk(ctx, space) {
1135
+ const apiBaseUrl = resolveKbApiBaseUrl(ctx.baseUrl, ctx.deps.env);
1136
+ const fetchFn = createAuthenticatedFetch(ctx);
1137
+ return createOmiSdk({ baseUrl: apiBaseUrl, space, fetch: fetchFn });
1138
+ }
1139
+
1140
+ // src/cli/context.ts
1141
+ var DEFAULT_BASE_URL = "http://localhost:3000";
1142
+ var defaultKbCliDeps = {
1143
+ fetch: globalThis.fetch.bind(globalThis),
1144
+ stdout: process.stdout,
1145
+ stderr: process.stderr,
1146
+ env: process.env
1147
+ };
1148
+ function parseGlobalOpts(program) {
1149
+ const o = program.opts();
1150
+ return {
1151
+ baseUrl: o.baseUrl ?? DEFAULT_BASE_URL,
1152
+ logLevel: o.logLevel ?? "error"
1153
+ };
1154
+ }
1155
+ function createKbCliContext(deps, program) {
1156
+ const g = parseGlobalOpts(program);
1157
+ const logger = deps.logger ?? createOmiLogger({
1158
+ service: "cli",
1159
+ level: g.logLevel,
1160
+ destination: "stderr",
1161
+ bindings: { component: "kb" }
1162
+ });
1163
+ return { deps, baseUrl: g.baseUrl, logger };
1164
+ }
1165
+
1166
+ // src/cli/space-resolve.ts
1167
+ function resolveExplicitSpaceId(program, env) {
1168
+ const o = program.opts();
1169
+ if (o.space !== void 0 && o.space.length > 0) {
1170
+ return o.space;
1171
+ }
1172
+ const fromEnv = env["KB_SPACE"];
1173
+ if (fromEnv !== void 0 && fromEnv.length > 0) {
1174
+ return fromEnv;
1175
+ }
1176
+ return void 0;
1177
+ }
1178
+ async function resolveSpaceId(program, deps, baseUrl, credentialsOptions) {
1179
+ const explicit = resolveExplicitSpaceId(program, deps.env);
1180
+ if (explicit !== void 0) {
1181
+ return explicit;
1182
+ }
1183
+ const credentials = await loadCredentials(credentialsOptions);
1184
+ const origin = resolveAuthOrigin(baseUrl);
1185
+ if (credentials !== null && credentialsMatchOrigin(credentials, origin)) {
1186
+ return credentials.spaceId;
1187
+ }
1188
+ return void 0;
1189
+ }
1190
+ async function requireSpaceId(program, deps, baseUrl, credentialsOptions) {
1191
+ const id = await resolveSpaceId(program, deps, baseUrl, credentialsOptions);
1192
+ if (id === void 0) {
1193
+ writeCliError(deps.stderr, {
1194
+ code: "VALIDATION_ERROR",
1195
+ message: "Missing space id: pass --space <id>, set KB_SPACE, or run kb login",
1196
+ details: null
1197
+ });
1198
+ return null;
1199
+ }
1200
+ return id;
1201
+ }
1202
+
1203
+ // src/http/write-json.ts
1204
+ function writeStdoutPrettyJson(stdout, value) {
1205
+ stdout.write(`${JSON.stringify(value, null, 2)}
1206
+ `);
1207
+ }
1208
+
1209
+ // src/http/command-success.ts
1210
+ function successJson(value) {
1211
+ return { kind: "json", value };
1212
+ }
1213
+ function successVoid() {
1214
+ return { kind: "void" };
1215
+ }
1216
+ function writeCommandSuccess(stdout, success) {
1217
+ if (success.kind === "void") {
1218
+ return;
1219
+ }
1220
+ writeStdoutPrettyJson(stdout, success.value);
1221
+ }
1222
+
1223
+ // src/http/sdk-bridge.ts
1224
+ function cliErrorFromUnknown(err) {
1225
+ if (err instanceof OmiSdkError) {
1226
+ return { code: err.code, message: err.message, details: err.details ?? null };
1227
+ }
1228
+ const msg = err instanceof Error ? err.message : String(err);
1229
+ return { code: "INTERNAL", message: msg, details: null };
1230
+ }
1231
+
1232
+ // src/commands/connectors/connectors.ts
1233
+ function isRecord(x) {
1234
+ return typeof x === "object" && x !== null && !Array.isArray(x);
1235
+ }
1236
+ function parseKvList(values) {
1237
+ const out = {};
1238
+ if (values === void 0) {
1239
+ return out;
1240
+ }
1241
+ for (const raw of values) {
1242
+ const i = raw.indexOf("=");
1243
+ if (i <= 0) {
1244
+ throw new Error(`invalid --config-kv "${raw}": expected KEY=value`);
1245
+ }
1246
+ const k = raw.slice(0, i).trim();
1247
+ const v = raw.slice(i + 1);
1248
+ if (k.length === 0) {
1249
+ throw new Error(`invalid --config-kv "${raw}": empty key`);
1250
+ }
1251
+ out[k] = v;
1252
+ }
1253
+ return out;
1254
+ }
1255
+ function mergeStringMaps(base, extra) {
1256
+ return { ...base, ...extra };
1257
+ }
1258
+ async function loadConnectorCreateInputFromFile(path) {
1259
+ const text = await readFile2(path, "utf8");
1260
+ const raw = path.endsWith(".json") ? JSON.parse(text) : parseYaml(text);
1261
+ if (!isRecord(raw)) {
1262
+ throw new Error("config file root must be an object");
1263
+ }
1264
+ const out = {};
1265
+ if (typeof raw["id"] === "string") {
1266
+ out.id = raw["id"];
1267
+ }
1268
+ if (typeof raw["name"] === "string") {
1269
+ out.name = raw["name"];
1270
+ }
1271
+ if (typeof raw["description"] === "string") {
1272
+ out.description = raw["description"];
1273
+ }
1274
+ if (typeof raw["type"] === "string") {
1275
+ out.type = raw["type"];
1276
+ }
1277
+ if (isRecord(raw["config"])) {
1278
+ const c = {};
1279
+ for (const [k, v] of Object.entries(raw["config"])) {
1280
+ if (typeof v === "string") {
1281
+ c[k] = v;
1282
+ }
1283
+ }
1284
+ out.config = c;
1285
+ }
1286
+ if (isRecord(raw["secrets"])) {
1287
+ const s = {};
1288
+ for (const [k, v] of Object.entries(raw["secrets"])) {
1289
+ if (typeof v === "string") {
1290
+ s[k] = v;
1291
+ }
1292
+ }
1293
+ out.secrets = s;
1294
+ }
1295
+ if (Array.isArray(raw["targetStoreIds"])) {
1296
+ const ids = raw["targetStoreIds"].filter((x) => typeof x === "string");
1297
+ out.targetStoreIds = ids;
1298
+ }
1299
+ return out;
1300
+ }
1301
+ function registerConnectorCommands(connectors, rootProgram, deps, exitRef) {
1302
+ connectors.command("create").description("Create a connector in the current space").option("--id <id>", "Explicit connector id").option("--name <name>", "Display name").option("--description <text>", "Description").option("--type <type>", "Connector type (e.g. notion, feishu)").option("--target-stores <csv>", "Comma-separated target store ids").option("--config <path>", "YAML or JSON file with partial create fields").option("--config-kv <pair...>", "Non-secret config KEY=value (repeat for multiple keys)").option("--secret-kv <pair...>", "Secret KEY=value (repeat for multiple keys)").action(
1303
+ async (opts) => {
1304
+ const ctx = createKbCliContext(deps, rootProgram);
1305
+ const spaceId = await requireSpaceId(rootProgram, deps, ctx.baseUrl);
1306
+ if (spaceId === null) {
1307
+ exitRef.code = 1;
1308
+ return;
1309
+ }
1310
+ const sdk = createKbSdk(ctx, spaceId);
1311
+ try {
1312
+ let fileInput = {};
1313
+ if (opts.config !== void 0) {
1314
+ fileInput = await loadConnectorCreateInputFromFile(opts.config);
1315
+ }
1316
+ const targetFromFlag = opts.targetStores !== void 0 ? opts.targetStores.split(",").map((s) => s.trim()).filter(Boolean) : void 0;
1317
+ const merged = {
1318
+ name: opts.name ?? fileInput.name ?? "",
1319
+ description: opts.description ?? fileInput.description ?? "",
1320
+ type: opts.type ?? fileInput.type ?? "",
1321
+ targetStoreIds: targetFromFlag ?? fileInput.targetStoreIds ?? [],
1322
+ config: mergeStringMaps(fileInput.config ?? {}, parseKvList(opts.configKv)),
1323
+ secrets: mergeStringMaps(fileInput.secrets ?? {}, parseKvList(opts.secretKv))
1324
+ };
1325
+ const id = opts.id ?? fileInput.id;
1326
+ if (id !== void 0 && id.trim() !== "") {
1327
+ merged.id = id.trim();
1328
+ }
1329
+ const created = await sdk.connectorApi.create(merged);
1330
+ writeCommandSuccess(ctx.deps.stdout, successJson(created));
1331
+ exitRef.code = 0;
1332
+ } catch (e) {
1333
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(e));
1334
+ exitRef.code = 1;
1335
+ }
1336
+ }
1337
+ );
1338
+ }
1339
+
1340
+ // src/cli/task-resolve.ts
1341
+ function normalizeTaskId(candidate) {
1342
+ if (candidate === void 0) {
1343
+ return void 0;
1344
+ }
1345
+ const trimmed = candidate.trim();
1346
+ return trimmed.length > 0 ? trimmed : void 0;
1347
+ }
1348
+ function resolveTaskId(program, env, explicitTaskId) {
1349
+ const fromExplicit = normalizeTaskId(explicitTaskId);
1350
+ if (fromExplicit !== void 0) {
1351
+ return fromExplicit;
1352
+ }
1353
+ const opts = program.opts();
1354
+ const fromOption = normalizeTaskId(opts.task);
1355
+ if (fromOption !== void 0) {
1356
+ return fromOption;
1357
+ }
1358
+ return normalizeTaskId(env["KB_TASK"]);
1359
+ }
1360
+ function resolveTaskContextId(program, env, explicitTaskId) {
1361
+ return resolveTaskId(program, env, explicitTaskId) ?? DEFAULT_TASK_ID;
1362
+ }
1363
+ function requireTaskId(program, deps, explicitTaskId) {
1364
+ const taskId = resolveTaskId(program, deps.env, explicitTaskId);
1365
+ if (taskId === void 0) {
1366
+ writeCliError(deps.stderr, {
1367
+ code: "VALIDATION_ERROR",
1368
+ message: "Missing task id: pass --task <id> or set KB_TASK",
1369
+ details: null
1370
+ });
1371
+ return null;
1372
+ }
1373
+ return taskId;
1374
+ }
1375
+ function requireTaskContextId(program, deps, explicitTaskId) {
1376
+ return resolveTaskContextId(program, deps.env, explicitTaskId);
1377
+ }
1378
+
1379
+ // src/commands/diff.ts
1380
+ function registerDiffCommand(program, rootProgram, deps, exitRef) {
1381
+ program.command("diff").description("Show merged proposal diffs for the current task").option("--task <taskId>", "Override task id").action(async (opts) => {
1382
+ const ctx = createKbCliContext(deps, rootProgram);
1383
+ const spaceId = await requireSpaceId(rootProgram, deps, ctx.baseUrl);
1384
+ if (spaceId === null) {
1385
+ exitRef.code = 1;
1386
+ return;
1387
+ }
1388
+ const taskId = requireTaskContextId(rootProgram, deps, opts.task);
1389
+ const sdk = createKbSdk(ctx, spaceId);
1390
+ try {
1391
+ const diffs = await sdk.taskApi.diff(taskId);
1392
+ writeCommandSuccess(ctx.deps.stdout, successJson({ diffs }));
1393
+ exitRef.code = 0;
1394
+ } catch (error) {
1395
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(error));
1396
+ exitRef.code = 1;
1397
+ }
1398
+ });
1399
+ }
1400
+
1401
+ // src/commands/proposal/proposal.ts
1402
+ async function resolveProposalIds(sdk, taskId, proposalIds, all) {
1403
+ if (all) {
1404
+ const proposals = await sdk.taskApi.listProposals(taskId);
1405
+ return proposals.map((proposal) => proposal.id);
1406
+ }
1407
+ return proposalIds;
1408
+ }
1409
+ function ensureProposalSelection(proposalIds, deps, exitRef) {
1410
+ if (proposalIds.length > 0) {
1411
+ return true;
1412
+ }
1413
+ writeCliError(deps.stderr, {
1414
+ code: "VALIDATION_ERROR",
1415
+ message: "Missing proposal ids: pass proposal ids or use --all",
1416
+ details: null
1417
+ });
1418
+ exitRef.code = 1;
1419
+ return false;
1420
+ }
1421
+ function registerProposalCommands(proposal, rootProgram, deps, exitRef) {
1422
+ proposal.command("list").description("List proposals for the current task").option("--task <taskId>", "Override task id").action(async (opts) => {
1423
+ const ctx = createKbCliContext(deps, rootProgram);
1424
+ const spaceId = await requireSpaceId(rootProgram, deps, ctx.baseUrl);
1425
+ if (spaceId === null) {
1426
+ exitRef.code = 1;
1427
+ return;
1428
+ }
1429
+ const taskId = requireTaskContextId(rootProgram, deps, opts.task);
1430
+ const sdk = createKbSdk(ctx, spaceId);
1431
+ try {
1432
+ const proposals = await sdk.taskApi.listProposals(taskId);
1433
+ writeCommandSuccess(ctx.deps.stdout, successJson({ proposals }));
1434
+ exitRef.code = 0;
1435
+ } catch (error) {
1436
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(error));
1437
+ exitRef.code = 1;
1438
+ }
1439
+ });
1440
+ proposal.command("submit").description("Submit one or more proposals").argument("[proposalIds...]", "Proposal ids").option("--all", "Submit all proposals in current task", false).option("--task <taskId>", "Override task id").action(async (proposalIds, opts) => {
1441
+ const ctx = createKbCliContext(deps, rootProgram);
1442
+ const spaceId = await requireSpaceId(rootProgram, deps, ctx.baseUrl);
1443
+ if (spaceId === null) {
1444
+ exitRef.code = 1;
1445
+ return;
1446
+ }
1447
+ const taskId = requireTaskContextId(rootProgram, deps, opts.task);
1448
+ const sdk = createKbSdk(ctx, spaceId);
1449
+ try {
1450
+ const resolvedIds = await resolveProposalIds(sdk, taskId, proposalIds, opts.all === true);
1451
+ if (!ensureProposalSelection(resolvedIds, deps, exitRef)) {
1452
+ return;
1453
+ }
1454
+ await sdk.taskApi.submit(taskId, resolvedIds);
1455
+ writeCommandSuccess(ctx.deps.stdout, successVoid());
1456
+ exitRef.code = 0;
1457
+ } catch (error) {
1458
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(error));
1459
+ exitRef.code = 1;
1460
+ }
1461
+ });
1462
+ proposal.command("approve").description("Approve one or more proposals").argument("[proposalIds...]", "Proposal ids").option("--all", "Approve all proposals in current task", false).option("--task <taskId>", "Override task id").action(async (proposalIds, opts) => {
1463
+ const ctx = createKbCliContext(deps, rootProgram);
1464
+ const spaceId = await requireSpaceId(rootProgram, deps, ctx.baseUrl);
1465
+ if (spaceId === null) {
1466
+ exitRef.code = 1;
1467
+ return;
1468
+ }
1469
+ const taskId = requireTaskContextId(rootProgram, deps, opts.task);
1470
+ const sdk = createKbSdk(ctx, spaceId);
1471
+ try {
1472
+ const resolvedIds = await resolveProposalIds(sdk, taskId, proposalIds, opts.all === true);
1473
+ if (!ensureProposalSelection(resolvedIds, deps, exitRef)) {
1474
+ return;
1475
+ }
1476
+ await sdk.taskApi.approve(taskId, resolvedIds);
1477
+ writeCommandSuccess(ctx.deps.stdout, successVoid());
1478
+ exitRef.code = 0;
1479
+ } catch (error) {
1480
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(error));
1481
+ exitRef.code = 1;
1482
+ }
1483
+ });
1484
+ proposal.command("reject").description("Reject one or more proposals").argument("[proposalIds...]", "Proposal ids").option("--reason <reason>", "Optional reject reason").option("--all", "Reject all proposals in current task", false).option("--task <taskId>", "Override task id").action(
1485
+ async (proposalIds, opts) => {
1486
+ const ctx = createKbCliContext(deps, rootProgram);
1487
+ const spaceId = await requireSpaceId(rootProgram, deps, ctx.baseUrl);
1488
+ if (spaceId === null) {
1489
+ exitRef.code = 1;
1490
+ return;
1491
+ }
1492
+ const taskId = requireTaskContextId(rootProgram, deps, opts.task);
1493
+ const sdk = createKbSdk(ctx, spaceId);
1494
+ try {
1495
+ const resolvedIds = await resolveProposalIds(sdk, taskId, proposalIds, opts.all === true);
1496
+ if (!ensureProposalSelection(resolvedIds, deps, exitRef)) {
1497
+ return;
1498
+ }
1499
+ await sdk.taskApi.reject(taskId, resolvedIds, opts.reason ?? "");
1500
+ writeCommandSuccess(ctx.deps.stdout, successVoid());
1501
+ exitRef.code = 0;
1502
+ } catch (error) {
1503
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(error));
1504
+ exitRef.code = 1;
1505
+ }
1506
+ }
1507
+ );
1508
+ proposal.command("merge").description("Merge one or more proposals").argument("[proposalIds...]", "Proposal ids").option("--all", "Merge all proposals in current task", false).option("--task <taskId>", "Override task id").action(async (proposalIds, opts) => {
1509
+ const ctx = createKbCliContext(deps, rootProgram);
1510
+ const spaceId = await requireSpaceId(rootProgram, deps, ctx.baseUrl);
1511
+ if (spaceId === null) {
1512
+ exitRef.code = 1;
1513
+ return;
1514
+ }
1515
+ const taskId = requireTaskContextId(rootProgram, deps, opts.task);
1516
+ const sdk = createKbSdk(ctx, spaceId);
1517
+ try {
1518
+ const resolvedIds = await resolveProposalIds(sdk, taskId, proposalIds, opts.all === true);
1519
+ if (!ensureProposalSelection(resolvedIds, deps, exitRef)) {
1520
+ return;
1521
+ }
1522
+ await sdk.taskApi.merge(taskId, resolvedIds);
1523
+ writeCommandSuccess(ctx.deps.stdout, successVoid());
1524
+ exitRef.code = 0;
1525
+ } catch (error) {
1526
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(error));
1527
+ exitRef.code = 1;
1528
+ }
1529
+ });
1530
+ }
1531
+
1532
+ // src/commands/search.ts
1533
+ function parseLimit(raw) {
1534
+ if (raw === void 0) {
1535
+ return void 0;
1536
+ }
1537
+ const parsed = Number(raw);
1538
+ if (!Number.isInteger(parsed) || parsed <= 0) {
1539
+ throw new Error("invalid option --limit: expected a positive integer");
1540
+ }
1541
+ return parsed;
1542
+ }
1543
+ function parseScoreThreshold(raw) {
1544
+ if (raw === void 0) {
1545
+ return void 0;
1546
+ }
1547
+ const parsed = Number(raw);
1548
+ if (!Number.isFinite(parsed)) {
1549
+ throw new Error("invalid option --score-threshold: expected a finite number");
1550
+ }
1551
+ return parsed;
1552
+ }
1553
+ function toSearchOption(opts) {
1554
+ const option = {};
1555
+ if (opts.targetUri !== void 0) {
1556
+ option.targetUri = opts.targetUri;
1557
+ }
1558
+ const limit = parseLimit(opts.limit);
1559
+ if (limit !== void 0) {
1560
+ option.limit = limit;
1561
+ }
1562
+ const scoreThreshold = parseScoreThreshold(opts.scoreThreshold);
1563
+ if (scoreThreshold !== void 0) {
1564
+ option.scoreThreshold = scoreThreshold;
1565
+ }
1566
+ return Object.keys(option).length === 0 ? void 0 : option;
1567
+ }
1568
+ function registerSearchCommand(program, rootProgram, deps, exitRef) {
1569
+ program.command("search").description("Search synced knowledge within the current space").argument("<query>", "Search query").option("--target-uri <uri>", "SearchOption.targetUri").option("--limit <n>", "SearchOption.limit").option("--score-threshold <n>", "SearchOption.scoreThreshold").action(async (query, opts) => {
1570
+ const ctx = createKbCliContext(deps, rootProgram);
1571
+ const spaceId = await requireSpaceId(rootProgram, deps, ctx.baseUrl);
1572
+ if (spaceId === null) {
1573
+ exitRef.code = 1;
1574
+ return;
1575
+ }
1576
+ let searchOption;
1577
+ try {
1578
+ searchOption = toSearchOption(opts);
1579
+ } catch (e) {
1580
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(e));
1581
+ exitRef.code = 1;
1582
+ return;
1583
+ }
1584
+ const sdk = createKbSdk(ctx, spaceId);
1585
+ try {
1586
+ const result = await sdk.storeApi.search(query, searchOption);
1587
+ writeCommandSuccess(ctx.deps.stdout, successJson(result));
1588
+ exitRef.code = 0;
1589
+ } catch (e) {
1590
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(e));
1591
+ exitRef.code = 1;
1592
+ }
1593
+ });
1594
+ }
1595
+
1596
+ // src/commands/shell.ts
1597
+ function parseTimeoutMs(value) {
1598
+ const parsed = Number.parseInt(value, 10);
1599
+ if (!Number.isFinite(parsed) || parsed <= 0) {
1600
+ throw new Error("invalid option --timeout-ms: expected a positive integer");
1601
+ }
1602
+ return parsed;
1603
+ }
1604
+ function parseEnvList(values) {
1605
+ const out = {};
1606
+ for (const entry of values ?? []) {
1607
+ const idx = entry.indexOf("=");
1608
+ if (idx <= 0 || idx === entry.length - 1) {
1609
+ throw new Error(`invalid --env entry "${entry}": expected KEY=VALUE`);
1610
+ }
1611
+ const key = entry.slice(0, idx);
1612
+ const val = entry.slice(idx + 1);
1613
+ out[key] = val;
1614
+ }
1615
+ return out;
1616
+ }
1617
+ function registerShellCommand(program, rootProgram, deps, exitRef) {
1618
+ program.command("shell").description("Execute a shell command in task context").argument("<command>", "Command to run").option("--task <taskId>", "Override task id").option("--cwd <cwd>", "Relative working directory", ".").option("--timeout-ms <ms>", "Timeout in milliseconds", parseTimeoutMs, 3e4).option("--env <pair...>", "Environment entries in KEY=VALUE form").action(
1619
+ async (command, opts) => {
1620
+ const ctx = createKbCliContext(deps, rootProgram);
1621
+ const spaceId = await requireSpaceId(rootProgram, deps, ctx.baseUrl);
1622
+ if (spaceId === null) {
1623
+ exitRef.code = 1;
1624
+ return;
1625
+ }
1626
+ const taskId = requireTaskContextId(rootProgram, deps, opts.task);
1627
+ const sdk = createKbSdk(ctx, spaceId);
1628
+ try {
1629
+ const env = parseEnvList(opts.env);
1630
+ const result = await sdk.taskApi.executeShellCommand(taskId, {
1631
+ command,
1632
+ cwd: opts.cwd ?? ".",
1633
+ timeoutMs: opts.timeoutMs,
1634
+ env
1635
+ });
1636
+ if (result.exitCode === 0) {
1637
+ if (result.stdout.length > 0) {
1638
+ ctx.deps.stdout.write(result.stdout);
1639
+ }
1640
+ exitRef.code = 0;
1641
+ return;
1642
+ }
1643
+ writeCommandSuccess(ctx.deps.stdout, successJson(result));
1644
+ exitRef.code = 1;
1645
+ } catch (error) {
1646
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(error));
1647
+ exitRef.code = 1;
1648
+ }
1649
+ }
1650
+ );
1651
+ }
1652
+
1653
+ // src/commands/space/space.ts
1654
+ function registerSpaceCommands(space, rootProgram, deps, exitRef) {
1655
+ space.command("create").description("Create a space").option("--id <id>", "Explicit id").option("--name <name>", "Display name").option("--description <text>", "Description").action(async (opts) => {
1656
+ const ctx = createKbCliContext(deps, rootProgram);
1657
+ ctx.logger.debug({ baseUrl: ctx.baseUrl }, "cli");
1658
+ const sdk = createKbSdk(ctx, "");
1659
+ const input = {};
1660
+ if (opts.id !== void 0) {
1661
+ input.id = opts.id;
1662
+ }
1663
+ if (opts.name !== void 0) {
1664
+ input.name = opts.name;
1665
+ }
1666
+ if (opts.description !== void 0) {
1667
+ input.description = opts.description;
1668
+ }
1669
+ try {
1670
+ const created = await sdk.spaceApi.create(
1671
+ Object.keys(input).length > 0 ? input : void 0
1672
+ );
1673
+ writeCommandSuccess(ctx.deps.stdout, successJson(created));
1674
+ exitRef.code = 0;
1675
+ } catch (e) {
1676
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(e));
1677
+ exitRef.code = 1;
1678
+ }
1679
+ });
1680
+ space.command("update").description("Update a space").argument("<id>", "Space id").option("--name <name>", "Display name").option("--description <text>", "Description").action(async (id, opts) => {
1681
+ const ctx = createKbCliContext(deps, rootProgram);
1682
+ ctx.logger.debug({ baseUrl: ctx.baseUrl }, "cli");
1683
+ const sdk = createKbSdk(ctx, "");
1684
+ const patch = {};
1685
+ if (opts.name !== void 0) {
1686
+ patch.name = opts.name;
1687
+ }
1688
+ if (opts.description !== void 0) {
1689
+ patch.description = opts.description;
1690
+ }
1691
+ try {
1692
+ const updated = await sdk.spaceApi.update(id, patch);
1693
+ writeCommandSuccess(ctx.deps.stdout, successJson(updated));
1694
+ exitRef.code = 0;
1695
+ } catch (e) {
1696
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(e));
1697
+ exitRef.code = 1;
1698
+ }
1699
+ });
1700
+ space.command("get").description("Get a space by id").argument("<id>", "Space id").action(async (id) => {
1701
+ const ctx = createKbCliContext(deps, rootProgram);
1702
+ ctx.logger.debug({ baseUrl: ctx.baseUrl }, "cli");
1703
+ const sdk = createKbSdk(ctx, "");
1704
+ try {
1705
+ const row = await sdk.spaceApi.get(id);
1706
+ writeCommandSuccess(ctx.deps.stdout, successJson(row));
1707
+ exitRef.code = 0;
1708
+ } catch (e) {
1709
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(e));
1710
+ exitRef.code = 1;
1711
+ }
1712
+ });
1713
+ space.command("delete").description("Delete a space").argument("<id>", "Space id").action(async (id) => {
1714
+ const ctx = createKbCliContext(deps, rootProgram);
1715
+ ctx.logger.debug({ baseUrl: ctx.baseUrl }, "cli");
1716
+ const sdk = createKbSdk(ctx, "");
1717
+ try {
1718
+ await sdk.spaceApi.delete(id);
1719
+ writeCommandSuccess(ctx.deps.stdout, successVoid());
1720
+ exitRef.code = 0;
1721
+ } catch (e) {
1722
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(e));
1723
+ exitRef.code = 1;
1724
+ }
1725
+ });
1726
+ space.command("list").description("List spaces").action(async () => {
1727
+ const ctx = createKbCliContext(deps, rootProgram);
1728
+ ctx.logger.debug({ baseUrl: ctx.baseUrl }, "cli");
1729
+ const sdk = createKbSdk(ctx, "");
1730
+ try {
1731
+ const spaces = await sdk.spaceApi.list();
1732
+ writeCommandSuccess(ctx.deps.stdout, successJson({ spaces }));
1733
+ exitRef.code = 0;
1734
+ } catch (e) {
1735
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(e));
1736
+ exitRef.code = 1;
1737
+ }
1738
+ });
1739
+ }
1740
+
1741
+ // src/commands/store/store.ts
1742
+ import { readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
1743
+
1744
+ // src/commands/store/store-cli-output.ts
1745
+ function storeResourceToCliOutput(row, spaceId) {
1746
+ const id = row.id;
1747
+ return {
1748
+ storeId: id,
1749
+ storeName: row.name,
1750
+ storeDescription: row.description,
1751
+ storeReadOnly: row.readOnly,
1752
+ storeCreatedAt: row.createdAt,
1753
+ storeUpdatedAt: row.updatedAt,
1754
+ path: formatKbUri(spaceId, id)
1755
+ };
1756
+ }
1757
+
1758
+ // src/commands/store/store.ts
1759
+ function registerStoreCommands(store, rootProgram, deps, exitRef) {
1760
+ store.command("create").description("Create a store in the current space").option("--id <id>", "Explicit store id").option("--name <name>", "Display name").option("--description <text>", "Description").option("--read-only", "Create store in read-only mode", false).action(
1761
+ async (opts) => {
1762
+ const ctx = createKbCliContext(deps, rootProgram);
1763
+ const spaceId = await requireSpaceId(rootProgram, deps, ctx.baseUrl);
1764
+ if (spaceId === null) {
1765
+ exitRef.code = 1;
1766
+ return;
1767
+ }
1768
+ const sdk = createKbSdk(ctx, spaceId);
1769
+ const input = {};
1770
+ if (opts.id !== void 0) {
1771
+ input.id = opts.id;
1772
+ }
1773
+ if (opts.name !== void 0) {
1774
+ input.name = opts.name;
1775
+ }
1776
+ if (opts.description !== void 0) {
1777
+ input.description = opts.description;
1778
+ }
1779
+ if (opts.readOnly === true) {
1780
+ input.readOnly = true;
1781
+ }
1782
+ try {
1783
+ const created = await sdk.storeApi.create(
1784
+ Object.keys(input).length > 0 ? input : void 0
1785
+ );
1786
+ writeStdoutPrettyJson(ctx.deps.stdout, storeResourceToCliOutput(created, spaceId));
1787
+ exitRef.code = 0;
1788
+ } catch (e) {
1789
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(e));
1790
+ exitRef.code = 1;
1791
+ }
1792
+ }
1793
+ );
1794
+ store.command("update").description("Update a store").argument("<storeId>", "Store id").option("--name <name>", "Display name").option("--description <text>", "Description").action(async (storeId, opts) => {
1795
+ const ctx = createKbCliContext(deps, rootProgram);
1796
+ const spaceId = await requireSpaceId(rootProgram, deps, ctx.baseUrl);
1797
+ if (spaceId === null) {
1798
+ exitRef.code = 1;
1799
+ return;
1800
+ }
1801
+ const sdk = createKbSdk(ctx, spaceId);
1802
+ const patch = {};
1803
+ if (opts.name !== void 0) {
1804
+ patch.name = opts.name;
1805
+ }
1806
+ if (opts.description !== void 0) {
1807
+ patch.description = opts.description;
1808
+ }
1809
+ try {
1810
+ const updated = await sdk.storeApi.update(storeId, patch);
1811
+ writeStdoutPrettyJson(ctx.deps.stdout, storeResourceToCliOutput(updated, spaceId));
1812
+ exitRef.code = 0;
1813
+ } catch (e) {
1814
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(e));
1815
+ exitRef.code = 1;
1816
+ }
1817
+ });
1818
+ store.command("get").description("Get a store by id").argument("<storeId>", "Store id").action(async (storeId) => {
1819
+ const ctx = createKbCliContext(deps, rootProgram);
1820
+ const spaceId = await requireSpaceId(rootProgram, deps, ctx.baseUrl);
1821
+ if (spaceId === null) {
1822
+ exitRef.code = 1;
1823
+ return;
1824
+ }
1825
+ const sdk = createKbSdk(ctx, spaceId);
1826
+ try {
1827
+ const row = await sdk.storeApi.get(storeId);
1828
+ writeStdoutPrettyJson(ctx.deps.stdout, storeResourceToCliOutput(row, spaceId));
1829
+ exitRef.code = 0;
1830
+ } catch (e) {
1831
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(e));
1832
+ exitRef.code = 1;
1833
+ }
1834
+ });
1835
+ store.command("delete").description("Delete a store").argument("<storeId>", "Store id").action(async (storeId) => {
1836
+ const ctx = createKbCliContext(deps, rootProgram);
1837
+ const spaceId = await requireSpaceId(rootProgram, deps, ctx.baseUrl);
1838
+ if (spaceId === null) {
1839
+ exitRef.code = 1;
1840
+ return;
1841
+ }
1842
+ const sdk = createKbSdk(ctx, spaceId);
1843
+ try {
1844
+ await sdk.storeApi.delete(storeId);
1845
+ exitRef.code = 0;
1846
+ } catch (e) {
1847
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(e));
1848
+ exitRef.code = 1;
1849
+ }
1850
+ });
1851
+ store.command("list").description("List stores in the current space").action(async () => {
1852
+ const ctx = createKbCliContext(deps, rootProgram);
1853
+ const spaceId = await requireSpaceId(rootProgram, deps, ctx.baseUrl);
1854
+ if (spaceId === null) {
1855
+ exitRef.code = 1;
1856
+ return;
1857
+ }
1858
+ const sdk = createKbSdk(ctx, spaceId);
1859
+ try {
1860
+ const rows = await sdk.storeApi.list();
1861
+ const out = {
1862
+ stores: rows.map((r) => storeResourceToCliOutput(r, spaceId))
1863
+ };
1864
+ writeStdoutPrettyJson(ctx.deps.stdout, out);
1865
+ exitRef.code = 0;
1866
+ } catch (e) {
1867
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(e));
1868
+ exitRef.code = 1;
1869
+ }
1870
+ });
1871
+ store.command("upload").description("Upload a local file into a store path (kb://spaceId/storeId/path)").requiredOption("--file <path>", "Local file path").requiredOption("--to <uri>", "Destination kb://\u2026 URI").action(async (opts) => {
1872
+ const ctx = createKbCliContext(deps, rootProgram);
1873
+ const spaceId = await requireSpaceId(rootProgram, deps, ctx.baseUrl);
1874
+ if (spaceId === null) {
1875
+ exitRef.code = 1;
1876
+ return;
1877
+ }
1878
+ let storeId;
1879
+ let destPath;
1880
+ try {
1881
+ const u = parseKbUri(opts.to);
1882
+ if (u.storeId === void 0) {
1883
+ deps.stderr.write(
1884
+ `${JSON.stringify({
1885
+ code: "VALIDATION_ERROR",
1886
+ message: "upload --to must include a storeId (kb://<spaceId>/<storeId>/<path>)",
1887
+ details: null
1888
+ })}
1889
+ `
1890
+ );
1891
+ exitRef.code = 1;
1892
+ return;
1893
+ }
1894
+ storeId = u.storeId;
1895
+ destPath = u.path;
1896
+ } catch (e) {
1897
+ const msg = e instanceof Error ? e.message : String(e);
1898
+ deps.stderr.write(
1899
+ `${JSON.stringify({ code: "VALIDATION_ERROR", message: msg, details: null })}
1900
+ `
1901
+ );
1902
+ exitRef.code = 1;
1903
+ return;
1904
+ }
1905
+ if (destPath.length === 0) {
1906
+ deps.stderr.write(
1907
+ `${JSON.stringify({
1908
+ code: "VALIDATION_ERROR",
1909
+ message: "upload --to must include a path after the store id (e.g. kb://spaceId/storeId/file.txt)",
1910
+ details: null
1911
+ })}
1912
+ `
1913
+ );
1914
+ exitRef.code = 1;
1915
+ return;
1916
+ }
1917
+ const sdk = createKbSdk(ctx, spaceId);
1918
+ try {
1919
+ const buf = await readFile3(opts.file);
1920
+ await sdk.storeApi.uploadFile({
1921
+ storeId,
1922
+ path: destPath,
1923
+ body: new Uint8Array(buf)
1924
+ });
1925
+ exitRef.code = 0;
1926
+ } catch (e) {
1927
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(e));
1928
+ exitRef.code = 1;
1929
+ }
1930
+ });
1931
+ store.command("download").description("Download a store file to a local path").requiredOption("--from <uri>", "Source kb://\u2026 URI").requiredOption("--to <path>", "Local file path").action(async (opts) => {
1932
+ const ctx = createKbCliContext(deps, rootProgram);
1933
+ const spaceId = await requireSpaceId(rootProgram, deps, ctx.baseUrl);
1934
+ if (spaceId === null) {
1935
+ exitRef.code = 1;
1936
+ return;
1937
+ }
1938
+ let storeId;
1939
+ let sourcePath;
1940
+ try {
1941
+ const u = parseKbUri(opts.from);
1942
+ if (u.storeId === void 0) {
1943
+ deps.stderr.write(
1944
+ `${JSON.stringify({
1945
+ code: "VALIDATION_ERROR",
1946
+ message: "download --from must include a storeId (kb://<spaceId>/<storeId>/<path>)",
1947
+ details: null
1948
+ })}
1949
+ `
1950
+ );
1951
+ exitRef.code = 1;
1952
+ return;
1953
+ }
1954
+ storeId = u.storeId;
1955
+ sourcePath = u.path;
1956
+ } catch (e) {
1957
+ const msg = e instanceof Error ? e.message : String(e);
1958
+ deps.stderr.write(
1959
+ `${JSON.stringify({ code: "VALIDATION_ERROR", message: msg, details: null })}
1960
+ `
1961
+ );
1962
+ exitRef.code = 1;
1963
+ return;
1964
+ }
1965
+ if (sourcePath.length === 0) {
1966
+ deps.stderr.write(
1967
+ `${JSON.stringify({
1968
+ code: "VALIDATION_ERROR",
1969
+ message: "download --from must include a path after the store id",
1970
+ details: null
1971
+ })}
1972
+ `
1973
+ );
1974
+ exitRef.code = 1;
1975
+ return;
1976
+ }
1977
+ const sdk = createKbSdk(ctx, spaceId);
1978
+ try {
1979
+ const bytes = await sdk.storeApi.downloadFile({ storeId, path: sourcePath });
1980
+ await writeFile2(opts.to, Buffer.from(bytes));
1981
+ exitRef.code = 0;
1982
+ } catch (e) {
1983
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(e));
1984
+ exitRef.code = 1;
1985
+ }
1986
+ });
1987
+ store.command("remove").description("Remove a file from a store (kb://spaceId/storeId/path)").requiredOption("--from <uri>", "kb://\u2026 URI of the file to remove").action(async (opts) => {
1988
+ const ctx = createKbCliContext(deps, rootProgram);
1989
+ const spaceId = await requireSpaceId(rootProgram, deps, ctx.baseUrl);
1990
+ if (spaceId === null) {
1991
+ exitRef.code = 1;
1992
+ return;
1993
+ }
1994
+ let storeId;
1995
+ let filePath;
1996
+ try {
1997
+ const u = parseKbUri(opts.from);
1998
+ if (u.storeId === void 0) {
1999
+ deps.stderr.write(
2000
+ `${JSON.stringify({
2001
+ code: "VALIDATION_ERROR",
2002
+ message: "remove --from must include a storeId (kb://<spaceId>/<storeId>/<path>)",
2003
+ details: null
2004
+ })}
2005
+ `
2006
+ );
2007
+ exitRef.code = 1;
2008
+ return;
2009
+ }
2010
+ storeId = u.storeId;
2011
+ filePath = u.path;
2012
+ } catch (e) {
2013
+ const msg = e instanceof Error ? e.message : String(e);
2014
+ deps.stderr.write(
2015
+ `${JSON.stringify({ code: "VALIDATION_ERROR", message: msg, details: null })}
2016
+ `
2017
+ );
2018
+ exitRef.code = 1;
2019
+ return;
2020
+ }
2021
+ if (filePath.length === 0) {
2022
+ deps.stderr.write(
2023
+ `${JSON.stringify({
2024
+ code: "VALIDATION_ERROR",
2025
+ message: "remove --from must include a path after the store id",
2026
+ details: null
2027
+ })}
2028
+ `
2029
+ );
2030
+ exitRef.code = 1;
2031
+ return;
2032
+ }
2033
+ const sdk = createKbSdk(ctx, spaceId);
2034
+ try {
2035
+ await sdk.storeApi.deleteFile({ storeId, path: filePath });
2036
+ exitRef.code = 0;
2037
+ } catch (e) {
2038
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(e));
2039
+ exitRef.code = 1;
2040
+ }
2041
+ });
2042
+ }
2043
+
2044
+ // src/commands/task/task.ts
2045
+ function appendStoreId(value, current) {
2046
+ return [...current, value];
2047
+ }
2048
+ function registerTaskCommands(task, rootProgram, deps, exitRef) {
2049
+ task.command("start").description("Start a task in the current space").option("--id <id>", "Explicit task id").option("--name <name>", "Display name").option("--description <text>", "Description").option("--readonly", "Start in readonly mode", false).option("--store <storeId>", "Bind store id to task runtime", appendStoreId, []).action(
2050
+ async (opts) => {
2051
+ const ctx = createKbCliContext(deps, rootProgram);
2052
+ const spaceId = await requireSpaceId(rootProgram, deps, ctx.baseUrl);
2053
+ if (spaceId === null) {
2054
+ exitRef.code = 1;
2055
+ return;
2056
+ }
2057
+ const sdk = createKbSdk(ctx, spaceId);
2058
+ const storeIds = opts.store ?? [];
2059
+ const input = storeIds.length > 0 ? { storeIds } : { all: true };
2060
+ if (opts.id !== void 0) {
2061
+ input.id = opts.id;
2062
+ }
2063
+ if (opts.name !== void 0) {
2064
+ input.name = opts.name;
2065
+ }
2066
+ if (opts.description !== void 0) {
2067
+ input.description = opts.description;
2068
+ }
2069
+ if (opts.readonly === true) {
2070
+ input.readonly = true;
2071
+ }
2072
+ try {
2073
+ const created = await sdk.taskApi.create(input);
2074
+ writeCommandSuccess(ctx.deps.stdout, successJson(created));
2075
+ exitRef.code = 0;
2076
+ } catch (error) {
2077
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(error));
2078
+ exitRef.code = 1;
2079
+ }
2080
+ }
2081
+ );
2082
+ task.command("get").description("Get a task by id").argument("[taskId]", "Task id (optional when --task or KB_TASK is set)").action(async (taskIdArg) => {
2083
+ const ctx = createKbCliContext(deps, rootProgram);
2084
+ const spaceId = await requireSpaceId(rootProgram, deps, ctx.baseUrl);
2085
+ if (spaceId === null) {
2086
+ exitRef.code = 1;
2087
+ return;
2088
+ }
2089
+ const taskId = requireTaskId(rootProgram, deps, taskIdArg);
2090
+ if (taskId === null) {
2091
+ exitRef.code = 1;
2092
+ return;
2093
+ }
2094
+ const sdk = createKbSdk(ctx, spaceId);
2095
+ try {
2096
+ const row = await sdk.taskApi.get(taskId);
2097
+ writeCommandSuccess(ctx.deps.stdout, successJson(row));
2098
+ exitRef.code = 0;
2099
+ } catch (error) {
2100
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(error));
2101
+ exitRef.code = 1;
2102
+ }
2103
+ });
2104
+ task.command("list").description("List tasks in the current space").action(async () => {
2105
+ const ctx = createKbCliContext(deps, rootProgram);
2106
+ const spaceId = await requireSpaceId(rootProgram, deps, ctx.baseUrl);
2107
+ if (spaceId === null) {
2108
+ exitRef.code = 1;
2109
+ return;
2110
+ }
2111
+ const sdk = createKbSdk(ctx, spaceId);
2112
+ try {
2113
+ const tasks = await sdk.taskApi.list();
2114
+ writeCommandSuccess(ctx.deps.stdout, successJson({ tasks }));
2115
+ exitRef.code = 0;
2116
+ } catch (error) {
2117
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(error));
2118
+ exitRef.code = 1;
2119
+ }
2120
+ });
2121
+ task.command("update").description("Update a task").argument("[taskId]", "Task id (optional when --task or KB_TASK is set)").option("--name <name>", "Display name").option("--description <text>", "Description").option("--clear-description", "Clear description", false).action(
2122
+ async (taskIdArg, opts) => {
2123
+ const ctx = createKbCliContext(deps, rootProgram);
2124
+ const spaceId = await requireSpaceId(rootProgram, deps, ctx.baseUrl);
2125
+ if (spaceId === null) {
2126
+ exitRef.code = 1;
2127
+ return;
2128
+ }
2129
+ const taskId = requireTaskId(rootProgram, deps, taskIdArg);
2130
+ if (taskId === null) {
2131
+ exitRef.code = 1;
2132
+ return;
2133
+ }
2134
+ const patch = {};
2135
+ if (opts.name !== void 0) {
2136
+ patch.name = opts.name;
2137
+ }
2138
+ if (opts.clearDescription === true) {
2139
+ patch.description = null;
2140
+ } else if (opts.description !== void 0) {
2141
+ patch.description = opts.description;
2142
+ }
2143
+ const sdk = createKbSdk(ctx, spaceId);
2144
+ try {
2145
+ const row = await sdk.taskApi.update(taskId, patch);
2146
+ writeCommandSuccess(ctx.deps.stdout, successJson(row));
2147
+ exitRef.code = 0;
2148
+ } catch (error) {
2149
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(error));
2150
+ exitRef.code = 1;
2151
+ }
2152
+ }
2153
+ );
2154
+ task.command("delete").description("Delete a task").argument("[taskId]", "Task id (optional when --task or KB_TASK is set)").action(async (taskIdArg) => {
2155
+ const ctx = createKbCliContext(deps, rootProgram);
2156
+ const spaceId = await requireSpaceId(rootProgram, deps, ctx.baseUrl);
2157
+ if (spaceId === null) {
2158
+ exitRef.code = 1;
2159
+ return;
2160
+ }
2161
+ const taskId = requireTaskId(rootProgram, deps, taskIdArg);
2162
+ if (taskId === null) {
2163
+ exitRef.code = 1;
2164
+ return;
2165
+ }
2166
+ const sdk = createKbSdk(ctx, spaceId);
2167
+ try {
2168
+ await sdk.taskApi.delete(taskId);
2169
+ writeCommandSuccess(ctx.deps.stdout, successVoid());
2170
+ exitRef.code = 0;
2171
+ } catch (error) {
2172
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(error));
2173
+ exitRef.code = 1;
2174
+ }
2175
+ });
2176
+ task.command("stop").description("Stop a task").argument("[taskId]", "Task id (optional when --task or KB_TASK is set)").action(async (taskIdArg) => {
2177
+ const ctx = createKbCliContext(deps, rootProgram);
2178
+ const spaceId = await requireSpaceId(rootProgram, deps, ctx.baseUrl);
2179
+ if (spaceId === null) {
2180
+ exitRef.code = 1;
2181
+ return;
2182
+ }
2183
+ const taskId = requireTaskId(rootProgram, deps, taskIdArg);
2184
+ if (taskId === null) {
2185
+ exitRef.code = 1;
2186
+ return;
2187
+ }
2188
+ const sdk = createKbSdk(ctx, spaceId);
2189
+ try {
2190
+ await sdk.taskApi.stop(taskId);
2191
+ writeCommandSuccess(ctx.deps.stdout, successVoid());
2192
+ exitRef.code = 0;
2193
+ } catch (error) {
2194
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(error));
2195
+ exitRef.code = 1;
2196
+ }
2197
+ });
2198
+ }
2199
+
2200
+ // src/auth/constants.ts
2201
+ var KB_DEVICE_CLIENT_ID = "knowbrain";
2202
+ var DEVICE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
2203
+
2204
+ // src/auth/device-oauth.ts
2205
+ function sleepDefault(ms) {
2206
+ return new Promise((resolve) => setTimeout(resolve, ms));
2207
+ }
2208
+ function authJsonHeaders(origin) {
2209
+ return {
2210
+ "content-type": "application/json",
2211
+ Origin: origin
2212
+ };
2213
+ }
2214
+ function deviceOAuthError(code2, message) {
2215
+ return { code: code2, message, details: null };
2216
+ }
2217
+ function mapTokenError(error, description) {
2218
+ switch (error) {
2219
+ case "expired_token":
2220
+ return deviceOAuthError(
2221
+ "AUTH_EXPIRED",
2222
+ description ?? "Device authorization expired. Run `kb login` again."
2223
+ );
2224
+ case "access_denied":
2225
+ return deviceOAuthError("AUTH_DENIED", description ?? "Sign-in was denied.");
2226
+ case "invalid_grant":
2227
+ case "invalid_client":
2228
+ return deviceOAuthError(
2229
+ "AUTH_FAILED",
2230
+ description ?? "Device authorization failed. Run `kb login` again."
2231
+ );
2232
+ default:
2233
+ return deviceOAuthError("AUTH_FAILED", description ?? error);
2234
+ }
2235
+ }
2236
+ async function parseJsonBody(res) {
2237
+ const text = await res.text();
2238
+ if (text.trim() === "") {
2239
+ return null;
2240
+ }
2241
+ try {
2242
+ return JSON.parse(text);
2243
+ } catch {
2244
+ return null;
2245
+ }
2246
+ }
2247
+ async function requestDeviceCode(fetchFn, origin) {
2248
+ const res = await fetchFn(`${origin}/api/auth/device/code`, {
2249
+ method: "POST",
2250
+ headers: authJsonHeaders(origin),
2251
+ body: JSON.stringify({ client_id: KB_DEVICE_CLIENT_ID })
2252
+ });
2253
+ const body = await parseJsonBody(res);
2254
+ if (!res.ok) {
2255
+ const o2 = body && typeof body === "object" && !Array.isArray(body) ? body : {};
2256
+ const err = typeof o2["error"] === "string" ? o2["error"] : void 0;
2257
+ if (err === "invalid_client") {
2258
+ throw mapTokenError("invalid_client");
2259
+ }
2260
+ throw deviceOAuthError("AUTH_FAILED", `Device code request failed (HTTP ${res.status})`);
2261
+ }
2262
+ const o = body;
2263
+ if (typeof o["device_code"] !== "string" || typeof o["user_code"] !== "string" || typeof o["verification_uri_complete"] !== "string" || typeof o["expires_in"] !== "number" || typeof o["interval"] !== "number") {
2264
+ throw deviceOAuthError("INTERNAL", "Invalid device code response");
2265
+ }
2266
+ if (!Number.isFinite(o["expires_in"]) || o["expires_in"] <= 0) {
2267
+ throw deviceOAuthError("INTERNAL", "Invalid device code response");
2268
+ }
2269
+ if (!Number.isFinite(o["interval"]) || o["interval"] < 0) {
2270
+ throw deviceOAuthError("INTERNAL", "Invalid device code response");
2271
+ }
2272
+ return {
2273
+ device_code: o["device_code"],
2274
+ user_code: o["user_code"],
2275
+ verification_uri: typeof o["verification_uri"] === "string" ? o["verification_uri"] : "",
2276
+ verification_uri_complete: o["verification_uri_complete"],
2277
+ expires_in: o["expires_in"],
2278
+ interval: o["interval"]
2279
+ };
2280
+ }
2281
+ async function pollDeviceToken(fetchFn, origin, deviceCode, options) {
2282
+ const sleepFn = options.sleep ?? sleepDefault;
2283
+ const nowFn = options.now ?? (() => Date.now());
2284
+ if (!Number.isFinite(options.expiresInSec) || options.expiresInSec <= 0) {
2285
+ throw deviceOAuthError("INTERNAL", "Invalid device token poll expiry");
2286
+ }
2287
+ if (!Number.isFinite(options.intervalSec) || options.intervalSec < 0) {
2288
+ throw deviceOAuthError("INTERNAL", "Invalid device token poll interval");
2289
+ }
2290
+ const deadline = nowFn() + options.expiresInSec * 1e3;
2291
+ let intervalSec = options.intervalSec;
2292
+ while (true) {
2293
+ const nowBeforeSleep = nowFn();
2294
+ if (nowBeforeSleep >= deadline) {
2295
+ throw mapTokenError("expired_token");
2296
+ }
2297
+ const intervalMs = intervalSec * 1e3;
2298
+ const sleepMs = Number.isFinite(intervalMs) ? Math.min(Math.max(intervalMs, 0), deadline - nowBeforeSleep) : deadline - nowBeforeSleep;
2299
+ await sleepFn(sleepMs);
2300
+ const res = await fetchFn(`${origin}/api/auth/device/token`, {
2301
+ method: "POST",
2302
+ headers: authJsonHeaders(origin),
2303
+ body: JSON.stringify({
2304
+ grant_type: DEVICE_GRANT_TYPE,
2305
+ device_code: deviceCode,
2306
+ client_id: KB_DEVICE_CLIENT_ID
2307
+ })
2308
+ });
2309
+ const body = await parseJsonBody(res);
2310
+ if (body && typeof body === "object" && !Array.isArray(body)) {
2311
+ const o = body;
2312
+ if (typeof o["access_token"] === "string" && typeof o["expires_in"] === "number") {
2313
+ const success = {
2314
+ access_token: o["access_token"],
2315
+ token_type: typeof o["token_type"] === "string" ? o["token_type"] : "Bearer",
2316
+ expires_in: o["expires_in"]
2317
+ };
2318
+ if (typeof o["scope"] === "string") {
2319
+ success.scope = o["scope"];
2320
+ }
2321
+ return success;
2322
+ }
2323
+ if (typeof o["error"] === "string") {
2324
+ if (o["error"] === "authorization_pending") {
2325
+ continue;
2326
+ }
2327
+ if (o["error"] === "slow_down") {
2328
+ intervalSec += 5;
2329
+ continue;
2330
+ }
2331
+ throw mapTokenError(
2332
+ o["error"],
2333
+ typeof o["error_description"] === "string" ? o["error_description"] : void 0
2334
+ );
2335
+ }
2336
+ }
2337
+ if (!res.ok && res.status !== 400) {
2338
+ throw deviceOAuthError("AUTH_FAILED", `Token poll failed (HTTP ${res.status})`);
2339
+ }
2340
+ }
2341
+ }
2342
+ async function fetchSessionProfile(fetchFn, origin, accessToken) {
2343
+ const res = await fetchFn(`${origin}/api/auth/get-session`, {
2344
+ method: "GET",
2345
+ headers: {
2346
+ Authorization: `Bearer ${accessToken}`,
2347
+ Origin: origin
2348
+ }
2349
+ });
2350
+ if (!res.ok) {
2351
+ return {};
2352
+ }
2353
+ const body = await parseJsonBody(res);
2354
+ if (!body || typeof body !== "object" || Array.isArray(body)) {
2355
+ return {};
2356
+ }
2357
+ const user = body["user"];
2358
+ if (!user || typeof user !== "object" || Array.isArray(user)) {
2359
+ return {};
2360
+ }
2361
+ const profile = {};
2362
+ const email = user["email"];
2363
+ if (typeof email === "string") {
2364
+ profile.email = email;
2365
+ }
2366
+ const spaceId = user["id"];
2367
+ if (typeof spaceId === "string" && spaceId.length > 0) {
2368
+ profile.spaceId = spaceId;
2369
+ }
2370
+ return profile;
2371
+ }
2372
+ async function runDeviceLogin(baseUrl, options = {}) {
2373
+ const fetchFn = options.fetch ?? globalThis.fetch.bind(globalThis);
2374
+ const stderr = options.stderr ?? process.stderr;
2375
+ const origin = resolveAuthOrigin(baseUrl);
2376
+ const logger = options.logger;
2377
+ logger?.debug({ origin }, "device login start");
2378
+ const codeResponse = await requestDeviceCode(fetchFn, origin);
2379
+ stderr.write(`Open this link to sign in:
2380
+ ${codeResponse.verification_uri_complete}
2381
+
2382
+ `);
2383
+ stderr.write(`Or enter code: ${codeResponse.user_code}
2384
+
2385
+ `);
2386
+ stderr.write("Waiting for approval\u2026\n");
2387
+ if (options.openBrowser) {
2388
+ try {
2389
+ await options.openBrowser(codeResponse.verification_uri_complete);
2390
+ } catch (cause) {
2391
+ logger?.warn({ cause }, "could not open browser");
2392
+ }
2393
+ }
2394
+ const pollOptions = {
2395
+ intervalSec: codeResponse.interval,
2396
+ expiresInSec: codeResponse.expires_in,
2397
+ stderr
2398
+ };
2399
+ if (options.sleep !== void 0) {
2400
+ pollOptions.sleep = options.sleep;
2401
+ }
2402
+ if (options.now !== void 0) {
2403
+ pollOptions.now = options.now;
2404
+ }
2405
+ const token = await pollDeviceToken(fetchFn, origin, codeResponse.device_code, pollOptions);
2406
+ const nowFn = options.now ?? (() => Date.now());
2407
+ const profile = await fetchSessionProfile(fetchFn, origin, token.access_token);
2408
+ if (profile.spaceId === void 0) {
2409
+ throw deviceOAuthError("INTERNAL", "Invalid get-session response: missing user id");
2410
+ }
2411
+ const credentials = {
2412
+ accessToken: token.access_token,
2413
+ expiresAt: new Date(nowFn() + token.expires_in * 1e3).toISOString(),
2414
+ origin,
2415
+ spaceId: profile.spaceId
2416
+ };
2417
+ await saveCredentials(credentials, options);
2418
+ if (profile.email) {
2419
+ stderr.write(`Signed in as ${profile.email}
2420
+ `);
2421
+ } else {
2422
+ stderr.write("Signed in.\n");
2423
+ }
2424
+ logger?.info({ origin }, "device login ok");
2425
+ const result = { credentials, spaceId: profile.spaceId };
2426
+ if (profile.email !== void 0) {
2427
+ result.userEmail = profile.email;
2428
+ }
2429
+ return result;
2430
+ }
2431
+
2432
+ // src/auth/open-url.ts
2433
+ import { execFile } from "child_process";
2434
+ import { promisify } from "util";
2435
+ var execFileAsync = promisify(execFile);
2436
+ async function openUrlInBrowser(url) {
2437
+ const platform = process.platform;
2438
+ if (platform === "darwin") {
2439
+ await execFileAsync("open", [url]);
2440
+ return;
2441
+ }
2442
+ if (platform === "win32") {
2443
+ await execFileAsync("cmd", ["/c", "start", "", url]);
2444
+ return;
2445
+ }
2446
+ await execFileAsync("xdg-open", [url]);
2447
+ }
2448
+
2449
+ // src/commands/login.ts
2450
+ function isCliErrorJson(err) {
2451
+ return err !== null && typeof err === "object" && "code" in err && typeof err.code === "string" && "message" in err && typeof err.message === "string";
2452
+ }
2453
+ function registerLoginCommand(program, rootProgram, deps, exitRef) {
2454
+ program.command("login").description("Sign in via device authorization (browser)").action(async () => {
2455
+ const ctx = createKbCliContext(deps, rootProgram);
2456
+ ctx.logger.debug({ baseUrl: ctx.baseUrl }, "cli login start");
2457
+ try {
2458
+ await runDeviceLogin(ctx.baseUrl, {
2459
+ fetch: ctx.deps.fetch,
2460
+ stderr: ctx.deps.stderr,
2461
+ logger: ctx.logger,
2462
+ openBrowser: openUrlInBrowser
2463
+ });
2464
+ writeCommandSuccess(ctx.deps.stdout, successVoid());
2465
+ exitRef.code = 0;
2466
+ } catch (e) {
2467
+ ctx.logger.error({ err: e }, "cli login failed");
2468
+ if (isCliErrorJson(e)) {
2469
+ writeCliError(ctx.deps.stderr, e);
2470
+ } else {
2471
+ const message = e instanceof Error ? e.message : String(e);
2472
+ writeCliError(ctx.deps.stderr, { code: "INTERNAL", message, details: null });
2473
+ }
2474
+ exitRef.code = 1;
2475
+ }
2476
+ });
2477
+ }
2478
+ function registerLogoutCommand(program, rootProgram, deps, exitRef) {
2479
+ program.command("logout").description("Remove stored sign-in credentials").action(async () => {
2480
+ const ctx = createKbCliContext(deps, rootProgram);
2481
+ ctx.logger.debug("cli logout start");
2482
+ try {
2483
+ await clearCredentials();
2484
+ ctx.logger.info("cli logout ok");
2485
+ writeCommandSuccess(ctx.deps.stdout, successVoid());
2486
+ exitRef.code = 0;
2487
+ } catch (e) {
2488
+ ctx.logger.error({ err: e }, "cli logout failed");
2489
+ const message = e instanceof Error ? e.message : String(e);
2490
+ writeCliError(ctx.deps.stderr, { code: "INTERNAL", message, details: null });
2491
+ exitRef.code = 1;
2492
+ }
2493
+ });
2494
+ }
2495
+
2496
+ // src/commands/wait-sync.ts
2497
+ function registerWaitSyncCommand(program, rootProgram, deps, exitRef) {
2498
+ program.command("waitSync").description("Wait for memory sync for a store (OpenViking)").requiredOption("--store <uri>", "kb://<spaceId>/<storeId> (path segment optional)").action(async (opts) => {
2499
+ const ctx = createKbCliContext(deps, rootProgram);
2500
+ const spaceId = await requireSpaceId(rootProgram, deps, ctx.baseUrl);
2501
+ if (spaceId === null) {
2502
+ exitRef.code = 1;
2503
+ return;
2504
+ }
2505
+ let storeId;
2506
+ try {
2507
+ const u = parseKbUri(opts.store);
2508
+ if (u.storeId === void 0) {
2509
+ deps.stderr.write(
2510
+ `${JSON.stringify({
2511
+ code: "VALIDATION_ERROR",
2512
+ message: "--store must include a storeId (kb://<spaceId>/<storeId>)",
2513
+ details: null
2514
+ })}
2515
+ `
2516
+ );
2517
+ exitRef.code = 1;
2518
+ return;
2519
+ }
2520
+ storeId = u.storeId;
2521
+ } catch (e) {
2522
+ const msg = e instanceof Error ? e.message : String(e);
2523
+ deps.stderr.write(
2524
+ `${JSON.stringify({ code: "VALIDATION_ERROR", message: msg, details: null })}
2525
+ `
2526
+ );
2527
+ exitRef.code = 1;
2528
+ return;
2529
+ }
2530
+ const sdk = createKbSdk(ctx, spaceId);
2531
+ try {
2532
+ await sdk.storeApi.waitSync(storeId);
2533
+ writeCommandSuccess(ctx.deps.stdout, successVoid());
2534
+ exitRef.code = 0;
2535
+ } catch (e) {
2536
+ writeCliError(ctx.deps.stderr, cliErrorFromUnknown(e));
2537
+ exitRef.code = 1;
2538
+ }
2539
+ });
2540
+ }
2541
+
2542
+ // src/cli/program.ts
2543
+ function buildProgram(deps, exitRef) {
2544
+ const program = new Command();
2545
+ program.name("kb");
2546
+ program.option("--base-url <url>", "API base URL", deps.env["KB_BASE_URL"] ?? DEFAULT_BASE_URL).option("--log-level <level>", "stderr log level (error|warn|info|debug)", "error").option(
2547
+ "--space <id>",
2548
+ "Default space id (overrides KB_SPACE and login credentials)",
2549
+ deps.env["KB_SPACE"]
2550
+ );
2551
+ program.option(
2552
+ "--task <id>",
2553
+ "Default task id for task/proposal/shell/diff commands (overrides KB_TASK)",
2554
+ deps.env["KB_TASK"]
2555
+ );
2556
+ registerLoginCommand(program, program, deps, exitRef);
2557
+ registerLogoutCommand(program, program, deps, exitRef);
2558
+ const space = program.command("space").description("Manage spaces");
2559
+ registerSpaceCommands(space, program, deps, exitRef);
2560
+ const store = program.command("store").description("Manage stores (space from --space, KB_SPACE, or kb login credentials)");
2561
+ registerStoreCommands(store, program, deps, exitRef);
2562
+ const connectors = program.command("connectors").description("Manage connectors (space from --space, KB_SPACE, or kb login credentials)");
2563
+ registerConnectorCommands(connectors, program, deps, exitRef);
2564
+ const task = program.command("task").description("Manage tasks (space from --space, KB_SPACE, or kb login credentials)");
2565
+ registerTaskCommands(task, program, deps, exitRef);
2566
+ const proposal = program.command("proposal").description("Manage proposals in the current task");
2567
+ registerProposalCommands(proposal, program, deps, exitRef);
2568
+ registerWaitSyncCommand(program, program, deps, exitRef);
2569
+ registerSearchCommand(program, program, deps, exitRef);
2570
+ registerShellCommand(program, program, deps, exitRef);
2571
+ registerDiffCommand(program, program, deps, exitRef);
2572
+ return program;
2573
+ }
2574
+
2575
+ // src/cli/run.ts
2576
+ function validationError(message) {
2577
+ return { code: "VALIDATION_ERROR", message, details: null };
2578
+ }
2579
+ function printUsage(stderr) {
2580
+ stderr.write(`Usage:
2581
+ kb login
2582
+ kb logout
2583
+ kb [--base-url <url>] [--log-level <level>] [--space <id>] space create ...
2584
+ kb [--base-url <url>] [--log-level <level>] [--space <id>] store create [--name <name>] ...
2585
+ kb [--base-url <url>] [--log-level <level>] [--space <id>] waitSync --store <kb://...>
2586
+
2587
+ Environment:
2588
+ KB_BASE_URL Service origin (default ${DEFAULT_BASE_URL})
2589
+ KB_API_PATH_PREFIX Resource API path prefix (default /api/knowbrain; empty for direct OMI)
2590
+ KB_SPACE Default space id when --space is omitted (overrides login credentials)
2591
+ `);
2592
+ }
2593
+ async function runKbCli(argv, deps = defaultKbCliDeps) {
2594
+ if (argv.length === 0) {
2595
+ printUsage(deps.stderr);
2596
+ return 1;
2597
+ }
2598
+ const exitRef = { code: 0 };
2599
+ const program = buildProgram(deps, exitRef);
2600
+ program.exitOverride();
2601
+ program.showHelpAfterError(false);
2602
+ try {
2603
+ await program.parseAsync(argv, { from: "user" });
2604
+ return exitRef.code;
2605
+ } catch (e) {
2606
+ if (e instanceof CommanderError) {
2607
+ if (e.exitCode === 0) {
2608
+ return 0;
2609
+ }
2610
+ writeCliError(deps.stderr, validationError(e.message));
2611
+ return e.exitCode;
2612
+ }
2613
+ const message = e instanceof Error ? e.message : String(e);
2614
+ writeCliError(deps.stderr, { code: "INTERNAL", message, details: null });
2615
+ return 1;
2616
+ }
2617
+ }
2618
+
2619
+ // src/main.ts
2620
+ var code = await runKbCli(process.argv.slice(2));
2621
+ process.exit(code);
2622
+ //# sourceMappingURL=kb.js.map