agent-nuvira 3.3.13 → 3.3.15
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/README.md +67 -1
- package/dist/agents/agents/planner.d.ts.map +1 -1
- package/dist/agents/agents/planner.js +9 -0
- package/dist/agents/agents/planner.js.map +1 -1
- package/dist/agents/orchestrator.d.ts +31 -0
- package/dist/agents/orchestrator.d.ts.map +1 -1
- package/dist/agents/orchestrator.js +74 -126
- package/dist/agents/orchestrator.js.map +1 -1
- package/dist/cli/chat.d.ts +89 -0
- package/dist/cli/chat.d.ts.map +1 -1
- package/dist/cli/chat.js +765 -33
- package/dist/cli/chat.js.map +1 -1
- package/dist/cli/cli-program.d.ts.map +1 -1
- package/dist/cli/cli-program.js +12 -0
- package/dist/cli/cli-program.js.map +1 -1
- package/dist/cli/config.d.ts +12 -0
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +86 -0
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/decisions.d.ts +28 -0
- package/dist/cli/decisions.d.ts.map +1 -0
- package/dist/cli/decisions.js +140 -0
- package/dist/cli/decisions.js.map +1 -0
- package/dist/cli/doctor.d.ts +6 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +46 -0
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/failover-runner.d.ts.map +1 -1
- package/dist/cli/failover-runner.js +19 -1
- package/dist/cli/failover-runner.js.map +1 -1
- package/dist/cli/feedback.d.ts.map +1 -1
- package/dist/cli/feedback.js +5 -1
- package/dist/cli/feedback.js.map +1 -1
- package/dist/cli/hooks.d.ts +30 -0
- package/dist/cli/hooks.d.ts.map +1 -0
- package/dist/cli/hooks.js +224 -0
- package/dist/cli/hooks.js.map +1 -0
- package/dist/cli/knowledge.d.ts +9 -1
- package/dist/cli/knowledge.d.ts.map +1 -1
- package/dist/cli/knowledge.js +93 -2
- package/dist/cli/knowledge.js.map +1 -1
- package/dist/cli/loop-executor.d.ts.map +1 -1
- package/dist/cli/loop-executor.js +47 -12
- package/dist/cli/loop-executor.js.map +1 -1
- package/dist/cli/model.d.ts +20 -0
- package/dist/cli/model.d.ts.map +1 -1
- package/dist/cli/model.js +294 -14
- package/dist/cli/model.js.map +1 -1
- package/dist/cli/rate.d.ts +78 -0
- package/dist/cli/rate.d.ts.map +1 -0
- package/dist/cli/rate.js +294 -0
- package/dist/cli/rate.js.map +1 -0
- package/dist/config/process-env.d.ts.map +1 -1
- package/dist/config/process-env.js +10 -0
- package/dist/config/process-env.js.map +1 -1
- package/dist/enterprise/vault.d.ts.map +1 -1
- package/dist/enterprise/vault.js +5 -21
- package/dist/enterprise/vault.js.map +1 -1
- package/dist/gateway/hook-contract.d.ts +33 -0
- package/dist/gateway/hook-contract.d.ts.map +1 -1
- package/dist/gateway/hook-contract.js +97 -0
- package/dist/gateway/hook-contract.js.map +1 -1
- package/dist/inference/gemini-adapter.d.ts.map +1 -1
- package/dist/inference/gemini-adapter.js +4 -0
- package/dist/inference/gemini-adapter.js.map +1 -1
- package/dist/inference/interface.d.ts +37 -0
- package/dist/inference/interface.d.ts.map +1 -1
- package/dist/inference/native-tools.d.ts +16 -1
- package/dist/inference/native-tools.d.ts.map +1 -1
- package/dist/inference/native-tools.js +34 -10
- package/dist/inference/native-tools.js.map +1 -1
- package/dist/inference/route-resolver.d.ts +30 -0
- package/dist/inference/route-resolver.d.ts.map +1 -1
- package/dist/inference/route-resolver.js +158 -1
- package/dist/inference/route-resolver.js.map +1 -1
- package/dist/inference/tools.d.ts +16 -1
- package/dist/inference/tools.d.ts.map +1 -1
- package/dist/inference/tools.js +51 -18
- package/dist/inference/tools.js.map +1 -1
- package/dist/learning/acceptance-model.d.ts +247 -0
- package/dist/learning/acceptance-model.d.ts.map +1 -0
- package/dist/learning/acceptance-model.js +708 -0
- package/dist/learning/acceptance-model.js.map +1 -0
- package/dist/learning/auto-router.d.ts +68 -24
- package/dist/learning/auto-router.d.ts.map +1 -1
- package/dist/learning/auto-router.js +301 -96
- package/dist/learning/auto-router.js.map +1 -1
- package/dist/learning/autonomy-policy.d.ts +12 -16
- package/dist/learning/autonomy-policy.d.ts.map +1 -1
- package/dist/learning/autonomy-policy.js +50 -48
- package/dist/learning/autonomy-policy.js.map +1 -1
- package/dist/learning/behavioural-labels.d.ts +86 -0
- package/dist/learning/behavioural-labels.d.ts.map +1 -0
- package/dist/learning/behavioural-labels.js +166 -0
- package/dist/learning/behavioural-labels.js.map +1 -0
- package/dist/learning/capability-evidence.d.ts +167 -0
- package/dist/learning/capability-evidence.d.ts.map +1 -0
- package/dist/learning/capability-evidence.js +210 -0
- package/dist/learning/capability-evidence.js.map +1 -0
- package/dist/learning/capability-readiness.d.ts +64 -0
- package/dist/learning/capability-readiness.d.ts.map +1 -0
- package/dist/learning/capability-readiness.js +74 -0
- package/dist/learning/capability-readiness.js.map +1 -0
- package/dist/learning/capability-types.d.ts +169 -0
- package/dist/learning/capability-types.d.ts.map +1 -0
- package/dist/learning/capability-types.js +20 -0
- package/dist/learning/capability-types.js.map +1 -0
- package/dist/learning/catalog-feed.d.ts +89 -0
- package/dist/learning/catalog-feed.d.ts.map +1 -0
- package/dist/learning/catalog-feed.js +211 -0
- package/dist/learning/catalog-feed.js.map +1 -0
- package/dist/learning/cli-intent-effects.d.ts +60 -0
- package/dist/learning/cli-intent-effects.d.ts.map +1 -0
- package/dist/learning/cli-intent-effects.js +153 -0
- package/dist/learning/cli-intent-effects.js.map +1 -0
- package/dist/learning/command-adaptation.d.ts +41 -0
- package/dist/learning/command-adaptation.d.ts.map +1 -0
- package/dist/learning/command-adaptation.js +122 -0
- package/dist/learning/command-adaptation.js.map +1 -0
- package/dist/learning/consent-picture.d.ts +42 -0
- package/dist/learning/consent-picture.d.ts.map +1 -0
- package/dist/learning/consent-picture.js +53 -0
- package/dist/learning/consent-picture.js.map +1 -0
- package/dist/learning/context-budget.d.ts +37 -6
- package/dist/learning/context-budget.d.ts.map +1 -1
- package/dist/learning/context-budget.js +38 -9
- package/dist/learning/context-budget.js.map +1 -1
- package/dist/learning/decision-log.d.ts +114 -0
- package/dist/learning/decision-log.d.ts.map +1 -0
- package/dist/learning/decision-log.js +296 -0
- package/dist/learning/decision-log.js.map +1 -0
- package/dist/learning/deliverable-class.d.ts.map +1 -1
- package/dist/learning/deliverable-class.js +19 -0
- package/dist/learning/deliverable-class.js.map +1 -1
- package/dist/learning/deliverable-corpus.d.ts +117 -0
- package/dist/learning/deliverable-corpus.d.ts.map +1 -0
- package/dist/learning/deliverable-corpus.js +176 -0
- package/dist/learning/deliverable-corpus.js.map +1 -0
- package/dist/learning/error-repair.d.ts +22 -1
- package/dist/learning/error-repair.d.ts.map +1 -1
- package/dist/learning/error-repair.js +37 -0
- package/dist/learning/error-repair.js.map +1 -1
- package/dist/learning/exhaustion-report.d.ts +136 -0
- package/dist/learning/exhaustion-report.d.ts.map +1 -0
- package/dist/learning/exhaustion-report.js +239 -0
- package/dist/learning/exhaustion-report.js.map +1 -0
- package/dist/learning/failure-bookkeeping.d.ts +16 -0
- package/dist/learning/failure-bookkeeping.d.ts.map +1 -1
- package/dist/learning/failure-bookkeeping.js +51 -5
- package/dist/learning/failure-bookkeeping.js.map +1 -1
- package/dist/learning/gate-friction.d.ts +39 -0
- package/dist/learning/gate-friction.d.ts.map +1 -0
- package/dist/learning/gate-friction.js +91 -0
- package/dist/learning/gate-friction.js.map +1 -0
- package/dist/learning/harness-narration.d.ts +34 -0
- package/dist/learning/harness-narration.d.ts.map +1 -0
- package/dist/learning/harness-narration.js +58 -0
- package/dist/learning/harness-narration.js.map +1 -0
- package/dist/learning/hub-skill-catalog.d.ts.map +1 -1
- package/dist/learning/hub-skill-catalog.js +1 -2
- package/dist/learning/hub-skill-catalog.js.map +1 -1
- package/dist/learning/hybrid-router.d.ts +65 -0
- package/dist/learning/hybrid-router.d.ts.map +1 -1
- package/dist/learning/hybrid-router.js +186 -0
- package/dist/learning/hybrid-router.js.map +1 -1
- package/dist/learning/knowledge-base.d.ts +229 -3
- package/dist/learning/knowledge-base.d.ts.map +1 -1
- package/dist/learning/knowledge-base.js +603 -25
- package/dist/learning/knowledge-base.js.map +1 -1
- package/dist/learning/knowledge-eval.d.ts +171 -0
- package/dist/learning/knowledge-eval.d.ts.map +1 -0
- package/dist/learning/knowledge-eval.js +196 -0
- package/dist/learning/knowledge-eval.js.map +1 -0
- package/dist/learning/knowledge-turn.d.ts +92 -0
- package/dist/learning/knowledge-turn.d.ts.map +1 -0
- package/dist/learning/knowledge-turn.js +190 -0
- package/dist/learning/knowledge-turn.js.map +1 -0
- package/dist/learning/learned-commands.d.ts +64 -0
- package/dist/learning/learned-commands.d.ts.map +1 -0
- package/dist/learning/learned-commands.js +108 -0
- package/dist/learning/learned-commands.js.map +1 -0
- package/dist/learning/lexical-search.d.ts +50 -0
- package/dist/learning/lexical-search.d.ts.map +1 -0
- package/dist/learning/lexical-search.js +111 -0
- package/dist/learning/lexical-search.js.map +1 -0
- package/dist/learning/machine-facts.d.ts +71 -0
- package/dist/learning/machine-facts.d.ts.map +1 -0
- package/dist/learning/machine-facts.js +164 -0
- package/dist/learning/machine-facts.js.map +1 -0
- package/dist/learning/markdown-outline.d.ts +73 -0
- package/dist/learning/markdown-outline.d.ts.map +1 -0
- package/dist/learning/markdown-outline.js +136 -0
- package/dist/learning/markdown-outline.js.map +1 -0
- package/dist/learning/model-first-router.d.ts +33 -1
- package/dist/learning/model-first-router.d.ts.map +1 -1
- package/dist/learning/model-first-router.js +123 -9
- package/dist/learning/model-first-router.js.map +1 -1
- package/dist/learning/model-identity.d.ts +80 -0
- package/dist/learning/model-identity.d.ts.map +1 -0
- package/dist/learning/model-identity.js +115 -0
- package/dist/learning/model-identity.js.map +1 -0
- package/dist/learning/model-registry.d.ts +141 -2
- package/dist/learning/model-registry.d.ts.map +1 -1
- package/dist/learning/model-registry.js +324 -38
- package/dist/learning/model-registry.js.map +1 -1
- package/dist/learning/model-scoring.d.ts.map +1 -1
- package/dist/learning/model-scoring.js +8 -1
- package/dist/learning/model-scoring.js.map +1 -1
- package/dist/learning/model-selection.d.ts.map +1 -1
- package/dist/learning/model-selection.js +41 -0
- package/dist/learning/model-selection.js.map +1 -1
- package/dist/learning/outcome-observation.d.ts +49 -0
- package/dist/learning/outcome-observation.d.ts.map +1 -0
- package/dist/learning/outcome-observation.js +95 -0
- package/dist/learning/outcome-observation.js.map +1 -0
- package/dist/learning/pair-entitlement.d.ts +184 -0
- package/dist/learning/pair-entitlement.d.ts.map +1 -0
- package/dist/learning/pair-entitlement.js +214 -0
- package/dist/learning/pair-entitlement.js.map +1 -0
- package/dist/learning/provider-fallback.d.ts +23 -1
- package/dist/learning/provider-fallback.d.ts.map +1 -1
- package/dist/learning/provider-fallback.js +24 -0
- package/dist/learning/provider-fallback.js.map +1 -1
- package/dist/learning/reasoning-trace.d.ts +65 -1
- package/dist/learning/reasoning-trace.d.ts.map +1 -1
- package/dist/learning/reasoning-trace.js +123 -1
- package/dist/learning/reasoning-trace.js.map +1 -1
- package/dist/learning/requirement-probe.d.ts +55 -0
- package/dist/learning/requirement-probe.d.ts.map +1 -0
- package/dist/learning/requirement-probe.js +77 -0
- package/dist/learning/requirement-probe.js.map +1 -0
- package/dist/learning/resilient-call.d.ts +20 -1
- package/dist/learning/resilient-call.d.ts.map +1 -1
- package/dist/learning/resilient-call.js +42 -4
- package/dist/learning/resilient-call.js.map +1 -1
- package/dist/learning/response-usability.d.ts +85 -0
- package/dist/learning/response-usability.d.ts.map +1 -0
- package/dist/learning/response-usability.js +135 -0
- package/dist/learning/response-usability.js.map +1 -0
- package/dist/learning/router-bandit.d.ts +132 -0
- package/dist/learning/router-bandit.d.ts.map +1 -1
- package/dist/learning/router-bandit.js +253 -0
- package/dist/learning/router-bandit.js.map +1 -1
- package/dist/learning/routing-history.d.ts +41 -2
- package/dist/learning/routing-history.d.ts.map +1 -1
- package/dist/learning/routing-history.js.map +1 -1
- package/dist/learning/run-trace.d.ts +21 -0
- package/dist/learning/run-trace.d.ts.map +1 -1
- package/dist/learning/run-trace.js +38 -0
- package/dist/learning/run-trace.js.map +1 -1
- package/dist/learning/session-grant.d.ts +75 -0
- package/dist/learning/session-grant.d.ts.map +1 -0
- package/dist/learning/session-grant.js +112 -0
- package/dist/learning/session-grant.js.map +1 -0
- package/dist/learning/task-model-continuity.d.ts +73 -0
- package/dist/learning/task-model-continuity.d.ts.map +1 -0
- package/dist/learning/task-model-continuity.js +87 -0
- package/dist/learning/task-model-continuity.js.map +1 -0
- package/dist/learning/turn-feedback.d.ts +93 -0
- package/dist/learning/turn-feedback.d.ts.map +1 -0
- package/dist/learning/turn-feedback.js +127 -0
- package/dist/learning/turn-feedback.js.map +1 -0
- package/dist/learning/turn-report.d.ts +104 -2
- package/dist/learning/turn-report.d.ts.map +1 -1
- package/dist/learning/turn-report.js +161 -6
- package/dist/learning/turn-report.js.map +1 -1
- package/dist/learning/verdict-routing.d.ts +51 -0
- package/dist/learning/verdict-routing.d.ts.map +1 -0
- package/dist/learning/verdict-routing.js +122 -0
- package/dist/learning/verdict-routing.js.map +1 -0
- package/dist/mcp/client.d.ts.map +1 -1
- package/dist/mcp/client.js +5 -0
- package/dist/mcp/client.js.map +1 -1
- package/dist/mcp/manager.d.ts +10 -0
- package/dist/mcp/manager.d.ts.map +1 -1
- package/dist/mcp/manager.js +20 -0
- package/dist/mcp/manager.js.map +1 -1
- package/dist/mcp/mcp-discovery.d.ts +34 -0
- package/dist/mcp/mcp-discovery.d.ts.map +1 -0
- package/dist/mcp/mcp-discovery.js +71 -0
- package/dist/mcp/mcp-discovery.js.map +1 -0
- package/dist/mcp/mcp-schema-cache.d.ts +17 -0
- package/dist/mcp/mcp-schema-cache.d.ts.map +1 -1
- package/dist/mcp/mcp-schema-cache.js +47 -3
- package/dist/mcp/mcp-schema-cache.js.map +1 -1
- package/dist/mcp/types.d.ts +28 -0
- package/dist/mcp/types.d.ts.map +1 -1
- package/dist/mcp/types.js.map +1 -1
- package/dist/parity/drivers.d.ts.map +1 -1
- package/dist/parity/drivers.js +3 -0
- package/dist/parity/drivers.js.map +1 -1
- package/dist/parity/observation.d.ts +12 -0
- package/dist/parity/observation.d.ts.map +1 -1
- package/dist/parity/observation.js +14 -0
- package/dist/parity/observation.js.map +1 -1
- package/dist/tools/ask-user.d.ts.map +1 -1
- package/dist/tools/ask-user.js +4 -0
- package/dist/tools/ask-user.js.map +1 -1
- package/dist/tools/capability-registry.d.ts +150 -0
- package/dist/tools/capability-registry.d.ts.map +1 -0
- package/dist/tools/capability-registry.js +400 -0
- package/dist/tools/capability-registry.js.map +1 -0
- package/dist/tools/child-agent-runtime.d.ts.map +1 -1
- package/dist/tools/child-agent-runtime.js +19 -5
- package/dist/tools/child-agent-runtime.js.map +1 -1
- package/dist/tools/coding-tools.d.ts +17 -5
- package/dist/tools/coding-tools.d.ts.map +1 -1
- package/dist/tools/coding-tools.js +80 -11
- package/dist/tools/coding-tools.js.map +1 -1
- package/dist/tools/command-memo.d.ts +116 -0
- package/dist/tools/command-memo.d.ts.map +1 -0
- package/dist/tools/command-memo.js +202 -0
- package/dist/tools/command-memo.js.map +1 -0
- package/dist/tools/git-tool.d.ts.map +1 -1
- package/dist/tools/git-tool.js +13 -3
- package/dist/tools/git-tool.js.map +1 -1
- package/dist/tools/harness-directive.d.ts +42 -0
- package/dist/tools/harness-directive.d.ts.map +1 -0
- package/dist/tools/harness-directive.js +45 -0
- package/dist/tools/harness-directive.js.map +1 -0
- package/dist/tools/loop-skill-hint.d.ts +74 -174
- package/dist/tools/loop-skill-hint.d.ts.map +1 -1
- package/dist/tools/loop-skill-hint.js +110 -536
- package/dist/tools/loop-skill-hint.js.map +1 -1
- package/dist/tools/mcp-client-tool.d.ts +2 -0
- package/dist/tools/mcp-client-tool.d.ts.map +1 -1
- package/dist/tools/mcp-client-tool.js +3 -0
- package/dist/tools/mcp-client-tool.js.map +1 -1
- package/dist/tools/modality/shared.d.ts +1 -4
- package/dist/tools/modality/shared.d.ts.map +1 -1
- package/dist/tools/modality/shared.js +7 -22
- package/dist/tools/modality/shared.js.map +1 -1
- package/dist/tools/plan-store.d.ts +20 -2
- package/dist/tools/plan-store.d.ts.map +1 -1
- package/dist/tools/plan-store.js +51 -7
- package/dist/tools/plan-store.js.map +1 -1
- package/dist/tools/registry.d.ts +76 -3
- package/dist/tools/registry.d.ts.map +1 -1
- package/dist/tools/registry.js +486 -26
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/remediation-ladder.d.ts.map +1 -1
- package/dist/tools/remediation-ladder.js +8 -0
- package/dist/tools/remediation-ladder.js.map +1 -1
- package/dist/tools/run-cli.d.ts.map +1 -1
- package/dist/tools/run-cli.js +29 -4
- package/dist/tools/run-cli.js.map +1 -1
- package/dist/tools/run-terminal.d.ts +11 -0
- package/dist/tools/run-terminal.d.ts.map +1 -1
- package/dist/tools/run-terminal.js +265 -10
- package/dist/tools/run-terminal.js.map +1 -1
- package/dist/tools/tool-loop.d.ts +321 -13
- package/dist/tools/tool-loop.d.ts.map +1 -1
- package/dist/tools/tool-loop.js +867 -66
- package/dist/tools/tool-loop.js.map +1 -1
- package/dist/utils/atomic-store.d.ts +53 -0
- package/dist/utils/atomic-store.d.ts.map +1 -0
- package/dist/utils/atomic-store.js +178 -0
- package/dist/utils/atomic-store.js.map +1 -0
- package/dist/utils/binary-probe.d.ts +25 -0
- package/dist/utils/binary-probe.d.ts.map +1 -0
- package/dist/utils/binary-probe.js +48 -0
- package/dist/utils/binary-probe.js.map +1 -0
- package/dist/utils/workspace-path.d.ts +50 -0
- package/dist/utils/workspace-path.d.ts.map +1 -0
- package/dist/utils/workspace-path.js +86 -0
- package/dist/utils/workspace-path.js.map +1 -0
- package/dist/web-dashboard/chat-console.d.ts +24 -0
- package/dist/web-dashboard/chat-console.d.ts.map +1 -1
- package/dist/web-dashboard/chat-console.js +38 -0
- package/dist/web-dashboard/chat-console.js.map +1 -1
- package/dist/web-dashboard/project-context.d.ts +27 -2
- package/dist/web-dashboard/project-context.d.ts.map +1 -1
- package/dist/web-dashboard/project-context.js +32 -2
- package/dist/web-dashboard/project-context.js.map +1 -1
- package/dist/web-dashboard/server.d.ts +11 -0
- package/dist/web-dashboard/server.d.ts.map +1 -1
- package/dist/web-dashboard/server.js +362 -11
- package/dist/web-dashboard/server.js.map +1 -1
- package/dist/web-dashboard/src/types.d.ts +170 -1
- package/dist/web-dashboard/src/types.d.ts.map +1 -1
- package/dist/web-dashboard/workspace-guard.d.ts +11 -2
- package/dist/web-dashboard/workspace-guard.d.ts.map +1 -1
- package/dist/web-dashboard/workspace-guard.js +24 -12
- package/dist/web-dashboard/workspace-guard.js.map +1 -1
- package/dist/web-dashboard/workspace-resolution.d.ts +87 -0
- package/dist/web-dashboard/workspace-resolution.d.ts.map +1 -0
- package/dist/web-dashboard/workspace-resolution.js +105 -0
- package/dist/web-dashboard/workspace-resolution.js.map +1 -0
- package/package.json +1 -1
- package/src/web-dashboard/public/assets/index-zjbdJnO-.js +210 -0
- package/src/web-dashboard/public/assets/index-zjbdJnO-.js.map +1 -0
- package/src/web-dashboard/public/index.html +1 -1
- package/dist/agents/nvda-addon.d.ts +0 -14
- package/dist/agents/nvda-addon.js +0 -52
- package/dist/forwarded.d.ts +0 -2
- package/dist/forwarded.js +0 -2
- package/src/web-dashboard/public/assets/index-DhiuR4S2.js +0 -210
- package/src/web-dashboard/public/assets/index-DhiuR4S2.js.map +0 -1
|
@@ -1,212 +1,45 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* hint applies the identical regex so "deploy the API" does not drag in
|
|
36
|
-
* static-site deployment steps.
|
|
37
|
-
* - Side-effect-free matching: the match itself marks nothing; usage is
|
|
38
|
-
* marked ONCE via markLoopSkillUsed by the caller (skillView()'s internal
|
|
39
|
-
* markUsed is deliberately avoided so the hint builder is idempotent).
|
|
40
|
-
* - Bounded injection: at most ONE methodology block per prompt, and the
|
|
41
|
-
* methodology text itself is capped (compiled: 8 steps; hub: 2000 chars)
|
|
42
|
-
* so a crowded catalog cannot balloon the system prompt.
|
|
43
|
-
* - Best-effort by construction: any store/catalog failure returns '' /
|
|
44
|
-
* null and the turn proceeds exactly as before (a hint must never break
|
|
45
|
-
* a turn).
|
|
46
|
-
*
|
|
47
|
-
* Consumers: chat's runChatAnswer (system prompt) and the execute loop's
|
|
48
|
-
* runLoopExecutor — the two runToolLoop callers that had no skill knowledge.
|
|
49
|
-
*/
|
|
50
|
-
/**
|
|
51
|
-
* Website-deploy activation gate — IDENTICAL to the orchestrator's
|
|
52
|
-
* (src/agents/orchestrator.ts §3c): a website-deployment skill (bundled OR
|
|
53
|
-
* hub-installed) is only injected when the goal carries hosting-specific
|
|
54
|
-
* intent. A generic "deploy the API" goal does NOT get website methodology.
|
|
55
|
-
*/
|
|
56
|
-
const WEBSITE_DEPLOY_ID = /website[-_ ]?deploy/i;
|
|
57
|
-
const HOSTING_INTENT = /cloudflare|netlify|vercel|github\s*pages|hosting|pages\.dev|web\s*site|website|static\s*site|landing\s*page/i;
|
|
58
|
-
/**
|
|
59
|
-
* Meta-words that appear in generic goalPatterns but carry NO goal evidence
|
|
60
|
-
* ("compile a plan for this goal"). Excluded from pattern-word matching so a
|
|
61
|
-
* goal containing only meta-vocabulary can never match a skill.
|
|
62
|
-
*/
|
|
63
|
-
const PATTERN_STOPWORDS = new Set([
|
|
64
|
-
'goal', 'goals', 'task', 'tasks', 'skill', 'skills', 'step', 'steps',
|
|
65
|
-
'plan', 'plans', 'planning', 'when', 'with', 'this', 'that', 'from',
|
|
66
|
-
'into', 'user', 'users', 'want', 'wants', 'need', 'needs', 'request',
|
|
67
|
-
'requests', 'help', 'make', 'using', 'used', 'work', 'works', 'some',
|
|
68
|
-
'onto', 'over', 'your', 'their', 'them', 'then', 'also', 'each',
|
|
69
|
-
// Generic document nouns/verbs — no domain evidence on their own.
|
|
70
|
-
//
|
|
71
|
-
// The docx skill's DESCRIPTION is long prose ("create, read, edit, or
|
|
72
|
-
// manipulate Word **documents**… produce professional **documents** with
|
|
73
|
-
// … **page** numbers"), so its generic words cleared the two-distinct-word
|
|
74
|
-
// bar for any goal that merely mentioned a document. Measured live
|
|
75
|
-
// (2026-10-03): the hub docx skill matched "Read the health report PDF …
|
|
76
|
-
// produce a thorough assessment" on exactly `documents` + `produce` + `page`
|
|
77
|
-
// — none of which names a document FORMAT.
|
|
78
|
-
'document', 'documents', 'produce', 'produces', 'page', 'pages',
|
|
79
|
-
// Generic document/analysis verbs — no domain evidence on their own.
|
|
80
|
-
//
|
|
81
|
-
// Measured live (2026-10-03): "read my health report - blood test report
|
|
82
|
-
// and share me findings which are concerning and what changes i should do"
|
|
83
|
-
// activated the **docx** skill and injected its whole "a .docx is a ZIP
|
|
84
|
-
// archive of XML files / read with pandoc / unzip → edit word/document.xml"
|
|
85
|
-
// methodology into a PDF lab-report turn — the model then reported the PDF
|
|
86
|
-
// as a .docx with blank tables. The two "domain" words that cleared the
|
|
87
|
-
// two-word bar were `read` (from the docx goalPattern) and `changes` (from
|
|
88
|
-
// the description's "tracked changes"); neither names a document FORMAT.
|
|
89
|
-
//
|
|
90
|
-
// A FORMAT skill must match on its format NAME or a domain TAG, never on the
|
|
91
|
-
// generic act of reading or on the noun "changes". Deliberately narrow: only
|
|
92
|
-
// the two words observed in the false positive are excluded, so skills whose
|
|
93
|
-
// real evidence is `create`/`build`/`edit`/`convert` are unaffected.
|
|
94
|
-
'read', 'reads', 'reading', 'changes', 'changed', 'changing',
|
|
95
|
-
]);
|
|
96
|
-
/**
|
|
97
|
-
* Skill-NAME words that are too generic to be evidence on their own.
|
|
98
|
-
*
|
|
99
|
-
* A skill's name is normally its strongest evidence — `wsl-setup` fires on
|
|
100
|
-
* "wsl", `docker-config` on "docker". But a handful of skill names are built
|
|
101
|
-
* from ordinary English words that carry a DIFFERENT meaning outside software:
|
|
102
|
-
* `test` is also a medical/chemical noun (a blood test), a school noun, a
|
|
103
|
-
* quality noun. Measured live (2026-10-03): the goal "read my health report -
|
|
104
|
-
* blood test report and share me findings…" matched the **test-strategy**
|
|
105
|
-
* skill on the single name word `test` and would have injected a
|
|
106
|
-
* unit/integration/e2e software-testing methodology into a lab-report turn.
|
|
107
|
-
*
|
|
108
|
-
* A generic name word is NOT thrown away — it is DEMOTED: it counts as
|
|
109
|
-
* evidence only when the goal uses it as the action (a leading/verb use, e.g.
|
|
110
|
-
* "test the project") or when the skill's own domain vocabulary corroborates
|
|
111
|
-
* it (see {@link isCompoundNounUse} and {@link hasRealGoalEvidence}).
|
|
112
|
-
*
|
|
113
|
-
* Deliberately tiny. Domain-ish names (`api`, `code`, `docx`, `docker`, `game`)
|
|
114
|
-
* stay strong on their own: `REST API` and `code review` ARE the domain, so
|
|
115
|
-
* excluding them would trade this false positive for a worse one. Only words
|
|
116
|
-
* whose NON-software sense is common enough to appear in everyday requests
|
|
117
|
-
* belong here.
|
|
118
|
-
*/
|
|
119
|
-
const GENERIC_SKILL_NAME_WORDS = new Set([
|
|
120
|
-
'test', 'tests', 'testing',
|
|
121
|
-
]);
|
|
122
|
-
/**
|
|
123
|
-
* Words that do NOT make a following token a compound-noun modifier.
|
|
124
|
-
*
|
|
125
|
-
* Used by {@link isCompoundNounUse} to tell `blood test report` (the generic
|
|
126
|
-
* word is a noun modifier, so it names no domain) from `please test the build`
|
|
127
|
-
* (the generic word is the verb, so it IS the action). Determiners, pronouns,
|
|
128
|
-
* prepositions, conjunctions, politeness and auxiliaries — the words a verb
|
|
129
|
-
* can legitimately follow.
|
|
130
|
-
*/
|
|
131
|
-
const VERB_PRECEDER_STOPWORDS = new Set([
|
|
132
|
-
...PATTERN_STOPWORDS,
|
|
133
|
-
'the', 'a', 'an', 'and', 'or', 'of', 'to', 'for', 'in', 'on', 'at', 'by',
|
|
134
|
-
'my', 'our', 'your', 'their', 'its', 'his', 'her', 'me', 'us', 'them', 'him',
|
|
135
|
-
'please', 'can', 'could', 'would', 'will', 'should', 'do', 'does', 'did',
|
|
136
|
-
'is', 'are', 'be', 'been', 'was', 'were', 'have', 'has', 'had', 'not',
|
|
137
|
-
'no', 'if', 'as', 'it', 'i', 'you', 'we', 'they', 'so', 'up', 'out',
|
|
138
|
-
'all', 'any', 'some', 'this', 'that', 'these', 'those', 'then', 'also',
|
|
139
|
-
'just', 'now', 'new', 'again', 'here', 'there',
|
|
140
|
-
]);
|
|
141
|
-
/**
|
|
142
|
-
* Is `word` used as a COMPOUND-NOUN modifier in the goal — i.e. immediately
|
|
143
|
-
* preceded by another content word?
|
|
144
|
-
*
|
|
145
|
-
* "blood test report" → `test` follows the content word `blood`, so it is a
|
|
146
|
-
* noun modifier and names no software domain. "test the project" / "please
|
|
147
|
-
* test the build" → `test` follows nothing or a determiner/auxiliary, so it is
|
|
148
|
-
* the verb and IS the action. Deterministic, no LLM.
|
|
149
|
-
*/
|
|
150
|
-
function isCompoundNounUse(goal, word) {
|
|
151
|
-
const tokens = (goal || '')
|
|
152
|
-
.toLowerCase()
|
|
153
|
-
.split(/[^a-z0-9]+/)
|
|
154
|
-
.filter((w) => w.length > 0);
|
|
155
|
-
for (let i = 1; i < tokens.length; i++) {
|
|
156
|
-
if (tokens[i] !== word)
|
|
157
|
-
continue;
|
|
158
|
-
const prev = tokens[i - 1];
|
|
159
|
-
if (prev.length > 3 && !VERB_PRECEDER_STOPWORDS.has(prev))
|
|
160
|
-
return true;
|
|
161
|
-
}
|
|
162
|
-
return false;
|
|
163
|
-
}
|
|
164
|
-
/**
|
|
165
|
-
* Is this word, for THIS goal, a generic word being used as a compound-noun
|
|
166
|
-
* modifier rather than as its own domain term?
|
|
167
|
-
*
|
|
168
|
-
* The single rule every evidence loop consults: a generic name word (`test`) is
|
|
169
|
-
* dropped when the goal only uses it as a noun modifier ("blood test report"),
|
|
170
|
-
* because there it names a different domain than the skill's. Applied to name,
|
|
171
|
-
* tag and pattern evidence alike so the three can never disagree.
|
|
172
|
-
*/
|
|
173
|
-
function isDemotedGenericUse(goal, word) {
|
|
174
|
-
return GENERIC_SKILL_NAME_WORDS.has(word) && isCompoundNounUse(goal, word);
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* Meta-vocabulary that is ALSO excluded from TAG hits.
|
|
178
|
-
*
|
|
179
|
-
* Why tag hits need this too (live, 2026-09-20): `technical-roadmap` carries the
|
|
180
|
-
* tags `roadmap`/`planning`, so the prompt "…how should i plan…" matched on the
|
|
181
|
-
* single generic tag word `planning` and injected the skill's whole phased-
|
|
182
|
-
* migration methodology into a TRAVEL-ITINERARY turn — irrelevant context that
|
|
183
|
-
* pushed the model toward planning meta-talk and grew the prompt. The evidence
|
|
184
|
-
* filter already excluded these words from goalPattern matching for exactly this
|
|
185
|
-
* reason; a tag hit is the same kind of evidence and gets the same treatment.
|
|
186
|
-
*
|
|
187
|
-
* Deliberately narrow — process/meta nouns that name how work is done rather
|
|
188
|
-
* than a domain. Domain tags (`deploy`, `testing`, `search`, `payments`) still
|
|
189
|
-
* match, and a name-word hit is unaffected.
|
|
2
|
+
* Skill hint (`src/tools/loop-skill-hint.ts`) — model-driven skill selection.
|
|
3
|
+
*
|
|
4
|
+
* HISTORY (why the keyword scorer is gone). This module used to decide, in code,
|
|
5
|
+
* WHICH skill a goal wanted: `findLoopSkillMatch` scored the compiled store and
|
|
6
|
+
* the hub catalog, then a hand-written evidence filter (`hasRealGoalEvidence`)
|
|
7
|
+
* pulled back the false positives with stopword lists, generic-name-word lists,
|
|
8
|
+
* generic-tag lists and platform-host lists. Every one of those lists was a bug
|
|
9
|
+
* report: "blood test report" matched the software `test-strategy` skill,
|
|
10
|
+
* "Windows and Linux" matched `wsl-setup`, "packaging" matched `electron-app`.
|
|
11
|
+
* A word list cannot decide what a goal MEANS, and each word added to force one
|
|
12
|
+
* case right made some real match wrong.
|
|
13
|
+
*
|
|
14
|
+
* THE REPLACEMENT. Selection is the MODEL's job now. The harness no longer
|
|
15
|
+
* guesses; it hands the model the discovery path and gets out of the way:
|
|
16
|
+
*
|
|
17
|
+
* - default (`pointer`) — a few lines saying skills exist and HOW to find one:
|
|
18
|
+
* the `skill` tool (list / load) and the capability search (`tool_search`,
|
|
19
|
+
* whose hits include `kind:"skill"` capabilities). Near-zero prompt cost,
|
|
20
|
+
* no false positives, no maintenance.
|
|
21
|
+
* - `catalog` / `names` (OPT-IN) — the full name+description catalog, or the
|
|
22
|
+
* names-only list, for a user who wants everything in-context.
|
|
23
|
+
* - `off` — inject nothing.
|
|
24
|
+
*
|
|
25
|
+
* The old default was the ~24.5K-char catalog, which buried the task on every
|
|
26
|
+
* turn (3.3.11 regression, see tests/release/agent-contracts.test.ts); the
|
|
27
|
+
* pointer keeps the small-prompt property while still being model-driven.
|
|
28
|
+
*
|
|
29
|
+
* The pipeline arm consumes the SAME catalog builder (see the orchestrator's
|
|
30
|
+
* `skillCatalog` injection): the planner is a model too, so it is handed the
|
|
31
|
+
* list instead of a keyword-selected skill.
|
|
32
|
+
*
|
|
33
|
+
* Best-effort by construction: any store/catalog failure returns '' and the turn
|
|
34
|
+
* proceeds byte-identically (a hint must never break a turn).
|
|
190
35
|
*/
|
|
191
|
-
const GENERIC_SKILL_TAGS = new Set([
|
|
192
|
-
'planning', 'roadmap', 'assessment', 'audit', 'quality', 'review',
|
|
193
|
-
'analysis', 'process', 'workflow', 'recommendations', 'gaps', 'strategy',
|
|
194
|
-
'methodology', 'checklist', 'template', 'guide', 'framework', 'report',
|
|
195
|
-
// C4 — `packaging` is how work is DELIVERED, not a domain. Measured live
|
|
196
|
-
// (2026-10-02): the goal "Fix the macOS hotkey permission and packaging
|
|
197
|
-
// defects … changing app behavior" matched `electron-app` on its `packaging`
|
|
198
|
-
// tag ALONE and injected Electron methodology into a PyQt6 bundle fix. The
|
|
199
|
-
// skill's real domain (`electron`) is unaffected: a goal that actually names
|
|
200
|
-
// Electron still matches on the name word.
|
|
201
|
-
'packaging',
|
|
202
|
-
]);
|
|
203
|
-
/** Cap on hub SKILL.md body text injected into the prompt (chars). */
|
|
204
|
-
const HUB_BODY_CAP = 2000;
|
|
205
|
-
/** Cap on compiled methodology steps injected into the prompt. */
|
|
206
|
-
const COMPILED_STEP_CAP = 8;
|
|
207
36
|
/** Cap on any single description line (chars). */
|
|
208
37
|
const LINE_CAP = 400;
|
|
209
|
-
|
|
38
|
+
function cap(text, max = LINE_CAP) {
|
|
39
|
+
const t = text.trim();
|
|
40
|
+
return t.length > max ? t.slice(0, max - 1) + '…' : t;
|
|
41
|
+
}
|
|
42
|
+
/** The skills.disabled[] gate: a disabled skill is never listed. */
|
|
210
43
|
function isDisabled(id, cm) {
|
|
211
44
|
try {
|
|
212
45
|
const cfg = cm?.getAll?.();
|
|
@@ -214,332 +47,94 @@ function isDisabled(id, cm) {
|
|
|
214
47
|
return Array.isArray(disabled) && disabled.includes(id);
|
|
215
48
|
}
|
|
216
49
|
catch {
|
|
217
|
-
return false; // config failure must not block
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
/**
|
|
221
|
-
* HOST/PLATFORM names — where something runs, not what the user wants done.
|
|
222
|
-
*
|
|
223
|
-
* Observed live (2026-09-21): the goal "…a multiple screen calculator and unit
|
|
224
|
-
* converter, it should be GUI and cross platform for Windows and Linux"
|
|
225
|
-
* activated `wsl-setup` (tags `wsl, windows, linux, development, gpu`) and
|
|
226
|
-
* injected its WSL/Distro/GPU-passthrough methodology into a Flutter app plan.
|
|
227
|
-
* Both tag hits and both pattern hits came from the platform names alone:
|
|
228
|
-
* "Windows" and "Linux" were read as intent to configure the machine they run
|
|
229
|
-
* on. A target platform is a CONSTRAINT on the work, never evidence for a
|
|
230
|
-
* methodology, so these words contribute no evidence anywhere in this file.
|
|
231
|
-
*
|
|
232
|
-
* Deliberately narrow — only HOSTS. Tooling and cloud domains stay evidence
|
|
233
|
-
* (`docker`, `kubernetes`, `aws`, `postgres`, `redis`, …): "deploy to AWS" IS
|
|
234
|
-
* a request for deployment methodology, while "cross platform for Windows" is
|
|
235
|
-
* not a request for WSL setup.
|
|
236
|
-
*/
|
|
237
|
-
const PLATFORM_HOST_NAMES = new Set([
|
|
238
|
-
'windows', 'win32', 'win64', 'windows10', 'windows11',
|
|
239
|
-
'linux', 'unix', 'gnu', 'ubuntu', 'debian', 'fedora', 'centos', 'rhel',
|
|
240
|
-
'alpine', 'arch', 'suse', 'freebsd', 'openbsd',
|
|
241
|
-
'macos', 'macosx', 'mac', 'osx', 'darwin', 'apple',
|
|
242
|
-
'android', 'ios', 'ipados', 'watchos', 'tvos',
|
|
243
|
-
'wsl', 'wsl2', 'cygwin', 'mingw', 'msys',
|
|
244
|
-
'crossplatform', 'cross-platform',
|
|
245
|
-
'x64', 'x86', 'arm64', 'aarch64', 'amd64',
|
|
246
|
-
]);
|
|
247
|
-
/** Is this token a host/platform name (never goal evidence)? */
|
|
248
|
-
export function isPlatformName(word) {
|
|
249
|
-
return PLATFORM_HOST_NAMES.has(word.trim().toLowerCase());
|
|
250
|
-
}
|
|
251
|
-
/**
|
|
252
|
-
* Did the goal show REAL evidence for this skill — a name-word hit, a tag hit,
|
|
253
|
-
* or two DISTINCT pattern/description words (meta-words and platform names
|
|
254
|
-
* excluded)? Guards the compiled store's intentionally loose threshold:
|
|
255
|
-
* findMatch adds a quality/usage bonus to every skill, so a generic word like
|
|
256
|
-
* "goal" alone must never inject methodology into a chat turn.
|
|
257
|
-
*
|
|
258
|
-
* Also the HUB path's only filter: `findHubSkillMatch` scores name words and
|
|
259
|
-
* DESCRIPTION keywords and returns the top scorer with no evidence gate at all,
|
|
260
|
-
* so an installed skill whose description merely names the target platform
|
|
261
|
-
* scored on that alone. A hub match carries no tags/goalPattern, so its
|
|
262
|
-
* description words are the pattern-level evidence (the caller passes it here).
|
|
263
|
-
*
|
|
264
|
-
* MATCHING IS BY WHOLE WORD, never substring. `q.includes(word)` matched
|
|
265
|
-
* "kill" inside "s**kill**" — measured: `feature-flags` (goalPattern “…kill
|
|
266
|
-
* switch…”) matched "no **skill** covers alpaca husbandry whatsoever", and the
|
|
267
|
-
* same class makes `mac` match "machine" and `arch` match "search". The goal is
|
|
268
|
-
* tokenized once into a word set and skills are matched against tokens.
|
|
269
|
-
*
|
|
270
|
-
* Deterministic, no LLM.
|
|
271
|
-
*/
|
|
272
|
-
export function hasRealGoalEvidence(goal, skill) {
|
|
273
|
-
const tokens = wordSet(goal);
|
|
274
|
-
if (tokens.size === 0)
|
|
275
|
-
return false;
|
|
276
|
-
let nameHits = 0;
|
|
277
|
-
for (const word of skill.name.toLowerCase().split(/[^a-z0-9]+/)) {
|
|
278
|
-
if (word.length <= 3 || isPlatformName(word) || !tokens.has(word))
|
|
279
|
-
continue;
|
|
280
|
-
// A GENERIC name word (see GENERIC_SKILL_NAME_WORDS) is evidence only when
|
|
281
|
-
// the goal uses it as the action, not as a compound-noun modifier. A
|
|
282
|
-
// count alone did the wrong thing: the single word `test` in "blood test
|
|
283
|
-
// report" cleared `nameHits >= 1` and activated the software-testing
|
|
284
|
-
// skill on a lab-report turn. `please test the project` still counts (a
|
|
285
|
-
// verb use), and `run the unit tests` counts below via its domain words.
|
|
286
|
-
if (isDemotedGenericUse(goal, word))
|
|
287
|
-
continue;
|
|
288
|
-
nameHits++;
|
|
289
|
-
}
|
|
290
|
-
let tagHits = 0;
|
|
291
|
-
for (const tag of skill.tags ?? []) {
|
|
292
|
-
const t = tag.toLowerCase().trim();
|
|
293
|
-
// Generic process vocabulary is not goal evidence (see GENERIC_SKILL_TAGS),
|
|
294
|
-
// and a generic word used only as a noun modifier is not either.
|
|
295
|
-
if (t.length > 3 && !GENERIC_SKILL_TAGS.has(t) && !isPlatformName(t) && !isDemotedGenericUse(goal, t) && tokens.has(t))
|
|
296
|
-
tagHits++;
|
|
50
|
+
return false; // config failure must not block discovery (the hint is advisory)
|
|
297
51
|
}
|
|
298
|
-
// Pattern-level evidence: the skill's own goalPattern words, plus (for a hub
|
|
299
|
-
// skill, which has no goalPattern) its description keywords. Two DISTINCT
|
|
300
|
-
// domain words are required — one shared word is not enough to inject a
|
|
301
|
-
// whole methodology into a turn.
|
|
302
|
-
//
|
|
303
|
-
// DISTINCT is the whole point, and a plain counter got it wrong: the evidence
|
|
304
|
-
// text is `goalPattern + description`, so ONE word that a skill repeats in
|
|
305
|
-
// both fields counted twice and satisfied the "two words" rule on its own.
|
|
306
|
-
// Measured live (2026-09-21): "Create a book which teaches math's division
|
|
307
|
-
// for class 4 student" activated `game-development`, whose ONLY overlap is
|
|
308
|
-
// the word `create` — present in its goalPattern (`game create build …`) and
|
|
309
|
-
// again in its description ("Use when the goal asks to create, build, or
|
|
310
|
-
// develop a game"). `create` is also a generic action verb, so the match was
|
|
311
|
-
// noise in both senses.
|
|
312
|
-
const patternHits = new Set();
|
|
313
|
-
const evidenceText = `${skill.goalPattern ?? ''} ${skill.description ?? ''}`;
|
|
314
|
-
for (const word of evidenceText.toLowerCase().split(/[^a-z0-9]+/)) {
|
|
315
|
-
const w = word.trim();
|
|
316
|
-
if (w.length > 3 && !PATTERN_STOPWORDS.has(w) && !GENERIC_SKILL_TAGS.has(w) && !isPlatformName(w) && !isDemotedGenericUse(goal, w) && tokens.has(w)) {
|
|
317
|
-
patternHits.add(w);
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
return nameHits >= 1 || tagHits >= 1 || patternHits.size >= 2;
|
|
321
|
-
}
|
|
322
|
-
/** Whole-word token set for a goal (word-boundary matching, never substring). */
|
|
323
|
-
function wordSet(text) {
|
|
324
|
-
return new Set((text || '')
|
|
325
|
-
.toLowerCase()
|
|
326
|
-
.split(/[^a-z0-9]+/)
|
|
327
|
-
.filter((w) => w.length > 0));
|
|
328
|
-
}
|
|
329
|
-
/**
|
|
330
|
-
* THE skill-activation gate — the single decision every injection path makes.
|
|
331
|
-
*
|
|
332
|
-
* Composes (1) the website-deploy activation rule: website methodology needs
|
|
333
|
-
* HOSTING intent, so a generic "deploy the API" goal never gets it; and (2) the
|
|
334
|
-
* evidence rule above.
|
|
335
|
-
*
|
|
336
|
-
* Before this existed the gate was implemented three times with different
|
|
337
|
-
* strength: the chat/execute loop applied the evidence filter to COMPILED
|
|
338
|
-
* matches but trusted hub matches raw, and the ORCHESTRATOR applied neither
|
|
339
|
-
* (only the website-deploy rule) — so the pipeline was the most exposed
|
|
340
|
-
* surface. One predicate, consumed by all of them.
|
|
341
|
-
*/
|
|
342
|
-
export function isSkillActivated(goal, skill) {
|
|
343
|
-
const label = `${skill.id ?? ''} ${skill.name}`;
|
|
344
|
-
if (WEBSITE_DEPLOY_ID.test(label) && !HOSTING_INTENT.test(goal))
|
|
345
|
-
return false;
|
|
346
|
-
return hasRealGoalEvidence(goal, skill);
|
|
347
52
|
}
|
|
348
53
|
/**
|
|
349
|
-
*
|
|
350
|
-
*
|
|
351
|
-
*
|
|
352
|
-
* seed id). Returns null when nothing matches (never a forced match).
|
|
54
|
+
* Every skill the model may pick from — compiled first-party + installed hub
|
|
55
|
+
* (SKILL.md) skills, deduped by name, with the disabled gate applied. Best-effort:
|
|
56
|
+
* a store/catalog failure contributes nothing rather than throwing.
|
|
353
57
|
*/
|
|
354
|
-
export async function
|
|
355
|
-
const
|
|
356
|
-
if (!q)
|
|
357
|
-
return null;
|
|
358
|
-
// 1. Compiled store (the first-party capability batch).
|
|
58
|
+
export async function collectSkillEntries(cm) {
|
|
59
|
+
const entries = [];
|
|
359
60
|
try {
|
|
360
61
|
const { getSkillStore } = await import('../learning/skill-store.js');
|
|
361
|
-
const
|
|
362
|
-
|
|
363
|
-
|
|
62
|
+
for (const skill of getSkillStore().getAll()) {
|
|
63
|
+
if (isDisabled(skill.id, cm))
|
|
64
|
+
continue;
|
|
65
|
+
entries.push({ name: skill.name, description: skill.description ?? '' });
|
|
364
66
|
}
|
|
365
67
|
}
|
|
366
68
|
catch {
|
|
367
|
-
//
|
|
69
|
+
// Best-effort — a store failure must not remove the hub half.
|
|
368
70
|
}
|
|
369
|
-
// 2. Hub catalog (installed SKILL.md skills — first-class runtime
|
|
370
|
-
// capabilities; a fresh `nuvira skills install` is matchable with zero
|
|
371
|
-
// recompilation, exactly like the orchestrator's fallback path).
|
|
372
|
-
//
|
|
373
|
-
// Its scoring is NOT evidence: `findHubSkillMatch` counts name words and
|
|
374
|
-
// DESCRIPTION keywords and returns the top scorer, so a skill whose
|
|
375
|
-
// description merely names the target platform ("…a Linux development
|
|
376
|
-
// environment on Windows") scored on those two words alone. The same
|
|
377
|
-
// evidence gate the compiled path uses is applied here now.
|
|
378
71
|
try {
|
|
379
|
-
const {
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
return { name: hub.name, id: hub.id, source: 'hub' };
|
|
72
|
+
const { listMatchableHubSkills } = await import('../learning/hub-skill-catalog.js');
|
|
73
|
+
for (const skill of listMatchableHubSkills(cm)) {
|
|
74
|
+
if (isDisabled(skill.id, cm))
|
|
75
|
+
continue;
|
|
76
|
+
if (entries.some((e) => e.name === skill.name))
|
|
77
|
+
continue;
|
|
78
|
+
entries.push({ name: skill.name, description: skill.description ?? '' });
|
|
387
79
|
}
|
|
388
80
|
}
|
|
389
81
|
catch {
|
|
390
|
-
// Best-effort — a catalog failure leaves
|
|
391
|
-
}
|
|
392
|
-
return null;
|
|
393
|
-
}
|
|
394
|
-
/**
|
|
395
|
-
* Bounded, side-effect-free methodology text for a compiled skill (the full
|
|
396
|
-
* Skill shape is fetched via the public get(); step descriptions carry the
|
|
397
|
-
* Level-2 methodology). Deliberately NOT store.skillView() — that marks the
|
|
398
|
-
* skill used as a side effect and renders reference-doc/quality sections the
|
|
399
|
-
* prompt block does not need.
|
|
400
|
-
*/
|
|
401
|
-
function formatCompiledMethodology(skill) {
|
|
402
|
-
const lines = [];
|
|
403
|
-
if (skill.description)
|
|
404
|
-
lines.push(cap(skill.description));
|
|
405
|
-
if (skill.parameters.length > 0) {
|
|
406
|
-
lines.push('Parameters: ' +
|
|
407
|
-
skill.parameters
|
|
408
|
-
.map((p) => `${p.name}${p.required ? '' : ' (optional)'}`)
|
|
409
|
-
.join(', '));
|
|
410
|
-
}
|
|
411
|
-
const steps = skill.steps.slice(0, COMPILED_STEP_CAP);
|
|
412
|
-
steps.forEach((s, i) => {
|
|
413
|
-
lines.push(`Step ${i + 1} [${s.agentType}]: ${cap(s.description)}`);
|
|
414
|
-
});
|
|
415
|
-
if (skill.steps.length > steps.length) {
|
|
416
|
-
lines.push(`(+${skill.steps.length - steps.length} more steps — load the skill for the full methodology)`);
|
|
82
|
+
// Best-effort — a catalog failure leaves the compiled half.
|
|
417
83
|
}
|
|
418
|
-
return
|
|
84
|
+
return entries;
|
|
419
85
|
}
|
|
420
|
-
function
|
|
421
|
-
|
|
422
|
-
|
|
86
|
+
function loadTail(loadHint) {
|
|
87
|
+
return loadHint === 'skill-view'
|
|
88
|
+
? 'Name the skill in the step that needs it; the writer agent can call skill_view(name) to load its full methodology.'
|
|
89
|
+
: 'Load one with the skill tool, e.g. {"skill":"<name>"} (or call it with no name to list every skill).';
|
|
423
90
|
}
|
|
424
91
|
/**
|
|
425
|
-
*
|
|
426
|
-
* match. The block follows the orchestrator's injection contract:
|
|
92
|
+
* The DEFAULT hint — a bounded discovery pointer, not a recommendation.
|
|
427
93
|
*
|
|
428
|
-
*
|
|
429
|
-
*
|
|
430
|
-
*
|
|
431
|
-
* the model sees the steps without paying a tool call for them),
|
|
432
|
-
* - the exact load syntax is included so the model can refresh/parameterize
|
|
433
|
-
* via the `skill` tool mid-turn,
|
|
434
|
-
* - ONE block max (bounded system-prompt growth).
|
|
435
|
-
*
|
|
436
|
-
* Marks nothing: usage tracking belongs to markLoopSkillUsed (the caller
|
|
437
|
-
* decides when a match actually got USED — i.e. was injected).
|
|
438
|
-
*
|
|
439
|
-
* @param goal the user's goal text (matched against skill triggers)
|
|
440
|
-
* @param cm ConfigManager for the disabled-skills gate (optional)
|
|
441
|
-
* @param injected out-param: when provided, receives the match that was
|
|
442
|
-
* injected (null when none).
|
|
94
|
+
* It names the two model-driven paths to a skill (the `skill` tool and the
|
|
95
|
+
* capability search) and leaves the decision with the model. Returns '' when
|
|
96
|
+
* there are no skills to discover (nothing to say — never a forced hint).
|
|
443
97
|
*/
|
|
444
|
-
export async function
|
|
445
|
-
const
|
|
446
|
-
if (
|
|
447
|
-
injected.value = match;
|
|
448
|
-
if (!match)
|
|
98
|
+
export async function buildSkillPointerHint(cm, loadHint = 'skill-tool') {
|
|
99
|
+
const entries = await collectSkillEntries(cm);
|
|
100
|
+
if (entries.length === 0)
|
|
449
101
|
return '';
|
|
450
|
-
|
|
451
|
-
// methodology). Hub: the SKILL.md body.
|
|
452
|
-
let methodology = '';
|
|
453
|
-
if (match.source === 'hub') {
|
|
454
|
-
try {
|
|
455
|
-
const { findHubSkillMatch } = await import('../learning/hub-skill-catalog.js');
|
|
456
|
-
methodology = cap(findHubSkillMatch(goal, cm)?.body ?? '', HUB_BODY_CAP);
|
|
457
|
-
}
|
|
458
|
-
catch {
|
|
459
|
-
methodology = '';
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
else {
|
|
463
|
-
try {
|
|
464
|
-
const { getSkillStore } = await import('../learning/skill-store.js');
|
|
465
|
-
methodology = formatCompiledMethodology(getSkillStore().get(match.id));
|
|
466
|
-
}
|
|
467
|
-
catch {
|
|
468
|
-
methodology = '';
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
const lines = [
|
|
102
|
+
return [
|
|
472
103
|
'',
|
|
473
|
-
'##
|
|
474
|
-
|
|
475
|
-
'
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
lines.push('', `To (re)load it with parameters mid-turn, call the skill tool with {"skill":"${match.name}"}.`);
|
|
481
|
-
return lines.join('\n');
|
|
104
|
+
'## Skills',
|
|
105
|
+
`${entries.length} reusable capability packs (skills) are available. Decide from the task itself whether one applies — do not guess:`,
|
|
106
|
+
' - call the skill tool with no name to list every skill, or',
|
|
107
|
+
' - call tool_search with a query describing this task; skills come back as capabilities (kind "skill").',
|
|
108
|
+
loadTail(loadHint),
|
|
109
|
+
'If none applies, ignore this and proceed.',
|
|
110
|
+
].join('\n');
|
|
482
111
|
}
|
|
483
112
|
/**
|
|
484
|
-
*
|
|
485
|
-
*
|
|
486
|
-
*
|
|
487
|
-
* WHY THIS REPLACES THE MATCHER: a word list cannot decide whether "blood test
|
|
488
|
-
* report" is software testing, and every stopword added to force it right made
|
|
489
|
-
* some real match wrong. The model can read the same catalog and judge instantly,
|
|
490
|
-
* so the fix is to STOP deciding in code and hand the model the list: name + a
|
|
491
|
-
* one-line description each, plus the exact `skill` tool syntax to load one. This
|
|
492
|
-
* scales to infinite permutations with no maintenance and no false positives —
|
|
493
|
-
* the model loads a skill only when it actually applies.
|
|
113
|
+
* The bounded CATALOG of available skills for the system prompt — the model-facing
|
|
114
|
+
* discovery surface, read straight through.
|
|
494
115
|
*
|
|
495
116
|
* Bounded deliberately: descriptions are capped and the list is capped, so a
|
|
496
|
-
* crowded catalog cannot balloon the
|
|
497
|
-
* skills (nothing to say) — never a forced recommendation.
|
|
117
|
+
* crowded catalog cannot balloon the prompt. Returns '' when there are no skills.
|
|
498
118
|
*
|
|
499
119
|
* @param cm ConfigManager (honors skills.disabled — a disabled skill is
|
|
500
120
|
* never listed, the same gate the tool enforces)
|
|
501
121
|
* @param opts caps: maxSkills (default 200 — the full bundled+hub catalog,
|
|
502
122
|
* so NO skill is dropped from the model's view; missing a skill
|
|
503
123
|
* is the failure this design exists to avoid), descriptionChars
|
|
504
|
-
* (default 140)
|
|
124
|
+
* (default 140), namesOnly (default false), loadHint
|
|
505
125
|
*/
|
|
506
126
|
export async function buildSkillCatalogHint(cm, opts = {}) {
|
|
507
127
|
const maxSkills = opts.maxSkills ?? 200;
|
|
508
128
|
const descChars = opts.descriptionChars ?? 140;
|
|
509
129
|
const namesOnly = opts.namesOnly === true;
|
|
510
|
-
const
|
|
511
|
-
|
|
512
|
-
try {
|
|
513
|
-
const { getSkillStore } = await import('../learning/skill-store.js');
|
|
514
|
-
for (const skill of getSkillStore().getAll()) {
|
|
515
|
-
if (isDisabled(skill.id, cm))
|
|
516
|
-
continue;
|
|
517
|
-
entries.push({ name: skill.name, description: skill.description ?? '' });
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
catch {
|
|
521
|
-
// Best-effort — a store failure must not remove the hub half.
|
|
522
|
-
}
|
|
523
|
-
// Hub (installed SKILL.md) skills.
|
|
524
|
-
try {
|
|
525
|
-
const { listMatchableHubSkills } = await import('../learning/hub-skill-catalog.js');
|
|
526
|
-
for (const skill of listMatchableHubSkills(cm)) {
|
|
527
|
-
if (isDisabled(skill.id, cm))
|
|
528
|
-
continue;
|
|
529
|
-
if (entries.some((e) => e.name === skill.name))
|
|
530
|
-
continue;
|
|
531
|
-
entries.push({ name: skill.name, description: skill.description ?? '' });
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
catch {
|
|
535
|
-
// Best-effort — a catalog failure leaves the compiled half.
|
|
536
|
-
}
|
|
130
|
+
const loadHint = opts.loadHint ?? 'skill-tool';
|
|
131
|
+
const entries = await collectSkillEntries(cm);
|
|
537
132
|
if (entries.length === 0)
|
|
538
133
|
return '';
|
|
539
134
|
const shown = entries.slice(0, maxSkills);
|
|
540
135
|
// `namesOnly` (mode `names`) drops the per-skill description: the model still
|
|
541
136
|
// sees the whole catalog and can `skill` with no name to read the details, but
|
|
542
|
-
// the prompt pays a fraction of the
|
|
137
|
+
// the prompt pays a fraction of the full description catalog.
|
|
543
138
|
const lines = shown.map((e) => (namesOnly ? ` - ${e.name}` : ` - ${e.name}: ${cap(e.description, descChars)}`));
|
|
544
139
|
const more = entries.length > shown.length ? `\n (+${entries.length - shown.length} more — call the skill tool with no name to list all)` : '';
|
|
545
140
|
return [
|
|
@@ -547,31 +142,35 @@ export async function buildSkillCatalogHint(cm, opts = {}) {
|
|
|
547
142
|
'## Available skills',
|
|
548
143
|
namesOnly
|
|
549
144
|
? 'A first-party skill may fit this goal. These are NAMES only — call the skill tool with no name to read a skill\u2019s description, then load one ONLY when it genuinely applies (ignore the rest):'
|
|
550
|
-
: 'A first-party skill may fit this goal. Read the list and decide — load one
|
|
145
|
+
: 'A first-party skill may fit this goal. Read the list and decide — load one ONLY when it genuinely applies (ignore the rest):',
|
|
551
146
|
...lines,
|
|
552
147
|
more,
|
|
553
148
|
'',
|
|
554
|
-
|
|
149
|
+
loadTail(loadHint),
|
|
555
150
|
].filter((l) => l !== undefined).join('\n');
|
|
556
151
|
}
|
|
557
152
|
/** The default. The catalog is ~24K chars — it must never be the default. */
|
|
558
|
-
export const DEFAULT_SKILL_HINT_MODE = '
|
|
153
|
+
export const DEFAULT_SKILL_HINT_MODE = 'pointer';
|
|
559
154
|
/** Env names, `NUVIRA_*` first with the legacy `BUFF_*` alias accepted. */
|
|
560
155
|
const SKILL_HINT_ENV_NAMES = ['NUVIRA_SKILL_CATALOG', 'BUFF_SKILL_CATALOG'];
|
|
561
156
|
/**
|
|
562
157
|
* Parse a raw value into a mode. Synonyms accepted so a typo cannot silently
|
|
563
158
|
* change behaviour; null (unrecognized) falls through to the next source.
|
|
564
|
-
* - match / keyword / auto / small / default
|
|
565
|
-
* - catalog / full / all / on / true / 1
|
|
566
|
-
* - names / names-only / list / bare / titles
|
|
567
|
-
* - off / none / never / false / 0
|
|
159
|
+
* - pointer / match / keyword / auto / small / default → 'pointer'
|
|
160
|
+
* - catalog / full / all / on / true / 1 → 'catalog'
|
|
161
|
+
* - names / names-only / list / bare / titles → 'names'
|
|
162
|
+
* - off / none / never / false / 0 → 'off'
|
|
163
|
+
*
|
|
164
|
+
* `match`/`keyword` are kept as ACCEPTED SYNONYMS for back-compat (an existing
|
|
165
|
+
* `NUVIRA_SKILL_CATALOG=match` or `skills.catalogHint: "match"` still works) —
|
|
166
|
+
* they now mean the pointer, since there is no keyword matcher any more.
|
|
568
167
|
*/
|
|
569
168
|
export function parseSkillHintMode(raw) {
|
|
570
169
|
const v = String(raw ?? '').trim().toLowerCase();
|
|
571
170
|
if (!v)
|
|
572
171
|
return null;
|
|
573
|
-
if (v === 'match' || v === 'keyword' || v === 'auto' || v === 'small' || v === 'default')
|
|
574
|
-
return '
|
|
172
|
+
if (v === 'pointer' || v === 'match' || v === 'keyword' || v === 'auto' || v === 'small' || v === 'default')
|
|
173
|
+
return 'pointer';
|
|
575
174
|
if (v === 'catalog' || v === 'full' || v === 'all' || v === 'on' || v === 'true' || v === '1')
|
|
576
175
|
return 'catalog';
|
|
577
176
|
if (v === 'names' || v === 'names-only' || v === 'list' || v === 'bare' || v === 'titles')
|
|
@@ -583,15 +182,7 @@ export function parseSkillHintMode(raw) {
|
|
|
583
182
|
/**
|
|
584
183
|
* The effective skill-hint mode. Env first (`NUVIRA_SKILL_CATALOG`, then the
|
|
585
184
|
* legacy `BUFF_*`), then `skills.catalogHint` in the config file, then the
|
|
586
|
-
* default (`
|
|
587
|
-
*
|
|
588
|
-
* WHY THIS EXISTS (2026-10-04). 3.3.11 replaced the keyword hint with the full
|
|
589
|
-
* catalog unconditionally — measured live, `buildSkillCatalogHint()` returned
|
|
590
|
-
* 24,543 chars on the goal "create mac od gui app", taking the chat system
|
|
591
|
-
* prompt from 7,653 chars (3.3.10) to 32,809. That ~6.1K-token tax on EVERY
|
|
592
|
-
* turn buried the task for weak/free-tier models and made 16K-token tiers
|
|
593
|
-
* impossible (the prompt alone is ~8.2K). The catalog is a genuinely useful
|
|
594
|
-
* discovery mechanism, but it must be CHOSEN, not imposed.
|
|
185
|
+
* default (`pointer`). Pure and never throws.
|
|
595
186
|
*/
|
|
596
187
|
export function resolveSkillHintMode(cm) {
|
|
597
188
|
for (const name of SKILL_HINT_ENV_NAMES) {
|
|
@@ -611,44 +202,27 @@ export function resolveSkillHintMode(cm) {
|
|
|
611
202
|
return DEFAULT_SKILL_HINT_MODE;
|
|
612
203
|
}
|
|
613
204
|
/**
|
|
614
|
-
* The skill hint
|
|
615
|
-
*
|
|
616
|
-
* the policy:
|
|
205
|
+
* The skill hint, resolved through the configured mode — the ONE entry point
|
|
206
|
+
* both the chat/execute loop and the pipeline call, so a surface can never drift
|
|
207
|
+
* from the policy:
|
|
617
208
|
* - `off` → ''
|
|
618
209
|
* - `catalog` → the full name+description catalog ({@link buildSkillCatalogHint})
|
|
619
210
|
* - `names` → the names-only catalog (no descriptions)
|
|
620
|
-
* - `
|
|
211
|
+
* - `pointer` → the discovery pointer ({@link buildSkillPointerHint})
|
|
621
212
|
*
|
|
622
|
-
* `
|
|
623
|
-
*
|
|
624
|
-
*
|
|
213
|
+
* `loadHint` lets the pipeline point its tail at skill_view (the writer's load
|
|
214
|
+
* path) instead of the loop's skill tool; it is ignored in the catalog modes'
|
|
215
|
+
* default wording and only affects the tail line.
|
|
625
216
|
*/
|
|
626
|
-
export async function buildConfiguredSkillHint(
|
|
217
|
+
export async function buildConfiguredSkillHint(cm, opts = {}) {
|
|
627
218
|
const mode = resolveSkillHintMode(cm);
|
|
219
|
+
const loadHint = opts.loadHint ?? 'skill-tool';
|
|
628
220
|
if (mode === 'off')
|
|
629
221
|
return '';
|
|
630
222
|
if (mode === 'catalog')
|
|
631
|
-
return buildSkillCatalogHint(cm);
|
|
223
|
+
return buildSkillCatalogHint(cm, { loadHint });
|
|
632
224
|
if (mode === 'names')
|
|
633
|
-
return buildSkillCatalogHint(cm, { namesOnly: true });
|
|
634
|
-
return
|
|
635
|
-
}
|
|
636
|
-
/**
|
|
637
|
-
* Mark an injected skill as used (usage tracking parity with the orchestrator
|
|
638
|
-
* — compiled skills only; hub skills have no compiled usage counter). The
|
|
639
|
-
* SINGLE usage marker for the loop hint path (the hint builder never marks).
|
|
640
|
-
* Best-effort, fire-and-forget: never throws, never awaited by callers on the
|
|
641
|
-
* hot path.
|
|
642
|
-
*/
|
|
643
|
-
export async function markLoopSkillUsed(match) {
|
|
644
|
-
if (!match || match.source !== 'compiled')
|
|
645
|
-
return;
|
|
646
|
-
try {
|
|
647
|
-
const { getSkillStore } = await import('../learning/skill-store.js');
|
|
648
|
-
getSkillStore().markUsed(match.id);
|
|
649
|
-
}
|
|
650
|
-
catch {
|
|
651
|
-
// Best-effort.
|
|
652
|
-
}
|
|
225
|
+
return buildSkillCatalogHint(cm, { namesOnly: true, loadHint });
|
|
226
|
+
return buildSkillPointerHint(cm, loadHint);
|
|
653
227
|
}
|
|
654
228
|
//# sourceMappingURL=loop-skill-hint.js.map
|