@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.
- package/dist/agents/identity-state.js +45 -23
- package/dist/agents/skill-runner.js +12 -2
- package/dist/agents/skill-usage.js +4 -7
- package/dist/agents/skills-status.js +3 -2
- package/dist/agents/skills.js +20 -23
- package/dist/agents/workspace.js +32 -19
- package/dist/capabilities/detector.js +2 -2
- package/dist/cli/cloud-cli.js +58 -0
- package/dist/cli/credential-cli.js +77 -8
- package/dist/cli/program.js +24 -2
- package/dist/cli/skills-cli.js +30 -18
- package/dist/cli/skills-hub-cli.js +9 -7
- package/dist/commands/bootstrap-preset.js +16 -6
- package/dist/commands/config.js +85 -0
- package/dist/commands/cursor-hooks.js +240 -0
- package/dist/commands/cursor-rules.js +13 -207
- package/dist/commands/identity.js +3 -3
- package/dist/commands/init.js +293 -6
- package/dist/commands/onboard-eve-identity.js +1 -1
- package/dist/commands/skills-manifest.js +89 -29
- package/dist/commands/status.js +52 -50
- package/dist/daemon/launchd.js +14 -0
- package/dist/entry.js +0 -0
- package/dist/native/nexus-cloud/darwin-arm64/nexus-cloud +0 -0
- package/dist/native/nexus-cloud/darwin-arm64/nexus-cloud-rs +0 -0
- package/dist/utils.js +6 -2
- package/docs/AGENTS.default.md +1 -1
- package/docs/configuration.md +1 -1
- package/docs/feature-inventory/overview.md +2 -2
- package/docs/reference/templates/AGENTS.md +172 -109
- package/docs/templates/AGENTS.md +140 -199
- package/docs/templates/BOOTSTRAP.md +40 -20
- package/docs/templates/IDENTITY.md +6 -0
- package/docs/templates/USER.md +22 -2
- package/package.json +3 -1
- package/skills/{notion → connectors/notion}/SKILL.md +1 -1
- package/skills/{filesystem → guides/filesystem}/SKILL.md +1 -1
- package/skills/{onboarding → guides/onboarding}/SKILL.md +1 -1
- package/skills/{onboarding → guides/onboarding}/docs/CAPABILITY_TAXONOMY.md +5 -5
- package/skills/{onboarding → guides/onboarding}/docs/CLI_GRAMMAR.md +8 -8
- package/skills/{onboarding → guides/onboarding}/docs/CLI_GRAMMAR_ONBOARDING.md +2 -2
- package/skills/{onboarding → guides/onboarding}/docs/CLI_GRAMMAR_SKILLS.md +26 -20
- package/skills/{onboarding → guides/onboarding}/docs/GOAL_STATE_ARCHITECTURE.md +38 -43
- package/skills/{onboarding → guides/onboarding}/docs/NEXUS_SYSTEM_OVERVIEW.md +4 -4
- package/skills/{onboarding → guides/onboarding}/docs/SKILLS_HUB_SPEC.md +1 -1
- package/skills/{onboarding → guides/onboarding}/docs/SKILLS_SPECIFICATION.md +8 -7
- package/skills/{onboarding → guides/onboarding}/docs/SKILL_GATEWAY_DESIGN.md +16 -16
- package/skills/{onboarding → guides/onboarding}/docs/SKILL_GATEWAY_PRD.md +10 -12
- package/skills/guides/onboarding/docs/canonical/00_CONFLICT_ANALYSIS.md +463 -0
- package/skills/guides/onboarding/docs/canonical/01_NEXUS_OVERVIEW.md +167 -0
- package/skills/guides/onboarding/docs/canonical/02_CLI_REFERENCE.md +404 -0
- package/skills/guides/onboarding/docs/canonical/03_STATE_ARCHITECTURE.md +357 -0
- package/skills/guides/onboarding/docs/canonical/04_SKILL_SPECIFICATION.md +393 -0
- package/skills/guides/onboarding/docs/canonical/05_CAPABILITY_TAXONOMY.md +298 -0
- package/skills/guides/onboarding/docs/canonical/06_CAPABILITIES_REFERENCE.md +207 -0
- package/skills/guides/onboarding/docs/canonical/07_AGENT_BINDINGS.md +85 -0
- package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/nexus-cloud.md +2 -2
- package/skills/{onboarding → guides/onboarding}/scripts/ralph/progress.txt +1 -1
- package/skills/{nexus-cloud → tools/nexus-cloud}/SKILL.md +2 -1
- package/skills/{nexus-cloud → tools/nexus-cloud}/docs/setup.md +1 -1
- package/docs/templates/PROFILE.md +0 -14
- /package/skills/{brave-search → connectors/brave-search}/SKILL.md +0 -0
- /package/skills/{brave-search → connectors/brave-search}/docs/setup.md +0 -0
- /package/skills/{brave-search → connectors/brave-search}/docs/troubleshooting.md +0 -0
- /package/skills/{brave-search → connectors/brave-search}/docs/usage.md +0 -0
- /package/skills/{brave-search → connectors/brave-search}/scripts/content.mjs +0 -0
- /package/skills/{brave-search → connectors/brave-search}/scripts/search.mjs +0 -0
- /package/skills/{discord → connectors/discord}/SKILL.md +0 -0
- /package/skills/{gemini → connectors/gemini}/SKILL.md +0 -0
- /package/skills/{github → connectors/github}/SKILL.md +0 -0
- /package/skills/{github → connectors/github}/docs/setup.md +0 -0
- /package/skills/{github → connectors/github}/docs/troubleshooting.md +0 -0
- /package/skills/{google-oauth → connectors/google-oauth}/SKILL.md +0 -0
- /package/skills/{slack → connectors/slack}/SKILL.md +0 -0
- /package/skills/{telegram → connectors/telegram}/SKILL.md +0 -0
- /package/skills/{telegram → connectors/telegram}/docs/pairing.md +0 -0
- /package/skills/{telegram → connectors/telegram}/docs/setup.md +0 -0
- /package/skills/{telegram → connectors/telegram}/docs/webhook.md +0 -0
- /package/skills/{wacli → connectors/wacli}/SKILL.md +0 -0
- /package/skills/{wacli → connectors/wacli}/docs/auth.md +0 -0
- /package/skills/{wacli → connectors/wacli}/docs/backup.md +0 -0
- /package/skills/{wacli → connectors/wacli}/docs/troubleshooting.md +0 -0
- /package/skills/{browser-use-agent-sdk → guides/browser-use-agent-sdk}/SKILL.md +0 -0
- /package/skills/{json-render → guides/json-render}/SKILL.md +0 -0
- /package/skills/{json-render → guides/json-render}/assets/components/README.md +0 -0
- /package/skills/{json-render → guides/json-render}/assets/components/catalog.ts +0 -0
- /package/skills/{json-render → guides/json-render}/assets/components/registry.tsx +0 -0
- /package/skills/{json-render → guides/json-render}/assets/demo/App.css +0 -0
- /package/skills/{json-render → guides/json-render}/assets/demo/App.tsx +0 -0
- /package/skills/{json-render → guides/json-render}/assets/demo/README.md +0 -0
- /package/skills/{json-render → guides/json-render}/assets/demo/catalog.ts +0 -0
- /package/skills/{json-render → guides/json-render}/assets/demo/data/nexus-core.json +0 -0
- /package/skills/{json-render → guides/json-render}/assets/demo/index.css +0 -0
- /package/skills/{json-render → guides/json-render}/assets/demo/registry.tsx +0 -0
- /package/skills/{json-render → guides/json-render}/docs/nexus-state-demo.md +0 -0
- /package/skills/{json-render → guides/json-render}/docs/shadcn-preset.md +0 -0
- /package/skills/{json-render → guides/json-render}/scripts/create-vite-demo.sh +0 -0
- /package/skills/{json-render → guides/json-render}/scripts/llm-server/README.md +0 -0
- /package/skills/{json-render → guides/json-render}/scripts/llm-server/catalog.ts +0 -0
- /package/skills/{json-render → guides/json-render}/scripts/llm-server/package-lock.json +0 -0
- /package/skills/{json-render → guides/json-render}/scripts/llm-server/package.json +0 -0
- /package/skills/{json-render → guides/json-render}/scripts/llm-server/server.ts +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/CAPABILITIES.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/CLI_GRAMMAR_CREDENTIALS.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/DOCUMENTATION_OVERVIEW.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/ENTITY_MODEL.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/SKILL_INVENTORY.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/STATE_ARCHITECTURE.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/TROUBLESHOOTING.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/USER_JOURNEY.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/WOW_MOMENTS.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/agent-apple-id.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/1password.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/TEMPLATE.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/aix.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/bird.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/brave-search.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/comms.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/computer-use.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/cron-and-heartbeat.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/eve.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/github.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/gog.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/homebrew-prereqs.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/qmd.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/telegram.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/wacli.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/docs/skill-deep-dives/weather.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/scripts/ralph/prd.json +0 -0
- /package/skills/{onboarding → guides/onboarding}/scripts/ralph/prompt.md +0 -0
- /package/skills/{onboarding → guides/onboarding}/scripts/ralph/ralph.log +0 -0
- /package/skills/{onboarding → guides/onboarding}/scripts/ralph/ralph.sh +0 -0
- /package/skills/{onboarding → guides/onboarding}/scripts/setup-cursor-skills.sh +0 -0
- /package/skills/{1password → tools/1password}/SKILL.md +0 -0
- /package/skills/{1password → tools/1password}/docs/setup.md +0 -0
- /package/skills/{1password → tools/1password}/docs/troubleshooting.md +0 -0
- /package/skills/{1password → tools/1password}/references/cli-examples.md +0 -0
- /package/skills/{1password → tools/1password}/references/get-started.md +0 -0
- /package/skills/{agent-browser → tools/agent-browser}/SKILL.md +0 -0
- /package/skills/{agent-browser → tools/agent-browser}/docs/browser-use-eval.md +0 -0
- /package/skills/{agent-browser → tools/agent-browser}/docs/first-tests.md +0 -0
- /package/skills/{agent-browser → tools/agent-browser}/docs/wordle-nyt-eval.js +0 -0
- /package/skills/{aix → tools/aix}/SKILL.md +0 -0
- /package/skills/{aix → tools/aix}/docs/embeddings.md +0 -0
- /package/skills/{aix → tools/aix}/docs/setup.md +0 -0
- /package/skills/{aix → tools/aix}/docs/troubleshooting.md +0 -0
- /package/skills/{aix → tools/aix}/references/sql.md +0 -0
- /package/skills/{apple-notes → tools/apple-notes}/SKILL.md +0 -0
- /package/skills/{apple-reminders → tools/apple-reminders}/SKILL.md +0 -0
- /package/skills/{bear-notes → tools/bear-notes}/SKILL.md +0 -0
- /package/skills/{bird → tools/bird}/SKILL.md +0 -0
- /package/skills/{bird → tools/bird}/docs/auth.md +0 -0
- /package/skills/{bird → tools/bird}/docs/troubleshooting.md +0 -0
- /package/skills/{blogwatcher → tools/blogwatcher}/SKILL.md +0 -0
- /package/skills/{blucli → tools/blucli}/SKILL.md +0 -0
- /package/skills/{camsnap → tools/camsnap}/SKILL.md +0 -0
- /package/skills/{clawdhub → tools/clawdhub}/SKILL.md +0 -0
- /package/skills/{coding-agent → tools/coding-agent}/SKILL.md +0 -0
- /package/skills/{comms → tools/comms}/SKILL.md +0 -0
- /package/skills/{comms → tools/comms}/docs/adapters.md +0 -0
- /package/skills/{comms → tools/comms}/docs/setup.md +0 -0
- /package/skills/{comms → tools/comms}/docs/troubleshooting.md +0 -0
- /package/skills/{comms → tools/comms}/references/schema.md +0 -0
- /package/skills/{computer-use → tools/computer-use}/SKILL.md +0 -0
- /package/skills/{computer-use → tools/computer-use}/docs/open-interpreter.md +0 -0
- /package/skills/{computer-use → tools/computer-use}/docs/peekaboo.md +0 -0
- /package/skills/{computer-use → tools/computer-use}/docs/setup.md +0 -0
- /package/skills/{computer-use → tools/computer-use}/docs/troubleshooting.md +0 -0
- /package/skills/{eightctl → tools/eightctl}/SKILL.md +0 -0
- /package/skills/{eve → tools/eve}/SKILL.md +0 -0
- /package/skills/{eve → tools/eve}/docs/dual-account.md +0 -0
- /package/skills/{eve → tools/eve}/docs/intelligence.md +0 -0
- /package/skills/{eve → tools/eve}/docs/setup.md +0 -0
- /package/skills/{eve → tools/eve}/docs/troubleshooting.md +0 -0
- /package/skills/{eve → tools/eve}/scripts/setup-dual-account.sh +0 -0
- /package/skills/{food-order → tools/food-order}/SKILL.md +0 -0
- /package/skills/{gh → tools/gh}/SKILL.md +0 -0
- /package/skills/{gh → tools/gh}/docs/usage.md +0 -0
- /package/skills/{gifgrep → tools/gifgrep}/SKILL.md +0 -0
- /package/skills/{gog → tools/gog}/SKILL.md +0 -0
- /package/skills/{gog → tools/gog}/docs/portability.md +0 -0
- /package/skills/{gog → tools/gog}/docs/setup.md +0 -0
- /package/skills/{gog → tools/gog}/docs/troubleshooting.md +0 -0
- /package/skills/{gog → tools/gog}/scripts/cdp/README.md +0 -0
- /package/skills/{gog → tools/gog}/scripts/cdp/add_test_users.py +0 -0
- /package/skills/{gog → tools/gog}/scripts/cdp/auth_add_accounts.py +0 -0
- /package/skills/{gog → tools/gog}/scripts/cdp/auth_add_accounts_manual.py +0 -0
- /package/skills/{gog → tools/gog}/scripts/cdp/create_oauth_client.py +0 -0
- /package/skills/{gog → tools/gog}/scripts/cdp/launch_cdp_chrome.sh +0 -0
- /package/skills/{goplaces → tools/goplaces}/SKILL.md +0 -0
- /package/skills/{imsg → tools/imsg}/SKILL.md +0 -0
- /package/skills/{local-places → tools/local-places}/SERVER_README.md +0 -0
- /package/skills/{local-places → tools/local-places}/SKILL.md +0 -0
- /package/skills/{local-places → tools/local-places}/pyproject.toml +0 -0
- /package/skills/{local-places → tools/local-places}/src/local_places/__init__.py +0 -0
- /package/skills/{local-places → tools/local-places}/src/local_places/__pycache__/__init__.cpython-314.pyc +0 -0
- /package/skills/{local-places → tools/local-places}/src/local_places/__pycache__/google_places.cpython-314.pyc +0 -0
- /package/skills/{local-places → tools/local-places}/src/local_places/__pycache__/main.cpython-314.pyc +0 -0
- /package/skills/{local-places → tools/local-places}/src/local_places/__pycache__/schemas.cpython-314.pyc +0 -0
- /package/skills/{local-places → tools/local-places}/src/local_places/google_places.py +0 -0
- /package/skills/{local-places → tools/local-places}/src/local_places/main.py +0 -0
- /package/skills/{local-places → tools/local-places}/src/local_places/schemas.py +0 -0
- /package/skills/{mcporter → tools/mcporter}/SKILL.md +0 -0
- /package/skills/{model-usage → tools/model-usage}/SKILL.md +0 -0
- /package/skills/{model-usage → tools/model-usage}/references/codexbar-cli.md +0 -0
- /package/skills/{model-usage → tools/model-usage}/scripts/model_usage.py +0 -0
- /package/skills/{nano-banana-pro → tools/nano-banana-pro}/SKILL.md +0 -0
- /package/skills/{nano-banana-pro → tools/nano-banana-pro}/scripts/generate_image.py +0 -0
- /package/skills/{nano-pdf → tools/nano-pdf}/SKILL.md +0 -0
- /package/skills/{nexus-cloud → tools/nexus-cloud}/docs/security.md +0 -0
- /package/skills/{nexus-cloud → tools/nexus-cloud}/docs/troubleshooting.md +0 -0
- /package/skills/{obsidian → tools/obsidian}/SKILL.md +0 -0
- /package/skills/{openai-image-gen → tools/openai-image-gen}/SKILL.md +0 -0
- /package/skills/{openai-image-gen → tools/openai-image-gen}/scripts/gen.py +0 -0
- /package/skills/{openai-whisper → tools/openai-whisper}/SKILL.md +0 -0
- /package/skills/{openai-whisper-api → tools/openai-whisper-api}/SKILL.md +0 -0
- /package/skills/{openai-whisper-api → tools/openai-whisper-api}/scripts/transcribe.sh +0 -0
- /package/skills/{openhue → tools/openhue}/SKILL.md +0 -0
- /package/skills/{oracle → tools/oracle}/SKILL.md +0 -0
- /package/skills/{ordercli → tools/ordercli}/SKILL.md +0 -0
- /package/skills/{peekaboo → tools/peekaboo}/SKILL.md +0 -0
- /package/skills/{qmd → tools/qmd}/SKILL.md +0 -0
- /package/skills/{qmd → tools/qmd}/docs/mcp.md +0 -0
- /package/skills/{qmd → tools/qmd}/docs/ollama.md +0 -0
- /package/skills/{qmd → tools/qmd}/docs/setup.md +0 -0
- /package/skills/{sag → tools/sag}/SKILL.md +0 -0
- /package/skills/{skill-cli-template → tools/skill-cli-template}/SKILL.md +0 -0
- /package/skills/{songsee → tools/songsee}/SKILL.md +0 -0
- /package/skills/{sonoscli → tools/sonoscli}/SKILL.md +0 -0
- /package/skills/{spotify-player → tools/spotify-player}/SKILL.md +0 -0
- /package/skills/{summarize → tools/summarize}/SKILL.md +0 -0
- /package/skills/{things-mac → tools/things-mac}/SKILL.md +0 -0
- /package/skills/{tmux → tools/tmux}/SKILL.md +0 -0
- /package/skills/{tmux → tools/tmux}/scripts/find-sessions.sh +0 -0
- /package/skills/{tmux → tools/tmux}/scripts/wait-for-text.sh +0 -0
- /package/skills/{trello → tools/trello}/SKILL.md +0 -0
- /package/skills/{upstream-sync → tools/upstream-sync}/SKILL.md +0 -0
- /package/skills/{upstream-sync → tools/upstream-sync}/scripts/auto-port.sh +0 -0
- /package/skills/{upstream-sync → tools/upstream-sync}/scripts/check-all.sh +0 -0
- /package/skills/{upstream-sync → tools/upstream-sync}/scripts/check-nexus.sh +0 -0
- /package/skills/{upstream-sync → tools/upstream-sync}/scripts/check-pi-ai.sh +0 -0
- /package/skills/{video-frames → tools/video-frames}/SKILL.md +0 -0
- /package/skills/{video-frames → tools/video-frames}/scripts/frame.sh +0 -0
- /package/skills/{weather → tools/weather}/SKILL.md +0 -0
- /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
|
|
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
|
|
17
|
-
|
|
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
|
|
41
|
-
const userIdentityDir = path.join(stateDir, "user"
|
|
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
|
|
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
|
|
51
|
-
const hasIdentity =
|
|
72
|
+
const userIdentityExists = fs.existsSync(userIdentityPath);
|
|
73
|
+
const hasIdentity = hasNamedIdentity(agentIdentityPath) && hasNamedIdentity(userIdentityPath);
|
|
52
74
|
const agentName = readField(agentIdentityPath, "Name");
|
|
53
|
-
const userName = readField(
|
|
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
|
-
|
|
87
|
+
userIdentityPath,
|
|
66
88
|
bootstrapPath,
|
|
67
89
|
agentIdentityExists,
|
|
68
90
|
agentSoulExists,
|
|
69
91
|
agentMemoryExists,
|
|
70
|
-
|
|
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 {
|
|
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 =
|
|
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 {
|
|
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,
|
|
14
|
+
return { config, workspaceDir, entries };
|
|
17
15
|
}
|
|
18
16
|
function resolveUsageLogPath(name) {
|
|
19
|
-
return path.join(
|
|
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,
|
|
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
|
|
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 ??
|
|
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 {
|
package/dist/agents/skills.js
CHANGED
|
@@ -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 {
|
|
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
|
|
402
|
-
const
|
|
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
|
-
?
|
|
410
|
-
dir: bundledSkillsDir,
|
|
411
|
-
source: "nexus-bundled",
|
|
412
|
-
})
|
|
418
|
+
? loadFromDirs(resolveSkillRootDirs(bundledSkillsDir), "nexus-bundled")
|
|
413
419
|
: [];
|
|
414
|
-
const extraSkills = extraDirs.flatMap((dir) =>
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
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 {
|
package/dist/agents/workspace.js
CHANGED
|
@@ -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 {
|
|
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 = "
|
|
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}/
|
|
35
|
-
- Agent values: state/agents/{agent}/
|
|
36
|
-
- Agent memory: state/agents/{agent}/
|
|
37
|
-
- User
|
|
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/
|
|
88
|
+
→ Write: state/user/IDENTITY.md
|
|
88
89
|
|
|
89
90
|
2) Let the user name you
|
|
90
|
-
→ Write: state/agents/{agent}/
|
|
91
|
+
→ Write: state/agents/{agent}/IDENTITY.md
|
|
91
92
|
|
|
92
93
|
3) Define personality and boundaries
|
|
93
|
-
→ Write: state/agents/{agent}/
|
|
94
|
+
→ Write: state/agents/{agent}/SOUL.md
|
|
94
95
|
|
|
95
96
|
4) Initialize long-term memory
|
|
96
|
-
→ Write: state/agents/{agent}/
|
|
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 =
|
|
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 =
|
|
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
|
-
-
|
|
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
|
|
173
|
-
const userIdentityDir = path.join(stateDir, "user"
|
|
174
|
-
const skillsStateDir =
|
|
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(
|
|
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
|
|
225
|
-
const userIdentityDir = path.join(stateDir, "user"
|
|
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 {
|
|
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(
|
|
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;
|
package/dist/cli/cloud-cli.js
CHANGED
|
@@ -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
|
-
.
|
|
87
|
-
.
|
|
88
|
-
.
|
|
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
|
|
94
|
-
account
|
|
95
|
-
authId
|
|
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;
|
package/dist/cli/program.js
CHANGED
|
@@ -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
|
-
|
|
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")
|