@agentprojectcontext/apx 1.33.1 → 1.35.0
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/package.json +1 -1
- package/skills/apx/SKILL.md +49 -61
- package/src/core/agent/a2a/reply.js +48 -0
- package/src/core/agent/build-agent-system.js +136 -59
- package/src/core/agent/channels/voice-context.js +98 -0
- package/src/core/agent/memory.js +2 -1
- package/src/core/agent/prompt-builder.js +178 -124
- package/src/core/agent/prompts/channels/code.md +12 -10
- package/src/core/agent/prompts/channels/desktop.md +5 -32
- package/src/core/agent/prompts/channels/telegram.md +4 -15
- package/src/core/agent/prompts/channels/web_code.md +11 -11
- package/src/core/agent/prompts/core/agent-base.md +24 -0
- package/src/core/agent/prompts/core/project-agent.md +11 -0
- package/src/core/agent/prompts/core/super-agent.md +21 -0
- package/src/core/agent/prompts/discipline/action.md +10 -0
- package/src/core/agent/prompts/discipline/single-segment.md +6 -0
- package/src/core/agent/prompts/discipline/two-segment.md +11 -0
- package/src/core/agent/prompts/modes/code-build.md +1 -0
- package/src/core/agent/prompts/modes/code-plan.md +1 -0
- package/src/core/agent/prompts/modes/index.js +28 -0
- package/src/core/agent/self-memory.js +43 -1
- package/src/core/agent/skills/index-store.js +307 -0
- package/src/core/agent/skills/index.js +15 -1
- package/src/core/agent/skills/inspector.js +317 -0
- package/src/core/agent/skills/loader.js +22 -18
- package/src/core/agent/stream/turn-accumulator.js +73 -0
- package/src/core/agent/suggestions.js +37 -0
- package/src/core/agent/super-agent.js +7 -1
- package/src/core/agent/tools/handlers/_git.js +50 -0
- package/src/core/agent/tools/handlers/add-project.js +5 -2
- package/src/core/agent/tools/handlers/call-runtime.js +3 -2
- package/src/core/agent/tools/handlers/git-diff.js +44 -0
- package/src/core/agent/tools/handlers/git-log.js +38 -0
- package/src/core/agent/tools/handlers/git-show.js +34 -0
- package/src/core/agent/tools/handlers/git-status.js +61 -0
- package/src/core/agent/tools/handlers/transcribe-audio.js +1 -1
- package/src/core/agent/tools/helpers.js +2 -2
- package/src/core/agent/tools/names.js +169 -0
- package/src/core/agent/tools/registry-bridge.js +6 -14
- package/src/core/agent/tools/registry.js +103 -69
- package/src/core/apc/context-copy.js +27 -0
- package/src/core/apc/notes.js +19 -0
- package/src/core/apc/parser.js +12 -5
- package/src/core/apc/paths.js +87 -0
- package/src/core/apc/scaffold.js +82 -76
- package/src/core/apc/skill-sync.js +10 -0
- package/src/{host/daemon/plugins → core/channels}/telegram/dispatch.js +38 -16
- package/src/core/config/index.js +24 -2
- package/src/core/config/redact.js +95 -0
- package/src/core/constants/channels.js +2 -0
- package/src/core/constants/code-modes.js +10 -0
- package/src/core/constants/index.js +1 -0
- package/src/core/deck/manifest.js +186 -0
- package/src/core/engines/catalog.js +83 -0
- package/src/core/{tools → http-tools}/browser.js +0 -1
- package/src/core/{tools → http-tools}/fetch.js +0 -1
- package/src/core/{tools → http-tools}/glob.js +0 -1
- package/src/core/{tools → http-tools}/grep.js +0 -1
- package/src/core/{tools → http-tools}/registry.js +0 -1
- package/src/core/{tools → http-tools}/search.js +0 -1
- package/src/core/i18n/en.js +9 -0
- package/src/core/i18n/es.js +12 -0
- package/src/core/i18n/index.js +54 -0
- package/src/core/i18n/pt.js +9 -0
- package/src/core/identity/telegram.js +2 -1
- package/src/core/mcp/runner.js +272 -14
- package/src/core/mcp/sources.js +3 -2
- package/src/core/routines/index.js +16 -0
- package/src/{host/daemon/routines.js → core/routines/runner.js} +36 -103
- package/src/core/runtime-skills/apc-context/SKILL.md +159 -0
- package/src/core/runtime-skills/apx/SKILL.md +83 -0
- package/src/core/runtime-skills/apx-agency-agents/SKILL.md +125 -0
- package/src/core/runtime-skills/apx-agent/SKILL.md +97 -0
- package/src/core/runtime-skills/apx-mcp/SKILL.md +111 -0
- package/src/core/runtime-skills/apx-mcp-builder/SKILL.md +169 -0
- package/{skills → src/core/runtime-skills}/apx-project/SKILL.md +20 -29
- package/src/core/runtime-skills/apx-routine/SKILL.md +127 -0
- package/src/core/runtime-skills/apx-runtime/SKILL.md +99 -0
- package/src/core/runtime-skills/apx-sessions/SKILL.md +232 -0
- package/src/core/runtime-skills/apx-skill-builder/SKILL.md +129 -0
- package/{skills → src/core/runtime-skills}/apx-task/SKILL.md +18 -21
- package/src/core/runtime-skills/apx-telegram/SKILL.md +120 -0
- package/src/core/runtime-skills/apx-voice/SKILL.md +117 -0
- package/src/core/runtime-skills/{claude-code.md → claude-code/SKILL.md} +1 -0
- package/src/core/runtime-skills/{codex-cli.md → codex-cli/SKILL.md} +1 -0
- package/src/core/runtime-skills/{opencode-cli.md → opencode-cli/SKILL.md} +1 -0
- package/src/core/runtime-skills/{openrouter.md → openrouter/SKILL.md} +1 -0
- package/src/{host/daemon/env-detect.js → core/runtimes/detect.js} +1 -1
- package/src/core/stores/code-sessions.js +50 -2
- package/src/core/stores/routine-memory.js +1 -1
- package/src/core/stores/sessions-search.js +121 -0
- package/src/core/stores/sessions.js +38 -0
- package/src/core/vars/index.js +14 -0
- package/src/core/vars/interpolate.js +86 -0
- package/src/core/vars/sources.js +151 -0
- package/src/core/voice/audio-decode.js +38 -0
- package/src/core/voice/transcription.js +225 -0
- package/src/host/daemon/api/admin-config.js +5 -82
- package/src/host/daemon/api/agents.js +5 -5
- package/src/host/daemon/api/code.js +17 -169
- package/src/host/daemon/api/config.js +3 -4
- package/src/host/daemon/api/conversations.js +8 -29
- package/src/host/daemon/api/deck.js +37 -404
- package/src/host/daemon/api/engines.js +1 -80
- package/src/host/daemon/api/exec.js +1 -1
- package/src/host/daemon/api/mcps.js +32 -0
- package/src/host/daemon/api/routines.js +1 -1
- package/src/host/daemon/api/runtimes.js +4 -3
- package/src/host/daemon/api/sessions-search.js +24 -140
- package/src/host/daemon/api/sessions.js +12 -30
- package/src/host/daemon/api/shared.js +2 -1
- package/src/host/daemon/api/skills.js +140 -6
- package/src/host/daemon/api/super-agent.js +56 -1
- package/src/host/daemon/api/telegram.js +1 -11
- package/src/host/daemon/api/tools.js +6 -6
- package/src/host/daemon/api/transcribe.js +2 -2
- package/src/host/daemon/api/vars.js +137 -0
- package/src/host/daemon/api/voice.js +13 -290
- package/src/host/daemon/api.js +2 -0
- package/src/host/daemon/db.js +6 -6
- package/src/host/daemon/deck-exec.js +148 -0
- package/src/host/daemon/index.js +20 -3
- package/src/host/daemon/plugins/telegram/index.js +9 -9
- package/src/host/daemon/routines-scheduler.js +64 -0
- package/src/host/daemon/smoke.js +3 -2
- package/src/host/daemon/whisper-server.js +225 -0
- package/src/interfaces/cli/branding.js +53 -0
- package/src/interfaces/cli/commands/agent.js +3 -2
- package/src/interfaces/cli/commands/command.js +2 -3
- package/src/interfaces/cli/commands/messages.js +6 -2
- package/src/interfaces/cli/commands/pair.js +5 -4
- package/src/interfaces/cli/commands/search.js +1 -1
- package/src/interfaces/cli/commands/sessions.js +3 -2
- package/src/interfaces/cli/commands/skills.js +290 -55
- package/src/interfaces/cli/index.js +84 -2
- package/src/interfaces/web/dist/assets/index-C0fm31dY.js +618 -0
- package/src/interfaces/web/dist/assets/index-C0fm31dY.js.map +1 -0
- package/src/interfaces/web/dist/assets/index-UcAqlBO6.css +1 -0
- package/src/interfaces/web/dist/index.html +2 -2
- package/src/interfaces/web/package-lock.json +182 -182
- package/src/interfaces/web/src/components/ModelCombobox.tsx +2 -1
- package/src/interfaces/web/src/components/TelegramChannelDialog.tsx +1 -1
- package/src/interfaces/web/src/components/chat/AskAnswersCard.tsx +76 -0
- package/src/interfaces/web/src/components/chat/MessageBubble.tsx +37 -4
- package/src/interfaces/web/src/components/chat/MessageList.tsx +23 -1
- package/src/interfaces/web/src/components/chat/ModelPicker.tsx +3 -1
- package/src/interfaces/web/src/components/code/CodeArtifactsTab.tsx +4 -4
- package/src/interfaces/web/src/components/code/CodeChangesTab.tsx +1 -1
- package/src/interfaces/web/src/components/code/CodeFileTree.tsx +3 -2
- package/src/interfaces/web/src/components/code/CodeFileViewer.tsx +3 -2
- package/src/interfaces/web/src/components/code/CodeTerminal.tsx +3 -2
- package/src/interfaces/web/src/components/config/GlobalConfigEditor.tsx +2 -1
- package/src/interfaces/web/src/components/deck/WidgetRow.tsx +2 -1
- package/src/interfaces/web/src/components/inputs/KeyValueList.tsx +93 -0
- package/src/interfaces/web/src/components/inputs/VarTokenInput.tsx +449 -0
- package/src/interfaces/web/src/components/settings/DefaultRouterCard.tsx +2 -1
- package/src/interfaces/web/src/components/settings/EnginesPanel.tsx +2 -2
- package/src/interfaces/web/src/components/settings/MemoryPanel.tsx +73 -4
- package/src/interfaces/web/src/components/settings/SkillsInspectorPanel.tsx +222 -0
- package/src/interfaces/web/src/components/settings/providers/ProviderCard.tsx +3 -2
- package/src/interfaces/web/src/components/settings/providers/ProviderModal.tsx +3 -2
- package/src/interfaces/web/src/components/ui/chat-input.tsx +5 -4
- package/src/interfaces/web/src/components/ui/sidebar.tsx +3 -2
- package/src/interfaces/web/src/components/voice/VoiceProviderModal.tsx +2 -1
- package/src/interfaces/web/src/constants/index.ts +1 -1
- package/src/interfaces/web/src/hooks/useChat.ts +19 -0
- package/src/interfaces/web/src/i18n/en.ts +175 -7
- package/src/interfaces/web/src/i18n/es.ts +180 -15
- package/src/interfaces/web/src/lib/api/mcps.ts +25 -0
- package/src/interfaces/web/src/lib/api/skills.ts +70 -0
- package/src/interfaces/web/src/lib/api/vars.ts +38 -0
- package/src/interfaces/web/src/lib/api.ts +1 -0
- package/src/interfaces/web/src/screens/ProjectScreen.tsx +8 -31
- package/src/interfaces/web/src/screens/SettingsScreen.tsx +6 -2
- package/src/interfaces/web/src/screens/modules/CodeScreen.tsx +1 -1
- package/src/interfaces/web/src/screens/modules/DeckScreen.tsx +4 -3
- package/src/interfaces/web/src/screens/modules/DesktopScreen.tsx +7 -6
- package/src/interfaces/web/src/screens/modules/VoiceScreen.tsx +4 -3
- package/src/interfaces/web/src/screens/project/AgentDetailScreen.tsx +1 -1
- package/src/interfaces/web/src/screens/project/ConfigTab.tsx +132 -1
- package/src/interfaces/web/src/screens/project/McpsTab.tsx +549 -104
- package/src/interfaces/web/src/screens/project/RoutinesTab.tsx +1 -1
- package/src/interfaces/web/src/screens/project/VarsTab.tsx +300 -0
- package/src/interfaces/web/src/types/daemon.ts +15 -0
- package/skills/apx-agency-agents/SKILL.md +0 -141
- package/skills/apx-agent/SKILL.md +0 -100
- package/skills/apx-mcp-builder/SKILL.md +0 -183
- package/skills/apx-routine/SKILL.md +0 -140
- package/skills/apx-runtime/SKILL.md +0 -117
- package/skills/apx-sessions/SKILL.md +0 -281
- package/skills/apx-skill-builder/SKILL.md +0 -153
- package/skills/apx-telegram/SKILL.md +0 -131
- package/skills/apx-voice/SKILL.md +0 -137
- package/src/core/agent/prompts/action-discipline.md +0 -24
- package/src/core/agent/prompts/super-agent-base.md +0 -42
- package/src/host/daemon/transcription.js +0 -538
- package/src/host/daemon/whisper-transcribe.py +0 -73
- package/src/interfaces/web/dist/assets/index-Aaiw8BZN.css +0 -1
- package/src/interfaces/web/dist/assets/index-DPqtjDjh.js +0 -602
- package/src/interfaces/web/dist/assets/index-DPqtjDjh.js.map +0 -1
- /package/src/{host/daemon → core/apc}/projects-helpers.js +0 -0
- /package/src/{host/daemon/plugins → core/channels}/telegram/ask.js +0 -0
- /package/src/{host/daemon/plugins → core/channels}/telegram/helpers.js +0 -0
- /package/src/{host/daemon/plugins → core/channels}/telegram/media.js +0 -0
- /package/src/core/{tools → http-tools}/index.js +0 -0
- /package/src/{host/daemon/compact.js → core/stores/conversations-compactor.js} +0 -0
- /package/src/{host/daemon → core/stores}/conversations.js +0 -0
- /package/src/{host/daemon → core/util}/thinking.js +0 -0
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import os from "node:os";
|
|
9
9
|
import qrcode from "qrcode-terminal";
|
|
10
10
|
import { http } from "../http.js";
|
|
11
|
+
import { CHANNELS } from "#core/constants/channels.js";
|
|
11
12
|
|
|
12
13
|
const c = {
|
|
13
14
|
reset: "\x1b[0m",
|
|
@@ -88,10 +89,10 @@ async function runPairing(args, channel) {
|
|
|
88
89
|
// 2. QR payload differs per channel — no mixing.
|
|
89
90
|
// deck: JSON {v,url,pid,fp} that the Deck app parses.
|
|
90
91
|
// web : the scan-to-login URL the browser understands.
|
|
91
|
-
const qrData = channel ===
|
|
92
|
+
const qrData = channel === CHANNELS.WEB
|
|
92
93
|
? webLink
|
|
93
94
|
: JSON.stringify({ v: 1, url: baseUrl, pid: init.pairing_id, fp: init.fingerprint });
|
|
94
|
-
const title = channel ===
|
|
95
|
+
const title = channel === CHANNELS.WEB ? "APX pairing (web)" : "APX pairing (deck)";
|
|
95
96
|
|
|
96
97
|
console.log("");
|
|
97
98
|
console.log(` ${fmt.bold(title)} ${fmt.gray("·")} ${fmt.dim(`expires in ${ttlSec}s`)}`);
|
|
@@ -100,7 +101,7 @@ async function runPairing(args, channel) {
|
|
|
100
101
|
console.log(qr);
|
|
101
102
|
});
|
|
102
103
|
|
|
103
|
-
if (channel ===
|
|
104
|
+
if (channel === CHANNELS.WEB) {
|
|
104
105
|
console.log(` ${fmt.gray("scan with the phone camera — opens the web already linked")}`);
|
|
105
106
|
console.log(` ${fmt.gray("link:")} ${fmt.cyan(webLink)}`);
|
|
106
107
|
console.log(` ${fmt.gray("code:")} ${fmt.bold(init.pairing_id)} ${fmt.dim("(or paste it in the web pairing screen)")}`);
|
|
@@ -111,7 +112,7 @@ async function runPairing(args, channel) {
|
|
|
111
112
|
console.log("");
|
|
112
113
|
|
|
113
114
|
// 3. Poll /pair/status until confirmed or expired.
|
|
114
|
-
const reRun = channel ===
|
|
115
|
+
const reRun = channel === CHANNELS.WEB ? "apx pair web" : "apx pair";
|
|
115
116
|
const deadline = Date.now() + (init.ttl_ms || 90_000) + 5_000;
|
|
116
117
|
while (Date.now() < deadline) {
|
|
117
118
|
await sleep(1500);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// Uses the daemon's tools/search.js module directly (no HTTP roundtrip,
|
|
4
4
|
// no need to have `apx daemon start` running).
|
|
5
5
|
|
|
6
|
-
import { webSearch } from "#core/tools/search.js";
|
|
6
|
+
import { webSearch } from "#core/http-tools/search.js";
|
|
7
7
|
|
|
8
8
|
const DIM = "\x1b[2m";
|
|
9
9
|
const BOLD = "\x1b[1m";
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import fs from "node:fs";
|
|
6
6
|
import os from "node:os";
|
|
7
7
|
import path from "node:path";
|
|
8
|
+
import { apcProjectFile } from "#core/apc/paths.js";
|
|
8
9
|
|
|
9
10
|
// ── shared helpers ───────────────────────────────────────────────────────────
|
|
10
11
|
|
|
@@ -124,7 +125,7 @@ function readApxProjects(opts) {
|
|
|
124
125
|
const proj = { path: path.resolve(e.path), name: null, apxId: null };
|
|
125
126
|
try {
|
|
126
127
|
const pj = JSON.parse(
|
|
127
|
-
fs.readFileSync(
|
|
128
|
+
fs.readFileSync(apcProjectFile(proj.path), "utf8")
|
|
128
129
|
);
|
|
129
130
|
if (pj.name) proj.name = pj.name;
|
|
130
131
|
if (pj.apx_id) proj.apxId = pj.apx_id;
|
|
@@ -608,7 +609,7 @@ const apxEngine = {
|
|
|
608
609
|
let apxId = null;
|
|
609
610
|
try {
|
|
610
611
|
const pj = JSON.parse(
|
|
611
|
-
fs.readFileSync(
|
|
612
|
+
fs.readFileSync(apcProjectFile(dir), "utf8")
|
|
612
613
|
);
|
|
613
614
|
apxId = pj.apx_id || null;
|
|
614
615
|
} catch {}
|
|
@@ -4,6 +4,7 @@ import path from "node:path";
|
|
|
4
4
|
import os from "node:os";
|
|
5
5
|
import readline from "node:readline";
|
|
6
6
|
import { findApfRoot } from "#core/apc/parser.js";
|
|
7
|
+
import { apcSkillsDir } from "#core/apc/paths.js";
|
|
7
8
|
import { http } from "../http.js";
|
|
8
9
|
import {
|
|
9
10
|
IDE_TARGETS,
|
|
@@ -11,7 +12,23 @@ import {
|
|
|
11
12
|
installGlobalSkills,
|
|
12
13
|
listBundledSkillSlugs,
|
|
13
14
|
listBundledSkills,
|
|
15
|
+
listEngineSkills,
|
|
16
|
+
listLegacyPruneSlugs,
|
|
14
17
|
} from "#core/apc/scaffold.js";
|
|
18
|
+
import {
|
|
19
|
+
ensureIndex,
|
|
20
|
+
planIndex,
|
|
21
|
+
readIndex,
|
|
22
|
+
clearIndex,
|
|
23
|
+
indexPath,
|
|
24
|
+
} from "#core/agent/skills/index-store.js";
|
|
25
|
+
import { isInspectorEnabled } from "#core/agent/skills/inspector.js";
|
|
26
|
+
import {
|
|
27
|
+
inspectPromptForSkills,
|
|
28
|
+
summarizeTrace,
|
|
29
|
+
INSPECTOR_DEFAULTS,
|
|
30
|
+
} from "#core/agent/skills/inspector.js";
|
|
31
|
+
import { readConfig, writeConfig } from "#core/config/index.js";
|
|
15
32
|
|
|
16
33
|
// ---------------------------------------------------------------------------
|
|
17
34
|
// Prompt helper
|
|
@@ -27,6 +44,31 @@ function ask(question) {
|
|
|
27
44
|
});
|
|
28
45
|
}
|
|
29
46
|
|
|
47
|
+
// When the Skill Inspector is on, the catalog it scores against must stay in
|
|
48
|
+
// sync with what's installed. Called after add/sync so a freshly available
|
|
49
|
+
// skill is searchable immediately, without a separate `apx skills index`.
|
|
50
|
+
// No-op (silent) when the inspector is disabled — nothing reads the index then.
|
|
51
|
+
async function reindexInspectorIfEnabled() {
|
|
52
|
+
let config;
|
|
53
|
+
try {
|
|
54
|
+
config = readConfig();
|
|
55
|
+
} catch {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (!isInspectorEnabled(config)) return;
|
|
59
|
+
try {
|
|
60
|
+
const plan = planIndex({});
|
|
61
|
+
const work = plan.missing.length + plan.stale.length + plan.gone.length;
|
|
62
|
+
if (work === 0) return;
|
|
63
|
+
process.stdout.write(`\n Skill Inspector on — reindexing ${work} changed skill(s)… `);
|
|
64
|
+
const out = await ensureIndex({ embedOpts: { globalConfig: config } });
|
|
65
|
+
const c = out.changed;
|
|
66
|
+
console.log(`done (${out.embedder}: +${c.added.length} ~${c.refreshed.length} -${c.removed.length}).`);
|
|
67
|
+
} catch (e) {
|
|
68
|
+
console.log(`\n (skill index refresh failed: ${e.message})`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
30
72
|
// ---------------------------------------------------------------------------
|
|
31
73
|
// apx skills add [<target>...] [--global] [--project]
|
|
32
74
|
// ---------------------------------------------------------------------------
|
|
@@ -62,6 +104,7 @@ export async function cmdSkillsAdd(args) {
|
|
|
62
104
|
}
|
|
63
105
|
console.log("\n Loaded by: Claude Code, Cursor, Codex (OpenAI), Antigravity, and skills.sh-compatible tools.");
|
|
64
106
|
console.log(" Activates automatically when working in a project with AGENTS.md or .apc/");
|
|
107
|
+
await reindexInspectorIfEnabled();
|
|
65
108
|
return;
|
|
66
109
|
}
|
|
67
110
|
|
|
@@ -90,6 +133,7 @@ export async function cmdSkillsAdd(args) {
|
|
|
90
133
|
console.log("");
|
|
91
134
|
for (const t of notes) console.log(` note: ${t.note}`);
|
|
92
135
|
}
|
|
136
|
+
await reindexInspectorIfEnabled();
|
|
93
137
|
}
|
|
94
138
|
|
|
95
139
|
// ---------------------------------------------------------------------------
|
|
@@ -100,37 +144,27 @@ export async function cmdSkillsAdd(args) {
|
|
|
100
144
|
// ---------------------------------------------------------------------------
|
|
101
145
|
|
|
102
146
|
export async function cmdSkillsSync(args) {
|
|
103
|
-
const includeOptional = !!args?.flags?.["include-optional"] || !!args?.flags?.optional;
|
|
104
|
-
const includeInternal = !!args?.flags?.["include-internal"] || !!args?.flags?.internal;
|
|
105
147
|
const prune = args?.flags?.["no-prune"] ? false : true;
|
|
106
148
|
|
|
107
|
-
const results = installGlobalSkills({
|
|
149
|
+
const results = installGlobalSkills({ prune });
|
|
108
150
|
const home = os.homedir();
|
|
109
151
|
|
|
110
|
-
// Group by skill so the output is dense and scannable.
|
|
111
152
|
const bySkill = {};
|
|
112
|
-
const scopeOf = {};
|
|
113
153
|
for (const r of results) {
|
|
114
154
|
if (!bySkill[r.skill]) bySkill[r.skill] = [];
|
|
115
|
-
bySkill[r.skill].push({ dir: r.dir.replace(home, "~"), status: r.status });
|
|
116
|
-
scopeOf[r.skill] = r.scope;
|
|
155
|
+
bySkill[r.skill].push({ dir: r.dir.replace(home, "~"), status: r.status, scope: r.scope });
|
|
117
156
|
}
|
|
118
157
|
|
|
119
|
-
const
|
|
120
|
-
if (
|
|
121
|
-
console.log("(no
|
|
158
|
+
const engineSet = listEngineSkills().map((s) => s.slug);
|
|
159
|
+
if (engineSet.length === 0) {
|
|
160
|
+
console.log("(no engine skills found in skills/engines/)");
|
|
122
161
|
return;
|
|
123
162
|
}
|
|
124
163
|
|
|
125
|
-
|
|
126
|
-
if (includeOptional) filters.push("+optional");
|
|
127
|
-
if (includeInternal) filters.push("+internal");
|
|
128
|
-
console.log(
|
|
129
|
-
`Syncing ${slugs.length} bundled skill(s) to global skill dirs` +
|
|
130
|
-
(filters.length ? ` [${filters.join(" ")}]` : "") + ":\n"
|
|
131
|
-
);
|
|
164
|
+
console.log(`Syncing engine skill set (${engineSet.join(", ")}) to global dirs:\n`);
|
|
132
165
|
|
|
133
|
-
const
|
|
166
|
+
const slugs = Object.keys(bySkill).sort();
|
|
167
|
+
const sw = Math.max(...slugs.map((s) => s.length), 8);
|
|
134
168
|
const totals = { unchanged: 0, updated: 0, created: 0, pruned: 0 };
|
|
135
169
|
for (const slug of slugs) {
|
|
136
170
|
const entries = bySkill[slug];
|
|
@@ -141,9 +175,8 @@ export async function cmdSkillsSync(args) {
|
|
|
141
175
|
for (const k of ["created", "updated", "unchanged", "pruned"]) {
|
|
142
176
|
if (counts[k]) parts.push(`${counts[k]} ${k}`);
|
|
143
177
|
}
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
console.log(` ${slug.padEnd(sw)}${tag.padEnd(11)} ${parts.join(", ")}`);
|
|
178
|
+
const tag = entries[0]?.scope === "legacy" ? " [legacy]" : "";
|
|
179
|
+
console.log(` ${slug.padEnd(sw)}${tag.padEnd(10)} ${parts.join(", ")}`);
|
|
147
180
|
}
|
|
148
181
|
console.log("");
|
|
149
182
|
console.log(`Targets: .claude/skills, .cursor/skills, .codex/skills, .agents/skills`);
|
|
@@ -153,21 +186,6 @@ export async function cmdSkillsSync(args) {
|
|
|
153
186
|
}
|
|
154
187
|
console.log(`Totals: ${totalParts.join(", ") || "(no changes)"}`);
|
|
155
188
|
|
|
156
|
-
// Hint about non-default tiers.
|
|
157
|
-
const skipped = listBundledSkills().filter(
|
|
158
|
-
(s) =>
|
|
159
|
-
(s.scope === "internal" && !includeInternal) ||
|
|
160
|
-
(s.scope === "optional" && !includeOptional)
|
|
161
|
-
);
|
|
162
|
-
if (skipped.length > 0) {
|
|
163
|
-
console.log("");
|
|
164
|
-
console.log("Skipped (not pushed by default):");
|
|
165
|
-
for (const s of skipped) console.log(` ${s.slug.padEnd(sw)} scope=${s.scope}`);
|
|
166
|
-
console.log("");
|
|
167
|
-
console.log("Re-run with --include-optional / --include-internal to push them too,");
|
|
168
|
-
console.log("or `apx skills add <slug> --global` for one-off install.");
|
|
169
|
-
}
|
|
170
|
-
|
|
171
189
|
if (args?.flags?.verbose) {
|
|
172
190
|
console.log("");
|
|
173
191
|
for (const slug of slugs) {
|
|
@@ -177,6 +195,7 @@ export async function cmdSkillsSync(args) {
|
|
|
177
195
|
}
|
|
178
196
|
}
|
|
179
197
|
}
|
|
198
|
+
await reindexInspectorIfEnabled();
|
|
180
199
|
}
|
|
181
200
|
|
|
182
201
|
// ---------------------------------------------------------------------------
|
|
@@ -184,8 +203,8 @@ export async function cmdSkillsSync(args) {
|
|
|
184
203
|
// ---------------------------------------------------------------------------
|
|
185
204
|
|
|
186
205
|
export async function cmdSkillsList(args = {}) {
|
|
187
|
-
// --all queries the daemon, which returns project + global + bundled
|
|
188
|
-
//
|
|
206
|
+
// --all queries the daemon, which returns project + global + bundled
|
|
207
|
+
// (the same catalog the super-agent sees and the web picker uses).
|
|
189
208
|
// Without --all we only list `.apc/skills/` (what the user installed in
|
|
190
209
|
// THIS project), matching the historical behaviour.
|
|
191
210
|
if (args?.flags?.all) {
|
|
@@ -205,7 +224,7 @@ export async function cmdSkillsList(args = {}) {
|
|
|
205
224
|
}
|
|
206
225
|
|
|
207
226
|
const root = findApfRoot();
|
|
208
|
-
const skillsDir = root ?
|
|
227
|
+
const skillsDir = root ? apcSkillsDir(root) : null;
|
|
209
228
|
const files = skillsDir && fs.existsSync(skillsDir)
|
|
210
229
|
? fs.readdirSync(skillsDir).filter((f) => f.endsWith(".md"))
|
|
211
230
|
: [];
|
|
@@ -224,17 +243,15 @@ export async function cmdSkillsList(args = {}) {
|
|
|
224
243
|
export async function cmdSkillsStatus() {
|
|
225
244
|
const root = findApfRoot();
|
|
226
245
|
|
|
227
|
-
|
|
228
|
-
const bundled = listBundledSkills();
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
optional: bundled.filter((s) => s.scope === "optional"),
|
|
232
|
-
internal: bundled.filter((s) => s.scope === "internal"),
|
|
233
|
-
};
|
|
246
|
+
const engineSet = listEngineSkills(); // what we publish to engines
|
|
247
|
+
const bundled = listBundledSkills(); // what stays in-repo for the super-agent
|
|
248
|
+
const legacy = listLegacyPruneSlugs(); // slugs APX shipped historically — pruned on sync
|
|
249
|
+
|
|
234
250
|
console.log(
|
|
235
|
-
`
|
|
236
|
-
|
|
251
|
+
`Engine skill set (replicated to global dirs): ${engineSet.length} ` +
|
|
252
|
+
`(${engineSet.map((s) => s.slug).join(", ") || "—"})`
|
|
237
253
|
);
|
|
254
|
+
console.log(`In-repo bundled skills (super-agent only): ${bundled.length}`);
|
|
238
255
|
console.log("");
|
|
239
256
|
console.log(`Global skill dirs:`);
|
|
240
257
|
const GLOBAL_DIRS = [
|
|
@@ -243,17 +260,23 @@ export async function cmdSkillsStatus() {
|
|
|
243
260
|
{ label: "Codex", dir: path.join(os.homedir(), ".codex", "skills") },
|
|
244
261
|
{ label: "Antigravity / others", dir: path.join(os.homedir(), ".agents", "skills") },
|
|
245
262
|
];
|
|
246
|
-
const
|
|
263
|
+
const allSlugs = [...engineSet.map((s) => s.slug), ...legacy];
|
|
264
|
+
const sw = Math.max(...allSlugs.map((s) => s.length), 8);
|
|
247
265
|
for (const { label, dir } of GLOBAL_DIRS) {
|
|
248
266
|
console.log(`\n ${label} — ${dir.replace(os.homedir(), "~")}`);
|
|
249
|
-
for (const { slug
|
|
267
|
+
for (const { slug } of engineSet) {
|
|
250
268
|
const dest = path.join(dir, slug, "SKILL.md");
|
|
251
269
|
const present = fs.existsSync(dest);
|
|
252
|
-
const
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
270
|
+
const state = present ? "✓ installed" : "✗ MISSING (run `apx skills sync`)";
|
|
271
|
+
console.log(` ${slug.padEnd(sw)} ${state}`);
|
|
272
|
+
}
|
|
273
|
+
const stale = legacy.filter((slug) =>
|
|
274
|
+
fs.existsSync(path.join(dir, slug, "SKILL.md"))
|
|
275
|
+
);
|
|
276
|
+
if (stale.length) {
|
|
277
|
+
for (const slug of stale) {
|
|
278
|
+
console.log(` ${slug.padEnd(sw)} [legacy] ⚠ stale (run \`apx skills sync\` to prune)`);
|
|
279
|
+
}
|
|
257
280
|
}
|
|
258
281
|
}
|
|
259
282
|
|
|
@@ -280,3 +303,215 @@ export async function cmdSkillsStatus() {
|
|
|
280
303
|
console.log("\n Tip: run `apx skills add` for an interactive install.");
|
|
281
304
|
console.log(" Claude Desktop has no project-file support (use apx-mcp instead).");
|
|
282
305
|
}
|
|
306
|
+
|
|
307
|
+
// ---------------------------------------------------------------------------
|
|
308
|
+
// apx skills index [--reset] [--force]
|
|
309
|
+
//
|
|
310
|
+
// Build the persistent vector index that powers the skill Inspector. Runs the
|
|
311
|
+
// configured embedding provider (defaults to local: ollama → tf fallback) over
|
|
312
|
+
// every skill's condensed description and writes ~/.apx/skills/.index.json.
|
|
313
|
+
// ---------------------------------------------------------------------------
|
|
314
|
+
|
|
315
|
+
function renderBar(done, total, width = 24) {
|
|
316
|
+
if (!Number.isFinite(total) || total <= 0) return "";
|
|
317
|
+
const ratio = Math.max(0, Math.min(1, done / total));
|
|
318
|
+
const filled = Math.round(ratio * width);
|
|
319
|
+
return "[" + "█".repeat(filled) + " ".repeat(width - filled) + "]";
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
export async function cmdSkillsIndex(args = {}) {
|
|
323
|
+
const reset = !!args?.flags?.reset;
|
|
324
|
+
const force = !!args?.flags?.force;
|
|
325
|
+
if (reset) clearIndex();
|
|
326
|
+
|
|
327
|
+
const config = readConfig();
|
|
328
|
+
const root = findApfRoot();
|
|
329
|
+
const projectPath = root || undefined;
|
|
330
|
+
|
|
331
|
+
const plan = planIndex({ projectPath });
|
|
332
|
+
if (plan.total === 0) {
|
|
333
|
+
console.log("(no skills available — install some first with `apx skills sync` or drop a SKILL.md in ~/.apx/skills/<slug>/)");
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
const headline = force
|
|
338
|
+
? `Rebuilding index for ${plan.total} skills (force).`
|
|
339
|
+
: `Indexing ${plan.total} skills (${plan.existing.length} cached · ${plan.missing.length} new · ${plan.stale.length} stale · ${plan.gone.length} gone).`;
|
|
340
|
+
console.log(headline);
|
|
341
|
+
|
|
342
|
+
const t0 = Date.now();
|
|
343
|
+
let lastLine = "";
|
|
344
|
+
const out = await ensureIndex({
|
|
345
|
+
projectPath,
|
|
346
|
+
embedOpts: { globalConfig: config },
|
|
347
|
+
force,
|
|
348
|
+
onProgress: ({ done, total, slug, action }) => {
|
|
349
|
+
const bar = renderBar(done, total);
|
|
350
|
+
const tag = action.padEnd(9);
|
|
351
|
+
const line = `\r${bar} ${done}/${total} ${tag} ${slug}`.padEnd(lastLine.length, " ");
|
|
352
|
+
process.stdout.write(line);
|
|
353
|
+
lastLine = line;
|
|
354
|
+
},
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
const elapsedMs = Date.now() - t0;
|
|
358
|
+
process.stdout.write("\r" + " ".repeat(lastLine.length) + "\r");
|
|
359
|
+
|
|
360
|
+
const c = out.changed;
|
|
361
|
+
console.log(
|
|
362
|
+
`Done in ${(elapsedMs / 1000).toFixed(1)}s using ${out.embedder} (dim ${out.dim}).\n` +
|
|
363
|
+
` added: ${c.added.length}\n` +
|
|
364
|
+
` refreshed: ${c.refreshed.length}\n` +
|
|
365
|
+
` removed: ${c.removed.length}\n` +
|
|
366
|
+
` kept: ${c.kept.length}\n` +
|
|
367
|
+
` index: ${indexPath()}`
|
|
368
|
+
);
|
|
369
|
+
if (c.added.length || c.refreshed.length) {
|
|
370
|
+
const sample = [...c.added, ...c.refreshed].slice(0, 6).join(", ");
|
|
371
|
+
if (sample) console.log(` changes: ${sample}${(c.added.length + c.refreshed.length) > 6 ? ", …" : ""}`);
|
|
372
|
+
}
|
|
373
|
+
if (out.embedder === "tf") {
|
|
374
|
+
console.log(" note: using offline TF fallback (no embedding provider reachable). Configure one in config.memory.embeddings for better recall.");
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// ---------------------------------------------------------------------------
|
|
379
|
+
// apx skills inspect <prompt>
|
|
380
|
+
//
|
|
381
|
+
// Show what the Inspector would inject for a given user prompt. Doesn't touch
|
|
382
|
+
// the model — pure middleware debug. Useful to tune thresholds and to see why
|
|
383
|
+
// a skill did or didn't fire.
|
|
384
|
+
// ---------------------------------------------------------------------------
|
|
385
|
+
|
|
386
|
+
export async function cmdSkillsInspect(args) {
|
|
387
|
+
const promptParts = args?._ || [];
|
|
388
|
+
const prompt = promptParts.join(" ").trim();
|
|
389
|
+
if (!prompt) {
|
|
390
|
+
console.error("usage: apx skills inspect \"<prompt text>\"");
|
|
391
|
+
process.exitCode = 2;
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
const config = readConfig();
|
|
396
|
+
const root = findApfRoot();
|
|
397
|
+
const projectPath = root || undefined;
|
|
398
|
+
|
|
399
|
+
// Force the inspector on for this command even if config has it off — the
|
|
400
|
+
// operator is explicitly asking "what WOULD the inspector do?".
|
|
401
|
+
const probedConfig = structuredClone(config);
|
|
402
|
+
probedConfig.skills = probedConfig.skills || {};
|
|
403
|
+
probedConfig.skills.inspector = {
|
|
404
|
+
...INSPECTOR_DEFAULTS,
|
|
405
|
+
...(probedConfig.skills.inspector || {}),
|
|
406
|
+
enabled: true,
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
const out = await inspectPromptForSkills({
|
|
410
|
+
prompt,
|
|
411
|
+
projectPath,
|
|
412
|
+
globalConfig: probedConfig,
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
console.log(`prompt: ${prompt}`);
|
|
416
|
+
console.log(`embedder: ${out.trace.embedder || "(none)"}`);
|
|
417
|
+
console.log(`decision: ${summarizeTrace(out.trace)}`);
|
|
418
|
+
if (out.trace.scored?.length) {
|
|
419
|
+
console.log("scores:");
|
|
420
|
+
for (const s of out.trace.scored) console.log(` ${s.sim.toFixed(3)} ${s.slug}`);
|
|
421
|
+
}
|
|
422
|
+
if (out.contextNote) {
|
|
423
|
+
console.log("");
|
|
424
|
+
console.log("--- contextNote that would be injected ---");
|
|
425
|
+
console.log(out.contextNote);
|
|
426
|
+
console.log("--- end ---");
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
// ---------------------------------------------------------------------------
|
|
431
|
+
// apx skills inspector [enable|disable|status|set <key> <value>]
|
|
432
|
+
//
|
|
433
|
+
// Manage config.skills.inspector. All keys live under that namespace; this
|
|
434
|
+
// command is a thin shortcut so you don't have to remember the path.
|
|
435
|
+
// ---------------------------------------------------------------------------
|
|
436
|
+
|
|
437
|
+
const KNOWN_INSPECTOR_KEYS = Object.keys(INSPECTOR_DEFAULTS);
|
|
438
|
+
|
|
439
|
+
function ensureInspectorBlock(cfg) {
|
|
440
|
+
cfg.skills = cfg.skills || {};
|
|
441
|
+
cfg.skills.inspector = { ...INSPECTOR_DEFAULTS, ...(cfg.skills.inspector || {}) };
|
|
442
|
+
return cfg;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
function printInspectorStatus(cfg) {
|
|
446
|
+
const insp = cfg.skills?.inspector || {};
|
|
447
|
+
const merged = { ...INSPECTOR_DEFAULTS, ...insp };
|
|
448
|
+
console.log(`Skill Inspector: ${merged.enabled ? "ENABLED" : "disabled"}`);
|
|
449
|
+
for (const k of KNOWN_INSPECTOR_KEYS) {
|
|
450
|
+
if (k === "enabled") continue;
|
|
451
|
+
console.log(` ${k.padEnd(16)} ${merged[k]}`);
|
|
452
|
+
}
|
|
453
|
+
const idx = readIndex();
|
|
454
|
+
const count = Object.keys(idx.items || {}).length;
|
|
455
|
+
console.log("");
|
|
456
|
+
console.log(`Index: ${count} skills (${idx.embedder || "—"}, dim ${idx.dim || "—"})`);
|
|
457
|
+
console.log(`File: ${indexPath()}`);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
export async function cmdSkillsInspector(args) {
|
|
461
|
+
const sub = (args?._ || [])[0];
|
|
462
|
+
const cfg = readConfig();
|
|
463
|
+
|
|
464
|
+
if (!sub || sub === "status") {
|
|
465
|
+
printInspectorStatus(cfg);
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
if (sub === "enable" || sub === "on") {
|
|
469
|
+
ensureInspectorBlock(cfg).skills.inspector.enabled = true;
|
|
470
|
+
writeConfig(cfg);
|
|
471
|
+
console.log("Skill Inspector ENABLED. The catalog-wide hint block will be suppressed; per-turn RAG decides what skills go into context.");
|
|
472
|
+
console.log("Tip: run `apx skills index` once so the inspector has cached vectors to score against.");
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
if (sub === "disable" || sub === "off") {
|
|
476
|
+
ensureInspectorBlock(cfg).skills.inspector.enabled = false;
|
|
477
|
+
writeConfig(cfg);
|
|
478
|
+
console.log("Skill Inspector disabled. Falling back to the legacy slug hint + passive RAG nudge.");
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
if (sub === "set") {
|
|
482
|
+
const key = args._[1];
|
|
483
|
+
const value = args._[2];
|
|
484
|
+
if (!key || value === undefined) {
|
|
485
|
+
console.error("usage: apx skills inspector set <key> <value>");
|
|
486
|
+
console.error(`keys: ${KNOWN_INSPECTOR_KEYS.join(", ")}`);
|
|
487
|
+
process.exitCode = 2;
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
if (!KNOWN_INSPECTOR_KEYS.includes(key)) {
|
|
491
|
+
console.error(`unknown key "${key}". Known: ${KNOWN_INSPECTOR_KEYS.join(", ")}`);
|
|
492
|
+
process.exitCode = 2;
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
ensureInspectorBlock(cfg);
|
|
496
|
+
const def = INSPECTOR_DEFAULTS[key];
|
|
497
|
+
let coerced = value;
|
|
498
|
+
if (typeof def === "boolean") coerced = value === "true" || value === "1" || value === "on";
|
|
499
|
+
else if (typeof def === "number") {
|
|
500
|
+
const n = Number(value);
|
|
501
|
+
if (!Number.isFinite(n)) {
|
|
502
|
+
console.error(`value for "${key}" must be a number; got "${value}"`);
|
|
503
|
+
process.exitCode = 2;
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
coerced = n;
|
|
507
|
+
}
|
|
508
|
+
cfg.skills.inspector[key] = coerced;
|
|
509
|
+
writeConfig(cfg);
|
|
510
|
+
console.log(`skills.inspector.${key} = ${coerced}`);
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
console.error(`unknown inspector subcommand: ${sub}`);
|
|
515
|
+
console.error("usage: apx skills inspector [status|enable|disable|set <key> <value>]");
|
|
516
|
+
process.exitCode = 2;
|
|
517
|
+
}
|
|
@@ -100,7 +100,7 @@ import {
|
|
|
100
100
|
import { cmdPluginsList, cmdPluginStatus } from "./commands/plugins.js";
|
|
101
101
|
import { cmdDesktopStart, cmdDesktopStop, cmdDesktopStatus, cmdDesktopInstall, cmdDesktopUninstall } from "./commands/desktop.js";
|
|
102
102
|
import { cmdVoiceSay, cmdVoiceListen, cmdVoiceProviders } from "./commands/voice.js";
|
|
103
|
-
import { cmdSkillsAdd, cmdSkillsList, cmdSkillsStatus, cmdSkillsSync } from "./commands/skills.js";
|
|
103
|
+
import { cmdSkillsAdd, cmdSkillsList, cmdSkillsStatus, cmdSkillsSync, cmdSkillsIndex, cmdSkillsInspect, cmdSkillsInspector } from "./commands/skills.js";
|
|
104
104
|
import { cmdIdentity } from "./commands/identity.js";
|
|
105
105
|
import { cmdCommandList, cmdCommandShow } from "./commands/command.js";
|
|
106
106
|
import { cmdUpdate } from "./commands/update.js";
|
|
@@ -110,6 +110,7 @@ import { cmdModel } from "./commands/model.js";
|
|
|
110
110
|
import { cmdPair, cmdPairWeb, cmdPairList, cmdPairRevoke } from "./commands/pair.js";
|
|
111
111
|
import { checkForUpdate } from "#core/update-check.js";
|
|
112
112
|
import { mascot } from "#core/mascot.js";
|
|
113
|
+
import { apxHeader, apxBanner } from "./branding.js";
|
|
113
114
|
import {
|
|
114
115
|
cmdRoutineList,
|
|
115
116
|
cmdRoutineGet,
|
|
@@ -1350,12 +1351,23 @@ const HELP_TOPICS = new Map(Object.entries({
|
|
|
1350
1351
|
skills: topic({
|
|
1351
1352
|
title: "apx skills",
|
|
1352
1353
|
summary: "Install and inspect APX skill files for IDEs and agent tools.",
|
|
1353
|
-
usage: [
|
|
1354
|
+
usage: [
|
|
1355
|
+
"apx skills [add] [targets] [--global]",
|
|
1356
|
+
"apx skills sync",
|
|
1357
|
+
"apx skills list",
|
|
1358
|
+
"apx skills status",
|
|
1359
|
+
"apx skills index [--reset] [--force]",
|
|
1360
|
+
"apx skills inspect \"<prompt>\"",
|
|
1361
|
+
"apx skills inspector [status|enable|disable|set <key> <value>]",
|
|
1362
|
+
],
|
|
1354
1363
|
commands: [
|
|
1355
1364
|
["add [targets]", "Install APX skills into selected targets."],
|
|
1356
1365
|
["sync | refresh", "Re-install every bundled skill to every global skill dir (idempotent)."],
|
|
1357
1366
|
["list | ls", "List skills installed in this project's .apc/skills/."],
|
|
1358
1367
|
["status", "Show which bundled skills are present in each global dir."],
|
|
1368
|
+
["index", "Build/refresh the local RAG vector index used by the Skill Inspector."],
|
|
1369
|
+
["inspect", "Show which skills the Inspector would surface for a given prompt (debug)."],
|
|
1370
|
+
["inspector", "Toggle and tune the Skill Inspector (per-turn skill RAG middleware)."],
|
|
1359
1371
|
],
|
|
1360
1372
|
examples: [
|
|
1361
1373
|
"apx skills add claude-code cursor",
|
|
@@ -1403,6 +1415,40 @@ const HELP_TOPICS = new Map(Object.entries({
|
|
|
1403
1415
|
usage: ["apx skills status"],
|
|
1404
1416
|
examples: ["apx skills status"],
|
|
1405
1417
|
}),
|
|
1418
|
+
"skills index": topic({
|
|
1419
|
+
title: "apx skills index",
|
|
1420
|
+
summary:
|
|
1421
|
+
"Build or refresh the local vector index that powers the Skill Inspector. Embeds each skill's condensed description with the configured embeddings provider (defaults to local: ollama → tf fallback). Idempotent: skills with unchanged file+description are kept. Use --force to re-embed everything; --reset to also delete the on-disk index first.",
|
|
1422
|
+
usage: ["apx skills index [--reset] [--force]"],
|
|
1423
|
+
options: [
|
|
1424
|
+
["--force", "Re-embed every skill, ignoring cached vectors."],
|
|
1425
|
+
["--reset", "Delete the index file before rebuilding."],
|
|
1426
|
+
],
|
|
1427
|
+
examples: ["apx skills index", "apx skills index --force", "apx skills index --reset"],
|
|
1428
|
+
}),
|
|
1429
|
+
"skills inspect": topic({
|
|
1430
|
+
title: "apx skills inspect",
|
|
1431
|
+
summary:
|
|
1432
|
+
"Dry-run the Skill Inspector against a prompt. Shows top similarity scores, which skill (if any) would be loaded inline, which would be hinted, and the actual contextNote that would be injected into the next turn's system prompt. The model is NOT called.",
|
|
1433
|
+
usage: ["apx skills inspect \"<prompt text>\""],
|
|
1434
|
+
examples: [
|
|
1435
|
+
"apx skills inspect \"crear un video promocional\"",
|
|
1436
|
+
"apx skills inspect \"profile the slow endpoint\"",
|
|
1437
|
+
],
|
|
1438
|
+
}),
|
|
1439
|
+
"skills inspector": topic({
|
|
1440
|
+
title: "apx skills inspector",
|
|
1441
|
+
summary:
|
|
1442
|
+
"Toggle and tune the Skill Inspector (per-turn skill RAG). When ON: the static slug-dump in the system prompt is suppressed and a local RAG picks 0–N skills per turn — loading the body of high-confidence matches, hinting mid-confidence ones, injecting nothing below threshold. When OFF: legacy behaviour (full slug list + passive suggestion). Opt-in test feature.",
|
|
1443
|
+
usage: ["apx skills inspector [status|enable|disable|set <key> <value>]"],
|
|
1444
|
+
examples: [
|
|
1445
|
+
"apx skills inspector enable",
|
|
1446
|
+
"apx skills inspector disable",
|
|
1447
|
+
"apx skills inspector status",
|
|
1448
|
+
"apx skills inspector set load_threshold 0.5",
|
|
1449
|
+
"apx skills inspector set max_loaded 2",
|
|
1450
|
+
],
|
|
1451
|
+
}),
|
|
1406
1452
|
plugins: topic({
|
|
1407
1453
|
title: "apx plugins",
|
|
1408
1454
|
summary: "Inspect loaded APX daemon plugins.",
|
|
@@ -2530,6 +2576,9 @@ async function dispatch(cmd, rest) {
|
|
|
2530
2576
|
else if (sub === "list" || sub === "ls") await cmdSkillsList(a);
|
|
2531
2577
|
else if (sub === "status") await cmdSkillsStatus();
|
|
2532
2578
|
else if (sub === "sync" || sub === "refresh") await cmdSkillsSync(a);
|
|
2579
|
+
else if (sub === "index") await cmdSkillsIndex(a);
|
|
2580
|
+
else if (sub === "inspect") await cmdSkillsInspect(a);
|
|
2581
|
+
else if (sub === "inspector") await cmdSkillsInspector(a);
|
|
2533
2582
|
else die(`unknown skills subcommand: ${sub}`);
|
|
2534
2583
|
break;
|
|
2535
2584
|
}
|
|
@@ -2583,8 +2632,41 @@ async function dispatch(cmd, rest) {
|
|
|
2583
2632
|
}
|
|
2584
2633
|
|
|
2585
2634
|
const [topCmd, ...topRest] = argv;
|
|
2635
|
+
|
|
2636
|
+
// ── CLI branding ────────────────────────────────────────────────────────────
|
|
2637
|
+
// Every command prints an "APX CLI · vX · <command>" mark to stderr (so stdout
|
|
2638
|
+
// pipes stay clean). Two exceptions:
|
|
2639
|
+
// - SELF_BRANDED: commands that already render their own logo/mascot/status
|
|
2640
|
+
// block — re-stamping them would double up.
|
|
2641
|
+
// - BANNERED: branding-heavy moments that get the big ASCII wordmark instead
|
|
2642
|
+
// of the compact line.
|
|
2643
|
+
// Suppress everything with APX_QUIET=1 / APX_NO_BANNER=1 (see branding.js).
|
|
2644
|
+
const SELF_BRANDED = new Set([
|
|
2645
|
+
"status", "setup", "install", "daemon", "update", "upgrade", "help",
|
|
2646
|
+
]);
|
|
2647
|
+
const BANNERED = new Set(["init"]);
|
|
2648
|
+
|
|
2649
|
+
function brandFor(cmd, rest) {
|
|
2650
|
+
if (SELF_BRANDED.has(cmd)) return;
|
|
2651
|
+
// Subtitle = the command path only (cmd + leading subcommand tokens), never
|
|
2652
|
+
// free-form args. Stop at the first token that looks like an argument: a flag,
|
|
2653
|
+
// something with spaces (a quoted prompt), or anything long. So
|
|
2654
|
+
// `skills inspector status` shows fully, but `exec "long prompt…"` shows just
|
|
2655
|
+
// `exec`.
|
|
2656
|
+
const path = [cmd];
|
|
2657
|
+
for (const tok of rest) {
|
|
2658
|
+
if (!tok || tok.startsWith("-") || /\s/.test(tok) || tok.length > 24) break;
|
|
2659
|
+
path.push(tok);
|
|
2660
|
+
if (path.length >= 3) break;
|
|
2661
|
+
}
|
|
2662
|
+
const subtitle = path.join(" ");
|
|
2663
|
+
if (BANNERED.has(cmd)) apxBanner(VERSION, subtitle);
|
|
2664
|
+
else apxHeader(VERSION, subtitle);
|
|
2665
|
+
}
|
|
2666
|
+
|
|
2586
2667
|
(async () => {
|
|
2587
2668
|
try {
|
|
2669
|
+
brandFor(topCmd, topRest);
|
|
2588
2670
|
await dispatch(topCmd, topRest);
|
|
2589
2671
|
checkForUpdate(VERSION);
|
|
2590
2672
|
} catch (err) {
|