@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
package/dist/cli/skills-cli.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import chalk from "chalk";
|
|
3
|
-
import { getSkillInfo,
|
|
3
|
+
import { getSkillInfo, verifySkill } from "../agents/skill-runner.js";
|
|
4
4
|
import { getAggregateStats, getSkillStats, hasSkillUsage, recordSkillUsage, } from "../agents/skill-usage.js";
|
|
5
5
|
import { getSkillMetadata, loadWorkspaceSkillEntries } from "../agents/skills.js";
|
|
6
6
|
import { buildWorkspaceSkillStatus } from "../agents/skills-status.js";
|
|
7
7
|
import { DEFAULT_AGENT_WORKSPACE_DIR } from "../agents/workspace.js";
|
|
8
8
|
import { loadConfig } from "../config/config.js";
|
|
9
|
-
import {
|
|
9
|
+
import { NEXUS_ROOT, SKILLS_STATE_DIR, resolveUserPath } from "../utils.js";
|
|
10
10
|
const STATUS_ICON = {
|
|
11
11
|
active: "✅",
|
|
12
12
|
ready: "⭐",
|
|
@@ -47,6 +47,7 @@ export function registerSkillsCommand(program) {
|
|
|
47
47
|
.description("List all available skills")
|
|
48
48
|
.option("--json", "Output as JSON")
|
|
49
49
|
.option("--type <type>", "Filter by type (guide|tool|connector)")
|
|
50
|
+
.option("--status <status>", "Filter by status (active|ready|needs-setup|needs-install|unavailable)")
|
|
50
51
|
.option("--active", "Only show active skills")
|
|
51
52
|
.option("--ready", "Only show ready skills")
|
|
52
53
|
.option("--needs-setup", "Only show skills needing setup")
|
|
@@ -56,13 +57,14 @@ export function registerSkillsCommand(program) {
|
|
|
56
57
|
.action(async (opts) => {
|
|
57
58
|
const config = loadConfig();
|
|
58
59
|
const workspaceDir = resolveUserPath(config.agent?.workspace ?? DEFAULT_AGENT_WORKSPACE_DIR);
|
|
60
|
+
const managedSkillsDir = path.join(NEXUS_ROOT, "skills", "managed");
|
|
59
61
|
const entries = loadWorkspaceSkillEntries(workspaceDir, {
|
|
60
62
|
config,
|
|
61
|
-
managedSkillsDir
|
|
63
|
+
managedSkillsDir,
|
|
62
64
|
});
|
|
63
65
|
const status = buildWorkspaceSkillStatus(workspaceDir, {
|
|
64
66
|
config,
|
|
65
|
-
managedSkillsDir
|
|
67
|
+
managedSkillsDir,
|
|
66
68
|
entries,
|
|
67
69
|
});
|
|
68
70
|
const statusMap = new Map(status.skills.map((item) => [item.name.toLowerCase(), item]));
|
|
@@ -84,6 +86,25 @@ export function registerSkillsCommand(program) {
|
|
|
84
86
|
? String(opts.type).toLowerCase()
|
|
85
87
|
: undefined;
|
|
86
88
|
const statusFilters = new Set();
|
|
89
|
+
if (opts.status) {
|
|
90
|
+
const raw = String(opts.status)
|
|
91
|
+
.split(",")
|
|
92
|
+
.map((entry) => entry.trim().toLowerCase())
|
|
93
|
+
.filter(Boolean);
|
|
94
|
+
for (const entry of raw) {
|
|
95
|
+
const normalized = entry.replace(/_/g, "-");
|
|
96
|
+
if (normalized === "needs-setup")
|
|
97
|
+
statusFilters.add("needs_setup");
|
|
98
|
+
else if (normalized === "needs-install")
|
|
99
|
+
statusFilters.add("needs_install");
|
|
100
|
+
else if (normalized === "active")
|
|
101
|
+
statusFilters.add("active");
|
|
102
|
+
else if (normalized === "ready")
|
|
103
|
+
statusFilters.add("ready");
|
|
104
|
+
else if (normalized === "unavailable")
|
|
105
|
+
statusFilters.add("unavailable");
|
|
106
|
+
}
|
|
107
|
+
}
|
|
87
108
|
if (opts.active)
|
|
88
109
|
statusFilters.add("active");
|
|
89
110
|
if (opts.ready)
|
|
@@ -125,8 +146,11 @@ export function registerSkillsCommand(program) {
|
|
|
125
146
|
const icon = STATUS_ICON[item.status] ?? "•";
|
|
126
147
|
console.log(` ${icon} ${item.name}${desc}`);
|
|
127
148
|
}
|
|
128
|
-
|
|
129
|
-
console.log(
|
|
149
|
+
const skillsRoot = path.join(NEXUS_ROOT, "skills");
|
|
150
|
+
console.log(`\nSkills directory: ${skillsRoot}`);
|
|
151
|
+
console.log(`Skill types: ${path.join(skillsRoot, "tools")}, ${path.join(skillsRoot, "connectors")}, ${path.join(skillsRoot, "guides")}`);
|
|
152
|
+
console.log(`Skill state: ${SKILLS_STATE_DIR}`);
|
|
153
|
+
console.log(`User skills: ${path.join(workspaceDir, "skills")}\n`);
|
|
130
154
|
});
|
|
131
155
|
skill
|
|
132
156
|
.command("info <name>")
|
|
@@ -190,18 +214,6 @@ export function registerSkillsCommand(program) {
|
|
|
190
214
|
console.log(info.prompt.trimEnd());
|
|
191
215
|
recordSkillUsage(name, { ts: Date.now(), event: "use", ok: true });
|
|
192
216
|
});
|
|
193
|
-
skill
|
|
194
|
-
.command("run <name>")
|
|
195
|
-
.description("Run a skill command with arguments")
|
|
196
|
-
.allowUnknownOption()
|
|
197
|
-
.action(async (name, _opts, command) => {
|
|
198
|
-
const args = command.args.slice(1);
|
|
199
|
-
const result = await runSkill(name, args);
|
|
200
|
-
if (!result.ok) {
|
|
201
|
-
console.error(result.error);
|
|
202
|
-
process.exit(1);
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
217
|
skill
|
|
206
218
|
.command("verify <name>")
|
|
207
219
|
.description("Verify skill setup and dependencies")
|
|
@@ -12,7 +12,7 @@ import { generateSkillManifest, writeSkillManifest, } from "../commands/skills-m
|
|
|
12
12
|
import { loadConfig } from "../config/config.js";
|
|
13
13
|
import { listCredentialEntries, resolveCredentialValue, } from "../credentials/store.js";
|
|
14
14
|
import { runCommandWithTimeout } from "../process/exec.js";
|
|
15
|
-
import {
|
|
15
|
+
import { NEXUS_ROOT, resolveUserPath } from "../utils.js";
|
|
16
16
|
function getHubBaseUrl() {
|
|
17
17
|
return (process.env.NEXUS_HUB_URL ||
|
|
18
18
|
process.env.NEXUS_WEBSITE_URL ||
|
|
@@ -284,9 +284,8 @@ function dirNameToSlug(dirName) {
|
|
|
284
284
|
async function ensureDir(dir) {
|
|
285
285
|
await fs.mkdir(dir, { recursive: true });
|
|
286
286
|
}
|
|
287
|
-
async function loadManagedSkillSlugs(
|
|
287
|
+
async function loadManagedSkillSlugs(managedDir) {
|
|
288
288
|
const slugs = new Set();
|
|
289
|
-
const managedDir = path.join(managedSkillsDir, "managed");
|
|
290
289
|
let entries = [];
|
|
291
290
|
try {
|
|
292
291
|
entries = await fs.readdir(managedDir, { withFileTypes: true });
|
|
@@ -600,7 +599,8 @@ async function installHubSkill(params) {
|
|
|
600
599
|
}
|
|
601
600
|
await extractArchive(artifactPath, destDir);
|
|
602
601
|
await normalizeSkillRoot(destDir);
|
|
603
|
-
const
|
|
602
|
+
const skillsRootDir = path.dirname(params.managedDir);
|
|
603
|
+
const manifest = await generateSkillManifest(skillsRootDir, params.userSkillsDir);
|
|
604
604
|
await writeSkillManifest(manifest);
|
|
605
605
|
return { installed: true, destDir };
|
|
606
606
|
}
|
|
@@ -628,7 +628,8 @@ export function registerSkillsHubCommand(program) {
|
|
|
628
628
|
: 10;
|
|
629
629
|
const cfg = loadConfig();
|
|
630
630
|
const workspaceDir = resolveUserPath(cfg.agent?.workspace ?? DEFAULT_AGENT_WORKSPACE_DIR);
|
|
631
|
-
const
|
|
631
|
+
const skillsRoot = path.join(NEXUS_ROOT, "skills");
|
|
632
|
+
const managedSkillsDir = path.join(skillsRoot, "managed");
|
|
632
633
|
const status = buildWorkspaceSkillStatus(workspaceDir, {
|
|
633
634
|
config: cfg,
|
|
634
635
|
managedSkillsDir,
|
|
@@ -1049,8 +1050,9 @@ export function registerSkillsHubCommand(program) {
|
|
|
1049
1050
|
const cfg = loadConfig();
|
|
1050
1051
|
const workspaceDir = resolveUserPath(cfg.agent?.workspace ?? DEFAULT_AGENT_WORKSPACE_DIR);
|
|
1051
1052
|
const userSkillsDir = path.join(workspaceDir, "skills");
|
|
1052
|
-
const
|
|
1053
|
-
const
|
|
1053
|
+
const skillsRoot = path.join(NEXUS_ROOT, "skills");
|
|
1054
|
+
const managedSkillsDir = path.join(skillsRoot, "managed");
|
|
1055
|
+
const managedDir = managedSkillsDir;
|
|
1054
1056
|
const metadataEntries = loadWorkspaceSkillEntries(workspaceDir, {
|
|
1055
1057
|
config: cfg,
|
|
1056
1058
|
managedSkillsDir,
|
|
@@ -107,15 +107,15 @@ export async function applyBootstrapPreset(params) {
|
|
|
107
107
|
const { workspaceDir, runtime } = params;
|
|
108
108
|
const stateDir = resolveStateDir();
|
|
109
109
|
const agentId = process.env.NEXUS_AGENT_ID?.trim() || "default";
|
|
110
|
-
const agentIdentityDir = path.join(stateDir, "agents", agentId
|
|
111
|
-
const userIdentityDir = path.join(stateDir, "user"
|
|
110
|
+
const agentIdentityDir = path.join(stateDir, "agents", agentId);
|
|
111
|
+
const userIdentityDir = path.join(stateDir, "user");
|
|
112
112
|
const bootstrapPath = resolveBootstrapPath(undefined, stateDir);
|
|
113
113
|
if (!(await fileExists(bootstrapPath)))
|
|
114
114
|
return;
|
|
115
115
|
await fs.mkdir(agentIdentityDir, { recursive: true });
|
|
116
116
|
await fs.mkdir(userIdentityDir, { recursive: true });
|
|
117
117
|
const identityPath = path.join(agentIdentityDir, "IDENTITY.md");
|
|
118
|
-
const userPath = path.join(userIdentityDir, "
|
|
118
|
+
const userPath = path.join(userIdentityDir, "IDENTITY.md");
|
|
119
119
|
const soulPath = path.join(agentIdentityDir, "SOUL.md");
|
|
120
120
|
const agentsPath = path.join(NEXUS_ROOT, "AGENTS.md");
|
|
121
121
|
const preset = resolvePreset(params.preset);
|
|
@@ -173,17 +173,27 @@ export async function applyBootstrapPreset(params) {
|
|
|
173
173
|
userName = "Test User";
|
|
174
174
|
if (!preferredAddress)
|
|
175
175
|
preferredAddress = firstName(userName) || "friend";
|
|
176
|
-
const identityMd =
|
|
176
|
+
const identityMd = `---
|
|
177
|
+
name: ${agentName}
|
|
178
|
+
emoji: ${preset.emoji}
|
|
179
|
+
creature: ${preset.creature}
|
|
180
|
+
vibe: ${preset.vibe}
|
|
181
|
+
---
|
|
182
|
+
# IDENTITY.md - Agent Identity
|
|
177
183
|
|
|
178
184
|
- Name: ${agentName}
|
|
179
185
|
- Creature: ${preset.creature}
|
|
180
186
|
- Vibe: ${preset.vibe}
|
|
181
187
|
- Emoji: ${preset.emoji}
|
|
182
188
|
`;
|
|
183
|
-
const userMd =
|
|
189
|
+
const userMd = `---
|
|
190
|
+
name: ${userName}
|
|
191
|
+
call: ${preferredAddress}
|
|
192
|
+
---
|
|
193
|
+
# IDENTITY.md - User Identity
|
|
184
194
|
|
|
185
195
|
- Name: ${userName}
|
|
186
|
-
-
|
|
196
|
+
- What to call them: ${preferredAddress}
|
|
187
197
|
- Pronouns (optional):
|
|
188
198
|
- Timezone (optional):
|
|
189
199
|
- Notes:
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { loadConfig, readConfigFileSnapshot, writeConfigFile } from "../config/config.js";
|
|
2
|
+
import { defaultRuntime } from "../runtime.js";
|
|
3
|
+
function getByPath(obj, key) {
|
|
4
|
+
const parts = key.split(".").filter(Boolean);
|
|
5
|
+
let current = obj;
|
|
6
|
+
for (const part of parts) {
|
|
7
|
+
if (!current || typeof current !== "object")
|
|
8
|
+
return undefined;
|
|
9
|
+
current = current[part];
|
|
10
|
+
}
|
|
11
|
+
return current;
|
|
12
|
+
}
|
|
13
|
+
function setByPath(obj, key, value) {
|
|
14
|
+
const parts = key.split(".").filter(Boolean);
|
|
15
|
+
let current = obj;
|
|
16
|
+
for (let i = 0; i < parts.length; i += 1) {
|
|
17
|
+
const part = parts[i];
|
|
18
|
+
if (i === parts.length - 1) {
|
|
19
|
+
current[part] = value;
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
const next = current[part];
|
|
23
|
+
if (!next || typeof next !== "object") {
|
|
24
|
+
current[part] = {};
|
|
25
|
+
}
|
|
26
|
+
current = current[part];
|
|
27
|
+
}
|
|
28
|
+
return obj;
|
|
29
|
+
}
|
|
30
|
+
function parseValue(raw) {
|
|
31
|
+
const trimmed = raw.trim();
|
|
32
|
+
if (!trimmed)
|
|
33
|
+
return "";
|
|
34
|
+
if (trimmed === "true")
|
|
35
|
+
return true;
|
|
36
|
+
if (trimmed === "false")
|
|
37
|
+
return false;
|
|
38
|
+
if (!Number.isNaN(Number(trimmed)))
|
|
39
|
+
return Number(trimmed);
|
|
40
|
+
if ((trimmed.startsWith("{") && trimmed.endsWith("}")) ||
|
|
41
|
+
(trimmed.startsWith("[") && trimmed.endsWith("]"))) {
|
|
42
|
+
try {
|
|
43
|
+
return JSON.parse(trimmed);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
return trimmed;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return trimmed;
|
|
50
|
+
}
|
|
51
|
+
export async function configListCommand(opts, runtime = defaultRuntime) {
|
|
52
|
+
const snapshot = await readConfigFileSnapshot();
|
|
53
|
+
const payload = snapshot.valid ? snapshot.parsed : {};
|
|
54
|
+
if (opts?.json) {
|
|
55
|
+
runtime.log(JSON.stringify(payload, null, 2));
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
runtime.log(JSON.stringify(payload, null, 2));
|
|
59
|
+
}
|
|
60
|
+
export async function configGetCommand(opts, runtime = defaultRuntime) {
|
|
61
|
+
const config = loadConfig();
|
|
62
|
+
const value = getByPath(config, opts.key);
|
|
63
|
+
if (opts.json) {
|
|
64
|
+
runtime.log(JSON.stringify({ key: opts.key, value }, null, 2));
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (typeof value === "string") {
|
|
68
|
+
runtime.log(value);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
runtime.log(JSON.stringify(value ?? null, null, 2));
|
|
72
|
+
}
|
|
73
|
+
export async function configSetCommand(opts, runtime = defaultRuntime) {
|
|
74
|
+
const snapshot = await readConfigFileSnapshot();
|
|
75
|
+
const base = snapshot.valid && snapshot.parsed && typeof snapshot.parsed === "object"
|
|
76
|
+
? snapshot.parsed
|
|
77
|
+
: {};
|
|
78
|
+
const next = setByPath({ ...base }, opts.key, parseValue(opts.value));
|
|
79
|
+
await writeConfigFile(next);
|
|
80
|
+
if (opts.json) {
|
|
81
|
+
runtime.log(JSON.stringify({ key: opts.key, value: getByPath(next, opts.key) }, null, 2));
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
runtime.log(`Updated ${opts.key}`);
|
|
85
|
+
}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import fsp from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { resolveUserPath } from "../utils.js";
|
|
4
|
+
const DEFAULT_SCRIPT_NAME = "nexus-session-start.js";
|
|
5
|
+
const HOOK_SCRIPT = `#!/usr/bin/env node
|
|
6
|
+
const { execFile } = require("child_process");
|
|
7
|
+
const fs = require("fs");
|
|
8
|
+
const fsp = require("fs/promises");
|
|
9
|
+
const os = require("os");
|
|
10
|
+
const path = require("path");
|
|
11
|
+
|
|
12
|
+
const MAX_IDENTITY_CHARS = 120000;
|
|
13
|
+
const MAX_MEMORY_CHARS = 120000;
|
|
14
|
+
const MAX_DAILY_CHARS = 40000;
|
|
15
|
+
const MAX_BOOTSTRAP_CHARS = 80000;
|
|
16
|
+
|
|
17
|
+
function readStdin() {
|
|
18
|
+
return new Promise((resolve) => {
|
|
19
|
+
let data = "";
|
|
20
|
+
process.stdin.setEncoding("utf8");
|
|
21
|
+
process.stdin.on("data", (chunk) => {
|
|
22
|
+
data += chunk;
|
|
23
|
+
});
|
|
24
|
+
process.stdin.on("end", () => resolve(data));
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function safeJsonParse(raw) {
|
|
29
|
+
if (!raw || !raw.trim()) return null;
|
|
30
|
+
try {
|
|
31
|
+
return JSON.parse(raw);
|
|
32
|
+
} catch {
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function formatDate(date) {
|
|
38
|
+
const year = date.getFullYear();
|
|
39
|
+
const month = String(date.getMonth() + 1).padStart(2, "0");
|
|
40
|
+
const day = String(date.getDate()).padStart(2, "0");
|
|
41
|
+
return \`\${year}-\${month}-\${day}\`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function resolveWorkspaceRoot(payload) {
|
|
45
|
+
const roots = payload?.workspace_roots;
|
|
46
|
+
if (Array.isArray(roots) && roots.length > 0 && roots[0]) {
|
|
47
|
+
return roots[0];
|
|
48
|
+
}
|
|
49
|
+
if (process.env.NEXUS_ROOT?.trim()) return process.env.NEXUS_ROOT.trim();
|
|
50
|
+
const home = os.homedir();
|
|
51
|
+
if (home) return path.join(home, "nexus");
|
|
52
|
+
return process.cwd();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function resolveStateDir(workspaceRoot) {
|
|
56
|
+
if (process.env.NEXUS_STATE_DIR?.trim()) {
|
|
57
|
+
return process.env.NEXUS_STATE_DIR.trim();
|
|
58
|
+
}
|
|
59
|
+
return path.join(workspaceRoot, "state");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function execFileAsync(command, args, options) {
|
|
63
|
+
return new Promise((resolve) => {
|
|
64
|
+
execFile(command, args, options, (error, stdout, stderr) => {
|
|
65
|
+
resolve({ error, stdout, stderr });
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function runStatus(env, cwd) {
|
|
71
|
+
const result = await execFileAsync("nexus", ["status", "--json"], {
|
|
72
|
+
env,
|
|
73
|
+
cwd,
|
|
74
|
+
});
|
|
75
|
+
const parsed = safeJsonParse(result.stdout);
|
|
76
|
+
if (parsed) return parsed;
|
|
77
|
+
if (result.error && result.error.stdout) {
|
|
78
|
+
const fallback = safeJsonParse(result.error.stdout.toString());
|
|
79
|
+
if (fallback) return fallback;
|
|
80
|
+
}
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async function readFileSnippet(filePath, limit) {
|
|
85
|
+
if (!filePath) return null;
|
|
86
|
+
try {
|
|
87
|
+
const content = await fsp.readFile(filePath, "utf8");
|
|
88
|
+
if (!content.trim()) return null;
|
|
89
|
+
if (content.length <= limit) return content.trim();
|
|
90
|
+
const slice = content.slice(-limit).trimStart();
|
|
91
|
+
return \`\${slice}\\n\\n[truncated]\`;
|
|
92
|
+
} catch {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function addSection(sections, title, body) {
|
|
98
|
+
if (!body) return;
|
|
99
|
+
sections.push(\`## \${title}\\n\${body}\`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async function main() {
|
|
103
|
+
const input = await readStdin();
|
|
104
|
+
const payload = safeJsonParse(input) || {};
|
|
105
|
+
const workspaceRoot = resolveWorkspaceRoot(payload);
|
|
106
|
+
const stateDir = resolveStateDir(workspaceRoot);
|
|
107
|
+
const env = {
|
|
108
|
+
...process.env,
|
|
109
|
+
NEXUS_ROOT: workspaceRoot,
|
|
110
|
+
NEXUS_STATE_DIR: stateDir,
|
|
111
|
+
};
|
|
112
|
+
const status = await runStatus(env, workspaceRoot);
|
|
113
|
+
const identity = status?.identity || null;
|
|
114
|
+
const agentId = identity?.agentId || process.env.NEXUS_AGENT_ID || "default";
|
|
115
|
+
const agentIdentityPath =
|
|
116
|
+
identity?.agentIdentityPath ||
|
|
117
|
+
path.join(stateDir, "agents", agentId, "IDENTITY.md");
|
|
118
|
+
const agentSoulPath =
|
|
119
|
+
identity?.agentSoulPath || path.join(stateDir, "agents", agentId, "SOUL.md");
|
|
120
|
+
const agentMemoryPath =
|
|
121
|
+
identity?.agentMemoryPath ||
|
|
122
|
+
path.join(stateDir, "agents", agentId, "MEMORY.md");
|
|
123
|
+
const userIdentityPath =
|
|
124
|
+
identity?.userIdentityPath || path.join(stateDir, "user", "IDENTITY.md");
|
|
125
|
+
const userProfilePath = path.join(stateDir, "user", "PROFILE.md");
|
|
126
|
+
const resolvedUserPath = fs.existsSync(userIdentityPath)
|
|
127
|
+
? userIdentityPath
|
|
128
|
+
: fs.existsSync(userProfilePath)
|
|
129
|
+
? userProfilePath
|
|
130
|
+
: userIdentityPath;
|
|
131
|
+
|
|
132
|
+
const sections = ["# Nexus Session Bootstrap"];
|
|
133
|
+
if (identity) {
|
|
134
|
+
const summary = [
|
|
135
|
+
\`Agent: \${identity.agentName || "(unknown)"} (\${identity.agentId})\`,
|
|
136
|
+
\`User: \${identity.userName || "(unknown)"}\`,
|
|
137
|
+
\`Agent ID: \${identity.agentId}\`,
|
|
138
|
+
];
|
|
139
|
+
addSection(sections, "Status", summary.join("\\n"));
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const bootstrapPath =
|
|
143
|
+
status?.identity?.bootstrapPath ||
|
|
144
|
+
path.join(stateDir, "agents", "BOOTSTRAP.md");
|
|
145
|
+
const hasIdentity =
|
|
146
|
+
typeof identity?.hasIdentity === "boolean"
|
|
147
|
+
? identity.hasIdentity
|
|
148
|
+
: fs.existsSync(agentIdentityPath) && fs.existsSync(resolvedUserPath);
|
|
149
|
+
let bootstrapPrompt = status?.bootstrap?.prompt || null;
|
|
150
|
+
if (!bootstrapPrompt && !hasIdentity) {
|
|
151
|
+
bootstrapPrompt = await readFileSnippet(
|
|
152
|
+
bootstrapPath,
|
|
153
|
+
MAX_BOOTSTRAP_CHARS,
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
if (bootstrapPrompt) {
|
|
157
|
+
addSection(sections, "Bootstrap Prompt", bootstrapPrompt.trim());
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const agentIdentity = await readFileSnippet(
|
|
161
|
+
agentIdentityPath,
|
|
162
|
+
MAX_IDENTITY_CHARS,
|
|
163
|
+
);
|
|
164
|
+
const agentSoul = await readFileSnippet(agentSoulPath, MAX_IDENTITY_CHARS);
|
|
165
|
+
const agentMemory = await readFileSnippet(agentMemoryPath, MAX_MEMORY_CHARS);
|
|
166
|
+
const userIdentity = await readFileSnippet(
|
|
167
|
+
resolvedUserPath,
|
|
168
|
+
MAX_IDENTITY_CHARS,
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
addSection(sections, "Agent Identity", agentIdentity);
|
|
172
|
+
addSection(sections, "Agent Soul", agentSoul);
|
|
173
|
+
addSection(sections, "Agent Memory", agentMemory);
|
|
174
|
+
addSection(sections, "User Identity", userIdentity);
|
|
175
|
+
|
|
176
|
+
const memoryDir = path.join(workspaceRoot, "home", "memory");
|
|
177
|
+
const today = formatDate(new Date());
|
|
178
|
+
const yesterday = formatDate(new Date(Date.now() - 86400000));
|
|
179
|
+
const todayLog = await readFileSnippet(
|
|
180
|
+
path.join(memoryDir, \`\${today}.md\`),
|
|
181
|
+
MAX_DAILY_CHARS,
|
|
182
|
+
);
|
|
183
|
+
const yesterdayLog = await readFileSnippet(
|
|
184
|
+
path.join(memoryDir, \`\${yesterday}.md\`),
|
|
185
|
+
MAX_DAILY_CHARS,
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
addSection(sections, \`Daily Memory (\${today})\`, todayLog);
|
|
189
|
+
addSection(sections, \`Daily Memory (\${yesterday})\`, yesterdayLog);
|
|
190
|
+
|
|
191
|
+
const additional = sections.join("\\n\\n").trim();
|
|
192
|
+
const output = { continue: true, additional_context: additional };
|
|
193
|
+
const envOut = {};
|
|
194
|
+
if (!process.env.NEXUS_ROOT?.trim() && workspaceRoot) {
|
|
195
|
+
envOut.NEXUS_ROOT = workspaceRoot;
|
|
196
|
+
}
|
|
197
|
+
if (!process.env.NEXUS_STATE_DIR?.trim() && stateDir) {
|
|
198
|
+
envOut.NEXUS_STATE_DIR = stateDir;
|
|
199
|
+
}
|
|
200
|
+
if (Object.keys(envOut).length > 0) {
|
|
201
|
+
output.env = envOut;
|
|
202
|
+
}
|
|
203
|
+
process.stdout.write(JSON.stringify(output) + "\\n");
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
main().catch(() => {
|
|
207
|
+
process.stdout.write(JSON.stringify({ continue: true }) + "\\n");
|
|
208
|
+
});
|
|
209
|
+
`;
|
|
210
|
+
async function writeFileIfMissing(filePath, content) {
|
|
211
|
+
try {
|
|
212
|
+
await fsp.writeFile(filePath, content, { encoding: "utf-8", flag: "wx" });
|
|
213
|
+
return true;
|
|
214
|
+
}
|
|
215
|
+
catch (err) {
|
|
216
|
+
const anyErr = err;
|
|
217
|
+
if (anyErr.code === "EEXIST")
|
|
218
|
+
return false;
|
|
219
|
+
throw err;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
export async function writeCursorHooks(options = {}) {
|
|
223
|
+
const workspaceDir = resolveUserPath(options.workspaceDir ?? process.cwd());
|
|
224
|
+
const hooksPath = options.hooksPath ?? path.join(workspaceDir, ".cursor", "hooks.json");
|
|
225
|
+
const scriptPath = options.scriptPath ??
|
|
226
|
+
path.join(workspaceDir, ".cursor", "hooks", DEFAULT_SCRIPT_NAME);
|
|
227
|
+
await fsp.mkdir(path.dirname(hooksPath), { recursive: true });
|
|
228
|
+
await fsp.mkdir(path.dirname(scriptPath), { recursive: true });
|
|
229
|
+
const hooksConfig = JSON.stringify({
|
|
230
|
+
version: 1,
|
|
231
|
+
hooks: {
|
|
232
|
+
sessionStart: [
|
|
233
|
+
{ command: `node .cursor/hooks/${DEFAULT_SCRIPT_NAME}` },
|
|
234
|
+
],
|
|
235
|
+
},
|
|
236
|
+
}, null, 2);
|
|
237
|
+
const hooksCreated = await writeFileIfMissing(hooksPath, `${hooksConfig}\n`);
|
|
238
|
+
const scriptCreated = await writeFileIfMissing(scriptPath, HOOK_SCRIPT);
|
|
239
|
+
return { hooksPath, scriptPath, hooksCreated, scriptCreated };
|
|
240
|
+
}
|