@sift-wiki/cli 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +30 -0
  2. package/dist/bin/sift.js +3497 -0
  3. package/package.json +29 -0
@@ -0,0 +1,3497 @@
1
+ #!/usr/bin/env node
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __esm = (fn, res) => function __init() {
5
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
6
+ };
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+
12
+ // ../tools/dist/inputParsers.js
13
+ function parseCaptureFile(input) {
14
+ return {
15
+ sourceName: requireString(input, "sourceName"),
16
+ externalId: requireString(input, "externalId"),
17
+ title: requireString(input, "title"),
18
+ filename: requireString(input, "filename"),
19
+ contentType: requireString(input, "contentType"),
20
+ bytes: requireBytes(input, "bytes"),
21
+ visibility: requireStringArray(input, "visibility")
22
+ };
23
+ }
24
+ function parseCaptureText(input) {
25
+ return {
26
+ sourceName: requireString(input, "sourceName"),
27
+ externalId: requireString(input, "externalId"),
28
+ title: requireString(input, "title"),
29
+ markdown: requireCaptureMarkdown(input, "markdown"),
30
+ visibility: requireStringArray(input, "visibility")
31
+ };
32
+ }
33
+ function parseCaptureBatch(input) {
34
+ const rawItems = input.items;
35
+ if (!Array.isArray(rawItems) || rawItems.length === 0) {
36
+ throw new Error("items must be a non-empty array.");
37
+ }
38
+ if (rawItems.length > 20) {
39
+ throw new Error("items must contain no more than 20 captures.");
40
+ }
41
+ return {
42
+ items: rawItems.map((item, index) => parseCaptureBatchItem(item, index))
43
+ };
44
+ }
45
+ function parseCaptureBatchItem(item, index) {
46
+ const record = requireRecord(item, `items[${index}]`);
47
+ const kind = requireString(record, "kind");
48
+ if (kind === "text") {
49
+ return { kind, ...parseCaptureText(record) };
50
+ }
51
+ if (kind === "file") {
52
+ return { kind, ...parseCaptureFile(record) };
53
+ }
54
+ throw new Error(`items[${index}].kind must be text or file.`);
55
+ }
56
+ function parseSourceCreate(input) {
57
+ return {
58
+ name: requireString(input, "name"),
59
+ visibility: requireStringArray(input, "visibility")
60
+ };
61
+ }
62
+ function parseSearchQuery(input) {
63
+ return {
64
+ query: requireString(input, "query"),
65
+ limit: requireInteger(input, "limit", 10)
66
+ };
67
+ }
68
+ function parseContextQuery(input) {
69
+ return {
70
+ query: requireString(input, "query"),
71
+ maxChars: requireInteger(input, "maxChars", 4e3)
72
+ };
73
+ }
74
+ function parseProfileQuery(input) {
75
+ return {
76
+ query: optionalString(input, "query"),
77
+ limit: optionalInteger(input, "limit")
78
+ };
79
+ }
80
+ function parseToolsSearch(input) {
81
+ const result2 = {
82
+ intent: requireString(input, "intent")
83
+ };
84
+ if (input.toolsetNames !== void 0) {
85
+ result2.toolsetNames = requireStringArray(input, "toolsetNames");
86
+ }
87
+ if (input.limit !== void 0) {
88
+ const limit = optionalInteger(input, "limit");
89
+ if (limit === void 0 || limit < 1 || limit > 20) {
90
+ throw new Error("limit must be an integer between 1 and 20.");
91
+ }
92
+ result2.limit = limit;
93
+ }
94
+ return result2;
95
+ }
96
+ function parseDecision(input) {
97
+ return {
98
+ statement: requireString(input, "statement"),
99
+ state: requireDecisionState(input, "state"),
100
+ rationale: optionalString(input, "rationale"),
101
+ authorship: optionalString(input, "authorship"),
102
+ evidenceIds: optionalStringArray(input, "evidenceIds"),
103
+ visibility: requireStringArray(input, "visibility")
104
+ };
105
+ }
106
+ function parseTask(input) {
107
+ return {
108
+ title: requireString(input, "title"),
109
+ status: optionalTaskStatus(input, "status"),
110
+ owner: optionalString(input, "owner"),
111
+ dueDate: optionalString(input, "dueDate"),
112
+ rationale: optionalString(input, "rationale"),
113
+ authorship: optionalString(input, "authorship"),
114
+ evidenceIds: optionalStringArray(input, "evidenceIds"),
115
+ visibility: requireStringArray(input, "visibility")
116
+ };
117
+ }
118
+ function parseMarkdownRecord(input) {
119
+ return {
120
+ recordType: requireString(input, "recordType"),
121
+ title: requireString(input, "title"),
122
+ markdown: requireString(input, "markdown"),
123
+ visibility: requireStringArray(input, "visibility")
124
+ };
125
+ }
126
+ function parseRecordRead(input) {
127
+ return {
128
+ recordId: requireString(input, "recordId"),
129
+ sectionAnchor: optionalString(input, "sectionAnchor")
130
+ };
131
+ }
132
+ function parseRecordSectionPatch(input) {
133
+ return {
134
+ recordId: requireString(input, "recordId"),
135
+ anchor: requireString(input, "anchor"),
136
+ replacementMarkdown: requireString(input, "replacementMarkdown"),
137
+ expectedMarkdown: optionalString(input, "expectedMarkdown")
138
+ };
139
+ }
140
+ function parseAuditEvents(input) {
141
+ return { targetId: optionalString(input, "targetId") };
142
+ }
143
+ function requireString(input, key) {
144
+ const value = input[key];
145
+ if (typeof value !== "string" || value.trim().length === 0) {
146
+ throw new Error(`${key} is required.`);
147
+ }
148
+ return value;
149
+ }
150
+ function requireCaptureMarkdown(input, key) {
151
+ const markdown = requireString(input, key);
152
+ if (textEncoder.encode(markdown).byteLength > MAX_CAPTURE_MARKDOWN_BYTES) {
153
+ throw new Error(`${key} must be no more than ${MAX_CAPTURE_MARKDOWN_BYTES} UTF-8 bytes. Use capture.file for larger material.`);
154
+ }
155
+ return markdown;
156
+ }
157
+ function optionalString(input, key) {
158
+ const value = input[key];
159
+ if (value === void 0) {
160
+ return void 0;
161
+ }
162
+ if (typeof value !== "string") {
163
+ throw new Error(`${key} must be a string.`);
164
+ }
165
+ const trimmed = value.trim();
166
+ return trimmed.length === 0 ? void 0 : trimmed;
167
+ }
168
+ function optionalTaskStatus(input, key) {
169
+ const value = input[key];
170
+ if (value === void 0) {
171
+ return void 0;
172
+ }
173
+ if (value !== "open" && value !== "in_progress" && value !== "done") {
174
+ throw new Error(`${key} must be open, in_progress, or done.`);
175
+ }
176
+ return value;
177
+ }
178
+ function requireDecisionState(input, key) {
179
+ const value = input[key];
180
+ if (value !== "proposed" && value !== "accepted" && value !== "rejected" && value !== "superseded") {
181
+ throw new Error(`${key} must be proposed, accepted, rejected, or superseded.`);
182
+ }
183
+ return value;
184
+ }
185
+ function requireStringArray(input, key) {
186
+ const value = input[key];
187
+ if (!Array.isArray(value) || !value.every((item) => typeof item === "string")) {
188
+ throw new Error(`${key} must be a string array.`);
189
+ }
190
+ return value;
191
+ }
192
+ function optionalStringArray(input, key) {
193
+ const value = input[key];
194
+ if (value === void 0) {
195
+ return void 0;
196
+ }
197
+ if (!Array.isArray(value) || !value.every((item) => typeof item === "string")) {
198
+ throw new Error(`${key} must be a string array.`);
199
+ }
200
+ const trimmed = value.map((item) => item.trim()).filter((item) => item.length > 0);
201
+ return trimmed.length === 0 ? void 0 : trimmed;
202
+ }
203
+ function requireRecord(value, label) {
204
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
205
+ throw new Error(`${label} must be an object.`);
206
+ }
207
+ return value;
208
+ }
209
+ function requireBytes(input, key) {
210
+ const value = input[key];
211
+ if (value instanceof Uint8Array) {
212
+ return value;
213
+ }
214
+ if (Array.isArray(value) && value.every((item) => Number.isInteger(item) && Number(item) >= 0 && Number(item) <= 255)) {
215
+ return new Uint8Array(value.map(Number));
216
+ }
217
+ throw new Error(`${key} must be a byte array.`);
218
+ }
219
+ function requireInteger(input, key, fallback) {
220
+ const value = input[key];
221
+ if (value === void 0) {
222
+ return fallback;
223
+ }
224
+ if (!Number.isInteger(value)) {
225
+ throw new Error(`${key} must be an integer.`);
226
+ }
227
+ return Number(value);
228
+ }
229
+ function optionalInteger(input, key) {
230
+ const value = input[key];
231
+ if (value === void 0) {
232
+ return void 0;
233
+ }
234
+ if (!Number.isInteger(value)) {
235
+ throw new Error(`${key} must be an integer.`);
236
+ }
237
+ return Number(value);
238
+ }
239
+ var MAX_CAPTURE_MARKDOWN_BYTES, textEncoder;
240
+ var init_inputParsers = __esm({
241
+ "../tools/dist/inputParsers.js"() {
242
+ "use strict";
243
+ MAX_CAPTURE_MARKDOWN_BYTES = 256 * 1024;
244
+ textEncoder = new TextEncoder();
245
+ }
246
+ });
247
+
248
+ // ../tools/dist/registry.js
249
+ function listToolDefinitions() {
250
+ return [...toolDefinitions];
251
+ }
252
+ function readTool(name, summary, properties, cliExample, options) {
253
+ return defineTool({
254
+ name,
255
+ summary,
256
+ properties,
257
+ required: options?.required,
258
+ capability: "record:read",
259
+ mutability: "read",
260
+ transports: readTransports,
261
+ cliExample,
262
+ hostedAgent: options?.hostedAgent
263
+ });
264
+ }
265
+ function writeTool(name, summary, properties, cliExample, options) {
266
+ return defineTool({
267
+ name,
268
+ summary,
269
+ properties,
270
+ required: options?.required,
271
+ capability: "record:write",
272
+ mutability: "write",
273
+ transports: writeTransports,
274
+ cliExample,
275
+ hostedAgent: options?.hostedAgent
276
+ });
277
+ }
278
+ function sourceWriteTool(name, summary, properties, cliExample) {
279
+ return defineTool({
280
+ name,
281
+ summary,
282
+ properties,
283
+ capability: "source:write",
284
+ mutability: "write",
285
+ transports: writeTransports,
286
+ cliExample
287
+ });
288
+ }
289
+ function adminTool(name, summary, properties, cliExample) {
290
+ return defineTool({
291
+ name,
292
+ summary,
293
+ properties,
294
+ capability: "event:audit:read",
295
+ mutability: "admin",
296
+ transports: readTransports,
297
+ cliExample
298
+ });
299
+ }
300
+ function defineTool(input) {
301
+ const required = input.required ?? Object.keys(input.properties);
302
+ return {
303
+ name: input.name,
304
+ summary: input.summary,
305
+ inputSchema: {
306
+ type: "object",
307
+ required,
308
+ properties: input.properties,
309
+ additionalProperties: false
310
+ },
311
+ outputSchema: { type: "object", properties: {}, additionalProperties: false },
312
+ capability: input.capability,
313
+ mutability: input.mutability,
314
+ auditCategory: input.mutability === "admin" ? "admin" : input.mutability,
315
+ transports: input.transports,
316
+ idempotency: input.mutability === "write" ? "recommended" : "none",
317
+ resultSize: "compact",
318
+ cliExample: input.cliExample,
319
+ hostedAgent: hostedAgentMetadata(input, required)
320
+ };
321
+ }
322
+ function hostedAgentMetadata(input, required) {
323
+ return {
324
+ available: input.hostedAgent?.available ?? true,
325
+ toolsets: input.hostedAgent?.toolsets ?? defaultToolsets(input.name),
326
+ searchTerms: input.hostedAgent?.searchTerms ?? defaultSearchTerms(input.name, input.summary),
327
+ inputHints: input.hostedAgent?.inputHints ?? required,
328
+ riskClass: input.hostedAgent?.riskClass ?? defaultRiskClass(input.mutability)
329
+ };
330
+ }
331
+ function defaultRiskClass(mutability) {
332
+ if (mutability === "write") {
333
+ return "medium";
334
+ }
335
+ if (mutability === "admin") {
336
+ return "high";
337
+ }
338
+ return "low";
339
+ }
340
+ function defaultToolsets(name) {
341
+ const [prefix] = name.split(".");
342
+ switch (prefix) {
343
+ case "decision":
344
+ case "task":
345
+ return ["work"];
346
+ case "skill":
347
+ return ["brain", "work"];
348
+ case "record":
349
+ case "source":
350
+ case "capture":
351
+ case "ingestion":
352
+ return ["brain", "ingestion"];
353
+ case "search":
354
+ case "context":
355
+ case "evidence":
356
+ case "graph":
357
+ return ["brain", "retrieval"];
358
+ case "tools":
359
+ return ["registry"];
360
+ case "audit":
361
+ case "event":
362
+ return ["audit"];
363
+ default:
364
+ return ["brain"];
365
+ }
366
+ }
367
+ function defaultSearchTerms(name, summary) {
368
+ return [.../* @__PURE__ */ new Set([...tokenize(name), ...tokenize(summary)])];
369
+ }
370
+ function tokenize(text) {
371
+ return text.toLowerCase().split(/[^a-z0-9]+/u).filter(Boolean);
372
+ }
373
+ function stringProps(names) {
374
+ return Object.fromEntries(names.map((name) => [name, { type: "string" }]));
375
+ }
376
+ var readTransports, writeTransports, toolDefinitions;
377
+ var init_registry = __esm({
378
+ "../tools/dist/registry.js"() {
379
+ "use strict";
380
+ init_inputParsers();
381
+ readTransports = ["cli", "hosted_mcp", "local_mcp"];
382
+ writeTransports = ["cli", "hosted_mcp", "local_mcp"];
383
+ toolDefinitions = [
384
+ readTool("whoami", "Return principal, actor, scope, and capabilities.", {}, "sift whoami"),
385
+ readTool("brain.list", "List brains available to the current scope.", {}, "sift brain list"),
386
+ readTool("brain.use", "Select the current brain scope for subsequent operations.", stringProps(["brainId"]), "sift brain use <brain-id>"),
387
+ readTool("scope.current", "Show the authenticated workspace and brain scope.", {}, "sift scope current"),
388
+ readTool("tools.list", "List tools available to this transport and scope.", {}, "sift tools list"),
389
+ readTool("tools.schema", "Return JSON schemas for available tools.", {}, "sift tools schema --json"),
390
+ readTool("tools.help", "Return compact help for a tool.", stringProps(["name"]), "sift tools help search.query"),
391
+ readTool("tools.search", "Search compact authorized tool entries by hosted-agent intent.", {
392
+ intent: { type: "string" },
393
+ toolsetNames: { type: "array", items: { type: "string" } },
394
+ limit: { type: "integer", minimum: 1, maximum: 20 }
395
+ }, "sift tools search 'record this as a decision'", {
396
+ required: ["intent"],
397
+ hostedAgent: { toolsets: ["registry", "brain"], searchTerms: ["discover", "tool", "search"] }
398
+ }),
399
+ readTool("source.list", "List sources visible in the selected brain.", {}, "sift source list"),
400
+ readTool("source.get", "Read source metadata.", stringProps(["sourceId"]), "sift source get <source-id>"),
401
+ sourceWriteTool("source.create", "Create a source for future captures.", { name: { type: "string" }, visibility: { type: "array", items: { type: "string" } } }, "sift source create --name Notes --visibility team"),
402
+ readTool("source.status", "Inspect source processing status.", stringProps(["sourceId"]), "sift source status <source-id>"),
403
+ sourceWriteTool("capture.text", "Capture text or markdown through the ingestion spine.", {
404
+ sourceName: { type: "string" },
405
+ externalId: { type: "string" },
406
+ title: { type: "string" },
407
+ markdown: { type: "string", maxLength: MAX_CAPTURE_MARKDOWN_BYTES },
408
+ visibility: { type: "array", items: { type: "string" } }
409
+ }, "sift capture text --source Notes --external-id note-1"),
410
+ sourceWriteTool("capture.file", "Capture file metadata and content without treating the local path as canonical.", {
411
+ sourceName: { type: "string" },
412
+ externalId: { type: "string" },
413
+ title: { type: "string" },
414
+ filename: { type: "string" },
415
+ contentType: { type: "string" },
416
+ bytes: { type: "array", items: { type: "integer" } },
417
+ visibility: { type: "array", items: { type: "string" } }
418
+ }, "sift capture file ./notes.md --source Notes --external-id note-1"),
419
+ sourceWriteTool("capture.batch", "Capture a bounded batch of text or file inputs.", {
420
+ items: {
421
+ type: "array",
422
+ items: {
423
+ type: "object",
424
+ required: ["kind", "sourceName", "externalId", "title", "visibility"],
425
+ properties: {
426
+ kind: { type: "string" },
427
+ sourceName: { type: "string" },
428
+ externalId: { type: "string" },
429
+ title: { type: "string" },
430
+ markdown: { type: "string", maxLength: MAX_CAPTURE_MARKDOWN_BYTES },
431
+ filename: { type: "string" },
432
+ contentType: { type: "string" },
433
+ bytes: { type: "array", items: { type: "integer" } },
434
+ visibility: { type: "array", items: { type: "string" } }
435
+ }
436
+ }
437
+ }
438
+ }, "sift capture batch manifest.json"),
439
+ readTool("ingestion.status", "Inspect ingestion job status.", stringProps(["jobId"]), "sift ingestion status <job-id>"),
440
+ readTool("record.list", "List authorized records.", {}, "sift record list"),
441
+ readTool("record.get", "Read an authorized markdown record.", { recordId: { type: "string" }, sectionAnchor: { type: "string" } }, "sift record get <record-id>", { required: ["recordId"] }),
442
+ writeTool("record.create_markdown", "Create a versioned markdown brain record.", {
443
+ recordType: { type: "string" },
444
+ title: { type: "string" },
445
+ markdown: { type: "string" },
446
+ visibility: { type: "array", items: { type: "string" } }
447
+ }, "sift record create-markdown --title Note"),
448
+ writeTool("record.patch_section", "Patch a stable markdown heading section with conflict detection.", stringProps(["recordId", "anchor", "replacementMarkdown", "expectedMarkdown"]), "sift record patch-section <record-id> <anchor>", { required: ["recordId", "anchor", "replacementMarkdown"] }),
449
+ readTool("record.versions", "List record versions.", stringProps(["recordId"]), "sift record versions <record-id>"),
450
+ writeTool("decision.create", "Create a canonical decision record.", {
451
+ statement: { type: "string" },
452
+ state: { type: "string" },
453
+ rationale: { type: "string" },
454
+ authorship: { type: "string" },
455
+ evidenceIds: { type: "array", items: { type: "string" } },
456
+ visibility: { type: "array", items: { type: "string" } }
457
+ }, "sift decision create", { required: ["statement", "state", "visibility"] }),
458
+ writeTool("task.create", "Create a canonical task record.", {
459
+ title: { type: "string" },
460
+ status: { type: "string" },
461
+ owner: { type: "string" },
462
+ dueDate: { type: "string" },
463
+ rationale: { type: "string" },
464
+ authorship: { type: "string" },
465
+ evidenceIds: { type: "array", items: { type: "string" } },
466
+ visibility: { type: "array", items: { type: "string" } }
467
+ }, "sift task create", { required: ["title", "visibility"] }),
468
+ readTool("skill.resolve", "Resolve at most three advisory skill candidates for a task description, each with the skill record id, pinned active version id, title, and applicability summary, or an empty list.", { query: { type: "string" } }, "sift skill resolve 'draft the monthly investor update'", { required: ["query"] }),
469
+ readTool("skill.get", "Read a skill's pinned active version markdown body and version id by skill record id.", { skillId: { type: "string" } }, "sift skill get <skill-id>", { required: ["skillId"] }),
470
+ writeTool("skill.exercise", "Report that a skill version informed an output on a surface; the report is an attribution claim only.", {
471
+ skillId: { type: "string" },
472
+ versionId: { type: "string" },
473
+ surface: { type: "string" },
474
+ outputRef: {
475
+ type: "object",
476
+ properties: {
477
+ kind: { type: "string" },
478
+ recordId: { type: "string" },
479
+ versionId: { type: "string" },
480
+ externalRef: { type: "string" }
481
+ },
482
+ required: ["kind"]
483
+ },
484
+ idempotencyKey: { type: "string" }
485
+ }, "sift skill exercise <skill-id> <version-id>", { required: ["skillId", "versionId", "surface", "outputRef", "idempotencyKey"] }),
486
+ writeTool("skill.teach", "Capture an explicit correction lesson for a skill with optional exercise reference; the explicit correction floor for surfaces without ambient capture.", {
487
+ skillId: { type: "string" },
488
+ lesson: { type: "string" },
489
+ exerciseId: { type: "string" },
490
+ severity: { type: "string" },
491
+ visibility: { type: "array", items: { type: "string" } }
492
+ }, "sift skill teach <skill-id> --lesson 'when X, do Y'", { required: ["skillId", "lesson", "visibility"] }),
493
+ readTool("search.query", "Search authorized brain context and return cited results.", {
494
+ query: { type: "string" },
495
+ limit: { type: "integer", minimum: 1, maximum: 20 }
496
+ }, "sift search query 'launch risks'"),
497
+ readTool("context.assemble", "Assemble compact cited context for an agent.", { query: { type: "string" }, maxChars: { type: "integer", minimum: 1 } }, "sift context assemble 'launch risks'", {
498
+ hostedAgent: {
499
+ toolsets: ["brain", "retrieval"],
500
+ searchTerms: ["context", "cite", "answer", "evidence"]
501
+ }
502
+ }),
503
+ readTool("context.profile", "Read a permission-filtered profile context model.", {}, "sift context profile"),
504
+ readTool("evidence.list", "List authorized evidence links for a record.", stringProps(["recordId"]), "sift evidence list <record-id>"),
505
+ readTool("evidence.get", "Read an authorized evidence item.", stringProps(["evidenceId"]), "sift evidence get <evidence-id>"),
506
+ readTool("graph.neighbors", "Traverse authorized graph neighbors.", stringProps(["recordId"]), "sift graph neighbors <record-id>"),
507
+ readTool("event.list", "List authorized brain events.", {}, "sift event list"),
508
+ adminTool("audit.events", "Inspect redacted audit events when authorized.", stringProps(["targetId"]), "sift audit events <target-id>")
509
+ ];
510
+ }
511
+ });
512
+
513
+ // ../tools/dist/discovery.js
514
+ function executeWhoami(auth) {
515
+ return {
516
+ principal: { id: auth.principalId, type: auth.principalType },
517
+ actor: { id: auth.actorId, type: auth.actorType },
518
+ scope: { workspaceId: auth.workspaceId, brainId: auth.brainId },
519
+ requestId: auth.requestId,
520
+ authPath: auth.authPath,
521
+ capabilities: auth.capabilities,
522
+ allowedVisibility: auth.allowedVisibility
523
+ };
524
+ }
525
+ function executeScopeCurrent(auth) {
526
+ return {
527
+ workspaceId: auth.workspaceId,
528
+ brainId: auth.brainId,
529
+ principalId: auth.principalId,
530
+ authPath: auth.authPath,
531
+ capabilities: auth.capabilities,
532
+ allowedVisibility: auth.allowedVisibility
533
+ };
534
+ }
535
+ function executeBrainList(auth) {
536
+ return [{ workspaceId: auth.workspaceId, brainId: auth.brainId, selected: true }];
537
+ }
538
+ function executeBrainUse(auth, brainId) {
539
+ return { workspaceId: auth.workspaceId, brainId, selected: true };
540
+ }
541
+ function executeToolsList(input) {
542
+ return availableTools(input).map((tool) => ({
543
+ name: tool.name,
544
+ summary: tool.summary,
545
+ capability: tool.capability,
546
+ mutability: tool.mutability
547
+ }));
548
+ }
549
+ function executeToolsSchema(input) {
550
+ return availableTools(input);
551
+ }
552
+ function executeToolsHelp(input, name) {
553
+ const tool = availableTools(input).find((candidate) => candidate.name === name);
554
+ if (tool === void 0) {
555
+ throw new Error(`Tool '${name}' is unavailable for this transport or scope.`);
556
+ }
557
+ return {
558
+ name: tool.name,
559
+ summary: tool.summary,
560
+ capability: tool.capability,
561
+ mutability: tool.mutability,
562
+ example: tool.cliExample
563
+ };
564
+ }
565
+ function executeToolsSearch(input, searchInput) {
566
+ const intentTokens = tokenize2(searchInput.intent);
567
+ const requestedToolsets = new Set(searchInput.toolsetNames ?? []);
568
+ const limit = searchInput.limit ?? 8;
569
+ return availableTools(input).filter((tool) => tool.hostedAgent.available).filter((tool) => {
570
+ if (requestedToolsets.size === 0)
571
+ return true;
572
+ return tool.hostedAgent.toolsets.some((toolset) => requestedToolsets.has(toolset));
573
+ }).map((tool) => ({ tool, score: scoreTool(tool, intentTokens) })).filter((entry) => entry.score > 0 || intentTokens.length === 0).sort((left, right) => right.score - left.score || left.tool.name.localeCompare(right.tool.name)).slice(0, limit).map(({ tool }) => ({
574
+ name: tool.name,
575
+ summary: tool.summary,
576
+ mutability: tool.mutability,
577
+ requiredCapability: tool.capability,
578
+ inputHints: tool.hostedAgent.inputHints
579
+ }));
580
+ }
581
+ function availableTools(input) {
582
+ const transport = input.transport ?? "local_mcp";
583
+ const availableNames = new Set(input.availableToolNames ?? IMPLEMENTED_TOOL_NAMES);
584
+ return listToolDefinitions().filter((tool) => availableNames.has(tool.name) && tool.transports.includes(transport) && input.auth.capabilities.includes(tool.capability));
585
+ }
586
+ function scoreTool(tool, intentTokens) {
587
+ const haystack = /* @__PURE__ */ new Set([
588
+ ...tokenize2(tool.name),
589
+ ...tokenize2(tool.summary),
590
+ ...tool.hostedAgent.searchTerms.flatMap(tokenize2),
591
+ ...tool.hostedAgent.inputHints.flatMap(tokenize2)
592
+ ]);
593
+ return intentTokens.reduce((score, token) => score + (haystack.has(token) ? 1 : 0), 0);
594
+ }
595
+ function tokenize2(text) {
596
+ return text.toLowerCase().split(/[^a-z0-9]+/u).filter(Boolean);
597
+ }
598
+ var IMPLEMENTED_TOOL_NAMES;
599
+ var init_discovery = __esm({
600
+ "../tools/dist/discovery.js"() {
601
+ "use strict";
602
+ init_registry();
603
+ IMPLEMENTED_TOOL_NAMES = [
604
+ "whoami",
605
+ "brain.list",
606
+ "brain.use",
607
+ "scope.current",
608
+ "tools.list",
609
+ "tools.schema",
610
+ "tools.help",
611
+ "tools.search",
612
+ "capture.text",
613
+ "capture.file",
614
+ "capture.batch",
615
+ "search.query",
616
+ "context.assemble",
617
+ "context.profile",
618
+ "decision.create",
619
+ "task.create",
620
+ "source.list",
621
+ "source.create",
622
+ "source.get",
623
+ "source.status",
624
+ "ingestion.status",
625
+ "record.list",
626
+ "record.get",
627
+ "record.create_markdown",
628
+ "record.patch_section",
629
+ "record.versions",
630
+ "evidence.list",
631
+ "evidence.get",
632
+ "graph.neighbors",
633
+ "event.list",
634
+ "audit.events"
635
+ ];
636
+ }
637
+ });
638
+
639
+ // ../tools/dist/results.js
640
+ function captureResult(result2) {
641
+ return {
642
+ status: result2.job?.status ?? result2.status ?? "captured",
643
+ jobId: result2.job?.id,
644
+ sourceId: result2.sourceId,
645
+ sourceItemId: result2.sourceItemId,
646
+ recordId: result2.recordId,
647
+ versionId: result2.versionId,
648
+ versionNumber: result2.versionNumber
649
+ };
650
+ }
651
+ function workRecordResult(result2) {
652
+ return {
653
+ status: result2.job.status,
654
+ jobId: result2.job.id,
655
+ recordId: result2.recordId,
656
+ versionId: result2.versionId,
657
+ versionNumber: result2.versionNumber
658
+ };
659
+ }
660
+ var init_results = __esm({
661
+ "../tools/dist/results.js"() {
662
+ "use strict";
663
+ }
664
+ });
665
+
666
+ // ../tools/dist/captureTools.js
667
+ async function executeCaptureText(input, toolInput) {
668
+ const capture = parseCaptureText(toolInput);
669
+ const result2 = await input.service.ingestText({ auth: input.auth, ...capture });
670
+ return captureResult(result2);
671
+ }
672
+ async function executeCaptureFile(input, toolInput) {
673
+ if (input.service.ingestFile === void 0) {
674
+ throw new Error("Tool 'capture.file' requires a file ingestion service contract.");
675
+ }
676
+ const file = parseCaptureFile(toolInput);
677
+ const result2 = await input.service.ingestFile({ auth: input.auth, ...file });
678
+ return captureResult(result2);
679
+ }
680
+ async function executeCaptureBatch(input, toolInput) {
681
+ const batch = parseCaptureBatch(toolInput);
682
+ const results = [];
683
+ for (const item of batch.items) {
684
+ if (item.kind === "text") {
685
+ const { kind: _kind2, ...capture } = item;
686
+ const result3 = await input.service.ingestText({ auth: input.auth, ...capture });
687
+ results.push(captureResult(result3));
688
+ continue;
689
+ }
690
+ if (input.service.ingestFile === void 0) {
691
+ throw new Error("Tool 'capture.batch' requires a file ingestion service contract.");
692
+ }
693
+ const { kind: _kind, ...file } = item;
694
+ const result2 = await input.service.ingestFile({ auth: input.auth, ...file });
695
+ results.push(captureResult(result2));
696
+ }
697
+ return results;
698
+ }
699
+ var init_captureTools = __esm({
700
+ "../tools/dist/captureTools.js"() {
701
+ "use strict";
702
+ init_inputParsers();
703
+ init_results();
704
+ }
705
+ });
706
+
707
+ // ../tools/dist/skillTools.js
708
+ function skillToolHandlers(input, toolInput) {
709
+ return {
710
+ "skill.resolve": () => {
711
+ if (input.service.resolveSkills === void 0)
712
+ throw missingSkillService("skill.resolve");
713
+ return input.service.resolveSkills({
714
+ auth: input.auth,
715
+ query: requireString(toolInput, "query")
716
+ });
717
+ },
718
+ "skill.get": () => {
719
+ if (input.service.getSkill === void 0)
720
+ throw missingSkillService("skill.get");
721
+ return input.service.getSkill({
722
+ auth: input.auth,
723
+ skillId: requireString(toolInput, "skillId")
724
+ });
725
+ },
726
+ "skill.exercise": () => {
727
+ if (input.service.recordSkillExercise === void 0) {
728
+ throw missingSkillService("skill.exercise");
729
+ }
730
+ return input.service.recordSkillExercise({
731
+ auth: input.auth,
732
+ ...parseSkillExercise(toolInput)
733
+ });
734
+ },
735
+ "skill.teach": () => {
736
+ if (input.service.teachSkill === void 0)
737
+ throw missingSkillService("skill.teach");
738
+ return input.service.teachSkill({ auth: input.auth, ...parseSkillTeach(toolInput) });
739
+ }
740
+ };
741
+ }
742
+ function skillToolAvailability(service) {
743
+ return [
744
+ [service.resolveSkills !== void 0, ["skill.resolve"]],
745
+ [service.getSkill !== void 0, ["skill.get"]],
746
+ [service.recordSkillExercise !== void 0, ["skill.exercise"]],
747
+ [service.teachSkill !== void 0, ["skill.teach"]]
748
+ ];
749
+ }
750
+ function parseSkillExercise(input) {
751
+ return {
752
+ skillId: requireString(input, "skillId"),
753
+ versionId: requireString(input, "versionId"),
754
+ surface: requireString(input, "surface"),
755
+ outputRef: requireSkillOutputRef(input, "outputRef"),
756
+ idempotencyKey: requireString(input, "idempotencyKey")
757
+ };
758
+ }
759
+ function parseSkillTeach(input) {
760
+ const exerciseId = input.exerciseId;
761
+ const severity = input.severity;
762
+ const visibility = input.visibility;
763
+ if (exerciseId !== void 0 && typeof exerciseId !== "string") {
764
+ throw new Error("exerciseId must be a string.");
765
+ }
766
+ if (severity !== void 0 && severity !== "normal" && severity !== "harmful") {
767
+ throw new Error("severity must be normal or harmful.");
768
+ }
769
+ if (!Array.isArray(visibility) || !visibility.every((item) => typeof item === "string")) {
770
+ throw new Error("visibility must be a string array.");
771
+ }
772
+ return {
773
+ skillId: requireString(input, "skillId"),
774
+ lesson: requireString(input, "lesson"),
775
+ exerciseId,
776
+ severity,
777
+ visibility
778
+ };
779
+ }
780
+ function requireSkillOutputRef(input, key) {
781
+ const value = input[key];
782
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
783
+ throw new Error(`${key} must be an object.`);
784
+ }
785
+ const ref = value;
786
+ if (ref.kind === "record") {
787
+ const versionId = ref.versionId;
788
+ if (versionId !== void 0 && typeof versionId !== "string") {
789
+ throw new Error(`${key}.versionId must be a string.`);
790
+ }
791
+ return { kind: "record", recordId: requireString(ref, "recordId"), versionId };
792
+ }
793
+ if (ref.kind === "external") {
794
+ return { kind: "external", externalRef: requireString(ref, "externalRef") };
795
+ }
796
+ throw new Error(`${key}.kind must be record or external.`);
797
+ }
798
+ function missingSkillService(toolName) {
799
+ return new Error(`Tool '${toolName}' requires a runtime service contract.`);
800
+ }
801
+ var init_skillTools = __esm({
802
+ "../tools/dist/skillTools.js"() {
803
+ "use strict";
804
+ init_inputParsers();
805
+ }
806
+ });
807
+
808
+ // ../tools/dist/toolLog.js
809
+ function logToolCall(input) {
810
+ input.onToolLog?.({
811
+ operation: input.operation,
812
+ requestId: input.auth.requestId,
813
+ workspaceId: input.auth.workspaceId,
814
+ brainId: input.auth.brainId,
815
+ inputKeys: Object.keys(input.toolInput).sort(),
816
+ sizeClass: classifyInputSize(input.toolInput),
817
+ status: input.status,
818
+ latencyMs: Date.now() - input.startedAt,
819
+ auditTargetIds: collectAuditTargetIds(input.toolInput, input.result)
820
+ });
821
+ }
822
+ function classifyInputSize(toolInput) {
823
+ return estimateValueSize(toolInput, /* @__PURE__ */ new WeakSet()) > 2e3 ? "large" : "small";
824
+ }
825
+ function estimateValueSize(value, seen) {
826
+ if (typeof value === "string")
827
+ return value.length;
828
+ if (typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
829
+ return 8;
830
+ }
831
+ if (value === void 0 || value === null || typeof value === "symbol")
832
+ return 0;
833
+ if (value instanceof Uint8Array)
834
+ return value.byteLength;
835
+ if (Array.isArray(value)) {
836
+ let total = 0;
837
+ for (const item of value) {
838
+ total += estimateValueSize(item, seen);
839
+ }
840
+ return total;
841
+ }
842
+ if (typeof value === "object") {
843
+ if (seen.has(value))
844
+ return 0;
845
+ seen.add(value);
846
+ let total = 0;
847
+ for (const [key, item] of Object.entries(value)) {
848
+ total += key.length + estimateValueSize(item, seen);
849
+ }
850
+ return total;
851
+ }
852
+ return 0;
853
+ }
854
+ function collectAuditTargetIds(...values) {
855
+ const ids = /* @__PURE__ */ new Set();
856
+ for (const value of values) {
857
+ if (typeof value !== "object" || value === null || Array.isArray(value))
858
+ continue;
859
+ for (const [key, candidate] of Object.entries(value)) {
860
+ if (key.endsWith("Id") && typeof candidate === "string" && candidate.trim().length > 0) {
861
+ ids.add(candidate);
862
+ }
863
+ }
864
+ }
865
+ return [...ids].sort();
866
+ }
867
+ var init_toolLog = __esm({
868
+ "../tools/dist/toolLog.js"() {
869
+ "use strict";
870
+ }
871
+ });
872
+
873
+ // ../tools/dist/executor.js
874
+ function createRuntimeToolExecutor(input) {
875
+ const availableToolNames = runtimeAvailableToolNames(input.service);
876
+ return {
877
+ listAvailableToolNames() {
878
+ return [...availableToolNames];
879
+ },
880
+ async execute(name, toolInput) {
881
+ const startedAt = Date.now();
882
+ const handlers = createToolHandlers({ ...input, availableToolNames }, toolInput);
883
+ const handler = handlers[name];
884
+ if (handler === void 0) {
885
+ const error = new Error(`Tool '${name}' is unavailable in this implementation slice.`);
886
+ logToolCall({
887
+ auth: input.auth,
888
+ onToolLog: input.onToolLog,
889
+ operation: name,
890
+ toolInput,
891
+ status: "error",
892
+ startedAt
893
+ });
894
+ throw error;
895
+ }
896
+ try {
897
+ const result2 = await handler();
898
+ logToolCall({
899
+ auth: input.auth,
900
+ onToolLog: input.onToolLog,
901
+ operation: name,
902
+ toolInput,
903
+ status: "success",
904
+ startedAt,
905
+ result: result2
906
+ });
907
+ return result2;
908
+ } catch (error) {
909
+ logToolCall({
910
+ auth: input.auth,
911
+ onToolLog: input.onToolLog,
912
+ operation: name,
913
+ toolInput,
914
+ status: "error",
915
+ startedAt
916
+ });
917
+ throw error;
918
+ }
919
+ }
920
+ };
921
+ }
922
+ function createToolHandlers(input, toolInput) {
923
+ return {
924
+ whoami: () => Promise.resolve(executeWhoami(input.auth)),
925
+ "brain.list": () => Promise.resolve(executeBrainList(input.auth)),
926
+ "brain.use": () => Promise.resolve(executeBrainUse(input.auth, requireString(toolInput, "brainId"))),
927
+ "scope.current": () => Promise.resolve(executeScopeCurrent(input.auth)),
928
+ "tools.list": () => Promise.resolve(executeToolsList(input)),
929
+ "tools.schema": () => Promise.resolve(executeToolsSchema(input)),
930
+ "tools.help": () => Promise.resolve(executeToolsHelp(input, requireString(toolInput, "name"))),
931
+ "tools.search": () => Promise.resolve(executeToolsSearch(input, parseToolsSearch(toolInput))),
932
+ "capture.text": () => executeCaptureText(input, toolInput),
933
+ "capture.file": () => executeCaptureFile(input, toolInput),
934
+ "capture.batch": () => executeCaptureBatch(input, toolInput),
935
+ "search.query": () => executeSearchQuery(input, toolInput),
936
+ "context.assemble": () => executeContextAssemble(input, toolInput),
937
+ "context.profile": () => executeContextProfile(input, toolInput),
938
+ "decision.create": () => executeDecisionCreate(input, toolInput),
939
+ "task.create": () => executeTaskCreate(input, toolInput),
940
+ ...skillToolHandlers(input, toolInput),
941
+ "source.list": () => executeSourceList(input),
942
+ "source.create": () => executeSourceCreate(input, toolInput),
943
+ "source.get": () => executeSourceRead(input, toolInput, "source.get"),
944
+ "source.status": () => executeSourceRead(input, toolInput, "source.status"),
945
+ "ingestion.status": () => executeIngestionStatus(input, toolInput),
946
+ "record.list": () => executeRecordList(input),
947
+ "record.get": () => executeRecordRead(input, toolInput),
948
+ "record.create_markdown": () => executeRecordCreateMarkdown(input, toolInput),
949
+ "record.patch_section": () => executeRecordPatchSection(input, toolInput),
950
+ "record.versions": () => executeRecordVersions(input, toolInput),
951
+ "evidence.list": () => {
952
+ if (input.service.listEvidence === void 0)
953
+ throw missingService("evidence.list");
954
+ return input.service.listEvidence({
955
+ auth: input.auth,
956
+ recordId: requireString(toolInput, "recordId")
957
+ });
958
+ },
959
+ "evidence.get": () => {
960
+ if (input.service.getEvidence === void 0)
961
+ throw missingService("evidence.get");
962
+ return input.service.getEvidence({
963
+ auth: input.auth,
964
+ evidenceId: requireString(toolInput, "evidenceId")
965
+ });
966
+ },
967
+ "graph.neighbors": () => {
968
+ if (input.service.listGraphNeighbors === void 0)
969
+ throw missingService("graph.neighbors");
970
+ return input.service.listGraphNeighbors({
971
+ auth: input.auth,
972
+ recordId: requireString(toolInput, "recordId")
973
+ });
974
+ },
975
+ "event.list": () => {
976
+ if (input.service.listEvents === void 0)
977
+ throw missingService("event.list");
978
+ return input.service.listEvents({ auth: input.auth });
979
+ },
980
+ "audit.events": () => executeAuditEvents(input, toolInput)
981
+ };
982
+ }
983
+ function runtimeAvailableToolNames(service) {
984
+ const baseNames = [
985
+ "whoami",
986
+ "tools.list",
987
+ "tools.schema",
988
+ "tools.help",
989
+ "tools.search",
990
+ "brain.list",
991
+ "brain.use",
992
+ "scope.current",
993
+ "capture.text",
994
+ "capture.batch",
995
+ "search.query",
996
+ "context.assemble"
997
+ ];
998
+ const optionalNames = [
999
+ [service.ingestFile !== void 0, ["capture.file"]],
1000
+ [service.createDecision !== void 0, ["decision.create"]],
1001
+ [service.createTask !== void 0, ["task.create"]],
1002
+ ...skillToolAvailability(service),
1003
+ [service.listSources !== void 0, ["source.list"]],
1004
+ [service.createSource !== void 0, ["source.create"]],
1005
+ [service.getSource !== void 0, ["source.get", "source.status"]],
1006
+ [service.getIngestionStatus !== void 0, ["ingestion.status"]],
1007
+ [service.listRecords !== void 0, ["record.list"]],
1008
+ [service.getRecord !== void 0, ["record.get"]],
1009
+ [service.createMarkdownRecord !== void 0, ["record.create_markdown"]],
1010
+ [service.patchRecordSection !== void 0, ["record.patch_section"]],
1011
+ [service.listRecordVersions !== void 0, ["record.versions"]],
1012
+ [service.listEvidence !== void 0, ["evidence.list"]],
1013
+ [service.getEvidence !== void 0, ["evidence.get"]],
1014
+ [service.listGraphNeighbors !== void 0, ["graph.neighbors"]],
1015
+ [service.listEvents !== void 0, ["event.list"]],
1016
+ [service.getContextProfile !== void 0, ["context.profile"]],
1017
+ [service.listAuditEvents !== void 0, ["audit.events"]]
1018
+ ];
1019
+ return [...baseNames, ...optionalNames.flatMap(([enabled, names]) => enabled ? names : [])];
1020
+ }
1021
+ function missingService(toolName) {
1022
+ return new Error(`Tool '${toolName}' requires a runtime service contract.`);
1023
+ }
1024
+ function executeSearchQuery(input, toolInput) {
1025
+ const query = parseSearchQuery(toolInput);
1026
+ return input.service.retrieveCitedContext({
1027
+ auth: input.auth,
1028
+ query: query.query,
1029
+ limit: query.limit,
1030
+ maxChars: 4e3
1031
+ });
1032
+ }
1033
+ function executeContextAssemble(input, toolInput) {
1034
+ const query = parseContextQuery(toolInput);
1035
+ return input.service.retrieveCitedContext({
1036
+ auth: input.auth,
1037
+ query: query.query,
1038
+ limit: 8,
1039
+ maxChars: query.maxChars
1040
+ });
1041
+ }
1042
+ function executeContextProfile(input, toolInput) {
1043
+ if (input.service.getContextProfile === void 0) {
1044
+ throw new Error("Tool 'context.profile' requires a profile read service contract.");
1045
+ }
1046
+ const profile = parseProfileQuery(toolInput);
1047
+ return input.service.getContextProfile({ auth: input.auth, ...profile });
1048
+ }
1049
+ async function executeDecisionCreate(input, toolInput) {
1050
+ if (input.service.createDecision === void 0) {
1051
+ throw new Error("Tool 'decision.create' requires a work-record service contract.");
1052
+ }
1053
+ const decision = parseDecision(toolInput);
1054
+ const result2 = await input.service.createDecision({ auth: input.auth, ...decision });
1055
+ return workRecordResult(result2);
1056
+ }
1057
+ async function executeTaskCreate(input, toolInput) {
1058
+ if (input.service.createTask === void 0) {
1059
+ throw new Error("Tool 'task.create' requires a work-record service contract.");
1060
+ }
1061
+ const task = parseTask(toolInput);
1062
+ const result2 = await input.service.createTask({ auth: input.auth, ...task });
1063
+ return workRecordResult(result2);
1064
+ }
1065
+ function executeSourceList(input) {
1066
+ if (input.service.listSources === void 0) {
1067
+ throw new Error("Tool 'source.list' requires a source read service contract.");
1068
+ }
1069
+ return input.service.listSources({ auth: input.auth });
1070
+ }
1071
+ function executeSourceCreate(input, toolInput) {
1072
+ if (input.service.createSource === void 0) {
1073
+ throw new Error("Tool 'source.create' requires a source write service contract.");
1074
+ }
1075
+ const source = parseSourceCreate(toolInput);
1076
+ return input.service.createSource({ auth: input.auth, ...source });
1077
+ }
1078
+ function executeSourceRead(input, toolInput, toolName) {
1079
+ if (input.service.getSource === void 0) {
1080
+ throw new Error(`Tool '${toolName}' requires a source read service contract.`);
1081
+ }
1082
+ return input.service.getSource({
1083
+ auth: input.auth,
1084
+ sourceId: requireString(toolInput, "sourceId")
1085
+ });
1086
+ }
1087
+ function executeIngestionStatus(input, toolInput) {
1088
+ if (input.service.getIngestionStatus === void 0) {
1089
+ throw new Error("Tool 'ingestion.status' requires an ingestion read service contract.");
1090
+ }
1091
+ return input.service.getIngestionStatus({
1092
+ auth: input.auth,
1093
+ jobId: requireString(toolInput, "jobId")
1094
+ });
1095
+ }
1096
+ function executeRecordList(input) {
1097
+ if (input.service.listRecords === void 0) {
1098
+ throw new Error("Tool 'record.list' requires a record read service contract.");
1099
+ }
1100
+ return input.service.listRecords({ auth: input.auth });
1101
+ }
1102
+ function executeRecordRead(input, toolInput) {
1103
+ if (input.service.getRecord === void 0) {
1104
+ throw new Error("Tool 'record.get' requires a record read service contract.");
1105
+ }
1106
+ const record = parseRecordRead(toolInput);
1107
+ return input.service.getRecord({ auth: input.auth, ...record });
1108
+ }
1109
+ async function executeRecordCreateMarkdown(input, toolInput) {
1110
+ if (input.service.createMarkdownRecord === void 0) {
1111
+ throw new Error("Tool 'record.create_markdown' requires a record write service contract.");
1112
+ }
1113
+ const record = parseMarkdownRecord(toolInput);
1114
+ const result2 = await input.service.createMarkdownRecord({ auth: input.auth, ...record });
1115
+ return workRecordResult(result2);
1116
+ }
1117
+ async function executeRecordPatchSection(input, toolInput) {
1118
+ if (input.service.patchRecordSection === void 0) {
1119
+ throw new Error("Tool 'record.patch_section' requires a record write service contract.");
1120
+ }
1121
+ const patch = parseRecordSectionPatch(toolInput);
1122
+ const result2 = await input.service.patchRecordSection({ auth: input.auth, ...patch });
1123
+ return workRecordResult(result2);
1124
+ }
1125
+ function executeRecordVersions(input, toolInput) {
1126
+ if (input.service.listRecordVersions === void 0) {
1127
+ throw new Error("Tool 'record.versions' requires a record read service contract.");
1128
+ }
1129
+ return input.service.listRecordVersions({
1130
+ auth: input.auth,
1131
+ recordId: requireString(toolInput, "recordId")
1132
+ });
1133
+ }
1134
+ function executeAuditEvents(input, toolInput) {
1135
+ if (input.service.listAuditEvents === void 0) {
1136
+ throw new Error("Tool 'audit.events' requires an audit read service contract.");
1137
+ }
1138
+ const auditInput = parseAuditEvents(toolInput);
1139
+ return input.service.listAuditEvents({ auth: input.auth, ...auditInput });
1140
+ }
1141
+ var init_executor = __esm({
1142
+ "../tools/dist/executor.js"() {
1143
+ "use strict";
1144
+ init_discovery();
1145
+ init_captureTools();
1146
+ init_inputParsers();
1147
+ init_skillTools();
1148
+ init_results();
1149
+ init_toolLog();
1150
+ }
1151
+ });
1152
+
1153
+ // ../tools/dist/generated.js
1154
+ function createMcpToolSchemas(filter) {
1155
+ return availableTools2(filter).map((tool) => ({
1156
+ name: tool.name,
1157
+ description: tool.summary,
1158
+ inputSchema: tool.inputSchema
1159
+ }));
1160
+ }
1161
+ function createCliCommandMetadata(filter) {
1162
+ return availableTools2(filter).map((tool) => ({
1163
+ name: tool.name,
1164
+ summary: tool.summary,
1165
+ capability: tool.capability,
1166
+ mutability: tool.mutability,
1167
+ example: tool.cliExample
1168
+ }));
1169
+ }
1170
+ function availableTools2(filter) {
1171
+ const availableNames = new Set(filter.toolNames ?? IMPLEMENTED_TOOL_NAMES);
1172
+ return listToolDefinitions().filter((tool) => availableNames.has(tool.name) && tool.transports.includes(filter.transport) && filter.capabilities.includes(tool.capability));
1173
+ }
1174
+ var init_generated = __esm({
1175
+ "../tools/dist/generated.js"() {
1176
+ "use strict";
1177
+ init_registry();
1178
+ init_discovery();
1179
+ }
1180
+ });
1181
+
1182
+ // ../tools/dist/mcpAdapter.js
1183
+ function createMcpAdapter(input) {
1184
+ const availableToolNames = input.executor.listAvailableToolNames?.() ?? [
1185
+ ...IMPLEMENTED_TOOL_NAMES
1186
+ ];
1187
+ const availableNameSet = new Set(availableToolNames);
1188
+ const available = listToolDefinitions().filter((tool) => availableNameSet.has(tool.name) && tool.transports.includes(input.transport) && input.capabilities.includes(tool.capability));
1189
+ return {
1190
+ listTools() {
1191
+ return createMcpToolSchemas({
1192
+ transport: input.transport,
1193
+ capabilities: input.capabilities,
1194
+ toolNames: availableToolNames
1195
+ });
1196
+ },
1197
+ async callTool(call) {
1198
+ if (!available.some((tool) => tool.name === call.name)) {
1199
+ return errorResult2("tool_unavailable", `Tool '${call.name}' is unavailable for this MCP transport or scope.`);
1200
+ }
1201
+ try {
1202
+ const result2 = await input.executor.execute(call.name, call.arguments);
1203
+ return {
1204
+ isError: false,
1205
+ structuredContent: result2,
1206
+ content: [{ type: "text", text: renderToolResult(result2) }]
1207
+ };
1208
+ } catch (error) {
1209
+ return errorResult2(classifyToolError(error), messageForError(error));
1210
+ }
1211
+ }
1212
+ };
1213
+ }
1214
+ function renderToolResult(result2) {
1215
+ if (typeof result2 === "object" && result2 !== null && "contextMarkdown" in result2) {
1216
+ const context = result2;
1217
+ if (typeof context.contextMarkdown === "string") {
1218
+ return context.contextMarkdown;
1219
+ }
1220
+ }
1221
+ return JSON.stringify(result2);
1222
+ }
1223
+ function classifyToolError(error) {
1224
+ if (error instanceof Error) {
1225
+ if (isPermissionError2(error)) {
1226
+ return "permission_denied";
1227
+ }
1228
+ if (isMissingServiceContractError2(error)) {
1229
+ return "tool_unavailable";
1230
+ }
1231
+ if (isConflictError2(error)) {
1232
+ return "conflict";
1233
+ }
1234
+ if (isNotFoundError2(error)) {
1235
+ return "not_found";
1236
+ }
1237
+ if (isRetriableUpstreamError2(error)) {
1238
+ return "retriable_upstream_failure";
1239
+ }
1240
+ if (isValidationError2(error)) {
1241
+ return "validation_failure";
1242
+ }
1243
+ }
1244
+ return "internal_error";
1245
+ }
1246
+ function isPermissionError2(error) {
1247
+ return error.name === "RuntimePermissionDeniedError" || error.message.startsWith("missing capability ");
1248
+ }
1249
+ function isMissingServiceContractError2(error) {
1250
+ return error.message.includes(" requires ") && error.message.includes(" service contract.");
1251
+ }
1252
+ function isConflictError2(error) {
1253
+ return error.name.includes("Conflict") || error.message.includes(" changed before ");
1254
+ }
1255
+ function isNotFoundError2(error) {
1256
+ return error.name.includes("NotFound") || /\bnot found\b/iu.test(error.message);
1257
+ }
1258
+ function isRetriableUpstreamError2(error) {
1259
+ return error.message.includes("fetch failed") || error.message.includes("ECONN") || error.message.toLowerCase().includes("timeout") || error.name.includes("Upstream");
1260
+ }
1261
+ function isValidationError2(error) {
1262
+ return error.message.endsWith(" is required.") || error.message.includes(" must be ") || error.message.includes(" is not valid");
1263
+ }
1264
+ function messageForError(error) {
1265
+ return error instanceof Error ? error.message : "Tool failed.";
1266
+ }
1267
+ function errorResult2(errorCode, message) {
1268
+ return {
1269
+ isError: true,
1270
+ errorCode,
1271
+ message,
1272
+ content: [{ type: "text", text: message }]
1273
+ };
1274
+ }
1275
+ var init_mcpAdapter = __esm({
1276
+ "../tools/dist/mcpAdapter.js"() {
1277
+ "use strict";
1278
+ init_generated();
1279
+ init_discovery();
1280
+ init_registry();
1281
+ }
1282
+ });
1283
+
1284
+ // ../tools/dist/hostedMcpEntrypoint.js
1285
+ function createHostedMcpEntrypoint(input) {
1286
+ return {
1287
+ discovery() {
1288
+ return input.authenticator.discovery();
1289
+ },
1290
+ async listTools(request) {
1291
+ const auth = await input.authenticator.authenticate({
1292
+ authorizationHeader: request.authorizationHeader
1293
+ });
1294
+ if (!auth.ok) {
1295
+ return { ok: false, error: authFailure(auth) };
1296
+ }
1297
+ return {
1298
+ ok: true,
1299
+ tools: createMcpAdapter({
1300
+ transport: "hosted_mcp",
1301
+ capabilities: auth.capabilities,
1302
+ executor: auth.executor
1303
+ }).listTools()
1304
+ };
1305
+ },
1306
+ async callTool(request) {
1307
+ const auth = await input.authenticator.authenticate({
1308
+ authorizationHeader: request.authorizationHeader
1309
+ });
1310
+ if (!auth.ok) {
1311
+ return authFailure(auth);
1312
+ }
1313
+ return createMcpAdapter({
1314
+ transport: "hosted_mcp",
1315
+ capabilities: auth.capabilities,
1316
+ executor: auth.executor
1317
+ }).callTool(request.call);
1318
+ }
1319
+ };
1320
+ }
1321
+ function authFailure(auth) {
1322
+ return {
1323
+ isError: true,
1324
+ errorCode: "auth_failed",
1325
+ message: auth.message,
1326
+ reconnectUrl: auth.reconnectUrl,
1327
+ content: [{ type: "text", text: auth.message }]
1328
+ };
1329
+ }
1330
+ var init_hostedMcpEntrypoint = __esm({
1331
+ "../tools/dist/hostedMcpEntrypoint.js"() {
1332
+ "use strict";
1333
+ init_mcpAdapter();
1334
+ }
1335
+ });
1336
+
1337
+ // ../tools/dist/localMcpStdioServer.js
1338
+ function createLocalMcpStdioServer(input) {
1339
+ return {
1340
+ async serve(serverInput) {
1341
+ const adapter = createMcpAdapter({
1342
+ transport: "local_mcp",
1343
+ capabilities: serverInput.capabilities,
1344
+ executor: serverInput.executor
1345
+ });
1346
+ let buffer = "";
1347
+ input.input.setEncoding("utf8");
1348
+ for await (const chunk of input.input) {
1349
+ buffer += chunk;
1350
+ let newline = buffer.indexOf("\n");
1351
+ while (newline >= 0) {
1352
+ const line = buffer.slice(0, newline).trim();
1353
+ buffer = buffer.slice(newline + 1);
1354
+ if (line.length > 0) {
1355
+ await handleLine(line, adapter, input.output, input.error);
1356
+ }
1357
+ newline = buffer.indexOf("\n");
1358
+ }
1359
+ }
1360
+ const trailing = buffer.trim();
1361
+ if (trailing.length > 0) {
1362
+ await handleLine(trailing, adapter, input.output, input.error);
1363
+ }
1364
+ }
1365
+ };
1366
+ }
1367
+ async function handleLine(line, adapter, output, error) {
1368
+ let message;
1369
+ try {
1370
+ message = JSON.parse(line);
1371
+ } catch {
1372
+ writeResponse(output, {
1373
+ jsonrpc: "2.0",
1374
+ id: null,
1375
+ error: { code: -32700, message: "Parse error" }
1376
+ });
1377
+ return;
1378
+ }
1379
+ if (message.id === void 0) {
1380
+ if (message.method === "notifications/initialized")
1381
+ return;
1382
+ error?.write(`Ignoring MCP notification '${String(message.method)}'.
1383
+ `);
1384
+ return;
1385
+ }
1386
+ const id = normalizeId(message.id);
1387
+ if (message.jsonrpc !== "2.0" || typeof message.method !== "string") {
1388
+ writeResponse(output, {
1389
+ jsonrpc: "2.0",
1390
+ id,
1391
+ error: { code: -32600, message: "Invalid Request" }
1392
+ });
1393
+ return;
1394
+ }
1395
+ try {
1396
+ writeResponse(output, {
1397
+ jsonrpc: "2.0",
1398
+ id,
1399
+ result: await dispatchRequest(message.method, message.params, adapter)
1400
+ });
1401
+ } catch (err) {
1402
+ writeResponse(output, {
1403
+ jsonrpc: "2.0",
1404
+ id,
1405
+ error: {
1406
+ code: -32601,
1407
+ message: err instanceof Error ? err.message : "Method not found"
1408
+ }
1409
+ });
1410
+ }
1411
+ }
1412
+ async function dispatchRequest(method, params, adapter) {
1413
+ if (method === "initialize") {
1414
+ const requested = readProtocolVersion(params);
1415
+ return {
1416
+ protocolVersion: requested ?? MCP_PROTOCOL_VERSION,
1417
+ capabilities: { tools: { listChanged: false } },
1418
+ serverInfo: { name: "sift-local-mcp", version: "0.1.0" },
1419
+ instructions: "Use Sift tools to read and write the hosted canonical brain."
1420
+ };
1421
+ }
1422
+ if (method === "ping")
1423
+ return {};
1424
+ if (method === "tools/list")
1425
+ return { tools: adapter.listTools() };
1426
+ if (method === "tools/call") {
1427
+ const call = parseToolCall(params);
1428
+ return adapter.callTool(call);
1429
+ }
1430
+ throw new Error(`Method '${method}' is not supported by Sift local MCP.`);
1431
+ }
1432
+ function readProtocolVersion(params) {
1433
+ if (!isRecord(params))
1434
+ return void 0;
1435
+ return typeof params.protocolVersion === "string" ? params.protocolVersion : void 0;
1436
+ }
1437
+ function parseToolCall(params) {
1438
+ if (!isRecord(params) || typeof params.name !== "string") {
1439
+ throw new Error("tools/call requires a tool name.");
1440
+ }
1441
+ return {
1442
+ name: params.name,
1443
+ arguments: isRecord(params.arguments) ? params.arguments : {}
1444
+ };
1445
+ }
1446
+ function isRecord(value) {
1447
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1448
+ }
1449
+ function normalizeId(value) {
1450
+ if (typeof value === "string" || typeof value === "number" || value === null)
1451
+ return value;
1452
+ return null;
1453
+ }
1454
+ function writeResponse(output, response) {
1455
+ output.write(`${JSON.stringify(response)}
1456
+ `);
1457
+ }
1458
+ var MCP_PROTOCOL_VERSION;
1459
+ var init_localMcpStdioServer = __esm({
1460
+ "../tools/dist/localMcpStdioServer.js"() {
1461
+ "use strict";
1462
+ init_mcpAdapter();
1463
+ MCP_PROTOCOL_VERSION = "2025-11-25";
1464
+ }
1465
+ });
1466
+
1467
+ // ../tools/dist/index.js
1468
+ var dist_exports = {};
1469
+ __export(dist_exports, {
1470
+ MCP_PROTOCOL_VERSION: () => MCP_PROTOCOL_VERSION,
1471
+ createCliCommandMetadata: () => createCliCommandMetadata,
1472
+ createHostedMcpEntrypoint: () => createHostedMcpEntrypoint,
1473
+ createLocalMcpStdioServer: () => createLocalMcpStdioServer,
1474
+ createMcpAdapter: () => createMcpAdapter,
1475
+ createMcpToolSchemas: () => createMcpToolSchemas,
1476
+ createRuntimeToolExecutor: () => createRuntimeToolExecutor,
1477
+ listToolDefinitions: () => listToolDefinitions
1478
+ });
1479
+ var init_dist = __esm({
1480
+ "../tools/dist/index.js"() {
1481
+ "use strict";
1482
+ init_executor();
1483
+ init_generated();
1484
+ init_hostedMcpEntrypoint();
1485
+ init_localMcpStdioServer();
1486
+ init_mcpAdapter();
1487
+ init_registry();
1488
+ }
1489
+ });
1490
+
1491
+ // src/index.ts
1492
+ import { readFile } from "fs/promises";
1493
+
1494
+ // src/support.ts
1495
+ import { createHash } from "crypto";
1496
+ var DEFAULT_CLI_CAPTURE_SOURCE = "CLI Capture";
1497
+ var DEFAULT_CLI_VISIBILITY = "team";
1498
+ function renderScope(scope) {
1499
+ return [
1500
+ `API: ${scope.apiBaseUrl}`,
1501
+ `Token: ${scope.tokenLabel}`,
1502
+ `Principal: ${scope.principalId}`,
1503
+ `Workspace: ${scope.workspaceId}`,
1504
+ `Brain: ${scope.brainId}`,
1505
+ `Capabilities: ${scope.capabilities.join(", ")}`,
1506
+ ""
1507
+ ].join("\n");
1508
+ }
1509
+ function validateAuthenticatedScope(config2, now) {
1510
+ const requiredScope = [
1511
+ ["apiBaseUrl", config2.apiBaseUrl],
1512
+ ["workspaceId", config2.workspaceId],
1513
+ ["brainId", config2.brainId],
1514
+ ["principalId", config2.principalId]
1515
+ ];
1516
+ const missing = requiredScope.find(([, value]) => value.trim().length === 0);
1517
+ if (missing !== void 0) {
1518
+ throw new Error(`Missing authenticated CLI scope: ${missing[0]}.`);
1519
+ }
1520
+ if (config2.tokenExpiresAt !== void 0) {
1521
+ const expiresAt = Date.parse(config2.tokenExpiresAt);
1522
+ if (!Number.isFinite(expiresAt)) {
1523
+ throw new Error("Invalid CLI auth expiry timestamp.");
1524
+ }
1525
+ if (expiresAt <= now.getTime()) {
1526
+ throw new Error("Sift CLI auth has expired. Reconnect or refresh the configured token.");
1527
+ }
1528
+ }
1529
+ }
1530
+ function renderSearchResult(result2) {
1531
+ if (typeof result2 === "object" && result2 !== null && "contextMarkdown" in result2) {
1532
+ const context = result2;
1533
+ return `${context.contextMarkdown}
1534
+ `;
1535
+ }
1536
+ return `${JSON.stringify(result2)}
1537
+ `;
1538
+ }
1539
+ function renderRecordResult(result2) {
1540
+ if (typeof result2 === "object" && result2 !== null && "markdown" in result2) {
1541
+ const record = result2;
1542
+ return `${record.markdown}
1543
+ `;
1544
+ }
1545
+ return `${JSON.stringify(result2)}
1546
+ `;
1547
+ }
1548
+ function renderProfileResult(result2) {
1549
+ if (typeof result2 === "object" && result2 !== null && "profileMarkdown" in result2) {
1550
+ const profile = result2;
1551
+ return `${profile.profileMarkdown}
1552
+ `;
1553
+ }
1554
+ return `${JSON.stringify(result2)}
1555
+ `;
1556
+ }
1557
+ function renderTools(tools) {
1558
+ return `${tools.map((tool) => `${tool.name}: ${tool.summary}`).join("\n")}
1559
+ `;
1560
+ }
1561
+ function renderSiftFound(result2) {
1562
+ return `Sift found:
1563
+
1564
+ ${renderSearchResult(result2)}`;
1565
+ }
1566
+ function renderWriteReceipt(action, result2) {
1567
+ if (typeof result2 !== "object" || result2 === null) {
1568
+ return `${action} complete.
1569
+ ${JSON.stringify(result2)}
1570
+ `;
1571
+ }
1572
+ const record = result2;
1573
+ const lines = [`${action} complete.`];
1574
+ addReceiptLine(lines, "Record", record.recordId);
1575
+ addReceiptLine(lines, "Version", record.versionId);
1576
+ addReceiptLine(lines, "Source", record.sourceId);
1577
+ addReceiptLine(lines, "Source item", record.sourceItemId);
1578
+ if (typeof record.job === "object" && record.job !== null && "id" in record.job) {
1579
+ addReceiptLine(lines, "Job", record.job.id);
1580
+ }
1581
+ if (lines.length === 1) {
1582
+ lines.push(JSON.stringify(result2));
1583
+ }
1584
+ lines.push("");
1585
+ return lines.join("\n");
1586
+ }
1587
+ function renderDoctorResult(result2) {
1588
+ return `${result2.checks.map((check) => {
1589
+ const fix = check.fix === void 0 ? "" : ` Fix: ${check.fix}`;
1590
+ return `[${check.status}] ${check.label}: ${check.detail}${fix}`;
1591
+ }).join("\n")}
1592
+ `;
1593
+ }
1594
+ function aliasJson(command, tool, result2) {
1595
+ return `${JSON.stringify({ command, tool, result: result2 })}
1596
+ `;
1597
+ }
1598
+ function positionalArgs(args) {
1599
+ const positionals = [];
1600
+ for (let index = 0; index < args.length; index += 1) {
1601
+ const key = args[index];
1602
+ if (key?.startsWith("--") === true) {
1603
+ index += 1;
1604
+ } else if (key !== void 0) {
1605
+ positionals.push(key);
1606
+ }
1607
+ }
1608
+ return positionals;
1609
+ }
1610
+ function parseOptions(args) {
1611
+ const parsed = /* @__PURE__ */ new Map();
1612
+ for (let index = 0; index < args.length; index += 1) {
1613
+ const key = args[index];
1614
+ const value = args[index + 1];
1615
+ if (key?.startsWith("--") === true && value !== void 0 && !value.startsWith("--")) {
1616
+ parsed.set(key.slice(2), value);
1617
+ index += 1;
1618
+ }
1619
+ }
1620
+ return parsed;
1621
+ }
1622
+ function parseIntegerOption(options, key, fallback) {
1623
+ const raw = options.get(key);
1624
+ if (raw === void 0) {
1625
+ return fallback;
1626
+ }
1627
+ const parsed = Number(raw);
1628
+ if (!Number.isInteger(parsed)) {
1629
+ throw new Error(`Option --${key} must be an integer.`);
1630
+ }
1631
+ return parsed;
1632
+ }
1633
+ function requireOption(options, key) {
1634
+ const value = options.get(key);
1635
+ if (value === void 0 || value.trim().length === 0) {
1636
+ throw new Error(`Missing required option --${key}.`);
1637
+ }
1638
+ return value;
1639
+ }
1640
+ function optionalOption(options, key) {
1641
+ const value = options.get(key);
1642
+ if (value === void 0 || value.trim().length === 0) {
1643
+ return void 0;
1644
+ }
1645
+ return value;
1646
+ }
1647
+ function addOptionalWorkMetadata(input, parsed) {
1648
+ const authorship = optionalOption(parsed, "authorship");
1649
+ if (authorship !== void 0) {
1650
+ input.authorship = authorship;
1651
+ }
1652
+ const evidence = optionalOption(parsed, "evidence");
1653
+ if (evidence !== void 0) {
1654
+ input.evidenceIds = evidence.split(",").map((item) => item.trim()).filter((item) => item.length > 0);
1655
+ }
1656
+ }
1657
+ function basename(path) {
1658
+ const normalized = path.replaceAll("\\", "/");
1659
+ return normalized.slice(normalized.lastIndexOf("/") + 1);
1660
+ }
1661
+ function sha256Hex(input) {
1662
+ return createHash("sha256").update(input).digest("hex");
1663
+ }
1664
+ function normalizeCliTextBody(text) {
1665
+ const withoutBom = text.startsWith("\uFEFF") ? text.slice(1) : text;
1666
+ return withoutBom.replace(/\r\n?/gu, "\n").trim();
1667
+ }
1668
+ function defaultCliTextExternalId(input) {
1669
+ const normalized = normalizeCliTextBody(input.body);
1670
+ const date = input.now.toISOString().slice(0, 10);
1671
+ return `cli-text:${date}:${sha256Hex(normalized)}`;
1672
+ }
1673
+ function defaultCliFileExternalId(input) {
1674
+ const hash = createHash("sha256");
1675
+ hash.update(input.basename);
1676
+ hash.update(new Uint8Array([0]));
1677
+ hash.update(String(input.bytes.byteLength));
1678
+ hash.update(new Uint8Array([0]));
1679
+ hash.update(input.bytes);
1680
+ return `cli-file:${hash.digest("hex")}`;
1681
+ }
1682
+ function anchorFromHeadingTitle(title) {
1683
+ const anchor = title.toLowerCase().replace(/[^a-z0-9]+/gu, "-").replace(/^-+|-+$/gu, "");
1684
+ return anchor.length === 0 ? "section" : anchor;
1685
+ }
1686
+ function defaultCliTitle(body) {
1687
+ const firstLine = normalizeCliTextBody(body).split("\n").map((line) => line.trim()).find((line) => line.length > 0);
1688
+ return firstLine === void 0 ? "" : firstLine.slice(0, 80);
1689
+ }
1690
+ function inferContentType(path) {
1691
+ const lower = path.toLowerCase();
1692
+ if (lower.endsWith(".md") || lower.endsWith(".markdown")) return "text/markdown";
1693
+ if (lower.endsWith(".txt")) return "text/plain";
1694
+ if (lower.endsWith(".html") || lower.endsWith(".htm")) return "text/html";
1695
+ if (lower.endsWith(".pdf")) return "application/pdf";
1696
+ return "application/octet-stream";
1697
+ }
1698
+ function errorResult(error, json) {
1699
+ const code = classifyError(error);
1700
+ const message = error instanceof Error ? error.message : "Command failed.";
1701
+ return errorResultWithCode(code, message, json);
1702
+ }
1703
+ function errorResultWithCode(code, message, json) {
1704
+ if (json) {
1705
+ return {
1706
+ exitCode: 1,
1707
+ stdout: `${JSON.stringify({ error: { code, message } })}
1708
+ `,
1709
+ stderr: ""
1710
+ };
1711
+ }
1712
+ return fail(`${code}: ${message}`);
1713
+ }
1714
+ function ok(stdout) {
1715
+ return { exitCode: 0, stdout, stderr: "" };
1716
+ }
1717
+ function fail(message) {
1718
+ return { exitCode: 1, stdout: "", stderr: `${message}
1719
+ ` };
1720
+ }
1721
+ function classifyError(error) {
1722
+ if (error instanceof Error) {
1723
+ if (isPermissionError(error)) {
1724
+ return "permission_denied";
1725
+ }
1726
+ if (isMissingServiceContractError(error)) {
1727
+ return "tool_unavailable";
1728
+ }
1729
+ if (error.message.includes("CLI auth has expired")) {
1730
+ return "auth_failed";
1731
+ }
1732
+ if (isConflictError(error)) {
1733
+ return "conflict";
1734
+ }
1735
+ if (isNotFoundError(error)) {
1736
+ return "not_found";
1737
+ }
1738
+ if (isValidationError(error)) {
1739
+ return "validation_failure";
1740
+ }
1741
+ if (isRetriableUpstreamError(error)) {
1742
+ return "retriable_upstream_failure";
1743
+ }
1744
+ }
1745
+ return "internal_error";
1746
+ }
1747
+ function isPermissionError(error) {
1748
+ return error.name === "RuntimePermissionDeniedError" || error.message.startsWith("missing capability ");
1749
+ }
1750
+ function isMissingServiceContractError(error) {
1751
+ return error.message.includes(" requires ") && error.message.includes(" service contract.");
1752
+ }
1753
+ function isConflictError(error) {
1754
+ return error.name.includes("Conflict") || error.message.includes(" changed before ");
1755
+ }
1756
+ function isNotFoundError(error) {
1757
+ return error.name.includes("NotFound") || /\bnot found\b/iu.test(error.message);
1758
+ }
1759
+ function isValidationError(error) {
1760
+ return error.message.endsWith(" is required.") || error.message.includes("Missing required option") || error.message.includes("Missing authenticated CLI scope") || error.message.includes("Invalid CLI auth expiry");
1761
+ }
1762
+ function isRetriableUpstreamError(error) {
1763
+ return error.message.includes("fetch failed") || error.message.includes("ECONN") || error.message.toLowerCase().includes("timeout") || error.name.includes("Upstream");
1764
+ }
1765
+ function addReceiptLine(lines, label, value) {
1766
+ if (typeof value === "string" && value.trim().length > 0) {
1767
+ lines.push(`${label}: ${value}`);
1768
+ }
1769
+ }
1770
+
1771
+ // src/auth/commandAdapter.ts
1772
+ function isAuthCommand(commandKey) {
1773
+ return commandKey === "login:" || commandKey === "auth:status" || commandKey === "logout:";
1774
+ }
1775
+ function authCommand(authCommands2, command, input) {
1776
+ if (authCommands2 === void 0) {
1777
+ return errorResultWithCode(
1778
+ "tool_unavailable",
1779
+ "No Sift CLI auth command runtime is configured.",
1780
+ input.json
1781
+ );
1782
+ }
1783
+ if (command === "login") {
1784
+ return authCommands2.login({ rest: input.rest ?? [], json: input.json });
1785
+ }
1786
+ if (command === "status") {
1787
+ return authCommands2.status({ json: input.json });
1788
+ }
1789
+ return authCommands2.logout({ json: input.json });
1790
+ }
1791
+
1792
+ // src/capabilityGuard.ts
1793
+ var commandCapabilities = {
1794
+ "whoami:": "record:read",
1795
+ "brain:list": "record:read",
1796
+ "brain:use": "record:read",
1797
+ "ask:": "record:read",
1798
+ "search:": "record:read",
1799
+ "show:": "record:read",
1800
+ "status:": "record:read",
1801
+ "scope:current": "record:read",
1802
+ "tools:list": "record:read",
1803
+ "tools:schema": "record:read",
1804
+ "tools:help": "record:read",
1805
+ "capture:text": "source:write",
1806
+ "capture:file": "source:write",
1807
+ "capture:batch": "source:write",
1808
+ "remember:": "source:write",
1809
+ "add:": "source:write",
1810
+ "source:list": "record:read",
1811
+ "source:create": "source:write",
1812
+ "source:get": "record:read",
1813
+ "source:status": "record:read",
1814
+ "ingestion:status": "record:read",
1815
+ "record:list": "record:read",
1816
+ "record:get": "record:read",
1817
+ "record:create-markdown": "record:write",
1818
+ "record:patch-section": "record:write",
1819
+ "record:versions": "record:read",
1820
+ "edit:": "record:write",
1821
+ "decision:create": "record:write",
1822
+ "task:create": "record:write",
1823
+ "decide:": "record:write",
1824
+ "todo:": "record:write",
1825
+ "search:query": "record:read",
1826
+ "context:assemble": "record:read",
1827
+ "context:profile": "record:read",
1828
+ "evidence:list": "record:read",
1829
+ "evidence:get": "record:read",
1830
+ "graph:neighbors": "record:read",
1831
+ "event:list": "record:read",
1832
+ "audit:events": "event:audit:read"
1833
+ };
1834
+ function validateCommandCapability(input) {
1835
+ const capability = commandCapabilities[input.commandKey];
1836
+ if (capability !== void 0 && !input.config.capabilities.includes(capability)) {
1837
+ throw new Error(`missing capability ${capability}`);
1838
+ }
1839
+ }
1840
+
1841
+ // src/doctor.ts
1842
+ async function doctor(input) {
1843
+ const checks = [
1844
+ { id: "bin", status: "ok", label: "Bin", detail: "sift command entrypoint is configured." },
1845
+ { id: "package", status: "ok", label: "Package", detail: "@sift-wiki/cli version unknown, bin sift." },
1846
+ authCheck(input.config, input.now),
1847
+ scopeCheck(input.config)
1848
+ ];
1849
+ const apiCheck = await checkApi(input.executor);
1850
+ checks.push(apiCheck);
1851
+ const availableTools3 = await discoverToolNames(input.executor);
1852
+ checks.push(readToolsCheck(availableTools3));
1853
+ checks.push(writeToolsCheck(input.config, availableTools3));
1854
+ checks.push(recordGetCheck(availableTools3));
1855
+ const result2 = {
1856
+ ok: !checks.some((check) => check.status === "failed"),
1857
+ apiBaseUrl: input.config.apiBaseUrl.trim().length > 0 ? input.config.apiBaseUrl : void 0,
1858
+ scope: scopeResult(input.config),
1859
+ checks
1860
+ };
1861
+ return {
1862
+ exitCode: result2.ok ? 0 : 1,
1863
+ stdout: input.json ? `${JSON.stringify(result2)}
1864
+ ` : renderDoctorResult(result2),
1865
+ stderr: ""
1866
+ };
1867
+ }
1868
+ async function discoverToolNames(executor) {
1869
+ if (executor === void 0) return void 0;
1870
+ if (executor.listAvailableToolNames !== void 0) return executor.listAvailableToolNames();
1871
+ const result2 = await executor.execute("tools.list", {});
1872
+ return toolNamesFromResult(result2);
1873
+ }
1874
+ async function apiReachability(executor) {
1875
+ if (executor === void 0) return { reachable: false, detail: "No API executor is configured." };
1876
+ try {
1877
+ await executor.execute("whoami", {});
1878
+ return { reachable: true, detail: "whoami succeeded." };
1879
+ } catch (error) {
1880
+ return {
1881
+ reachable: false,
1882
+ detail: error instanceof Error ? error.message : "Hosted Sift API request failed."
1883
+ };
1884
+ }
1885
+ }
1886
+ function scopeResult(config2) {
1887
+ if (config2.workspaceId.trim().length === 0 || config2.brainId.trim().length === 0 || config2.principalId.trim().length === 0) {
1888
+ return void 0;
1889
+ }
1890
+ return {
1891
+ workspaceId: config2.workspaceId,
1892
+ brainId: config2.brainId,
1893
+ principalId: config2.principalId,
1894
+ capabilities: [...config2.capabilities]
1895
+ };
1896
+ }
1897
+ async function checkApi(executor) {
1898
+ if (executor === void 0) {
1899
+ return {
1900
+ id: "api",
1901
+ status: "warning",
1902
+ label: "API",
1903
+ detail: "not checked because no API executor is configured.",
1904
+ fix: "Run sift login or configure hosted API credentials."
1905
+ };
1906
+ }
1907
+ const api = await apiReachability(executor);
1908
+ return api.reachable ? { id: "api", status: "ok", label: "API", detail: "whoami succeeded." } : { id: "api", status: "failed", label: "API", detail: api.detail };
1909
+ }
1910
+ function authCheck(config2, now) {
1911
+ if (config2.apiBaseUrl.trim().length === 0 || config2.workspaceId.trim().length === 0 || config2.brainId.trim().length === 0 || config2.principalId.trim().length === 0) {
1912
+ return {
1913
+ id: "auth",
1914
+ status: "failed",
1915
+ label: "Auth",
1916
+ detail: "no authenticated CLI profile is loaded.",
1917
+ fix: "Run sift login."
1918
+ };
1919
+ }
1920
+ if (config2.tokenExpiresAt !== void 0 && Date.parse(config2.tokenExpiresAt) <= now.getTime()) {
1921
+ return {
1922
+ id: "auth",
1923
+ status: "failed",
1924
+ label: "Auth",
1925
+ detail: "configured CLI auth has expired.",
1926
+ fix: "Run sift login again."
1927
+ };
1928
+ }
1929
+ return { id: "auth", status: "ok", label: "Auth", detail: "authenticated profile loaded." };
1930
+ }
1931
+ function scopeCheck(config2) {
1932
+ if (config2.workspaceId.trim().length === 0 || config2.brainId.trim().length === 0) {
1933
+ return {
1934
+ id: "scope",
1935
+ status: "failed",
1936
+ label: "Scope",
1937
+ detail: "workspace or brain scope is missing.",
1938
+ fix: "Run sift scope current after login."
1939
+ };
1940
+ }
1941
+ return {
1942
+ id: "scope",
1943
+ status: "ok",
1944
+ label: "Scope",
1945
+ detail: `${config2.workspaceId}/${config2.brainId}`
1946
+ };
1947
+ }
1948
+ function readToolsCheck(names) {
1949
+ return toolSetCheck("read-tools", "Read tools", ["context.assemble", "search.query"], names);
1950
+ }
1951
+ function writeToolsCheck(config2, names) {
1952
+ const hasWrite = config2.capabilities.includes("record:write") || config2.capabilities.includes("source:write");
1953
+ if (!hasWrite) {
1954
+ return {
1955
+ id: "write-tools",
1956
+ status: "warning",
1957
+ label: "Write tools",
1958
+ detail: "write capability is not present for this token."
1959
+ };
1960
+ }
1961
+ return toolSetCheck(
1962
+ "write-tools",
1963
+ "Write tools",
1964
+ ["capture.text", "capture.file", "record.patch_section", "decision.create", "task.create"],
1965
+ names
1966
+ );
1967
+ }
1968
+ function recordGetCheck(names) {
1969
+ if (names === void 0) {
1970
+ return {
1971
+ id: "record-get-contract",
1972
+ status: "warning",
1973
+ label: "record.get",
1974
+ detail: "runtime tool discovery was not available."
1975
+ };
1976
+ }
1977
+ return names.includes("record.get") ? { id: "record-get-contract", status: "ok", label: "record.get", detail: "available." } : {
1978
+ id: "record-get-contract",
1979
+ status: "failed",
1980
+ label: "record.get",
1981
+ detail: "runtime discovery did not advertise record.get."
1982
+ };
1983
+ }
1984
+ function toolSetCheck(id, label, required, names) {
1985
+ if (names === void 0) {
1986
+ return { id, status: "warning", label, detail: "runtime tool discovery was not available." };
1987
+ }
1988
+ const missing = required.filter((name) => !names.includes(name));
1989
+ return missing.length === 0 ? { id, status: "ok", label, detail: "required tools are available." } : { id, status: "failed", label, detail: `missing ${missing.join(", ")}.` };
1990
+ }
1991
+ function toolNamesFromResult(result2) {
1992
+ if (!Array.isArray(result2)) return [];
1993
+ return result2.flatMap((item) => {
1994
+ if (typeof item === "object" && item !== null && "name" in item) {
1995
+ const name = item.name;
1996
+ return typeof name === "string" ? [name] : [];
1997
+ }
1998
+ return [];
1999
+ });
2000
+ }
2001
+
2002
+ // src/simpleCommands.ts
2003
+ var knownTopLevelCommands = /* @__PURE__ */ new Set([
2004
+ "add",
2005
+ "ask",
2006
+ "audit",
2007
+ "auth",
2008
+ "brain",
2009
+ "capture",
2010
+ "context",
2011
+ "decision",
2012
+ "decide",
2013
+ "doctor",
2014
+ "edit",
2015
+ "event",
2016
+ "evidence",
2017
+ "graph",
2018
+ "ingestion",
2019
+ "login",
2020
+ "logout",
2021
+ "mcp",
2022
+ "record",
2023
+ "remember",
2024
+ "scope",
2025
+ "search",
2026
+ "show",
2027
+ "source",
2028
+ "status",
2029
+ "task",
2030
+ "thread",
2031
+ "todo",
2032
+ "tools",
2033
+ "whoami"
2034
+ ]);
2035
+ var valueOptions = /* @__PURE__ */ new Set([
2036
+ "anchor",
2037
+ "authorship",
2038
+ "content-type",
2039
+ "due-date",
2040
+ "evidence",
2041
+ "expected",
2042
+ "external-id",
2043
+ "limit",
2044
+ "max-chars",
2045
+ "owner",
2046
+ "rationale",
2047
+ "replace",
2048
+ "section",
2049
+ "source",
2050
+ "state",
2051
+ "status",
2052
+ "title",
2053
+ "visibility"
2054
+ ]);
2055
+ function resolveSimpleCommand(input) {
2056
+ const [group, command] = input.args;
2057
+ if (group === void 0) {
2058
+ return void 0;
2059
+ }
2060
+ if (group === "ask") {
2061
+ return { commandKey: "ask:", run: () => ask(input.executor, input.args.slice(1), input.json) };
2062
+ }
2063
+ if (group === "search" && command !== "query") {
2064
+ return {
2065
+ commandKey: "search:",
2066
+ run: () => simpleSearch(input.executor, input.args.slice(1), input.json)
2067
+ };
2068
+ }
2069
+ if (group === "remember") {
2070
+ return {
2071
+ commandKey: "remember:",
2072
+ run: () => remember(input.executor, input.args.slice(1), input.json, input.readStdin, input.now)
2073
+ };
2074
+ }
2075
+ if (group === "add") {
2076
+ return {
2077
+ commandKey: "add:",
2078
+ run: () => addFile(input.executor, input.readFile, input.args.slice(1), input.json)
2079
+ };
2080
+ }
2081
+ if (group === "edit") {
2082
+ return { commandKey: "edit:", run: () => edit(input.executor, input.args.slice(1), input.json) };
2083
+ }
2084
+ if (group === "decide") {
2085
+ return {
2086
+ commandKey: "decide:",
2087
+ run: () => decide(input.executor, input.args.slice(1), input.json)
2088
+ };
2089
+ }
2090
+ if (group === "todo") {
2091
+ return { commandKey: "todo:", run: () => todo(input.executor, input.args.slice(1), input.json) };
2092
+ }
2093
+ if (group === "show") {
2094
+ return {
2095
+ commandKey: "show:",
2096
+ run: () => show(input.executor, input.args.slice(1), input.json)
2097
+ };
2098
+ }
2099
+ if (group === "status" && command === void 0) {
2100
+ return {
2101
+ commandKey: "status:",
2102
+ run: () => status(input.config, input.executor, input.json)
2103
+ };
2104
+ }
2105
+ if (!knownTopLevelCommands.has(group)) {
2106
+ return { commandKey: "ask:", run: () => ask(input.executor, input.args, input.json) };
2107
+ }
2108
+ return void 0;
2109
+ }
2110
+ async function ask(executor, rest, json) {
2111
+ if (executor === void 0) {
2112
+ return fail("No Sift API executor is configured for context.assemble.");
2113
+ }
2114
+ const parsed = parseOptions(rest);
2115
+ const query = argsWithoutOptions(rest).join(" ").trim();
2116
+ const result2 = await executor.execute("context.assemble", {
2117
+ query,
2118
+ maxChars: parseIntegerOption(parsed, "max-chars", 8e3)
2119
+ });
2120
+ return ok(json ? aliasJson("ask", "context.assemble", result2) : renderSiftFound(result2));
2121
+ }
2122
+ async function simpleSearch(executor, rest, json) {
2123
+ if (executor === void 0) {
2124
+ return fail("No Sift API executor is configured for search.query.");
2125
+ }
2126
+ const parsed = parseOptions(rest);
2127
+ const query = argsWithoutOptions(rest).join(" ").trim();
2128
+ const result2 = await executor.execute("search.query", {
2129
+ query,
2130
+ limit: parseIntegerOption(parsed, "limit", 10)
2131
+ });
2132
+ return ok(json ? aliasJson("search", "search.query", result2) : renderSearchResult(result2));
2133
+ }
2134
+ async function remember(executor, rest, json, readStdin2, now) {
2135
+ if (executor === void 0) {
2136
+ return fail("No Sift API executor is configured for capture.text.");
2137
+ }
2138
+ const parsed = parseOptions(rest);
2139
+ const rawBody = rest.includes("--stdin") ? await readRequiredStdin(readStdin2) : argsWithoutOptions(rest).join(" ");
2140
+ const markdown = normalizeCliTextBody(rawBody);
2141
+ if (markdown.length === 0) {
2142
+ throw new Error("remember content is required.");
2143
+ }
2144
+ const input = {
2145
+ sourceName: optionalOption(parsed, "source") ?? DEFAULT_CLI_CAPTURE_SOURCE,
2146
+ externalId: optionalOption(parsed, "external-id") ?? defaultCliTextExternalId({ body: markdown, now }),
2147
+ title: optionalOption(parsed, "title") ?? defaultCliTitle(markdown),
2148
+ visibility: [optionalOption(parsed, "visibility") ?? DEFAULT_CLI_VISIBILITY],
2149
+ markdown
2150
+ };
2151
+ const result2 = await executor.execute("capture.text", input);
2152
+ return ok(json ? aliasJson("remember", "capture.text", result2) : renderWriteReceipt("Remember", result2));
2153
+ }
2154
+ async function addFile(executor, fileReader, rest, json) {
2155
+ if (executor === void 0) {
2156
+ return fail("No Sift API executor is configured for capture.file.");
2157
+ }
2158
+ const [path, ...optionArgs] = rest;
2159
+ if (path === void 0 || path.trim().length === 0) {
2160
+ return fail("Missing required file path for add.");
2161
+ }
2162
+ const parsed = parseOptions(optionArgs);
2163
+ const bytes = await fileReader(path);
2164
+ const fileBasename = basename(path);
2165
+ const input = {
2166
+ sourceName: optionalOption(parsed, "source") ?? DEFAULT_CLI_CAPTURE_SOURCE,
2167
+ externalId: optionalOption(parsed, "external-id") ?? defaultCliFileExternalId({ basename: fileBasename, bytes }),
2168
+ title: optionalOption(parsed, "title") ?? fileBasename,
2169
+ filename: fileBasename,
2170
+ contentType: optionalOption(parsed, "content-type") ?? inferContentType(path),
2171
+ bytes,
2172
+ visibility: [optionalOption(parsed, "visibility") ?? DEFAULT_CLI_VISIBILITY]
2173
+ };
2174
+ const result2 = await executor.execute("capture.file", input);
2175
+ return ok(json ? aliasJson("add", "capture.file", result2) : renderWriteReceipt("Add", result2));
2176
+ }
2177
+ async function edit(executor, rest, json) {
2178
+ if (executor === void 0) {
2179
+ return fail("No Sift API executor is configured for record.patch_section.");
2180
+ }
2181
+ const [recordId, ...optionArgs] = rest;
2182
+ if (recordId === void 0 || recordId.trim().length === 0) {
2183
+ return fail("Missing required record ID for edit.");
2184
+ }
2185
+ const parsed = parseOptions(optionArgs);
2186
+ const section = optionalOption(parsed, "section");
2187
+ const anchor = optionalOption(parsed, "anchor");
2188
+ if (section === void 0 && anchor === void 0 || section !== void 0 && anchor !== void 0) {
2189
+ throw new Error("Exactly one of --section or --anchor is required.");
2190
+ }
2191
+ const input = {
2192
+ recordId,
2193
+ anchor: anchor === void 0 ? anchorFromHeadingTitle(section ?? "") : anchor.trim(),
2194
+ replacementMarkdown: requireOption(parsed, "replace")
2195
+ };
2196
+ const expectedMarkdown = optionalOption(parsed, "expected");
2197
+ if (expectedMarkdown !== void 0) {
2198
+ input.expectedMarkdown = expectedMarkdown;
2199
+ }
2200
+ const result2 = await executor.execute("record.patch_section", input);
2201
+ return ok(json ? aliasJson("edit", "record.patch_section", result2) : renderWriteReceipt("Edit", result2));
2202
+ }
2203
+ async function decide(executor, rest, json) {
2204
+ if (executor === void 0) {
2205
+ return fail("No Sift API executor is configured for decision.create.");
2206
+ }
2207
+ const parsed = parseOptions(rest);
2208
+ const input = {
2209
+ statement: argsWithoutOptions(rest).join(" ").trim(),
2210
+ state: optionalOption(parsed, "state") ?? "accepted",
2211
+ visibility: [optionalOption(parsed, "visibility") ?? DEFAULT_CLI_VISIBILITY]
2212
+ };
2213
+ addOptionalWorkAliasMetadata(input, parsed);
2214
+ const result2 = await executor.execute("decision.create", input);
2215
+ return ok(json ? aliasJson("decide", "decision.create", result2) : renderWriteReceipt("Decision", result2));
2216
+ }
2217
+ async function todo(executor, rest, json) {
2218
+ if (executor === void 0) {
2219
+ return fail("No Sift API executor is configured for task.create.");
2220
+ }
2221
+ const parsed = parseOptions(rest);
2222
+ const input = {
2223
+ title: argsWithoutOptions(rest).join(" ").trim(),
2224
+ status: optionalOption(parsed, "status") ?? "open",
2225
+ visibility: [optionalOption(parsed, "visibility") ?? DEFAULT_CLI_VISIBILITY]
2226
+ };
2227
+ const owner = optionalOption(parsed, "owner");
2228
+ if (owner !== void 0) input.owner = owner;
2229
+ const dueDate = optionalOption(parsed, "due-date");
2230
+ if (dueDate !== void 0) input.dueDate = dueDate;
2231
+ addOptionalWorkAliasMetadata(input, parsed);
2232
+ const result2 = await executor.execute("task.create", input);
2233
+ return ok(json ? aliasJson("todo", "task.create", result2) : renderWriteReceipt("Task", result2));
2234
+ }
2235
+ async function show(executor, rest, json) {
2236
+ if (executor === void 0) {
2237
+ return fail("No Sift API executor is configured for record.get.");
2238
+ }
2239
+ if (!await isToolAvailable(executor, "record.get")) {
2240
+ return errorResultWithCode(
2241
+ "tool_unavailable",
2242
+ "Tool 'record.get' is unavailable for this CLI transport or scope.",
2243
+ json
2244
+ );
2245
+ }
2246
+ const [recordId, ...optionArgs] = rest;
2247
+ if (recordId === void 0 || recordId.trim().length === 0) {
2248
+ return fail("Missing required record ID for show.");
2249
+ }
2250
+ const parsed = parseOptions(optionArgs);
2251
+ const input = { recordId };
2252
+ const sectionAnchor = optionalOption(parsed, "section");
2253
+ if (sectionAnchor !== void 0) {
2254
+ input.sectionAnchor = sectionAnchor;
2255
+ }
2256
+ const result2 = await executor.execute("record.get", input);
2257
+ return ok(json ? aliasJson("show", "record.get", result2) : renderRecordResult(result2));
2258
+ }
2259
+ async function status(config2, executor, json) {
2260
+ const scope = {
2261
+ apiBaseUrl: config2.apiBaseUrl,
2262
+ principalId: config2.principalId,
2263
+ workspaceId: config2.workspaceId,
2264
+ brainId: config2.brainId,
2265
+ capabilities: [...config2.capabilities]
2266
+ };
2267
+ const api = await apiReachability(executor);
2268
+ const result2 = { scope, api };
2269
+ if (json) {
2270
+ return ok(`${JSON.stringify({ command: "status", result: result2 })}
2271
+ `);
2272
+ }
2273
+ return ok(`${renderScope({ ...scope, tokenLabel: "configured" })}API reachable: ${api.reachable}
2274
+ `);
2275
+ }
2276
+ async function readRequiredStdin(readStdin2) {
2277
+ if (readStdin2 === void 0) {
2278
+ throw new Error("stdin reader is required.");
2279
+ }
2280
+ return readStdin2();
2281
+ }
2282
+ async function isToolAvailable(executor, toolName) {
2283
+ const names = await discoverToolNames(executor);
2284
+ return names?.includes(toolName) === true;
2285
+ }
2286
+ function addOptionalWorkAliasMetadata(input, parsed) {
2287
+ const rationale = optionalOption(parsed, "rationale");
2288
+ if (rationale !== void 0) input.rationale = rationale;
2289
+ const authorship = optionalOption(parsed, "authorship");
2290
+ if (authorship !== void 0) input.authorship = authorship;
2291
+ const evidence = optionalOption(parsed, "evidence");
2292
+ if (evidence !== void 0) {
2293
+ input.evidenceIds = evidence.split(",").map((item) => item.trim()).filter((item) => item.length > 0);
2294
+ }
2295
+ }
2296
+ function argsWithoutOptions(args) {
2297
+ const positionals = [];
2298
+ for (let index = 0; index < args.length; index += 1) {
2299
+ const arg = args[index];
2300
+ if (arg === void 0) continue;
2301
+ if (!arg.startsWith("--")) {
2302
+ positionals.push(arg);
2303
+ continue;
2304
+ }
2305
+ const key = arg.slice(2);
2306
+ if (valueOptions.has(key)) {
2307
+ index += 1;
2308
+ }
2309
+ }
2310
+ return positionals;
2311
+ }
2312
+
2313
+ // src/toolDiscovery.ts
2314
+ function toolsList(input) {
2315
+ if (input.executor !== void 0) {
2316
+ return executeSimple(input.executor, "tools.list", {}, input.json);
2317
+ }
2318
+ const tools = input.metadata?.filter((tool) => input.config.capabilities.includes(tool.capability)) ?? [];
2319
+ return ok(input.json ? `${JSON.stringify(tools)}
2320
+ ` : renderTools(tools));
2321
+ }
2322
+ function toolsHelp(input) {
2323
+ const [name] = input.rest;
2324
+ if (name === void 0 || name.trim().length === 0) {
2325
+ return Promise.resolve(fail("Missing required tool name for tools.help."));
2326
+ }
2327
+ if (input.executor === void 0) {
2328
+ const tool = input.metadata?.find(
2329
+ (item) => item.name === name && input.config.capabilities.includes(item.capability)
2330
+ );
2331
+ if (tool === void 0) {
2332
+ return Promise.resolve(
2333
+ errorResultWithCode(
2334
+ "tool_unavailable",
2335
+ `Tool '${name}' is unavailable for this CLI transport or scope.`,
2336
+ input.json
2337
+ )
2338
+ );
2339
+ }
2340
+ return Promise.resolve(ok(input.json ? `${JSON.stringify(tool)}
2341
+ ` : renderTools([tool])));
2342
+ }
2343
+ return executeSimple(input.executor, "tools.help", { name }, input.json);
2344
+ }
2345
+ async function executeSimple(executor, name, toolInput, json) {
2346
+ const result2 = await executor.execute(name, toolInput);
2347
+ return ok(json ? `${JSON.stringify(result2)}
2348
+ ` : `${JSON.stringify(result2)}
2349
+ `);
2350
+ }
2351
+
2352
+ // src/hostedApiExecutor.ts
2353
+ function createHostedApiExecutor(input) {
2354
+ const fetchImpl = input.fetch ?? globalThis.fetch;
2355
+ return {
2356
+ async execute(name, toolInput) {
2357
+ const response = await fetchImpl(toolUrl(input.apiBaseUrl, name), {
2358
+ method: "POST",
2359
+ headers: {
2360
+ authorization: `Bearer ${input.token}`,
2361
+ "content-type": "application/json",
2362
+ "x-sift-brain-id": input.brainId,
2363
+ "x-sift-workspace-id": input.workspaceId
2364
+ },
2365
+ body: JSON.stringify({ input: toolInput }, serializeJsonValue)
2366
+ });
2367
+ const body = await response.text();
2368
+ const parsed = body.length > 0 ? parseJson(body) : {};
2369
+ if (!response.ok) {
2370
+ throw new Error(errorMessage(parsed, response.status));
2371
+ }
2372
+ return parsed;
2373
+ }
2374
+ };
2375
+ }
2376
+ function serializeJsonValue(_key, value) {
2377
+ if (value instanceof Uint8Array) {
2378
+ return [...value];
2379
+ }
2380
+ return value;
2381
+ }
2382
+ function toolUrl(apiBaseUrl, name) {
2383
+ return `${apiBaseUrl.replace(/\/+$/u, "")}/agent-tools/${encodeURIComponent(name)}`;
2384
+ }
2385
+ function parseJson(body) {
2386
+ try {
2387
+ return JSON.parse(body);
2388
+ } catch {
2389
+ throw new Error("Hosted Sift API returned invalid JSON.");
2390
+ }
2391
+ }
2392
+ function errorMessage(parsed, status2) {
2393
+ if (typeof parsed === "object" && parsed !== null && "error" in parsed) {
2394
+ const error = parsed.error;
2395
+ if (typeof error === "object" && error !== null && "message" in error) {
2396
+ const message = error.message;
2397
+ if (typeof message === "string" && message.trim().length > 0) {
2398
+ return message;
2399
+ }
2400
+ }
2401
+ }
2402
+ return `Hosted Sift API request failed with status ${status2}.`;
2403
+ }
2404
+
2405
+ // src/index.ts
2406
+ async function runSiftCli(input) {
2407
+ const json = input.argv.includes("--json");
2408
+ const args = input.argv.filter((arg) => arg !== "--json");
2409
+ const [group, command, ...rest] = args;
2410
+ const special = await runSpecialCommand(input, args, json, group, command);
2411
+ if (special !== void 0) return special;
2412
+ const commandKey = group === "login" ? "login:" : `${group ?? ""}:${command ?? ""}`;
2413
+ const commandRest = group === "login" ? args.slice(1) : rest;
2414
+ const handlers = {
2415
+ "whoami:": () => executeSimple2(input.executor, "whoami", {}, json),
2416
+ "brain:list": () => executeSimple2(input.executor, "brain.list", {}, json),
2417
+ "brain:use": () => idTool({
2418
+ executor: input.executor,
2419
+ toolName: "brain.use",
2420
+ inputKey: "brainId",
2421
+ idLabel: "brain ID",
2422
+ rest,
2423
+ json
2424
+ }),
2425
+ "scope:current": () => scopeCurrent(input.config, json),
2426
+ "search:query": () => searchQuery(input.executor, rest, json),
2427
+ "context:assemble": () => contextAssemble(input.executor, rest, json),
2428
+ "context:profile": () => contextProfile(input.executor, rest, json),
2429
+ "tools:list": () => toolsList({
2430
+ config: input.config,
2431
+ executor: input.executor,
2432
+ metadata: input.toolMetadata,
2433
+ json
2434
+ }),
2435
+ "tools:schema": () => executeSimple2(input.executor, "tools.schema", {}, json),
2436
+ "tools:help": () => toolsHelp({
2437
+ config: input.config,
2438
+ executor: input.executor,
2439
+ metadata: input.toolMetadata,
2440
+ rest,
2441
+ json
2442
+ }),
2443
+ "capture:text": () => captureText(input.executor, rest, json),
2444
+ "capture:file": () => captureFile(input.executor, input.readFile ?? readFile, rest, json),
2445
+ "capture:batch": () => captureBatch(input.executor, input.readFile ?? readFile, rest, json),
2446
+ "source:list": () => sourceList(input.executor, json),
2447
+ "source:create": () => sourceCreate(input.executor, rest, json),
2448
+ "source:get": () => sourceRead(input.executor, "get", rest, json),
2449
+ "source:status": () => sourceRead(input.executor, "status", rest, json),
2450
+ "ingestion:status": () => ingestionStatus(input.executor, rest, json),
2451
+ "record:list": () => recordList(input.executor, json),
2452
+ "record:get": () => recordRead(input.executor, "record.get", rest, json),
2453
+ "record:create-markdown": () => createMarkdownRecord(input.executor, rest, json),
2454
+ "record:patch-section": () => patchRecordSection(input.executor, rest, json),
2455
+ "record:versions": () => recordRead(input.executor, "record.versions", rest, json),
2456
+ "evidence:list": () => idTool({ executor: input.executor, toolName: "evidence.list", inputKey: "recordId", idLabel: "record ID", rest, json }),
2457
+ "evidence:get": () => idTool({ executor: input.executor, toolName: "evidence.get", inputKey: "evidenceId", idLabel: "evidence ID", rest, json }),
2458
+ "graph:neighbors": () => idTool({ executor: input.executor, toolName: "graph.neighbors", inputKey: "recordId", idLabel: "record ID", rest, json }),
2459
+ "event:list": () => executeSimple2(input.executor, "event.list", {}, json),
2460
+ "audit:events": () => auditEvents(input.executor, rest, json),
2461
+ "decision:create": () => createDecision(input.executor, rest, json),
2462
+ "task:create": () => createTask(input.executor, rest, json),
2463
+ "mcp:serve": () => mcpServe(input.mcpServer, input.config, input.executor, json),
2464
+ "login:": () => authCommand(input.authCommands, "login", { rest: commandRest, json }),
2465
+ "auth:status": () => authCommand(input.authCommands, "status", { json }),
2466
+ "logout:": () => authCommand(input.authCommands, "logout", { json })
2467
+ };
2468
+ const handler = handlers[commandKey];
2469
+ if (handler === void 0) {
2470
+ return errorResultWithCode(
2471
+ "tool_unavailable",
2472
+ `Tool or command '${args.join(" ")}' is unavailable for this CLI transport or implementation slice.`,
2473
+ json
2474
+ );
2475
+ }
2476
+ try {
2477
+ if (isAuthCommand(commandKey)) {
2478
+ return await handler();
2479
+ }
2480
+ validateAuthenticatedScope(input.config, input.now ?? /* @__PURE__ */ new Date());
2481
+ validateCommandCapability({ commandKey, config: input.config });
2482
+ return await handler();
2483
+ } catch (error) {
2484
+ return errorResult(error, json);
2485
+ }
2486
+ }
2487
+ async function runSpecialCommand(input, args, json, group, command) {
2488
+ if (group === "doctor" && command === void 0) {
2489
+ return doctor({ config: input.config, executor: input.executor, json, now: input.now ?? /* @__PURE__ */ new Date() });
2490
+ }
2491
+ const simpleCommand = resolveSimpleCommand({
2492
+ args,
2493
+ json,
2494
+ config: input.config,
2495
+ executor: input.executor,
2496
+ readFile: input.readFile ?? readFile,
2497
+ readStdin: input.readStdin,
2498
+ now: input.now ?? /* @__PURE__ */ new Date()
2499
+ });
2500
+ if (simpleCommand === void 0) return void 0;
2501
+ try {
2502
+ validateAuthenticatedScope(input.config, input.now ?? /* @__PURE__ */ new Date());
2503
+ validateCommandCapability({ commandKey: simpleCommand.commandKey, config: input.config });
2504
+ return await simpleCommand.run();
2505
+ } catch (error) {
2506
+ return errorResult(error, json);
2507
+ }
2508
+ }
2509
+ async function mcpServe(mcpServer, config2, executor, json) {
2510
+ if (mcpServer === void 0) {
2511
+ return fail("No local MCP server is configured for mcp.serve.");
2512
+ }
2513
+ if (executor === void 0) {
2514
+ return fail("No Sift API executor is configured for mcp.serve.");
2515
+ }
2516
+ const result2 = await mcpServer.serve({ config: config2, executor, transport: "local_mcp" });
2517
+ if (result2 === void 0) return ok("");
2518
+ return ok(json ? `${JSON.stringify(result2)}
2519
+ ` : `${JSON.stringify(result2)}
2520
+ `);
2521
+ }
2522
+ function scopeCurrent(config2, json) {
2523
+ const scope = {
2524
+ apiBaseUrl: config2.apiBaseUrl,
2525
+ tokenLabel: config2.tokenLabel,
2526
+ tokenExpiresAt: config2.tokenExpiresAt,
2527
+ principalId: config2.principalId,
2528
+ workspaceId: config2.workspaceId,
2529
+ brainId: config2.brainId,
2530
+ capabilities: config2.capabilities
2531
+ };
2532
+ return ok(json ? `${JSON.stringify(scope)}
2533
+ ` : renderScope(scope));
2534
+ }
2535
+ async function searchQuery(executor, rest, json) {
2536
+ if (executor === void 0) {
2537
+ return fail("No Sift API executor is configured for search.query.");
2538
+ }
2539
+ const query = rest.join(" ").trim();
2540
+ const result2 = await executor.execute("search.query", { query, limit: 10 });
2541
+ return ok(json ? `${JSON.stringify(result2)}
2542
+ ` : renderSearchResult(result2));
2543
+ }
2544
+ async function contextAssemble(executor, rest, json) {
2545
+ if (executor === void 0) {
2546
+ return fail("No Sift API executor is configured for context.assemble.");
2547
+ }
2548
+ const parsed = parseOptions(rest);
2549
+ const query = positionalArgs(rest).join(" ").trim();
2550
+ const result2 = await executor.execute("context.assemble", {
2551
+ query,
2552
+ maxChars: parseIntegerOption(parsed, "max-chars", 4e3)
2553
+ });
2554
+ return ok(json ? `${JSON.stringify(result2)}
2555
+ ` : renderSearchResult(result2));
2556
+ }
2557
+ async function contextProfile(executor, rest, json) {
2558
+ if (executor === void 0) {
2559
+ return fail("No Sift API executor is configured for context.profile.");
2560
+ }
2561
+ const parsed = parseOptions(rest);
2562
+ const input = {
2563
+ limit: parseIntegerOption(parsed, "limit", 6)
2564
+ };
2565
+ const query = positionalArgs(rest).join(" ").trim();
2566
+ if (query.length > 0) {
2567
+ input.query = query;
2568
+ }
2569
+ const result2 = await executor.execute("context.profile", input);
2570
+ return ok(json ? `${JSON.stringify(result2)}
2571
+ ` : renderProfileResult(result2));
2572
+ }
2573
+ async function executeSimple2(executor, name, toolInput, json) {
2574
+ if (executor === void 0) {
2575
+ return fail(`No Sift API executor is configured for ${name}.`);
2576
+ }
2577
+ const result2 = await executor.execute(name, toolInput);
2578
+ return ok(json ? `${JSON.stringify(result2)}
2579
+ ` : `${JSON.stringify(result2)}
2580
+ `);
2581
+ }
2582
+ async function captureText(executor, rest, json) {
2583
+ if (executor === void 0) {
2584
+ return fail("No Sift API executor is configured for capture.text.");
2585
+ }
2586
+ const parsed = parseOptions(rest);
2587
+ const result2 = await executor.execute("capture.text", {
2588
+ sourceName: requireOption(parsed, "source"),
2589
+ externalId: requireOption(parsed, "external-id"),
2590
+ title: requireOption(parsed, "title"),
2591
+ visibility: [requireOption(parsed, "visibility")],
2592
+ markdown: requireOption(parsed, "markdown")
2593
+ });
2594
+ return ok(json ? `${JSON.stringify(result2)}
2595
+ ` : `${JSON.stringify(result2)}
2596
+ `);
2597
+ }
2598
+ async function captureFile(executor, fileReader, rest, json) {
2599
+ if (executor === void 0) {
2600
+ return fail("No Sift API executor is configured for capture.file.");
2601
+ }
2602
+ const [path, ...optionArgs] = rest;
2603
+ if (path === void 0 || path.trim().length === 0) {
2604
+ return fail("Missing required file path for capture.file.");
2605
+ }
2606
+ const parsed = parseOptions(optionArgs);
2607
+ const bytes = await fileReader(path);
2608
+ const result2 = await executor.execute("capture.file", {
2609
+ sourceName: requireOption(parsed, "source"),
2610
+ externalId: requireOption(parsed, "external-id"),
2611
+ title: requireOption(parsed, "title"),
2612
+ filename: basename(path),
2613
+ contentType: optionalOption(parsed, "content-type") ?? inferContentType(path),
2614
+ bytes,
2615
+ visibility: [requireOption(parsed, "visibility")]
2616
+ });
2617
+ return ok(json ? `${JSON.stringify(result2)}
2618
+ ` : `${JSON.stringify(result2)}
2619
+ `);
2620
+ }
2621
+ async function captureBatch(executor, fileReader, rest, json) {
2622
+ if (executor === void 0) {
2623
+ return fail("No Sift API executor is configured for capture.batch.");
2624
+ }
2625
+ const [manifestPath] = rest;
2626
+ if (manifestPath === void 0 || manifestPath.trim().length === 0) {
2627
+ return fail("Missing required manifest path for capture.batch.");
2628
+ }
2629
+ const manifest = parseBatchManifest(await fileReader(manifestPath));
2630
+ const result2 = await executor.execute("capture.batch", { items: manifest });
2631
+ return ok(json ? `${JSON.stringify(result2)}
2632
+ ` : `${JSON.stringify(result2)}
2633
+ `);
2634
+ }
2635
+ function parseBatchManifest(bytes) {
2636
+ const parsed = JSON.parse(new TextDecoder().decode(bytes));
2637
+ if (!Array.isArray(parsed)) {
2638
+ throw new Error("Batch manifest must be a JSON array.");
2639
+ }
2640
+ return parsed;
2641
+ }
2642
+ async function createDecision(executor, rest, json) {
2643
+ if (executor === void 0) {
2644
+ return fail("No Sift API executor is configured for decision.create.");
2645
+ }
2646
+ const parsed = parseOptions(rest);
2647
+ const input = {
2648
+ statement: requireOption(parsed, "statement"),
2649
+ state: requireOption(parsed, "state"),
2650
+ visibility: [requireOption(parsed, "visibility")]
2651
+ };
2652
+ const rationale = optionalOption(parsed, "rationale");
2653
+ if (rationale !== void 0) {
2654
+ input.rationale = rationale;
2655
+ }
2656
+ addOptionalWorkMetadata(input, parsed);
2657
+ const result2 = await executor.execute("decision.create", input);
2658
+ return ok(json ? `${JSON.stringify(result2)}
2659
+ ` : `${JSON.stringify(result2)}
2660
+ `);
2661
+ }
2662
+ async function sourceList(executor, json) {
2663
+ if (executor === void 0) {
2664
+ return fail("No Sift API executor is configured for source.list.");
2665
+ }
2666
+ const result2 = await executor.execute("source.list", {});
2667
+ return ok(json ? `${JSON.stringify(result2)}
2668
+ ` : `${JSON.stringify(result2)}
2669
+ `);
2670
+ }
2671
+ async function sourceCreate(executor, rest, json) {
2672
+ if (executor === void 0) {
2673
+ return fail("No Sift API executor is configured for source.create.");
2674
+ }
2675
+ const parsed = parseOptions(rest);
2676
+ const result2 = await executor.execute("source.create", {
2677
+ name: requireOption(parsed, "name"),
2678
+ visibility: [requireOption(parsed, "visibility")]
2679
+ });
2680
+ return ok(json ? `${JSON.stringify(result2)}
2681
+ ` : `${JSON.stringify(result2)}
2682
+ `);
2683
+ }
2684
+ async function sourceRead(executor, command, rest, json) {
2685
+ const toolName = command === "get" ? "source.get" : "source.status";
2686
+ if (executor === void 0) {
2687
+ return fail(`No Sift API executor is configured for ${toolName}.`);
2688
+ }
2689
+ const [sourceId] = rest;
2690
+ if (sourceId === void 0 || sourceId.trim().length === 0) {
2691
+ return fail(`Missing required source ID for ${toolName}.`);
2692
+ }
2693
+ const result2 = await executor.execute(toolName, { sourceId });
2694
+ return ok(json ? `${JSON.stringify(result2)}
2695
+ ` : `${JSON.stringify(result2)}
2696
+ `);
2697
+ }
2698
+ async function ingestionStatus(executor, rest, json) {
2699
+ if (executor === void 0) {
2700
+ return fail("No Sift API executor is configured for ingestion.status.");
2701
+ }
2702
+ const [jobId] = rest;
2703
+ if (jobId === void 0 || jobId.trim().length === 0) {
2704
+ return fail("Missing required job ID for ingestion.status.");
2705
+ }
2706
+ const result2 = await executor.execute("ingestion.status", { jobId });
2707
+ return ok(json ? `${JSON.stringify(result2)}
2708
+ ` : `${JSON.stringify(result2)}
2709
+ `);
2710
+ }
2711
+ async function recordList(executor, json) {
2712
+ if (executor === void 0) {
2713
+ return fail("No Sift API executor is configured for record.list.");
2714
+ }
2715
+ const result2 = await executor.execute("record.list", {});
2716
+ return ok(json ? `${JSON.stringify(result2)}
2717
+ ` : `${JSON.stringify(result2)}
2718
+ `);
2719
+ }
2720
+ async function recordRead(executor, toolName, rest, json) {
2721
+ if (executor === void 0) {
2722
+ return fail(`No Sift API executor is configured for ${toolName}.`);
2723
+ }
2724
+ const [recordId] = rest;
2725
+ if (recordId === void 0 || recordId.trim().length === 0) {
2726
+ return fail(`Missing required record ID for ${toolName}.`);
2727
+ }
2728
+ const input = { recordId };
2729
+ if (toolName === "record.get") {
2730
+ const sectionAnchor = optionalOption(parseOptions(rest.slice(1)), "section");
2731
+ if (sectionAnchor !== void 0) {
2732
+ input.sectionAnchor = sectionAnchor;
2733
+ }
2734
+ }
2735
+ const result2 = await executor.execute(toolName, input);
2736
+ return ok(json ? `${JSON.stringify(result2)}
2737
+ ` : renderRecordResult(result2));
2738
+ }
2739
+ async function createMarkdownRecord(executor, rest, json) {
2740
+ if (executor === void 0) {
2741
+ return fail("No Sift API executor is configured for record.create_markdown.");
2742
+ }
2743
+ const parsed = parseOptions(rest);
2744
+ const result2 = await executor.execute("record.create_markdown", {
2745
+ recordType: requireOption(parsed, "type"),
2746
+ title: requireOption(parsed, "title"),
2747
+ markdown: requireOption(parsed, "markdown"),
2748
+ visibility: [requireOption(parsed, "visibility")]
2749
+ });
2750
+ return ok(json ? `${JSON.stringify(result2)}
2751
+ ` : `${JSON.stringify(result2)}
2752
+ `);
2753
+ }
2754
+ async function patchRecordSection(executor, rest, json) {
2755
+ if (executor === void 0) {
2756
+ return fail("No Sift API executor is configured for record.patch_section.");
2757
+ }
2758
+ const [recordId, anchor, ...optionArgs] = rest;
2759
+ if (recordId === void 0 || recordId.trim().length === 0) {
2760
+ return fail("Missing required record ID for record.patch_section.");
2761
+ }
2762
+ if (anchor === void 0 || anchor.trim().length === 0) {
2763
+ return fail("Missing required anchor for record.patch_section.");
2764
+ }
2765
+ const parsed = parseOptions(optionArgs);
2766
+ const input = {
2767
+ recordId,
2768
+ anchor,
2769
+ replacementMarkdown: requireOption(parsed, "replacement-markdown")
2770
+ };
2771
+ const expectedMarkdown = optionalOption(parsed, "expected-markdown");
2772
+ if (expectedMarkdown !== void 0) {
2773
+ input.expectedMarkdown = expectedMarkdown;
2774
+ }
2775
+ const result2 = await executor.execute("record.patch_section", input);
2776
+ return ok(json ? `${JSON.stringify(result2)}
2777
+ ` : `${JSON.stringify(result2)}
2778
+ `);
2779
+ }
2780
+ async function createTask(executor, rest, json) {
2781
+ if (executor === void 0) {
2782
+ return fail("No Sift API executor is configured for task.create.");
2783
+ }
2784
+ const parsed = parseOptions(rest);
2785
+ const input = {
2786
+ title: requireOption(parsed, "title"),
2787
+ visibility: [requireOption(parsed, "visibility")]
2788
+ };
2789
+ const status2 = optionalOption(parsed, "status");
2790
+ if (status2 !== void 0) {
2791
+ input.status = status2;
2792
+ }
2793
+ const owner = optionalOption(parsed, "owner");
2794
+ if (owner !== void 0) {
2795
+ input.owner = owner;
2796
+ }
2797
+ const dueDate = optionalOption(parsed, "due-date");
2798
+ if (dueDate !== void 0) {
2799
+ input.dueDate = dueDate;
2800
+ }
2801
+ const rationale = optionalOption(parsed, "rationale");
2802
+ if (rationale !== void 0) {
2803
+ input.rationale = rationale;
2804
+ }
2805
+ addOptionalWorkMetadata(input, parsed);
2806
+ const result2 = await executor.execute("task.create", input);
2807
+ return ok(json ? `${JSON.stringify(result2)}
2808
+ ` : `${JSON.stringify(result2)}
2809
+ `);
2810
+ }
2811
+ async function auditEvents(executor, rest, json) {
2812
+ if (executor === void 0) {
2813
+ return fail("No Sift API executor is configured for audit.events.");
2814
+ }
2815
+ const [targetId] = rest;
2816
+ const input = {};
2817
+ if (targetId !== void 0 && targetId.trim().length > 0) {
2818
+ input.targetId = targetId;
2819
+ }
2820
+ const result2 = await executor.execute("audit.events", input);
2821
+ return ok(json ? `${JSON.stringify(result2)}
2822
+ ` : `${JSON.stringify(result2)}
2823
+ `);
2824
+ }
2825
+ async function idTool(input) {
2826
+ if (input.executor === void 0) {
2827
+ return fail(`No Sift API executor is configured for ${input.toolName}.`);
2828
+ }
2829
+ const [id] = input.rest;
2830
+ if (id === void 0 || id.trim().length === 0) {
2831
+ return fail(`Missing required ${input.idLabel} for ${input.toolName}.`);
2832
+ }
2833
+ const result2 = await input.executor.execute(input.toolName, { [input.inputKey]: id });
2834
+ return ok(input.json ? `${JSON.stringify(result2)}
2835
+ ` : `${JSON.stringify(result2)}
2836
+ `);
2837
+ }
2838
+
2839
+ // src/auth/configStore.ts
2840
+ import { mkdir, readFile as readFile2, rm, writeFile, chmod } from "fs/promises";
2841
+ import { dirname, join } from "path";
2842
+ function resolveSiftConfigPath(input) {
2843
+ return join(input.homeDir, ".sift", "config.json");
2844
+ }
2845
+ async function readStoredSiftConfig(input) {
2846
+ let raw;
2847
+ try {
2848
+ raw = await readFile2(resolveSiftConfigPath(input), "utf8");
2849
+ } catch (error) {
2850
+ if (isNodeError(error) && error.code === "ENOENT") {
2851
+ return void 0;
2852
+ }
2853
+ throw error;
2854
+ }
2855
+ return parseStoredSiftConfig(JSON.parse(raw));
2856
+ }
2857
+ async function writeStoredSiftConfig(input) {
2858
+ const config2 = parseStoredSiftConfig(input.config);
2859
+ const path = resolveSiftConfigPath(input);
2860
+ await mkdir(dirname(path), { recursive: true, mode: 448 });
2861
+ await writeFile(path, `${JSON.stringify(config2, null, 2)}
2862
+ `, { mode: 384 });
2863
+ await chmod(path, 384);
2864
+ }
2865
+ async function clearStoredSiftConfig(input) {
2866
+ await rm(resolveSiftConfigPath(input), { force: true });
2867
+ }
2868
+ async function loadCliAuthConfig(input) {
2869
+ const envToken = clean(input.env.SIFT_API_TOKEN);
2870
+ if (envToken !== void 0) {
2871
+ return loadEnvAuth(input.env, envToken);
2872
+ }
2873
+ const stored = await readStoredSiftConfig({ homeDir: input.homeDir });
2874
+ if (stored === void 0) {
2875
+ return void 0;
2876
+ }
2877
+ const profile = stored.profiles[stored.currentProfile];
2878
+ if (profile === void 0) {
2879
+ throw new Error(`Stored Sift profile '${stored.currentProfile}' was not found.`);
2880
+ }
2881
+ if (Date.parse(profile.tokenExpiresAt) <= input.now.getTime()) {
2882
+ throw new Error("Stored Sift CLI auth has expired; run `sift login` again.");
2883
+ }
2884
+ const token = await input.credentialStore.read({
2885
+ apiBaseUrl: profile.apiBaseUrl,
2886
+ tokenId: profile.tokenId
2887
+ });
2888
+ if (token === void 0) {
2889
+ throw new Error("Stored Sift credential store secret is missing; run `sift login` again.");
2890
+ }
2891
+ return {
2892
+ source: "stored",
2893
+ token,
2894
+ config: {
2895
+ apiBaseUrl: profile.apiBaseUrl,
2896
+ tokenLabel: profile.tokenLabel,
2897
+ tokenExpiresAt: profile.tokenExpiresAt,
2898
+ workspaceId: profile.workspaceId,
2899
+ brainId: profile.brainId,
2900
+ principalId: profile.principalId,
2901
+ capabilities: [...profile.capabilities]
2902
+ }
2903
+ };
2904
+ }
2905
+ function loadEnvAuth(env, token) {
2906
+ return {
2907
+ source: "env",
2908
+ token,
2909
+ config: {
2910
+ apiBaseUrl: requiredEnv(env, "SIFT_API_BASE_URL").replace(/\/+$/u, ""),
2911
+ tokenLabel: clean(env.SIFT_TOKEN_LABEL) ?? "env-token",
2912
+ tokenExpiresAt: clean(env.SIFT_TOKEN_EXPIRES_AT),
2913
+ workspaceId: requiredEnv(env, "SIFT_WORKSPACE_ID"),
2914
+ brainId: requiredEnv(env, "SIFT_BRAIN_ID"),
2915
+ principalId: requiredEnv(env, "SIFT_PRINCIPAL_ID"),
2916
+ capabilities: (clean(env.SIFT_TOKEN_CAPABILITIES) ?? "").split(",").map((item) => item.trim()).filter((item) => item.length > 0)
2917
+ }
2918
+ };
2919
+ }
2920
+ function parseStoredSiftConfig(value) {
2921
+ const record = objectValue(value, "config");
2922
+ const currentProfile = stringValue(record.currentProfile, "currentProfile");
2923
+ const profilesRecord = objectValue(record.profiles, "profiles");
2924
+ const profiles = {};
2925
+ for (const [name, profileValue] of Object.entries(profilesRecord)) {
2926
+ profiles[name] = parseStoredSiftProfile(profileValue);
2927
+ }
2928
+ if (profiles[currentProfile] === void 0) {
2929
+ throw new Error("currentProfile must reference an existing stored profile.");
2930
+ }
2931
+ return { currentProfile, profiles };
2932
+ }
2933
+ function parseStoredSiftProfile(value) {
2934
+ const record = objectValue(value, "profile");
2935
+ if ("token" in record || "secret" in record || "tokenSecret" in record) {
2936
+ throw new Error("Stored Sift config must not contain token secrets.");
2937
+ }
2938
+ return {
2939
+ apiBaseUrl: stringValue(record.apiBaseUrl, "apiBaseUrl").replace(/\/+$/u, ""),
2940
+ appBaseUrl: stringValue(record.appBaseUrl, "appBaseUrl").replace(/\/+$/u, ""),
2941
+ workspaceId: stringValue(record.workspaceId, "workspaceId"),
2942
+ brainId: stringValue(record.brainId, "brainId"),
2943
+ principalId: stringValue(record.principalId, "principalId"),
2944
+ tokenId: stringValue(record.tokenId, "tokenId"),
2945
+ tokenLabel: stringValue(record.tokenLabel, "tokenLabel"),
2946
+ tokenExpiresAt: stringValue(record.tokenExpiresAt, "tokenExpiresAt"),
2947
+ capabilities: stringArray(record.capabilities, "capabilities")
2948
+ };
2949
+ }
2950
+ function requiredEnv(env, name) {
2951
+ const value = clean(env[name]);
2952
+ if (value === void 0) {
2953
+ throw new Error(`Missing authenticated CLI scope: ${name}.`);
2954
+ }
2955
+ return value;
2956
+ }
2957
+ function objectValue(value, name) {
2958
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
2959
+ throw new Error(`${name} must be an object.`);
2960
+ }
2961
+ return value;
2962
+ }
2963
+ function stringValue(value, name) {
2964
+ if (typeof value !== "string" || value.trim().length === 0) {
2965
+ throw new Error(`${name} is required.`);
2966
+ }
2967
+ return value;
2968
+ }
2969
+ function stringArray(value, name) {
2970
+ if (!Array.isArray(value) || !value.every((item) => typeof item === "string")) {
2971
+ throw new Error(`${name} must be a string array.`);
2972
+ }
2973
+ return [...value];
2974
+ }
2975
+ function clean(value) {
2976
+ const trimmed = value?.trim();
2977
+ return trimmed === void 0 || trimmed.length === 0 ? void 0 : trimmed;
2978
+ }
2979
+ function isNodeError(error) {
2980
+ return error instanceof Error && "code" in error;
2981
+ }
2982
+
2983
+ // src/auth/keychainStore.ts
2984
+ import { execFile } from "child_process";
2985
+ import { promisify } from "util";
2986
+ var securityPath = "/usr/bin/security";
2987
+ var serviceName = "sift-cli";
2988
+ var execFileAsync = promisify(execFile);
2989
+ var UnsupportedCredentialStoreError = class extends Error {
2990
+ constructor() {
2991
+ super(
2992
+ "Sift CLI interactive login requires macOS Keychain in this slice. Use SIFT_API_TOKEN for env-token auth on unsupported platforms."
2993
+ );
2994
+ this.name = "UnsupportedCredentialStoreError";
2995
+ }
2996
+ };
2997
+ function createMacOSKeychainStore(input = {}) {
2998
+ const platform = input.platform ?? process.platform;
2999
+ const runCommand = input.runCommand ?? runSecurityCommand;
3000
+ async function requireSupported() {
3001
+ if (platform !== "darwin") {
3002
+ throw new UnsupportedCredentialStoreError();
3003
+ }
3004
+ await Promise.resolve();
3005
+ }
3006
+ return {
3007
+ async assertAvailable() {
3008
+ await requireSupported();
3009
+ const result2 = await runCommand(securityPath, ["list-keychains"]);
3010
+ if (result2.exitCode !== 0) {
3011
+ throw new UnsupportedCredentialStoreError();
3012
+ }
3013
+ },
3014
+ async read(readInput) {
3015
+ await requireSupported();
3016
+ const result2 = await runCommand(securityPath, [
3017
+ "find-generic-password",
3018
+ "-s",
3019
+ serviceName,
3020
+ "-a",
3021
+ account(readInput),
3022
+ "-w"
3023
+ ]);
3024
+ if (result2.exitCode !== 0) {
3025
+ return void 0;
3026
+ }
3027
+ const secret = result2.stdout.trim();
3028
+ return secret.length === 0 ? void 0 : secret;
3029
+ },
3030
+ async write(writeInput) {
3031
+ await requireSupported();
3032
+ const result2 = await runCommand(securityPath, [
3033
+ "add-generic-password",
3034
+ "-U",
3035
+ "-s",
3036
+ serviceName,
3037
+ "-a",
3038
+ account(writeInput),
3039
+ "-w",
3040
+ writeInput.secret
3041
+ ]);
3042
+ if (result2.exitCode !== 0) {
3043
+ throw new Error("Failed to write Sift CLI token secret to macOS Keychain.");
3044
+ }
3045
+ },
3046
+ async delete(deleteInput) {
3047
+ await requireSupported();
3048
+ await runCommand(securityPath, [
3049
+ "delete-generic-password",
3050
+ "-s",
3051
+ serviceName,
3052
+ "-a",
3053
+ account(deleteInput)
3054
+ ]);
3055
+ }
3056
+ };
3057
+ }
3058
+ async function runSecurityCommand(file, args) {
3059
+ try {
3060
+ const result2 = await execFileAsync(file, args);
3061
+ return { stdout: result2.stdout, stderr: result2.stderr, exitCode: 0 };
3062
+ } catch (error) {
3063
+ if (isExecError(error)) {
3064
+ return {
3065
+ stdout: typeof error.stdout === "string" ? error.stdout : "",
3066
+ stderr: typeof error.stderr === "string" ? error.stderr : "",
3067
+ exitCode: typeof error.code === "number" ? error.code : 1
3068
+ };
3069
+ }
3070
+ throw error;
3071
+ }
3072
+ }
3073
+ function account(input) {
3074
+ return `${input.apiBaseUrl}|${input.tokenId}`;
3075
+ }
3076
+ function isExecError(error) {
3077
+ return error instanceof Error;
3078
+ }
3079
+
3080
+ // src/auth/loginFlow.ts
3081
+ import { execFile as execFile2 } from "child_process";
3082
+ import { hostname } from "os";
3083
+ import { promisify as promisify2 } from "util";
3084
+
3085
+ // src/auth/localCallback.ts
3086
+ import { createServer } from "http";
3087
+ async function createLocalCallbackServer() {
3088
+ let resolveCallback;
3089
+ let rejectCallback;
3090
+ const callbackPromise = new Promise((resolve, reject) => {
3091
+ resolveCallback = resolve;
3092
+ rejectCallback = reject;
3093
+ });
3094
+ const server = createServer((request, response) => {
3095
+ try {
3096
+ const url = new URL(request.url ?? "/", "http://127.0.0.1");
3097
+ const code = url.searchParams.get("code");
3098
+ const state = url.searchParams.get("state");
3099
+ if (code === null || state === null) {
3100
+ response.writeHead(400, { "Content-Type": "text/plain" });
3101
+ response.end("Missing Sift CLI authorization callback fields.");
3102
+ rejectCallback?.(new Error("Missing CLI authorization callback fields."));
3103
+ return;
3104
+ }
3105
+ response.writeHead(200, { "Content-Type": "text/plain" });
3106
+ response.end("Sift CLI authorization complete. You can return to the terminal.");
3107
+ resolveCallback?.({ code, state });
3108
+ } catch (error) {
3109
+ rejectCallback?.(error instanceof Error ? error : new Error("Invalid callback."));
3110
+ }
3111
+ });
3112
+ await listen(server);
3113
+ const address = server.address();
3114
+ if (address === null || typeof address === "string") {
3115
+ throw new Error("Failed to bind Sift CLI callback server.");
3116
+ }
3117
+ return {
3118
+ redirectUri: `http://127.0.0.1:${address.port}/callback`,
3119
+ waitForCallback: () => callbackPromise,
3120
+ close: () => closeServer(server)
3121
+ };
3122
+ }
3123
+ function listen(server) {
3124
+ return new Promise((resolve, reject) => {
3125
+ server.once("error", reject);
3126
+ server.listen(0, "127.0.0.1", () => {
3127
+ server.off("error", reject);
3128
+ resolve();
3129
+ });
3130
+ });
3131
+ }
3132
+ function closeServer(server) {
3133
+ return new Promise((resolve, reject) => {
3134
+ server.close((error) => {
3135
+ if (error) {
3136
+ reject(error);
3137
+ } else {
3138
+ resolve();
3139
+ }
3140
+ });
3141
+ });
3142
+ }
3143
+
3144
+ // src/auth/pkce.ts
3145
+ import { createHash as createHash2, randomUUID } from "crypto";
3146
+ function createPkceState(input = {}) {
3147
+ const nextSecret = input.nextSecret ?? (() => randomUUID().replaceAll("-", ""));
3148
+ const state = nextSecret();
3149
+ const codeVerifier = nextSecret();
3150
+ return {
3151
+ state,
3152
+ stateHash: sha256Hex2(state),
3153
+ codeVerifier,
3154
+ codeChallenge: sha256Base64Url(codeVerifier)
3155
+ };
3156
+ }
3157
+ function sha256Hex2(value) {
3158
+ return createHash2("sha256").update(value).digest("hex");
3159
+ }
3160
+ function sha256Base64Url(value) {
3161
+ return createHash2("sha256").update(value).digest("base64url");
3162
+ }
3163
+
3164
+ // src/auth/loginFlow.ts
3165
+ var execFileAsync2 = promisify2(execFile2);
3166
+ function createSiftCliAuthCommands(input) {
3167
+ const now = input.now ?? (() => /* @__PURE__ */ new Date());
3168
+ const sleep = input.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
3169
+ return {
3170
+ async login({ rest, json }) {
3171
+ try {
3172
+ return rest.includes("--no-browser") ? await deviceLogin(input, rest, sleep, json) : await browserLogin(input, rest, json);
3173
+ } catch (error) {
3174
+ return json ? failJson(error instanceof Error ? error.message : "Login failed.") : fail(error instanceof Error ? error.message : "Login failed.");
3175
+ }
3176
+ },
3177
+ async status({ json }) {
3178
+ return authStatus(input, now(), json);
3179
+ },
3180
+ async logout({ json }) {
3181
+ return logout(input, now(), json);
3182
+ },
3183
+ async loadAuth() {
3184
+ return loadCliAuthConfig({
3185
+ env: input.env,
3186
+ homeDir: input.homeDir,
3187
+ credentialStore: input.credentialStore,
3188
+ now: now()
3189
+ });
3190
+ }
3191
+ };
3192
+ }
3193
+ async function resolveLoginApiBaseUrl(input) {
3194
+ const options = parseOptions(input.argv);
3195
+ const fromFlag = clean2(options.get("api-base-url"));
3196
+ if (fromFlag !== void 0) return normalizeUrl(fromFlag);
3197
+ const fromEnv = clean2(input.env.SIFT_API_BASE_URL);
3198
+ if (fromEnv !== void 0) return normalizeUrl(fromEnv);
3199
+ const stored = await readStoredSiftConfig({ homeDir: input.homeDir });
3200
+ const profile = stored?.profiles[stored.currentProfile];
3201
+ if (profile !== void 0) return normalizeUrl(profile.apiBaseUrl);
3202
+ return "https://api.sift.com";
3203
+ }
3204
+ async function browserLogin(input, rest, json) {
3205
+ await input.credentialStore.assertAvailable();
3206
+ const apiBaseUrl = await resolveLoginApiBaseUrl({ argv: rest, env: input.env, homeDir: input.homeDir });
3207
+ const callbackServer = await (input.createCallbackServer ?? createLocalCallbackServer)();
3208
+ try {
3209
+ const pkce = createPkceState({ nextSecret: input.nextSecret });
3210
+ const request = await postJson(input.fetch, `${apiBaseUrl}/cli-auth/requests`, {
3211
+ mode: "browser",
3212
+ redirectUri: callbackServer.redirectUri,
3213
+ codeChallenge: pkce.codeChallenge,
3214
+ codeChallengeMethod: "S256",
3215
+ stateHash: pkce.stateHash,
3216
+ deviceLabel: input.deviceLabel ?? hostname(),
3217
+ requestedCapabilities: requestedCapabilities(rest)
3218
+ });
3219
+ await tryOpenBrowser(input.openBrowser, request.authorizeUrl);
3220
+ const callback = await callbackServer.waitForCallback();
3221
+ if (callback.state !== pkce.stateHash) {
3222
+ throw new Error("CLI auth callback state mismatch.");
3223
+ }
3224
+ const token = await postJson(input.fetch, `${apiBaseUrl}/cli-auth/token`, {
3225
+ requestId: request.requestId,
3226
+ code: callback.code,
3227
+ codeVerifier: pkce.codeVerifier,
3228
+ state: pkce.state
3229
+ });
3230
+ return persistLogin(input, token, json);
3231
+ } finally {
3232
+ await callbackServer.close();
3233
+ }
3234
+ }
3235
+ async function deviceLogin(input, rest, sleep, json) {
3236
+ await input.credentialStore.assertAvailable();
3237
+ const apiBaseUrl = await resolveLoginApiBaseUrl({ argv: rest, env: input.env, homeDir: input.homeDir });
3238
+ const request = await postJson(input.fetch, `${apiBaseUrl}/cli-auth/device`, {
3239
+ deviceLabel: input.deviceLabel ?? hostname(),
3240
+ requestedCapabilities: requestedCapabilities(rest)
3241
+ });
3242
+ let intervalSeconds = request.intervalSeconds;
3243
+ for (; ; ) {
3244
+ await sleep(intervalSeconds * 1e3);
3245
+ const token = await postJson(
3246
+ input.fetch,
3247
+ `${apiBaseUrl}/cli-auth/device/token`,
3248
+ { requestId: request.requestId, userCode: request.userCode }
3249
+ );
3250
+ if ("token" in token) {
3251
+ const result2 = await persistLogin(input, token, json);
3252
+ return result2.exitCode === 0 ? { ...result2, stdout: `Code: ${request.userCode}
3253
+ ${result2.stdout}` } : result2;
3254
+ }
3255
+ if (token.status === "authorization_pending" || token.status === "slow_down") {
3256
+ intervalSeconds = token.intervalSeconds;
3257
+ continue;
3258
+ }
3259
+ throw new Error(`Device authorization failed: ${token.status}.`);
3260
+ }
3261
+ }
3262
+ async function persistLogin(input, token, json) {
3263
+ const oldConfig = await readStoredSiftConfig({ homeDir: input.homeDir });
3264
+ const oldProfile = oldConfig?.profiles[oldConfig.currentProfile];
3265
+ try {
3266
+ await input.credentialStore.write({
3267
+ apiBaseUrl: token.apiBaseUrl,
3268
+ tokenId: token.tokenId,
3269
+ secret: token.token
3270
+ });
3271
+ } catch (error) {
3272
+ await revokeToken(input.fetch, token.apiBaseUrl, token.token).catch(() => void 0);
3273
+ return fail(
3274
+ `Sift CLI login storage failure: ${error instanceof Error ? error.message : "credential store write failed"}`
3275
+ );
3276
+ }
3277
+ const config2 = configFromToken(token);
3278
+ await writeStoredSiftConfig({ homeDir: input.homeDir, config: config2 });
3279
+ if (oldProfile !== void 0) {
3280
+ const oldSecret = await input.credentialStore.read({
3281
+ apiBaseUrl: oldProfile.apiBaseUrl,
3282
+ tokenId: oldProfile.tokenId
3283
+ });
3284
+ if (oldSecret !== void 0) {
3285
+ await revokeToken(input.fetch, oldProfile.apiBaseUrl, oldSecret).catch(() => void 0);
3286
+ }
3287
+ }
3288
+ const scope = {
3289
+ apiBaseUrl: token.apiBaseUrl,
3290
+ tokenLabel: token.tokenLabel,
3291
+ tokenExpiresAt: token.tokenExpiresAt,
3292
+ principalId: token.principalId,
3293
+ workspaceId: token.workspaceId,
3294
+ brainId: token.brainId,
3295
+ capabilities: token.capabilities
3296
+ };
3297
+ return ok(json ? `${JSON.stringify(scope)}
3298
+ ` : `Authenticated Sift CLI
3299
+ ${renderScope(scope)}`);
3300
+ }
3301
+ async function authStatus(input, now, json) {
3302
+ const envToken = clean2(input.env.SIFT_API_TOKEN);
3303
+ if (envToken !== void 0) {
3304
+ const loaded = await loadCliAuthConfig({
3305
+ env: input.env,
3306
+ homeDir: input.homeDir,
3307
+ credentialStore: input.credentialStore,
3308
+ now
3309
+ });
3310
+ return okStatus("env", loaded, json);
3311
+ }
3312
+ const stored = await readStoredSiftConfig({ homeDir: input.homeDir });
3313
+ const profile = stored?.profiles[stored.currentProfile];
3314
+ if (profile === void 0) {
3315
+ return ok(json ? '{"auth":"none"}\n' : "Auth: none\n");
3316
+ }
3317
+ return ok(
3318
+ json ? `${JSON.stringify({ auth: "stored", ...profile })}
3319
+ ` : [
3320
+ "Auth: stored",
3321
+ `API: ${profile.apiBaseUrl}`,
3322
+ `Token: ${profile.tokenLabel}`,
3323
+ `Principal: ${profile.principalId}`,
3324
+ `Workspace: ${profile.workspaceId}`,
3325
+ `Brain: ${profile.brainId}`,
3326
+ `Capabilities: ${profile.capabilities.join(", ")}`,
3327
+ ""
3328
+ ].join("\n")
3329
+ );
3330
+ }
3331
+ async function logout(input, now, json) {
3332
+ if (clean2(input.env.SIFT_API_TOKEN) !== void 0) {
3333
+ return ok(json ? '{"status":"env_auth_active"}\n' : "Auth: env\nUnset SIFT_API_TOKEN to log out.\n");
3334
+ }
3335
+ const stored = await readStoredSiftConfig({ homeDir: input.homeDir });
3336
+ const profile = stored?.profiles[stored.currentProfile];
3337
+ if (profile === void 0) {
3338
+ return ok(json ? '{"status":"not_logged_in"}\n' : "Not logged in.\n");
3339
+ }
3340
+ const secret = await input.credentialStore.read({
3341
+ apiBaseUrl: profile.apiBaseUrl,
3342
+ tokenId: profile.tokenId
3343
+ });
3344
+ let revoked = false;
3345
+ if (secret !== void 0) {
3346
+ revoked = await revokeToken(input.fetch, profile.apiBaseUrl, secret).then(() => true).catch(() => false);
3347
+ }
3348
+ await input.credentialStore.delete({ apiBaseUrl: profile.apiBaseUrl, tokenId: profile.tokenId });
3349
+ await clearStoredSiftConfig({ homeDir: input.homeDir });
3350
+ const message = revoked ? "Logged out of Sift CLI." : `Logged out locally. Remote revoke was not confirmed; revoke from ${profile.appBaseUrl}.`;
3351
+ return ok(json ? `${JSON.stringify({ status: "logged_out", remoteRevoked: revoked, at: now.toISOString() })}
3352
+ ` : `${message}
3353
+ `);
3354
+ }
3355
+ function okStatus(source, loaded, json) {
3356
+ if (loaded === void 0) {
3357
+ return ok(json ? '{"auth":"none"}\n' : "Auth: none\n");
3358
+ }
3359
+ return ok(
3360
+ json ? `${JSON.stringify({ auth: source, ...loaded.config })}
3361
+ ` : `Auth: ${source}
3362
+ ${renderScope(loaded.config)}`
3363
+ );
3364
+ }
3365
+ function requestedCapabilities(rest) {
3366
+ const option = parseOptions(rest).get("capability");
3367
+ return option === void 0 ? ["record:read"] : option.split(",").map((item) => item.trim()).filter((item) => item.length > 0);
3368
+ }
3369
+ function configFromToken(token) {
3370
+ return {
3371
+ currentProfile: "default",
3372
+ profiles: {
3373
+ default: {
3374
+ apiBaseUrl: token.apiBaseUrl,
3375
+ appBaseUrl: token.appBaseUrl,
3376
+ workspaceId: token.workspaceId,
3377
+ brainId: token.brainId,
3378
+ principalId: token.principalId,
3379
+ tokenId: token.tokenId,
3380
+ tokenLabel: token.tokenLabel,
3381
+ tokenExpiresAt: token.tokenExpiresAt,
3382
+ capabilities: [...token.capabilities]
3383
+ }
3384
+ }
3385
+ };
3386
+ }
3387
+ async function tryOpenBrowser(openBrowser, url) {
3388
+ await (openBrowser ?? openBrowserUrl)(url).catch(() => void 0);
3389
+ }
3390
+ async function openBrowserUrl(url) {
3391
+ if (process.platform === "darwin") {
3392
+ await execFileAsync2("open", [url]);
3393
+ return;
3394
+ }
3395
+ if (process.platform === "win32") {
3396
+ await execFileAsync2("cmd", ["/c", "start", "", url]);
3397
+ return;
3398
+ }
3399
+ await execFileAsync2("xdg-open", [url]);
3400
+ }
3401
+ async function revokeToken(fetchImpl, apiBaseUrl, token) {
3402
+ await postJson(fetchImpl, `${apiBaseUrl}/cli-auth/revoke`, {}, { Authorization: `Bearer ${token}` });
3403
+ }
3404
+ async function postJson(fetchImpl, url, body, headers = {}) {
3405
+ const response = await fetchImpl(url, {
3406
+ method: "POST",
3407
+ headers: { "Content-Type": "application/json", ...headers },
3408
+ body: JSON.stringify(body)
3409
+ });
3410
+ const text = await response.text();
3411
+ const parsed = text.length === 0 ? {} : JSON.parse(text);
3412
+ if (!response.ok) {
3413
+ throw new Error(errorMessage2(parsed, response.status));
3414
+ }
3415
+ return parsed;
3416
+ }
3417
+ function errorMessage2(parsed, status2) {
3418
+ if (typeof parsed === "object" && parsed !== null && "error" in parsed) {
3419
+ const error = parsed.error;
3420
+ if (typeof error === "object" && error !== null && "message" in error) {
3421
+ const message = error.message;
3422
+ if (typeof message === "string") return message;
3423
+ }
3424
+ }
3425
+ return `CLI auth request failed with status ${status2}.`;
3426
+ }
3427
+ function failJson(message) {
3428
+ return {
3429
+ exitCode: 1,
3430
+ stdout: `${JSON.stringify({ error: { code: "auth_failed", message } })}
3431
+ `,
3432
+ stderr: ""
3433
+ };
3434
+ }
3435
+ function normalizeUrl(value) {
3436
+ return value.replace(/\/+$/u, "");
3437
+ }
3438
+ function clean2(value) {
3439
+ const trimmed = value?.trim();
3440
+ return trimmed === void 0 || trimmed.length === 0 ? void 0 : trimmed;
3441
+ }
3442
+
3443
+ // src/bin/sift.ts
3444
+ var credentialStore = createMacOSKeychainStore();
3445
+ var authCommands = createSiftCliAuthCommands({
3446
+ env: process.env,
3447
+ homeDir: process.env.HOME ?? process.cwd(),
3448
+ credentialStore,
3449
+ fetch
3450
+ });
3451
+ var loadedAuth = await authCommands.loadAuth();
3452
+ var config = loadedAuth?.config ?? {
3453
+ apiBaseUrl: "",
3454
+ tokenLabel: "unset",
3455
+ workspaceId: "",
3456
+ brainId: "",
3457
+ principalId: "",
3458
+ capabilities: []
3459
+ };
3460
+ var result = await runSiftCli({
3461
+ argv: process.argv.slice(2),
3462
+ config,
3463
+ readStdin,
3464
+ executor: loadedAuth === void 0 ? void 0 : createHostedApiExecutor({
3465
+ apiBaseUrl: loadedAuth.config.apiBaseUrl,
3466
+ token: loadedAuth.token,
3467
+ workspaceId: loadedAuth.config.workspaceId,
3468
+ brainId: loadedAuth.config.brainId
3469
+ }),
3470
+ authCommands,
3471
+ mcpServer: {
3472
+ serve: async ({ config: config2, executor }) => {
3473
+ if (executor === void 0) {
3474
+ throw new Error("No Sift API executor is configured for mcp.serve.");
3475
+ }
3476
+ const { createLocalMcpStdioServer: createLocalMcpStdioServer2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
3477
+ return createLocalMcpStdioServer2({
3478
+ input: process.stdin,
3479
+ output: process.stdout,
3480
+ error: process.stderr
3481
+ }).serve({
3482
+ capabilities: config2.capabilities,
3483
+ executor
3484
+ });
3485
+ }
3486
+ }
3487
+ });
3488
+ process.stdout.write(result.stdout);
3489
+ process.stderr.write(result.stderr);
3490
+ process.exitCode = result.exitCode;
3491
+ async function readStdin() {
3492
+ const chunks = [];
3493
+ for await (const chunk of process.stdin) {
3494
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
3495
+ }
3496
+ return Buffer.concat(chunks).toString("utf8");
3497
+ }