@intent-systems/nexus 2026.1.5-3 → 2026.1.5-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 (144) hide show
  1. package/dist/agents/agent-id.js +41 -0
  2. package/dist/agents/auth-profiles.js +114 -25
  3. package/dist/agents/identity-state.js +79 -0
  4. package/dist/agents/model-auth.js +1 -0
  5. package/dist/agents/model-fallback.js +15 -9
  6. package/dist/agents/model-selection.js +1 -1
  7. package/dist/agents/models-config.js +17 -11
  8. package/dist/agents/pi-embedded-runner.js +101 -9
  9. package/dist/agents/sandbox.js +12 -3
  10. package/dist/agents/skill-runner.js +29 -4
  11. package/dist/agents/skill-usage.js +114 -11
  12. package/dist/agents/skills-status.js +4 -4
  13. package/dist/agents/skills.js +18 -7
  14. package/dist/agents/subagent-registry.js +25 -11
  15. package/dist/agents/system-prompt.js +16 -0
  16. package/dist/agents/tool-policy.js +19 -3
  17. package/dist/agents/tools/browser-tool.js +5 -2
  18. package/dist/agents/tools/image-tool.js +93 -8
  19. package/dist/agents/tools/sessions-announce-target.js +5 -1
  20. package/dist/agents/workspace.js +55 -46
  21. package/dist/auto-reply/command-detection.js +2 -1
  22. package/dist/auto-reply/reply/directive-handling.js +153 -28
  23. package/dist/auto-reply/reply/directives.js +17 -2
  24. package/dist/auto-reply/reply/model-selection.js +8 -3
  25. package/dist/auto-reply/reply/queue.js +2 -2
  26. package/dist/auto-reply/reply.js +1 -1
  27. package/dist/auto-reply/thinking.js +15 -0
  28. package/dist/browser/chrome.js +1 -1
  29. package/dist/browser/client.js +2 -0
  30. package/dist/browser/config.js +6 -2
  31. package/dist/browser/pw-tools-core.js +3 -0
  32. package/dist/browser/routes/agent.js +14 -0
  33. package/dist/canvas-host/server.js +1 -1
  34. package/dist/capabilities/detector.js +245 -0
  35. package/dist/capabilities/registry.js +99 -0
  36. package/dist/channels/location.js +44 -0
  37. package/dist/channels/web/index.js +2 -0
  38. package/dist/cli/cloud-cli.js +12 -7
  39. package/dist/cli/credential-cli.js +139 -17
  40. package/dist/cli/gateway-cli.js +1 -1
  41. package/dist/cli/log-cli.js +25 -0
  42. package/dist/cli/pairing-cli.js +1 -1
  43. package/dist/cli/program.js +58 -6
  44. package/dist/cli/run-main.js +1 -1
  45. package/dist/cli/skills-cli.js +144 -21
  46. package/dist/cli/skills-hub-cli.js +59 -29
  47. package/dist/cli/tool-connector-cli.js +99 -24
  48. package/dist/cli/upstream-sync-cli.js +253 -96
  49. package/dist/cli/usage-cli.js +14 -0
  50. package/dist/commands/auth-choice-options.js +6 -1
  51. package/dist/commands/auth-choice.js +157 -5
  52. package/dist/commands/bootstrap-preset.js +10 -6
  53. package/dist/commands/capabilities.js +33 -6
  54. package/dist/commands/claude-md.js +3 -2
  55. package/dist/commands/config-view.js +1 -1
  56. package/dist/commands/configure.js +4 -4
  57. package/dist/commands/credential.js +497 -36
  58. package/dist/commands/cursor-rules.js +39 -19
  59. package/dist/commands/doctor.js +5 -4
  60. package/dist/commands/identity.js +28 -31
  61. package/dist/commands/init.js +15 -18
  62. package/dist/commands/log.js +134 -0
  63. package/dist/commands/models/fallbacks.js +1 -1
  64. package/dist/commands/models/image-fallbacks.js +1 -1
  65. package/dist/commands/models/list.js +1 -1
  66. package/dist/commands/models/scan.js +1 -1
  67. package/dist/commands/onboard-auth.js +27 -2
  68. package/dist/commands/onboard-eve-identity.js +7 -8
  69. package/dist/commands/onboard-non-interactive.js +4 -2
  70. package/dist/commands/onboard-quickstart.js +18 -11
  71. package/dist/commands/quest-state.js +271 -0
  72. package/dist/commands/quest.js +53 -13
  73. package/dist/commands/reset.js +1 -1
  74. package/dist/commands/sessions-ingest.js +5 -4
  75. package/dist/commands/setup.js +4 -2
  76. package/dist/commands/skills-manifest.js +2 -2
  77. package/dist/commands/status.js +179 -61
  78. package/dist/commands/suggestions.js +1 -1
  79. package/dist/commands/usage-tracking.js +32 -0
  80. package/dist/commands/usage-upload.js +6 -1
  81. package/dist/config/defaults.js +1 -3
  82. package/dist/config/includes.js +5 -7
  83. package/dist/config/io.js +88 -16
  84. package/dist/config/legacy.js +4 -2
  85. package/dist/config/paths.js +16 -0
  86. package/dist/config/sessions.js +9 -5
  87. package/dist/config/zod-schema.js +4 -3
  88. package/dist/control-plane/broker/broker.js +1022 -0
  89. package/dist/control-plane/compaction.js +282 -0
  90. package/dist/control-plane/factory.js +31 -0
  91. package/dist/control-plane/index.js +10 -0
  92. package/dist/control-plane/odu/agents.js +192 -0
  93. package/dist/control-plane/odu/interaction-tools.js +208 -0
  94. package/dist/control-plane/odu/prompt-loader.js +95 -0
  95. package/dist/control-plane/odu/runtime.js +479 -0
  96. package/dist/control-plane/odu/types.js +6 -0
  97. package/dist/control-plane/odu-control-plane.js +316 -0
  98. package/dist/control-plane/single-agent.js +249 -0
  99. package/dist/control-plane/types.js +11 -0
  100. package/dist/credentials/store.js +449 -0
  101. package/dist/gateway/server-browser.js +5 -4
  102. package/dist/gateway/server-methods/cron.js +11 -1
  103. package/dist/gateway/server.js +14 -7
  104. package/dist/infra/bonjour.js +1 -1
  105. package/dist/infra/event-log.js +8 -2
  106. package/dist/infra/path-env.js +1 -2
  107. package/dist/infra/provider-usage.auth.js +5 -3
  108. package/dist/infra/provider-usage.fetch.claude.js +16 -6
  109. package/dist/infra/provider-usage.fetch.minimax.js +8 -3
  110. package/dist/infra/provider-usage.js +9 -5
  111. package/dist/infra/restart.js +2 -2
  112. package/dist/infra/usage-settings.js +78 -0
  113. package/dist/infra/usage-suggestions.js +17 -5
  114. package/dist/infra/usage-upload.js +38 -1
  115. package/dist/infra/voicewake.js +2 -2
  116. package/dist/logging/redact.js +109 -0
  117. package/dist/markdown/fences.js +58 -0
  118. package/dist/media/image-ops.js +3 -1
  119. package/dist/memory/embeddings.js +146 -0
  120. package/dist/memory/index.js +3 -0
  121. package/dist/memory/internal.js +163 -0
  122. package/dist/pairing/pairing-store.js +218 -0
  123. package/dist/plugins/cli.js +42 -0
  124. package/dist/plugins/discovery.js +253 -0
  125. package/dist/plugins/install.js +181 -0
  126. package/dist/plugins/loader.js +290 -0
  127. package/dist/plugins/registry.js +105 -0
  128. package/dist/plugins/status.js +29 -0
  129. package/dist/plugins/tools.js +39 -0
  130. package/dist/plugins/types.js +1 -0
  131. package/dist/providers/github-copilot-auth.js +1 -1
  132. package/dist/routing/resolve-route.js +144 -0
  133. package/dist/routing/session-key.js +65 -0
  134. package/dist/sessions/send-policy.js +5 -5
  135. package/dist/slack/monitor.js +22 -1
  136. package/dist/telegram/reaction-level.js +2 -1
  137. package/dist/utils/provider-utils.js +28 -0
  138. package/dist/utils.js +4 -3
  139. package/dist/wizard/onboarding.js +29 -7
  140. package/package.json +4 -29
  141. package/patches/@mariozechner__pi-ai.patch +215 -0
  142. package/patches/playwright-core@1.57.0.patch +13 -0
  143. package/patches/qrcode-terminal.patch +12 -0
  144. package/scripts/postinstall.js +202 -0
@@ -1,17 +1,17 @@
1
+ import crypto from "node:crypto";
1
2
  import fs from "node:fs/promises";
2
- import path from "node:path";
3
3
  import os from "node:os";
4
- import crypto from "node:crypto";
4
+ import path from "node:path";
5
5
  import { Readable } from "node:stream";
6
6
  import { pipeline } from "node:stream/promises";
7
7
  import { fileTypeFromFile } from "file-type";
8
- import { buildWorkspaceSkillStatus } from "../agents/skills-status.js";
9
8
  import { getSkillMetadata, hasBinary, loadWorkspaceSkillEntries, } from "../agents/skills.js";
9
+ import { buildWorkspaceSkillStatus } from "../agents/skills-status.js";
10
10
  import { DEFAULT_AGENT_WORKSPACE_DIR } from "../agents/workspace.js";
11
- import { generateSkillManifest, writeSkillManifest } from "../commands/skills-manifest.js";
11
+ import { generateSkillManifest, writeSkillManifest, } from "../commands/skills-manifest.js";
12
12
  import { loadConfig } from "../config/config.js";
13
- import { runCommandWithTimeout } from "../process/exec.js";
14
13
  import { listCredentialEntries, resolveCredentialValue, } from "../credentials/store.js";
14
+ import { runCommandWithTimeout } from "../process/exec.js";
15
15
  import { MANAGED_SKILLS_DIR, resolveUserPath } from "../utils.js";
16
16
  function getHubBaseUrl() {
17
17
  return (process.env.NEXUS_HUB_URL ||
@@ -41,7 +41,9 @@ function normalizeStringList(value) {
41
41
  return [];
42
42
  }
43
43
  function normalizeHubDependencies(value) {
44
- const raw = value && typeof value === "object" ? value : {};
44
+ const raw = value && typeof value === "object"
45
+ ? value
46
+ : {};
45
47
  return {
46
48
  dependencies: normalizeStringList(raw.dependencies),
47
49
  tools: normalizeStringList(raw.tools),
@@ -142,16 +144,16 @@ function normalizeMetadata(value) {
142
144
  return {};
143
145
  }
144
146
  function resolveCapabilities(entry) {
147
+ const metadata = entry.metadata;
148
+ const metadataNexus = metadata && typeof metadata.nexus === "object"
149
+ ? metadata.nexus
150
+ : undefined;
145
151
  const candidates = [
146
152
  entry.capabilities,
147
153
  entry.provides,
148
- entry.metadata?.nexus
149
- ? entry.metadata.nexus.provides
150
- : undefined,
151
- entry.metadata?.nexus
152
- ? entry.metadata.nexus.capabilities
153
- : undefined,
154
- entry.metadata?.capabilities,
154
+ metadataNexus?.provides,
155
+ metadataNexus?.capabilities,
156
+ metadata?.capabilities,
155
157
  ];
156
158
  for (const candidate of candidates) {
157
159
  const parsed = normalizeStringList(candidate);
@@ -456,7 +458,7 @@ async function computeArtifactInfo(filePath) {
456
458
  return { sha256: hash, bytes: stats.size };
457
459
  }
458
460
  async function resolveHubToken(input) {
459
- if (input && input.trim())
461
+ if (input?.trim())
460
462
  return input.trim();
461
463
  const envToken = process.env.NEXUS_HUB_TOKEN ||
462
464
  process.env.NEXUS_WEBSITE_TOKEN ||
@@ -483,7 +485,9 @@ function buildManifestPayload(input) {
483
485
  (typeof frontmatter.name === "string" ? frontmatter.name : "") ||
484
486
  "";
485
487
  const description = overrides.description ||
486
- (typeof frontmatter.description === "string" ? frontmatter.description : "") ||
488
+ (typeof frontmatter.description === "string"
489
+ ? frontmatter.description
490
+ : "") ||
487
491
  "";
488
492
  const type = overrides.type ||
489
493
  (typeof frontmatter.type === "string" ? frontmatter.type : "") ||
@@ -496,7 +500,9 @@ function buildManifestPayload(input) {
496
500
  (typeof frontmatter.license === "string" ? frontmatter.license : "") ||
497
501
  "";
498
502
  const repository = overrides.repository ||
499
- (typeof frontmatter.repository === "string" ? frontmatter.repository : "") ||
503
+ (typeof frontmatter.repository === "string"
504
+ ? frontmatter.repository
505
+ : "") ||
500
506
  (typeof frontmatter.repo === "string" ? frontmatter.repo : "") ||
501
507
  "";
502
508
  const homepage = overrides.homepage ||
@@ -530,11 +536,15 @@ function buildManifestPayload(input) {
530
536
  const capabilities = resolveCapabilities(capabilityCandidates);
531
537
  if (capabilities.length > 0) {
532
538
  manifestEntry.capabilities = capabilities;
533
- const nexus = manifestEntry.metadata;
534
- nexus.nexus = {
535
- ...(nexus.nexus ?? {}),
539
+ const metadata = (manifestEntry.metadata ?? {});
540
+ const existingNexus = metadata.nexus && typeof metadata.nexus === "object"
541
+ ? metadata.nexus
542
+ : {};
543
+ metadata.nexus = {
544
+ ...existingNexus,
536
545
  provides: capabilities,
537
546
  };
547
+ manifestEntry.metadata = metadata;
538
548
  }
539
549
  const readmeExcerpt = extractExcerpt(body || description);
540
550
  return {
@@ -595,7 +605,9 @@ async function installHubSkill(params) {
595
605
  return { installed: true, destDir };
596
606
  }
597
607
  export function registerSkillsHubCommand(program) {
598
- const skills = program.command("skills").description("Search and install skills from the Nexus Hub");
608
+ const skills = program
609
+ .command("skills")
610
+ .description("Search and install skills from the Nexus Hub");
599
611
  skills
600
612
  .command("search <query>")
601
613
  .description("Search local skills and the Nexus Hub")
@@ -625,7 +637,10 @@ export function registerSkillsHubCommand(program) {
625
637
  config: cfg,
626
638
  managedSkillsDir,
627
639
  });
628
- const metadataByName = new Map(metadataEntries.map((entry) => [entry.skill.name, getSkillMetadata(entry)]));
640
+ const metadataByName = new Map(metadataEntries.map((entry) => [
641
+ entry.skill.name,
642
+ getSkillMetadata(entry),
643
+ ]));
629
644
  const installedNames = new Set(metadataEntries.map((entry) => normalizeSkillKey(entry.skill.name)));
630
645
  const installedSlugs = await loadManagedSkillSlugs(managedSkillsDir);
631
646
  const installedIndex = {
@@ -666,7 +681,7 @@ export function registerSkillsHubCommand(program) {
666
681
  })
667
682
  .filter((skill) => skill.score > 0)
668
683
  .sort((a, b) => b.score - a.score)
669
- .map(({ score, ...rest }) => rest);
684
+ .map(({ score: _score, ...rest }) => rest);
670
685
  let hubMatches = [];
671
686
  if (!opts.localOnly) {
672
687
  try {
@@ -801,7 +816,10 @@ export function registerSkillsHubCommand(program) {
801
816
  console.log(` Requires → ${deps.join(" | ")}`);
802
817
  }
803
818
  if (skill.install.length > 0) {
804
- console.log(` Install → ${skill.install.map((i) => i.label).filter(Boolean).join(", ")}`);
819
+ console.log(` Install → ${skill.install
820
+ .map((i) => i.label)
821
+ .filter(Boolean)
822
+ .join(", ")}`);
805
823
  }
806
824
  }
807
825
  console.log("");
@@ -873,20 +891,32 @@ export function registerSkillsHubCommand(program) {
873
891
  const capOverrides = [
874
892
  ...(Array.isArray(opts.capability) ? opts.capability : []),
875
893
  ...normalizeStringList(opts.capabilities),
876
- ].map((cap) => cap.trim()).filter(Boolean);
894
+ ]
895
+ .map((cap) => cap.trim())
896
+ .filter(Boolean);
877
897
  const overrides = {
878
898
  path: skillDir,
879
899
  slug: typeof opts.slug === "string" ? opts.slug.trim() : undefined,
880
900
  name: typeof opts.name === "string" ? opts.name.trim() : undefined,
881
- description: typeof opts.description === "string" ? opts.description.trim() : undefined,
901
+ description: typeof opts.description === "string"
902
+ ? opts.description.trim()
903
+ : undefined,
882
904
  type: typeof opts.type === "string" ? opts.type.trim() : undefined,
883
905
  version: typeof opts.version === "string" ? opts.version.trim() : undefined,
884
906
  license: typeof opts.license === "string" ? opts.license.trim() : undefined,
885
- repository: typeof opts.repository === "string" ? opts.repository.trim() : undefined,
886
- homepage: typeof opts.homepage === "string" ? opts.homepage.trim() : undefined,
887
- visibility: typeof opts.visibility === "string" ? opts.visibility.trim() : "public",
907
+ repository: typeof opts.repository === "string"
908
+ ? opts.repository.trim()
909
+ : undefined,
910
+ homepage: typeof opts.homepage === "string"
911
+ ? opts.homepage.trim()
912
+ : undefined,
913
+ visibility: typeof opts.visibility === "string"
914
+ ? opts.visibility.trim()
915
+ : "public",
888
916
  capabilities: capOverrides.length > 0 ? capOverrides : undefined,
889
- sourcePath: typeof opts.source === "string" ? resolveUserPath(opts.source) : undefined,
917
+ sourcePath: typeof opts.source === "string"
918
+ ? resolveUserPath(opts.source)
919
+ : undefined,
890
920
  sourceCommit: typeof opts.sourceCommit === "string"
891
921
  ? opts.sourceCommit.trim()
892
922
  : undefined,
@@ -1,8 +1,11 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { getSkillMetadata, hasBinary, loadWorkspaceSkillEntries, } from "../agents/skills.js";
4
- import { ensureCredentialIndexSync } from "../credentials/store.js";
5
- import { NEXUS_ROOT } from "../utils.js";
4
+ import { DEFAULT_AGENT_WORKSPACE_DIR } from "../agents/workspace.js";
5
+ import { loadConfig } from "../config/config.js";
6
+ import { ensureCredentialIndexSync, } from "../credentials/store.js";
7
+ import { verifyCredentials } from "../commands/credential.js";
8
+ import { resolveUserPath } from "../utils.js";
6
9
  function resolveBinaryPath(bin) {
7
10
  const pathEnv = process.env.PATH ?? "";
8
11
  const parts = pathEnv.split(path.delimiter).filter(Boolean);
@@ -19,16 +22,29 @@ function resolveBinaryPath(bin) {
19
22
  return null;
20
23
  }
21
24
  export function registerToolConnectorCli(program) {
22
- const tool = program.command("tool").description("Tool verification and paths");
23
- const connector = program.command("connector").description("Connector verification and accounts");
25
+ const tool = program
26
+ .command("tool")
27
+ .description("Tool verification and paths");
28
+ const connector = program
29
+ .command("connector")
30
+ .description("Connector verification and accounts");
24
31
  tool
25
- .command("verify")
32
+ .command("verify [name]")
26
33
  .description("Verify tool dependencies")
27
34
  .option("--json", "Output as JSON")
28
- .action((opts) => {
29
- const entries = loadWorkspaceSkillEntries(path.join(NEXUS_ROOT, "home"));
35
+ .action((name, opts) => {
36
+ const config = loadConfig();
37
+ const workspaceDir = resolveUserPath(config.agent?.workspace ?? DEFAULT_AGENT_WORKSPACE_DIR);
38
+ const entries = loadWorkspaceSkillEntries(workspaceDir);
30
39
  const tools = entries.filter((entry) => getSkillMetadata(entry)?.type === "tool");
31
- const results = tools.map((entry) => {
40
+ const scoped = name?.trim() && name.trim().length > 0
41
+ ? tools.filter((entry) => entry.skill.name.toLowerCase() === name.toLowerCase())
42
+ : tools;
43
+ if (name && scoped.length === 0) {
44
+ console.error(`Tool skill not found: ${name}`);
45
+ process.exit(1);
46
+ }
47
+ const results = scoped.map((entry) => {
32
48
  const meta = getSkillMetadata(entry);
33
49
  const bins = meta?.requires?.bins ?? [];
34
50
  const missing = bins.filter((bin) => !hasBinary(bin));
@@ -53,38 +69,80 @@ export function registerToolConnectorCli(program) {
53
69
  }
54
70
  });
55
71
  tool
56
- .command("path <bin>")
57
- .description("Resolve binary path")
58
- .action((bin) => {
59
- const resolved = resolveBinaryPath(bin);
72
+ .command("path <name>")
73
+ .description("Resolve binary path for a tool skill or bin")
74
+ .action((name) => {
75
+ const config = loadConfig();
76
+ const workspaceDir = resolveUserPath(config.agent?.workspace ?? DEFAULT_AGENT_WORKSPACE_DIR);
77
+ const entries = loadWorkspaceSkillEntries(workspaceDir);
78
+ const match = entries.find((entry) => entry.skill.name.toLowerCase() === name.toLowerCase());
79
+ if (match) {
80
+ const meta = getSkillMetadata(match);
81
+ const bins = meta?.requires?.bins ?? [];
82
+ if (bins.length === 0) {
83
+ console.error(`No binaries listed for tool: ${match.skill.name}`);
84
+ process.exit(1);
85
+ }
86
+ const resolvedBins = bins.map((bin) => ({
87
+ bin,
88
+ path: resolveBinaryPath(bin),
89
+ }));
90
+ const missing = resolvedBins.filter((item) => !item.path);
91
+ if (missing.length > 0) {
92
+ console.error(`Missing binaries: ${missing.map((item) => item.bin).join(", ")}`);
93
+ process.exit(1);
94
+ }
95
+ for (const item of resolvedBins) {
96
+ if (item.path)
97
+ console.log(item.path);
98
+ }
99
+ return;
100
+ }
101
+ const resolved = resolveBinaryPath(name);
60
102
  if (!resolved) {
61
- console.error(`Binary not found: ${bin}`);
103
+ console.error(`Binary not found: ${name}`);
62
104
  process.exit(1);
63
105
  }
64
106
  console.log(resolved);
65
107
  });
66
108
  connector
67
- .command("verify")
109
+ .command("verify [name]")
68
110
  .description("Verify connector credentials")
69
111
  .option("--json", "Output as JSON")
70
- .action((opts) => {
71
- const entries = loadWorkspaceSkillEntries(path.join(NEXUS_ROOT, "home"));
112
+ .action(async (name, opts) => {
113
+ const config = loadConfig();
114
+ const workspaceDir = resolveUserPath(config.agent?.workspace ?? DEFAULT_AGENT_WORKSPACE_DIR);
115
+ const entries = loadWorkspaceSkillEntries(workspaceDir);
72
116
  const connectors = entries.filter((entry) => getSkillMetadata(entry)?.type === "connector");
117
+ const scoped = name?.trim() && name.trim().length > 0
118
+ ? connectors.filter((entry) => entry.skill.name.toLowerCase() === name.toLowerCase())
119
+ : connectors;
120
+ if (name && scoped.length === 0) {
121
+ console.error(`Connector skill not found: ${name}`);
122
+ process.exit(1);
123
+ }
73
124
  const index = ensureCredentialIndexSync();
74
125
  const services = new Set(Object.keys(index.services ?? {}).map((id) => id.toLowerCase()));
75
- const results = connectors.map((entry) => {
126
+ const results = await Promise.all(scoped.map(async (entry) => {
76
127
  const meta = getSkillMetadata(entry);
77
128
  const provides = meta?.provides ?? [];
78
129
  const requires = meta?.requires?.credentials ?? [];
79
130
  const hints = [...requires, entry.skill.name].map((value) => value.toLowerCase());
80
131
  const hasCredential = hints.some((hint) => services.has(hint));
132
+ const verified = hasCredential
133
+ ? await Promise.all(hints.map((hint) => verifyCredentials({ service: hint }).catch(() => null)))
134
+ : [];
135
+ const ok = hasCredential
136
+ ? verified.every((result) => result?.ok !== false)
137
+ : false;
81
138
  return {
82
139
  skill: entry.skill.name,
83
140
  provides,
84
141
  requires,
85
- ok: hasCredential,
142
+ ok,
143
+ verified,
86
144
  };
87
- });
145
+ }));
88
146
  if (opts.json) {
89
147
  console.log(JSON.stringify(results, null, 2));
90
148
  return;
@@ -99,17 +157,34 @@ export function registerToolConnectorCli(program) {
99
157
  }
100
158
  });
101
159
  connector
102
- .command("accounts")
160
+ .command("accounts [service]")
103
161
  .description("List credential accounts")
104
162
  .option("--json", "Output as JSON")
105
- .action((opts) => {
163
+ .action((service, opts) => {
106
164
  const index = ensureCredentialIndexSync();
165
+ const filter = service?.trim();
107
166
  if (opts.json) {
108
- console.log(JSON.stringify(index, null, 2));
167
+ if (!filter) {
168
+ console.log(JSON.stringify(index, null, 2));
169
+ return;
170
+ }
171
+ const entry = index.services?.[filter];
172
+ if (!entry) {
173
+ console.error(`Service not found: ${filter}`);
174
+ process.exit(1);
175
+ }
176
+ console.log(JSON.stringify({ [filter]: entry }, null, 2));
109
177
  return;
110
178
  }
111
- for (const [service, info] of Object.entries(index.services ?? {})) {
112
- console.log(service);
179
+ const entries = filter
180
+ ? index.services?.[filter]
181
+ ? [[filter, index.services[filter]]]
182
+ : []
183
+ : Object.entries(index.services ?? {});
184
+ for (const [serviceId, info] of entries) {
185
+ if (!info)
186
+ continue;
187
+ console.log(serviceId);
113
188
  for (const account of info.accounts ?? []) {
114
189
  console.log(` - ${account.id}`);
115
190
  }