@vpxa/aikit 0.1.377 → 0.1.379
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/packages/browser/dist/index.js +1 -1
- package/packages/claude-desktop/dist/manifest.json +1 -1
- package/packages/cli/dist/index.js +3 -3
- package/packages/cli/dist/{init-CAIdybTd.js → init-BTsNYC02.js} +1 -1
- package/packages/cli/dist/{templates-3q6NnbZs.js → templates-CRs_gkfS.js} +14 -13
- package/packages/core/dist/index.d.ts +7 -7
- package/packages/core/dist/index.js +1 -1
- package/packages/server/dist/bin.js +1 -1
- package/packages/server/dist/config-BJiacqlj.js +2 -0
- package/packages/server/dist/config-DyLck_1C.js +1 -0
- package/packages/server/dist/index.js +1 -1
- package/packages/server/dist/prelude-BbNJxiBp.js +1 -0
- package/packages/server/dist/prelude-CZ1LShfj.js +2 -0
- package/packages/server/dist/sampling-CzGQqIbt.js +1 -0
- package/packages/server/dist/sampling-MSeOiAqz.js +2 -0
- package/packages/server/dist/server-CMpnBSAC.js +3068 -0
- package/packages/server/dist/server-Cq5wP6Hk.js +3067 -0
- package/packages/server/dist/{server-http-CUG7Wtib.js → server-http-UNbq9MsP.js} +1 -1
- package/packages/server/dist/{server-http-4z6DRLev.js → server-http-dyzC379J.js} +1 -1
- package/packages/server/dist/{server-stdio-CuhNvKfr.js → server-stdio-COZ6ut6S.js} +1 -1
- package/packages/server/dist/{server-stdio-CGrww9xa.js → server-stdio-yz2eyGS4.js} +1 -1
- package/packages/tools/dist/index.d.ts +118 -203
- package/packages/tools/dist/index.js +115 -117
- package/scaffold/dist/adapters/_shared.mjs +12 -11
- package/scaffold/dist/adapters/claude-code.mjs +7 -7
- package/scaffold/dist/adapters/copilot.mjs +12 -12
- package/scaffold/dist/adapters/hermes.mjs +1 -1
- package/scaffold/dist/definitions/bodies.mjs +11 -1
- package/scaffold/dist/definitions/exec-hooks.mjs +1 -1
- package/scaffold/dist/definitions/tools.mjs +1 -1
- package/scaffold/general/hooks/scripts/bash-guard.mjs +76 -0
- package/scaffold/general/hooks/scripts/read-size-guard.mjs +61 -0
- package/scaffold/general/hooks/scripts/session-reminder.mjs +108 -26
- package/packages/server/dist/config-B4klhHVp.js +0 -2
- package/packages/server/dist/config-D3rRPB9X.js +0 -1
- package/packages/server/dist/prelude-BWAg5ESi.js +0 -2
- package/packages/server/dist/prelude-qHhtG0FU.js +0 -1
- package/packages/server/dist/sampling-D61kCvwj.js +0 -2
- package/packages/server/dist/sampling-DIln2Pr4.js +0 -1
- package/packages/server/dist/server-B9RF008q.js +0 -3084
- package/packages/server/dist/server-D3IS2SBd.js +0 -3083
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import{renderLayeredKnowledgeOperatingPolicyV1 as e}from"../definitions/protocols.mjs";function t(e){return e&&e[0].toLowerCase()+e.slice(1)}function n(
|
|
2
|
-
`)}
|
|
3
|
-
`)}function i({name:e,title:
|
|
1
|
+
import{renderLayeredKnowledgeOperatingPolicyV1 as e}from"../definitions/protocols.mjs";function t(e){return e&&e[0].toLowerCase()+e.slice(1)}function n(){return[`## Workspace Skill`,``,`This project has an auto-generated workspace skill at`,"`<aikit-workspace>/skills/<workspace-name>/SKILL.md`.",``,`The skill tracks **conventions**, **known issues**, and **workflow tips**`,`specific to this codebase. Load it at session start by either:`,``,"1. Calling `status()` and checking the `workspace_skill` metadata field"," for the skill file path, then reading it with `read_file`.",`2. Reading the skill file directly if you know the workspace path.`,``,`The skill is auto-generated from the AI Kit knowledge store and updates`,`automatically when new facts are promoted. To contribute learnings, use`,"the `knowledge` tool — entries appear in the skill on next regeneration.",``,`**Deep-dive references** (per-topic, loaded on demand):`,"- `<skill-dir>/references/architecture.md` — deep architecture","- `<skill-dir>/references/known-issues.md` — recurring problems","- `<skill-dir>/references/workflow-tips.md` — optimization patterns","- `<skill-dir>/references/flow-<slug>.md` — active flow briefing",``].join(`
|
|
2
|
+
`)}function r(e){return!e||e.length===0?``:`## Skills\n\n| Skill | When to load |\n|-------|--------------|\n${e.map(([e,t])=>`| ${e} | ${t} |`).join(`
|
|
3
|
+
`)}`}function i({name:e,title:i,description:a,skills:o,bodyAddendum:s}){let c=r(o),l=n(),u=[`# ${e} - ${i||e}`,``,`> ${a}`,``,`You are the **${e}**, ${t(a)}.`];return s&&u.push(``,s.trim()),c&&u.push(``,c),u.push(``,l),u.push(``),u.join(`
|
|
4
|
+
`)}function a({name:e,title:n,description:i,body:a,skills:o,additionalSections:s}){let c=[`### ${e} — ${n||e}`,``,`> ${i}`,``,`You are the **${e}**, ${t(i)}.`],l=[a,...s||[],r(o)].filter(Boolean).join(`
|
|
4
5
|
|
|
5
6
|
`).trim();return l&&c.push(``,l),c.push(``,`---`,``),c.join(`
|
|
6
|
-
`)}function
|
|
7
|
+
`)}function o({title:e,content:t}){return`# ${e}\n\n${t}`}function s(e){return Object.entries(e).map(([e,t])=>[`### ${t.title||t.description||e}`,``,t.content.trim(),``,`---`,``].join(`
|
|
7
8
|
`)).join(`
|
|
8
|
-
`).trimEnd()}const
|
|
9
|
-
`):``}function
|
|
10
|
-
`)}const
|
|
11
|
-
`).trimEnd()}function
|
|
9
|
+
`).trimEnd()}const c={sessionStart:`SessionStart`,beforeCodeChange:`PreToolUse`,beforeCommit:`PreCommit`,sessionEnd:`SessionEnd`},l=[`sessionStart`,`beforeCodeChange`,`beforeCommit`,`sessionEnd`];function u(e){return e?.overall===`none`?[``,`> **Note**: This platform does not support native hook execution (no SessionStart, PreToolUse,`,`> PostToolUse, or PreCommit events). All hook behaviors documented below are **manual** -- you`,`> must perform them yourself. If you need server-side guardrails (privacy guards, scope`,`> enforcement, auto-knowledge signals), consider running the MCP server's **EventBus**, which`,`> provides in-process lifecycle subscribers without requiring IDE-level hook support.`,"> Check `aikit://hooks/config` for available EventBus subscribers.",``].join(`
|
|
10
|
+
`):``}function d(e,t,n,r,i){if(!e||i===`omit`)return``;i!==void 0&&i!==`pinned`&&i!=="default"&&console.warn(`buildHookSubsection: unrecognized treatment "${i}" for "${t}". Valid: ${m.join(`, `)}. Falling back to level-based rendering.`);let a=(e.actions||[]).map(e=>`- \`${e}\``),o=[`### ${t}`];return n===`native`?o.push(``,`_`+(r.native||`Auto-handled by native hooks.`)+`_ The following run automatically:`,``,...a,``):n===`eventbus`?o.push(``,`_`+(r.eventbus||`Monitored by EventBus.`)+`_ Active subscribers run automatically.`,`For awareness, these are the current subscribers:`,``,...a,``,"Check `aikit://hooks/config` for the full subscriber list.",``):n===`middleware`?o.push(``,`_`+(r.middleware||`Automated by middleware.`)+`_ The platform middleware handles this:`,``,...a,``):o.push(``,`${r.none||`Manually run the following:`}`,``,...a,``),o.join(`
|
|
11
|
+
`)}const f={sessionStart:{native:`Auto-handled by hooks. Status/knowledge/search run on every session start.`,eventbus:`Handled by EventBus. Session-start subscribers fire on connection.`,middleware:`Automated by ToolPipeline middleware. Status/knowledge/search run on session init.`,none:`On every session start, manually run the following to resume context:`},beforeCodeChange:{native:`Auto-handled by hooks. Search+scope checks run before every code change.`,eventbus:`Monitored by EventBus. Tool-before subscribers may provide context.`,none:`Before modifying any code, manually run these checks:`},beforeCommit:{native:`Hook auto-runs. Check+test+blast-radius run before every commit.`,eventbus:`No native pre-commit hooks on this platform. Validate manually:`,middleware:`No middleware-based pre-commit support. Validate manually:`,none:`Before committing changes, manually run these validations:`},sessionEnd:{native:`Auto-handled by hooks. Session-end hook persists checkpoints automatically.`,eventbus:`Tracked by EventBus. Stop subscribers fire on shutdown.`,middleware:`Automated by middleware. Handoff runs on session end.`,none:`Before ending a session (or at high context pressure), manually create a handoff:`}},p={sessionStart:`Session Start`,beforeCodeChange:`Before Code Change`,beforeCommit:`Before Commit`,sessionEnd:`Session End`},m=[`pinned`,`default`,`omit`];function h(e,t,n){if(!e)return``;let r=l.map(r=>{let i=e[r];if(!i)return``;let a=c[r],o=t&&a&&t[a]||`none`,s=f[r]||{},l=n?.[r];return d(i,p[r],o,s,l)}),i=u(t);return[...r,i].filter(Boolean).join(`
|
|
12
|
+
`).trimEnd()}function g(e,t){if(!e)return null;let n=typeof e==`function`?e(t):e[t];return n?typeof n==`string`?n:n.primary||n.model||null:null}function _(e,t){let n=!!t,r=[];for(let[i,a]of Object.entries(e))if(a.variants)for(let[e,o]of Object.entries(a.variants)){let s=`${i}-${e}`,c=[`| **${s}** | ${o.description} |`];n&&c.push(` ${g(t,s)||`—`} |`),c.push(` ${a.category||`—`} |`),r.push(c.join(``))}else{let e=[`| **${i}** | ${a.description} |`];n&&e.push(` ${g(t,i)||`—`} |`),e.push(` ${a.category||`—`} |`),r.push(e.join(``))}return n?`| Agent | Purpose | Model | Category |\n|-------|---------|-------|----------|\n${r.join(`
|
|
12
13
|
`)}`:`| Agent | Purpose | Category |\n|-------|---------|----------|\n${r.join(`
|
|
13
|
-
`)}`}function
|
|
14
|
-
`)}`}function
|
|
15
|
-
`)}function
|
|
14
|
+
`)}`}function v(e){let t=[];for(let[n,r]of Object.entries(e)){if(n===`Orchestrator`)continue;let e=r.compactRole||r.description;if(r.variants){let i=Object.keys(r.variants);t.push(`| **${n}-${i.join(`/`)}** | ${e} |`)}else t.push(`| **${n}** | ${e} |`)}return`| Agent | Role |\n|-------|------|\n${t.join(`
|
|
15
|
+
`)}`}function y({serverName:e,mcpEntry:t,configKey:n,extraServerFields:r}){let i={...t};return r&&Object.assign(i,r),JSON.stringify({[n]:{[e]:i}},null,2)}function b({flowTool:t=`flow`,isLifecycleOwner:n=!0}={}){let r=[`## Flows`,``,`This project uses aikit's pluggable flow system. Check flow status with the \`${t}\` MCP tool.`,``];return n?r.push(e({audience:`agent`}),``,`Use \`${t}({ action: 'list' })\` to see available flows and \`${t}({ action: 'start', name, topic })\` to begin one.`,``,`If a flow is active, follow the current step's skill instructions. Advance with \`${t}({ action: 'step', advance: 'next' })\`.`):r.push(`This project uses aikit's pluggable flow system. Use \`${t}({ action: 'status' })\` to check if a flow is active.`,`If dispatched as part of a flow, your work contributes to the current step. Do NOT advance or manage the flow — the Orchestrator handles flow lifecycle.`),r.join(`
|
|
16
|
+
`)}function x({flowTool:e=`flow`}={}){return b({flowTool:e,isLifecycleOwner:!1})}const S=`You MUST follow the Orchestrator Protocol: decompose every task into subtasks, delegate via Task()/sub-agents, and synthesize results. You are an orchestrator, not an implementer. Never write code directly unless the change is trivially small (≤5 lines, one file) or you are fixing a sub-agent's output. When in doubt, delegate.`;function C(e){return[`# ${S}`,``,...e]}export{S as ORCHESTRATOR_DIRECTIVE,i as buildAgentPrompt,_ as buildAgentTable,v as buildCompactAgentTable,u as buildEventBusNote,b as buildFlowSection,h as buildHooksSection,a as buildInlineAgentSection,y as buildMcpConfigJson,o as buildPromptFile,s as buildPromptSections,r as buildSkillsSection,x as buildSubagentFlowSection,n as buildWorkspaceSkillSection,C as injectOrchestratorDirective,t as lowerFirst};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{AGENTS as e}from"../definitions/agents.mjs";import{AGENT_BODIES as t}from"../definitions/bodies.mjs";import{HOOKS as n}from"../definitions/hooks.mjs";import{SERVER_NAME as r}from"../definitions/mcp.mjs";import{getPlatformPrimaryModelMap as i}from"../definitions/models.mjs";import{PLATFORM_HOOK_CAPABILITIES as a}from"../definitions/platform-capabilities.mjs";import{PROMPTS as o}from"../definitions/prompts.mjs";import{AIKIT_INSTALL_HINT_SECTION as s,PLATFORM_OUTPUT_RULES_SECTION as c,PROTOCOLS as l}from"../definitions/protocols.mjs";import{
|
|
2
|
-
`)}function
|
|
3
|
-
`)}function
|
|
4
|
-
`)}function
|
|
5
|
-
`)}function
|
|
1
|
+
import{AGENTS as e}from"../definitions/agents.mjs";import{AGENT_BODIES as t}from"../definitions/bodies.mjs";import{HOOKS as n}from"../definitions/hooks.mjs";import{SERVER_NAME as r}from"../definitions/mcp.mjs";import{getPlatformPrimaryModelMap as i}from"../definitions/models.mjs";import{PLATFORM_HOOK_CAPABILITIES as a}from"../definitions/platform-capabilities.mjs";import{PROMPTS as o}from"../definitions/prompts.mjs";import{AIKIT_INSTALL_HINT_SECTION as s,PLATFORM_OUTPUT_RULES_SECTION as c,PROTOCOLS as l}from"../definitions/protocols.mjs";import{AIKIT_TOOLS as u,CLAUDE_CODE_TOOL_MAP as d,IDE_CAPABILITIES as f}from"../definitions/tools.mjs";import{buildAgentTable as p,buildCompactAgentTable as m,buildFlowSection as h,buildHooksSection as g,buildSkillsSection as _,buildWorkspaceSkillSection as v,injectOrchestratorDirective as y,lowerFirst as b}from"./_shared.mjs";const x=h({flowTool:`flow`,isLifecycleOwner:!0}),S=h({flowTool:`flow`,isLifecycleOwner:!1});function C(e){return e.replace(/([a-z0-9])([A-Z])/g,`$1-$2`).replace(/[^a-zA-Z0-9]+/g,`-`).replace(/^-+|-+$/g,``).toLowerCase()}function w(e){return`"${String(e).replace(/\\/g,`\\\\`).replace(/"/g,`\\"`)}"`}function T(e){let t=(f[e]||[]).flatMap(e=>d[e]||[]),n=u.map(e=>`mcp__${r.toLowerCase().replace(/[^a-z0-9]/g,``)}__${e}`);return[...new Set([...t,...n])].sort((e,t)=>e.localeCompare(t))}function E(e,t){let n=[];return n.push(`# ${r} ${e}`),n.push(``),t.description&&(n.push(`> ${t.description}`),n.push(``)),n.push(t.content.trim()),n.push(``),n.join(`
|
|
2
|
+
`)}function D(e,n){let r=t[e];return typeof r==`function`?r(n):r||``}function O(e){let t=[];e.extraBody&&t.push(e.extraBody),e.sharedBase&&l[e.sharedBase]&&t.push(l[e.sharedBase]);for(let n of e.sharedProtocols||[])l[n]&&t.push(l[n]);return t}function k(){let t=[];for(let[n,r]of Object.entries(e)){if(r.variants){for(let[e,i]of Object.entries(r.variants))t.push({name:`${n}-${e}`,description:i.description||r.description});continue}t.push({name:n,description:r.description})}return t}function A(e){return k().map(({name:t,description:n})=>`- \`${e}/${t}.md\` — ${n}`).join(`
|
|
3
|
+
`)}function j(t=p(e,i(`claude-code`))){return[`# ${r} — Claude Code Agents`,``,c,``,s,``,`## MCP Server`,``,`Server name: \`${r}\``,"Configured in `.mcp.json` (project) and `~/.claude.json` (user-global — `claude mcp add --scope user` format).","Default agent: `Orchestrator` in `~/.claude/settings.json` — every conversation starts as Orchestrator automatically.",``,`## Agents`,``,t,``,`## Agent Files`,``,A(`.claude/agents`),``,`## Commands`,``,"Slash commands live under `.claude/commands/`.",``,`## Session Protocol`,``,g(n,a[`claude-code`]),``].join(`
|
|
4
|
+
`)}function M(){return y([`# ${r} — Claude Code Instructions`,``,"Detailed workspace instructions live in `AGENTS.md`.","Full sub-agent instructions live in `.claude/agents/`.","Slash commands live in `.claude/commands/`.","MCP server config lives in `.mcp.json` (project) and `~/.claude.json` (user-global — written by `claude mcp add --scope user`).","Default agent set to `Orchestrator` in `~/.claude/settings.json` — every conversation starts as Orchestrator, no `/agent` command needed.",``,"Start with `AGENTS.md`, then open the specific sub-agent file you want to use.",``,c,``,s,``,v(),``]).join(`
|
|
5
|
+
`)}function N(e,t,n,i,a){let o=T(t.toolRole),s=O(t),c=_(t.skills),l=e===`Orchestrator`?[x]:[S],u=[n,...s,t.bodyAddendum,c,...l].filter(Boolean).join(`
|
|
6
6
|
|
|
7
|
-
`).trim(),d=t.identity?`You are the **${e}**${t.identity}`:`You are the **${e}**, ${
|
|
8
|
-
`)}function
|
|
7
|
+
`).trim(),d=t.identity?`You are the **${e}**${t.identity}`:`You are the **${e}**, ${b(t.description)}.`,f=a?.[e],p=o.length>0?`tools: [${o.join(`, `)}]`:null,m=t.skills?.length>0?`skills: [${t.skills.map(([e])=>e).join(`, `)}]`:null,h=[`---`,`name: ${C(e)}`,`description: ${w(t.description)}`,...f?[`model: ${w(f)}`]:[],...p?[p]:[],`mcpServers:`,` - ${r}`,...m?[m]:[],`---`,``,`# ${e} - ${t.title||e}`,``,d];return u&&h.push(``,u),h.push(``),h.join(`
|
|
8
|
+
`)}function P(){let t=[],n=i(`claude-code`),r=p(e,n),a=m(e);t.push({path:`CLAUDE.md`,content:M()}),t.push({path:`AGENTS.md`,content:j(r)});for(let[e,n]of Object.entries(o))t.push({path:`.claude/commands/aikit-${e}.md`,content:E(e,n)});for(let[i,o]of Object.entries(e)){let e=D(i,a);if(o.variants){for(let[a,s]of Object.entries(o.variants)){let c=`${i}-${a}`;t.push({path:`.claude/agents/${c}.md`,content:N(c,{...o,description:s.description||o.description,identity:s.identity,bodyAddendum:s.bodyAddendum},e,r,n)})}continue}t.push({path:`.claude/agents/${i}.md`,content:N(i,o,e,r,n)})}return t}export{x as CLAUDE_FLOWS_SECTION,P as generateClaudeCode};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import{AGENTS as e}from"../definitions/agents.mjs";import{AGENT_BODIES as t}from"../definitions/bodies.mjs";import{VARIANT_GROUPS as n,getPrimaryAgentModel as r}from"../definitions/models.mjs";import{PROMPTS as i}from"../definitions/prompts.mjs";import{AIKIT_INSTALL_HINT_SECTION as a,PLATFORM_OUTPUT_RULES_SECTION as o,PROTOCOLS as s,TEMPLATES as c}from"../definitions/protocols.mjs";import{IDE_CAPABILITIES as l}from"../definitions/tools.mjs";import{buildCompactAgentTable as u,buildFlowSection as d,buildSubagentFlowSection as f,injectOrchestratorDirective as
|
|
2
|
-
`)}`}function
|
|
1
|
+
import{AGENTS as e}from"../definitions/agents.mjs";import{AGENT_BODIES as t}from"../definitions/bodies.mjs";import{VARIANT_GROUPS as n,getPrimaryAgentModel as r}from"../definitions/models.mjs";import{PROMPTS as i}from"../definitions/prompts.mjs";import{AIKIT_INSTALL_HINT_SECTION as a,PLATFORM_OUTPUT_RULES_SECTION as o,PROTOCOLS as s,TEMPLATES as c}from"../definitions/protocols.mjs";import{IDE_CAPABILITIES as l}from"../definitions/tools.mjs";import{buildCompactAgentTable as u,buildFlowSection as d,buildSubagentFlowSection as f,buildWorkspaceSkillSection as p,injectOrchestratorDirective as m}from"./_shared.mjs";import{generateForbiddenTable as h}from"../definitions/policies.mjs";import{generateHooks as g,getHookScriptFiles as _}from"./hooks.mjs";const v={terminal:`execute/runInTerminal`,problems:`read/problems`,readFile:`read/readFile`,lastCommand:`read/terminalLastCommand`,subagent:`agent/runSubagent`,createFile:`edit/createFile`,editFiles:`edit/editFiles`,rename:`edit/rename`,createDirectory:`edit/createDirectory`,search:`search/changes, search/codebase, search/usages`,web:`web/fetch, web/githubRepo`,todo:`todo`,memory:`vscode/memory`,newWorkspace:`vscode/newWorkspace`,reviewPlan:`vscode/reviewPlan`,askQuestions:`vscode/askQuestions`,resolveMemoryFileUri:`vscode/resolveMemoryFileUri`,runCommand:`vscode/runCommand`,switchAgent:`vscode/switchAgent`,killTerminal:`execute/killTerminal`,createTask:`execute/createAndRunTask`,terminalSel:`read/terminalSelection`,fileSearch:`search/fileSearch`,listDir:`search/listDirectory`,textSearch:`search/textSearch`,searchSubagent:`search/searchSubagent`};function y(e){return`[${[...(l[e]||[]).map(e=>v[e]).filter(Boolean),`aikit/*`].join(`, `)}]`}function b(e){return r(`copilot`,e,`Auto (copilot)`)}const x=d({flowTool:`flow`,isLifecycleOwner:!0}),S=f({flowTool:`flow`});function C(){let t=[];for(let[i,a]of Object.entries(e))if(a.variants)for(let e of n[i]||[]){let n=`${i}-${e}`,o=r(`copilot`,n,`Unknown`),s=(a.variants[e]||{}).description||a.description;t.push(`| **${n}** | ${s} | ${o} | ${a.category} |`)}else{let e=r(`copilot`,i,`Unknown`);t.push(`| **${i}** | ${a.description} | ${e} | ${a.category} |`)}return`| Agent | Purpose | Model | Category |\n|-------|---------|-------|----------|\n${t.join(`
|
|
2
|
+
`)}`}function w(e,t,r){let i=`${e}-${t}`,a=r.variants[t]||{},o=b(i),c=a.description||r.description,l=a.identity||(t===n[e]?.[0]?`, the primary ${e} agent.`:`, a variant of ${e}. Same responsibilities, different model perspective.`),u=r.sharedBase&&s[r.sharedBase]?`\n\n${s[r.sharedBase]}`:``,d=r.extraBody?`\n\n${r.extraBody}`:``,f=a.bodyAddendum?`\n\n${a.bodyAddendum}`:``,p=(r.sharedProtocols||[]).map(e=>s[e]?`\n\n${s[e]}`:``).join(``),m=r.skills?.length?`\n\n## Skills (load on demand)\n\n| Skill | When to load |\n|-------|--------------|\n${r.skills.map(([e,t])=>`| ${e} | ${t} |`).join(`
|
|
3
3
|
`)}`:``,h=r.title||e;return`---
|
|
4
4
|
description: '${c}'
|
|
5
|
-
${r.argumentHint?`argument-hint: "${r.argumentHint}"\n`:``}tools: ${
|
|
5
|
+
${r.argumentHint?`argument-hint: "${r.argumentHint}"\n`:``}tools: ${y(r.toolRole)}
|
|
6
6
|
model: ${o}
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -11,11 +11,11 @@ model: ${o}
|
|
|
11
11
|
You are **${i}**${l}${d}
|
|
12
12
|
${u}${p}${f}${m}
|
|
13
13
|
|
|
14
|
-
${
|
|
15
|
-
`}function
|
|
14
|
+
${S}
|
|
15
|
+
`}function T(n,r){let i=b(n),a=typeof t[n]==`function`?t[n](u(e)):t[n]||``,o=r.sharedBase&&s[r.sharedBase]?`\n\n${s[r.sharedBase]}`:``,c=(r.sharedProtocols||[]).map(e=>s[e]?`\n\n${s[e]}`:``).join(``),l=r.title||n,d=r.skills?.length?`\n## Skills (load on demand)\n\n| Skill | When to load |\n|-------|--------------|\n${r.skills.map(([e,t])=>`| ${e} | ${t} |`).join(`
|
|
16
16
|
`)}\n`:``;return`---
|
|
17
17
|
description: '${r.description}'
|
|
18
|
-
${r.argumentHint?`argument-hint: "${r.argumentHint}"\n`:``}tools: ${
|
|
18
|
+
${r.argumentHint?`argument-hint: "${r.argumentHint}"\n`:``}tools: ${y(r.toolRole)}
|
|
19
19
|
model: ${i}
|
|
20
20
|
---
|
|
21
21
|
|
|
@@ -25,20 +25,20 @@ You are the **${n}**, ${r.description.toLowerCase().replace(/^./,e=>e.toLowerCas
|
|
|
25
25
|
|
|
26
26
|
${a}${o}${c}${d}
|
|
27
27
|
|
|
28
|
-
${n===`Orchestrator`?
|
|
29
|
-
`}function
|
|
28
|
+
${n===`Orchestrator`?x:S}
|
|
29
|
+
`}function E(e,t){return`---
|
|
30
30
|
description: "${t.description}"
|
|
31
31
|
agent: "${t.agent}"
|
|
32
32
|
---
|
|
33
33
|
|
|
34
34
|
${t.content}
|
|
35
|
-
`}function
|
|
35
|
+
`}function D(){return`# Agents
|
|
36
36
|
|
|
37
37
|
This directory contains AI agent definitions generated by \`@vpxa/aikit init\`.
|
|
38
38
|
|
|
39
39
|
## Agent Roster
|
|
40
40
|
|
|
41
|
-
${
|
|
41
|
+
${C()}
|
|
42
42
|
|
|
43
43
|
## Multi-Model Pattern
|
|
44
44
|
|
|
@@ -64,5 +64,5 @@ To regenerate after changing models or agent definitions:
|
|
|
64
64
|
cd knowledge-base
|
|
65
65
|
node scaffold/generate.mjs
|
|
66
66
|
\`\`\`
|
|
67
|
-
`}function
|
|
68
|
-
`)}function
|
|
67
|
+
`}function O(){return m([`# AI Kit — Copilot Instructions`,``,"This file is generated from `scaffold/definitions/`. Do not edit directly.",``,o,``,`## Tool Routing Rules`,``,`These rules are enforced by AI Kit compliance checking. Violations are flagged in reports and reduce your compliance score.`,``,h(),``,a,``,p(),``]).join(`
|
|
68
|
+
`)}function k(){let t=[];if(_().length===0)throw Error(`Executable hooks are not configured.`);t.push({path:`copilot-instructions.md`,content:O()});for(let[r,i]of Object.entries(e))if(i.variants)for(let e of n[r]||[])t.push({path:`agents/${r}-${e}.agent.md`,content:w(r,e,i)});else t.push({path:`agents/${r}.agent.md`,content:T(r,i)});for(let[e,n]of Object.entries(c))t.push({path:`agents/templates/${e}.md`,content:`${n}\n`});t.push({path:`agents/README.md`,content:D()});for(let[e,n]of Object.entries(i))t.push({path:`prompts/aikit-${e}.prompt.md`,content:E(e,n)});let r=g(`copilot`,`~/.copilot/hooks/scripts`);return t.push(...r.map(e=>({path:`hooks/${e.path}`,content:e.content}))),t}export{k as generateCopilot};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{AGENTS as e}from"../definitions/agents.mjs";import{AGENT_BODIES as t}from"../definitions/bodies.mjs";import{HOOKS as n}from"../definitions/hooks.mjs";import{VARIANT_GROUPS as r,getPrimaryAgentModel as i}from"../definitions/models.mjs";import{PLATFORM_HOOK_CAPABILITIES as a}from"../definitions/platform-capabilities.mjs";import{PROMPTS as o}from"../definitions/prompts.mjs";import{PROTOCOLS as s,TEMPLATES as c}from"../definitions/protocols.mjs";import{IDE_CAPABILITIES as l}from"../definitions/tools.mjs";import{buildAgentTable as u,buildCompactAgentTable as d,buildFlowSection as f,buildHooksSection as p,buildPromptSections as m,buildSkillsSection as h,injectOrchestratorDirective as g,lowerFirst as _}from"./_shared.mjs";import{generateHooks as v,getHookScriptFiles as y}from"./hooks.mjs";const b=f({flowTool:`flow`,isLifecycleOwner:!0}),x=f({flowTool:`flow`,isLifecycleOwner:!1});function S(e,n){let r=t[e];return typeof r==`function`?r(n):r||``}function C(e){let t=[];e.extraBody&&t.push(e.extraBody),e.sharedBase&&s[e.sharedBase]&&t.push(s[e.sharedBase]);for(let n of e.sharedProtocols||[])s[n]&&t.push(s[n]);return t}const w={terminal:`terminal`,problems:`mcp_aikit_check`,readFile:`read_file`,lastCommand:`terminal`,subagent:`delegate_task`,createFile:`write_file`,editFiles:`patch`,rename:`write_file`,createDirectory:`terminal(mkdir)`,search:`search_files, mcp_aikit_search, mcp_aikit_find`,web:`web_search, web_extract, mcp_aikit_web_search, mcp_aikit_web_fetch`,todo:`todo`,memory:`memory`,newWorkspace:`terminal(cd)`,reviewPlan:`clarify`,askQuestions:`clarify`,resolveMemoryFileUri:`read_file`,runCommand:`terminal`,switchAgent:`delegate_task`,killTerminal:`process(kill)`,createTask:`todo`,terminalSel:`terminal`,fileSearch:`search_files`,listDir:`search_files(target=files)`,textSearch:`search_files(target=content)`,searchSubagent:`delegate_task`,browser:`mcp_aikit_browser, browser_navigate`};function T(e){let t=(l[e]||[]).map(e=>{let t=w[e];return t?t.split(`,`).map(e=>e.trim()):null}).filter(Boolean).flat();return`[${[...new Set(t),`aikit/*`].join(`, `)}]`}function E(e){return i(`hermes`,e,`Auto (hermes)`)}function D(e){let t=[[/`runSubagent`/g,"`delegate_task`"],[/`runSubagent\(/g,"`delegate_task("],[/\brunSubagent\b/g,`delegate_task`],[/`editFiles`/g,"`patch`"],[/`createFile`/g,"`write_file`"],[/`edit\/createFile`/g,"`write_file`"],[/`edit\/editFiles`/g,"`patch`"],[/`run_in_terminal`/g,"`terminal`"],[/`execute\/runInTerminal`/g,"`terminal`"],[/`execute\/killTerminal`/g,"`process(kill)`"],[/`grep_search`/g,"`search_files`"],[/`search\/codebase`/g,"`mcp_aikit_search`"],[/`search\/changes`/g,"`search_files`"],[/`search\/usages`/g,"`mcp_aikit_symbol` / `mcp_aikit_trace`"],[/`search\/textSearch`/g,"`search_files`"],[/`search\/searchSubagent`/g,"`delegate_task`"],[/`web\/fetch`/g,"`web_extract` / `mcp_aikit_web_fetch`"],[/`web\/githubRepo`/g,"`terminal(git ...)`"],[/`web\/webSearch`/g,"`web_search` / `mcp_aikit_web_search`"],[/`vscode\/memory`/g,"`memory`"],[/`vscode\/runCommand`/g,"`terminal`"],[/`vscode\/switchAgent`/g,"`delegate_task`"],[/`vscode\/newWorkspace`/g,"`terminal(cd)`"],[/`vscode\/reviewPlan`/g,"`clarify`"],[/`vscode\/askQuestions`/g,"`clarify`"],[/`vscode\/resolveMemoryFileUri`/g,"`read_file`"],[/`read\/readFile`/g,"`read_file`"],[/`read\/terminalLastCommand`/g,"`terminal`"],[/`read\/terminalSelection`/g,"`terminal`"],[/`read\/problems`/g,"`mcp_aikit_check`"],[/`agent\/runSubagent`/g,"`delegate_task`"],[/`execute\/createAndRunTask`/g,"`todo` / `delegate_task`"],[/`read_file` \(for understanding\)/g,"`read_file` (Hermes)"],[/(copilot)/g,`(hermes)`],[/runSubagent\(\{agentName:/g,`delegate_task({goal:`],[/runSubagent\(\{/g,`delegate_task({`]],n=e;for(let[e,r]of t)n=n.replace(e,r);return n}function O(){let t=u(e),r=d(e),i=m(o),s=[];for(let[t,n]of Object.entries(e)){let e=S(t,r);if(n.variants){for(let[r,i]of Object.entries(n.variants)){let a=`${t}-${r}`;s.push(k(a,{...n,description:i.description||n.description,identity:i.identity,bodyAddendum:i.bodyAddendum},e))}continue}s.push(k(t,n,e))}return g([`# AI Kit — Hermes Agent Instructions`,``,"This project uses **AI Kit** (`@vpxa/aikit`), a local-first MCP server that provides search,",`code analysis, persistent memory, context compression, and guided development flows.`,``,`The AI Kit MCP server is registered in your Hermes config and its
|
|
1
|
+
import{AGENTS as e}from"../definitions/agents.mjs";import{AGENT_BODIES as t}from"../definitions/bodies.mjs";import{HOOKS as n}from"../definitions/hooks.mjs";import{VARIANT_GROUPS as r,getPrimaryAgentModel as i}from"../definitions/models.mjs";import{PLATFORM_HOOK_CAPABILITIES as a}from"../definitions/platform-capabilities.mjs";import{PROMPTS as o}from"../definitions/prompts.mjs";import{PROTOCOLS as s,TEMPLATES as c}from"../definitions/protocols.mjs";import{IDE_CAPABILITIES as l}from"../definitions/tools.mjs";import{buildAgentTable as u,buildCompactAgentTable as d,buildFlowSection as f,buildHooksSection as p,buildPromptSections as m,buildSkillsSection as h,injectOrchestratorDirective as g,lowerFirst as _}from"./_shared.mjs";import{generateHooks as v,getHookScriptFiles as y}from"./hooks.mjs";const b=f({flowTool:`flow`,isLifecycleOwner:!0}),x=f({flowTool:`flow`,isLifecycleOwner:!1});function S(e,n){let r=t[e];return typeof r==`function`?r(n):r||``}function C(e){let t=[];e.extraBody&&t.push(e.extraBody),e.sharedBase&&s[e.sharedBase]&&t.push(s[e.sharedBase]);for(let n of e.sharedProtocols||[])s[n]&&t.push(s[n]);return t}const w={terminal:`terminal`,problems:`mcp_aikit_check`,readFile:`read_file`,lastCommand:`terminal`,subagent:`delegate_task`,createFile:`write_file`,editFiles:`patch`,rename:`write_file`,createDirectory:`terminal(mkdir)`,search:`search_files, mcp_aikit_search, mcp_aikit_find`,web:`web_search, web_extract, mcp_aikit_web_search, mcp_aikit_web_fetch`,todo:`todo`,memory:`memory`,newWorkspace:`terminal(cd)`,reviewPlan:`clarify`,askQuestions:`clarify`,resolveMemoryFileUri:`read_file`,runCommand:`terminal`,switchAgent:`delegate_task`,killTerminal:`process(kill)`,createTask:`todo`,terminalSel:`terminal`,fileSearch:`search_files`,listDir:`search_files(target=files)`,textSearch:`search_files(target=content)`,searchSubagent:`delegate_task`,browser:`mcp_aikit_browser, browser_navigate`};function T(e){let t=(l[e]||[]).map(e=>{let t=w[e];return t?t.split(`,`).map(e=>e.trim()):null}).filter(Boolean).flat();return`[${[...new Set(t),`aikit/*`].join(`, `)}]`}function E(e){return i(`hermes`,e,`Auto (hermes)`)}function D(e){let t=[[/`runSubagent`/g,"`delegate_task`"],[/`runSubagent\(/g,"`delegate_task("],[/\brunSubagent\b/g,`delegate_task`],[/`editFiles`/g,"`patch`"],[/`createFile`/g,"`write_file`"],[/`edit\/createFile`/g,"`write_file`"],[/`edit\/editFiles`/g,"`patch`"],[/`run_in_terminal`/g,"`terminal`"],[/`execute\/runInTerminal`/g,"`terminal`"],[/`execute\/killTerminal`/g,"`process(kill)`"],[/`grep_search`/g,"`search_files`"],[/`search\/codebase`/g,"`mcp_aikit_search`"],[/`search\/changes`/g,"`search_files`"],[/`search\/usages`/g,"`mcp_aikit_symbol` / `mcp_aikit_trace`"],[/`search\/textSearch`/g,"`search_files`"],[/`search\/searchSubagent`/g,"`delegate_task`"],[/`web\/fetch`/g,"`web_extract` / `mcp_aikit_web_fetch`"],[/`web\/githubRepo`/g,"`terminal(git ...)`"],[/`web\/webSearch`/g,"`web_search` / `mcp_aikit_web_search`"],[/`vscode\/memory`/g,"`memory`"],[/`vscode\/runCommand`/g,"`terminal`"],[/`vscode\/switchAgent`/g,"`delegate_task`"],[/`vscode\/newWorkspace`/g,"`terminal(cd)`"],[/`vscode\/reviewPlan`/g,"`clarify`"],[/`vscode\/askQuestions`/g,"`clarify`"],[/`vscode\/resolveMemoryFileUri`/g,"`read_file`"],[/`read\/readFile`/g,"`read_file`"],[/`read\/terminalLastCommand`/g,"`terminal`"],[/`read\/terminalSelection`/g,"`terminal`"],[/`read\/problems`/g,"`mcp_aikit_check`"],[/`agent\/runSubagent`/g,"`delegate_task`"],[/`execute\/createAndRunTask`/g,"`todo` / `delegate_task`"],[/`read_file` \(for understanding\)/g,"`read_file` (Hermes)"],[/(copilot)/g,`(hermes)`],[/runSubagent\(\{agentName:/g,`delegate_task({goal:`],[/runSubagent\(\{/g,`delegate_task({`]],n=e;for(let[e,r]of t)n=n.replace(e,r);return n}function O(){let t=u(e),r=d(e),i=m(o),s=[];for(let[t,n]of Object.entries(e)){let e=S(t,r);if(n.variants){for(let[r,i]of Object.entries(n.variants)){let a=`${t}-${r}`;s.push(k(a,{...n,description:i.description||n.description,identity:i.identity,bodyAddendum:i.bodyAddendum},e))}continue}s.push(k(t,n,e))}return g([`# AI Kit — Hermes Agent Instructions`,``,"This project uses **AI Kit** (`@vpxa/aikit`), a local-first MCP server that provides search,",`code analysis, persistent memory, context compression, and guided development flows.`,``,`The AI Kit MCP server is registered in your Hermes config and its 52 tools are available`,"as `mcp_aikit_*` tool calls in every conversation.",``,`## MCP Server`,``,"Server name: `AI Kit`","Configured via `hermes mcp add` (user-level). Tools are auto-discovered at session start.",``,`## Skills-First Rule`,``,`**Before starting ANY task, check available skills.** If a skill matches your task domain`,`— load it first. Skills contain domain-specific patterns, templates, and constraints.`,``,`## Workspace Skill`,``,`This project has an auto-generated workspace skill that tracks conventions, known issues,`,`and workflow tips for this specific codebase. Load it at session start:`,``,` skill_view('<workspace-name>')`,``,`The skill is named after your workspace (the project directory name).`,`It's auto-generated from the knowledge store and updates automatically.`,"If you discover something new about this workspace, store it via `knowledge` tool",`— it will appear in the skill on the next regeneration.`,``,"Use `skill_view(name, file_path)` for deep-dives into specific topics:","- `skill_view(name, 'references/architecture.md')` — deep architecture","- `skill_view(name, 'references/known-issues.md')` — recurring problems","- `skill_view(name, 'references/workflow-tips.md')` — optimization patterns","- `skill_view(name, 'references/flow-<slug>.md')` — active flow briefing",``,`## Available Tools (37)`,``,`AI Kit provides tools across the following categories:`,``,`| Category | Tools |`,`|----------|-------|`,"| **Search & Discovery** | `search`, `find`, `symbol`, `trace`, `scope_map`, `file_summary` |","| **Code Analysis** | `analyze`, `audit`, `graph`, `check` |","| **Context Compression** | `file_summary`, `digest` |","| **Memory & Knowledge** | `knowledge`, `remember`, `read`, `update`, `forget`, `list` |","| **FORGE Quality Gates** | `forge_ground`, `evidence_map` |","| **Development Workflows** | `flow`, `onboard`, `reindex`, `status`, `config` |","| **Testing & Build** | `test_run`, `parse_output`, `check`, `eval` |","| **Code Manipulation** | `rename`, `codemod`, `diff_parse`, `replay` |","| **Git** | `git` |","| **Session** | `session` |","| **Web & HTTP** | `web_search`, `web_fetch` |","| **Present & Visualize** | `present` |","| **Sandbox & Process** | `process`, `queue`, `restore`, `delegate` |","| **Utilities** | `measure`, `env` |","| **Browser** | `browser` |",``,`## Important: Prefer AI Kit Tools Over Generic Shell Commands`,``,`When working in this project, use AI Kit MCP tools instead of generic alternatives:`,``,`| Instead of | Use AI Kit Tool | Why |`,`|-----------|----------------|-----|`,"| `grep` / `rg` | `mcp_aikit_search` or `mcp_aikit_find` | Hybrid search (vector + keyword + BM25) across all indexed content |","| `read_file` for understanding | `mcp_aikit_file_summary` | T1=structure, T2=structure+content — 10x fewer tokens than raw file reads |","| `cd` + `ls` | `mcp_aikit_analyze` | Structural analysis with tree views |","| Running tests in terminal | `mcp_aikit_test_run` | Structured test output — no shell needed |","| `tsc` / `biome` in terminal | `mcp_aikit_check` | Typecheck + lint combined |","| Web search | `mcp_aikit_web_search` | Fans out to multiple keyless providers |",``,`## Agents`,``,t,``,`## Agent Instructions`,``,s.join(`
|
|
2
2
|
`),``,`## Prompts`,``,i,``,b,``,`## Session Protocol`,``,p(n,a.hermes),``]).join(`
|
|
3
3
|
`)}function k(e,t,n){let r=C(t),i=h(t.skills),a=e===`Orchestrator`?b:x,o=[n,...r,t.bodyAddendum,i,a].filter(Boolean).join(`
|
|
4
4
|
|
|
@@ -2,6 +2,16 @@ import{AGENTS as e}from"./agents.mjs";import{postTaskLesson as t,preTaskKnowledg
|
|
|
2
2
|
${t.map((e,t)=>` ${t+1}. ${e}`).join(`
|
|
3
3
|
`)}`}const a={Orchestrator:e=>`You orchestrate full lifecycle: planning -> implementation -> review -> recovery -> commit. Own contract: what, order, owner. No source-code edits; delegate all implementation.
|
|
4
4
|
|
|
5
|
+
## MANDATORY FIRST ACTIONS
|
|
6
|
+
|
|
7
|
+
Execute these MCP calls at session start, before ANY other work:
|
|
8
|
+
|
|
9
|
+
1. \`mcp__aikit__flow({ action: 'status' })\` — Check active flow state.
|
|
10
|
+
2. \`mcp__aikit__status({ includePrelude: true })\` — Load L0 workspace context (compact summary).
|
|
11
|
+
3. If workspaceCore is null → \`mcp__aikit__onboard({ path: "." })\` first, then status again.
|
|
12
|
+
|
|
13
|
+
**Failure to execute these before any other action is a protocol violation.**
|
|
14
|
+
|
|
5
15
|
## Prime Contract
|
|
6
16
|
1. Plan work.
|
|
7
17
|
2. Dispatch specialists.
|
|
@@ -29,7 +39,7 @@ When dispatching subagents, include this line: "Communication style: terse like
|
|
|
29
39
|
1a. For flow dispatch: status({ includePrelude: true }) → if onboard missing or workspace stale, onboard({ path: ".", update: true }) before any subagent dispatch.
|
|
30
40
|
2. Apply layered knowledge protocol (see below).<!-- layered-header -->
|
|
31
41
|
3. search({ query: "SESSION CHECKPOINT", origin: "curated" }) before planning.
|
|
32
|
-
5. Load skills by trigger: aikit always; multi-agents-development before delegation; present before non-tiny output (
|
|
42
|
+
5. Load skills by trigger: aikit always; multi-agents-development before delegation; present before non-tiny output (preferBrowser=true by default; set preferBrowser:false for inline rendering — auto-falls back to browser if client doesn't support inline); brainstorming for design decisions.
|
|
33
43
|
|
|
34
44
|
## Tiered Lifecycle
|
|
35
45
|
Floor: forge_classify -> one specialist -> check({}) + test_run({}) -> present result.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=[`copilot`,`claude`,`copilotCli`,`hermes`],t={SessionStart:{copilot:`SessionStart`,claude:`SessionStart`,copilotCli:`sessionStart`,hermes:`SessionStart`},PreToolUse:{copilot:`PreToolUse`,claude:`PreToolUse`,copilotCli:`preToolUse`,hermes:`PreToolUse`},PostToolUse:{copilot:`PostToolUse`,claude:`PostToolUse`,copilotCli:`postToolUse`,hermes:`PostToolUse`},SubagentStart:{copilot:`SubagentStart`,claude:`SubagentStart`,copilotCli:`subagentStart`,hermes:`SubagentStart`},PreCompact:{copilot:`PreCompact`,claude:`PreCompact`,copilotCli:`preCompact`,hermes:`PreCompact`},Stop:{copilot:`Stop`,claude:`Stop`,copilotCli:`stop`,hermes:`Stop`}},n={fileRead:{copilot:[`read_file`,`readFile`],claude:[`Read`],copilotCli:[`read_file`],hermes:[`read_file`]},fileWrite:{copilot:[`editFiles`,`replace_string_in_file`,`create_file`],claude:[`Edit`,`Write`,`MultiEdit`],copilotCli:[`editFiles`,`replace_string_in_file`],hermes:[`write_file`,`patch`]},fileSearch:{copilot:[`grep_search`,`semantic_search`,`find`],claude:[`Bash`],copilotCli:[`grep_search`],hermes:[`search_files`]}},r={"privacy-guard":{id:`privacy-guard`,event:`PreToolUse`,category:`guard`,description:`Deny reads of secret-bearing files: .env, .pem, .key, .ssh/*, credentials, tokens, .netrc.`,llmBenefit:`Prevents accidental leakage of API keys, tokens, and credentials into conversation context.`,script:`privacy-guard.mjs`,matcher:[`fileRead`],outputBudgetLines:0,executionModel:`child-process`,scope:`user`,failurePolicy:`deny-closed`,supportedPlatforms:[`copilot`,`claude`,`copilotCli`,`hermes`],unsupportedBehavior:`Reject via agent instruction — no native hook runtime available`,evidenceRequirements:`Hook script tested against known secret patterns`,rollbackBehavior:`Remove from settings.json hooks block and delete script file`},"scout-guard":{id:`scout-guard`,event:`PreToolUse`,category:`guard`,description:`Deny reads inside generated/dependency directories: node_modules/, dist/, .git/objects/, vendor/, build/.`,llmBenefit:`Keeps context clean by preventing reads of irrelevant generated or vendored files.`,script:`scout-guard.mjs`,matcher:[`fileRead`,`fileSearch`],outputBudgetLines:0,executionModel:`child-process`,scope:`user`,failurePolicy:`deny-closed`,supportedPlatforms:[`copilot`,`claude`,`copilotCli`,`hermes`],unsupportedBehavior:`Reject via agent instruction — no native hook runtime available`,evidenceRequirements:`Hook script tested against known generated directory patterns`,rollbackBehavior:`Remove from settings.json hooks block and delete script file`},"freshness-signal":{id:`freshness-signal`,event:`SessionStart`,category:`signal`,description:`Check workspace state freshness at session start: onboard staleness, active flow, scaffold drift.`,llmBenefit:`Avoids working with stale onboard data or drifting scaffold state.`,script:`freshness-signal.mjs`,outputBudgetLines:5,executionModel:`child-process`,scope:`user`,silentWhenHealthy:!0,failurePolicy:`allow-open`,matcher:[],supportedPlatforms:[`copilot`,`claude`,`copilotCli`,`hermes`],unsupportedBehavior:`Skip — no native hook runtime on this platform`,evidenceRequirements:`None (signal-only, no enforcement)`,rollbackBehavior:`Remove from settings.json hooks block`},"scope-guard":{id:`scope-guard`,event:`PostToolUse`,category:`signal`,description:`After file writes, detect edit drift: files changed outside flow scope, too many files, scaffold source/dist mismatch.`,llmBenefit:`Prevents accidental scope creep, over-editing, and scaffold drift during a session.`,script:`scope-guard.mjs`,matcher:[`fileWrite`],outputBudgetLines:5,executionModel:`child-process`,scope:`user`,silentWhenHealthy:!0,failurePolicy:`allow-open`,supportedPlatforms:[`copilot`,`claude`,`copilotCli`,`hermes`],unsupportedBehavior:`Skip — no native hook runtime on this platform`,evidenceRequirements:`None (signal-only, no enforcement)`,rollbackBehavior:`Remove from settings.json hooks block`},"session-reminder":{id:`session-reminder`,event:`SessionStart`,category:`signal`,description:`Inject orchestrator skill protocol ("Delegate, never implement") at every session start as additionalContext.`,llmBenefit:`Reinforces the delegation protocol at the start of every Orchestrator session — harder for the model to skip than CLAUDE.md or agent instructions alone.`,script:`session-reminder.mjs`,outputBudgetLines:50,executionModel:`child-process`,scope:`user`,silentWhenHealthy:!1,failurePolicy:`allow-open`,matcher:[],supportedPlatforms:[`claude`],unsupportedBehavior:`Skip — only meaningful on Claude Code with its hooks runtime`,evidenceRequirements:`None (signal-only, no enforcement)`,rollbackBehavior:`Remove from settings.json hooks block and delete script file`}},i=[`id`,`event`,`category`,`script`,`description`],a=[`matcher`,`llmBenefit`,`executionModel`,`scope`,`failurePolicy`,`outputBudgetLines`,`supportedPlatforms`,`unsupportedBehavior`],o=[`evidenceRequirements`,`rollbackBehavior`],s=[`silentWhenHealthy`];function c(){let e=new Set(Object.keys(t)),n=[`child-process`,`eventbus-subscriber`],c=[`deny-closed`,`allow-open`];for(let[t,l]of Object.entries(r)){for(let e of i){if(!(e in l)||l[e]===void 0||l[e]===null)throw Error(`EXEC_HOOKS["${t}"] is missing or null Tier 1 field "${e}". Add it to the "${t}" entry in exec-hooks.mjs.`);if(typeof l[e]==`string`&&l[e].trim()===``)throw Error(`EXEC_HOOKS["${t}"] has empty string for Tier 1 field "${e}". Provide a non-empty value.`)}for(let e of a)(!(e in l)||l[e]===void 0||l[e]===null)&&console.warn(`EXEC_HOOKS["${t}"] is missing Tier 2 field "${e}". Add it when the field values are actionable.`);if(l.category===`guard`)for(let e of o)(!(e in l)||l[e]===void 0||l[e]===null)&&console.warn(`EXEC_HOOKS["${t}"] (guard) is missing guard field "${e}". Add it when guard lifecycle tooling exists.`);if(l.category===`signal`)for(let e of s)(!(e in l)||l[e]===void 0||l[e]===null)&&console.warn(`EXEC_HOOKS["${t}"] (signal) is missing signal field "${e}". Add it when signal lifecycle tooling exists.`);if(l.id!==t)throw Error(`EXEC_HOOKS["${t}"] has id="${l.id}" which doesn't match its object key. Set id to "${t}".`);if(!e.has(l.event))throw Error(`EXEC_HOOKS["${t}"] has unrecognized event "${l.event}". Valid: ${[...e].join(`, `)}.`);if(![`guard`,`signal`].includes(l.category))throw Error(`EXEC_HOOKS["${t}"] has invalid category "${l.category}". Must be "guard" or "signal".`);[`user`,`workspace`].includes(l.scope)||console.warn(`EXEC_HOOKS["${t}"] has invalid scope "${l.scope}". Must be "user" or "workspace".`),l.executionModel&&!n.includes(l.executionModel)&&console.warn(`EXEC_HOOKS["${t}"] has unrecognized executionModel "${l.executionModel}". Valid: ${n.join(`, `)}.`),l.failurePolicy&&!c.includes(l.failurePolicy)&&console.warn(`EXEC_HOOKS["${t}"] has unrecognized failurePolicy "${l.failurePolicy}". Valid: ${c.join(`, `)}.`)}}function l(r){let i=[{name:`HOOK_EVENTS`,entries:Object.values(t)},{name:`HOOK_TOOL_MATCHERS`,entries:Object.values(n)}];for(let t of e){for(let e of i)for(let n of e.entries)if(!(t in n))throw Error(`Registration drift: platform "${t}" is missing from ${e.name} (entry has keys: ${Object.keys(n).join(`, `)}). Add a "${t}" key to all entries in ${e.name} in exec-hooks.mjs.`);if(r){for(let[e,n]of Object.entries(r))if(!(t in n))throw Error(`Registration drift: platform "${t}" is missing from ${e} (has keys: ${Object.keys(n).join(`, `)}). Add "${t}: '...'" to ${e}.`)}}}function u(e){let t=[];if(!e||typeof e!=`object`)return t.push(`Generated hook must be a non-null object`),t;for(let n of[`id`,`event`,`category`,`description`])(!e[n]||typeof e[n]!=`string`)&&t.push(`Generated hook missing or invalid "${n}" (must be a non-empty string)`);e.category&&![`guard`,`signal`].includes(e.category)&&t.push(`Generated hook has invalid category "${e.category}". Must be "guard" or "signal".`);let n=[`candidate`,`evaluated`,`promoted`,`rejected`,`disabled`];return e.promotionState&&!n.includes(e.promotionState)&&t.push(`Generated hook has invalid promotionState "${e.promotionState}". Valid: ${n.join(`, `)}.`),e.confidence!==void 0&&(typeof e.confidence!=`number`||e.confidence<0||e.confidence>1)&&t.push(`Generated hook confidence must be a number between 0 and 1, got "${e.confidence}"`),e.originToolNames!==void 0&&!Array.isArray(e.originToolNames)&&t.push(`Generated hook originToolNames must be an array of strings`),e.promotionState===`promoted`&&!e.createdAt&&t.push(`Generated hook promoted but missing createdAt timestamp`),t}export{r as EXEC_HOOKS,t as HOOK_EVENTS,n as HOOK_TOOL_MATCHERS,e as SUPPORTED_PLATFORMS,l as validateAllPlatformRegistries,u as validateGeneratedHookDef,c as validateHookDefinitions};
|
|
1
|
+
const e=[`copilot`,`claude`,`copilotCli`,`hermes`],t={SessionStart:{copilot:`SessionStart`,claude:`SessionStart`,copilotCli:`sessionStart`,hermes:`SessionStart`},PreToolUse:{copilot:`PreToolUse`,claude:`PreToolUse`,copilotCli:`preToolUse`,hermes:`PreToolUse`},PostToolUse:{copilot:`PostToolUse`,claude:`PostToolUse`,copilotCli:`postToolUse`,hermes:`PostToolUse`},SubagentStart:{copilot:`SubagentStart`,claude:`SubagentStart`,copilotCli:`subagentStart`,hermes:`SubagentStart`},PreCompact:{copilot:`PreCompact`,claude:`PreCompact`,copilotCli:`preCompact`,hermes:`PreCompact`},Stop:{copilot:`Stop`,claude:`Stop`,copilotCli:`stop`,hermes:`Stop`}},n={fileRead:{copilot:[`read_file`,`readFile`],claude:[`Read`],copilotCli:[`read_file`],hermes:[`read_file`]},fileWrite:{copilot:[`editFiles`,`replace_string_in_file`,`create_file`],claude:[`Edit`,`Write`,`MultiEdit`],copilotCli:[`editFiles`,`replace_string_in_file`],hermes:[`write_file`,`patch`]},fileSearch:{copilot:[`grep_search`,`semantic_search`,`find`],claude:[`Bash`],copilotCli:[`grep_search`],hermes:[`search_files`]}},r={"privacy-guard":{id:`privacy-guard`,event:`PreToolUse`,category:`guard`,description:`Deny reads of secret-bearing files: .env, .pem, .key, .ssh/*, credentials, tokens, .netrc.`,llmBenefit:`Prevents accidental leakage of API keys, tokens, and credentials into conversation context.`,script:`privacy-guard.mjs`,matcher:[`fileRead`],outputBudgetLines:0,executionModel:`child-process`,scope:`user`,failurePolicy:`deny-closed`,supportedPlatforms:[`copilot`,`claude`,`copilotCli`,`hermes`],unsupportedBehavior:`Reject via agent instruction — no native hook runtime available`,evidenceRequirements:`Hook script tested against known secret patterns`,rollbackBehavior:`Remove from settings.json hooks block and delete script file`},"scout-guard":{id:`scout-guard`,event:`PreToolUse`,category:`guard`,description:`Deny reads inside generated/dependency directories: node_modules/, dist/, .git/objects/, vendor/, build/.`,llmBenefit:`Keeps context clean by preventing reads of irrelevant generated or vendored files.`,script:`scout-guard.mjs`,matcher:[`fileRead`,`fileSearch`],outputBudgetLines:0,executionModel:`child-process`,scope:`user`,failurePolicy:`deny-closed`,supportedPlatforms:[`copilot`,`claude`,`copilotCli`,`hermes`],unsupportedBehavior:`Reject via agent instruction — no native hook runtime available`,evidenceRequirements:`Hook script tested against known generated directory patterns`,rollbackBehavior:`Remove from settings.json hooks block and delete script file`},"bash-guard":{id:`bash-guard`,event:`PreToolUse`,category:`guard`,description:`Deny grep/find/cat/ls/rg in Bash tool; redirect to MCP search, find, file_summary.`,llmBenefit:`Prevents context waste from raw shell code exploration. Pushes agent toward token-efficient MCP tools.`,script:`bash-guard.mjs`,matcher:[`fileSearch`],outputBudgetLines:0,executionModel:`child-process`,scope:`user`,failurePolicy:`deny-closed`,supportedPlatforms:[`claude`],unsupportedBehavior:`Skip — only meaningful on Claude Code with its Bash tool`,evidenceRequirements:`Hook script tested against grep/find/cat/ls/rg command patterns`,rollbackBehavior:`Remove from settings.json hooks block and delete script file`},"read-size-guard":{id:`read-size-guard`,event:`PreToolUse`,category:`guard`,description:`Deny Read tool on files exceeding 100 lines; redirect to mcp__aikit__file_summary for compressed context.`,llmBenefit:`Prevents wasting context budget on reading large files directly. file_summary provides compressed, structured views.`,script:`read-size-guard.mjs`,matcher:[`fileRead`],outputBudgetLines:0,executionModel:`child-process`,scope:`user`,failurePolicy:`deny-closed`,supportedPlatforms:[`claude`],unsupportedBehavior:`Skip — only meaningful on Claude Code with aikit MCP tools`,evidenceRequirements:`Hook script tested against large-file read patterns`,rollbackBehavior:`Remove from settings.json hooks block and delete script file`},"freshness-signal":{id:`freshness-signal`,event:`SessionStart`,category:`signal`,description:`Check workspace state freshness at session start: onboard staleness, active flow, scaffold drift.`,llmBenefit:`Avoids working with stale onboard data or drifting scaffold state.`,script:`freshness-signal.mjs`,outputBudgetLines:5,executionModel:`child-process`,scope:`user`,silentWhenHealthy:!0,failurePolicy:`allow-open`,matcher:[],supportedPlatforms:[`copilot`,`claude`,`copilotCli`,`hermes`],unsupportedBehavior:`Skip — no native hook runtime on this platform`,evidenceRequirements:`None (signal-only, no enforcement)`,rollbackBehavior:`Remove from settings.json hooks block`},"scope-guard":{id:`scope-guard`,event:`PostToolUse`,category:`signal`,description:`After file writes, detect edit drift: files changed outside flow scope, too many files, scaffold source/dist mismatch.`,llmBenefit:`Prevents accidental scope creep, over-editing, and scaffold drift during a session.`,script:`scope-guard.mjs`,matcher:[`fileWrite`],outputBudgetLines:5,executionModel:`child-process`,scope:`user`,silentWhenHealthy:!0,failurePolicy:`allow-open`,supportedPlatforms:[`copilot`,`claude`,`copilotCli`,`hermes`],unsupportedBehavior:`Skip — no native hook runtime on this platform`,evidenceRequirements:`None (signal-only, no enforcement)`,rollbackBehavior:`Remove from settings.json hooks block`},"session-reminder":{id:`session-reminder`,event:`SessionStart`,category:`signal`,description:`Inject FORBIDDEN tool substitutions, mandatory first actions, orchestrator delegation protocol, and AI Kit tool routing at every session start as additionalContext.`,llmBenefit:`Reinforces tool routing discipline (grep→search, read→file_summary) and session-start protocol (flow status, onboard check) at the start of every session — harder for the model to skip than CLAUDE.md or agent instructions alone.`,script:`session-reminder.mjs`,outputBudgetLines:50,executionModel:`child-process`,scope:`user`,silentWhenHealthy:!1,failurePolicy:`allow-open`,matcher:[],supportedPlatforms:[`claude`],unsupportedBehavior:`Skip — only meaningful on Claude Code with its hooks runtime`,evidenceRequirements:`None (signal-only, no enforcement)`,rollbackBehavior:`Remove from settings.json hooks block and delete script file`}},i=[`id`,`event`,`category`,`script`,`description`],a=[`matcher`,`llmBenefit`,`executionModel`,`scope`,`failurePolicy`,`outputBudgetLines`,`supportedPlatforms`,`unsupportedBehavior`],o=[`evidenceRequirements`,`rollbackBehavior`],s=[`silentWhenHealthy`];function c(){let e=new Set(Object.keys(t)),n=[`child-process`,`eventbus-subscriber`],c=[`deny-closed`,`allow-open`];for(let[t,l]of Object.entries(r)){for(let e of i){if(!(e in l)||l[e]===void 0||l[e]===null)throw Error(`EXEC_HOOKS["${t}"] is missing or null Tier 1 field "${e}". Add it to the "${t}" entry in exec-hooks.mjs.`);if(typeof l[e]==`string`&&l[e].trim()===``)throw Error(`EXEC_HOOKS["${t}"] has empty string for Tier 1 field "${e}". Provide a non-empty value.`)}for(let e of a)(!(e in l)||l[e]===void 0||l[e]===null)&&console.warn(`EXEC_HOOKS["${t}"] is missing Tier 2 field "${e}". Add it when the field values are actionable.`);if(l.category===`guard`)for(let e of o)(!(e in l)||l[e]===void 0||l[e]===null)&&console.warn(`EXEC_HOOKS["${t}"] (guard) is missing guard field "${e}". Add it when guard lifecycle tooling exists.`);if(l.category===`signal`)for(let e of s)(!(e in l)||l[e]===void 0||l[e]===null)&&console.warn(`EXEC_HOOKS["${t}"] (signal) is missing signal field "${e}". Add it when signal lifecycle tooling exists.`);if(l.id!==t)throw Error(`EXEC_HOOKS["${t}"] has id="${l.id}" which doesn't match its object key. Set id to "${t}".`);if(!e.has(l.event))throw Error(`EXEC_HOOKS["${t}"] has unrecognized event "${l.event}". Valid: ${[...e].join(`, `)}.`);if(![`guard`,`signal`].includes(l.category))throw Error(`EXEC_HOOKS["${t}"] has invalid category "${l.category}". Must be "guard" or "signal".`);[`user`,`workspace`].includes(l.scope)||console.warn(`EXEC_HOOKS["${t}"] has invalid scope "${l.scope}". Must be "user" or "workspace".`),l.executionModel&&!n.includes(l.executionModel)&&console.warn(`EXEC_HOOKS["${t}"] has unrecognized executionModel "${l.executionModel}". Valid: ${n.join(`, `)}.`),l.failurePolicy&&!c.includes(l.failurePolicy)&&console.warn(`EXEC_HOOKS["${t}"] has unrecognized failurePolicy "${l.failurePolicy}". Valid: ${c.join(`, `)}.`)}}function l(r){let i=[{name:`HOOK_EVENTS`,entries:Object.values(t)},{name:`HOOK_TOOL_MATCHERS`,entries:Object.values(n)}];for(let t of e){for(let e of i)for(let n of e.entries)if(!(t in n))throw Error(`Registration drift: platform "${t}" is missing from ${e.name} (entry has keys: ${Object.keys(n).join(`, `)}). Add a "${t}" key to all entries in ${e.name} in exec-hooks.mjs.`);if(r){for(let[e,n]of Object.entries(r))if(!(t in n))throw Error(`Registration drift: platform "${t}" is missing from ${e} (has keys: ${Object.keys(n).join(`, `)}). Add "${t}: '...'" to ${e}.`)}}}function u(e){let t=[];if(!e||typeof e!=`object`)return t.push(`Generated hook must be a non-null object`),t;for(let n of[`id`,`event`,`category`,`description`])(!e[n]||typeof e[n]!=`string`)&&t.push(`Generated hook missing or invalid "${n}" (must be a non-empty string)`);e.category&&![`guard`,`signal`].includes(e.category)&&t.push(`Generated hook has invalid category "${e.category}". Must be "guard" or "signal".`);let n=[`candidate`,`evaluated`,`promoted`,`rejected`,`disabled`];return e.promotionState&&!n.includes(e.promotionState)&&t.push(`Generated hook has invalid promotionState "${e.promotionState}". Valid: ${n.join(`, `)}.`),e.confidence!==void 0&&(typeof e.confidence!=`number`||e.confidence<0||e.confidence>1)&&t.push(`Generated hook confidence must be a number between 0 and 1, got "${e.confidence}"`),e.originToolNames!==void 0&&!Array.isArray(e.originToolNames)&&t.push(`Generated hook originToolNames must be an array of strings`),e.promotionState===`promoted`&&!e.createdAt&&t.push(`Generated hook promoted but missing createdAt timestamp`),t}export{r as EXEC_HOOKS,t as HOOK_EVENTS,n as HOOK_TOOL_MATCHERS,e as SUPPORTED_PLATFORMS,l as validateAllPlatformRegistries,u as validateGeneratedHookDef,c as validateHookDefinitions};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const e=`analyze.audit.
|
|
1
|
+
const e=`analyze.audit.browser.check.codemod.config.delegate.digest.env.eval.evidence_map.file_summary.find.flow.forge_ground.git.graph.knowledge.measure.onboard.parse_output.present.process.produce_knowledge.queue.reindex.rename.replay.restore.scope_map.search.session.status.symbol.test_run.trace.web_fetch.web_search`.split(`.`),t={orchestrator:[`memory`,`runCommand`,`switchAgent`,`newWorkspace`,`reviewPlan`,`killTerminal`,`createTask`,`terminal`,`terminalSel`,`lastCommand`,`problems`,`readFile`,`editFiles`,`subagent`,`search`,`web`,`todo`,`searchSubagent`,`textSearch`,`browser`,`askQuestions`,`resolveMemoryFileUri`],researcher:[`terminal`,`problems`,`readFile`,`lastCommand`,`subagent`,`search`,`web`,`browser`],reviewer:[`terminal`,`problems`,`readFile`,`lastCommand`,`subagent`,`search`,`web`,`browser`],codeAgent:[`createTask`,`terminal`,`problems`,`readFile`,`lastCommand`,`subagent`,`createFile`,`editFiles`,`rename`,`createDirectory`,`search`,`todo`,`browser`],debugger:[`terminal`,`problems`,`readFile`,`terminalSel`,`lastCommand`,`subagent`,`createFile`,`editFiles`,`search`,`browser`],refactor:[`terminal`,`problems`,`readFile`,`lastCommand`,`subagent`,`createFile`,`editFiles`,`rename`,`createDirectory`,`search`,`browser`],explorer:[`problems`,`readFile`,`search`,`fileSearch`,`listDir`,`textSearch`,`browser`],planner:[`terminal`,`problems`,`readFile`,`reviewPlan`,`memory`,`askQuestions`,`resolveMemoryFileUri`,`lastCommand`,`subagent`,`createFile`,`editFiles`,`rename`,`createDirectory`,`search`,`web`,`todo`,`searchSubagent`,`browser`],security:[`terminal`,`problems`,`readFile`,`subagent`,`search`,`web`,`browser`],documenter:[`terminal`,`problems`,`readFile`,`lastCommand`,`subagent`,`createFile`,`editFiles`,`rename`,`createDirectory`,`search`,`web`,`browser`]},n={terminal:[`Bash`],problems:[`Read`],readFile:[`Read`],lastCommand:[`Bash`],subagent:[],createFile:[`Write`],editFiles:[`Edit`],rename:[`Write`],createDirectory:[`Write`],search:[`Read`],web:[`WebFetch`,`WebSearch`],todo:[`TodoRead`,`TodoWrite`],memory:[],runCommand:[`Bash`],switchAgent:[],newWorkspace:[`Bash`],reviewPlan:[],killTerminal:[`Bash`],createTask:[`Task`],terminalSel:[`Bash`],fileSearch:[`Read`],listDir:[`Read`],textSearch:[`Read`],searchSubagent:[],browser:[],askQuestions:[],resolveMemoryFileUri:[]};export{e as AIKIT_TOOLS,n as CLAUDE_CODE_TOOL_MAP,t as IDE_CAPABILITIES};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* bash-guard — PreToolUse guard against low-value Bash commands.
|
|
4
|
+
*
|
|
5
|
+
* Detects grep, find, cat, ls, rg patterns in Bash tool invocations
|
|
6
|
+
* and blocks them with a redirect to the appropriate AI Kit MCP tool
|
|
7
|
+
* (search, find, file_summary). All agents now have mcp__aikit__* tools
|
|
8
|
+
* in their tools: frontmatter alongside native tools.
|
|
9
|
+
*
|
|
10
|
+
* Only fires when the command STARTS with one of these patterns —
|
|
11
|
+
* mid-pipe uses (e.g., `git log | grep fix`) are allowed.
|
|
12
|
+
*
|
|
13
|
+
* @category guard
|
|
14
|
+
* @event PreToolUse
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { createHook } from './_runtime.mjs';
|
|
18
|
+
|
|
19
|
+
const BASH_TOOLS = new Set(['Bash', 'bash', 'execute_command', 'terminal']);
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Patterns that map to MCP tools instead of raw shell.
|
|
23
|
+
* Only matches when the command STARTS with the pattern (after optional whitespace).
|
|
24
|
+
*/
|
|
25
|
+
const REDIRECT_PATTERNS = [
|
|
26
|
+
{
|
|
27
|
+
re: /^\s*grep(\s|$)/m,
|
|
28
|
+
tool: 'mcp__aikit__search or mcp__aikit__find',
|
|
29
|
+
reason: 'grep for code search',
|
|
30
|
+
},
|
|
31
|
+
{ re: /^\s*find(\s|$)/m, tool: 'mcp__aikit__find({ glob })', reason: 'find for file search' },
|
|
32
|
+
{ re: /^\s*cat(\s|$)/m, tool: 'mcp__aikit__file_summary', reason: 'cat for reading files' },
|
|
33
|
+
{
|
|
34
|
+
re: /^\s*ls(\s|$)/m,
|
|
35
|
+
tool: 'mcp__aikit__find({ glob }) or mcp__aikit__search',
|
|
36
|
+
reason: 'ls for exploration',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
re: /^\s*rg(\s|$)/m,
|
|
40
|
+
tool: 'mcp__aikit__search or mcp__aikit__find',
|
|
41
|
+
reason: 'rg (ripgrep) for search',
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
re: /^\s*dir(\s|$)/m,
|
|
45
|
+
tool: 'mcp__aikit__find({ glob }) or mcp__aikit__search',
|
|
46
|
+
reason: 'dir for exploration',
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
/** Check if the command starts with a blocked pattern. */
|
|
51
|
+
const handler = async (context) => {
|
|
52
|
+
if (!BASH_TOOLS.has(context.toolName)) return { decision: 'allow' };
|
|
53
|
+
|
|
54
|
+
const command = String(
|
|
55
|
+
context.toolInput?.command ??
|
|
56
|
+
context.toolInput?.cmd ??
|
|
57
|
+
context.toolInput?.input ??
|
|
58
|
+
context.toolInput?.script ??
|
|
59
|
+
'',
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
if (!command.trim()) return { decision: 'allow' };
|
|
63
|
+
|
|
64
|
+
for (const { re, tool, reason } of REDIRECT_PATTERNS) {
|
|
65
|
+
if (re.test(command)) {
|
|
66
|
+
return {
|
|
67
|
+
decision: 'deny',
|
|
68
|
+
reason: `${reason}: use ${tool} instead. Bash is for builds, installs, git, scripts, network, and processes, not codebase exploration.`,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return { decision: 'allow' };
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
createHook(handler, { event: 'PreToolUse', category: 'guard' });
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* read-size-guard — PreToolUse guard against reading large files for understanding.
|
|
4
|
+
*
|
|
5
|
+
* Blocks Read tool on files exceeding MAX_LINES when the purpose appears to be
|
|
6
|
+
* understanding (not editing). Redirects to mcp__aikit__file_summary which
|
|
7
|
+
* provides compressed, relevant context at lower token cost.
|
|
8
|
+
*
|
|
9
|
+
* Editing goes through the Edit/MultiEdit tools, not Read — so this guard
|
|
10
|
+
* only affects context-wasting full-file reads.
|
|
11
|
+
*
|
|
12
|
+
* @category guard
|
|
13
|
+
* @event PreToolUse
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import fs from 'node:fs';
|
|
17
|
+
import { createHook } from './_runtime.mjs';
|
|
18
|
+
|
|
19
|
+
const READ_TOOLS = new Set(['Read', 'read_file', 'readFile']);
|
|
20
|
+
const MAX_LINES = 100;
|
|
21
|
+
|
|
22
|
+
/** Count lines efficiently by reading the first 64KB (covers most files). */
|
|
23
|
+
function countLines(filePath) {
|
|
24
|
+
try {
|
|
25
|
+
const fd = fs.openSync(filePath, 'r');
|
|
26
|
+
try {
|
|
27
|
+
const buf = Buffer.alloc(65536);
|
|
28
|
+
const bytesRead = fs.readSync(fd, buf, 0, buf.length, 0);
|
|
29
|
+
if (bytesRead === 0) return 0;
|
|
30
|
+
const firstChunk = buf.toString('utf-8', 0, bytesRead);
|
|
31
|
+
const lines = firstChunk.split('\n').length;
|
|
32
|
+
// If we read less than the buffer, we have the whole file
|
|
33
|
+
if (bytesRead < buf.length) return lines;
|
|
34
|
+
// File is >64KB — likely over MAX_LINES
|
|
35
|
+
return MAX_LINES + 1;
|
|
36
|
+
} finally {
|
|
37
|
+
fs.closeSync(fd);
|
|
38
|
+
}
|
|
39
|
+
} catch {
|
|
40
|
+
return 0; // Can't read — allow the tool call
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const handler = async (context) => {
|
|
45
|
+
if (!READ_TOOLS.has(context.toolName)) return { decision: 'allow' };
|
|
46
|
+
|
|
47
|
+
for (const filePath of context.filePaths) {
|
|
48
|
+
if (!filePath) continue;
|
|
49
|
+
const lineCount = countLines(filePath);
|
|
50
|
+
if (lineCount > MAX_LINES) {
|
|
51
|
+
return {
|
|
52
|
+
decision: 'deny',
|
|
53
|
+
reason: `File has ~${lineCount}+ lines (max ${MAX_LINES} for Read). Use mcp__aikit__file_summary({ files: ["${filePath.replace(/\\/g, '\\\\')}"], tier: 'T2', query: "<what you need>" }) for compressed context instead. Read is only for small files (< ${MAX_LINES} lines) or exact edit lines.`,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return { decision: 'allow' };
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
createHook(handler, { event: 'PreToolUse', category: 'guard' });
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* session-reminder — SessionStart hook that injects
|
|
4
|
-
* skill
|
|
3
|
+
* session-reminder — SessionStart hook that injects tool routing rules,
|
|
4
|
+
* mandatory first actions, and skill protocols at every session start.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* Falls back to inline essentials if skill file is unavailable.
|
|
6
|
+
* All agents now include mcp__aikit__* tools in their tools: frontmatter
|
|
7
|
+
* alongside native tools (Bash, Edit, Read, Task, etc.).
|
|
9
8
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* Reads ~/.claude/skills/orchestrator/SKILL.md and ~/.claude/skills/aikit/SKILL.md,
|
|
10
|
+
* strips YAML frontmatter, and injects:
|
|
11
|
+
* - FORBIDDEN TOOL SUBSTITUTIONS (grep/find/ls → MCP tools)
|
|
12
|
+
* - MANDATORY FIRST ACTIONS (flow status, status with prelude, onboard)
|
|
13
|
+
* - Orchestrator delegation protocol (from skill file or inline fallback)
|
|
14
|
+
* - AI Kit tool routing essentials (from aikit skill file)
|
|
15
|
+
*
|
|
16
|
+
* Falls back to inline essentials if skill files are unavailable.
|
|
13
17
|
*
|
|
14
18
|
* @category signal
|
|
15
19
|
* @event SessionStart
|
|
@@ -20,25 +24,59 @@ import { homedir } from 'node:os';
|
|
|
20
24
|
import { resolve } from 'node:path';
|
|
21
25
|
import { createHook } from './_runtime.mjs';
|
|
22
26
|
|
|
27
|
+
/**
|
|
28
|
+
* Read a skill SKILL.md file and return its body (YAML frontmatter stripped).
|
|
29
|
+
* Returns null if the file is missing or unreadable.
|
|
30
|
+
*/
|
|
31
|
+
function readSkillBody(skillName) {
|
|
32
|
+
const skillPath = resolve(homedir(), '.claude', 'skills', skillName, 'SKILL.md');
|
|
33
|
+
try {
|
|
34
|
+
const raw = readFileSync(skillPath, 'utf-8');
|
|
35
|
+
const body = raw.replace(/^---[\s\S]*?---\n*/, '').trim();
|
|
36
|
+
return body || null;
|
|
37
|
+
} catch {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
23
42
|
createHook(
|
|
24
43
|
() => {
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
try {
|
|
29
|
-
const raw = readFileSync(skillPath, 'utf-8');
|
|
30
|
-
// Strip YAML frontmatter (everything between first two ---)
|
|
31
|
-
const body = raw.replace(/^---[\s\S]*?---\n*/, '').trim();
|
|
32
|
-
if (body) extracted = body;
|
|
33
|
-
} catch {
|
|
34
|
-
// fallback inline instructions below
|
|
35
|
-
}
|
|
44
|
+
const orchestratorBody = readSkillBody('orchestrator');
|
|
45
|
+
const aikitBody = readSkillBody('aikit');
|
|
36
46
|
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
47
|
+
const parts = [];
|
|
48
|
+
|
|
49
|
+
// ── FORBIDDEN TOOL SUBSTITUTIONS ──
|
|
50
|
+
parts.push(
|
|
51
|
+
'── FORBIDDEN TOOL SUBSTITUTIONS (enforced) ──',
|
|
52
|
+
'These shell commands waste context on codebase exploration. Use MCP tools instead:',
|
|
53
|
+
'',
|
|
54
|
+
'| Shell pattern | Use MCP tool instead |',
|
|
55
|
+
'|---|---|',
|
|
56
|
+
'| grep, find, rg | mcp__aikit__search or mcp__aikit__find |',
|
|
57
|
+
'| cat (large files) | mcp__aikit__file_summary |',
|
|
58
|
+
'| ls (code exploration) | mcp__aikit__find({ glob }) or mcp__aikit__search |',
|
|
59
|
+
'| tsc, biome CLI | mcp__aikit__check |',
|
|
60
|
+
'| npx vitest | mcp__aikit__test_run |',
|
|
61
|
+
'| read_file (understanding) | mcp__aikit__file_summary({ tier: T2, query }) |',
|
|
62
|
+
'',
|
|
63
|
+
'read_file is ONLY for exact edit lines after compressed tools identify the target.',
|
|
64
|
+
'',
|
|
65
|
+
'── MANDATORY FIRST ACTIONS (session start) ──',
|
|
66
|
+
'Execute these MCP calls before ANY other work:',
|
|
67
|
+
"1. mcp__aikit__flow({ action: 'status' }) — check active flow state",
|
|
68
|
+
'2. mcp__aikit__status({ includePrelude: true }) — load L0 workspace context',
|
|
69
|
+
'3. If workspaceCore is null → mcp__aikit__onboard({ path: "." }) first, then status again',
|
|
70
|
+
'',
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
// ── Delegation Protocol ──
|
|
74
|
+
if (orchestratorBody) {
|
|
75
|
+
parts.push('── Delegation Protocol ──');
|
|
76
|
+
parts.push(orchestratorBody);
|
|
77
|
+
} else {
|
|
78
|
+
parts.push(
|
|
79
|
+
'── Delegation Protocol (fallback) ──',
|
|
42
80
|
'YOU MUST FOLLOW THIS PROTOCOL ON EVERY TASK. You are an orchestrator, not an implementer.',
|
|
43
81
|
'',
|
|
44
82
|
'**RULE 1 — Decompose everything.** Every task gets a TODO list in your first response. Break it into independent, parallelizable subtasks.',
|
|
@@ -55,9 +93,53 @@ createHook(
|
|
|
55
93
|
'',
|
|
56
94
|
'**Exceptions (ONLY these):** ≤5 lines trivial, fixing sub-agent output, no sub-agent available.',
|
|
57
95
|
'When in doubt, delegate. When unsure, spawn an extra sub-agent.',
|
|
58
|
-
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// ── AI Kit Tool Routing ──
|
|
100
|
+
if (aikitBody) {
|
|
101
|
+
// Extract key sections: Session Loop, Retrieval Ladder, Context Reuse
|
|
102
|
+
const sections = aikitBody.split('\n## ');
|
|
103
|
+
const keySections = [
|
|
104
|
+
'Session Loop',
|
|
105
|
+
'Retrieval Ladder',
|
|
106
|
+
'Context Reuse',
|
|
107
|
+
'Patterns',
|
|
108
|
+
'Memory Discipline',
|
|
109
|
+
];
|
|
110
|
+
const extracted = sections.filter((s) => {
|
|
111
|
+
const header = s
|
|
112
|
+
.split('\n')[0]
|
|
113
|
+
.trim()
|
|
114
|
+
.replace(/^#+\s*/, '');
|
|
115
|
+
return keySections.some((k) => header.startsWith(k));
|
|
116
|
+
});
|
|
117
|
+
if (extracted.length > 0) {
|
|
118
|
+
parts.push('── AI Kit Tool Routing ──');
|
|
119
|
+
parts.push(extracted.join('\n\n'));
|
|
120
|
+
}
|
|
121
|
+
} else {
|
|
122
|
+
parts.push(
|
|
123
|
+
'── AI Kit Tool Routing (fallback) ──',
|
|
124
|
+
'',
|
|
125
|
+
'| Need | Use |',
|
|
126
|
+
'|---|---|',
|
|
127
|
+
'| L0 workspace context | status({ includePrelude: true }) |',
|
|
128
|
+
'| Search code | search({ query }) |',
|
|
129
|
+
'| Find files | find({ glob }) |',
|
|
130
|
+
'| File summary / exploration | file_summary({ files, tier: T2 }) |',
|
|
131
|
+
'| Symbol definition | symbol({ name }) |',
|
|
132
|
+
'| Type/lint check | check({}) |',
|
|
133
|
+
'| Run tests | test_run({}) |',
|
|
134
|
+
'| Call/data flow | trace({ start, direction }) |',
|
|
135
|
+
'| Impact analysis | blast_radius({ files }) |',
|
|
136
|
+
'| Module graph | graph({ action: neighbors, node_id }) |',
|
|
137
|
+
'',
|
|
138
|
+
'Prefer compressed MCP tools over raw read_file. read_file is only for editing.',
|
|
139
|
+
);
|
|
140
|
+
}
|
|
59
141
|
|
|
60
|
-
return { additionalContext:
|
|
142
|
+
return { additionalContext: parts.join('\n') };
|
|
61
143
|
},
|
|
62
144
|
{ event: 'SessionStart' },
|
|
63
145
|
);
|