@intent-systems/nexus 2026.1.5-5 → 2026.1.5-8

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 (245) hide show
  1. package/dist/agents/identity-state.js +45 -23
  2. package/dist/agents/skill-runner.js +12 -2
  3. package/dist/agents/skill-usage.js +4 -7
  4. package/dist/agents/skills-status.js +3 -2
  5. package/dist/agents/skills.js +20 -23
  6. package/dist/agents/workspace.js +32 -19
  7. package/dist/capabilities/detector.js +2 -2
  8. package/dist/cli/cloud-cli.js +58 -0
  9. package/dist/cli/credential-cli.js +77 -8
  10. package/dist/cli/program.js +24 -2
  11. package/dist/cli/skills-cli.js +30 -18
  12. package/dist/cli/skills-hub-cli.js +9 -7
  13. package/dist/commands/bootstrap-preset.js +16 -6
  14. package/dist/commands/config.js +85 -0
  15. package/dist/commands/cursor-hooks.js +240 -0
  16. package/dist/commands/cursor-rules.js +13 -207
  17. package/dist/commands/identity.js +3 -3
  18. package/dist/commands/init.js +293 -6
  19. package/dist/commands/onboard-eve-identity.js +1 -1
  20. package/dist/commands/skills-manifest.js +89 -29
  21. package/dist/commands/status.js +52 -50
  22. package/dist/daemon/launchd.js +14 -0
  23. package/dist/entry.js +0 -0
  24. package/dist/native/nexus-cloud/darwin-arm64/nexus-cloud +0 -0
  25. package/dist/native/nexus-cloud/darwin-arm64/nexus-cloud-rs +0 -0
  26. package/dist/utils.js +6 -2
  27. package/docs/AGENTS.default.md +1 -1
  28. package/docs/configuration.md +1 -1
  29. package/docs/feature-inventory/overview.md +2 -2
  30. package/docs/reference/templates/AGENTS.md +172 -109
  31. package/docs/templates/AGENTS.md +140 -199
  32. package/docs/templates/BOOTSTRAP.md +40 -20
  33. package/docs/templates/IDENTITY.md +6 -0
  34. package/docs/templates/USER.md +22 -2
  35. package/package.json +3 -1
  36. package/skills/{notion → connectors/notion}/SKILL.md +1 -1
  37. package/skills/{filesystem → guides/filesystem}/SKILL.md +1 -1
  38. package/skills/{onboarding → guides/onboarding}/SKILL.md +1 -1
  39. package/skills/{onboarding → guides/onboarding}/docs/CAPABILITY_TAXONOMY.md +5 -5
  40. package/skills/{onboarding → guides/onboarding}/docs/CLI_GRAMMAR.md +8 -8
  41. package/skills/{onboarding → guides/onboarding}/docs/CLI_GRAMMAR_ONBOARDING.md +2 -2
  42. package/skills/{onboarding → guides/onboarding}/docs/CLI_GRAMMAR_SKILLS.md +26 -20
  43. package/skills/{onboarding → guides/onboarding}/docs/GOAL_STATE_ARCHITECTURE.md +38 -43
  44. package/skills/{onboarding → guides/onboarding}/docs/NEXUS_SYSTEM_OVERVIEW.md +4 -4
  45. package/skills/{onboarding → guides/onboarding}/docs/SKILLS_HUB_SPEC.md +1 -1
  46. package/skills/{onboarding → guides/onboarding}/docs/SKILLS_SPECIFICATION.md +8 -7
  47. package/skills/{onboarding → guides/onboarding}/docs/SKILL_GATEWAY_DESIGN.md +16 -16
  48. package/skills/{onboarding → guides/onboarding}/docs/SKILL_GATEWAY_PRD.md +10 -12
  49. package/skills/guides/onboarding/docs/canonical/00_CONFLICT_ANALYSIS.md +463 -0
  50. package/skills/guides/onboarding/docs/canonical/01_NEXUS_OVERVIEW.md +167 -0
  51. package/skills/guides/onboarding/docs/canonical/02_CLI_REFERENCE.md +404 -0
  52. package/skills/guides/onboarding/docs/canonical/03_STATE_ARCHITECTURE.md +357 -0
  53. package/skills/guides/onboarding/docs/canonical/04_SKILL_SPECIFICATION.md +393 -0
  54. package/skills/guides/onboarding/docs/canonical/05_CAPABILITY_TAXONOMY.md +298 -0
  55. package/skills/guides/onboarding/docs/canonical/06_CAPABILITIES_REFERENCE.md +207 -0
  56. package/skills/guides/onboarding/docs/canonical/07_AGENT_BINDINGS.md +85 -0
  57. package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/nexus-cloud.md +2 -2
  58. package/skills/{onboarding → guides/onboarding}/scripts/ralph/progress.txt +1 -1
  59. package/skills/{nexus-cloud → tools/nexus-cloud}/SKILL.md +2 -1
  60. package/skills/{nexus-cloud → tools/nexus-cloud}/docs/setup.md +1 -1
  61. package/docs/templates/PROFILE.md +0 -14
  62. /package/skills/{brave-search → connectors/brave-search}/SKILL.md +0 -0
  63. /package/skills/{brave-search → connectors/brave-search}/docs/setup.md +0 -0
  64. /package/skills/{brave-search → connectors/brave-search}/docs/troubleshooting.md +0 -0
  65. /package/skills/{brave-search → connectors/brave-search}/docs/usage.md +0 -0
  66. /package/skills/{brave-search → connectors/brave-search}/scripts/content.mjs +0 -0
  67. /package/skills/{brave-search → connectors/brave-search}/scripts/search.mjs +0 -0
  68. /package/skills/{discord → connectors/discord}/SKILL.md +0 -0
  69. /package/skills/{gemini → connectors/gemini}/SKILL.md +0 -0
  70. /package/skills/{github → connectors/github}/SKILL.md +0 -0
  71. /package/skills/{github → connectors/github}/docs/setup.md +0 -0
  72. /package/skills/{github → connectors/github}/docs/troubleshooting.md +0 -0
  73. /package/skills/{google-oauth → connectors/google-oauth}/SKILL.md +0 -0
  74. /package/skills/{slack → connectors/slack}/SKILL.md +0 -0
  75. /package/skills/{telegram → connectors/telegram}/SKILL.md +0 -0
  76. /package/skills/{telegram → connectors/telegram}/docs/pairing.md +0 -0
  77. /package/skills/{telegram → connectors/telegram}/docs/setup.md +0 -0
  78. /package/skills/{telegram → connectors/telegram}/docs/webhook.md +0 -0
  79. /package/skills/{wacli → connectors/wacli}/SKILL.md +0 -0
  80. /package/skills/{wacli → connectors/wacli}/docs/auth.md +0 -0
  81. /package/skills/{wacli → connectors/wacli}/docs/backup.md +0 -0
  82. /package/skills/{wacli → connectors/wacli}/docs/troubleshooting.md +0 -0
  83. /package/skills/{browser-use-agent-sdk → guides/browser-use-agent-sdk}/SKILL.md +0 -0
  84. /package/skills/{json-render → guides/json-render}/SKILL.md +0 -0
  85. /package/skills/{json-render → guides/json-render}/assets/components/README.md +0 -0
  86. /package/skills/{json-render → guides/json-render}/assets/components/catalog.ts +0 -0
  87. /package/skills/{json-render → guides/json-render}/assets/components/registry.tsx +0 -0
  88. /package/skills/{json-render → guides/json-render}/assets/demo/App.css +0 -0
  89. /package/skills/{json-render → guides/json-render}/assets/demo/App.tsx +0 -0
  90. /package/skills/{json-render → guides/json-render}/assets/demo/README.md +0 -0
  91. /package/skills/{json-render → guides/json-render}/assets/demo/catalog.ts +0 -0
  92. /package/skills/{json-render → guides/json-render}/assets/demo/data/nexus-core.json +0 -0
  93. /package/skills/{json-render → guides/json-render}/assets/demo/index.css +0 -0
  94. /package/skills/{json-render → guides/json-render}/assets/demo/registry.tsx +0 -0
  95. /package/skills/{json-render → guides/json-render}/docs/nexus-state-demo.md +0 -0
  96. /package/skills/{json-render → guides/json-render}/docs/shadcn-preset.md +0 -0
  97. /package/skills/{json-render → guides/json-render}/scripts/create-vite-demo.sh +0 -0
  98. /package/skills/{json-render → guides/json-render}/scripts/llm-server/README.md +0 -0
  99. /package/skills/{json-render → guides/json-render}/scripts/llm-server/catalog.ts +0 -0
  100. /package/skills/{json-render → guides/json-render}/scripts/llm-server/package-lock.json +0 -0
  101. /package/skills/{json-render → guides/json-render}/scripts/llm-server/package.json +0 -0
  102. /package/skills/{json-render → guides/json-render}/scripts/llm-server/server.ts +0 -0
  103. /package/skills/{onboarding → guides/onboarding}/docs/CAPABILITIES.md +0 -0
  104. /package/skills/{onboarding → guides/onboarding}/docs/CLI_GRAMMAR_CREDENTIALS.md +0 -0
  105. /package/skills/{onboarding → guides/onboarding}/docs/DOCUMENTATION_OVERVIEW.md +0 -0
  106. /package/skills/{onboarding → guides/onboarding}/docs/ENTITY_MODEL.md +0 -0
  107. /package/skills/{onboarding → guides/onboarding}/docs/SKILL_INVENTORY.md +0 -0
  108. /package/skills/{onboarding → guides/onboarding}/docs/STATE_ARCHITECTURE.md +0 -0
  109. /package/skills/{onboarding → guides/onboarding}/docs/TROUBLESHOOTING.md +0 -0
  110. /package/skills/{onboarding → guides/onboarding}/docs/USER_JOURNEY.md +0 -0
  111. /package/skills/{onboarding → guides/onboarding}/docs/WOW_MOMENTS.md +0 -0
  112. /package/skills/{onboarding → guides/onboarding}/docs/agent-apple-id.md +0 -0
  113. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/1password.md +0 -0
  114. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/TEMPLATE.md +0 -0
  115. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/aix.md +0 -0
  116. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/bird.md +0 -0
  117. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/brave-search.md +0 -0
  118. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/comms.md +0 -0
  119. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/computer-use.md +0 -0
  120. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/cron-and-heartbeat.md +0 -0
  121. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/eve.md +0 -0
  122. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/github.md +0 -0
  123. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/gog.md +0 -0
  124. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/homebrew-prereqs.md +0 -0
  125. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/qmd.md +0 -0
  126. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/telegram.md +0 -0
  127. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/wacli.md +0 -0
  128. /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/weather.md +0 -0
  129. /package/skills/{onboarding → guides/onboarding}/scripts/ralph/prd.json +0 -0
  130. /package/skills/{onboarding → guides/onboarding}/scripts/ralph/prompt.md +0 -0
  131. /package/skills/{onboarding → guides/onboarding}/scripts/ralph/ralph.log +0 -0
  132. /package/skills/{onboarding → guides/onboarding}/scripts/ralph/ralph.sh +0 -0
  133. /package/skills/{onboarding → guides/onboarding}/scripts/setup-cursor-skills.sh +0 -0
  134. /package/skills/{1password → tools/1password}/SKILL.md +0 -0
  135. /package/skills/{1password → tools/1password}/docs/setup.md +0 -0
  136. /package/skills/{1password → tools/1password}/docs/troubleshooting.md +0 -0
  137. /package/skills/{1password → tools/1password}/references/cli-examples.md +0 -0
  138. /package/skills/{1password → tools/1password}/references/get-started.md +0 -0
  139. /package/skills/{agent-browser → tools/agent-browser}/SKILL.md +0 -0
  140. /package/skills/{agent-browser → tools/agent-browser}/docs/browser-use-eval.md +0 -0
  141. /package/skills/{agent-browser → tools/agent-browser}/docs/first-tests.md +0 -0
  142. /package/skills/{agent-browser → tools/agent-browser}/docs/wordle-nyt-eval.js +0 -0
  143. /package/skills/{aix → tools/aix}/SKILL.md +0 -0
  144. /package/skills/{aix → tools/aix}/docs/embeddings.md +0 -0
  145. /package/skills/{aix → tools/aix}/docs/setup.md +0 -0
  146. /package/skills/{aix → tools/aix}/docs/troubleshooting.md +0 -0
  147. /package/skills/{aix → tools/aix}/references/sql.md +0 -0
  148. /package/skills/{apple-notes → tools/apple-notes}/SKILL.md +0 -0
  149. /package/skills/{apple-reminders → tools/apple-reminders}/SKILL.md +0 -0
  150. /package/skills/{bear-notes → tools/bear-notes}/SKILL.md +0 -0
  151. /package/skills/{bird → tools/bird}/SKILL.md +0 -0
  152. /package/skills/{bird → tools/bird}/docs/auth.md +0 -0
  153. /package/skills/{bird → tools/bird}/docs/troubleshooting.md +0 -0
  154. /package/skills/{blogwatcher → tools/blogwatcher}/SKILL.md +0 -0
  155. /package/skills/{blucli → tools/blucli}/SKILL.md +0 -0
  156. /package/skills/{camsnap → tools/camsnap}/SKILL.md +0 -0
  157. /package/skills/{clawdhub → tools/clawdhub}/SKILL.md +0 -0
  158. /package/skills/{coding-agent → tools/coding-agent}/SKILL.md +0 -0
  159. /package/skills/{comms → tools/comms}/SKILL.md +0 -0
  160. /package/skills/{comms → tools/comms}/docs/adapters.md +0 -0
  161. /package/skills/{comms → tools/comms}/docs/setup.md +0 -0
  162. /package/skills/{comms → tools/comms}/docs/troubleshooting.md +0 -0
  163. /package/skills/{comms → tools/comms}/references/schema.md +0 -0
  164. /package/skills/{computer-use → tools/computer-use}/SKILL.md +0 -0
  165. /package/skills/{computer-use → tools/computer-use}/docs/open-interpreter.md +0 -0
  166. /package/skills/{computer-use → tools/computer-use}/docs/peekaboo.md +0 -0
  167. /package/skills/{computer-use → tools/computer-use}/docs/setup.md +0 -0
  168. /package/skills/{computer-use → tools/computer-use}/docs/troubleshooting.md +0 -0
  169. /package/skills/{eightctl → tools/eightctl}/SKILL.md +0 -0
  170. /package/skills/{eve → tools/eve}/SKILL.md +0 -0
  171. /package/skills/{eve → tools/eve}/docs/dual-account.md +0 -0
  172. /package/skills/{eve → tools/eve}/docs/intelligence.md +0 -0
  173. /package/skills/{eve → tools/eve}/docs/setup.md +0 -0
  174. /package/skills/{eve → tools/eve}/docs/troubleshooting.md +0 -0
  175. /package/skills/{eve → tools/eve}/scripts/setup-dual-account.sh +0 -0
  176. /package/skills/{food-order → tools/food-order}/SKILL.md +0 -0
  177. /package/skills/{gh → tools/gh}/SKILL.md +0 -0
  178. /package/skills/{gh → tools/gh}/docs/usage.md +0 -0
  179. /package/skills/{gifgrep → tools/gifgrep}/SKILL.md +0 -0
  180. /package/skills/{gog → tools/gog}/SKILL.md +0 -0
  181. /package/skills/{gog → tools/gog}/docs/portability.md +0 -0
  182. /package/skills/{gog → tools/gog}/docs/setup.md +0 -0
  183. /package/skills/{gog → tools/gog}/docs/troubleshooting.md +0 -0
  184. /package/skills/{gog → tools/gog}/scripts/cdp/README.md +0 -0
  185. /package/skills/{gog → tools/gog}/scripts/cdp/add_test_users.py +0 -0
  186. /package/skills/{gog → tools/gog}/scripts/cdp/auth_add_accounts.py +0 -0
  187. /package/skills/{gog → tools/gog}/scripts/cdp/auth_add_accounts_manual.py +0 -0
  188. /package/skills/{gog → tools/gog}/scripts/cdp/create_oauth_client.py +0 -0
  189. /package/skills/{gog → tools/gog}/scripts/cdp/launch_cdp_chrome.sh +0 -0
  190. /package/skills/{goplaces → tools/goplaces}/SKILL.md +0 -0
  191. /package/skills/{imsg → tools/imsg}/SKILL.md +0 -0
  192. /package/skills/{local-places → tools/local-places}/SERVER_README.md +0 -0
  193. /package/skills/{local-places → tools/local-places}/SKILL.md +0 -0
  194. /package/skills/{local-places → tools/local-places}/pyproject.toml +0 -0
  195. /package/skills/{local-places → tools/local-places}/src/local_places/__init__.py +0 -0
  196. /package/skills/{local-places → tools/local-places}/src/local_places/__pycache__/__init__.cpython-314.pyc +0 -0
  197. /package/skills/{local-places → tools/local-places}/src/local_places/__pycache__/google_places.cpython-314.pyc +0 -0
  198. /package/skills/{local-places → tools/local-places}/src/local_places/__pycache__/main.cpython-314.pyc +0 -0
  199. /package/skills/{local-places → tools/local-places}/src/local_places/__pycache__/schemas.cpython-314.pyc +0 -0
  200. /package/skills/{local-places → tools/local-places}/src/local_places/google_places.py +0 -0
  201. /package/skills/{local-places → tools/local-places}/src/local_places/main.py +0 -0
  202. /package/skills/{local-places → tools/local-places}/src/local_places/schemas.py +0 -0
  203. /package/skills/{mcporter → tools/mcporter}/SKILL.md +0 -0
  204. /package/skills/{model-usage → tools/model-usage}/SKILL.md +0 -0
  205. /package/skills/{model-usage → tools/model-usage}/references/codexbar-cli.md +0 -0
  206. /package/skills/{model-usage → tools/model-usage}/scripts/model_usage.py +0 -0
  207. /package/skills/{nano-banana-pro → tools/nano-banana-pro}/SKILL.md +0 -0
  208. /package/skills/{nano-banana-pro → tools/nano-banana-pro}/scripts/generate_image.py +0 -0
  209. /package/skills/{nano-pdf → tools/nano-pdf}/SKILL.md +0 -0
  210. /package/skills/{nexus-cloud → tools/nexus-cloud}/docs/security.md +0 -0
  211. /package/skills/{nexus-cloud → tools/nexus-cloud}/docs/troubleshooting.md +0 -0
  212. /package/skills/{obsidian → tools/obsidian}/SKILL.md +0 -0
  213. /package/skills/{openai-image-gen → tools/openai-image-gen}/SKILL.md +0 -0
  214. /package/skills/{openai-image-gen → tools/openai-image-gen}/scripts/gen.py +0 -0
  215. /package/skills/{openai-whisper → tools/openai-whisper}/SKILL.md +0 -0
  216. /package/skills/{openai-whisper-api → tools/openai-whisper-api}/SKILL.md +0 -0
  217. /package/skills/{openai-whisper-api → tools/openai-whisper-api}/scripts/transcribe.sh +0 -0
  218. /package/skills/{openhue → tools/openhue}/SKILL.md +0 -0
  219. /package/skills/{oracle → tools/oracle}/SKILL.md +0 -0
  220. /package/skills/{ordercli → tools/ordercli}/SKILL.md +0 -0
  221. /package/skills/{peekaboo → tools/peekaboo}/SKILL.md +0 -0
  222. /package/skills/{qmd → tools/qmd}/SKILL.md +0 -0
  223. /package/skills/{qmd → tools/qmd}/docs/mcp.md +0 -0
  224. /package/skills/{qmd → tools/qmd}/docs/ollama.md +0 -0
  225. /package/skills/{qmd → tools/qmd}/docs/setup.md +0 -0
  226. /package/skills/{sag → tools/sag}/SKILL.md +0 -0
  227. /package/skills/{skill-cli-template → tools/skill-cli-template}/SKILL.md +0 -0
  228. /package/skills/{songsee → tools/songsee}/SKILL.md +0 -0
  229. /package/skills/{sonoscli → tools/sonoscli}/SKILL.md +0 -0
  230. /package/skills/{spotify-player → tools/spotify-player}/SKILL.md +0 -0
  231. /package/skills/{summarize → tools/summarize}/SKILL.md +0 -0
  232. /package/skills/{things-mac → tools/things-mac}/SKILL.md +0 -0
  233. /package/skills/{tmux → tools/tmux}/SKILL.md +0 -0
  234. /package/skills/{tmux → tools/tmux}/scripts/find-sessions.sh +0 -0
  235. /package/skills/{tmux → tools/tmux}/scripts/wait-for-text.sh +0 -0
  236. /package/skills/{trello → tools/trello}/SKILL.md +0 -0
  237. /package/skills/{upstream-sync → tools/upstream-sync}/SKILL.md +0 -0
  238. /package/skills/{upstream-sync → tools/upstream-sync}/scripts/auto-port.sh +0 -0
  239. /package/skills/{upstream-sync → tools/upstream-sync}/scripts/check-all.sh +0 -0
  240. /package/skills/{upstream-sync → tools/upstream-sync}/scripts/check-nexus.sh +0 -0
  241. /package/skills/{upstream-sync → tools/upstream-sync}/scripts/check-pi-ai.sh +0 -0
  242. /package/skills/{video-frames → tools/video-frames}/SKILL.md +0 -0
  243. /package/skills/{video-frames → tools/video-frames}/scripts/frame.sh +0 -0
  244. /package/skills/{weather → tools/weather}/SKILL.md +0 -0
  245. /package/skills/{weather → tools/weather}/docs/usage.md +0 -0
@@ -2,10 +2,44 @@ import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { resolveBootstrapPath, resolveStateDir } from "../config/paths.js";
4
4
  import { resolveAgentId } from "./agent-id.js";
5
+ function parseFrontmatter(content) {
6
+ const frontmatter = {};
7
+ const normalized = content.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
8
+ if (!normalized.startsWith("---"))
9
+ return frontmatter;
10
+ const endIndex = normalized.indexOf("\n---", 3);
11
+ if (endIndex === -1)
12
+ return frontmatter;
13
+ const block = normalized.slice(4, endIndex);
14
+ for (const line of block.split("\n")) {
15
+ const match = line.match(/^([\w-]+)\s*:\s*(.*)$/);
16
+ if (!match)
17
+ continue;
18
+ const key = match[1].trim().toLowerCase();
19
+ const rawValue = match[2].trim();
20
+ if (!key || !rawValue)
21
+ continue;
22
+ const value = (rawValue.startsWith('"') && rawValue.endsWith('"')) ||
23
+ (rawValue.startsWith("'") && rawValue.endsWith("'"))
24
+ ? rawValue.slice(1, -1)
25
+ : rawValue;
26
+ frontmatter[key] = value;
27
+ }
28
+ return frontmatter;
29
+ }
30
+ function escapeRegex(input) {
31
+ return input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
32
+ }
5
33
  function readField(pathname, label) {
6
34
  try {
7
35
  const raw = fs.readFileSync(pathname, "utf-8");
8
- const regex = new RegExp(`^[-*]?\\s*${label}\\s*:\\s*(.+)$`, "im");
36
+ const frontmatter = parseFrontmatter(raw);
37
+ const key = label.trim().toLowerCase();
38
+ const frontmatterValue = frontmatter[key];
39
+ if (frontmatterValue)
40
+ return frontmatterValue;
41
+ const escaped = escapeRegex(label.trim());
42
+ const regex = new RegExp(`^[-*]?\\s*(?:\\*\\*)?${escaped}(?:\\*\\*)?\\s*:\\s*(.+)$`, "im");
9
43
  const match = raw.match(regex);
10
44
  return match?.[1]?.trim();
11
45
  }
@@ -13,20 +47,8 @@ function readField(pathname, label) {
13
47
  return undefined;
14
48
  }
15
49
  }
16
- function hasPopulatedField(pathname) {
17
- try {
18
- const raw = fs.readFileSync(pathname, "utf-8");
19
- const lines = raw.split(/\r?\n/);
20
- return lines.some((line) => {
21
- const match = line.match(/^[-*]?\s*[^:]+:\s*(.+)$/);
22
- if (!match)
23
- return false;
24
- return match[1].trim().length > 0;
25
- });
26
- }
27
- catch {
28
- return false;
29
- }
50
+ function hasNamedIdentity(pathname) {
51
+ return Boolean(readField(pathname, "Name"));
30
52
  }
31
53
  function resolveAgentFromState(resolution, stateDir) {
32
54
  if (!resolution.ok) {
@@ -37,20 +59,20 @@ function resolveAgentFromState(resolution, stateDir) {
37
59
  };
38
60
  }
39
61
  const agentId = resolution.agentId;
40
- const agentIdentityDir = path.join(stateDir, "agents", agentId, "identity");
41
- const userIdentityDir = path.join(stateDir, "user", "identity");
62
+ const agentIdentityDir = path.join(stateDir, "agents", agentId);
63
+ const userIdentityDir = path.join(stateDir, "user");
42
64
  const agentIdentityPath = path.join(agentIdentityDir, "IDENTITY.md");
43
65
  const agentSoulPath = path.join(agentIdentityDir, "SOUL.md");
44
66
  const agentMemoryPath = path.join(agentIdentityDir, "MEMORY.md");
45
- const userProfilePath = path.join(userIdentityDir, "PROFILE.md");
67
+ const userIdentityPath = path.join(userIdentityDir, "IDENTITY.md");
46
68
  const bootstrapPath = resolveBootstrapPath(undefined, stateDir);
47
69
  const agentIdentityExists = fs.existsSync(agentIdentityPath);
48
70
  const agentSoulExists = fs.existsSync(agentSoulPath);
49
71
  const agentMemoryExists = fs.existsSync(agentMemoryPath);
50
- const userProfileExists = fs.existsSync(userProfilePath);
51
- const hasIdentity = hasPopulatedField(agentIdentityPath) && hasPopulatedField(userProfilePath);
72
+ const userIdentityExists = fs.existsSync(userIdentityPath);
73
+ const hasIdentity = hasNamedIdentity(agentIdentityPath) && hasNamedIdentity(userIdentityPath);
52
74
  const agentName = readField(agentIdentityPath, "Name");
53
- const userName = readField(userProfilePath, "Name");
75
+ const userName = readField(userIdentityPath, "Name");
54
76
  return {
55
77
  ok: true,
56
78
  snapshot: {
@@ -62,12 +84,12 @@ function resolveAgentFromState(resolution, stateDir) {
62
84
  agentIdentityPath,
63
85
  agentSoulPath,
64
86
  agentMemoryPath,
65
- userProfilePath,
87
+ userIdentityPath,
66
88
  bootstrapPath,
67
89
  agentIdentityExists,
68
90
  agentSoulExists,
69
91
  agentMemoryExists,
70
- userProfileExists,
92
+ userIdentityExists,
71
93
  hasIdentity,
72
94
  },
73
95
  };
@@ -2,7 +2,7 @@ import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { loadConfig } from "../config/config.js";
4
4
  import { runCommandWithTimeout } from "../process/exec.js";
5
- import { MANAGED_SKILLS_DIR, resolveUserPath } from "../utils.js";
5
+ import { NEXUS_ROOT, resolveUserPath } from "../utils.js";
6
6
  import { getSkillExecutionType, getSkillScriptConfig, getSkillToolConfig, } from "./skill-tools.js";
7
7
  import { recordSkillUsage } from "./skill-usage.js";
8
8
  import { getSkillMetadata, hasBinary, loadWorkspaceSkillEntries, } from "./skills.js";
@@ -11,7 +11,7 @@ import { DEFAULT_AGENT_WORKSPACE_DIR } from "./workspace.js";
11
11
  function loadSkillContext(name) {
12
12
  const config = loadConfig();
13
13
  const workspaceDir = resolveUserPath(config.agent?.workspace ?? DEFAULT_AGENT_WORKSPACE_DIR);
14
- const managedSkillsDir = MANAGED_SKILLS_DIR;
14
+ const managedSkillsDir = path.join(NEXUS_ROOT, "skills", "managed");
15
15
  const entries = loadWorkspaceSkillEntries(workspaceDir, {
16
16
  config,
17
17
  managedSkillsDir,
@@ -200,6 +200,8 @@ export async function verifySkill(name) {
200
200
  return { ok: false, error: `Missing requirements: ${missingSummary}` };
201
201
  }
202
202
  const execType = getSkillExecutionType(entry.skill.name);
203
+ const metadata = getSkillMetadata(entry);
204
+ const metaType = metadata?.type;
203
205
  if (execType === "prompt") {
204
206
  return { ok: true, message: "Prompt-only skill requires no verification." };
205
207
  }
@@ -223,6 +225,14 @@ export async function verifySkill(name) {
223
225
  }
224
226
  return { ok: true, message: "Skill verified successfully." };
225
227
  }
228
+ if (execType === "unknown" && (metaType === "tool" || metaType === "connector")) {
229
+ const bins = metadata?.requires?.bins ?? metadata?.requires?.anyBins ?? [];
230
+ const missing = bins.filter((bin) => !hasBinary(bin));
231
+ if (missing.length > 0) {
232
+ return { ok: false, error: `Missing binary: ${missing.join(", ")}` };
233
+ }
234
+ return { ok: true, message: "Skill appears configured." };
235
+ }
226
236
  if (execType === "script") {
227
237
  const scriptConfig = getSkillScriptConfig(entry.skill.name);
228
238
  if (!scriptConfig) {
@@ -1,22 +1,20 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { loadConfig } from "../config/config.js";
4
- import { MANAGED_SKILLS_DIR, resolveUserPath } from "../utils.js";
4
+ import { SKILLS_STATE_DIR, resolveUserPath } from "../utils.js";
5
5
  import { loadWorkspaceSkillEntries } from "./skills.js";
6
6
  import { buildWorkspaceSkillStatus } from "./skills-status.js";
7
7
  import { DEFAULT_AGENT_WORKSPACE_DIR } from "./workspace.js";
8
8
  function loadSkillEntries() {
9
9
  const config = loadConfig();
10
10
  const workspaceDir = resolveUserPath(config.agent?.workspace ?? DEFAULT_AGENT_WORKSPACE_DIR);
11
- const managedSkillsDir = MANAGED_SKILLS_DIR;
12
11
  const entries = loadWorkspaceSkillEntries(workspaceDir, {
13
12
  config,
14
- managedSkillsDir,
15
13
  });
16
- return { config, workspaceDir, managedSkillsDir, entries };
14
+ return { config, workspaceDir, entries };
17
15
  }
18
16
  function resolveUsageLogPath(name) {
19
- return path.join(MANAGED_SKILLS_DIR, name, "usage.log");
17
+ return path.join(SKILLS_STATE_DIR, name, "usage.log");
20
18
  }
21
19
  function parseUsageEntry(line) {
22
20
  try {
@@ -110,10 +108,9 @@ export async function getSkillStats(name, opts) {
110
108
  };
111
109
  }
112
110
  export async function getAggregateStats(opts) {
113
- const { config, workspaceDir, managedSkillsDir, entries } = loadSkillEntries();
111
+ const { config, workspaceDir, entries } = loadSkillEntries();
114
112
  const status = buildWorkspaceSkillStatus(workspaceDir, {
115
113
  config,
116
- managedSkillsDir,
117
114
  entries,
118
115
  });
119
116
  const sinceMs = opts?.windowDays && opts.windowDays > 0
@@ -1,4 +1,5 @@
1
- import { MANAGED_SKILLS_DIR } from "../utils.js";
1
+ import path from "node:path";
2
+ import { NEXUS_ROOT } from "../utils.js";
2
3
  import { getSkillMetadata, hasBinary, isBundledSkillAllowed, isConfigPathTruthy, loadWorkspaceSkillEntries, resolveBundledAllowlist, resolveConfigPath, resolveSkillConfig, resolveSkillsInstallPreferences, } from "./skills.js";
3
4
  function resolveSkillKey(entry) {
4
5
  return getSkillMetadata(entry)?.skillKey ?? entry.skill.name;
@@ -146,7 +147,7 @@ function buildSkillStatus(entry, config, prefs) {
146
147
  };
147
148
  }
148
149
  export function buildWorkspaceSkillStatus(workspaceDir, opts) {
149
- const managedSkillsDir = opts?.managedSkillsDir ?? MANAGED_SKILLS_DIR;
150
+ const managedSkillsDir = opts?.managedSkillsDir ?? path.join(NEXUS_ROOT, "skills", "managed");
150
151
  const skillEntries = opts?.entries ?? loadWorkspaceSkillEntries(workspaceDir, opts);
151
152
  const prefs = resolveSkillsInstallPreferences(opts?.config);
152
153
  return {
@@ -2,7 +2,7 @@ import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { formatSkillsForPrompt, loadSkillsFromDir, } from "@mariozechner/pi-coding-agent";
5
- import { MANAGED_SKILLS_DIR, resolveUserPath } from "../utils.js";
5
+ import { NEXUS_ROOT, resolveUserPath } from "../utils.js";
6
6
  function resolveBundledSkillsDir() {
7
7
  const override = process.env.NEXUS_BUNDLED_SKILLS_DIR?.trim();
8
8
  if (override)
@@ -41,6 +41,13 @@ function stripQuotes(value) {
41
41
  }
42
42
  return value;
43
43
  }
44
+ function resolveSkillRootDirs(rootDir) {
45
+ const typedDirs = ["tools", "connectors", "guides"].map((segment) => path.join(rootDir, segment));
46
+ const existingTyped = typedDirs.filter((dir) => fs.existsSync(dir));
47
+ if (existingTyped.length > 0)
48
+ return existingTyped;
49
+ return fs.existsSync(rootDir) ? [rootDir] : [];
50
+ }
44
51
  function parseFrontmatter(content) {
45
52
  const frontmatter = {};
46
53
  const normalized = content.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
@@ -398,36 +405,24 @@ function loadSkillEntries(workspaceDir, opts) {
398
405
  }
399
406
  return [];
400
407
  };
401
- const managedSkillsDir = opts?.managedSkillsDir ?? MANAGED_SKILLS_DIR;
402
- const workspaceSkillsDir = path.join(workspaceDir, "skills");
408
+ const workspaceSkillsRoot = path.join(NEXUS_ROOT, "skills");
409
+ const userSkillsRoot = path.join(resolveUserPath(workspaceDir), "skills");
410
+ const managedSkillsDir = opts?.managedSkillsDir ?? path.join(workspaceSkillsRoot, "managed");
403
411
  const bundledSkillsDir = opts?.bundledSkillsDir ?? resolveBundledSkillsDir();
404
412
  const extraDirsRaw = opts?.config?.skills?.load?.extraDirs ?? [];
405
413
  const extraDirs = extraDirsRaw
406
414
  .map((d) => (typeof d === "string" ? d.trim() : ""))
407
415
  .filter(Boolean);
416
+ const loadFromDirs = (dirs, source) => dirs.flatMap((dir) => loadSkills({ dir, source }));
408
417
  const bundledSkills = bundledSkillsDir
409
- ? loadSkills({
410
- dir: bundledSkillsDir,
411
- source: "nexus-bundled",
412
- })
418
+ ? loadFromDirs(resolveSkillRootDirs(bundledSkillsDir), "nexus-bundled")
413
419
  : [];
414
- const extraSkills = extraDirs.flatMap((dir) => {
415
- const resolved = resolveUserPath(dir);
416
- return loadSkills({
417
- dir: resolved,
418
- source: "nexus-extra",
419
- });
420
- });
421
- const managedSkills = loadSkills({
422
- dir: managedSkillsDir,
423
- source: "nexus-managed",
424
- });
425
- const workspaceSkills = loadSkills({
426
- dir: workspaceSkillsDir,
427
- source: "nexus-workspace",
428
- });
420
+ const extraSkills = extraDirs.flatMap((dir) => loadFromDirs(resolveSkillRootDirs(resolveUserPath(dir)), "nexus-extra"));
421
+ const managedSkills = loadFromDirs(resolveSkillRootDirs(managedSkillsDir), "nexus-managed");
422
+ const workspaceSkills = loadFromDirs(resolveSkillRootDirs(workspaceSkillsRoot), "nexus-workspace");
423
+ const userSkills = loadFromDirs(resolveSkillRootDirs(userSkillsRoot), "nexus-user");
429
424
  const merged = new Map();
430
- // Precedence: extra < bundled < managed < workspace
425
+ // Precedence: extra < bundled < managed < workspace < user
431
426
  for (const skill of extraSkills)
432
427
  merged.set(skill.name, skill);
433
428
  for (const skill of bundledSkills)
@@ -436,6 +431,8 @@ function loadSkillEntries(workspaceDir, opts) {
436
431
  merged.set(skill.name, skill);
437
432
  for (const skill of workspaceSkills)
438
433
  merged.set(skill.name, skill);
434
+ for (const skill of userSkills)
435
+ merged.set(skill.name, skill);
439
436
  const skillEntries = Array.from(merged.values()).map((skill) => {
440
437
  let frontmatter = {};
441
438
  try {
@@ -3,7 +3,7 @@ import os from "node:os";
3
3
  import path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
5
  import { resolveBootstrapPath, resolveStateDir } from "../config/paths.js";
6
- import { MANAGED_SKILLS_DIR, NEXUS_ROOT, resolveUserPath } from "../utils.js";
6
+ import { NEXUS_ROOT, SKILLS_STATE_DIR, resolveUserPath } from "../utils.js";
7
7
  export function resolveDefaultAgentWorkspaceDir(env = process.env, homedir = os.homedir) {
8
8
  const profile = env.NEXUS_PROFILE?.trim();
9
9
  if (profile && profile.toLowerCase() !== "default") {
@@ -16,7 +16,8 @@ export const DEFAULT_AGENTS_FILENAME = "AGENTS.md";
16
16
  export const DEFAULT_SOUL_FILENAME = "SOUL.md";
17
17
  export const DEFAULT_TOOLS_FILENAME = "TOOLS.md";
18
18
  export const DEFAULT_IDENTITY_FILENAME = "IDENTITY.md";
19
- export const DEFAULT_USER_FILENAME = "PROFILE.md";
19
+ export const DEFAULT_USER_FILENAME = "IDENTITY.md";
20
+ export const DEFAULT_USER_TEMPLATE_NAME = "USER.md";
20
21
  export const DEFAULT_BOOTSTRAP_FILENAME = "BOOTSTRAP.md";
21
22
  const DEFAULT_AGENTS_TEMPLATE = `# AGENTS.md - Nexus Workspace
22
23
 
@@ -31,10 +32,10 @@ nexus status
31
32
  That command tells you who you are, what you can do, and what to do next.
32
33
 
33
34
  ## Identity & memory
34
- - Agent identity: state/agents/{agent}/identity/IDENTITY.md
35
- - Agent values: state/agents/{agent}/identity/SOUL.md
36
- - Agent memory: state/agents/{agent}/identity/MEMORY.md
37
- - User profile: state/user/identity/PROFILE.md
35
+ - Agent identity: state/agents/{agent}/IDENTITY.md
36
+ - Agent values: state/agents/{agent}/SOUL.md
37
+ - Agent memory: state/agents/{agent}/MEMORY.md
38
+ - User identity: state/user/IDENTITY.md
38
39
 
39
40
  ## User workspace
40
41
  The user-owned workspace lives in home/. Do not modify it without permission.
@@ -84,32 +85,44 @@ The agent will write identity files as you chat (takes ~5 min).
84
85
  You are beginning the bootstrap conversation. Goals:
85
86
 
86
87
  1) Learn the user's name
87
- → Write: state/user/identity/PROFILE.md
88
+ → Write: state/user/IDENTITY.md
88
89
 
89
90
  2) Let the user name you
90
- → Write: state/agents/{agent}/identity/IDENTITY.md
91
+ → Write: state/agents/{agent}/IDENTITY.md
91
92
 
92
93
  3) Define personality and boundaries
93
- → Write: state/agents/{agent}/identity/SOUL.md
94
+ → Write: state/agents/{agent}/SOUL.md
94
95
 
95
96
  4) Initialize long-term memory
96
- → Write: state/agents/{agent}/identity/MEMORY.md
97
+ → Write: state/agents/{agent}/MEMORY.md
97
98
 
98
99
  Be warm, curious, and conversational. Don't rush a checklist.
99
100
 
100
101
  When complete, run \`nexus status\` to show what's unlocked.
101
102
  `;
102
- const DEFAULT_IDENTITY_TEMPLATE = `# IDENTITY.md - Agent Identity
103
+ const DEFAULT_IDENTITY_TEMPLATE = `---
104
+ name:
105
+ emoji:
106
+ creature:
107
+ vibe:
108
+ ---
109
+ # IDENTITY.md - Agent Identity
103
110
 
104
111
  - Name:
105
112
  - Creature:
106
113
  - Vibe:
107
114
  - Emoji:
108
115
  `;
109
- const DEFAULT_USER_TEMPLATE = `# PROFILE.md - User Profile
116
+ const DEFAULT_USER_TEMPLATE = `---
117
+ name:
118
+ call:
119
+ pronouns:
120
+ timezone:
121
+ ---
122
+ # IDENTITY.md - About Your Human
110
123
 
111
124
  - Name:
112
- - Preferred address:
125
+ - What to call them:
113
126
  - Pronouns (optional):
114
127
  - Timezone (optional):
115
128
  - Notes:
@@ -169,9 +182,9 @@ export async function ensureAgentWorkspace(params) {
169
182
  const stateDir = resolveStateDir();
170
183
  const nexusStateDir = path.join(stateDir, "nexus");
171
184
  const agentId = process.env.NEXUS_AGENT_ID?.trim() || "default";
172
- const agentIdentityDir = path.join(stateDir, "agents", agentId, "identity");
173
- const userIdentityDir = path.join(stateDir, "user", "identity");
174
- const skillsStateDir = MANAGED_SKILLS_DIR;
185
+ const agentIdentityDir = path.join(stateDir, "agents", agentId);
186
+ const userIdentityDir = path.join(stateDir, "user");
187
+ const skillsStateDir = SKILLS_STATE_DIR;
175
188
  const credentialsDir = path.join(stateDir, "credentials");
176
189
  await fs.mkdir(nexusStateDir, { recursive: true });
177
190
  await fs.mkdir(agentIdentityDir, { recursive: true });
@@ -192,7 +205,7 @@ export async function ensureAgentWorkspace(params) {
192
205
  const soulTemplate = await loadTemplate(DEFAULT_SOUL_FILENAME, DEFAULT_SOUL_TEMPLATE);
193
206
  const toolsTemplate = await loadTemplate(DEFAULT_TOOLS_FILENAME, DEFAULT_TOOLS_TEMPLATE);
194
207
  const identityTemplate = await loadTemplate(DEFAULT_IDENTITY_FILENAME, DEFAULT_IDENTITY_TEMPLATE);
195
- const userTemplate = await loadTemplate(DEFAULT_USER_FILENAME, DEFAULT_USER_TEMPLATE);
208
+ const userTemplate = await loadTemplate(DEFAULT_USER_TEMPLATE_NAME, DEFAULT_USER_TEMPLATE);
196
209
  const memoryTemplate = DEFAULT_MEMORY_TEMPLATE;
197
210
  const bootstrapTemplate = await loadTemplate(DEFAULT_BOOTSTRAP_FILENAME, DEFAULT_BOOTSTRAP_TEMPLATE);
198
211
  if (createHomeLayout) {
@@ -221,8 +234,8 @@ export async function loadWorkspaceBootstrapFiles(dir) {
221
234
  const resolvedDir = resolveUserPath(dir);
222
235
  const stateDir = resolveStateDir();
223
236
  const agentId = process.env.NEXUS_AGENT_ID?.trim() || "default";
224
- const agentIdentityDir = path.join(stateDir, "agents", agentId, "identity");
225
- const userIdentityDir = path.join(stateDir, "user", "identity");
237
+ const agentIdentityDir = path.join(stateDir, "agents", agentId);
238
+ const userIdentityDir = path.join(stateDir, "user");
226
239
  const bootstrapPath = resolveBootstrapPath();
227
240
  const entries = [
228
241
  {
@@ -3,7 +3,7 @@ import path from "node:path";
3
3
  import { getSkillMetadata, isConfigPathTruthy, loadWorkspaceSkillEntries, resolveRuntimePlatform, resolveSkillConfig, } from "../agents/skills.js";
4
4
  import { loadConfig } from "../config/config.js";
5
5
  import { ensureCredentialIndexSync } from "../credentials/store.js";
6
- import { MANAGED_SKILLS_DIR, NEXUS_ROOT } from "../utils.js";
6
+ import { NEXUS_ROOT, SKILLS_STATE_DIR } from "../utils.js";
7
7
  import { loadCapabilityRegistry } from "./registry.js";
8
8
  const STATUS_PRIORITY = [
9
9
  "active",
@@ -57,7 +57,7 @@ function setupLooksCredentialed(raw) {
57
57
  lowered.includes("key"));
58
58
  }
59
59
  function detectSkillUsageActive(skillName) {
60
- const usageLog = path.join(MANAGED_SKILLS_DIR, skillName, "usage.log");
60
+ const usageLog = path.join(SKILLS_STATE_DIR, skillName, "usage.log");
61
61
  try {
62
62
  const stat = fs.statSync(usageLog);
63
63
  return stat.isFile() && stat.size > 0;
@@ -2,6 +2,7 @@ import { spawn } from "node:child_process";
2
2
  import crypto from "node:crypto";
3
3
  import fs from "node:fs";
4
4
  import path from "node:path";
5
+ import { fileURLToPath } from "node:url";
5
6
  import { scanCredentials } from "../commands/credential.js";
6
7
  import { openUrl } from "../commands/onboard-helpers.js";
7
8
  import { resolveDefaultEnvVar, storeKeychainSecret, writeCredentialRecord, } from "../credentials/store.js";
@@ -208,6 +209,56 @@ function resolveRepoRoot(argv1 = process.argv[1]) {
208
209
  }
209
210
  return null;
210
211
  }
212
+ function resolveModuleRoot() {
213
+ try {
214
+ let dir = path.dirname(fileURLToPath(import.meta.url));
215
+ for (let i = 0; i < 6; i += 1) {
216
+ if (fs.existsSync(path.join(dir, "package.json")))
217
+ return dir;
218
+ const parent = path.dirname(dir);
219
+ if (parent === dir)
220
+ break;
221
+ dir = parent;
222
+ }
223
+ }
224
+ catch {
225
+ return null;
226
+ }
227
+ return null;
228
+ }
229
+ function resolvePackageRoot(argv1 = process.argv[1]) {
230
+ const moduleRoot = resolveModuleRoot();
231
+ if (moduleRoot)
232
+ return moduleRoot;
233
+ if (!argv1)
234
+ return null;
235
+ let normalized = path.resolve(argv1);
236
+ try {
237
+ normalized = fs.realpathSync(normalized);
238
+ }
239
+ catch {
240
+ // ignore
241
+ }
242
+ const parts = normalized.split(path.sep);
243
+ const distIndex = parts.lastIndexOf("dist");
244
+ if (distIndex !== -1) {
245
+ return parts.slice(0, distIndex).join(path.sep);
246
+ }
247
+ return null;
248
+ }
249
+ function resolveBundledCloudBinary(packageRoot) {
250
+ const ext = process.platform === "win32" ? ".exe" : "";
251
+ const platformId = `${process.platform}-${process.arch}`;
252
+ const candidates = [
253
+ path.join(packageRoot, "dist", "native", "nexus-cloud", platformId, `nexus-cloud-rs${ext}`),
254
+ path.join(packageRoot, "dist", "native", "nexus-cloud", `nexus-cloud-rs${ext}`),
255
+ ];
256
+ for (const candidate of candidates) {
257
+ if (fs.existsSync(candidate))
258
+ return candidate;
259
+ }
260
+ return null;
261
+ }
211
262
  function resolveCloudRunner(args) {
212
263
  const env = { ...process.env };
213
264
  if (!env.NEXUS_HOME && NEXUS_ROOT) {
@@ -217,6 +268,13 @@ function resolveCloudRunner(args) {
217
268
  if (override) {
218
269
  return { command: override, args, env };
219
270
  }
271
+ const packageRoot = resolvePackageRoot();
272
+ if (packageRoot) {
273
+ const bundled = resolveBundledCloudBinary(packageRoot);
274
+ if (bundled) {
275
+ return { command: bundled, args, env };
276
+ }
277
+ }
220
278
  const repoRoot = resolveRepoRoot();
221
279
  if (repoRoot) {
222
280
  const nativeRoot = path.join(repoRoot, "native", "nexus-cloud");
@@ -1,5 +1,6 @@
1
1
  import { cancel, confirm, isCancel } from "@clack/prompts";
2
2
  import { addCredential, flagCredential, getCredential, getCredentialPaths, getCredentialValue, importCliCredential, listCredentials, removeCredential, scanCredentialEnv, verifyCredentials, } from "../commands/credential.js";
3
+ import { listCredentialEntries } from "../credentials/store.js";
3
4
  function parseFields(raw, fieldsArgs) {
4
5
  const out = {};
5
6
  if (raw) {
@@ -81,18 +82,47 @@ export function registerCredentialCli(program) {
81
82
  }
82
83
  });
83
84
  credential
84
- .command("get")
85
+ .command("get [serviceAccount]")
85
86
  .description("Get a credential value")
86
- .requiredOption("--service <id>", "Service id")
87
- .requiredOption("--account <id>", "Account id")
88
- .requiredOption("--auth <id>", "Auth id")
87
+ .option("--service <id>", "Service id")
88
+ .option("--account <id>", "Account id")
89
+ .option("--auth <id>", "Auth id")
89
90
  .option("--json", "Output as JSON")
90
91
  .option("--record", "Show credential record instead of value")
91
- .action(async (opts) => {
92
+ .action(async (serviceAccount, opts) => {
93
+ let service = opts.service;
94
+ let account = opts.account;
95
+ let authId = opts.auth;
96
+ if (serviceAccount && typeof serviceAccount === "string") {
97
+ const parts = serviceAccount.split("/").filter(Boolean);
98
+ if (parts.length >= 2) {
99
+ service = service ?? parts[0];
100
+ account = account ?? parts[1];
101
+ if (parts.length >= 3) {
102
+ authId = authId ?? parts.slice(2).join("/");
103
+ }
104
+ }
105
+ }
106
+ if (!service || !account) {
107
+ console.error("Missing service/account. Use service/account or flags.");
108
+ process.exit(1);
109
+ }
110
+ if (!authId) {
111
+ const entries = await listCredentialEntries();
112
+ const matches = entries.filter((entry) => entry.service === service && entry.account === account);
113
+ const auths = Array.from(new Set(matches.map((entry) => entry.authId)));
114
+ if (auths.length === 1) {
115
+ authId = auths[0];
116
+ }
117
+ else {
118
+ console.error(`Missing --auth. Available auth ids: ${auths.join(", ") || "none"}`);
119
+ process.exit(1);
120
+ }
121
+ }
92
122
  const params = {
93
- service: opts.service,
94
- account: opts.account,
95
- authId: opts.auth,
123
+ service,
124
+ account,
125
+ authId,
96
126
  };
97
127
  if (opts.record) {
98
128
  const result = await getCredential(params);
@@ -269,6 +299,8 @@ export function registerCredentialCli(program) {
269
299
  .command("scan")
270
300
  .description("Scan environment variables for credentials")
271
301
  .option("--deep", "Scan all environment variables for credential patterns")
302
+ .option("--import", "Import detected credentials into the store")
303
+ .option("--account <id>", "Account id for imported credentials")
272
304
  .option("--yes", "Skip confirmation prompts")
273
305
  .option("--json", "Output as JSON")
274
306
  .action(async (opts) => {
@@ -283,6 +315,43 @@ export function registerCredentialCli(program) {
283
315
  }
284
316
  }
285
317
  const result = scanCredentialEnv({ deep: Boolean(opts.deep) });
318
+ if (opts.import) {
319
+ const accountOverride = typeof opts.account === "string" && opts.account.trim()
320
+ ? opts.account.trim()
321
+ : null;
322
+ const importable = [
323
+ ...result.known,
324
+ ...(result.deep ? result.discovered : []),
325
+ ].filter((entry) => entry.service && entry.type);
326
+ const existing = await listCredentialEntries();
327
+ const existingKeys = new Set(existing.map((entry) => `${entry.service}::${entry.account}::${entry.authId}`));
328
+ const imported = [];
329
+ const skipped = [];
330
+ for (const entry of importable) {
331
+ const account = accountOverride ?? `env:${entry.env}`;
332
+ const authId = entry.type ?? "token";
333
+ const key = `${entry.service}::${account}::${authId}`;
334
+ if (existingKeys.has(key)) {
335
+ skipped.push(`${entry.service}/${account}/${authId}`);
336
+ continue;
337
+ }
338
+ await addCredential({
339
+ service: entry.service ?? "unknown",
340
+ account,
341
+ type: authId,
342
+ storage: { provider: "env", var: entry.env },
343
+ });
344
+ imported.push(`${entry.service}/${account}/${authId}`);
345
+ }
346
+ if (opts.json) {
347
+ console.log(JSON.stringify({ imported, skipped, total: importable.length }, null, 2));
348
+ return;
349
+ }
350
+ console.log(`Imported: ${imported.length}`);
351
+ if (skipped.length > 0) {
352
+ console.log(`Skipped (already exists): ${skipped.length}`);
353
+ }
354
+ }
286
355
  if (opts.json) {
287
356
  console.log(JSON.stringify(result, null, 2));
288
357
  return;
@@ -1,5 +1,6 @@
1
1
  import { Command } from "commander";
2
2
  import { capabilitiesCommand } from "../commands/capabilities.js";
3
+ import { configGetCommand, configListCommand, configSetCommand, } from "../commands/config.js";
3
4
  import { configViewCommand } from "../commands/config-view.js";
4
5
  import { identityCommand } from "../commands/identity.js";
5
6
  import { initCommand } from "../commands/init.js";
@@ -167,13 +168,34 @@ export function buildProgram() {
167
168
  : undefined;
168
169
  await identityCommand({ target: normalized, json: Boolean(opts.json) }, defaultRuntime);
169
170
  });
170
- program
171
- .command("config")
171
+ const config = program.command("config").description("Manage config");
172
+ config
172
173
  .description("Show config path and status")
173
174
  .option("--json", "Output as JSON")
174
175
  .action(async (opts) => {
175
176
  await configViewCommand({ json: Boolean(opts.json) }, defaultRuntime);
176
177
  });
178
+ config
179
+ .command("list")
180
+ .description("List config values")
181
+ .option("--json", "Output as JSON")
182
+ .action(async (opts) => {
183
+ await configListCommand({ json: Boolean(opts.json) }, defaultRuntime);
184
+ });
185
+ config
186
+ .command("get <key>")
187
+ .description("Get a config value")
188
+ .option("--json", "Output as JSON")
189
+ .action(async (key, opts) => {
190
+ await configGetCommand({ key, json: Boolean(opts.json) }, defaultRuntime);
191
+ });
192
+ config
193
+ .command("set <key> <value>")
194
+ .description("Set a config value")
195
+ .option("--json", "Output as JSON")
196
+ .action(async (key, value, opts) => {
197
+ await configSetCommand({ key, value, json: Boolean(opts.json) }, defaultRuntime);
198
+ });
177
199
  program
178
200
  .command("update")
179
201
  .description("Update nexus CLI")