@sift-wiki/cli 0.1.4 → 0.1.5

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 +21 -0
  2. package/dist/bin/sift.js +878 -304
  3. package/package.json +1 -1
package/dist/bin/sift.js CHANGED
@@ -149,20 +149,20 @@ function parseProfileQuery(input) {
149
149
  };
150
150
  }
151
151
  function parseToolsSearch(input) {
152
- const result2 = {
152
+ const result = {
153
153
  intent: requireString(input, "intent")
154
154
  };
155
155
  if (input.toolsetNames !== void 0) {
156
- result2.toolsetNames = requireStringArray(input, "toolsetNames");
156
+ result.toolsetNames = requireStringArray(input, "toolsetNames");
157
157
  }
158
158
  if (input.limit !== void 0) {
159
159
  const limit = optionalInteger(input, "limit");
160
160
  if (limit === void 0 || limit < 1 || limit > 20) {
161
161
  throw new Error("limit must be an integer between 1 and 20.");
162
162
  }
163
- result2.limit = limit;
163
+ result.limit = limit;
164
164
  }
165
- return result2;
165
+ return result;
166
166
  }
167
167
  function parseDecision(input) {
168
168
  return {
@@ -373,6 +373,7 @@ function writeTool(name, summary, properties, cliExample, options) {
373
373
  capability: "record:write",
374
374
  mutability: "write",
375
375
  transports: writeTransports,
376
+ idempotency: options?.idempotency,
376
377
  cliExample,
377
378
  hostedAgent: options?.hostedAgent
378
379
  });
@@ -428,7 +429,7 @@ function defineTool(input) {
428
429
  mutability: input.mutability,
429
430
  auditCategory: input.mutability === "admin" ? "admin" : input.mutability,
430
431
  transports: input.transports,
431
- idempotency: input.mutability === "write" ? "recommended" : "none",
432
+ idempotency: input.idempotency ?? (input.mutability === "write" ? "recommended" : "none"),
432
433
  resultSize: "compact",
433
434
  cliExample: input.cliExample,
434
435
  hostedAgent: hostedAgentMetadata(input, required)
@@ -610,6 +611,32 @@ var init_registry = __esm({
610
611
  severity: { type: "string" },
611
612
  visibility: { type: "array", items: { type: "string" } }
612
613
  }, "sift skill teach <skill-id> --lesson 'when X, do Y'", { required: ["skillId", "lesson", "visibility"] }),
614
+ writeTool("skill.feedback", "Report structured feedback for a pinned skill version; external-agent reports remain reported until trusted Sift evidence verifies them.", {
615
+ skillId: { type: "string" },
616
+ skillVersionId: { type: "string" },
617
+ exerciseRef: {
618
+ type: "object",
619
+ properties: { exerciseId: { type: "string" } },
620
+ required: ["exerciseId"]
621
+ },
622
+ subjectRef: { type: "object", properties: {} },
623
+ signalKind: { type: "string" },
624
+ polarity: { type: "string", enum: ["positive", "negative", "mixed", "unknown"] },
625
+ strength: { type: "string", enum: ["weak", "medium", "strong"] },
626
+ payload: { type: "object", properties: {} },
627
+ idempotencyKey: { type: "string" }
628
+ }, "sift skill feedback <skill-id> <skill-version-id>", {
629
+ required: [
630
+ "skillId",
631
+ "skillVersionId",
632
+ "signalKind",
633
+ "polarity",
634
+ "strength",
635
+ "payload",
636
+ "idempotencyKey"
637
+ ],
638
+ idempotency: "required"
639
+ }),
613
640
  readTool("search.query", "Search authorized brain context and return raw cited candidate results for exploration.", {
614
641
  query: { type: "string" },
615
642
  limit: { type: "integer", minimum: 1, maximum: 20 }
@@ -813,24 +840,24 @@ var init_discovery = __esm({
813
840
  });
814
841
 
815
842
  // ../tools/dist/results.js
816
- function captureResult(result2) {
843
+ function captureResult(result) {
817
844
  return {
818
- status: result2.job?.status ?? result2.status ?? "captured",
819
- jobId: result2.job?.id,
820
- sourceId: result2.sourceId,
821
- sourceItemId: result2.sourceItemId,
822
- recordId: result2.recordId,
823
- versionId: result2.versionId,
824
- versionNumber: result2.versionNumber
845
+ status: result.job?.status ?? result.status ?? "captured",
846
+ jobId: result.job?.id,
847
+ sourceId: result.sourceId,
848
+ sourceItemId: result.sourceItemId,
849
+ recordId: result.recordId,
850
+ versionId: result.versionId,
851
+ versionNumber: result.versionNumber
825
852
  };
826
853
  }
827
- function workRecordResult(result2) {
854
+ function workRecordResult(result) {
828
855
  return {
829
- status: result2.job.status,
830
- jobId: result2.job.id,
831
- recordId: result2.recordId,
832
- versionId: result2.versionId,
833
- versionNumber: result2.versionNumber
856
+ status: result.job.status,
857
+ jobId: result.job.id,
858
+ recordId: result.recordId,
859
+ versionId: result.versionId,
860
+ versionNumber: result.versionNumber
834
861
  };
835
862
  }
836
863
  var init_results = __esm({
@@ -842,16 +869,16 @@ var init_results = __esm({
842
869
  // ../tools/dist/captureTools.js
843
870
  async function executeCaptureText(input, toolInput) {
844
871
  const capture = parseCaptureText(toolInput);
845
- const result2 = await input.service.ingestText({ auth: input.auth, ...capture });
846
- return captureResult(result2);
872
+ const result = await input.service.ingestText({ auth: input.auth, ...capture });
873
+ return captureResult(result);
847
874
  }
848
875
  async function executeCaptureFile(input, toolInput) {
849
876
  if (input.service.ingestFile === void 0) {
850
877
  throw new Error("Tool 'capture.file' requires a file ingestion service contract.");
851
878
  }
852
879
  const file = parseCaptureFile(toolInput);
853
- const result2 = await input.service.ingestFile({ auth: input.auth, ...file });
854
- return captureResult(result2);
880
+ const result = await input.service.ingestFile({ auth: input.auth, ...file });
881
+ return captureResult(result);
855
882
  }
856
883
  async function executeCaptureBatch(input, toolInput) {
857
884
  const batch = parseCaptureBatch(toolInput);
@@ -859,16 +886,16 @@ async function executeCaptureBatch(input, toolInput) {
859
886
  for (const item of batch.items) {
860
887
  if (item.kind === "text") {
861
888
  const { kind: _kind2, ...capture } = item;
862
- const result3 = await input.service.ingestText({ auth: input.auth, ...capture });
863
- results.push(captureResult(result3));
889
+ const result2 = await input.service.ingestText({ auth: input.auth, ...capture });
890
+ results.push(captureResult(result2));
864
891
  continue;
865
892
  }
866
893
  if (input.service.ingestFile === void 0) {
867
894
  throw new Error("Tool 'capture.batch' requires a file ingestion service contract.");
868
895
  }
869
896
  const { kind: _kind, ...file } = item;
870
- const result2 = await input.service.ingestFile({ auth: input.auth, ...file });
871
- results.push(captureResult(result2));
897
+ const result = await input.service.ingestFile({ auth: input.auth, ...file });
898
+ results.push(captureResult(result));
872
899
  }
873
900
  return results;
874
901
  }
@@ -941,6 +968,15 @@ function skillToolHandlers(input, toolInput) {
941
968
  if (input.service.teachSkill === void 0)
942
969
  throw missingSkillService("skill.teach");
943
970
  return input.service.teachSkill({ auth: input.auth, ...parseSkillTeach(toolInput) });
971
+ },
972
+ "skill.feedback": () => {
973
+ if (input.service.reportFeedbackSignal === void 0) {
974
+ throw missingSkillService("skill.feedback");
975
+ }
976
+ return input.service.reportFeedbackSignal({
977
+ auth: input.auth,
978
+ ...parseSkillFeedback(toolInput)
979
+ });
944
980
  }
945
981
  };
946
982
  }
@@ -950,7 +986,8 @@ function skillToolAvailability(service) {
950
986
  [service.getSkill !== void 0, ["skill.get"]],
951
987
  [service.getSkillFile !== void 0, ["skill.file"]],
952
988
  [service.recordSkillExercise !== void 0, ["skill.exercise"]],
953
- [service.teachSkill !== void 0, ["skill.teach"]]
989
+ [service.teachSkill !== void 0, ["skill.teach"]],
990
+ [service.reportFeedbackSignal !== void 0, ["skill.feedback"]]
954
991
  ];
955
992
  }
956
993
  function parseSkillExercise(input) {
@@ -983,6 +1020,29 @@ function parseSkillTeach(input) {
983
1020
  visibility
984
1021
  };
985
1022
  }
1023
+ function parseSkillFeedback(input) {
1024
+ const exerciseRef = optionalObject(input, "exerciseRef");
1025
+ const subjectRef = optionalObject(input, "subjectRef");
1026
+ const polarity = requireString(input, "polarity");
1027
+ const strength = requireString(input, "strength");
1028
+ if (!isSkillFeedbackPolarity(polarity)) {
1029
+ throw new Error("polarity must be positive, negative, mixed, or unknown.");
1030
+ }
1031
+ if (!isSkillFeedbackStrength(strength)) {
1032
+ throw new Error("strength must be weak, medium, or strong.");
1033
+ }
1034
+ return {
1035
+ skillId: requireString(input, "skillId"),
1036
+ skillVersionId: requireString(input, "skillVersionId"),
1037
+ exerciseRef: exerciseRef === void 0 ? void 0 : { exerciseId: requireString(exerciseRef, "exerciseId") },
1038
+ subjectRef,
1039
+ signalKind: requireString(input, "signalKind"),
1040
+ polarity,
1041
+ strength,
1042
+ payload: optionalObject(input, "payload") ?? {},
1043
+ idempotencyKey: requireString(input, "idempotencyKey")
1044
+ };
1045
+ }
986
1046
  function requireSkillOutputRef(input, key) {
987
1047
  const value = input[key];
988
1048
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
@@ -1001,6 +1061,22 @@ function requireSkillOutputRef(input, key) {
1001
1061
  }
1002
1062
  throw new Error(`${key}.kind must be record or external.`);
1003
1063
  }
1064
+ function optionalObject(input, key) {
1065
+ const value = input[key];
1066
+ if (value === void 0) {
1067
+ return void 0;
1068
+ }
1069
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
1070
+ throw new Error(`${key} must be an object.`);
1071
+ }
1072
+ return value;
1073
+ }
1074
+ function isSkillFeedbackPolarity(value) {
1075
+ return value === "positive" || value === "negative" || value === "mixed" || value === "unknown";
1076
+ }
1077
+ function isSkillFeedbackStrength(value) {
1078
+ return value === "weak" || value === "medium" || value === "strong";
1079
+ }
1004
1080
  function missingSkillService(toolName) {
1005
1081
  return new Error(`Tool '${toolName}' requires a runtime service contract.`);
1006
1082
  }
@@ -1267,7 +1343,7 @@ function createRuntimeToolExecutor(input) {
1267
1343
  throw error;
1268
1344
  }
1269
1345
  try {
1270
- const result2 = await handler();
1346
+ const result = await handler();
1271
1347
  logToolCall({
1272
1348
  auth: input.auth,
1273
1349
  onToolLog: input.onToolLog,
@@ -1275,9 +1351,9 @@ function createRuntimeToolExecutor(input) {
1275
1351
  toolInput,
1276
1352
  status: "success",
1277
1353
  startedAt,
1278
- result: result2
1354
+ result
1279
1355
  });
1280
- return result2;
1356
+ return result;
1281
1357
  } catch (error) {
1282
1358
  logToolCall({
1283
1359
  auth: input.auth,
@@ -1411,16 +1487,16 @@ async function executeDecisionCreate(input, toolInput) {
1411
1487
  throw new Error("Tool 'decision.create' requires a work-record service contract.");
1412
1488
  }
1413
1489
  const decision = parseDecision(toolInput);
1414
- const result2 = await input.service.createDecision({ auth: input.auth, ...decision });
1415
- return workRecordResult(result2);
1490
+ const result = await input.service.createDecision({ auth: input.auth, ...decision });
1491
+ return workRecordResult(result);
1416
1492
  }
1417
1493
  async function executeTaskCreate(input, toolInput) {
1418
1494
  if (input.service.createTask === void 0) {
1419
1495
  throw new Error("Tool 'task.create' requires a work-record service contract.");
1420
1496
  }
1421
1497
  const task = parseTask(toolInput);
1422
- const result2 = await input.service.createTask({ auth: input.auth, ...task });
1423
- return workRecordResult(result2);
1498
+ const result = await input.service.createTask({ auth: input.auth, ...task });
1499
+ return workRecordResult(result);
1424
1500
  }
1425
1501
  function executeSourceList(input) {
1426
1502
  if (input.service.listSources === void 0) {
@@ -1471,16 +1547,16 @@ async function executeRecordCreateMarkdown(input, toolInput) {
1471
1547
  throw new Error("Tool 'record.create_markdown' requires a record write service contract.");
1472
1548
  }
1473
1549
  const record = parseMarkdownRecord(toolInput);
1474
- const result2 = await input.service.createMarkdownRecord({ auth: input.auth, ...record });
1475
- return workRecordResult(result2);
1550
+ const result = await input.service.createMarkdownRecord({ auth: input.auth, ...record });
1551
+ return workRecordResult(result);
1476
1552
  }
1477
1553
  async function executeRecordPatchSection(input, toolInput) {
1478
1554
  if (input.service.patchRecordSection === void 0) {
1479
1555
  throw new Error("Tool 'record.patch_section' requires a record write service contract.");
1480
1556
  }
1481
1557
  const patch = parseRecordSectionPatch(toolInput);
1482
- const result2 = await input.service.patchRecordSection({ auth: input.auth, ...patch });
1483
- return workRecordResult(result2);
1558
+ const result = await input.service.patchRecordSection({ auth: input.auth, ...patch });
1559
+ return workRecordResult(result);
1484
1560
  }
1485
1561
  function executeRecordVersions(input, toolInput) {
1486
1562
  if (input.service.listRecordVersions === void 0) {
@@ -1563,11 +1639,11 @@ function createMcpAdapter(input) {
1563
1639
  return errorResult2("tool_unavailable", `Tool '${call.name}' is unavailable for this MCP transport or scope.`);
1564
1640
  }
1565
1641
  try {
1566
- const result2 = await input.executor.execute(call.name, call.arguments);
1642
+ const result = await input.executor.execute(call.name, call.arguments);
1567
1643
  return {
1568
1644
  isError: false,
1569
- structuredContent: result2,
1570
- content: [{ type: "text", text: renderToolResult(result2) }]
1645
+ structuredContent: result,
1646
+ content: [{ type: "text", text: renderToolResult(result) }]
1571
1647
  };
1572
1648
  } catch (error) {
1573
1649
  return errorResult2(classifyToolError(error), messageForError(error));
@@ -1575,14 +1651,14 @@ function createMcpAdapter(input) {
1575
1651
  }
1576
1652
  };
1577
1653
  }
1578
- function renderToolResult(result2) {
1579
- if (typeof result2 === "object" && result2 !== null && "contextMarkdown" in result2) {
1580
- const context = result2;
1654
+ function renderToolResult(result) {
1655
+ if (typeof result === "object" && result !== null && "contextMarkdown" in result) {
1656
+ const context = result;
1581
1657
  if (typeof context.contextMarkdown === "string") {
1582
1658
  return context.contextMarkdown;
1583
1659
  }
1584
1660
  }
1585
- return JSON.stringify(result2);
1661
+ return JSON.stringify(result);
1586
1662
  }
1587
1663
  function classifyToolError(error) {
1588
1664
  if (error instanceof Error) {
@@ -1703,7 +1779,7 @@ var init_hostedMcpEntrypoint = __esm({
1703
1779
 
1704
1780
  // ../tools/dist/mcpJsonRpcCore.js
1705
1781
  function createMcpJsonRpcCore(input) {
1706
- const { adapter, config: config2 } = input;
1782
+ const { adapter, config } = input;
1707
1783
  return {
1708
1784
  async handleMessage(message) {
1709
1785
  if (message.id === void 0) {
@@ -1717,7 +1793,7 @@ function createMcpJsonRpcCore(input) {
1717
1793
  return {
1718
1794
  jsonrpc: "2.0",
1719
1795
  id,
1720
- result: await dispatchRequest(message.method, message.params, adapter, config2)
1796
+ result: await dispatchRequest(message.method, message.params, adapter, config)
1721
1797
  };
1722
1798
  } catch (err) {
1723
1799
  return errorResponse(id, -32601, err instanceof Error ? err.message : "Method not found");
@@ -1728,14 +1804,14 @@ function createMcpJsonRpcCore(input) {
1728
1804
  function parseErrorResponse() {
1729
1805
  return errorResponse(null, -32700, "Parse error");
1730
1806
  }
1731
- async function dispatchRequest(method, params, adapter, config2) {
1807
+ async function dispatchRequest(method, params, adapter, config) {
1732
1808
  if (method === "initialize") {
1733
1809
  const requested = readProtocolVersion(params);
1734
1810
  return {
1735
1811
  protocolVersion: requested ?? MCP_PROTOCOL_VERSION,
1736
1812
  capabilities: { tools: { listChanged: false } },
1737
- serverInfo: { name: config2.serverName, version: config2.version },
1738
- instructions: config2.instructions
1813
+ serverInfo: { name: config.serverName, version: config.version },
1814
+ instructions: config.instructions
1739
1815
  };
1740
1816
  }
1741
1817
  if (method === "ping")
@@ -1749,23 +1825,23 @@ async function dispatchRequest(method, params, adapter, config2) {
1749
1825
  throw new Error(`Method '${method}' is not supported by Sift MCP.`);
1750
1826
  }
1751
1827
  function readProtocolVersion(params) {
1752
- if (!isRecord(params))
1828
+ if (!isRecord2(params))
1753
1829
  return void 0;
1754
1830
  return typeof params.protocolVersion === "string" ? params.protocolVersion : void 0;
1755
1831
  }
1756
1832
  function parseToolCall(params) {
1757
- if (!isRecord(params) || typeof params.name !== "string") {
1833
+ if (!isRecord2(params) || typeof params.name !== "string") {
1758
1834
  throw new Error("tools/call requires a tool name.");
1759
1835
  }
1760
1836
  return {
1761
1837
  name: params.name,
1762
- arguments: isRecord(params.arguments) ? params.arguments : {}
1838
+ arguments: isRecord2(params.arguments) ? params.arguments : {}
1763
1839
  };
1764
1840
  }
1765
1841
  function errorResponse(id, code, message) {
1766
1842
  return { jsonrpc: "2.0", id, error: { code, message } };
1767
1843
  }
1768
- function isRecord(value) {
1844
+ function isRecord2(value) {
1769
1845
  return typeof value === "object" && value !== null && !Array.isArray(value);
1770
1846
  }
1771
1847
  function normalizeId(value) {
@@ -1900,19 +1976,19 @@ function renderScope(scope) {
1900
1976
  ""
1901
1977
  ].join("\n");
1902
1978
  }
1903
- function validateAuthenticatedScope(config2, now) {
1979
+ function validateAuthenticatedScope(config, now) {
1904
1980
  const requiredScope = [
1905
- ["apiBaseUrl", config2.apiBaseUrl],
1906
- ["workspaceId", config2.workspaceId],
1907
- ["brainId", config2.brainId],
1908
- ["principalId", config2.principalId]
1981
+ ["apiBaseUrl", config.apiBaseUrl],
1982
+ ["workspaceId", config.workspaceId],
1983
+ ["brainId", config.brainId],
1984
+ ["principalId", config.principalId]
1909
1985
  ];
1910
1986
  const missing = requiredScope.find(([, value]) => value.trim().length === 0);
1911
1987
  if (missing !== void 0) {
1912
1988
  throw new Error(`Missing authenticated CLI scope: ${missing[0]}.`);
1913
1989
  }
1914
- if (config2.tokenExpiresAt !== void 0) {
1915
- const expiresAt = Date.parse(config2.tokenExpiresAt);
1990
+ if (config.tokenExpiresAt !== void 0) {
1991
+ const expiresAt = Date.parse(config.tokenExpiresAt);
1916
1992
  if (!Number.isFinite(expiresAt)) {
1917
1993
  throw new Error("Invalid CLI auth expiry timestamp.");
1918
1994
  }
@@ -1921,49 +1997,49 @@ function validateAuthenticatedScope(config2, now) {
1921
1997
  }
1922
1998
  }
1923
1999
  }
1924
- function renderSearchResult(result2) {
1925
- if (typeof result2 === "object" && result2 !== null && "contextMarkdown" in result2) {
1926
- const context = result2;
2000
+ function renderSearchResult(result) {
2001
+ if (typeof result === "object" && result !== null && "contextMarkdown" in result) {
2002
+ const context = result;
1927
2003
  return `${context.contextMarkdown}
1928
2004
  `;
1929
2005
  }
1930
- return `${JSON.stringify(result2)}
2006
+ return `${JSON.stringify(result)}
1931
2007
  `;
1932
2008
  }
1933
- function renderRecordResult(result2) {
1934
- if (typeof result2 === "object" && result2 !== null && "markdown" in result2) {
1935
- const record = result2;
2009
+ function renderRecordResult(result) {
2010
+ if (typeof result === "object" && result !== null && "markdown" in result) {
2011
+ const record = result;
1936
2012
  return `${record.markdown}
1937
2013
  `;
1938
2014
  }
1939
- return `${JSON.stringify(result2)}
2015
+ return `${JSON.stringify(result)}
1940
2016
  `;
1941
2017
  }
1942
- function renderProfileResult(result2) {
1943
- if (typeof result2 === "object" && result2 !== null && "profileMarkdown" in result2) {
1944
- const profile = result2;
2018
+ function renderProfileResult(result) {
2019
+ if (typeof result === "object" && result !== null && "profileMarkdown" in result) {
2020
+ const profile = result;
1945
2021
  return `${profile.profileMarkdown}
1946
2022
  `;
1947
2023
  }
1948
- return `${JSON.stringify(result2)}
2024
+ return `${JSON.stringify(result)}
1949
2025
  `;
1950
2026
  }
1951
2027
  function renderTools(tools) {
1952
2028
  return `${tools.map((tool) => `${tool.name}: ${tool.summary}`).join("\n")}
1953
2029
  `;
1954
2030
  }
1955
- function renderSiftFound(result2) {
2031
+ function renderSiftFound(result) {
1956
2032
  return `Sift found:
1957
2033
 
1958
- ${renderSearchResult(result2)}`;
2034
+ ${renderSearchResult(result)}`;
1959
2035
  }
1960
- function renderWriteReceipt(action, result2) {
1961
- if (typeof result2 !== "object" || result2 === null) {
2036
+ function renderWriteReceipt(action, result) {
2037
+ if (typeof result !== "object" || result === null) {
1962
2038
  return `${action} complete.
1963
- ${JSON.stringify(result2)}
2039
+ ${JSON.stringify(result)}
1964
2040
  `;
1965
2041
  }
1966
- const record = result2;
2042
+ const record = result;
1967
2043
  const lines = [`${action} complete.`];
1968
2044
  addReceiptLine(lines, "Record", record.recordId);
1969
2045
  addReceiptLine(lines, "Version", record.versionId);
@@ -1973,20 +2049,20 @@ ${JSON.stringify(result2)}
1973
2049
  addReceiptLine(lines, "Job", record.job.id);
1974
2050
  }
1975
2051
  if (lines.length === 1) {
1976
- lines.push(JSON.stringify(result2));
2052
+ lines.push(JSON.stringify(result));
1977
2053
  }
1978
2054
  lines.push("");
1979
2055
  return lines.join("\n");
1980
2056
  }
1981
- function renderDoctorResult(result2) {
1982
- return `${result2.checks.map((check) => {
2057
+ function renderDoctorResult(result) {
2058
+ return `${result.checks.map((check) => {
1983
2059
  const fix = check.fix === void 0 ? "" : ` Fix: ${check.fix}`;
1984
2060
  return `[${check.status}] ${check.label}: ${check.detail}${fix}`;
1985
2061
  }).join("\n")}
1986
2062
  `;
1987
2063
  }
1988
- function aliasJson(command, tool, result2) {
1989
- return `${JSON.stringify({ command, tool, result: result2 })}
2064
+ function aliasJson(command, tool, result) {
2065
+ return `${JSON.stringify({ command, tool, result })}
1990
2066
  `;
1991
2067
  }
1992
2068
  function positionalArgs(args) {
@@ -2184,16 +2260,16 @@ async function agentRegister(executor, assertedAgentName, rest, json) {
2184
2260
  if (kind !== void 0) {
2185
2261
  input.kind = kind;
2186
2262
  }
2187
- const result2 = await executor.execute("agent.register", input);
2188
- return ok(json ? `${JSON.stringify(result2)}
2189
- ` : renderAgentRegisterResult(result2));
2263
+ const result = await executor.execute("agent.register", input);
2264
+ return ok(json ? `${JSON.stringify(result)}
2265
+ ` : renderAgentRegisterResult(result));
2190
2266
  }
2191
- function renderAgentRegisterResult(result2) {
2192
- if (typeof result2 !== "object" || result2 === null || !("agent" in result2)) {
2193
- return `${JSON.stringify(result2)}
2267
+ function renderAgentRegisterResult(result) {
2268
+ if (typeof result !== "object" || result === null || !("agent" in result)) {
2269
+ return `${JSON.stringify(result)}
2194
2270
  `;
2195
2271
  }
2196
- const { agent, created, reactivated } = result2;
2272
+ const { agent, created, reactivated } = result;
2197
2273
  const verb = created === true ? "Registered" : reactivated === true ? "Reactivated" : "Already registered";
2198
2274
  const actsFor = agent.actsForDisplayName === void 0 ? "" : ` (acting for ${agent.actsForDisplayName})`;
2199
2275
  return `${verb} agent worker '${agent.name ?? "unknown"}'${actsFor}.
@@ -2262,7 +2338,8 @@ var commandCapabilities = {
2262
2338
  "evidence:get": "record:read",
2263
2339
  "graph:neighbors": "record:read",
2264
2340
  "event:list": "record:read",
2265
- "audit:events": "event:audit:read"
2341
+ "audit:events": "event:audit:read",
2342
+ "roam:import": "source:manage"
2266
2343
  };
2267
2344
  function validateCommandCapability(input) {
2268
2345
  const capability = commandCapabilities[input.commandKey];
@@ -2300,6 +2377,190 @@ function withContractVersion(executor, contractVersion) {
2300
2377
  };
2301
2378
  }
2302
2379
 
2380
+ // src/roamImport.ts
2381
+ async function runRoamImportCommand(input) {
2382
+ try {
2383
+ const parsed = parseOptions(input.rest);
2384
+ const scope = parseCliRoamScope(optionalOption(parsed, "scope") ?? "sift-tag");
2385
+ const mode = parseCliRoamMode(optionalOption(parsed, "mode") ?? "personal");
2386
+ const limit = parseIntegerOption(parsed, "limit", 100);
2387
+ if (limit < 1 || limit > 100) {
2388
+ throw new Error("Option --limit must be between 1 and 100.");
2389
+ }
2390
+ const wholeGraphConfirmed = input.rest.includes("--confirm-whole-graph") || input.rest.includes("--yes");
2391
+ if (scope === "whole_graph" && !wholeGraphConfirmed) {
2392
+ throw new Error("Option --confirm-whole-graph is required.");
2393
+ }
2394
+ const workspaceAttestation = input.rest.includes("--workspace-attestation") || input.rest.includes("--confirm-workspace");
2395
+ if (mode === "workspace" && !workspaceAttestation) {
2396
+ throw new Error("Option --workspace-attestation is required.");
2397
+ }
2398
+ if (input.reader === void 0) {
2399
+ throw new Error(
2400
+ "Roam import needs the local Roam helper. Run this command through the Sift CLI package."
2401
+ );
2402
+ }
2403
+ if (input.importer === void 0) {
2404
+ throw new Error("Not signed in. Run 'sift login', then retry 'sift roam import'.");
2405
+ }
2406
+ const records = await input.reader.exportPages({
2407
+ scope,
2408
+ graph: optionalOption(parsed, "graph"),
2409
+ limit,
2410
+ now: input.now
2411
+ });
2412
+ if (records.length === 0) {
2413
+ throw new Error(
2414
+ scope === "sift_tag" ? "No Roam pages marked [[Sift]] were found." : "No Roam pages were found for import."
2415
+ );
2416
+ }
2417
+ const result = await input.importer.importRecords({
2418
+ mode,
2419
+ scope,
2420
+ records,
2421
+ defaultVisibility: visibilityOption(parsed),
2422
+ workspaceAttestation,
2423
+ wholeGraphConfirmed
2424
+ });
2425
+ return ok(input.json ? `${JSON.stringify(result)}
2426
+ ` : renderRoamImportResult(result));
2427
+ } catch (error) {
2428
+ return errorResult(error, input.json);
2429
+ }
2430
+ }
2431
+ function createSiftRoamImportClient(input) {
2432
+ const fetchImpl = input.fetch ?? globalThis.fetch;
2433
+ return {
2434
+ async importRecords(request) {
2435
+ const response = await fetchImpl(roamImportUrl(input.apiBaseUrl, input.workspaceId), {
2436
+ method: "POST",
2437
+ headers: {
2438
+ Authorization: `Bearer ${input.token}`,
2439
+ "Content-Type": "application/json"
2440
+ },
2441
+ body: JSON.stringify(request)
2442
+ });
2443
+ const body = await response.text();
2444
+ const parsed = body.length > 0 ? parseJson(body) : {};
2445
+ if (!response.ok) {
2446
+ throw new Error(responseError(parsed, response.status));
2447
+ }
2448
+ return parseRoamImportResult(parsed);
2449
+ }
2450
+ };
2451
+ }
2452
+ function parseCliRoamScope(value) {
2453
+ if (value === "sift-tag" || value === "sift_tag" || value === "marked" || value === "sift") {
2454
+ return "sift_tag";
2455
+ }
2456
+ if (value === "whole-graph" || value === "whole_graph" || value === "everything") {
2457
+ return "whole_graph";
2458
+ }
2459
+ throw new Error("Roam scope must be sift-tag or whole-graph.");
2460
+ }
2461
+ function parseCliRoamMode(value) {
2462
+ if (value === "personal" || value === "workspace") return value;
2463
+ throw new Error("Roam import mode must be personal or workspace.");
2464
+ }
2465
+ function visibilityOption(parsed) {
2466
+ const visibility = optionalOption(parsed, "visibility");
2467
+ if (visibility === void 0) return void 0;
2468
+ const values = visibility.split(",").map((value) => value.trim()).filter((value) => value.length > 0);
2469
+ if (values.length === 0) {
2470
+ throw new Error("Option --visibility must include at least one visibility segment.");
2471
+ }
2472
+ return values;
2473
+ }
2474
+ function renderRoamImportResult(result) {
2475
+ return [
2476
+ `Imported ${result.importedCount} Roam pages.`,
2477
+ `Stored: ${result.storedCount}`,
2478
+ `Deduped: ${result.dedupedCount}`,
2479
+ `Rejected: ${result.rejectedCount}`,
2480
+ ""
2481
+ ].join("\n");
2482
+ }
2483
+ function roamImportUrl(apiBaseUrl, workspaceId) {
2484
+ const base = `${apiBaseUrl.replace(/\/+$/u, "")}/integrations/roam/import`;
2485
+ return workspaceId === void 0 ? base : `${base}?workspaceId=${encodeURIComponent(workspaceId)}`;
2486
+ }
2487
+ function parseJson(body) {
2488
+ try {
2489
+ return JSON.parse(body);
2490
+ } catch {
2491
+ throw new Error("Sift Roam import API returned invalid JSON.");
2492
+ }
2493
+ }
2494
+ function responseError(parsed, status2) {
2495
+ if (typeof parsed === "object" && parsed !== null) {
2496
+ const record = parsed;
2497
+ const message = record.message;
2498
+ if (typeof message === "string" && message.trim().length > 0) return message;
2499
+ const error = record.error;
2500
+ if (typeof error === "object" && error !== null && "message" in error) {
2501
+ const nested = error.message;
2502
+ if (typeof nested === "string" && nested.trim().length > 0) return nested;
2503
+ }
2504
+ }
2505
+ return `Sift Roam import API failed with status ${status2}.`;
2506
+ }
2507
+ function parseRoamImportResult(value) {
2508
+ if (typeof value !== "object" || value === null || Array.isArray(value)) {
2509
+ throw new Error("Sift Roam import API returned an invalid result.");
2510
+ }
2511
+ const record = value;
2512
+ if (record.providerKind !== "roam") {
2513
+ throw new Error("Sift Roam import API returned an unexpected provider kind.");
2514
+ }
2515
+ return {
2516
+ providerKind: "roam",
2517
+ importedCount: integerField(record, "importedCount"),
2518
+ storedCount: integerField(record, "storedCount"),
2519
+ dedupedCount: integerField(record, "dedupedCount"),
2520
+ rejectedCount: integerField(record, "rejectedCount")
2521
+ };
2522
+ }
2523
+ function integerField(record, key) {
2524
+ const value = record[key];
2525
+ if (typeof value !== "number" || !Number.isInteger(value)) {
2526
+ throw new Error(`Sift Roam import API result field ${key} must be an integer.`);
2527
+ }
2528
+ return value;
2529
+ }
2530
+
2531
+ // src/mcpServeCommand.ts
2532
+ async function mcpServe(input) {
2533
+ if (input.mcpServer === void 0) {
2534
+ return fail("No local MCP server is configured for mcp.serve.");
2535
+ }
2536
+ if (input.executor === void 0) {
2537
+ return fail("Not signed in. Run 'sift login', then 'sift mcp serve'.");
2538
+ }
2539
+ const result = await input.mcpServer.serve({
2540
+ config: input.config,
2541
+ executor: input.executor,
2542
+ transport: "local_mcp"
2543
+ });
2544
+ if (result === void 0) return ok("");
2545
+ return ok(`${JSON.stringify(result)}
2546
+ `);
2547
+ }
2548
+
2549
+ // src/scopeCurrentCommand.ts
2550
+ function scopeCurrent(config, json) {
2551
+ const scope = {
2552
+ apiBaseUrl: config.apiBaseUrl,
2553
+ tokenLabel: config.tokenLabel,
2554
+ tokenExpiresAt: config.tokenExpiresAt,
2555
+ principalId: config.principalId,
2556
+ workspaceId: config.workspaceId,
2557
+ brainId: config.brainId,
2558
+ capabilities: config.capabilities
2559
+ };
2560
+ return ok(json ? `${JSON.stringify(scope)}
2561
+ ` : renderScope(scope));
2562
+ }
2563
+
2303
2564
  // src/specialCommands.ts
2304
2565
  import { readFile } from "fs/promises";
2305
2566
 
@@ -2317,24 +2578,24 @@ async function doctor(input) {
2317
2578
  checks.push(readToolsCheck(availableTools3));
2318
2579
  checks.push(writeToolsCheck(input.config, availableTools3));
2319
2580
  checks.push(recordGetCheck(availableTools3));
2320
- const result2 = {
2581
+ const result = {
2321
2582
  ok: !checks.some((check) => check.status === "failed"),
2322
2583
  apiBaseUrl: input.config.apiBaseUrl.trim().length > 0 ? input.config.apiBaseUrl : void 0,
2323
2584
  scope: scopeResult(input.config),
2324
2585
  checks
2325
2586
  };
2326
2587
  return {
2327
- exitCode: result2.ok ? 0 : 1,
2328
- stdout: input.json ? `${JSON.stringify(result2)}
2329
- ` : renderDoctorResult(result2),
2588
+ exitCode: result.ok ? 0 : 1,
2589
+ stdout: input.json ? `${JSON.stringify(result)}
2590
+ ` : renderDoctorResult(result),
2330
2591
  stderr: ""
2331
2592
  };
2332
2593
  }
2333
2594
  async function discoverToolNames(executor) {
2334
2595
  if (executor === void 0) return void 0;
2335
2596
  if (executor.listAvailableToolNames !== void 0) return executor.listAvailableToolNames();
2336
- const result2 = await executor.execute("tools.list", {});
2337
- return toolNamesFromResult(result2);
2597
+ const result = await executor.execute("tools.list", {});
2598
+ return toolNamesFromResult(result);
2338
2599
  }
2339
2600
  async function apiReachability(executor) {
2340
2601
  if (executor === void 0) return { reachable: false, detail: "No API executor is configured." };
@@ -2348,15 +2609,15 @@ async function apiReachability(executor) {
2348
2609
  };
2349
2610
  }
2350
2611
  }
2351
- function scopeResult(config2) {
2352
- if (config2.workspaceId.trim().length === 0 || config2.brainId.trim().length === 0 || config2.principalId.trim().length === 0) {
2612
+ function scopeResult(config) {
2613
+ if (config.workspaceId.trim().length === 0 || config.brainId.trim().length === 0 || config.principalId.trim().length === 0) {
2353
2614
  return void 0;
2354
2615
  }
2355
2616
  return {
2356
- workspaceId: config2.workspaceId,
2357
- brainId: config2.brainId,
2358
- principalId: config2.principalId,
2359
- capabilities: [...config2.capabilities]
2617
+ workspaceId: config.workspaceId,
2618
+ brainId: config.brainId,
2619
+ principalId: config.principalId,
2620
+ capabilities: [...config.capabilities]
2360
2621
  };
2361
2622
  }
2362
2623
  async function checkApi(executor) {
@@ -2372,8 +2633,8 @@ async function checkApi(executor) {
2372
2633
  const api = await apiReachability(executor);
2373
2634
  return api.reachable ? { id: "api", status: "ok", label: "API", detail: "whoami succeeded." } : { id: "api", status: "failed", label: "API", detail: api.detail };
2374
2635
  }
2375
- function authCheck(config2, now) {
2376
- if (config2.apiBaseUrl.trim().length === 0 || config2.workspaceId.trim().length === 0 || config2.brainId.trim().length === 0 || config2.principalId.trim().length === 0) {
2636
+ function authCheck(config, now) {
2637
+ if (config.apiBaseUrl.trim().length === 0 || config.workspaceId.trim().length === 0 || config.brainId.trim().length === 0 || config.principalId.trim().length === 0) {
2377
2638
  return {
2378
2639
  id: "auth",
2379
2640
  status: "failed",
@@ -2382,7 +2643,7 @@ function authCheck(config2, now) {
2382
2643
  fix: "Run sift login."
2383
2644
  };
2384
2645
  }
2385
- if (config2.tokenExpiresAt !== void 0 && Date.parse(config2.tokenExpiresAt) <= now.getTime()) {
2646
+ if (config.tokenExpiresAt !== void 0 && Date.parse(config.tokenExpiresAt) <= now.getTime()) {
2386
2647
  return {
2387
2648
  id: "auth",
2388
2649
  status: "failed",
@@ -2393,8 +2654,8 @@ function authCheck(config2, now) {
2393
2654
  }
2394
2655
  return { id: "auth", status: "ok", label: "Auth", detail: "authenticated profile loaded." };
2395
2656
  }
2396
- function scopeCheck(config2) {
2397
- if (config2.workspaceId.trim().length === 0 || config2.brainId.trim().length === 0) {
2657
+ function scopeCheck(config) {
2658
+ if (config.workspaceId.trim().length === 0 || config.brainId.trim().length === 0) {
2398
2659
  return {
2399
2660
  id: "scope",
2400
2661
  status: "failed",
@@ -2407,14 +2668,14 @@ function scopeCheck(config2) {
2407
2668
  id: "scope",
2408
2669
  status: "ok",
2409
2670
  label: "Scope",
2410
- detail: `${config2.workspaceId}/${config2.brainId}`
2671
+ detail: `${config.workspaceId}/${config.brainId}`
2411
2672
  };
2412
2673
  }
2413
2674
  function readToolsCheck(names) {
2414
2675
  return toolSetCheck("read-tools", "Read tools", ["context.assemble", "search.query"], names);
2415
2676
  }
2416
- function writeToolsCheck(config2, names) {
2417
- const hasWrite = config2.capabilities.includes("record:write") || config2.capabilities.includes("source:write");
2677
+ function writeToolsCheck(config, names) {
2678
+ const hasWrite = config.capabilities.includes("record:write") || config.capabilities.includes("source:write");
2418
2679
  if (!hasWrite) {
2419
2680
  return {
2420
2681
  id: "write-tools",
@@ -2453,9 +2714,9 @@ function toolSetCheck(id, label, required, names) {
2453
2714
  const missing = required.filter((name) => !names.includes(name));
2454
2715
  return missing.length === 0 ? { id, status: "ok", label, detail: "required tools are available." } : { id, status: "failed", label, detail: `missing ${missing.join(", ")}.` };
2455
2716
  }
2456
- function toolNamesFromResult(result2) {
2457
- if (!Array.isArray(result2)) return [];
2458
- return result2.flatMap((item) => {
2717
+ function toolNamesFromResult(result) {
2718
+ if (!Array.isArray(result)) return [];
2719
+ return result.flatMap((item) => {
2459
2720
  if (typeof item === "object" && item !== null && "name" in item) {
2460
2721
  const name = item.name;
2461
2722
  return typeof name === "string" ? [name] : [];
@@ -2488,6 +2749,7 @@ var knownTopLevelCommands = /* @__PURE__ */ new Set([
2488
2749
  "mcp",
2489
2750
  "record",
2490
2751
  "remember",
2752
+ "roam",
2491
2753
  "scope",
2492
2754
  "search",
2493
2755
  "show",
@@ -2580,11 +2842,11 @@ async function ask(executor, rest, json) {
2580
2842
  }
2581
2843
  const parsed = parseOptions(rest);
2582
2844
  const query = argsWithoutOptions(rest).join(" ").trim();
2583
- const result2 = await executor.execute("context.assemble", {
2845
+ const result = await executor.execute("context.assemble", {
2584
2846
  query,
2585
2847
  maxChars: parseIntegerOption(parsed, "max-chars", 8e3)
2586
2848
  });
2587
- return ok(json ? aliasJson("ask", "context.assemble", result2) : renderSiftFound(result2));
2849
+ return ok(json ? aliasJson("ask", "context.assemble", result) : renderSiftFound(result));
2588
2850
  }
2589
2851
  async function simpleSearch(executor, rest, json) {
2590
2852
  if (executor === void 0) {
@@ -2592,11 +2854,11 @@ async function simpleSearch(executor, rest, json) {
2592
2854
  }
2593
2855
  const parsed = parseOptions(rest);
2594
2856
  const query = argsWithoutOptions(rest).join(" ").trim();
2595
- const result2 = await executor.execute("search.query", {
2857
+ const result = await executor.execute("search.query", {
2596
2858
  query,
2597
2859
  limit: parseIntegerOption(parsed, "limit", 10)
2598
2860
  });
2599
- return ok(json ? aliasJson("search", "search.query", result2) : renderSearchResult(result2));
2861
+ return ok(json ? aliasJson("search", "search.query", result) : renderSearchResult(result));
2600
2862
  }
2601
2863
  async function remember(executor, rest, json, readStdin2, now) {
2602
2864
  if (executor === void 0) {
@@ -2615,8 +2877,8 @@ async function remember(executor, rest, json, readStdin2, now) {
2615
2877
  visibility: [optionalOption(parsed, "visibility") ?? DEFAULT_CLI_VISIBILITY],
2616
2878
  markdown
2617
2879
  };
2618
- const result2 = await executor.execute("capture.text", input);
2619
- return ok(json ? aliasJson("remember", "capture.text", result2) : renderWriteReceipt("Remember", result2));
2880
+ const result = await executor.execute("capture.text", input);
2881
+ return ok(json ? aliasJson("remember", "capture.text", result) : renderWriteReceipt("Remember", result));
2620
2882
  }
2621
2883
  async function addFile(executor, fileReader, rest, json) {
2622
2884
  if (executor === void 0) {
@@ -2638,8 +2900,8 @@ async function addFile(executor, fileReader, rest, json) {
2638
2900
  bytes,
2639
2901
  visibility: [optionalOption(parsed, "visibility") ?? DEFAULT_CLI_VISIBILITY]
2640
2902
  };
2641
- const result2 = await executor.execute("capture.file", input);
2642
- return ok(json ? aliasJson("add", "capture.file", result2) : renderWriteReceipt("Add", result2));
2903
+ const result = await executor.execute("capture.file", input);
2904
+ return ok(json ? aliasJson("add", "capture.file", result) : renderWriteReceipt("Add", result));
2643
2905
  }
2644
2906
  async function edit(executor, rest, json) {
2645
2907
  if (executor === void 0) {
@@ -2664,8 +2926,8 @@ async function edit(executor, rest, json) {
2664
2926
  if (expectedMarkdown !== void 0) {
2665
2927
  input.expectedMarkdown = expectedMarkdown;
2666
2928
  }
2667
- const result2 = await executor.execute("record.patch_section", input);
2668
- return ok(json ? aliasJson("edit", "record.patch_section", result2) : renderWriteReceipt("Edit", result2));
2929
+ const result = await executor.execute("record.patch_section", input);
2930
+ return ok(json ? aliasJson("edit", "record.patch_section", result) : renderWriteReceipt("Edit", result));
2669
2931
  }
2670
2932
  async function decide(executor, rest, json) {
2671
2933
  if (executor === void 0) {
@@ -2678,8 +2940,8 @@ async function decide(executor, rest, json) {
2678
2940
  visibility: [optionalOption(parsed, "visibility") ?? DEFAULT_CLI_VISIBILITY]
2679
2941
  };
2680
2942
  addOptionalWorkAliasMetadata(input, parsed);
2681
- const result2 = await executor.execute("decision.create", input);
2682
- return ok(json ? aliasJson("decide", "decision.create", result2) : renderWriteReceipt("Decision", result2));
2943
+ const result = await executor.execute("decision.create", input);
2944
+ return ok(json ? aliasJson("decide", "decision.create", result) : renderWriteReceipt("Decision", result));
2683
2945
  }
2684
2946
  async function todo(executor, rest, json) {
2685
2947
  if (executor === void 0) {
@@ -2696,8 +2958,8 @@ async function todo(executor, rest, json) {
2696
2958
  const dueDate = optionalOption(parsed, "due-date");
2697
2959
  if (dueDate !== void 0) input.dueDate = dueDate;
2698
2960
  addOptionalWorkAliasMetadata(input, parsed);
2699
- const result2 = await executor.execute("task.create", input);
2700
- return ok(json ? aliasJson("todo", "task.create", result2) : renderWriteReceipt("Task", result2));
2961
+ const result = await executor.execute("task.create", input);
2962
+ return ok(json ? aliasJson("todo", "task.create", result) : renderWriteReceipt("Task", result));
2701
2963
  }
2702
2964
  async function show(executor, rest, json) {
2703
2965
  if (executor === void 0) {
@@ -2720,21 +2982,21 @@ async function show(executor, rest, json) {
2720
2982
  if (sectionAnchor !== void 0) {
2721
2983
  input.sectionAnchor = sectionAnchor;
2722
2984
  }
2723
- const result2 = await executor.execute("record.get", input);
2724
- return ok(json ? aliasJson("show", "record.get", result2) : renderRecordResult(result2));
2985
+ const result = await executor.execute("record.get", input);
2986
+ return ok(json ? aliasJson("show", "record.get", result) : renderRecordResult(result));
2725
2987
  }
2726
- async function status(config2, executor, json) {
2988
+ async function status(config, executor, json) {
2727
2989
  const scope = {
2728
- apiBaseUrl: config2.apiBaseUrl,
2729
- principalId: config2.principalId,
2730
- workspaceId: config2.workspaceId,
2731
- brainId: config2.brainId,
2732
- capabilities: [...config2.capabilities]
2990
+ apiBaseUrl: config.apiBaseUrl,
2991
+ principalId: config.principalId,
2992
+ workspaceId: config.workspaceId,
2993
+ brainId: config.brainId,
2994
+ capabilities: [...config.capabilities]
2733
2995
  };
2734
2996
  const api = await apiReachability(executor);
2735
- const result2 = { scope, api };
2997
+ const result = { scope, api };
2736
2998
  if (json) {
2737
- return ok(`${JSON.stringify({ command: "status", result: result2 })}
2999
+ return ok(`${JSON.stringify({ command: "status", result })}
2738
3000
  `);
2739
3001
  }
2740
3002
  return ok(`${renderScope({ ...scope, tokenLabel: "configured" })}API reachable: ${api.reachable}
@@ -3005,9 +3267,9 @@ function toolsHelp(input) {
3005
3267
  return executeSimple(input.executor, "tools.help", { name }, input.json);
3006
3268
  }
3007
3269
  async function executeSimple(executor, name, toolInput, json) {
3008
- const result2 = await executor.execute(name, toolInput);
3009
- return ok(json ? `${JSON.stringify(result2)}
3010
- ` : `${JSON.stringify(result2)}
3270
+ const result = await executor.execute(name, toolInput);
3271
+ return ok(json ? `${JSON.stringify(result)}
3272
+ ` : `${JSON.stringify(result)}
3011
3273
  `);
3012
3274
  }
3013
3275
 
@@ -3028,7 +3290,7 @@ function createHostedApiExecutor(input) {
3028
3290
  body: JSON.stringify({ input: toolInput }, serializeJsonValue)
3029
3291
  });
3030
3292
  const body = await response.text();
3031
- const parsed = body.length > 0 ? parseJson(body) : {};
3293
+ const parsed = body.length > 0 ? parseJson2(body) : {};
3032
3294
  if (!response.ok) {
3033
3295
  throw new Error(errorMessage(parsed, response.status));
3034
3296
  }
@@ -3045,7 +3307,7 @@ function serializeJsonValue(_key, value) {
3045
3307
  function toolUrl(apiBaseUrl, name) {
3046
3308
  return `${apiBaseUrl.replace(/\/+$/u, "")}/agent-tools/${encodeURIComponent(name)}`;
3047
3309
  }
3048
- function parseJson(body) {
3310
+ function parseJson2(body) {
3049
3311
  try {
3050
3312
  return JSON.parse(body);
3051
3313
  } catch {
@@ -3148,7 +3410,19 @@ async function runSiftCli(rawInput) {
3148
3410
  "task:create": () => createTask(input.executor, rest, json),
3149
3411
  "agent:register": () => agentRegister(input.executor, input.agentName, rest, json),
3150
3412
  "agent:status": () => executeSimple2(input.executor, "agent.status", {}, json),
3151
- "mcp:serve": () => mcpServe(input.mcpServer, input.config, rawInput.executor, json),
3413
+ "mcp:serve": () => mcpServe({
3414
+ mcpServer: input.mcpServer,
3415
+ config: input.config,
3416
+ executor: rawInput.executor
3417
+ }),
3418
+ "roam:import": () => runRoamImportCommand({
3419
+ rest,
3420
+ json,
3421
+ config: input.config,
3422
+ reader: input.roamReader,
3423
+ importer: input.roamImporter,
3424
+ now: input.now ?? /* @__PURE__ */ new Date()
3425
+ }),
3152
3426
  "login:": () => authCommand(input.authCommands, "login", { rest: commandRest, json }),
3153
3427
  "auth:status": () => authCommand(input.authCommands, "status", { json }),
3154
3428
  "logout:": () => authCommand(input.authCommands, "logout", { json })
@@ -3172,39 +3446,14 @@ async function runSiftCli(rawInput) {
3172
3446
  return errorResult(error, json);
3173
3447
  }
3174
3448
  }
3175
- async function mcpServe(mcpServer, config2, executor, _json) {
3176
- if (mcpServer === void 0) {
3177
- return fail("No local MCP server is configured for mcp.serve.");
3178
- }
3179
- if (executor === void 0) {
3180
- return fail("Not signed in. Run 'sift login', then 'sift mcp serve'.");
3181
- }
3182
- const result2 = await mcpServer.serve({ config: config2, executor, transport: "local_mcp" });
3183
- if (result2 === void 0) return ok("");
3184
- return ok(`${JSON.stringify(result2)}
3185
- `);
3186
- }
3187
- function scopeCurrent(config2, json) {
3188
- const scope = {
3189
- apiBaseUrl: config2.apiBaseUrl,
3190
- tokenLabel: config2.tokenLabel,
3191
- tokenExpiresAt: config2.tokenExpiresAt,
3192
- principalId: config2.principalId,
3193
- workspaceId: config2.workspaceId,
3194
- brainId: config2.brainId,
3195
- capabilities: config2.capabilities
3196
- };
3197
- return ok(json ? `${JSON.stringify(scope)}
3198
- ` : renderScope(scope));
3199
- }
3200
3449
  async function searchQuery(executor, rest, json) {
3201
3450
  if (executor === void 0) {
3202
3451
  return fail("No Sift API executor is configured for search.query.");
3203
3452
  }
3204
3453
  const query = rest.join(" ").trim();
3205
- const result2 = await executor.execute("search.query", { query, limit: 10 });
3206
- return ok(json ? `${JSON.stringify(result2)}
3207
- ` : renderSearchResult(result2));
3454
+ const result = await executor.execute("search.query", { query, limit: 10 });
3455
+ return ok(json ? `${JSON.stringify(result)}
3456
+ ` : renderSearchResult(result));
3208
3457
  }
3209
3458
  async function contextAssemble(executor, rest, json) {
3210
3459
  if (executor === void 0) {
@@ -3212,12 +3461,12 @@ async function contextAssemble(executor, rest, json) {
3212
3461
  }
3213
3462
  const parsed = parseOptions(rest);
3214
3463
  const query = positionalArgs(rest).join(" ").trim();
3215
- const result2 = await executor.execute("context.assemble", {
3464
+ const result = await executor.execute("context.assemble", {
3216
3465
  query,
3217
3466
  maxChars: parseIntegerOption(parsed, "max-chars", 4e3)
3218
3467
  });
3219
- return ok(json ? `${JSON.stringify(result2)}
3220
- ` : renderSearchResult(result2));
3468
+ return ok(json ? `${JSON.stringify(result)}
3469
+ ` : renderSearchResult(result));
3221
3470
  }
3222
3471
  async function contextProfile(executor, rest, json) {
3223
3472
  if (executor === void 0) {
@@ -3231,17 +3480,17 @@ async function contextProfile(executor, rest, json) {
3231
3480
  if (query.length > 0) {
3232
3481
  input.query = query;
3233
3482
  }
3234
- const result2 = await executor.execute("context.profile", input);
3235
- return ok(json ? `${JSON.stringify(result2)}
3236
- ` : renderProfileResult(result2));
3483
+ const result = await executor.execute("context.profile", input);
3484
+ return ok(json ? `${JSON.stringify(result)}
3485
+ ` : renderProfileResult(result));
3237
3486
  }
3238
3487
  async function executeSimple2(executor, name, toolInput, json) {
3239
3488
  if (executor === void 0) {
3240
3489
  return fail(`No Sift API executor is configured for ${name}.`);
3241
3490
  }
3242
- const result2 = await executor.execute(name, toolInput);
3243
- return ok(json ? `${JSON.stringify(result2)}
3244
- ` : `${JSON.stringify(result2)}
3491
+ const result = await executor.execute(name, toolInput);
3492
+ return ok(json ? `${JSON.stringify(result)}
3493
+ ` : `${JSON.stringify(result)}
3245
3494
  `);
3246
3495
  }
3247
3496
  async function captureText(executor, rest, json) {
@@ -3249,15 +3498,15 @@ async function captureText(executor, rest, json) {
3249
3498
  return fail("No Sift API executor is configured for capture.text.");
3250
3499
  }
3251
3500
  const parsed = parseOptions(rest);
3252
- const result2 = await executor.execute("capture.text", {
3501
+ const result = await executor.execute("capture.text", {
3253
3502
  sourceName: requireOption(parsed, "source"),
3254
3503
  externalId: requireOption(parsed, "external-id"),
3255
3504
  title: requireOption(parsed, "title"),
3256
3505
  visibility: [requireOption(parsed, "visibility")],
3257
3506
  markdown: requireOption(parsed, "markdown")
3258
3507
  });
3259
- return ok(json ? `${JSON.stringify(result2)}
3260
- ` : `${JSON.stringify(result2)}
3508
+ return ok(json ? `${JSON.stringify(result)}
3509
+ ` : `${JSON.stringify(result)}
3261
3510
  `);
3262
3511
  }
3263
3512
  async function captureFile(executor, fileReader, rest, json) {
@@ -3270,7 +3519,7 @@ async function captureFile(executor, fileReader, rest, json) {
3270
3519
  }
3271
3520
  const parsed = parseOptions(optionArgs);
3272
3521
  const bytes = await fileReader(path);
3273
- const result2 = await executor.execute("capture.file", {
3522
+ const result = await executor.execute("capture.file", {
3274
3523
  sourceName: requireOption(parsed, "source"),
3275
3524
  externalId: requireOption(parsed, "external-id"),
3276
3525
  title: requireOption(parsed, "title"),
@@ -3279,8 +3528,8 @@ async function captureFile(executor, fileReader, rest, json) {
3279
3528
  bytes,
3280
3529
  visibility: [requireOption(parsed, "visibility")]
3281
3530
  });
3282
- return ok(json ? `${JSON.stringify(result2)}
3283
- ` : `${JSON.stringify(result2)}
3531
+ return ok(json ? `${JSON.stringify(result)}
3532
+ ` : `${JSON.stringify(result)}
3284
3533
  `);
3285
3534
  }
3286
3535
  async function captureBatch(executor, fileReader, rest, json) {
@@ -3292,9 +3541,9 @@ async function captureBatch(executor, fileReader, rest, json) {
3292
3541
  return fail("Missing required manifest path for capture.batch.");
3293
3542
  }
3294
3543
  const manifest = parseBatchManifest(await fileReader(manifestPath));
3295
- const result2 = await executor.execute("capture.batch", { items: manifest });
3296
- return ok(json ? `${JSON.stringify(result2)}
3297
- ` : `${JSON.stringify(result2)}
3544
+ const result = await executor.execute("capture.batch", { items: manifest });
3545
+ return ok(json ? `${JSON.stringify(result)}
3546
+ ` : `${JSON.stringify(result)}
3298
3547
  `);
3299
3548
  }
3300
3549
  function parseBatchManifest(bytes) {
@@ -3319,18 +3568,18 @@ async function createDecision(executor, rest, json) {
3319
3568
  input.rationale = rationale;
3320
3569
  }
3321
3570
  addOptionalWorkMetadata(input, parsed);
3322
- const result2 = await executor.execute("decision.create", input);
3323
- return ok(json ? `${JSON.stringify(result2)}
3324
- ` : `${JSON.stringify(result2)}
3571
+ const result = await executor.execute("decision.create", input);
3572
+ return ok(json ? `${JSON.stringify(result)}
3573
+ ` : `${JSON.stringify(result)}
3325
3574
  `);
3326
3575
  }
3327
3576
  async function sourceList(executor, json) {
3328
3577
  if (executor === void 0) {
3329
3578
  return fail("No Sift API executor is configured for source.list.");
3330
3579
  }
3331
- const result2 = await executor.execute("source.list", {});
3332
- return ok(json ? `${JSON.stringify(result2)}
3333
- ` : `${JSON.stringify(result2)}
3580
+ const result = await executor.execute("source.list", {});
3581
+ return ok(json ? `${JSON.stringify(result)}
3582
+ ` : `${JSON.stringify(result)}
3334
3583
  `);
3335
3584
  }
3336
3585
  async function sourceCreate(executor, rest, json) {
@@ -3338,12 +3587,12 @@ async function sourceCreate(executor, rest, json) {
3338
3587
  return fail("No Sift API executor is configured for source.create.");
3339
3588
  }
3340
3589
  const parsed = parseOptions(rest);
3341
- const result2 = await executor.execute("source.create", {
3590
+ const result = await executor.execute("source.create", {
3342
3591
  name: requireOption(parsed, "name"),
3343
3592
  visibility: [requireOption(parsed, "visibility")]
3344
3593
  });
3345
- return ok(json ? `${JSON.stringify(result2)}
3346
- ` : `${JSON.stringify(result2)}
3594
+ return ok(json ? `${JSON.stringify(result)}
3595
+ ` : `${JSON.stringify(result)}
3347
3596
  `);
3348
3597
  }
3349
3598
  async function sourceRead(executor, command, rest, json) {
@@ -3355,9 +3604,9 @@ async function sourceRead(executor, command, rest, json) {
3355
3604
  if (sourceId === void 0 || sourceId.trim().length === 0) {
3356
3605
  return fail(`Missing required source ID for ${toolName}.`);
3357
3606
  }
3358
- const result2 = await executor.execute(toolName, { sourceId });
3359
- return ok(json ? `${JSON.stringify(result2)}
3360
- ` : `${JSON.stringify(result2)}
3607
+ const result = await executor.execute(toolName, { sourceId });
3608
+ return ok(json ? `${JSON.stringify(result)}
3609
+ ` : `${JSON.stringify(result)}
3361
3610
  `);
3362
3611
  }
3363
3612
  async function ingestionStatus(executor, rest, json) {
@@ -3368,18 +3617,18 @@ async function ingestionStatus(executor, rest, json) {
3368
3617
  if (jobId === void 0 || jobId.trim().length === 0) {
3369
3618
  return fail("Missing required job ID for ingestion.status.");
3370
3619
  }
3371
- const result2 = await executor.execute("ingestion.status", { jobId });
3372
- return ok(json ? `${JSON.stringify(result2)}
3373
- ` : `${JSON.stringify(result2)}
3620
+ const result = await executor.execute("ingestion.status", { jobId });
3621
+ return ok(json ? `${JSON.stringify(result)}
3622
+ ` : `${JSON.stringify(result)}
3374
3623
  `);
3375
3624
  }
3376
3625
  async function recordList(executor, json) {
3377
3626
  if (executor === void 0) {
3378
3627
  return fail("No Sift API executor is configured for record.list.");
3379
3628
  }
3380
- const result2 = await executor.execute("record.list", {});
3381
- return ok(json ? `${JSON.stringify(result2)}
3382
- ` : `${JSON.stringify(result2)}
3629
+ const result = await executor.execute("record.list", {});
3630
+ return ok(json ? `${JSON.stringify(result)}
3631
+ ` : `${JSON.stringify(result)}
3383
3632
  `);
3384
3633
  }
3385
3634
  async function recordRead(executor, toolName, rest, json) {
@@ -3397,23 +3646,23 @@ async function recordRead(executor, toolName, rest, json) {
3397
3646
  input.sectionAnchor = sectionAnchor;
3398
3647
  }
3399
3648
  }
3400
- const result2 = await executor.execute(toolName, input);
3401
- return ok(json ? `${JSON.stringify(result2)}
3402
- ` : renderRecordResult(result2));
3649
+ const result = await executor.execute(toolName, input);
3650
+ return ok(json ? `${JSON.stringify(result)}
3651
+ ` : renderRecordResult(result));
3403
3652
  }
3404
3653
  async function createMarkdownRecord(executor, rest, json) {
3405
3654
  if (executor === void 0) {
3406
3655
  return fail("No Sift API executor is configured for record.create_markdown.");
3407
3656
  }
3408
3657
  const parsed = parseOptions(rest);
3409
- const result2 = await executor.execute("record.create_markdown", {
3658
+ const result = await executor.execute("record.create_markdown", {
3410
3659
  recordType: requireOption(parsed, "type"),
3411
3660
  title: requireOption(parsed, "title"),
3412
3661
  markdown: requireOption(parsed, "markdown"),
3413
3662
  visibility: [requireOption(parsed, "visibility")]
3414
3663
  });
3415
- return ok(json ? `${JSON.stringify(result2)}
3416
- ` : `${JSON.stringify(result2)}
3664
+ return ok(json ? `${JSON.stringify(result)}
3665
+ ` : `${JSON.stringify(result)}
3417
3666
  `);
3418
3667
  }
3419
3668
  async function patchRecordSection(executor, rest, json) {
@@ -3437,9 +3686,9 @@ async function patchRecordSection(executor, rest, json) {
3437
3686
  if (expectedMarkdown !== void 0) {
3438
3687
  input.expectedMarkdown = expectedMarkdown;
3439
3688
  }
3440
- const result2 = await executor.execute("record.patch_section", input);
3441
- return ok(json ? `${JSON.stringify(result2)}
3442
- ` : `${JSON.stringify(result2)}
3689
+ const result = await executor.execute("record.patch_section", input);
3690
+ return ok(json ? `${JSON.stringify(result)}
3691
+ ` : `${JSON.stringify(result)}
3443
3692
  `);
3444
3693
  }
3445
3694
  async function createTask(executor, rest, json) {
@@ -3468,9 +3717,9 @@ async function createTask(executor, rest, json) {
3468
3717
  input.rationale = rationale;
3469
3718
  }
3470
3719
  addOptionalWorkMetadata(input, parsed);
3471
- const result2 = await executor.execute("task.create", input);
3472
- return ok(json ? `${JSON.stringify(result2)}
3473
- ` : `${JSON.stringify(result2)}
3720
+ const result = await executor.execute("task.create", input);
3721
+ return ok(json ? `${JSON.stringify(result)}
3722
+ ` : `${JSON.stringify(result)}
3474
3723
  `);
3475
3724
  }
3476
3725
  async function auditEvents(executor, rest, json) {
@@ -3482,9 +3731,9 @@ async function auditEvents(executor, rest, json) {
3482
3731
  if (targetId !== void 0 && targetId.trim().length > 0) {
3483
3732
  input.targetId = targetId;
3484
3733
  }
3485
- const result2 = await executor.execute("audit.events", input);
3486
- return ok(json ? `${JSON.stringify(result2)}
3487
- ` : `${JSON.stringify(result2)}
3734
+ const result = await executor.execute("audit.events", input);
3735
+ return ok(json ? `${JSON.stringify(result)}
3736
+ ` : `${JSON.stringify(result)}
3488
3737
  `);
3489
3738
  }
3490
3739
  async function idTool(input) {
@@ -3495,9 +3744,9 @@ async function idTool(input) {
3495
3744
  if (id === void 0 || id.trim().length === 0) {
3496
3745
  return fail(`Missing required ${input.idLabel} for ${input.toolName}.`);
3497
3746
  }
3498
- const result2 = await input.executor.execute(input.toolName, { [input.inputKey]: id });
3499
- return ok(input.json ? `${JSON.stringify(result2)}
3500
- ` : `${JSON.stringify(result2)}
3747
+ const result = await input.executor.execute(input.toolName, { [input.inputKey]: id });
3748
+ return ok(input.json ? `${JSON.stringify(result)}
3749
+ ` : `${JSON.stringify(result)}
3501
3750
  `);
3502
3751
  }
3503
3752
 
@@ -3523,10 +3772,10 @@ async function readStoredSiftConfig(input) {
3523
3772
  return parseStoredSiftConfig(JSON.parse(raw));
3524
3773
  }
3525
3774
  async function writeStoredSiftConfig(input) {
3526
- const config2 = parseStoredSiftConfig(input.config);
3775
+ const config = parseStoredSiftConfig(input.config);
3527
3776
  const path = resolveSiftConfigPath(input);
3528
3777
  await mkdir(dirname(path), { recursive: true, mode: 448 });
3529
- await writeFile(path, `${JSON.stringify(config2, null, 2)}
3778
+ await writeFile(path, `${JSON.stringify(config, null, 2)}
3530
3779
  `, { mode: 384 });
3531
3780
  await chmod(path, 384);
3532
3781
  }
@@ -3747,14 +3996,14 @@ function createMacOSKeychainStore(input = {}) {
3747
3996
  return {
3748
3997
  async assertAvailable() {
3749
3998
  await requireSupported();
3750
- const result2 = await runCommand(securityPath, ["list-keychains"]);
3751
- if (result2.exitCode !== 0) {
3999
+ const result = await runCommand(securityPath, ["list-keychains"]);
4000
+ if (result.exitCode !== 0) {
3752
4001
  throw new UnsupportedCredentialStoreError();
3753
4002
  }
3754
4003
  },
3755
4004
  async read(readInput) {
3756
4005
  await requireSupported();
3757
- const result2 = await runCommand(securityPath, [
4006
+ const result = await runCommand(securityPath, [
3758
4007
  "find-generic-password",
3759
4008
  "-s",
3760
4009
  serviceName,
@@ -3762,15 +4011,15 @@ function createMacOSKeychainStore(input = {}) {
3762
4011
  account(readInput),
3763
4012
  "-w"
3764
4013
  ]);
3765
- if (result2.exitCode !== 0) {
4014
+ if (result.exitCode !== 0) {
3766
4015
  return void 0;
3767
4016
  }
3768
- const secret = result2.stdout.trim();
4017
+ const secret = result.stdout.trim();
3769
4018
  return secret.length === 0 ? void 0 : secret;
3770
4019
  },
3771
4020
  async write(writeInput) {
3772
4021
  await requireSupported();
3773
- const result2 = await runCommand(securityPath, [
4022
+ const result = await runCommand(securityPath, [
3774
4023
  "add-generic-password",
3775
4024
  "-U",
3776
4025
  "-s",
@@ -3780,7 +4029,7 @@ function createMacOSKeychainStore(input = {}) {
3780
4029
  "-w",
3781
4030
  writeInput.secret
3782
4031
  ]);
3783
- if (result2.exitCode !== 0) {
4032
+ if (result.exitCode !== 0) {
3784
4033
  throw new Error("Failed to write Sift CLI token secret to macOS Keychain.");
3785
4034
  }
3786
4035
  },
@@ -3798,8 +4047,8 @@ function createMacOSKeychainStore(input = {}) {
3798
4047
  }
3799
4048
  async function runSecurityCommand(file, args) {
3800
4049
  try {
3801
- const result2 = await execFileAsync(file, args);
3802
- return { stdout: result2.stdout, stderr: result2.stderr, exitCode: 0 };
4050
+ const result = await execFileAsync(file, args);
4051
+ return { stdout: result.stdout, stderr: result.stderr, exitCode: 0 };
3803
4052
  } catch (error) {
3804
4053
  if (isExecError(error)) {
3805
4054
  return {
@@ -3824,6 +4073,7 @@ import { hostname as hostname3 } from "os";
3824
4073
  import { promisify as promisify2 } from "util";
3825
4074
 
3826
4075
  // src/auth/loginHelpers.ts
4076
+ var DEFAULT_SIFT_API_BASE_URL = "https://sift-wiki-api.fly.dev";
3827
4077
  async function resolveLoginApiBaseUrl(input) {
3828
4078
  const options = parseOptions(input.argv);
3829
4079
  const fromFlag = clean2(options.get("api-base-url"));
@@ -3833,7 +4083,7 @@ async function resolveLoginApiBaseUrl(input) {
3833
4083
  const stored = await readStoredSiftConfig({ homeDir: input.homeDir });
3834
4084
  const profile = stored?.profiles[stored.currentProfile];
3835
4085
  if (profile !== void 0) return normalizeUrl(profile.apiBaseUrl);
3836
- return "https://api.sift.com";
4086
+ return DEFAULT_SIFT_API_BASE_URL;
3837
4087
  }
3838
4088
  function requestedCapabilities(rest) {
3839
4089
  const option = parseOptions(rest).get("capability");
@@ -3874,15 +4124,15 @@ function resolveCliOAuthConfig(input) {
3874
4124
  return void 0;
3875
4125
  }
3876
4126
  const registrationUrl = clean3(options.get("oauth-registration-url")) ?? clean3(input.env.SIFT_OAUTH_REGISTRATION_URL);
3877
- const config2 = { authorizeUrl, tokenUrl, clientId };
4127
+ const config = { authorizeUrl, tokenUrl, clientId };
3878
4128
  if (registrationUrl !== void 0) {
3879
- config2.registrationUrl = registrationUrl;
4129
+ config.registrationUrl = registrationUrl;
3880
4130
  }
3881
4131
  const scopes = parseScopeList(clean3(options.get("oauth-scopes")) ?? clean3(input.env.SIFT_OAUTH_SCOPES));
3882
4132
  if (scopes.length > 0) {
3883
- config2.defaultScopes = scopes;
4133
+ config.defaultScopes = scopes;
3884
4134
  }
3885
- return config2;
4135
+ return config;
3886
4136
  }
3887
4137
  function scopesForCapabilities(capabilities) {
3888
4138
  const scopes = /* @__PURE__ */ new Set(["read"]);
@@ -4057,11 +4307,11 @@ async function finalizeOAuthLogin(input, tokens) {
4057
4307
  tokenKind: "oauth",
4058
4308
  refreshable: tokens.refreshToken !== void 0
4059
4309
  };
4060
- const result2 = { profile, accessToken: tokens.accessToken };
4310
+ const result = { profile, accessToken: tokens.accessToken };
4061
4311
  if (tokens.refreshToken !== void 0) {
4062
- result2.refreshToken = tokens.refreshToken;
4312
+ result.refreshToken = tokens.refreshToken;
4063
4313
  }
4064
- return result2;
4314
+ return result;
4065
4315
  }
4066
4316
  function buildAuthorizeUrl(input) {
4067
4317
  const url = new URL(input.oauth.authorizeUrl);
@@ -4294,7 +4544,7 @@ function oauthRefresherFor(input, rest) {
4294
4544
  async function oauthBrowserLoginFlow(input, rest, json) {
4295
4545
  const apiBaseUrl = await resolveLoginApiBaseUrl({ argv: rest, env: input.env, homeDir: input.homeDir });
4296
4546
  const oauth = resolveOAuthConfigOrThrow(input, rest);
4297
- const result2 = await oauthBrowserLogin({
4547
+ const result = await oauthBrowserLogin({
4298
4548
  apiBaseUrl,
4299
4549
  appBaseUrl: resolveAppBaseUrl(input.env, apiBaseUrl),
4300
4550
  oauth,
@@ -4309,16 +4559,16 @@ async function oauthBrowserLoginFlow(input, rest, json) {
4309
4559
  return persistConvergedLogin(
4310
4560
  input,
4311
4561
  {
4312
- profile: result2.profile,
4313
- accessToken: result2.accessToken,
4314
- ...result2.refreshToken === void 0 ? {} : { refreshToken: result2.refreshToken }
4562
+ profile: result.profile,
4563
+ accessToken: result.accessToken,
4564
+ ...result.refreshToken === void 0 ? {} : { refreshToken: result.refreshToken }
4315
4565
  },
4316
4566
  json
4317
4567
  );
4318
4568
  }
4319
4569
  async function serviceTokenLoginFlow(input, rest, json) {
4320
4570
  const apiBaseUrl = await resolveLoginApiBaseUrl({ argv: rest, env: input.env, homeDir: input.homeDir });
4321
- const result2 = await serviceTokenLogin({
4571
+ const result = await serviceTokenLogin({
4322
4572
  apiBaseUrl,
4323
4573
  appBaseUrl: resolveAppBaseUrl(input.env, apiBaseUrl),
4324
4574
  rest,
@@ -4327,7 +4577,7 @@ async function serviceTokenLoginFlow(input, rest, json) {
4327
4577
  credentialStore: input.credentialStore,
4328
4578
  resolveCallerBearer: defaultCallerBearerResolver(input)
4329
4579
  });
4330
- return persistConvergedLogin(input, { profile: result2.profile, accessToken: result2.token }, json);
4580
+ return persistConvergedLogin(input, { profile: result.profile, accessToken: result.token }, json);
4331
4581
  }
4332
4582
  function resolveOAuthConfigOrThrow(input, rest) {
4333
4583
  const oauth = input.oauthConfig ?? resolveCliOAuthConfig({ argv: rest, env: input.env });
@@ -4388,19 +4638,19 @@ function resolveAppBaseUrl(env, apiBaseUrl) {
4388
4638
  if (fromEnv !== void 0) return normalizeUrl(fromEnv);
4389
4639
  return apiBaseUrl.replace(/\/\/api\./u, "//");
4390
4640
  }
4391
- async function persistConvergedLogin(input, result2, json) {
4392
- const { profile } = result2;
4641
+ async function persistConvergedLogin(input, result, json) {
4642
+ const { profile } = result;
4393
4643
  try {
4394
4644
  await input.credentialStore.write({
4395
4645
  apiBaseUrl: profile.apiBaseUrl,
4396
4646
  tokenId: profile.tokenId,
4397
- secret: result2.accessToken
4647
+ secret: result.accessToken
4398
4648
  });
4399
- if (result2.refreshToken !== void 0) {
4649
+ if (result.refreshToken !== void 0) {
4400
4650
  await input.credentialStore.write({
4401
4651
  apiBaseUrl: profile.apiBaseUrl,
4402
4652
  tokenId: refreshSlotTokenId(profile.tokenId),
4403
- secret: result2.refreshToken
4653
+ secret: result.refreshToken
4404
4654
  });
4405
4655
  }
4406
4656
  } catch (error) {
@@ -4510,9 +4760,9 @@ async function deviceLogin(input, rest, sleep, json) {
4510
4760
  { requestId: request.requestId, userCode: request.userCode }
4511
4761
  );
4512
4762
  if ("token" in token) {
4513
- const result2 = await persistLogin(input, token, json);
4514
- return result2.exitCode === 0 ? { ...result2, stdout: `Code: ${request.userCode}
4515
- ${result2.stdout}` } : result2;
4763
+ const result = await persistLogin(input, token, json);
4764
+ return result.exitCode === 0 ? { ...result, stdout: `Code: ${request.userCode}
4765
+ ${result.stdout}` } : result;
4516
4766
  }
4517
4767
  if (token.status === "authorization_pending" || token.status === "slow_down") {
4518
4768
  intervalSeconds = token.intervalSeconds;
@@ -4536,8 +4786,8 @@ async function persistLogin(input, token, json) {
4536
4786
  `Sift CLI login storage failure: ${error instanceof Error ? error.message : "credential store write failed"}`
4537
4787
  );
4538
4788
  }
4539
- const config2 = configFromToken(token);
4540
- await writeStoredSiftConfig({ homeDir: input.homeDir, config: config2 });
4789
+ const config = configFromToken(token);
4790
+ await writeStoredSiftConfig({ homeDir: input.homeDir, config });
4541
4791
  if (oldProfile !== void 0) {
4542
4792
  const oldSecret = await input.credentialStore.read({
4543
4793
  apiBaseUrl: oldProfile.apiBaseUrl,
@@ -4576,6 +4826,33 @@ async function authStatus(input, now, json) {
4576
4826
  if (profile === void 0) {
4577
4827
  return ok(json ? '{"auth":"none"}\n' : "Auth: none\n");
4578
4828
  }
4829
+ const expired = Date.parse(profile.tokenExpiresAt) <= now.getTime();
4830
+ if (expired) {
4831
+ return staleStoredStatus(
4832
+ profile,
4833
+ "expired",
4834
+ "Stored Sift CLI auth has expired; run `sift login` again.",
4835
+ json
4836
+ );
4837
+ }
4838
+ let secret;
4839
+ try {
4840
+ secret = await input.credentialStore.read({
4841
+ apiBaseUrl: profile.apiBaseUrl,
4842
+ tokenId: profile.tokenId
4843
+ });
4844
+ } catch (error) {
4845
+ const message = error instanceof Error ? error.message : "Stored Sift credential store could not be read; run `sift login` again.";
4846
+ return staleStoredStatus(profile, "credential_store_unavailable", message, json);
4847
+ }
4848
+ if (secret === void 0) {
4849
+ return staleStoredStatus(
4850
+ profile,
4851
+ "credential_missing",
4852
+ "Stored Sift credential store secret is missing; run `sift login` again.",
4853
+ json
4854
+ );
4855
+ }
4579
4856
  return ok(
4580
4857
  json ? `${JSON.stringify({ auth: "stored", ...profile })}
4581
4858
  ` : [
@@ -4590,6 +4867,24 @@ async function authStatus(input, now, json) {
4590
4867
  ].join("\n")
4591
4868
  );
4592
4869
  }
4870
+ function staleStoredStatus(profile, reason, message, json) {
4871
+ if (json) {
4872
+ return ok(
4873
+ `${JSON.stringify({ auth: "stored", status: "stale", reason, message, ...profile })}
4874
+ `
4875
+ );
4876
+ }
4877
+ return ok(
4878
+ [
4879
+ "Auth: stale",
4880
+ `Reason: ${reason}`,
4881
+ message,
4882
+ `API: ${profile.apiBaseUrl}`,
4883
+ `Token: ${profile.tokenLabel}`,
4884
+ ""
4885
+ ].join("\n")
4886
+ );
4887
+ }
4593
4888
  async function logout(input, now, json) {
4594
4889
  if (clean2(input.env.SIFT_API_TOKEN) !== void 0) {
4595
4890
  return ok(json ? '{"status":"env_auth_active"}\n' : "Auth: env\nUnset SIFT_API_TOKEN to log out.\n");
@@ -4681,6 +4976,244 @@ function failJson(message) {
4681
4976
  };
4682
4977
  }
4683
4978
 
4979
+ // src/roamMcpReader.ts
4980
+ import { spawn } from "child_process";
4981
+ function createRoamMcpReader(input = {}) {
4982
+ return {
4983
+ async exportPages(request) {
4984
+ const client = createRoamMcpJsonLineClient({
4985
+ command: input.command ?? "npx",
4986
+ args: input.args ?? ["-y", "@roam-research/roam-mcp"],
4987
+ spawnProcess: input.spawnProcess ?? spawn
4988
+ });
4989
+ try {
4990
+ return await exportRoamPagesFromMcp(client, request);
4991
+ } finally {
4992
+ await client.close();
4993
+ }
4994
+ }
4995
+ };
4996
+ }
4997
+ async function exportRoamPagesFromMcp(client, input) {
4998
+ const graphId = await resolveGraphId(client, input.graph);
4999
+ await client.callTool("get_graph_guidelines", graphArgs(graphId)).catch(() => void 0);
5000
+ const tuples = input.scope === "sift_tag" ? await queryMarkedPageTuples(client, graphId, input.limit) : await queryWholeGraphPageTuples(client, graphId, input.limit);
5001
+ const records = [];
5002
+ const seen = /* @__PURE__ */ new Set();
5003
+ for (const tuple of tuples) {
5004
+ const key = tuple.uid ?? tuple.title;
5005
+ if (seen.has(key)) continue;
5006
+ seen.add(key);
5007
+ const markdown = await fetchPageMarkdown(client, graphId, tuple);
5008
+ records.push({
5009
+ graphId,
5010
+ pageUid: tuple.uid ?? stableFallbackUid(tuple.title),
5011
+ pageTitle: tuple.title,
5012
+ markdown,
5013
+ scope: input.scope,
5014
+ blockCount: estimateBlockCount(markdown),
5015
+ importedAt: input.now.toISOString()
5016
+ });
5017
+ }
5018
+ return records;
5019
+ }
5020
+ async function resolveGraphId(client, graph) {
5021
+ if (graph !== void 0) return graph;
5022
+ const result = await client.callTool("list_graphs", {});
5023
+ const parsed = parseToolJson(result);
5024
+ const graphId = firstGraphId(parsed);
5025
+ if (graphId !== void 0) return graphId;
5026
+ const message = errorMessageFromParsedTool(parsed);
5027
+ if (message !== void 0) throw new Error(message);
5028
+ return "local-graph";
5029
+ }
5030
+ async function queryMarkedPageTuples(client, graphId, limit) {
5031
+ const result = await client.callTool("datalog_query", {
5032
+ ...graphArgs(graphId),
5033
+ query: '[:find ?title ?uid :where [?tag :node/title "Sift"] [?block :block/refs ?tag] [?block :block/page ?page] [?page :node/title ?title] [?page :block/uid ?uid]]'
5034
+ });
5035
+ return tuplesFromToolResult(result).slice(0, limit);
5036
+ }
5037
+ async function queryWholeGraphPageTuples(client, graphId, limit) {
5038
+ const result = await client.callTool("datalog_query", {
5039
+ ...graphArgs(graphId),
5040
+ query: "[:find ?title ?uid :where [?page :node/title ?title] [?page :block/uid ?uid]]"
5041
+ });
5042
+ return tuplesFromToolResult(result).slice(0, limit);
5043
+ }
5044
+ async function fetchPageMarkdown(client, graphId, tuple) {
5045
+ const result = await client.callTool("get_page", {
5046
+ ...graphArgs(graphId),
5047
+ ...tuple.uid === void 0 ? { title: tuple.title } : { uid: tuple.uid }
5048
+ });
5049
+ const text = toolText(result);
5050
+ const parsed = parseJsonIfPossible(text);
5051
+ const markdown = markdownFromParsed(parsed) ?? text;
5052
+ return stripRoamMetadataTags(markdown).trim();
5053
+ }
5054
+ function graphArgs(graphId) {
5055
+ return { graph: graphId };
5056
+ }
5057
+ function tuplesFromToolResult(result) {
5058
+ const parsed = parseToolJson(result);
5059
+ const values = candidateArrays(parsed);
5060
+ const tuples = [];
5061
+ for (const value of values) {
5062
+ if (Array.isArray(value) && typeof value[0] === "string") {
5063
+ tuples.push({ title: value[0], ...typeof value[1] === "string" ? { uid: value[1] } : {} });
5064
+ } else if (isRecord(value)) {
5065
+ const title = stringProperty(value, ["title", "pageTitle", "name"]);
5066
+ const uid = stringProperty(value, ["uid", "pageUid"]);
5067
+ if (title !== void 0) tuples.push({ title, ...uid === void 0 ? {} : { uid } });
5068
+ }
5069
+ }
5070
+ return tuples;
5071
+ }
5072
+ function parseToolJson(result) {
5073
+ const text = toolText(result);
5074
+ return parseJsonIfPossible(text);
5075
+ }
5076
+ function toolText(result) {
5077
+ if (isRecord(result) && Array.isArray(result.content)) {
5078
+ return result.content.flatMap((item) => isRecord(item) && typeof item.text === "string" ? [item.text] : []).join("\n").trim();
5079
+ }
5080
+ return typeof result === "string" ? result : JSON.stringify(result);
5081
+ }
5082
+ function parseJsonIfPossible(text) {
5083
+ try {
5084
+ return JSON.parse(text);
5085
+ } catch {
5086
+ return text;
5087
+ }
5088
+ }
5089
+ function candidateArrays(value) {
5090
+ if (Array.isArray(value)) return value;
5091
+ if (!isRecord(value)) return [];
5092
+ for (const key of ["results", "result", "data", "rows", "pages"]) {
5093
+ const candidate = value[key];
5094
+ if (Array.isArray(candidate)) return candidate;
5095
+ }
5096
+ return [];
5097
+ }
5098
+ function markdownFromParsed(value) {
5099
+ if (typeof value === "string") return value;
5100
+ if (!isRecord(value)) return void 0;
5101
+ return stringProperty(value, ["markdown", "content", "text"]);
5102
+ }
5103
+ function firstGraphId(value) {
5104
+ const graphs = isRecord(value) && Array.isArray(value.graphs) ? value.graphs : candidateArrays(value);
5105
+ for (const graph of graphs) {
5106
+ if (!isRecord(graph)) continue;
5107
+ const id = stringProperty(graph, ["nickname", "graph", "name", "id"]);
5108
+ if (id !== void 0) return id;
5109
+ }
5110
+ return void 0;
5111
+ }
5112
+ function errorMessageFromParsedTool(value) {
5113
+ if (!isRecord(value) || !isRecord(value.error)) return void 0;
5114
+ const message = value.error.message;
5115
+ return typeof message === "string" ? message : void 0;
5116
+ }
5117
+ function stringProperty(record, keys) {
5118
+ for (const key of keys) {
5119
+ const value = record[key];
5120
+ if (typeof value === "string" && value.trim().length > 0) return value;
5121
+ }
5122
+ return void 0;
5123
+ }
5124
+ function stripRoamMetadataTags(markdown) {
5125
+ return markdown.replace(/<roam\b[^>]*>/giu, "").replace(/<\/roam>/giu, "");
5126
+ }
5127
+ function estimateBlockCount(markdown) {
5128
+ const lines = markdown.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
5129
+ return Math.max(1, lines.length);
5130
+ }
5131
+ function stableFallbackUid(title) {
5132
+ return title.toLowerCase().replace(/[^a-z0-9]+/gu, "-").replace(/^-+|-+$/gu, "").slice(0, 80);
5133
+ }
5134
+ function isRecord(value) {
5135
+ return typeof value === "object" && value !== null && !Array.isArray(value);
5136
+ }
5137
+ function createRoamMcpJsonLineClient(input) {
5138
+ const child = input.spawnProcess(input.command, input.args, {
5139
+ stdio: ["pipe", "pipe", "pipe"]
5140
+ });
5141
+ child.stderr.resume();
5142
+ child.stdout.setEncoding("utf8");
5143
+ let nextId = 1;
5144
+ let buffer = "";
5145
+ const pending = /* @__PURE__ */ new Map();
5146
+ child.stdout.on("data", (chunk) => {
5147
+ buffer += chunk;
5148
+ let newline = buffer.indexOf("\n");
5149
+ while (newline >= 0) {
5150
+ const line = buffer.slice(0, newline).trim();
5151
+ buffer = buffer.slice(newline + 1);
5152
+ if (line.length > 0) handleJsonRpcLine(line, pending);
5153
+ newline = buffer.indexOf("\n");
5154
+ }
5155
+ });
5156
+ child.on("error", (error) => {
5157
+ for (const entry of pending.values()) entry.reject(error);
5158
+ pending.clear();
5159
+ });
5160
+ child.on("exit", () => {
5161
+ for (const entry of pending.values()) entry.reject(new Error("Roam MCP server exited."));
5162
+ pending.clear();
5163
+ });
5164
+ const request = (method, params) => {
5165
+ const id = nextId;
5166
+ nextId += 1;
5167
+ const promise = new Promise((resolve2, reject) => {
5168
+ pending.set(id, { resolve: resolve2, reject });
5169
+ });
5170
+ child.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", id, method, params })}
5171
+ `);
5172
+ return promise;
5173
+ };
5174
+ const initialized = request("initialize", {
5175
+ protocolVersion: "2025-11-25",
5176
+ capabilities: {},
5177
+ clientInfo: { name: "sift-roam-import", version: "0.1.0" }
5178
+ }).then(() => {
5179
+ child.stdin.write(
5180
+ `${JSON.stringify({ jsonrpc: "2.0", method: "notifications/initialized" })}
5181
+ `
5182
+ );
5183
+ });
5184
+ return {
5185
+ async callTool(name, args) {
5186
+ await initialized;
5187
+ return request("tools/call", { name, arguments: args });
5188
+ },
5189
+ async close() {
5190
+ child.stdin.end();
5191
+ child.kill("SIGTERM");
5192
+ }
5193
+ };
5194
+ }
5195
+ function handleJsonRpcLine(line, pending) {
5196
+ let parsed;
5197
+ try {
5198
+ parsed = JSON.parse(line);
5199
+ } catch {
5200
+ return;
5201
+ }
5202
+ if (typeof parsed.id !== "number") return;
5203
+ const entry = pending.get(parsed.id);
5204
+ if (entry === void 0) return;
5205
+ pending.delete(parsed.id);
5206
+ if (parsed.error !== void 0) {
5207
+ entry.reject(
5208
+ new Error(
5209
+ typeof parsed.error.message === "string" ? parsed.error.message : "Roam MCP error."
5210
+ )
5211
+ );
5212
+ return;
5213
+ }
5214
+ entry.resolve(parsed.result);
5215
+ }
5216
+
4684
5217
  // src/bin/sift.ts
4685
5218
  var credentialStore = createMacOSKeychainStore();
4686
5219
  var authCommands = createSiftCliAuthCommands({
@@ -4689,51 +5222,92 @@ var authCommands = createSiftCliAuthCommands({
4689
5222
  credentialStore,
4690
5223
  fetch
4691
5224
  });
4692
- var loadedAuth = await authCommands.loadAuth();
4693
- var config = loadedAuth?.config ?? {
4694
- apiBaseUrl: "",
4695
- tokenLabel: "unset",
4696
- workspaceId: "",
4697
- brainId: "",
4698
- principalId: "",
4699
- capabilities: []
4700
- };
4701
5225
  var { argv, agentName } = extractAgentName(process.argv.slice(2), process.env.SIFT_AGENT);
4702
- var result = await runSiftCli({
4703
- argv,
4704
- config,
4705
- readStdin,
4706
- agentName,
4707
- executor: loadedAuth === void 0 ? void 0 : createHostedApiExecutor({
4708
- apiBaseUrl: loadedAuth.config.apiBaseUrl,
4709
- token: loadedAuth.token,
4710
- workspaceId: loadedAuth.config.workspaceId,
4711
- brainId: loadedAuth.config.brainId,
4712
- agentName
4713
- }),
4714
- authCommands,
4715
- mcpServer: {
4716
- serve: async ({ config: config2, executor }) => {
4717
- if (executor === void 0) {
4718
- throw new Error(
4719
- "Not signed in. Run 'sift login' to authenticate, then 'sift mcp serve' to start the local MCP server."
4720
- );
5226
+ var startupAuth = await loadAuthForStartup(authCommands, argv);
5227
+ if (startupAuth.ok === false) {
5228
+ process.stderr.write(`${startupAuth.message}
5229
+ `);
5230
+ process.exitCode = 1;
5231
+ } else {
5232
+ const loadedAuth = startupAuth.loadedAuth;
5233
+ const config = loadedAuth?.config ?? {
5234
+ apiBaseUrl: "",
5235
+ tokenLabel: "unset",
5236
+ workspaceId: "",
5237
+ brainId: "",
5238
+ principalId: "",
5239
+ capabilities: []
5240
+ };
5241
+ const result = await runSiftCli({
5242
+ argv,
5243
+ config,
5244
+ readStdin,
5245
+ agentName,
5246
+ executor: loadedAuth === void 0 ? void 0 : createHostedApiExecutor({
5247
+ apiBaseUrl: loadedAuth.config.apiBaseUrl,
5248
+ token: loadedAuth.token,
5249
+ workspaceId: loadedAuth.config.workspaceId,
5250
+ brainId: loadedAuth.config.brainId,
5251
+ agentName
5252
+ }),
5253
+ roamReader: createRoamMcpReader(),
5254
+ roamImporter: loadedAuth === void 0 ? void 0 : createSiftRoamImportClient({
5255
+ apiBaseUrl: loadedAuth.config.apiBaseUrl,
5256
+ token: loadedAuth.token,
5257
+ workspaceId: loadedAuth.config.workspaceId
5258
+ }),
5259
+ authCommands,
5260
+ mcpServer: {
5261
+ serve: async ({ config: config2, executor }) => {
5262
+ if (executor === void 0) {
5263
+ throw new Error(
5264
+ "Not signed in. Run 'sift login' to authenticate, then 'sift mcp serve' to start the local MCP server."
5265
+ );
5266
+ }
5267
+ const { createLocalMcpStdioServer: createLocalMcpStdioServer2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
5268
+ return createLocalMcpStdioServer2({
5269
+ input: process.stdin,
5270
+ output: process.stdout,
5271
+ error: process.stderr
5272
+ }).serve({
5273
+ capabilities: config2.capabilities,
5274
+ executor
5275
+ });
4721
5276
  }
4722
- const { createLocalMcpStdioServer: createLocalMcpStdioServer2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
4723
- return createLocalMcpStdioServer2({
4724
- input: process.stdin,
4725
- output: process.stdout,
4726
- error: process.stderr
4727
- }).serve({
4728
- capabilities: config2.capabilities,
4729
- executor
4730
- });
4731
5277
  }
5278
+ });
5279
+ process.stdout.write(result.stdout);
5280
+ process.stderr.write(result.stderr);
5281
+ process.exitCode = result.exitCode;
5282
+ }
5283
+ async function loadAuthForStartup(commands, args) {
5284
+ try {
5285
+ const loadedAuth = await commands.loadAuth();
5286
+ if (loadedAuth === void 0 && !canRunWithoutLoadedAuth(args)) {
5287
+ return { ok: false, message: missingAuthMessage(args) };
5288
+ }
5289
+ return { ok: true, loadedAuth };
5290
+ } catch (error) {
5291
+ if (canRunWithoutLoadedAuth(args)) {
5292
+ return { ok: true, loadedAuth: void 0 };
5293
+ }
5294
+ return {
5295
+ ok: false,
5296
+ message: error instanceof Error ? error.message : "Failed to load Sift CLI auth."
5297
+ };
4732
5298
  }
4733
- });
4734
- process.stdout.write(result.stdout);
4735
- process.stderr.write(result.stderr);
4736
- process.exitCode = result.exitCode;
5299
+ }
5300
+ function missingAuthMessage(args) {
5301
+ const commandArgs = args.filter((arg) => arg !== "--json");
5302
+ const [group, command] = commandArgs;
5303
+ const capability = group === "roam" && command === "import" ? " --capability record:read,source:manage" : "";
5304
+ return `Not signed in. Run 'npx -y @sift-wiki/cli@latest login --api-base-url ${DEFAULT_SIFT_API_BASE_URL}${capability}', then retry this command.`;
5305
+ }
5306
+ function canRunWithoutLoadedAuth(args) {
5307
+ const commandArgs = args.filter((arg) => arg !== "--json");
5308
+ const [group, command] = commandArgs;
5309
+ return group === void 0 || group === "help" || group === "--help" || group === "doctor" || group === "skill" || group === "login" || group === "logout" || group === "auth" && command === "status";
5310
+ }
4737
5311
  function extractAgentName(args, envAgentName) {
4738
5312
  const flagIndex = args.indexOf("--as-agent");
4739
5313
  if (flagIndex !== -1 && args[flagIndex + 1] !== void 0) {