@sift-wiki/cli 0.1.1 → 0.1.3

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 +28 -16
  2. package/dist/bin/sift.js +357 -52
  3. package/package.json +11 -9
package/README.md CHANGED
@@ -1,30 +1,42 @@
1
1
  # Sift CLI
2
2
 
3
- The intended public install path is npm:
3
+ This repository is the public release mirror for `@sift-wiki/cli`.
4
+
5
+ The package installs the `sift` command:
4
6
 
5
7
  ```bash
6
8
  npm install -g @sift-wiki/cli
9
+ sift login
10
+ sift doctor
7
11
  ```
8
12
 
9
- Current release caveat: do not claim live `npm install -g @sift-wiki/cli` proof until
10
- npm trusted publishing is configured, a matching `cli-v<version>` tag has
11
- published the package, and a post-publish global install smoke has passed. Repo
12
- verification before that is:
13
+ For one-off use without a global install:
13
14
 
14
15
  ```bash
15
- pnpm --filter @sift-wiki/cli pack:verify
16
+ npx -y @sift-wiki/cli@latest auth status --json
17
+ npm exec --yes --package @sift-wiki/cli@latest -- sift auth status --json
16
18
  ```
17
19
 
18
- Then authenticate and check the installed command:
20
+ ## Release Shape
19
21
 
20
- ```bash
21
- sift login
22
- sift doctor
23
- sift ask "what changed this week?"
24
- ```
22
+ The private Sift monorepo builds the bundled CLI artifact. This public repo
23
+ contains only the files needed to publish the public npm package:
24
+
25
+ - `package.json`
26
+ - `README.md`
27
+ - `dist/bin/sift.js`
28
+ - `scripts/verify-release.mjs`
29
+ - `.github/workflows/publish-cli.yml`
30
+
31
+ The bundled `dist/bin/sift.js` is the same artifact npm users receive.
32
+
33
+ ## Maintainer Release
25
34
 
26
- The CLI is a hosted thin client. `sift login` is the normal setup path and opens
27
- the existing browser login flow.
35
+ 1. Update `package.json` and `dist/bin/sift.js`.
36
+ 2. Run `npm run verify`.
37
+ 3. Commit and push to `main`.
38
+ 4. Tag `cli-v<package-version>`.
39
+ 5. Push the tag.
28
40
 
29
- For repo-local install details, troubleshooting, and advanced CI/headless
30
- env-token auth, see `docs/cli/install.md`.
41
+ The tag workflow publishes through npm trusted publishing. It uses GitHub OIDC
42
+ and does not require an npm token secret.
package/dist/bin/sift.js CHANGED
@@ -9,6 +9,75 @@ var __export = (target, all) => {
9
9
  __defProp(target, name, { get: all[name], enumerable: true });
10
10
  };
11
11
 
12
+ // ../tools/dist/gating.js
13
+ function isGatedTool(name) {
14
+ return !ungatedToolNames.has(name);
15
+ }
16
+ var UNGATED_TOOL_NAMES, ungatedToolNames;
17
+ var init_gating = __esm({
18
+ "../tools/dist/gating.js"() {
19
+ "use strict";
20
+ UNGATED_TOOL_NAMES = [
21
+ "contract.get",
22
+ "whoami",
23
+ "tools.list",
24
+ "tools.schema",
25
+ "tools.help",
26
+ "tools.search",
27
+ "brain.list",
28
+ "brain.use",
29
+ "scope.current"
30
+ ];
31
+ ungatedToolNames = new Set(UNGATED_TOOL_NAMES);
32
+ }
33
+ });
34
+
35
+ // ../tools/dist/canvasTools.js
36
+ function canvasToolDefinitions(writeTool2) {
37
+ return [
38
+ writeTool2("canvas.create", "Create a canvas (a spatial board of live views and notes). Returns the canvas id; compose it with canvas.add_node.", {
39
+ title: { type: "string" },
40
+ intent: { type: "string" }
41
+ }, "sift canvas create --title 'This week'", { required: ["title"] }),
42
+ writeTool2("canvas.add_node", [
43
+ "Add one node to a canvas. Pick the most structured nodeType that fits; prose is the",
44
+ "last resort. nodeType: plan (title + tracks of {name, owners?, goal?, items:[{text,",
45
+ "who?, when?, done?}]} \u2014 roadmaps, weekly plans, agendas), metric (label + value,",
46
+ "optional delta {direction,magnitude,sentiment} \u2014 one number), chart (rows of",
47
+ "{label, value:number}, optional title \u2014 comparing numbers), kanban or checklist",
48
+ "(queryRef binding to a live workspace query), prose (markdown, optional title),",
49
+ "note (text \u2014 a short plain annotation, never primary content).",
50
+ "Content must come from brain data you actually read, never invented."
51
+ ].join(" "), {
52
+ canvasId: { type: "string" },
53
+ nodeType: {
54
+ type: "string",
55
+ enum: ["plan", "metric", "chart", "kanban", "checklist", "prose", "note"]
56
+ },
57
+ text: { type: "string" },
58
+ markdown: { type: "string" },
59
+ title: { type: "string" },
60
+ timeframe: { type: "string" },
61
+ tracks: { type: "array", items: { type: "object" } },
62
+ label: { type: "string" },
63
+ value: { type: "string" },
64
+ delta: { type: "object" },
65
+ rows: { type: "array", items: { type: "object" } },
66
+ queryRef: { type: "string" },
67
+ position: { type: "object" }
68
+ }, "sift canvas add-node <canvas-id> --type metric", { required: ["canvasId", "nodeType"] }),
69
+ writeTool2("canvas.remove_node", "Remove a node or note from a canvas by id.", {
70
+ canvasId: { type: "string" },
71
+ nodeId: { type: "string" }
72
+ }, "sift canvas remove-node <canvas-id> <node-id>", { required: ["canvasId", "nodeId"] })
73
+ ];
74
+ }
75
+ var init_canvasTools = __esm({
76
+ "../tools/dist/canvasTools.js"() {
77
+ "use strict";
78
+ }
79
+ });
80
+
12
81
  // ../tools/dist/inputParsers.js
13
82
  function parseCaptureFile(input) {
14
83
  return {
@@ -247,7 +316,38 @@ var init_inputParsers = __esm({
247
316
 
248
317
  // ../tools/dist/registry.js
249
318
  function listToolDefinitions() {
250
- return [...toolDefinitions];
319
+ return [...toolDefinitions, ...canvasToolDefinitions(writeTool)].map((tool) => isGatedTool(tool.name) ? withContractVersionProperty(tool) : tool);
320
+ }
321
+ function withContractVersionProperty(tool) {
322
+ return {
323
+ ...tool,
324
+ inputSchema: {
325
+ ...tool.inputSchema,
326
+ properties: {
327
+ ...tool.inputSchema.properties,
328
+ contractVersion: {
329
+ type: "string",
330
+ description: "Echo the current Sift contract version from contract.get."
331
+ }
332
+ }
333
+ }
334
+ };
335
+ }
336
+ function isToolAuthorized(capabilities, tool) {
337
+ return tool.capability === NO_CAPABILITY || capabilities.includes(tool.capability);
338
+ }
339
+ function identityTool(name, summary, properties, cliExample, options) {
340
+ return defineTool({
341
+ name,
342
+ summary,
343
+ properties,
344
+ required: options.required ?? [],
345
+ capability: NO_CAPABILITY,
346
+ mutability: options.mutability,
347
+ transports: writeTransports,
348
+ cliExample,
349
+ hostedAgent: { available: false, ...options.hostedAgent }
350
+ });
251
351
  }
252
352
  function readTool(name, summary, properties, cliExample, options) {
253
353
  return defineTool({
@@ -373,14 +473,18 @@ function tokenize(text) {
373
473
  function stringProps(names) {
374
474
  return Object.fromEntries(names.map((name) => [name, { type: "string" }]));
375
475
  }
376
- var readTransports, writeTransports, toolDefinitions;
476
+ var readTransports, writeTransports, NO_CAPABILITY, toolDefinitions;
377
477
  var init_registry = __esm({
378
478
  "../tools/dist/registry.js"() {
379
479
  "use strict";
480
+ init_gating();
481
+ init_canvasTools();
380
482
  init_inputParsers();
381
483
  readTransports = ["cli", "hosted_mcp", "local_mcp"];
382
484
  writeTransports = ["cli", "hosted_mcp", "local_mcp"];
485
+ NO_CAPABILITY = "none";
383
486
  toolDefinitions = [
487
+ readTool("contract.get", "Fetch the Sift agent contract (kernel + workspace overlay) and the contractVersion to echo on every gated tool call. Call this before any other Sift work.", {}, "sift contract get"),
384
488
  readTool("whoami", "Return principal, actor, scope, and capabilities.", {}, "sift whoami"),
385
489
  readTool("brain.list", "List brains available to the current scope.", {}, "sift brain list"),
386
490
  readTool("brain.use", "Select the current brain scope for subsequent operations.", stringProps(["brainId"]), "sift brain use <brain-id>"),
@@ -465,8 +569,15 @@ var init_registry = __esm({
465
569
  evidenceIds: { type: "array", items: { type: "string" } },
466
570
  visibility: { type: "array", items: { type: "string" } }
467
571
  }, "sift task create", { required: ["title", "visibility"] }),
572
+ identityTool("agent.register", "Register the calling agent as a workspace agent worker acting for the token's owner; idempotent on (workspace, owner, normalized name) and never mutates token state.", {
573
+ name: { type: "string", maxLength: 80 },
574
+ description: { type: "string", maxLength: 280 },
575
+ kind: { type: "string" }
576
+ }, 'sift agent register --name "Claude Code" --description "Coding agent"', { required: ["name"], mutability: "write" }),
577
+ identityTool("agent.status", "Report the request's resolved agent identity (from the asserted agent name) or none.", {}, "sift agent status --json", { mutability: "read" }),
468
578
  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"] }),
579
+ readTool("skill.get", "Read a skill's pinned active version markdown body, version id, and bundle file paths by skill record id.", { skillId: { type: "string" } }, "sift skill get <skill-id>", { required: ["skillId"] }),
580
+ readTool("skill.file", "Read one of a skill's bundle files by path; fetch a file only when the skill body references it and the task needs that detail, using a path listed by skill.get.", { skillId: { type: "string" }, path: { type: "string" } }, "sift skill file <skill-id> examples/2026-05-29-good.md", { required: ["skillId", "path"] }),
470
581
  writeTool("skill.exercise", "Report that a skill version informed an output on a surface; the report is an attribution claim only.", {
471
582
  skillId: { type: "string" },
472
583
  versionId: { type: "string" },
@@ -515,6 +626,7 @@ function executeWhoami(auth) {
515
626
  return {
516
627
  principal: { id: auth.principalId, type: auth.principalType },
517
628
  actor: { id: auth.actorId, type: auth.actorType },
629
+ ...auth.agent === void 0 ? {} : { agent: auth.agent },
518
630
  scope: { workspaceId: auth.workspaceId, brainId: auth.brainId },
519
631
  requestId: auth.requestId,
520
632
  authPath: auth.authPath,
@@ -581,7 +693,7 @@ function executeToolsSearch(input, searchInput) {
581
693
  function availableTools(input) {
582
694
  const transport = input.transport ?? "local_mcp";
583
695
  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));
696
+ return listToolDefinitions().filter((tool) => availableNames.has(tool.name) && tool.transports.includes(transport) && isToolAuthorized(input.auth.capabilities, tool));
585
697
  }
586
698
  function scoreTool(tool, intentTokens) {
587
699
  const haystack = /* @__PURE__ */ new Set([
@@ -631,7 +743,9 @@ var init_discovery = __esm({
631
743
  "evidence.get",
632
744
  "graph.neighbors",
633
745
  "event.list",
634
- "audit.events"
746
+ "audit.events",
747
+ "agent.register",
748
+ "agent.status"
635
749
  ];
636
750
  }
637
751
  });
@@ -704,6 +818,26 @@ var init_captureTools = __esm({
704
818
  }
705
819
  });
706
820
 
821
+ // ../tools/dist/contractTools.js
822
+ function contractToolHandlers(input) {
823
+ return {
824
+ "contract.get": () => {
825
+ if (input.service.getContract === void 0) {
826
+ throw new Error("Tool 'contract.get' requires a runtime service contract.");
827
+ }
828
+ return input.service.getContract({ auth: input.auth });
829
+ }
830
+ };
831
+ }
832
+ function contractToolAvailability(service) {
833
+ return [[service.getContract !== void 0, ["contract.get"]]];
834
+ }
835
+ var init_contractTools = __esm({
836
+ "../tools/dist/contractTools.js"() {
837
+ "use strict";
838
+ }
839
+ });
840
+
707
841
  // ../tools/dist/skillTools.js
708
842
  function skillToolHandlers(input, toolInput) {
709
843
  return {
@@ -723,6 +857,15 @@ function skillToolHandlers(input, toolInput) {
723
857
  skillId: requireString(toolInput, "skillId")
724
858
  });
725
859
  },
860
+ "skill.file": () => {
861
+ if (input.service.getSkillFile === void 0)
862
+ throw missingSkillService("skill.file");
863
+ return input.service.getSkillFile({
864
+ auth: input.auth,
865
+ skillId: requireString(toolInput, "skillId"),
866
+ path: requireString(toolInput, "path")
867
+ });
868
+ },
726
869
  "skill.exercise": () => {
727
870
  if (input.service.recordSkillExercise === void 0) {
728
871
  throw missingSkillService("skill.exercise");
@@ -743,6 +886,7 @@ function skillToolAvailability(service) {
743
886
  return [
744
887
  [service.resolveSkills !== void 0, ["skill.resolve"]],
745
888
  [service.getSkill !== void 0, ["skill.get"]],
889
+ [service.getSkillFile !== void 0, ["skill.file"]],
746
890
  [service.recordSkillExercise !== void 0, ["skill.exercise"]],
747
891
  [service.teachSkill !== void 0, ["skill.teach"]]
748
892
  ];
@@ -805,6 +949,104 @@ var init_skillTools = __esm({
805
949
  }
806
950
  });
807
951
 
952
+ // ../tools/dist/agentIdentityTools.js
953
+ function agentIdentityToolHandlers(input, toolInput) {
954
+ return {
955
+ "agent.register": () => {
956
+ if (input.service.registerAgent === void 0) {
957
+ throw missingAgentIdentityService("agent.register");
958
+ }
959
+ return input.service.registerAgent({
960
+ auth: input.auth,
961
+ name: requireString(toolInput, "name"),
962
+ description: optionalString(toolInput, "description"),
963
+ kind: parseAgentKind(toolInput)
964
+ });
965
+ },
966
+ "agent.status": () => {
967
+ if (input.service.getAgentStatus === void 0) {
968
+ throw missingAgentIdentityService("agent.status");
969
+ }
970
+ return input.service.getAgentStatus({ auth: input.auth });
971
+ }
972
+ };
973
+ }
974
+ function agentIdentityToolAvailability(service) {
975
+ return [
976
+ [service.registerAgent !== void 0, ["agent.register"]],
977
+ [service.getAgentStatus !== void 0, ["agent.status"]]
978
+ ];
979
+ }
980
+ function parseAgentKind(toolInput) {
981
+ const kind = optionalString(toolInput, "kind");
982
+ if (kind === void 0) {
983
+ return void 0;
984
+ }
985
+ if (kind !== "agent" && kind !== "service") {
986
+ throw new Error("kind must be 'agent' or 'service'.");
987
+ }
988
+ return kind;
989
+ }
990
+ function missingAgentIdentityService(toolName) {
991
+ return new Error(`Tool '${toolName}' requires a runtime service contract.`);
992
+ }
993
+ var init_agentIdentityTools = __esm({
994
+ "../tools/dist/agentIdentityTools.js"() {
995
+ "use strict";
996
+ init_inputParsers();
997
+ }
998
+ });
999
+
1000
+ // ../tools/dist/toolAvailability.js
1001
+ function runtimeAvailableToolNames(service) {
1002
+ const baseNames = [
1003
+ "whoami",
1004
+ "tools.list",
1005
+ "tools.schema",
1006
+ "tools.help",
1007
+ "tools.search",
1008
+ "brain.list",
1009
+ "brain.use",
1010
+ "scope.current",
1011
+ "capture.text",
1012
+ "capture.batch",
1013
+ "search.query",
1014
+ "context.assemble"
1015
+ ];
1016
+ const optionalNames = [
1017
+ [service.ingestFile !== void 0, ["capture.file"]],
1018
+ [service.createDecision !== void 0, ["decision.create"]],
1019
+ [service.createTask !== void 0, ["task.create"]],
1020
+ ...skillToolAvailability(service),
1021
+ ...agentIdentityToolAvailability(service),
1022
+ ...contractToolAvailability(service),
1023
+ [service.listSources !== void 0, ["source.list"]],
1024
+ [service.createSource !== void 0, ["source.create"]],
1025
+ [service.getSource !== void 0, ["source.get", "source.status"]],
1026
+ [service.getIngestionStatus !== void 0, ["ingestion.status"]],
1027
+ [service.listRecords !== void 0, ["record.list"]],
1028
+ [service.getRecord !== void 0, ["record.get"]],
1029
+ [service.createMarkdownRecord !== void 0, ["record.create_markdown"]],
1030
+ [service.patchRecordSection !== void 0, ["record.patch_section"]],
1031
+ [service.listRecordVersions !== void 0, ["record.versions"]],
1032
+ [service.listEvidence !== void 0, ["evidence.list"]],
1033
+ [service.getEvidence !== void 0, ["evidence.get"]],
1034
+ [service.listGraphNeighbors !== void 0, ["graph.neighbors"]],
1035
+ [service.listEvents !== void 0, ["event.list"]],
1036
+ [service.getContextProfile !== void 0, ["context.profile"]],
1037
+ [service.listAuditEvents !== void 0, ["audit.events"]]
1038
+ ];
1039
+ return [...baseNames, ...optionalNames.flatMap(([enabled, names]) => enabled ? names : [])];
1040
+ }
1041
+ var init_toolAvailability = __esm({
1042
+ "../tools/dist/toolAvailability.js"() {
1043
+ "use strict";
1044
+ init_agentIdentityTools();
1045
+ init_contractTools();
1046
+ init_skillTools();
1047
+ }
1048
+ });
1049
+
808
1050
  // ../tools/dist/toolLog.js
809
1051
  function logToolCall(input) {
810
1052
  input.onToolLog?.({
@@ -938,6 +1180,8 @@ function createToolHandlers(input, toolInput) {
938
1180
  "decision.create": () => executeDecisionCreate(input, toolInput),
939
1181
  "task.create": () => executeTaskCreate(input, toolInput),
940
1182
  ...skillToolHandlers(input, toolInput),
1183
+ ...agentIdentityToolHandlers(input, toolInput),
1184
+ ...contractToolHandlers(input),
941
1185
  "source.list": () => executeSourceList(input),
942
1186
  "source.create": () => executeSourceCreate(input, toolInput),
943
1187
  "source.get": () => executeSourceRead(input, toolInput, "source.get"),
@@ -980,44 +1224,6 @@ function createToolHandlers(input, toolInput) {
980
1224
  "audit.events": () => executeAuditEvents(input, toolInput)
981
1225
  };
982
1226
  }
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
1227
  function missingService(toolName) {
1022
1228
  return new Error(`Tool '${toolName}' requires a runtime service contract.`);
1023
1229
  }
@@ -1144,7 +1350,10 @@ var init_executor = __esm({
1144
1350
  init_discovery();
1145
1351
  init_captureTools();
1146
1352
  init_inputParsers();
1353
+ init_contractTools();
1147
1354
  init_skillTools();
1355
+ init_agentIdentityTools();
1356
+ init_toolAvailability();
1148
1357
  init_results();
1149
1358
  init_toolLog();
1150
1359
  }
@@ -1169,7 +1378,7 @@ function createCliCommandMetadata(filter) {
1169
1378
  }
1170
1379
  function availableTools2(filter) {
1171
1380
  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));
1381
+ return listToolDefinitions().filter((tool) => availableNames.has(tool.name) && tool.transports.includes(filter.transport) && isToolAuthorized(filter.capabilities, tool));
1173
1382
  }
1174
1383
  var init_generated = __esm({
1175
1384
  "../tools/dist/generated.js"() {
@@ -1222,6 +1431,9 @@ function renderToolResult(result2) {
1222
1431
  }
1223
1432
  function classifyToolError(error) {
1224
1433
  if (error instanceof Error) {
1434
+ if (error.message.startsWith("Sift contract required.")) {
1435
+ return "contract_required";
1436
+ }
1225
1437
  if (isPermissionError2(error)) {
1226
1438
  return "permission_denied";
1227
1439
  }
@@ -1416,7 +1628,7 @@ async function dispatchRequest(method, params, adapter) {
1416
1628
  protocolVersion: requested ?? MCP_PROTOCOL_VERSION,
1417
1629
  capabilities: { tools: { listChanged: false } },
1418
1630
  serverInfo: { name: "sift-local-mcp", version: "0.1.0" },
1419
- instructions: "Use Sift tools to read and write the hosted canonical brain."
1631
+ instructions: "Call contract.get first and echo its contractVersion on every other Sift tool call. Use Sift tools to read and write the hosted canonical brain."
1420
1632
  };
1421
1633
  }
1422
1634
  if (method === "ping")
@@ -1468,12 +1680,16 @@ var init_localMcpStdioServer = __esm({
1468
1680
  var dist_exports = {};
1469
1681
  __export(dist_exports, {
1470
1682
  MCP_PROTOCOL_VERSION: () => MCP_PROTOCOL_VERSION,
1683
+ NO_CAPABILITY: () => NO_CAPABILITY,
1684
+ UNGATED_TOOL_NAMES: () => UNGATED_TOOL_NAMES,
1471
1685
  createCliCommandMetadata: () => createCliCommandMetadata,
1472
1686
  createHostedMcpEntrypoint: () => createHostedMcpEntrypoint,
1473
1687
  createLocalMcpStdioServer: () => createLocalMcpStdioServer,
1474
1688
  createMcpAdapter: () => createMcpAdapter,
1475
1689
  createMcpToolSchemas: () => createMcpToolSchemas,
1476
1690
  createRuntimeToolExecutor: () => createRuntimeToolExecutor,
1691
+ isGatedTool: () => isGatedTool,
1692
+ isToolAuthorized: () => isToolAuthorized,
1477
1693
  listToolDefinitions: () => listToolDefinitions
1478
1694
  });
1479
1695
  var init_dist = __esm({
@@ -1484,6 +1700,7 @@ var init_dist = __esm({
1484
1700
  init_hostedMcpEntrypoint();
1485
1701
  init_localMcpStdioServer();
1486
1702
  init_mcpAdapter();
1703
+ init_gating();
1487
1704
  init_registry();
1488
1705
  }
1489
1706
  });
@@ -1720,6 +1937,9 @@ function fail(message) {
1720
1937
  }
1721
1938
  function classifyError(error) {
1722
1939
  if (error instanceof Error) {
1940
+ if (error.message.startsWith("Sift contract required.")) {
1941
+ return "contract_required";
1942
+ }
1723
1943
  if (isPermissionError(error)) {
1724
1944
  return "permission_denied";
1725
1945
  }
@@ -1768,6 +1988,41 @@ function addReceiptLine(lines, label, value) {
1768
1988
  }
1769
1989
  }
1770
1990
 
1991
+ // src/agentCommands.ts
1992
+ async function agentRegister(executor, assertedAgentName, rest, json) {
1993
+ if (executor === void 0) {
1994
+ return fail("No Sift API executor is configured for agent.register.");
1995
+ }
1996
+ const parsed = parseOptions(rest);
1997
+ const name = optionalOption(parsed, "name") ?? assertedAgentName;
1998
+ if (name === void 0 || name.trim().length === 0) {
1999
+ return fail("Missing agent name: pass --name or set SIFT_AGENT.");
2000
+ }
2001
+ const input = { name };
2002
+ const description = optionalOption(parsed, "description");
2003
+ if (description !== void 0) {
2004
+ input.description = description;
2005
+ }
2006
+ const kind = optionalOption(parsed, "kind");
2007
+ if (kind !== void 0) {
2008
+ input.kind = kind;
2009
+ }
2010
+ const result2 = await executor.execute("agent.register", input);
2011
+ return ok(json ? `${JSON.stringify(result2)}
2012
+ ` : renderAgentRegisterResult(result2));
2013
+ }
2014
+ function renderAgentRegisterResult(result2) {
2015
+ if (typeof result2 !== "object" || result2 === null || !("agent" in result2)) {
2016
+ return `${JSON.stringify(result2)}
2017
+ `;
2018
+ }
2019
+ const { agent, created, reactivated } = result2;
2020
+ const verb = created === true ? "Registered" : reactivated === true ? "Reactivated" : "Already registered";
2021
+ const actsFor = agent.actsForDisplayName === void 0 ? "" : ` (acting for ${agent.actsForDisplayName})`;
2022
+ return `${verb} agent worker '${agent.name ?? "unknown"}'${actsFor}.
2023
+ `;
2024
+ }
2025
+
1771
2026
  // src/auth/commandAdapter.ts
1772
2027
  function isAuthCommand(commandKey) {
1773
2028
  return commandKey === "login:" || commandKey === "auth:status" || commandKey === "logout:";
@@ -1791,6 +2046,7 @@ function authCommand(authCommands2, command, input) {
1791
2046
 
1792
2047
  // src/capabilityGuard.ts
1793
2048
  var commandCapabilities = {
2049
+ "contract:get": "record:read",
1794
2050
  "whoami:": "record:read",
1795
2051
  "brain:list": "record:read",
1796
2052
  "brain:use": "record:read",
@@ -1838,6 +2094,35 @@ function validateCommandCapability(input) {
1838
2094
  }
1839
2095
  }
1840
2096
 
2097
+ // src/contractOption.ts
2098
+ function extractContractVersion(argv2) {
2099
+ const index = argv2.indexOf("--contract");
2100
+ if (index === -1) {
2101
+ return { argv: argv2 };
2102
+ }
2103
+ const value = argv2[index + 1];
2104
+ if (value === void 0 || value.trim().length === 0 || value.startsWith("--")) {
2105
+ return { argv: [...argv2.slice(0, index), ...argv2.slice(index + 1)] };
2106
+ }
2107
+ return {
2108
+ argv: [...argv2.slice(0, index), ...argv2.slice(index + 2)],
2109
+ contractVersion: value
2110
+ };
2111
+ }
2112
+ function applyContractOption(input) {
2113
+ const { argv: argv2, contractVersion } = extractContractVersion(input.argv);
2114
+ if (contractVersion === void 0 || input.executor === void 0) {
2115
+ return { ...input, argv: argv2 };
2116
+ }
2117
+ return { ...input, argv: argv2, executor: withContractVersion(input.executor, contractVersion) };
2118
+ }
2119
+ function withContractVersion(executor, contractVersion) {
2120
+ return {
2121
+ ...executor,
2122
+ execute: (name, toolInput) => executor.execute(name, { ...toolInput, contractVersion })
2123
+ };
2124
+ }
2125
+
1841
2126
  // src/doctor.ts
1842
2127
  async function doctor(input) {
1843
2128
  const checks = [
@@ -2008,6 +2293,7 @@ var knownTopLevelCommands = /* @__PURE__ */ new Set([
2008
2293
  "brain",
2009
2294
  "capture",
2010
2295
  "context",
2296
+ "contract",
2011
2297
  "decision",
2012
2298
  "decide",
2013
2299
  "doctor",
@@ -2360,7 +2646,8 @@ function createHostedApiExecutor(input) {
2360
2646
  authorization: `Bearer ${input.token}`,
2361
2647
  "content-type": "application/json",
2362
2648
  "x-sift-brain-id": input.brainId,
2363
- "x-sift-workspace-id": input.workspaceId
2649
+ "x-sift-workspace-id": input.workspaceId,
2650
+ ...input.agentName === void 0 || input.agentName.trim().length === 0 ? {} : { "x-sift-agent-name": input.agentName.trim() }
2364
2651
  },
2365
2652
  body: JSON.stringify({ input: toolInput }, serializeJsonValue)
2366
2653
  });
@@ -2403,7 +2690,8 @@ function errorMessage(parsed, status2) {
2403
2690
  }
2404
2691
 
2405
2692
  // src/index.ts
2406
- async function runSiftCli(input) {
2693
+ async function runSiftCli(rawInput) {
2694
+ const input = applyContractOption(rawInput);
2407
2695
  const json = input.argv.includes("--json");
2408
2696
  const args = input.argv.filter((arg) => arg !== "--json");
2409
2697
  const [group, command, ...rest] = args;
@@ -2412,6 +2700,7 @@ async function runSiftCli(input) {
2412
2700
  const commandKey = group === "login" ? "login:" : `${group ?? ""}:${command ?? ""}`;
2413
2701
  const commandRest = group === "login" ? args.slice(1) : rest;
2414
2702
  const handlers = {
2703
+ "contract:get": () => executeSimple2(rawInput.executor, "contract.get", {}, json),
2415
2704
  "whoami:": () => executeSimple2(input.executor, "whoami", {}, json),
2416
2705
  "brain:list": () => executeSimple2(input.executor, "brain.list", {}, json),
2417
2706
  "brain:use": () => idTool({
@@ -2460,7 +2749,9 @@ async function runSiftCli(input) {
2460
2749
  "audit:events": () => auditEvents(input.executor, rest, json),
2461
2750
  "decision:create": () => createDecision(input.executor, rest, json),
2462
2751
  "task:create": () => createTask(input.executor, rest, json),
2463
- "mcp:serve": () => mcpServe(input.mcpServer, input.config, input.executor, json),
2752
+ "agent:register": () => agentRegister(input.executor, input.agentName, rest, json),
2753
+ "agent:status": () => executeSimple2(input.executor, "agent.status", {}, json),
2754
+ "mcp:serve": () => mcpServe(input.mcpServer, input.config, rawInput.executor, json),
2464
2755
  "login:": () => authCommand(input.authCommands, "login", { rest: commandRest, json }),
2465
2756
  "auth:status": () => authCommand(input.authCommands, "status", { json }),
2466
2757
  "logout:": () => authCommand(input.authCommands, "logout", { json })
@@ -2515,8 +2806,7 @@ async function mcpServe(mcpServer, config2, executor, json) {
2515
2806
  }
2516
2807
  const result2 = await mcpServer.serve({ config: config2, executor, transport: "local_mcp" });
2517
2808
  if (result2 === void 0) return ok("");
2518
- return ok(json ? `${JSON.stringify(result2)}
2519
- ` : `${JSON.stringify(result2)}
2809
+ return ok(`${JSON.stringify(result2)}
2520
2810
  `);
2521
2811
  }
2522
2812
  function scopeCurrent(config2, json) {
@@ -3457,15 +3747,18 @@ var config = loadedAuth?.config ?? {
3457
3747
  principalId: "",
3458
3748
  capabilities: []
3459
3749
  };
3750
+ var { argv, agentName } = extractAgentName(process.argv.slice(2), process.env.SIFT_AGENT);
3460
3751
  var result = await runSiftCli({
3461
- argv: process.argv.slice(2),
3752
+ argv,
3462
3753
  config,
3463
3754
  readStdin,
3755
+ agentName,
3464
3756
  executor: loadedAuth === void 0 ? void 0 : createHostedApiExecutor({
3465
3757
  apiBaseUrl: loadedAuth.config.apiBaseUrl,
3466
3758
  token: loadedAuth.token,
3467
3759
  workspaceId: loadedAuth.config.workspaceId,
3468
- brainId: loadedAuth.config.brainId
3760
+ brainId: loadedAuth.config.brainId,
3761
+ agentName
3469
3762
  }),
3470
3763
  authCommands,
3471
3764
  mcpServer: {
@@ -3488,6 +3781,18 @@ var result = await runSiftCli({
3488
3781
  process.stdout.write(result.stdout);
3489
3782
  process.stderr.write(result.stderr);
3490
3783
  process.exitCode = result.exitCode;
3784
+ function extractAgentName(args, envAgentName) {
3785
+ const flagIndex = args.indexOf("--as-agent");
3786
+ if (flagIndex !== -1 && args[flagIndex + 1] !== void 0) {
3787
+ const name = args[flagIndex + 1];
3788
+ return {
3789
+ argv: [...args.slice(0, flagIndex), ...args.slice(flagIndex + 2)],
3790
+ agentName: name
3791
+ };
3792
+ }
3793
+ const env = envAgentName?.trim();
3794
+ return { argv: args, agentName: env === void 0 || env.length === 0 ? void 0 : env };
3795
+ }
3491
3796
  async function readStdin() {
3492
3797
  const chunks = [];
3493
3798
  for await (const chunk of process.stdin) {
package/package.json CHANGED
@@ -1,8 +1,17 @@
1
1
  {
2
2
  "name": "@sift-wiki/cli",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "license": "UNLICENSED",
6
+ "description": "Sift CLI release artifact.",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/goodnight000/sift-cli.git"
10
+ },
11
+ "homepage": "https://github.com/goodnight000/sift-cli#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/goodnight000/sift-cli/issues"
14
+ },
6
15
  "bin": {
7
16
  "sift": "dist/bin/sift.js"
8
17
  },
@@ -17,13 +26,6 @@
17
26
  "access": "public"
18
27
  },
19
28
  "scripts": {
20
- "build": "tsup",
21
- "typecheck": "tsc -p tsconfig.json --noEmit",
22
- "pack:verify": "node ../../scripts/verify_cli_package.mjs"
23
- },
24
- "devDependencies": {
25
- "@sift/api": "workspace:*",
26
- "@sift/tools": "workspace:*",
27
- "tsup": "8.5.1"
29
+ "verify": "node scripts/verify-release.mjs"
28
30
  }
29
31
  }