trybeacon 0.1.62 → 0.1.64
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/.claude-plugin/plugin.json +19 -0
- package/.next/BUILD_ID +1 -1
- package/.next/app-path-routes-manifest.json +11 -11
- package/.next/build-manifest.json +2 -2
- package/.next/prerender-manifest.json +3 -3
- package/.next/required-server-files.js +1 -1
- package/.next/required-server-files.json +1 -1
- package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +2 -2
- package/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/api/share/create/route.js +1 -1
- package/.next/server/app/api/share/route.js +1 -1
- package/.next/server/app/docs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/docs.html +1 -1
- package/.next/server/app/docs.rsc +3 -3
- package/.next/server/app/docs.segments/_full.segment.rsc +3 -3
- package/.next/server/app/docs.segments/_head.segment.rsc +1 -1
- package/.next/server/app/docs.segments/_index.segment.rsc +2 -2
- package/.next/server/app/docs.segments/_tree.segment.rsc +3 -3
- package/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/docs.segments/docs.segment.rsc +1 -1
- package/.next/server/app/feedback/page_client-reference-manifest.js +1 -1
- package/.next/server/app/feedback.html +1 -1
- package/.next/server/app/feedback.rsc +2 -2
- package/.next/server/app/feedback.segments/_full.segment.rsc +2 -2
- package/.next/server/app/feedback.segments/_head.segment.rsc +1 -1
- package/.next/server/app/feedback.segments/_index.segment.rsc +2 -2
- package/.next/server/app/feedback.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/feedback.segments/feedback/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/feedback.segments/feedback.segment.rsc +1 -1
- package/.next/server/app/help/page_client-reference-manifest.js +1 -1
- package/.next/server/app/help.html +1 -1
- package/.next/server/app/help.rsc +2 -2
- package/.next/server/app/help.segments/_full.segment.rsc +2 -2
- package/.next/server/app/help.segments/_head.segment.rsc +1 -1
- package/.next/server/app/help.segments/_index.segment.rsc +2 -2
- package/.next/server/app/help.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/help.segments/help/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/help.segments/help.segment.rsc +1 -1
- package/.next/server/app/index.html +1 -1
- package/.next/server/app/index.rsc +4 -4
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +3 -3
- package/.next/server/app/index.segments/_full.segment.rsc +4 -4
- package/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/.next/server/app/index.segments/_index.segment.rsc +2 -2
- package/.next/server/app/index.segments/_tree.segment.rsc +3 -3
- package/.next/server/app/map/page.js +1 -1
- package/.next/server/app/map/page.js.nft.json +1 -1
- package/.next/server/app/map/page_client-reference-manifest.js +1 -1
- package/.next/server/app/page.js +2 -2
- package/.next/server/app/page.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/plan/page.js +2 -2
- package/.next/server/app/plan/page.js.nft.json +1 -1
- package/.next/server/app/plan/page_client-reference-manifest.js +1 -1
- package/.next/server/app/s/[token]/page.js +1 -1
- package/.next/server/app/s/[token]/page.js.nft.json +1 -1
- package/.next/server/app/s/[token]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/page.js +1 -1
- package/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +11 -11
- package/.next/server/chunks/2994.js +2 -0
- package/.next/server/chunks/3284.js +154 -0
- package/.next/server/chunks/4384.js +1 -0
- package/.next/server/chunks/5719.js +1 -0
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/{2980-07afca8f83adfcea.js → 3415-05007c2bd98125c7.js} +1 -1
- package/.next/static/chunks/{3021-ed52ee7b3f02e2cd.js → 5957-83f611fcd5a08b45.js} +1 -1
- package/.next/static/chunks/766-242213d211df0afd.js +1 -0
- package/.next/static/chunks/{5847-9e0d59eaaa2ed4e0.js → 8915-fa61a860c63a7c85.js} +3 -3
- package/.next/static/chunks/app/map/{page-756355c41278dd07.js → page-491d4767dbc4e954.js} +1 -1
- package/.next/static/chunks/app/page-d08947a671077569.js +1 -0
- package/.next/static/chunks/app/plan/{page-71925c6a12eb1180.js → page-a90e0981499546e3.js} +1 -1
- package/.next/static/chunks/app/s/[token]/{page-6d7e15718d081a4a.js → page-5c8f260e75758b02.js} +1 -1
- package/.next/static/chunks/app/settings/page-7e176d120b1effa9.js +1 -0
- package/.next/static/css/490566ec68a48e1a.css +1 -0
- package/.next/static/css/53e84df868515cf7.css +1 -0
- package/.next/trace +42 -42
- package/.next/trace-build +1 -1
- package/LICENSE +201 -0
- package/README.md +39 -8
- package/bun.lock +2274 -0
- package/dist/bin/beacon.js +14 -13
- package/dist/bin/boot.js +4 -0
- package/dist/bin/doctor.js +38 -30
- package/dist/bin/hook.js +34 -26
- package/dist/bin/mcp.js +40 -32
- package/dist/bin/plan.js +35 -27
- package/dist/bin/uninstall.js +37 -29
- package/dist/lib/assets.js +10 -2
- package/dist/lib/codex-install.js +35 -27
- package/dist/lib/global-install.js +34 -26
- package/package.json +16 -3
- package/plugin/commands/beacon.md +11 -0
- package/plugin/hooks.json +70 -0
- package/plugin/mcp.json +10 -0
- package/plugin/skills/beacon-init/SKILL.md +47 -0
- package/plugin/skills/beacon-plan/SKILL.md +48 -0
- package/plugin/skills/beacon-refresh/SKILL.md +47 -0
- package/.next/server/chunks/1988.js +0 -154
- package/.next/server/chunks/6192.js +0 -1
- package/.next/server/chunks/8035.js +0 -1
- package/.next/server/chunks/8846.js +0 -2
- package/.next/static/chunks/6638-4e53879181b1df75.js +0 -1
- package/.next/static/chunks/app/page-a229992616b3a3de.js +0 -1
- package/.next/static/chunks/app/settings/page-323bfcf32d1e7fc8.js +0 -1
- package/.next/static/css/5a3abd6d2c9dd5a8.css +0 -1
- package/.next/static/css/e63457bec0b3ee27.css +0 -1
- /package/.next/static/{dFKft-kT3vVI6erpmcYuN → qoq7TibU72duRZATxeVnT}/_buildManifest.js +0 -0
- /package/.next/static/{dFKft-kT3vVI6erpmcYuN → qoq7TibU72duRZATxeVnT}/_ssgManifest.js +0 -0
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var
|
|
2
|
+
var uq=Object.defineProperty;var wq=(q)=>q;function bq(q,z){this[q]=wq.bind(null,z)}var d=(q,z)=>{for(var J in z)uq(q,J,{get:z[J],enumerable:!0,configurable:!0,set:bq.bind(z,J)})};var x=(q,z)=>()=>(q&&(z=q(q=0)),z);var dq=1500,cq=480000,tq=1800000,g=3600000,nq=3000;var c=()=>{};var r={};d(r,{removeRepoAssets:()=>Iq,installRefreshSkill:()=>gq,installPlanSkill:()=>Kq,installInitSkill:()=>jq,installCodexRepoSkills:()=>Nq,ensureWorkflowDoc:()=>Mq,ensureMcp:()=>Rq,auditRepo:()=>fq,REFRESH_SKILL:()=>O,PLAN_SKILL:()=>n,INIT_SKILL:()=>L});import{existsSync as X,mkdirSync as C,readFileSync as B,rmSync as K,writeFileSync as W}from"fs";import{join as $}from"path";function jq(q){let z=$(q,".claude","skills","beacon-init");C(z,{recursive:!0});let J=$(z,"SKILL.md");return W(J,L),J}function gq(q){let z=$(q,".claude","skills","beacon-refresh");C(z,{recursive:!0});let J=$(z,"SKILL.md");return W(J,O),J}function Kq(q){let z=$(q,".claude","skills","beacon-plan");C(z,{recursive:!0});let J=$(z,"SKILL.md");return W(J,n),J}function Nq(q){let z=[];for(let J of Cq){let Q=$(q,".agents","skills",J.name);C(Q,{recursive:!0});let V=$(Q,"SKILL.md");W(V,J.body()),z.push(V)}return z}function Mq(q){let z=$(q,"AGENTS.md"),J="";try{J=B(z,"utf8")}catch{}let Q=new RegExp(`${N}[\\s\\S]*?${y}`);J=Q.test(J)?J.replace(Q,t):`${J.trim()}
|
|
3
3
|
|
|
4
|
-
${
|
|
4
|
+
${t}
|
|
5
5
|
`.trimStart(),W(z,J.endsWith(`
|
|
6
6
|
`)?J:`${J}
|
|
7
|
-
`);let V=$(q,"CLAUDE.md"),Y="";try{Y=
|
|
7
|
+
`);let V=$(q,"CLAUDE.md"),Y="";try{Y=B(V,"utf8")}catch{}if(!/@AGENTS\.md/.test(Y))W(V,`${Y?`${Y.trim()}
|
|
8
8
|
|
|
9
9
|
`:""}@AGENTS.md
|
|
10
|
-
`)}function
|
|
11
|
-
`),{path:z,added:!1,updated:!0};return{path:z,added:!1,updated:!1}}return J.mcpServers.beacon={command:"beacon",args:["mcp"],timeout:
|
|
12
|
-
`),{path:z,added:!0,updated:!1}}function
|
|
13
|
-
`)}}catch{}let V=!1,Y=$(q,"AGENTS.md");try{let Z=
|
|
10
|
+
`)}function Rq(q){let z=$(q,".mcp.json"),J={};try{J=JSON.parse(B(z,"utf8"))}catch{}J.mcpServers=J.mcpServers??{};let Q=J.mcpServers.beacon;if(Q){if(!Q.timeout||Q.timeout<g)return Q.timeout=g,W(z,JSON.stringify(J,null,2)+`
|
|
11
|
+
`),{path:z,added:!1,updated:!0};return{path:z,added:!1,updated:!1}}return J.mcpServers.beacon={command:"beacon",args:["mcp"],timeout:g},W(z,JSON.stringify(J,null,2)+`
|
|
12
|
+
`),{path:z,added:!0,updated:!1}}function fq(q){let z=$(q,".mcp.json"),J=!1;try{J=!!JSON.parse(B(z,"utf8")).mcpServers?.beacon}catch{}let Q=!1;try{Q=B($(q,"AGENTS.md"),"utf8").includes(N)}catch{}let V=!1;try{V=/@AGENTS\.md/.test(B($(q,"CLAUDE.md"),"utf8"))}catch{}return{repo:q,mcpRegistered:J,agentsMdBlock:Q,claudeMdImport:V,skills:{"beacon-init":X($(q,".claude","skills","beacon-init","SKILL.md")),"beacon-refresh":X($(q,".claude","skills","beacon-refresh","SKILL.md"))},codexSkills:{"beacon-init":X($(q,".agents","skills","beacon-init","SKILL.md")),"beacon-refresh":X($(q,".agents","skills","beacon-refresh","SKILL.md"))}}}function Iq(q){let z=[];for(let Z of["beacon-init","beacon-refresh","beacon-db-design"]){let P=$(q,".claude","skills",Z);if(X(P))K(P,{recursive:!0,force:!0}),z.push(Z)}for(let Z of["beacon-init","beacon-refresh"]){let P=$(q,".agents","skills",Z);if(X(P))K(P,{recursive:!0,force:!0}),z.push(`codex:${Z}`)}let J=!1,Q=$(q,".mcp.json");try{let Z=JSON.parse(B(Q,"utf8"));if(Z.mcpServers?.beacon){if(delete Z.mcpServers.beacon,J=!0,Z.mcpServers&&Object.keys(Z.mcpServers).length===0)delete Z.mcpServers;if(Object.keys(Z).length===0)K(Q,{force:!0});else W(Q,JSON.stringify(Z,null,2)+`
|
|
13
|
+
`)}}catch{}let V=!1,Y=$(q,"AGENTS.md");try{let Z=B(Y,"utf8"),P=new RegExp(`\\n?${N}[\\s\\S]*?${y}\\n?`);if(P.test(Z)){let E=Z.replace(P,`
|
|
14
14
|
`).replace(/\n{3,}/g,`
|
|
15
15
|
|
|
16
|
-
`).trimStart();W(Y,
|
|
17
|
-
`)?
|
|
18
|
-
`),V=!0}}catch{}let U=!1,
|
|
16
|
+
`).trimStart();W(Y,E.endsWith(`
|
|
17
|
+
`)?E:`${E}
|
|
18
|
+
`),V=!0}}catch{}let U=!1,H=$(q,"CLAUDE.md");try{let Z=B(H,"utf8"),P=Z.replace(/^[ \t]*@AGENTS\.md[ \t]*\n?/m,"");if(P!==Z){if(!P.trim())K(H,{force:!0});else W(H,P);U=!0}}catch{}return{skillsRemoved:z,mcpUnregistered:J,agentsBlockRemoved:V,claudeImportRemoved:U}}var L=`---
|
|
19
19
|
name: beacon-init
|
|
20
20
|
description: Read this repository and map its architecture, schema, and roadmap into Beacon (the local visual planning panel). Use when the user runs /beacon-init, asks to "set up Beacon for this repo", or asks to initialize/bootstrap Beacon's map of this codebase.
|
|
21
21
|
---
|
|
@@ -51,10 +51,18 @@ A single \`beacon_init_persist\` MCP tool call with:
|
|
|
51
51
|
- Don't fabricate tables/endpoints. If you can't find the schema source, omit \`snapshot\`.
|
|
52
52
|
- Don't ask the user to confirm before persisting. The user invoked /beacon-init \u2014 that's the confirmation.
|
|
53
53
|
|
|
54
|
-
If \`beacon_init_persist\`
|
|
54
|
+
## If \`beacon_init_persist\` is NOT in your tools (or the call can't reach the daemon)
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
|
|
56
|
+
That happens when this repo was never opened with \`beacon\`: there's no \`.mcp.json\`, so the Beacon MCP server isn't in this session \u2014 and MCP tools can't be added mid-session. (It also covers a wired repo whose daemon is down, so the tool call errors.) **Do NOT stop and tell the user to run \`beacon\` first.** /beacon-init bootstraps itself: write the EXACT analysis object you'd have passed to \`beacon_init_persist\` to a temp JSON file, then persist it through the CLI:
|
|
57
|
+
|
|
58
|
+
\`\`\`bash
|
|
59
|
+
beacon init-persist /tmp/beacon-init.json # or: beacon init-persist < /tmp/beacon-init.json
|
|
60
|
+
\`\`\`
|
|
61
|
+
|
|
62
|
+
That one command wires the repo (writes \`.mcp.json\` + skills so your NEXT session gets the \`beacon_*\` tools natively, heals the global install), starts the Beacon daemon if it isn't running, registers + provisions this workspace, and POSTs your analysis to the same \`/api/init\` endpoint the MCP tool uses \u2014 so init completes in THIS session. Read the counts it prints and report them.
|
|
63
|
+
|
|
64
|
+
After the tool (or \`beacon init-persist\`) returns, tell the user the counts (components / roadmap / tables / endpoints) and point them at the running Beacon panel.
|
|
65
|
+
`,O=`---
|
|
58
66
|
name: beacon-refresh
|
|
59
67
|
description: Re-survey the repo and update Beacon's architecture / schema / endpoints map after /beacon-init was already run \u2014 picks up new components, removed ones, schema changes, and new routes. Use when the user runs /beacon-refresh or asks to "refresh", "update", "re-sync", or "bring Beacon up to date" with the current code.
|
|
60
68
|
---
|
|
@@ -101,7 +109,7 @@ The one caveat: if the user manually edited an INIT-source node on the canvas (e
|
|
|
101
109
|
If \`beacon_entities\` or \`beacon_init_persist\` isn't available, the Beacon panel isn't running in this repo. Tell the user to run \`beacon\` here first, then re-invoke /beacon-refresh.
|
|
102
110
|
|
|
103
111
|
After the tool returns, report the final counts plus a one-line summary of the diff you surfaced.
|
|
104
|
-
`,
|
|
112
|
+
`,n=`---
|
|
105
113
|
name: beacon-plan
|
|
106
114
|
description: Present your current plan or approach to the user on Beacon's /plan canvas for review \u2014 instead of asking for approval in prose. Use when the user says "present the plan", "show me the plan", "let me see it / the plan", or whenever you are about to end a turn asking whether to proceed with a plan, design, or approach.
|
|
107
115
|
---
|
|
@@ -149,7 +157,7 @@ If it returns feedback, revise and call it again.
|
|
|
149
157
|
If \`beacon_present_plan\` isn't available, the panel isn't wired here \u2014 fall back to ExitPlanMode
|
|
150
158
|
with the same \`\`\`beacon block (Claude Code only; Codex has no ExitPlanMode), or tell the user to
|
|
151
159
|
run \`beacon\` in this repo once.
|
|
152
|
-
`,Cq,
|
|
160
|
+
`,Cq,N="<!-- beacon:workflow:start -->",y="<!-- beacon:workflow:end -->",t;var o=x(()=>{c();Cq=[{name:"beacon-init",body:()=>L},{name:"beacon-refresh",body:()=>O}];t=`${N}
|
|
153
161
|
## Beacon \u2014 feature workflow
|
|
154
162
|
|
|
155
163
|
This project uses Beacon (a local planning/visualization panel; run \`beacon\` to open it). When you start work on a FEATURE \u2014 whether referenced via an \`@beacon:feature://\u2026\` mention, an \`@beacon:note://\u2026\` note the user wrote in the Notes panel (treat its checkbox \`- [ ]\` todos as subtasks and order features by their dependencies), or just described in chat \u2014 follow these steps in order:
|
|
@@ -217,18 +225,18 @@ Register them all in that single batched call. If a plan added five features, th
|
|
|
217
225
|
If the feature added or materially changed a REAL architectural component (a subsystem \u2014 NOT a file), also pass \`architecture: [{ title, domain, role, \u2026 }]\` so the Architecture map stays accurate. It upserts curated components by title; never list files as components. If you found a bug or something worth investigating in a component's code, add \`bugs: [{ note }]\` to its architecture entry \u2014 it renders as a bug flag on the node (attributed to the agent); identical open flags are not duplicated. Only flag what you actually saw in the code.
|
|
218
226
|
|
|
219
227
|
Pull raw planning data anytime with \`beacon_entities\` (features / architecture / tables / endpoints).
|
|
220
|
-
${y}`});import{existsSync as
|
|
221
|
-
`)}function zq(q,z){let J=
|
|
228
|
+
${y}`});import{existsSync as M,mkdirSync as h,readdirSync as Aq,readFileSync as u,rmSync as Dq,writeFileSync as R}from"fs";import{dirname as i,join as v}from"path";function Jz(){return!!process.env.CLAUDE_PLUGIN_ROOT}function Tq(q=process.env.HOME||process.env.USERPROFILE||""){if(!q)return null;let z=v(q,".claude","plugins");if(!M(z))return null;let J=[z];for(let Q=0;Q<3&&J.length;Q++){let V=[];for(let Y of J){let U=v(Y,".claude-plugin","plugin.json");try{if(M(U)&&JSON.parse(u(U,"utf8")).name==="beacon")return Y}catch{}try{for(let H of Aq(Y,{withFileTypes:!0}))if(H.isDirectory())V.push(v(Y,H.name))}catch{}}J=V}return null}function Qz(q){return Tq(q)!==null}function _(q){try{return JSON.parse(u(q,"utf8"))}catch{return{}}}function qq(q,z){h(i(q),{recursive:!0}),R(q,JSON.stringify(z,null,2)+`
|
|
229
|
+
`)}function zq(q,z){let J=_(q);J.hooks=J.hooks??{},J.hooks[z.event]=J.hooks[z.event]??[];let Q=J.hooks[z.event];if(Q.some((Y)=>Y.matcher===z.matcher&&Y.hooks?.some((U)=>U.command===z.command)))return!1;return Q.push({matcher:z.matcher,hooks:[{type:"command",command:z.command}]}),qq(q,J),!0}function Jq(q,z){return(_(q).hooks?.[z.event]??[]).some((V)=>V.hooks?.some((Y)=>Y.command===z.command))}function Qq(q,z){let J=_(q),Q=J.hooks?.[z.event];if(!Q)return!1;let V=!1,Y=Q.map((U)=>{let H=U.hooks?.length??0,Z=(U.hooks??[]).filter((P)=>P.command!==z.command);if(Z.length!==H)V=!0;return{...U,hooks:Z}}).filter((U)=>(U.hooks??[]).length>0);if(!V)return!1;if(Y.length)J.hooks[z.event]=Y;else delete J.hooks[z.event];if(J.hooks&&Object.keys(J.hooks).length===0)delete J.hooks;return qq(q,J),!0}function Vq(q,z,J,Q){let V=`${z}
|
|
222
230
|
${Q.trim()}
|
|
223
|
-
${J}`,Y="";try{Y=
|
|
231
|
+
${J}`,Y="";try{Y=u(q,"utf8")}catch{}let U=new RegExp(`${z}[\\s\\S]*?${J}`);Y=U.test(Y)?Y.replace(U,V):Y.trim()?`${Y.trim()}
|
|
224
232
|
|
|
225
233
|
${V}
|
|
226
234
|
`:`${V}
|
|
227
|
-
`,
|
|
235
|
+
`,h(i(q),{recursive:!0}),R(q,Y.endsWith(`
|
|
228
236
|
`)?Y:`${Y}
|
|
229
|
-
`)}function
|
|
237
|
+
`)}function m(q,z){try{return u(q,"utf8").includes(z)}catch{return!1}}function Yq(q,z,J){let Q="";try{Q=u(q,"utf8")}catch{return!1}let V=new RegExp(`${z}[\\s\\S]*?${J}\\n?`);if(!V.test(Q))return!1;let Y=Q.replace(V,"").replace(/\n{3,}/g,`
|
|
230
238
|
|
|
231
|
-
`).trimStart();return
|
|
239
|
+
`).trimStart();return R(q,Y),!0}function Zq(q,z,J){let Q=v(q,z);h(Q,{recursive:!0});let V=v(Q,"SKILL.md");return R(V,J),V}function S(q,z){return M(v(q,z,"SKILL.md"))}function $q(q,z){let J=v(q,z);if(!M(J))return!1;return Dq(J,{recursive:!0,force:!0}),!0}var f,e=`## Beacon (visual planning panel)
|
|
232
240
|
|
|
233
241
|
This machine has Beacon installed \u2014 a local visual planning surface for the terminal-side
|
|
234
242
|
agent. Beacon proposes feature plans (roadmap features + DB schema + endpoints) via MCP,
|
|
@@ -249,17 +257,17 @@ the user reviews on a canvas at /plan, and feedback flows back as the next round
|
|
|
249
257
|
Feedback bundles inline annotations on the markdown PLUS any edits the user made directly
|
|
250
258
|
on the /map and /db boards (added features, attached subtasks, edited columns, new
|
|
251
259
|
endpoints). Treat board edits as the user's revision intent \u2014 re-propose matching them
|
|
252
|
-
verbatim. Do NOT implement until the tool returns approval.`;var Uq=
|
|
260
|
+
verbatim. Do NOT implement until the tool returns approval.`;var Uq=x(()=>{f=["beacon-init","beacon-refresh","beacon-plan"]});import{mkdirSync as kq,renameSync as Fq,rmSync as Eq,writeFileSync as Lq}from"fs";import{dirname as Oq}from"path";function I(q,z){kq(Oq(q),{recursive:!0});let J=`${q}.tmp`;try{Lq(J,z),Fq(J,q)}catch(Q){throw Eq(J,{force:!0}),Q}}function $z(q,z,J=!1){I(q,JSON.stringify(z,null,J?2:void 0))}var Pq=()=>{};var aq={};d(aq,{setupCodexAssets:()=>mq,removeCodexMcp:()=>xq,removeCodexArtifacts:()=>pq,hasCodexMcp:()=>s,ensureCodexMcp:()=>Gq,codexMcpProblem:()=>_q,codexDetected:()=>Bq,auditCodex:()=>Sq,CODEX_HOOKS:()=>F});import{readFileSync as k}from"fs";import{homedir as yq}from"os";import{join as j}from"path";function Wq(){return process.env.HOME||process.env.USERPROFILE||yq()}function Bq(){if(process.env.BEACON_CODEX==="1")return!0;if(process.env.BEACON_CODEX==="0")return!1;if(p===void 0)p=Bun.which("codex")!==null;return p}function b(q){try{return Bun.TOML.parse(q)}catch{return null}}function s(){try{return Boolean(b(k(G(),"utf8"))?.mcp_servers?.beacon)}catch{return!1}}function _q(){let q="";try{q=k(G(),"utf8")}catch{return null}let z=b(q);if(!z)return`~/.codex/config.toml does not parse \u2014 ${w}`;if(z.mcp_servers?.beacon)return null;if(/^\s*mcp_servers\s*=/m.test(q))return`mcp_servers is an inline table \u2014 ${w}`;return null}function Gq(){let q="",z=!1;try{q=k(G(),"utf8"),z=!0}catch{}if(z){let Y=b(q);if(!Y)return{added:!1,error:`~/.codex/config.toml does not parse \u2014 ${w}`};if(Y.mcp_servers?.beacon)return{added:!1};if(/^\s*mcp_servers\s*=/m.test(q))return{added:!1,error:`mcp_servers is an inline table \u2014 ${w}`}}let J=!q?"":q.endsWith(`
|
|
253
261
|
`)?`
|
|
254
262
|
`:`
|
|
255
263
|
|
|
256
|
-
`,Q=q+J+
|
|
257
|
-
`),J=z.indexOf(vq);if(J===-1)return{removed:!1,skipped:
|
|
264
|
+
`,Q=q+J+hq;if(b(Q)?.mcp_servers?.beacon?.command!=="beacon")return{added:!1,error:`could not safely append [mcp_servers.beacon] \u2014 ${w}`};return I(G(),Q),{added:!0}}function xq(){let q="";try{q=k(G(),"utf8")}catch{return{removed:!1}}let z=q.split(`
|
|
265
|
+
`),J=z.indexOf(vq);if(J===-1)return{removed:!1,skipped:s()};let Q=z.indexOf(Xq,J);if(Q===-1)return{removed:!1,skipped:!0};z.splice(J,Q-J+1);let V=z.join(`
|
|
258
266
|
`).replace(/\n{3,}/g,`
|
|
259
267
|
|
|
260
|
-
`).replace(/^\n+/,"");if(b(V)===null)return{removed:!1,skipped:!0};return
|
|
268
|
+
`).replace(/^\n+/,"");if(b(V)===null)return{removed:!1,skipped:!0};return I(G(),V),{removed:!0}}async function mq(){let{INIT_SKILL:q,REFRESH_SKILL:z,PLAN_SKILL:J}=await Promise.resolve().then(() => (o(),r)),Q={"beacon-init":q,"beacon-refresh":z,"beacon-plan":J},V=[];for(let Z of f){if(!S(D(),Z))V.push(Z);Zq(D(),Z,Q[Z])}let Y=0;for(let Z of F)if(zq(l(),{event:Z.event,matcher:Z.matcher,command:Z.command}))Y++;let U=m(A(),T);Vq(A(),T,Hq,e);let H=Gq();return{skillsAdded:V,hooksAdded:Y,agentsMdBlockTouched:!U,mcp:H}}function Sq(){let q={};for(let J of f)q[J]=S(D(),J);let z={};for(let J of F)z[J.event]=Jq(l(),{event:J.event,command:J.command});return{detected:Bq(),skills:q,hooks:z,agentsMdBlock:m(A(),T),mcp:s()}}function pq(){let q=[];for(let V of f)if($q(D(),V))q.push(V);let z=0;for(let V of F)if(Qq(l(),{event:V.event,command:V.command}))z++;let J=Yq(A(),T,Hq),Q=xq();return{skillsRemoved:q,hooksRemoved:z,agentsMdBlockRemoved:J,mcpRemoved:Q.removed,mcpSkipped:Q.skipped}}var a=()=>j(Wq(),".codex"),l=()=>j(a(),"hooks.json"),G=()=>j(a(),"config.toml"),A=()=>j(a(),"AGENTS.md"),D=()=>j(Wq(),".agents","skills"),T="<!-- beacon:global:start -->",Hq="<!-- beacon:global:end -->",F,p,vq="# beacon:start (managed by Beacon \u2014 `beacon uninstall` removes this block)",Xq="# beacon:end",hq,w="add it manually: codex mcp add beacon -- beacon mcp";var lq=x(()=>{Uq();Pq();F=[{event:"PostToolUse",matcher:"apply_patch",command:"beacon hook",description:"Report file edits to Beacon's active feature so the map stays fresh."},{event:"UserPromptSubmit",matcher:"*",command:"beacon prompt",description:"On feature-y prompts in a Beacon-wired repo, remind the agent to run the context\u2192propose\u2192describe loop (no-op otherwise)."},{event:"Stop",matcher:"*",command:"beacon stop-hook",description:"When the agent ends a turn asking for plan approval in prose, nudge it to present the plan on Beacon's /plan canvas."}];hq=`${vq}
|
|
261
269
|
[mcp_servers.beacon]
|
|
262
270
|
command = "beacon"
|
|
263
271
|
args = ["mcp"]
|
|
264
|
-
${
|
|
265
|
-
`});
|
|
272
|
+
${Xq}
|
|
273
|
+
`});lq();export{mq as setupCodexAssets,xq as removeCodexMcp,pq as removeCodexArtifacts,s as hasCodexMcp,Gq as ensureCodexMcp,_q as codexMcpProblem,Bq as codexDetected,Sq as auditCodex,F as CODEX_HOOKS};
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
var
|
|
2
|
+
var yq=Object.defineProperty;var Aq=(q)=>q;function Dq(q,z){this[q]=Aq.bind(null,z)}var Xq=(q,z)=>{for(var J in z)yq(q,J,{get:z[J],enumerable:!0,configurable:!0,set:Dq.bind(z,J)})};var B=(q,z)=>()=>(q&&(z=q(q=0)),z);var Bz=1500,gz=480000,Nz=1800000,C=3600000,Gz=3000;var Uq=()=>{};var l={};Xq(l,{removeRepoAssets:()=>cq,installRefreshSkill:()=>kq,installPlanSkill:()=>hq,installInitSkill:()=>Oq,installCodexRepoSkills:()=>_q,ensureWorkflowDoc:()=>pq,ensureMcp:()=>mq,auditRepo:()=>Sq,REFRESH_SKILL:()=>n,PLAN_SKILL:()=>wq,INIT_SKILL:()=>r});import{existsSync as v,mkdirSync as F,readFileSync as H,rmSync as f,writeFileSync as U}from"fs";import{join as $}from"path";function Oq(q){let z=$(q,".claude","skills","beacon-init");F(z,{recursive:!0});let J=$(z,"SKILL.md");return U(J,r),J}function kq(q){let z=$(q,".claude","skills","beacon-refresh");F(z,{recursive:!0});let J=$(z,"SKILL.md");return U(J,n),J}function hq(q){let z=$(q,".claude","skills","beacon-plan");F(z,{recursive:!0});let J=$(z,"SKILL.md");return U(J,wq),J}function _q(q){let z=[];for(let J of Lq){let Q=$(q,".agents","skills",J.name);F(Q,{recursive:!0});let V=$(Q,"SKILL.md");U(V,J.body()),z.push(V)}return z}function pq(q){let z=$(q,"AGENTS.md"),J="";try{J=H(z,"utf8")}catch{}let Q=new RegExp(`${R}[\\s\\S]*?${s}`);J=Q.test(J)?J.replace(Q,Hq):`${J.trim()}
|
|
3
3
|
|
|
4
|
-
${
|
|
4
|
+
${Hq}
|
|
5
5
|
`.trimStart(),U(z,J.endsWith(`
|
|
6
6
|
`)?J:`${J}
|
|
7
|
-
`);let V=$(q,"CLAUDE.md"),Y="";try{Y=
|
|
7
|
+
`);let V=$(q,"CLAUDE.md"),Y="";try{Y=H(V,"utf8")}catch{}if(!/@AGENTS\.md/.test(Y))U(V,`${Y?`${Y.trim()}
|
|
8
8
|
|
|
9
9
|
`:""}@AGENTS.md
|
|
10
|
-
`)}function
|
|
11
|
-
`),{path:z,added:!1,updated:!0};return{path:z,added:!1,updated:!1}}return J.mcpServers.beacon={command:"beacon",args:["mcp"],timeout:
|
|
12
|
-
`),{path:z,added:!0,updated:!1}}function
|
|
13
|
-
`)}}catch{}let V=!1,Y=$(q,"AGENTS.md");try{let Z=
|
|
10
|
+
`)}function mq(q){let z=$(q,".mcp.json"),J={};try{J=JSON.parse(H(z,"utf8"))}catch{}J.mcpServers=J.mcpServers??{};let Q=J.mcpServers.beacon;if(Q){if(!Q.timeout||Q.timeout<C)return Q.timeout=C,U(z,JSON.stringify(J,null,2)+`
|
|
11
|
+
`),{path:z,added:!1,updated:!0};return{path:z,added:!1,updated:!1}}return J.mcpServers.beacon={command:"beacon",args:["mcp"],timeout:C},U(z,JSON.stringify(J,null,2)+`
|
|
12
|
+
`),{path:z,added:!0,updated:!1}}function Sq(q){let z=$(q,".mcp.json"),J=!1;try{J=!!JSON.parse(H(z,"utf8")).mcpServers?.beacon}catch{}let Q=!1;try{Q=H($(q,"AGENTS.md"),"utf8").includes(R)}catch{}let V=!1;try{V=/@AGENTS\.md/.test(H($(q,"CLAUDE.md"),"utf8"))}catch{}return{repo:q,mcpRegistered:J,agentsMdBlock:Q,claudeMdImport:V,skills:{"beacon-init":v($(q,".claude","skills","beacon-init","SKILL.md")),"beacon-refresh":v($(q,".claude","skills","beacon-refresh","SKILL.md"))},codexSkills:{"beacon-init":v($(q,".agents","skills","beacon-init","SKILL.md")),"beacon-refresh":v($(q,".agents","skills","beacon-refresh","SKILL.md"))}}}function cq(q){let z=[];for(let Z of["beacon-init","beacon-refresh","beacon-db-design"]){let X=$(q,".claude","skills",Z);if(v(X))f(X,{recursive:!0,force:!0}),z.push(Z)}for(let Z of["beacon-init","beacon-refresh"]){let X=$(q,".agents","skills",Z);if(v(X))f(X,{recursive:!0,force:!0}),z.push(`codex:${Z}`)}let J=!1,Q=$(q,".mcp.json");try{let Z=JSON.parse(H(Q,"utf8"));if(Z.mcpServers?.beacon){if(delete Z.mcpServers.beacon,J=!0,Z.mcpServers&&Object.keys(Z.mcpServers).length===0)delete Z.mcpServers;if(Object.keys(Z).length===0)f(Q,{force:!0});else U(Q,JSON.stringify(Z,null,2)+`
|
|
13
|
+
`)}}catch{}let V=!1,Y=$(q,"AGENTS.md");try{let Z=H(Y,"utf8"),X=new RegExp(`\\n?${R}[\\s\\S]*?${s}\\n?`);if(X.test(Z)){let d=Z.replace(X,`
|
|
14
14
|
`).replace(/\n{3,}/g,`
|
|
15
15
|
|
|
16
|
-
`).trimStart();U(Y,
|
|
17
|
-
`)?
|
|
18
|
-
`),V=!0}}catch{}let
|
|
16
|
+
`).trimStart();U(Y,d.endsWith(`
|
|
17
|
+
`)?d:`${d}
|
|
18
|
+
`),V=!0}}catch{}let W=!1,P=$(q,"CLAUDE.md");try{let Z=H(P,"utf8"),X=Z.replace(/^[ \t]*@AGENTS\.md[ \t]*\n?/m,"");if(X!==Z){if(!X.trim())f(P,{force:!0});else U(P,X);W=!0}}catch{}return{skillsRemoved:z,mcpUnregistered:J,agentsBlockRemoved:V,claudeImportRemoved:W}}var r=`---
|
|
19
19
|
name: beacon-init
|
|
20
20
|
description: Read this repository and map its architecture, schema, and roadmap into Beacon (the local visual planning panel). Use when the user runs /beacon-init, asks to "set up Beacon for this repo", or asks to initialize/bootstrap Beacon's map of this codebase.
|
|
21
21
|
---
|
|
@@ -51,9 +51,17 @@ A single \`beacon_init_persist\` MCP tool call with:
|
|
|
51
51
|
- Don't fabricate tables/endpoints. If you can't find the schema source, omit \`snapshot\`.
|
|
52
52
|
- Don't ask the user to confirm before persisting. The user invoked /beacon-init \u2014 that's the confirmation.
|
|
53
53
|
|
|
54
|
-
If \`beacon_init_persist\`
|
|
54
|
+
## If \`beacon_init_persist\` is NOT in your tools (or the call can't reach the daemon)
|
|
55
55
|
|
|
56
|
-
|
|
56
|
+
That happens when this repo was never opened with \`beacon\`: there's no \`.mcp.json\`, so the Beacon MCP server isn't in this session \u2014 and MCP tools can't be added mid-session. (It also covers a wired repo whose daemon is down, so the tool call errors.) **Do NOT stop and tell the user to run \`beacon\` first.** /beacon-init bootstraps itself: write the EXACT analysis object you'd have passed to \`beacon_init_persist\` to a temp JSON file, then persist it through the CLI:
|
|
57
|
+
|
|
58
|
+
\`\`\`bash
|
|
59
|
+
beacon init-persist /tmp/beacon-init.json # or: beacon init-persist < /tmp/beacon-init.json
|
|
60
|
+
\`\`\`
|
|
61
|
+
|
|
62
|
+
That one command wires the repo (writes \`.mcp.json\` + skills so your NEXT session gets the \`beacon_*\` tools natively, heals the global install), starts the Beacon daemon if it isn't running, registers + provisions this workspace, and POSTs your analysis to the same \`/api/init\` endpoint the MCP tool uses \u2014 so init completes in THIS session. Read the counts it prints and report them.
|
|
63
|
+
|
|
64
|
+
After the tool (or \`beacon init-persist\`) returns, tell the user the counts (components / roadmap / tables / endpoints) and point them at the running Beacon panel.
|
|
57
65
|
`,n=`---
|
|
58
66
|
name: beacon-refresh
|
|
59
67
|
description: Re-survey the repo and update Beacon's architecture / schema / endpoints map after /beacon-init was already run \u2014 picks up new components, removed ones, schema changes, and new routes. Use when the user runs /beacon-refresh or asks to "refresh", "update", "re-sync", or "bring Beacon up to date" with the current code.
|
|
@@ -101,7 +109,7 @@ The one caveat: if the user manually edited an INIT-source node on the canvas (e
|
|
|
101
109
|
If \`beacon_entities\` or \`beacon_init_persist\` isn't available, the Beacon panel isn't running in this repo. Tell the user to run \`beacon\` here first, then re-invoke /beacon-refresh.
|
|
102
110
|
|
|
103
111
|
After the tool returns, report the final counts plus a one-line summary of the diff you surfaced.
|
|
104
|
-
`,
|
|
112
|
+
`,wq=`---
|
|
105
113
|
name: beacon-plan
|
|
106
114
|
description: Present your current plan or approach to the user on Beacon's /plan canvas for review \u2014 instead of asking for approval in prose. Use when the user says "present the plan", "show me the plan", "let me see it / the plan", or whenever you are about to end a turn asking whether to proceed with a plan, design, or approach.
|
|
107
115
|
---
|
|
@@ -149,7 +157,7 @@ If it returns feedback, revise and call it again.
|
|
|
149
157
|
If \`beacon_present_plan\` isn't available, the panel isn't wired here \u2014 fall back to ExitPlanMode
|
|
150
158
|
with the same \`\`\`beacon block (Claude Code only; Codex has no ExitPlanMode), or tell the user to
|
|
151
159
|
run \`beacon\` in this repo once.
|
|
152
|
-
`,
|
|
160
|
+
`,Lq,R="<!-- beacon:workflow:start -->",s="<!-- beacon:workflow:end -->",Hq;var i=B(()=>{Uq();Lq=[{name:"beacon-init",body:()=>r},{name:"beacon-refresh",body:()=>n}];Hq=`${R}
|
|
153
161
|
## Beacon \u2014 feature workflow
|
|
154
162
|
|
|
155
163
|
This project uses Beacon (a local planning/visualization panel; run \`beacon\` to open it). When you start work on a FEATURE \u2014 whether referenced via an \`@beacon:feature://\u2026\` mention, an \`@beacon:note://\u2026\` note the user wrote in the Notes panel (treat its checkbox \`- [ ]\` todos as subtasks and order features by their dependencies), or just described in chat \u2014 follow these steps in order:
|
|
@@ -217,18 +225,18 @@ Register them all in that single batched call. If a plan added five features, th
|
|
|
217
225
|
If the feature added or materially changed a REAL architectural component (a subsystem \u2014 NOT a file), also pass \`architecture: [{ title, domain, role, \u2026 }]\` so the Architecture map stays accurate. It upserts curated components by title; never list files as components. If you found a bug or something worth investigating in a component's code, add \`bugs: [{ note }]\` to its architecture entry \u2014 it renders as a bug flag on the node (attributed to the agent); identical open flags are not duplicated. Only flag what you actually saw in the code.
|
|
218
226
|
|
|
219
227
|
Pull raw planning data anytime with \`beacon_entities\` (features / architecture / tables / endpoints).
|
|
220
|
-
${
|
|
221
|
-
`)}function
|
|
228
|
+
${s}`});import{existsSync as M,mkdirSync as o,readdirSync as aq,readFileSync as g,rmSync as tq,writeFileSync as T}from"fs";import{dirname as xq,join as x}from"path";function vq(){return!!process.env.CLAUDE_PLUGIN_ROOT}function jq(q=process.env.HOME||process.env.USERPROFILE||""){if(!q)return null;let z=x(q,".claude","plugins");if(!M(z))return null;let J=[z];for(let Q=0;Q<3&&J.length;Q++){let V=[];for(let Y of J){let W=x(Y,".claude-plugin","plugin.json");try{if(M(W)&&JSON.parse(g(W,"utf8")).name==="beacon")return Y}catch{}try{for(let P of aq(Y,{withFileTypes:!0}))if(P.isDirectory())V.push(x(Y,P.name))}catch{}}J=V}return null}function Bq(q){return jq(q)!==null}function e(q){try{return JSON.parse(g(q,"utf8"))}catch{return{}}}function gq(q,z){o(xq(q),{recursive:!0}),T(q,JSON.stringify(z,null,2)+`
|
|
229
|
+
`)}function E(q,z){let J=e(q);J.hooks=J.hooks??{},J.hooks[z.event]=J.hooks[z.event]??[];let Q=J.hooks[z.event];if(Q.some((Y)=>Y.matcher===z.matcher&&Y.hooks?.some((W)=>W.command===z.command)))return!1;return Q.push({matcher:z.matcher,hooks:[{type:"command",command:z.command}]}),gq(q,J),!0}function y(q,z){return(e(q).hooks?.[z.event]??[]).some((V)=>V.hooks?.some((Y)=>Y.command===z.command))}function A(q,z){let J=e(q),Q=J.hooks?.[z.event];if(!Q)return!1;let V=!1,Y=Q.map((W)=>{let P=W.hooks?.length??0,Z=(W.hooks??[]).filter((X)=>X.command!==z.command);if(Z.length!==P)V=!0;return{...W,hooks:Z}}).filter((W)=>(W.hooks??[]).length>0);if(!V)return!1;if(Y.length)J.hooks[z.event]=Y;else delete J.hooks[z.event];if(J.hooks&&Object.keys(J.hooks).length===0)delete J.hooks;return gq(q,J),!0}function D(q,z,J,Q){let V=`${z}
|
|
222
230
|
${Q.trim()}
|
|
223
|
-
${J}`,Y="";try{Y=
|
|
231
|
+
${J}`,Y="";try{Y=g(q,"utf8")}catch{}let W=new RegExp(`${z}[\\s\\S]*?${J}`);Y=W.test(Y)?Y.replace(W,V):Y.trim()?`${Y.trim()}
|
|
224
232
|
|
|
225
233
|
${V}
|
|
226
234
|
`:`${V}
|
|
227
|
-
`,
|
|
235
|
+
`,o(xq(q),{recursive:!0}),T(q,Y.endsWith(`
|
|
228
236
|
`)?Y:`${Y}
|
|
229
|
-
`)}function
|
|
237
|
+
`)}function N(q,z){try{return g(q,"utf8").includes(z)}catch{return!1}}function O(q,z,J){let Q="";try{Q=g(q,"utf8")}catch{return!1}let V=new RegExp(`${z}[\\s\\S]*?${J}\\n?`);if(!V.test(Q))return!1;let Y=Q.replace(V,"").replace(/\n{3,}/g,`
|
|
230
238
|
|
|
231
|
-
`).trimStart();return
|
|
239
|
+
`).trimStart();return T(q,Y),!0}function k(q,z,J){let Q=x(q,z);o(Q,{recursive:!0});let V=x(Q,"SKILL.md");return T(V,J),V}function G(q,z){return M(x(q,z,"SKILL.md"))}function h(q,z){let J=x(q,z);if(!M(J))return!1;return tq(J,{recursive:!0,force:!0}),!0}var w,I=`## Beacon (visual planning panel)
|
|
232
240
|
|
|
233
241
|
This machine has Beacon installed \u2014 a local visual planning surface for the terminal-side
|
|
234
242
|
agent. Beacon proposes feature plans (roadmap features + DB schema + endpoints) via MCP,
|
|
@@ -249,17 +257,17 @@ the user reviews on a canvas at /plan, and feedback flows back as the next round
|
|
|
249
257
|
Feedback bundles inline annotations on the markdown PLUS any edits the user made directly
|
|
250
258
|
on the /map and /db boards (added features, attached subtasks, edited columns, new
|
|
251
259
|
endpoints). Treat board edits as the user's revision intent \u2014 re-propose matching them
|
|
252
|
-
verbatim. Do NOT implement until the tool returns approval.`;var
|
|
260
|
+
verbatim. Do NOT implement until the tool returns approval.`;var qq=B(()=>{w=["beacon-init","beacon-refresh","beacon-plan"]});import{mkdirSync as dq,renameSync as rq,rmSync as nq,writeFileSync as sq}from"fs";import{dirname as lq}from"path";function L(q,z){dq(lq(q),{recursive:!0});let J=`${q}.tmp`;try{sq(J,z),rq(J,q)}catch(Q){throw nq(J,{force:!0}),Q}}function Iz(q,z,J=!1){L(q,JSON.stringify(z,null,J?2:void 0))}var Nq=()=>{};var Rq={};Xq(Rq,{setupCodexAssets:()=>qz,removeCodexMcp:()=>Fq,removeCodexArtifacts:()=>Jz,hasCodexMcp:()=>Vq,ensureCodexMcp:()=>fq,codexMcpProblem:()=>eq,codexDetected:()=>uq,auditCodex:()=>zz,CODEX_HOOKS:()=>c});import{readFileSync as S}from"fs";import{homedir as iq}from"os";import{join as K}from"path";function Gq(){return process.env.HOME||process.env.USERPROFILE||iq()}function uq(){if(process.env.BEACON_CODEX==="1")return!0;if(process.env.BEACON_CODEX==="0")return!1;if(zq===void 0)zq=Bun.which("codex")!==null;return zq}function u(q){try{return Bun.TOML.parse(q)}catch{return null}}function Vq(){try{return Boolean(u(S(j(),"utf8"))?.mcp_servers?.beacon)}catch{return!1}}function eq(){let q="";try{q=S(j(),"utf8")}catch{return null}let z=u(q);if(!z)return`~/.codex/config.toml does not parse \u2014 ${b}`;if(z.mcp_servers?.beacon)return null;if(/^\s*mcp_servers\s*=/m.test(q))return`mcp_servers is an inline table \u2014 ${b}`;return null}function fq(){let q="",z=!1;try{q=S(j(),"utf8"),z=!0}catch{}if(z){let Y=u(q);if(!Y)return{added:!1,error:`~/.codex/config.toml does not parse \u2014 ${b}`};if(Y.mcp_servers?.beacon)return{added:!1};if(/^\s*mcp_servers\s*=/m.test(q))return{added:!1,error:`mcp_servers is an inline table \u2014 ${b}`}}let J=!q?"":q.endsWith(`
|
|
253
261
|
`)?`
|
|
254
262
|
`:`
|
|
255
263
|
|
|
256
|
-
`,Q=q+J+
|
|
257
|
-
`),J=z.indexOf(
|
|
264
|
+
`,Q=q+J+oq;if(u(Q)?.mcp_servers?.beacon?.command!=="beacon")return{added:!1,error:`could not safely append [mcp_servers.beacon] \u2014 ${b}`};return L(j(),Q),{added:!0}}function Fq(){let q="";try{q=S(j(),"utf8")}catch{return{removed:!1}}let z=q.split(`
|
|
265
|
+
`),J=z.indexOf(Kq);if(J===-1)return{removed:!1,skipped:Vq()};let Q=z.indexOf(Cq,J);if(Q===-1)return{removed:!1,skipped:!0};z.splice(J,Q-J+1);let V=z.join(`
|
|
258
266
|
`).replace(/\n{3,}/g,`
|
|
259
267
|
|
|
260
|
-
`).replace(/^\n+/,"");if(
|
|
268
|
+
`).replace(/^\n+/,"");if(u(V)===null)return{removed:!1,skipped:!0};return L(j(),V),{removed:!0}}async function qz(){let{INIT_SKILL:q,REFRESH_SKILL:z,PLAN_SKILL:J}=await Promise.resolve().then(() => (i(),l)),Q={"beacon-init":q,"beacon-refresh":z,"beacon-plan":J},V=[];for(let Z of w){if(!G(p(),Z))V.push(Z);k(p(),Z,Q[Z])}let Y=0;for(let Z of c)if(E(Qq(),{event:Z.event,matcher:Z.matcher,command:Z.command}))Y++;let W=N(_(),m);D(_(),m,bq,I);let P=fq();return{skillsAdded:V,hooksAdded:Y,agentsMdBlockTouched:!W,mcp:P}}function zz(){let q={};for(let J of w)q[J]=G(p(),J);let z={};for(let J of c)z[J.event]=y(Qq(),{event:J.event,command:J.command});return{detected:uq(),skills:q,hooks:z,agentsMdBlock:N(_(),m),mcp:Vq()}}function Jz(){let q=[];for(let V of w)if(h(p(),V))q.push(V);let z=0;for(let V of c)if(A(Qq(),{event:V.event,command:V.command}))z++;let J=O(_(),m,bq),Q=Fq();return{skillsRemoved:q,hooksRemoved:z,agentsMdBlockRemoved:J,mcpRemoved:Q.removed,mcpSkipped:Q.skipped}}var Jq=()=>K(Gq(),".codex"),Qq=()=>K(Jq(),"hooks.json"),j=()=>K(Jq(),"config.toml"),_=()=>K(Jq(),"AGENTS.md"),p=()=>K(Gq(),".agents","skills"),m="<!-- beacon:global:start -->",bq="<!-- beacon:global:end -->",c,zq,Kq="# beacon:start (managed by Beacon \u2014 `beacon uninstall` removes this block)",Cq="# beacon:end",oq,b="add it manually: codex mcp add beacon -- beacon mcp";var Mq=B(()=>{qq();Nq();c=[{event:"PostToolUse",matcher:"apply_patch",command:"beacon hook",description:"Report file edits to Beacon's active feature so the map stays fresh."},{event:"UserPromptSubmit",matcher:"*",command:"beacon prompt",description:"On feature-y prompts in a Beacon-wired repo, remind the agent to run the context\u2192propose\u2192describe loop (no-op otherwise)."},{event:"Stop",matcher:"*",command:"beacon stop-hook",description:"When the agent ends a turn asking for plan approval in prose, nudge it to present the plan on Beacon's /plan canvas."}];oq=`${Kq}
|
|
261
269
|
[mcp_servers.beacon]
|
|
262
270
|
command = "beacon"
|
|
263
271
|
args = ["mcp"]
|
|
264
|
-
${
|
|
265
|
-
`});
|
|
272
|
+
${Cq}
|
|
273
|
+
`});qq();import{existsSync as Qz}from"fs";import{homedir as Vz}from"os";import{join as a}from"path";function Yz(){return process.env.HOME||process.env.USERPROFILE||Vz()}var t=()=>a(Yz(),".claude"),Yq=()=>a(t(),"skills"),Zq=()=>a(t(),"settings.json"),$q=()=>a(t(),"CLAUDE.md"),Wq="<!-- beacon:global:start -->",Tq="<!-- beacon:global:end -->";var Zz=I,Pq=[{event:"PreToolUse",matcher:"Edit|Write|MultiEdit",command:"beacon guard",description:"Gate edits against the active plan's scope contract (when the scope-guard flag is on): in-scope \u2192 allow, off-scope \u2192 ask the user to authorize. No-op + fail-open otherwise."},{event:"PostToolUse",matcher:"Edit|Write|MultiEdit",command:"beacon hook",description:"Report file edits to Beacon's active feature so the map stays fresh."},{event:"PermissionRequest",matcher:"ExitPlanMode",command:"beacon plan",description:"Pipe the agent's plan markdown into Beacon's /plan canvas for review."},{event:"UserPromptSubmit",matcher:"*",command:"beacon prompt",description:"On feature-y prompts in a Beacon-wired repo, remind the agent to run the context\u2192propose\u2192describe loop (no-op otherwise)."},{event:"Stop",matcher:"*",command:"beacon stop-hook",description:"When the agent ends a turn asking for plan approval in prose (instead of presenting it), nudge it to present the plan on Beacon's /plan canvas. Bounded by stop_hook_active \u2014 at most one nudge."}];function $z(q,z){return k(Yq(),q,z)}function Iq(q){return G(Yq(),q)}function Wz(q){return h(Yq(),q)}function Pz(q){return E(Zq(),q)}function Xz(q){return y(Zq(),q)}function Uz(q){return A(Zq(),q)}function Hz(q){D($q(),Wq,Tq,q)}function Eq(){return N($q(),Wq)}function wz(){return O($q(),Wq,Tq)}function mz(){let q={};for(let J of w)q[J]=Iq(J);let z={};for(let J of Pq)z[J.event]=Xz({event:J.event,command:J.command});return{homeExists:Qz(t()),skills:q,hooks:z,claudeMdBlock:Eq()}}async function xz(){let{INIT_SKILL:q,REFRESH_SKILL:z,PLAN_SKILL:J}=await Promise.resolve().then(() => (i(),l)),Q={"beacon-init":q,"beacon-refresh":z,"beacon-plan":J},V=[];for(let P of w){if(!Iq(P))V.push(P);$z(P,Q[P])}let Y=0;for(let P of Pq)if(Pz({event:P.event,matcher:P.matcher,command:P.command}))Y++;let W=Eq();return Hz(Zz),{skillsAdded:V,hooksAdded:Y,claudeMdBlockTouched:!W}}async function Sz(){if(vq())return{ok:!0,skipped:"plugin",skillsAdded:[],hooksAdded:0,claudeMdBlockTouched:!1};let q;if(Bq()){try{vz()}catch{}q={ok:!0,skipped:"plugin-present",skillsAdded:[],hooksAdded:0,claudeMdBlockTouched:!1}}else try{q={ok:!0,...await xz()}}catch(z){q={ok:!1,error:z instanceof Error?z.message:String(z),skillsAdded:[],hooksAdded:0,claudeMdBlockTouched:!1}}try{let z=await Promise.resolve().then(() => (Mq(),Rq));if(z.codexDetected())q.codex={ok:!0,...await z.setupCodexAssets()}}catch(z){q.codex={ok:!1,error:z instanceof Error?z.message:String(z),skillsAdded:[],hooksAdded:0,agentsMdBlockTouched:!1,mcp:{added:!1}}}return q}function vz(){let q=[];for(let Q of w)if(Wz(Q))q.push(Q);let z=0;for(let Q of Pq)if(Uz(Q))z++;let J=wz();return{skillsRemoved:q,hooksRemoved:z,claudeMdBlockRemoved:J}}export{xz as setupGlobalAssets,Sz as selfHealGlobal,Wz as removeGlobalSkill,Uz as removeGlobalHook,wz as removeGlobalClaudeMdBlock,vz as removeBeaconArtifacts,vq as isPluginManaged,Iq as isGlobalSkillInstalled,$z as installGlobalSkill,Xz as hasGlobalHook,Eq as hasGlobalClaudeMdBlock,jq as findBeaconPluginDir,Pz as ensureGlobalHook,Hz as ensureGlobalClaudeMdBlock,Bq as beaconPluginInstalled,mz as auditGlobal,w as GLOBAL_SKILLS,Pq as GLOBAL_HOOKS,Zz as GLOBAL_CLAUDE_MD_BLOCK};
|
package/package.json
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "trybeacon",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.64",
|
|
4
4
|
"description": "The visual planning surface for the coding agent in your terminal.",
|
|
5
5
|
"homepage": "https://trybeacon.sh",
|
|
6
|
+
"license": "Apache-2.0",
|
|
7
|
+
"author": "Wenzo (https://trybeacon.sh)",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/wenzorithelly/beacon.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/wenzorithelly/beacon/issues"
|
|
14
|
+
},
|
|
6
15
|
"bin": {
|
|
7
16
|
"beacon": "dist/bin/beacon.js"
|
|
8
17
|
},
|
|
@@ -11,13 +20,17 @@
|
|
|
11
20
|
".next",
|
|
12
21
|
"public",
|
|
13
22
|
"drizzle",
|
|
14
|
-
"next.config.ts"
|
|
23
|
+
"next.config.ts",
|
|
24
|
+
"bun.lock",
|
|
25
|
+
".claude-plugin/plugin.json",
|
|
26
|
+
"plugin"
|
|
15
27
|
],
|
|
16
28
|
"scripts": {
|
|
17
29
|
"dev": "next dev",
|
|
18
30
|
"build": "next build",
|
|
19
31
|
"build:cli": "bun scripts/build-cli.ts",
|
|
20
|
-
"build:
|
|
32
|
+
"build:plugin": "bun scripts/build-plugin.ts",
|
|
33
|
+
"build:release": "rm -rf .next && next build --webpack && rm -rf .next/cache .next/dev && find .next -name '*.js.map' -delete && bun run build:cli && bun run build:plugin",
|
|
21
34
|
"prepublishOnly": "bun run build:release",
|
|
22
35
|
"start": "next start",
|
|
23
36
|
"lint": "eslint",
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: beacon
|
|
3
|
+
description: Open the Beacon visual planning panel for this repo in your browser.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Open Beacon's panel for the current repo. Run this in the repo's shell — it registers the repo,
|
|
7
|
+
makes sure the shared Beacon daemon is running, and opens (or reuses) the browser tab on /map:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
bun "${CLAUDE_PLUGIN_ROOT}/dist/bin/boot.js"
|
|
11
|
+
```
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"PreToolUse": [
|
|
4
|
+
{
|
|
5
|
+
"matcher": "Edit|Write|MultiEdit",
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "bun ${CLAUDE_PLUGIN_ROOT}/dist/bin/boot.js guard"
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"PostToolUse": [
|
|
15
|
+
{
|
|
16
|
+
"matcher": "Edit|Write|MultiEdit",
|
|
17
|
+
"hooks": [
|
|
18
|
+
{
|
|
19
|
+
"type": "command",
|
|
20
|
+
"command": "bun ${CLAUDE_PLUGIN_ROOT}/dist/bin/boot.js hook"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
],
|
|
25
|
+
"PermissionRequest": [
|
|
26
|
+
{
|
|
27
|
+
"matcher": "ExitPlanMode",
|
|
28
|
+
"hooks": [
|
|
29
|
+
{
|
|
30
|
+
"type": "command",
|
|
31
|
+
"command": "bun ${CLAUDE_PLUGIN_ROOT}/dist/bin/boot.js plan"
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"UserPromptSubmit": [
|
|
37
|
+
{
|
|
38
|
+
"matcher": "*",
|
|
39
|
+
"hooks": [
|
|
40
|
+
{
|
|
41
|
+
"type": "command",
|
|
42
|
+
"command": "bun ${CLAUDE_PLUGIN_ROOT}/dist/bin/boot.js prompt"
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
],
|
|
47
|
+
"Stop": [
|
|
48
|
+
{
|
|
49
|
+
"matcher": "*",
|
|
50
|
+
"hooks": [
|
|
51
|
+
{
|
|
52
|
+
"type": "command",
|
|
53
|
+
"command": "bun ${CLAUDE_PLUGIN_ROOT}/dist/bin/boot.js stop-hook"
|
|
54
|
+
}
|
|
55
|
+
]
|
|
56
|
+
}
|
|
57
|
+
],
|
|
58
|
+
"SessionStart": [
|
|
59
|
+
{
|
|
60
|
+
"matcher": "*",
|
|
61
|
+
"hooks": [
|
|
62
|
+
{
|
|
63
|
+
"type": "command",
|
|
64
|
+
"command": "bun ${CLAUDE_PLUGIN_ROOT}/dist/bin/boot.js ensure"
|
|
65
|
+
}
|
|
66
|
+
]
|
|
67
|
+
}
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
}
|
package/plugin/mcp.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: beacon-init
|
|
3
|
+
description: Read this repository and map its architecture, schema, and roadmap into Beacon (the local visual planning panel). Use when the user runs /beacon-init, asks to "set up Beacon for this repo", or asks to initialize/bootstrap Beacon's map of this codebase.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Map this repo into Beacon (/beacon-init)
|
|
7
|
+
|
|
8
|
+
The user already has Beacon running. You're going to map this repository's architecture into it — what used to be `beacon init`. **You** do the analysis (your session already has the codebase context); Beacon just persists what you send.
|
|
9
|
+
|
|
10
|
+
## What you produce
|
|
11
|
+
|
|
12
|
+
A single `beacon_init_persist` MCP tool call with:
|
|
13
|
+
|
|
14
|
+
- **hasFrontend**: `true` or `false` — does this repo have a frontend surface (UI code)? You just read the repo, so you know. Set it explicitly; it gates the frontend/backend `layer` distinction on the boards (a pure-backend repo never shows it).
|
|
15
|
+
- **classificationRoots** (optional): the top-level directories whose immediate children are the meaningful groups on the Files canvas — e.g. `["frontend", "backend/app"]`. The canvas groups files ONE level below each root (so `frontend` → `frontend/components`, `frontend/app`, …). Pick the dir sitting directly ABOVE the real package dirs — use `frontend/src` if there's a `src/` wrapper. List both sides of a monorepo so neither collapses into one flat blob. Not every dir — just where grouping should START. Omit it for a simple single-root repo; the canvas falls back to automatic grouping.
|
|
16
|
+
- **components**: 8–25 main building blocks of this codebase. NOT every file. Group them by `domain` (short UPPERCASE: AUTH, API, DATA, UI, JOBS, INFRA, BILLING, SEARCH, …). For each: a one-line technical `role`, a one-sentence plain-language `plain`, the few `files` that implement it (repo-relative), `depends` listing other component titles it relies on — and, when `hasFrontend` is true, `layer` (`"frontend" | "backend" | "fullstack"`). Use the dependency graph you can see in the source — files that import each other heavily usually belong together. If you spot a bug or something worth investigating while reading a component's code, add `bugs: [{ note }]` to that component — it renders as a bug flag on the node (attributed to the agent). Only flag what you actually saw in the code; don't speculate.
|
|
17
|
+
- **roadmap**: 3–6 BROAD strategic directions. Big-picture themes only — "Harden auth & security", "Add observability", "Scale the data layer", "Pay down test-coverage debt". NOT detailed tasks. NOT file-level. Each gets a short title and one-line `why`. If one of them is a concrete BUG to fix (something broken you saw in the code), add `kind: "BUG"` so it renders as a typed bug card. When `hasFrontend` is true, give each a `layer` too (`"frontend" | "backend" | "fullstack"`).
|
|
18
|
+
- **overview**: one paragraph describing what this project is and its stack. This lands in AGENTS.md as the project intro.
|
|
19
|
+
- **conventions**: 3–8 concrete rules a contributor MUST follow — build/test commands, where code goes, patterns, things easy to get wrong. Infer from actual files, not assumptions.
|
|
20
|
+
- **snapshot** (optional but encouraged): `{ tables, relations, endpoints }` for the existing database. If the project uses Prisma, read `prisma/schema.prisma`. If SQLAlchemy, read the model files. If Django, read `models.py`. If you find no obvious schema source, skip the snapshot — don't fabricate.
|
|
21
|
+
|
|
22
|
+
## How to do it
|
|
23
|
+
|
|
24
|
+
1. **Survey**. Use `LS` / `Glob` to see the top-level structure. Read `README.md` and the manifest (`package.json` / `pyproject.toml` / `go.mod` / `Cargo.toml` / `pom.xml`).
|
|
25
|
+
2. **Sample the source.** Read 15–30 representative files — one per cluster you can identify. Don't read everything; pick by name (route files, model files, main entrypoints, key services). The goal is to identify boundaries, not memorize every line.
|
|
26
|
+
3. **Identify the schema** if any. `prisma/schema.prisma` → translate each model into a `tables` entry. `alembic`/SQLAlchemy → read the latest models. Django → read `models.py`. Skip the snapshot if the source-of-truth isn't obvious.
|
|
27
|
+
4. **Identify endpoints** if any. Look for routes — Next.js `app/api/*` files, FastAPI `@router.*` / `@app.*`, Express `app.get`/etc. For each endpoint try to fill `uses: [{ table, access }]` so the canvas can draw which endpoint touches which table.
|
|
28
|
+
5. **Call `beacon_init_persist`** ONCE with the whole analysis. It replaces any prior init-derived map (idempotent) and regenerates `AGENTS.md`.
|
|
29
|
+
|
|
30
|
+
## What you should NOT do
|
|
31
|
+
|
|
32
|
+
- Don't propose detailed tasks in `roadmap` — that's what `beacon_propose_plan` is for. Init roadmap is strategic only.
|
|
33
|
+
- Don't list every file as a `component`. Aim for ~15. If you have 40, you're listing files, not components.
|
|
34
|
+
- Don't fabricate tables/endpoints. If you can't find the schema source, omit `snapshot`.
|
|
35
|
+
- Don't ask the user to confirm before persisting. The user invoked /beacon-init — that's the confirmation.
|
|
36
|
+
|
|
37
|
+
## If `beacon_init_persist` is NOT in your tools (or the call can't reach the daemon)
|
|
38
|
+
|
|
39
|
+
That happens when this repo was never opened with `beacon`: there's no `.mcp.json`, so the Beacon MCP server isn't in this session — and MCP tools can't be added mid-session. (It also covers a wired repo whose daemon is down, so the tool call errors.) **Do NOT stop and tell the user to run `beacon` first.** /beacon-init bootstraps itself: write the EXACT analysis object you'd have passed to `beacon_init_persist` to a temp JSON file, then persist it through the CLI:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
beacon init-persist /tmp/beacon-init.json # or: beacon init-persist < /tmp/beacon-init.json
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
That one command wires the repo (writes `.mcp.json` + skills so your NEXT session gets the `beacon_*` tools natively, heals the global install), starts the Beacon daemon if it isn't running, registers + provisions this workspace, and POSTs your analysis to the same `/api/init` endpoint the MCP tool uses — so init completes in THIS session. Read the counts it prints and report them.
|
|
46
|
+
|
|
47
|
+
After the tool (or `beacon init-persist`) returns, tell the user the counts (components / roadmap / tables / endpoints) and point them at the running Beacon panel.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: beacon-plan
|
|
3
|
+
description: Present your current plan or approach to the user on Beacon's /plan canvas for review — instead of asking for approval in prose. Use when the user says "present the plan", "show me the plan", "let me see it / the plan", or whenever you are about to end a turn asking whether to proceed with a plan, design, or approach.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Present a plan on Beacon (/beacon-plan)
|
|
7
|
+
|
|
8
|
+
Beacon reviews plans on a canvas at /plan — never as a wall of text in the terminal. So do NOT
|
|
9
|
+
end a turn with "here's my plan… should I proceed?" in prose. Present it through Beacon and let the
|
|
10
|
+
tool BLOCK until the user decides.
|
|
11
|
+
|
|
12
|
+
## How to present
|
|
13
|
+
|
|
14
|
+
Call the **`beacon_present_plan`** MCP tool with your plan as markdown:
|
|
15
|
+
|
|
16
|
+
- `description`: a one-line summary shown in the review header.
|
|
17
|
+
- `markdown`: the full plan as markdown (headings, lists, code).
|
|
18
|
+
- If the plan proposes DB tables / relations / endpoints or roadmap features, embed ONE fenced
|
|
19
|
+
```beacon JSON block in the markdown — the same shapes `beacon_propose_plan` accepts:
|
|
20
|
+
|
|
21
|
+
```beacon
|
|
22
|
+
{ "tables": [...], "relations": [...], "endpoints": [...], "features": [...] }
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Beacon extracts that block deterministically, strips it from the prose, and renders an editable
|
|
26
|
+
board on /plan. The board is built ONLY from the block — prose is never parsed — so mirror EVERY
|
|
27
|
+
table/endpoint/feature you mention in the prose into the block, or that board will be empty.
|
|
28
|
+
|
|
29
|
+
- **Declare your scope.** List the repo-relative files this plan will touch in a top-level
|
|
30
|
+
`"contract"` array in the block (or the `contract` arg of `beacon_propose_plan`). When the user
|
|
31
|
+
has the plan scope-guard enabled, those files are frozen at approval and you're held to them while
|
|
32
|
+
implementing — editing an undeclared file pauses for the user's authorization (which then adds it
|
|
33
|
+
to the contract). Harmless when the guard is off. Declare the files you genuinely expect to edit.
|
|
34
|
+
|
|
35
|
+
`beacon_present_plan` opens /plan and BLOCKS until the user clicks Approve / Discard / submits
|
|
36
|
+
feedback, then returns their verdict. Implement code or migrations ONLY after it returns approval.
|
|
37
|
+
If it returns feedback, revise and call it again.
|
|
38
|
+
|
|
39
|
+
## Which tool
|
|
40
|
+
|
|
41
|
+
- **Pure schema/feature plan** (tables + endpoints + roadmap features, little prose) → you may use
|
|
42
|
+
`beacon_propose_plan` with the structured fields instead; it's the same review loop.
|
|
43
|
+
- **Anything else** (a code-change plan, a mixed plan, a "how should I approach X") → use
|
|
44
|
+
`beacon_present_plan` with markdown so the full reasoning shows on /plan.
|
|
45
|
+
|
|
46
|
+
If `beacon_present_plan` isn't available, the panel isn't wired here — fall back to ExitPlanMode
|
|
47
|
+
with the same ```beacon block (Claude Code only; Codex has no ExitPlanMode), or tell the user to
|
|
48
|
+
run `beacon` in this repo once.
|