@puku/puku-cli 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +29 -0
- package/README.md +29 -0
- package/bin/import-specifier.mjs +7 -0
- package/bin/openpuku +15 -0
- package/dist/cli.mjs +8826 -0
- package/dist/smart-context/configs/puku-cli/ROUTING-ONLY.md +27 -0
- package/dist/smart-context/hooks/core/formatters.mjs +1 -0
- package/dist/smart-context/hooks/core/mcp-ready.mjs +1 -0
- package/dist/smart-context/hooks/core/routing.mjs +1 -0
- package/dist/smart-context/hooks/core/stdin.mjs +1 -0
- package/dist/smart-context/hooks/core/tool-naming.mjs +1 -0
- package/dist/smart-context/hooks/ensure-deps.mjs +1 -0
- package/dist/smart-context/hooks/posttooluse.mjs +2 -0
- package/dist/smart-context/hooks/precompact.mjs +3 -0
- package/dist/smart-context/hooks/pretooluse.mjs +6 -0
- package/dist/smart-context/hooks/routing-block.mjs +85 -0
- package/dist/smart-context/hooks/session-db.bundle.mjs +57 -0
- package/dist/smart-context/hooks/session-directive.mjs +69 -0
- package/dist/smart-context/hooks/session-extract.bundle.mjs +1 -0
- package/dist/smart-context/hooks/session-helpers.mjs +1 -0
- package/dist/smart-context/hooks/session-loaders.mjs +1 -0
- package/dist/smart-context/hooks/session-snapshot.bundle.mjs +29 -0
- package/dist/smart-context/hooks/sessionstart.mjs +4 -0
- package/dist/smart-context/hooks/suppress-stderr.mjs +1 -0
- package/dist/smart-context/hooks/userpromptsubmit.mjs +2 -0
- package/dist/smart-context/server.bundle.mjs +555 -0
- package/dist/smart-context/start.mjs +7 -0
- package/package.json +148 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# smart-context — routing rules
|
|
2
|
+
|
|
3
|
+
When you need to analyze, count, filter, compare, search, parse, transform, or process data:
|
|
4
|
+
**write a Bash script** that does the work and logs only the answer. Do NOT read raw files
|
|
5
|
+
into context to process mentally. One script replaces ten Read calls and saves 100x context.
|
|
6
|
+
|
|
7
|
+
## Think in Code
|
|
8
|
+
|
|
9
|
+
Example: Instead of `Read(src/auth.ts)` to count functions, run:
|
|
10
|
+
```
|
|
11
|
+
Bash: grep -c "^export function" src/auth.ts
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Write pure shell or JavaScript — no npm dependencies. Always handle errors. Print only the
|
|
15
|
+
result, not the raw data.
|
|
16
|
+
|
|
17
|
+
## Tool selection
|
|
18
|
+
|
|
19
|
+
- **Bash** — for `git`, `mkdir`, `rm`, `mv`, short-output commands, and analysis scripts
|
|
20
|
+
- **Read** — only for files you intend to **Edit** (Edit needs content in context)
|
|
21
|
+
- **Grep** — use `grep -c` or `grep -l` before `grep -n` to avoid large output
|
|
22
|
+
|
|
23
|
+
## Output constraints
|
|
24
|
+
|
|
25
|
+
- Keep responses under 500 words.
|
|
26
|
+
- Write code, configs, and docs to FILES — never return them as inline text.
|
|
27
|
+
- Return only: file path + 1-line description.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var q={deny:(j,k)=>({hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"deny",permissionDecisionReason:k??j,...k?{additionalContext:j}:{}}}),ask:()=>({hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"ask"}}),modify:(j,k)=>({hookSpecificOutput:{hookEventName:"PreToolUse",permissionDecision:"allow",updatedInput:{command:`echo "${k??"( Redirected to ctx tools )"}"`},additionalContext:w(j)}}),context:(j)=>({hookSpecificOutput:{hookEventName:"PreToolUse",additionalContext:j}})};function w(j){let k=j?.command??"",v=k.match(/^echo\s+"([\s\S]+)"$/);return v?v[1]:k}function B(j){if(!j)return null;switch(j.action){case"deny":return q.deny(j.reason,j.displayLabel);case"ask":return q.ask();case"modify":return q.modify(j.updatedInput,j.displayLabel);case"context":return q.context(j.additionalContext);default:return null}}export{B as formatDecision};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{readFileSync as g}from"node:fs";import{tmpdir as j}from"node:os";import{resolve as k}from"node:path";function q(){return k(j(),`context-mode-mcp-ready-${process.ppid}`)}function B(){try{let b=parseInt(g(q(),"utf8"),10);return process.kill(b,0),!0}catch{return!1}}export{q as sentinelPath,B as isMCPReady};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createRequire as b}from"node:module";var T=b(import.meta.url);import{ROUTING_BLOCK as G,READ_GUIDANCE as S,GREP_GUIDANCE as f,BASH_GUIDANCE as h,createRoutingBlock as R,createReadGuidance as c,createGrepGuidance as n,createBashGuidance as l}from"../routing-block.mjs";import{createToolNamer as j}from"./tool-naming.mjs";import{isMCPReady as C}from"./mcp-ready.mjs";import{existsSync as qq,mkdirSync as _,rmSync as D,openSync as g,closeSync as N,constants as P}from"node:fs";import{tmpdir as I}from"node:os";import{resolve as E}from"node:path";function W(q){if(!C())return null;return q}var v=new Set,y=process.env.VITEST_WORKER_ID?`${process.ppid}-w${process.env.VITEST_WORKER_ID}`:String(process.ppid),B=E(I(),`context-mode-guidance-${y}`);function w(q,z){if(v.has(q))return null;try{_(B,{recursive:!0})}catch{}let K=E(B,q);try{let F=g(K,P.O_CREAT|P.O_EXCL|P.O_WRONLY);N(F)}catch{return v.add(q),null}return v.add(q),{action:"context",additionalContext:z}}function Jq(){v.clear();try{D(B,{recursive:!0,force:!0})}catch{}}function H(q){return q.replace(/<<-?\s*["']?(\w+)["']?[\s\S]*?\n\s*\1/g,"")}function m(q){return H(q).replace(/'[^']*'/g,"''").replace(/"[^"]*"/g,'""')}var X=null;async function Vq(q){try{let{pathToFileURL:z}=await import("node:url"),K=(await import("node:path")).resolve(q,"security.js");X=await import(z(K).href)}catch{}}var d={};function Xq(q,z,K){let F=j(),a=G,U=S,k=f,A=h,Q=d[q]??q;if(Q==="Bash"){let Y=z.command??"";if(X){let Z=X.readBashPolicies(K);if(Z.length>0){let $=X.evaluateCommand(Y,Z);if($.decision==="deny")return{action:"deny",reason:`Blocked by security policy: matches deny pattern ${$.matchedPattern}`};if($.decision==="ask"&&$.matchedPattern)return{action:"ask"}}}let V=m(Y);if(/(^|\s|&&|\||\;)(curl|wget)\s/i.test(V)){if(V.split(/\s*(?:&&|\|\||;)\s*/).some((M)=>{let x=M.trim();if(!/(^|\s)(curl|wget)\s/i.test(x))return!1;let L=/\bcurl\b/i.test(x),O=/\bwget\b/i.test(x);if(!(L?/\s(-o|--output)\s/.test(x)||/\s*>\s*/.test(x)||/\s*>>\s*/.test(x):/\s(-O|--output-document)\s/.test(x)||/\s*>\s*/.test(x)||/\s*>>\s*/.test(x)))return!0;if(L&&/\s(-o|--output)\s+(-|\/dev\/stdout)(\s|$)/.test(x))return!0;if(O&&/\s(-O|--output-document)\s+(-|\/dev\/stdout)(\s|$)/.test(x))return!0;if(/\s(-v|--verbose|--trace|-D\s+-)\b/.test(x))return!0;if(!(L?/\s-[a-zA-Z]*s|--silent/.test(x):/\s-[a-zA-Z]*q|--quiet/.test(x)))return!0;return!1}))return W({action:"modify",displayLabel:"( Crafting fetch request )",updatedInput:{command:`echo "curl/wget blocked. Think in Code — use ${F("ctx_execute")}(language, code) to write code that fetches, processes, and prints only the answer. Or use ${F("ctx_fetch_and_index")}(url, source) to fetch and index. Write pure JS with try/catch, no npm deps. Do NOT retry with curl/wget."`}});return null}let J=H(Y);if(/fetch\s*\(\s*['"](https?:\/\/|http)/i.test(J)||/requests\.(get|post|put)\s*\(/i.test(J)||/http\.(get|request)\s*\(/i.test(J))return W({action:"modify",displayLabel:"( Crafting HTTP request )",updatedInput:{command:`echo "Inline HTTP blocked. Think in Code — use ${F("ctx_execute")}(language, code) to write code that fetches, processes, and console.log() only the result. Write robust pure JS with try/catch, no npm deps. Do NOT retry with Bash."`}});if(/(^|\s|&&|\||\;)(\.\/gradlew|gradlew|gradle|\.\/mvnw|mvnw|mvn)\s/i.test(V)){let Z=Y.replace(/\\/g,"\\\\").replace(/"/g,"\\\"");return W({action:"modify",displayLabel:"( Running build )",updatedInput:{command:`echo "Build tool redirected. Think in Code — use ${F("ctx_execute")}(language: \\"shell\\", code: \\"${Z} 2>&1 | tail -30\\") to run and print only errors/summary. Do NOT retry with Bash."`}})}return w("bash",A)}if(Q==="Read")return w("read",U);if(Q==="Grep")return w("grep",k);if(Q==="WebFetch"){let Y=z.url??"";return W({action:"deny",displayLabel:"( Fetching remote resource )",reason:`WebFetch blocked. Think in Code — use ${F("ctx_fetch_and_index")}(url: "${Y}", source: "...") to fetch and index, then ${F("ctx_search")}(queries: [...]) to query. Or use ${F("ctx_execute")}(language, code) to fetch, process, and console.log() only what you need. Write pure JS, no npm deps. Do NOT use curl, wget, or WebFetch.`})}if(Q==="Agent"){let Y=z.subagent_type??"",V=["prompt","request","objective","question","query","task"].find((M)=>(M in z))??"prompt",J=z[V]??"",Z=R(F,{includeCommands:!1});return{action:"modify",updatedInput:Y==="Bash"?{...z,[V]:J+Z,subagent_type:"general-purpose"}:{...z,[V]:J+Z}}}if(q.includes("context-mode")&&/(?:__|\/)(ctx_)?execute$/.test(q)||/^MCP:(ctx_)?execute$/.test(q)){if(X&&z.language==="shell"){let Y=z.code??"",V=X.readBashPolicies(K);if(V.length>0){let J=X.evaluateCommand(Y,V);if(J.decision==="deny")return{action:"deny",reason:`Blocked by security policy: shell code matches deny pattern ${J.matchedPattern}`};if(J.decision==="ask"&&J.matchedPattern)return{action:"ask"}}}return null}if(q.includes("context-mode")&&/(?:__|\/)(ctx_)?execute_file$/.test(q)||/^MCP:(ctx_)?execute_file$/.test(q)){if(X){let Y=z.path??"",V=X.readToolDenyPatterns("Read",K),J=X.evaluateFilePath(Y,V);if(J.denied)return{action:"deny",reason:`Blocked by security policy: file path matches Read deny pattern ${J.matchedPattern}`};let Z=z.language??"",$=z.code??"";if(Z==="shell"){let M=X.readBashPolicies(K);if(M.length>0){let x=X.evaluateCommand($,M);if(x.decision==="deny")return{action:"deny",reason:`Blocked by security policy: shell code matches deny pattern ${x.matchedPattern}`};if(x.decision==="ask"&&x.matchedPattern)return{action:"ask"}}}}return null}if(q.includes("context-mode")&&/(?:__|\/)(ctx_)?batch_execute$/.test(q)){if(X){let Y=z.commands??[],V=X.readBashPolicies(K);if(V.length>0)for(let J of Y){let Z=J.command??"",$=X.evaluateCommand(Z,V);if($.decision==="deny")return{action:"deny",reason:`Blocked by security policy: batch command "${J.label??Z}" matches deny pattern ${$.matchedPattern}`};if($.decision==="ask"&&$.matchedPattern)return{action:"ask"}}}return null}return null}export{Xq as routePreToolUse,Jq as resetGuidanceThrottle,Vq as initSecurity};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function r(){return new Promise((n,e)=>{let s="";process.stdin.setEncoding("utf-8"),process.stdin.on("data",(o)=>{s+=o}),process.stdin.on("end",()=>n(s.replace(/^\uFEFF/,""))),process.stdin.on("error",e),process.stdin.resume()})}export{r as readStdin};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function t(o){return`mcp__puku_cli__${o}`}function e(){return(o)=>t(o)}export{t as getToolName,e as createToolNamer};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{existsSync as z,copyFileSync as Q}from"node:fs";import{execSync as J}from"node:child_process";import{resolve as G,dirname as Y}from"node:path";import{fileURLToPath as Z}from"node:url";var $=Y(Z(import.meta.url)),M=G($,".."),j=["better-sqlite3"];function L(){for(let q of j){let H=G(M,"node_modules",q);if(!z(H))try{J(`npm install ${q} --no-package-lock --no-save --silent`,{cwd:M,stdio:"pipe",timeout:120000})}catch{}else if(!z(G(H,"build","Release"))&&!z(G(H,"prebuilds")))try{J(`npm rebuild ${q} --ignore-scripts=false`,{cwd:M,stdio:"pipe",timeout:120000})}catch{}}}function W(q){try{return J(`node -e "new (require('better-sqlite3'))(':memory:').close()"`,{cwd:q,stdio:"pipe",timeout:1e4}),!0}catch{return!1}}function U(q){try{let H=process.versions.modules,O=G(q,"node_modules","better-sqlite3","build","Release"),w=G(O,"better_sqlite3.node"),K=G(O,`better_sqlite3.abi${H}.node`);if(!z(O))return;if(z(K)){if(Q(K,w),X(w),W(q))return}if(!z(w))return;if(W(q))Q(w,K);else if(J("npm rebuild better-sqlite3",{cwd:q,stdio:"pipe",timeout:60000}),X(w),z(w))Q(w,K)}catch{}}function X(q){if(process.platform==="darwin")try{J(`codesign --sign - --force "${q}"`,{stdio:"pipe",timeout:1e4})}catch{}}L();U(M);export{U as ensureNativeCompat,L as ensureDeps,X as codesignBinary};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import"./suppress-stderr.mjs";import"./ensure-deps.mjs";import{readStdin as N,getSessionId as Q,getSessionDBPath as V}from"./session-helpers.mjs";import{createSessionLoaders as W}from"./session-loaders.mjs";import{dirname as X}from"node:path";import{fileURLToPath as Y}from"node:url";var Z=X(Y(import.meta.url)),{loadSessionDB:$,loadExtract:w}=W(Z);try{let A=await N(),q=JSON.parse(A),{extractEvents:C}=await w(),{SessionDB:F}=await $(),G=V(),y=new F({dbPath:G}),z=Q(q);y.ensureSession(z,process.env.PUKU_PROJECT_DIR||process.cwd());let J=C({tool_name:q.tool_name,tool_input:q.tool_input??{},tool_response:typeof q.tool_response==="string"?q.tool_response:JSON.stringify(q.tool_response??""),tool_output:q.tool_output});for(let M of J)y.insertEvent(z,M,"PostToolUse");y.close()}catch{}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import"./suppress-stderr.mjs";import"./ensure-deps.mjs";import{readStdin as X,getSessionId as Y,getSessionDBPath as Z}from"./session-helpers.mjs";import{createSessionLoaders as $}from"./session-loaders.mjs";import{appendFileSync as k}from"node:fs";import{join as w,dirname as y}from"node:path";import{homedir as C}from"node:os";import{fileURLToPath as E}from"node:url";var F=y(E(import.meta.url)),{loadSessionDB:H,loadSnapshot:K}=$(F),T=w(C(),".claude","context-mode","precompact-debug.log");try{let z=await X(),J=JSON.parse(z),{buildResumeSnapshot:M}=await K(),{SessionDB:N}=await H(),Q=Z(),q=new N({dbPath:Q}),x=Y(J),A=q.getEvents(x);if(A.length>0){let V=q.getSessionStats(x),W=M(A,{compactCount:(V?.compact_count??0)+1});q.upsertResume(x,W,A.length),q.incrementCompactCount(x)}q.close()}catch(z){try{k(T,`[${new Date().toISOString()}] ${z.message}
|
|
3
|
+
`)}catch{}}console.log(JSON.stringify({}));
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import"./suppress-stderr.mjs";import{readFileSync as N,writeFileSync as $,existsSync as Q,rmSync as c,mkdirSync as F,copyFileSync as k,readdirSync as u}from"node:fs";import{resolve as q,dirname as H,basename as R}from"node:path";import{fileURLToPath as x}from"node:url";import{homedir as M,tmpdir as v}from"node:os";import{readStdin as g}from"./core/stdin.mjs";import{routePreToolUse as D,initSecurity as P}from"./core/routing.mjs";import{formatDecision as S}from"./core/formatters.mjs";function T(W,z){F(z,{recursive:!0});for(let X of u(W,{withFileTypes:!0})){let A=q(W,X.name),Y=q(z,X.name);if(X.isDirectory())T(A,Y);else k(A,Y)}}try{let W=H(x(import.meta.url)),z=q(W,".."),A=JSON.parse(N(q(z,"package.json"),"utf-8")).version??"unknown",Y=R(z),f=H(z),I=q(v(),`context-mode-healed-${A}`),j=z.includes("/plugins/cache/")||z.includes("\\plugins\\cache\\");if(A!=="unknown"&&j&&!Q(I)){let J=q(f,A);if(Y!==A&&!Q(J)){T(z,J);let B=q(J,"start.mjs");if(!Q(B))$(B,["#!/usr/bin/env node",'import { existsSync } from "node:fs";','import { dirname, resolve } from "node:path";','import { fileURLToPath } from "node:url";',"const __dirname = dirname(fileURLToPath(import.meta.url));","process.chdir(__dirname);","if (!process.env.PUKU_PROJECT_DIR) process.env.PUKU_PROJECT_DIR = process.cwd();",'if (existsSync(resolve(__dirname, "server.bundle.mjs"))) {',' await import("./server.bundle.mjs");','} else if (existsSync(resolve(__dirname, "build", "server.js"))) {',' await import("./build/server.js");',"}"].join(`
|
|
3
|
+
`),"utf-8")}let b=Q(J)?J:z,C=q(M(),".claude","plugins","installed_plugins.json");if(Q(C)){let B=JSON.parse(N(C,"utf-8"));for(let[Z,K]of Object.entries(B.plugins||{})){if(!Z.toLowerCase().includes("context-mode"))continue;for(let E of K)E.installPath=b,E.version=A,E.lastUpdated=new Date().toISOString()}$(C,JSON.stringify(B,null,2)+`
|
|
4
|
+
`,"utf-8")}let L=q(M(),".claude","settings.json");try{let B=JSON.parse(N(L,"utf-8")),Z=B.hooks||{},K=!1;for(let E of Object.keys(Z)){let _=Z[E];if(!Array.isArray(_))continue;for(let O of _){if(E==="PreToolUse"&&O.matcher?.includes("Task")&&!O.matcher.includes("Agent"))O.matcher=O.matcher.replace("Task","Agent|Task"),K=!0;for(let G of O.hooks||[])if(G.command&&G.command.includes(".mjs")&&G.command.includes("context-mode")&&!G.command.includes(b)){let U=G.command.match(/([a-z]+\.mjs)\s*"?\s*$/);if(U)G.command="node "+q(b,"hooks",U[1]),K=!0}}}if(K)$(L,JSON.stringify(B,null,2)+`
|
|
5
|
+
`,"utf-8")}catch{}$(I,Date.now().toString(),"utf-8")}}catch{}var p=H(x(import.meta.url));await P(q(p,"..","build"));var l=await g(),V=JSON.parse(l),d=V.tool_name??"",h=V.tool_input??{},m=D(d,h,process.env.PUKU_PROJECT_DIR),w=S(m);if(w!==null)process.stdout.write(JSON.stringify(w)+`
|
|
6
|
+
`);
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import{createToolNamer as x}from"./core/tool-naming.mjs";function z(b,v={}){let{includeCommands:w=!0}=v;return`
|
|
2
|
+
<context_window_protection>
|
|
3
|
+
<priority_instructions>
|
|
4
|
+
Raw tool output floods your context window. You MUST use context-mode MCP tools to keep raw data in the sandbox.
|
|
5
|
+
</priority_instructions>
|
|
6
|
+
|
|
7
|
+
<tool_selection_hierarchy>
|
|
8
|
+
1. GATHER: ${b("ctx_batch_execute")}(commands, queries)
|
|
9
|
+
- Primary tool for research. Runs all commands, auto-indexes, and searches.
|
|
10
|
+
- ONE call replaces many individual steps.
|
|
11
|
+
- Each command: {label: "descriptive section header", command: "shell command"}
|
|
12
|
+
- label becomes the FTS5 chunk title — use descriptive labels for better search.
|
|
13
|
+
2. FOLLOW-UP: ${b("ctx_search")}(queries: ["q1", "q2", ...])
|
|
14
|
+
- Use for all follow-up questions. ONE call, many queries.
|
|
15
|
+
3. PROCESSING: ${b("ctx_execute")}(language, code) | ${b("ctx_execute_file")}(path, language, code)
|
|
16
|
+
- Use for API calls, log analysis, and data processing.
|
|
17
|
+
</tool_selection_hierarchy>
|
|
18
|
+
|
|
19
|
+
<forbidden_actions>
|
|
20
|
+
- DO NOT use Bash for commands producing >20 lines of output.
|
|
21
|
+
- DO NOT use Read for analysis (use execute_file). Read IS correct for files you intend to Edit.
|
|
22
|
+
- DO NOT use WebFetch (use ${b("ctx_fetch_and_index")} instead).
|
|
23
|
+
- Bash is ONLY for git/mkdir/rm/mv/navigation.
|
|
24
|
+
- DO NOT use ${b("ctx_execute")} or ${b("ctx_execute_file")} to create, modify, or overwrite files.
|
|
25
|
+
ctx_execute is for data analysis, log processing, and computation only.
|
|
26
|
+
</forbidden_actions>
|
|
27
|
+
|
|
28
|
+
<file_writing_policy>
|
|
29
|
+
ALWAYS use the native Write tool to create files and Edit tool to modify files.
|
|
30
|
+
NEVER use ${b("ctx_execute")}, ${b("ctx_execute_file")}, or Bash to write file content.
|
|
31
|
+
This applies to all file types: code, configs, plans, specs, YAML, JSON, markdown.
|
|
32
|
+
</file_writing_policy>
|
|
33
|
+
|
|
34
|
+
<output_constraints>
|
|
35
|
+
<word_limit>Keep your final response under 500 words.</word_limit>
|
|
36
|
+
<artifact_policy>
|
|
37
|
+
Write artifacts (code, configs, PRDs) to FILES using the native Write tool. NEVER return them as inline text.
|
|
38
|
+
Use Edit tool for modifications to existing files.
|
|
39
|
+
Return only: file path + 1-line description.
|
|
40
|
+
</artifact_policy>
|
|
41
|
+
<response_format>
|
|
42
|
+
Your response must be a concise summary:
|
|
43
|
+
- Actions taken (2-3 bullets)
|
|
44
|
+
- File paths created/modified
|
|
45
|
+
- Knowledge base source labels (so parent can search)
|
|
46
|
+
- Key findings
|
|
47
|
+
</response_format>
|
|
48
|
+
</output_constraints>
|
|
49
|
+
${w?`
|
|
50
|
+
<ctx_commands>
|
|
51
|
+
When the user says "ctx stats", "ctx-stats", "/ctx-stats", or asks about context savings:
|
|
52
|
+
→ Call the stats MCP tool and display the full output verbatim.
|
|
53
|
+
|
|
54
|
+
When the user says "ctx doctor", "ctx-doctor", "/ctx-doctor", or asks to diagnose context-mode:
|
|
55
|
+
→ Call the doctor MCP tool, execute the returned shell command, display results as a checklist.
|
|
56
|
+
|
|
57
|
+
When the user says "ctx upgrade", "ctx-upgrade", "/ctx-upgrade", or asks to update context-mode:
|
|
58
|
+
→ Call the upgrade MCP tool, execute the returned shell command, display results as a checklist.
|
|
59
|
+
|
|
60
|
+
When the user says "ctx purge", "ctx-purge", "/ctx-purge", or asks to wipe/reset the knowledge base:
|
|
61
|
+
→ Call the purge MCP tool with confirm: true. Warn the user this is irreversible.
|
|
62
|
+
|
|
63
|
+
After /clear or /compact: knowledge base and session stats are preserved. Inform the user: "context-mode knowledge base preserved. Use \`ctx purge\` if you want to start fresh."
|
|
64
|
+
</ctx_commands>
|
|
65
|
+
`:""}
|
|
66
|
+
</context_window_protection>`}function A(b){return`<context_guidance>
|
|
67
|
+
<tip>
|
|
68
|
+
If you are reading this file to Edit it, Read is the correct tool — Edit needs file content in context.
|
|
69
|
+
If you are reading to analyze or explore, use `+b("ctx_execute_file")+`(path, language, code) instead — only your printed summary will enter the context.
|
|
70
|
+
</tip>
|
|
71
|
+
</context_guidance>`}function D(b){return`<context_guidance>
|
|
72
|
+
<tip>
|
|
73
|
+
This operation may flood your context window. To stay efficient:
|
|
74
|
+
- Use `+b("ctx_execute")+`(language: "shell", code: "...") to run searches in the sandbox.
|
|
75
|
+
- Only your final printed summary will enter the context.
|
|
76
|
+
</tip>
|
|
77
|
+
</context_guidance>`}function E(b){return`<context_guidance>
|
|
78
|
+
<tip>
|
|
79
|
+
This Bash command may produce large output. To stay efficient:
|
|
80
|
+
- Use `+b("ctx_batch_execute")+`(commands, queries) for multiple commands
|
|
81
|
+
- Use `+b("ctx_execute")+`(language: "shell", code: "...") to run in sandbox
|
|
82
|
+
- Only your final printed summary will enter the context.
|
|
83
|
+
- Bash is best for: git, mkdir, rm, mv, navigation, and short-output commands only.
|
|
84
|
+
</tip>
|
|
85
|
+
</context_guidance>`}var q=x(),I=z(q),J=A(q),K=D(q),L=E(q);export{z as createRoutingBlock,A as createReadGuidance,D as createGrepGuidance,E as createBashGuidance,I as ROUTING_BLOCK,J as READ_GUIDANCE,K as GREP_GUIDANCE,L as BASH_GUIDANCE};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import{createRequire as R}from"node:module";import{existsSync as v,unlinkSync as T,renameSync as L}from"node:fs";import{tmpdir as N}from"node:os";import{join as w}from"node:path";var l=class{#t;constructor(t){this.#t=t}pragma(t){let e=this.#t.prepare(`PRAGMA ${t}`).all();if(!e||e.length===0)return;if(e.length>1)return e;let r=Object.values(e[0]);return r.length===1?r[0]:e[0]}exec(t){let s="",e=null;for(let o=0;o<t.length;o++){let a=t[o];if(e)s+=a,a===e&&(e=null);else if(a==="'"||a==='"')s+=a,e=a;else if(a===";"){let u=s.trim();u&&this.#t.prepare(u).run(),s=""}else s+=a}let r=s.trim();return r&&this.#t.prepare(r).run(),this}prepare(t){let s=this.#t.prepare(t);return{run:(...e)=>s.run(...e),get:(...e)=>{let r=s.get(...e);return r===null?void 0:r},all:(...e)=>s.all(...e),iterate:(...e)=>s.iterate(...e)}}transaction(t){return this.#t.transaction(t)}close(){this.#t.close()}},p=class{#t;constructor(t){this.#t=t}pragma(t){let e=this.#t.prepare(`PRAGMA ${t}`).all();if(!e||e.length===0)return;if(e.length>1)return e;let r=Object.values(e[0]);return r.length===1?r[0]:e[0]}exec(t){return this.#t.exec(t),this}prepare(t){let s=this.#t.prepare(t);return{run:(...e)=>s.run(...e),get:(...e)=>s.get(...e),all:(...e)=>s.all(...e),iterate:(...e)=>typeof s.iterate=="function"?s.iterate(...e):s.all(...e)[Symbol.iterator]()}}transaction(t){return(...s)=>{this.#t.exec("BEGIN");try{let e=t(...s);return this.#t.exec("COMMIT"),e}catch(e){throw this.#t.exec("ROLLBACK"),e}}}close(){this.#t.close()}},c=null;function O(){if(!c){let n=R(import.meta.url);if(globalThis.Bun){let t=n(["bun","sqlite"].join(":")).Database;c=function(e,r){let o=new t(e,{readonly:r?.readonly,create:!0}),a=new l(o);return r?.timeout&&a.pragma(`busy_timeout = ${r.timeout}`),a}}else if(process.platform==="linux")try{let{DatabaseSync:t}=n(["node","sqlite"].join(":"));c=function(e,r){let o=new t(e,{readOnly:r?.readonly??!1});return new p(o)}}catch{c=n("better-sqlite3")}else c=n("better-sqlite3")}return c}function g(n){n.pragma("journal_mode = WAL"),n.pragma("synchronous = NORMAL");try{n.pragma("mmap_size = 268435456")}catch{}}function h(n){if(!v(n))for(let t of["-wal","-shm"])try{T(n+t)}catch{}}function D(n){for(let t of["","-wal","-shm"])try{T(n+t)}catch{}}function _(n){try{n.pragma("wal_checkpoint(TRUNCATE)")}catch{}try{n.close()}catch{}}function y(n="context-mode"){return w(N(),`${n}-${process.pid}.db`)}function b(n,t=[100,500,2e3]){let s;for(let e=0;e<=t.length;e++)try{return n()}catch(r){let o=r instanceof Error?r.message:String(r);if(!o.includes("SQLITE_BUSY")&&!o.includes("database is locked"))throw r;if(s=r instanceof Error?r:new Error(o),e<t.length){let a=t[e],u=Date.now();for(;Date.now()-u<a;);}}throw new Error(`SQLITE_BUSY: database is locked after ${t.length} retries. Original error: ${s?.message}`)}function I(n){return n.includes("SQLITE_CORRUPT")||n.includes("SQLITE_NOTADB")||n.includes("database disk image is malformed")||n.includes("file is not a database")}function C(n){let t=Date.now();for(let s of["","-wal","-shm"])try{L(n+s,`${n}${s}.corrupt-${t}`)}catch{}}var d=Symbol.for("__context_mode_live_dbs__"),m=(()=>{let n=globalThis;return n[d]||(n[d]=new Set,process.on("exit",()=>{for(let t of n[d])_(t);n[d].clear()})),n[d]})(),E=class{#t;#e;constructor(t){let s=O();this.#t=t,h(t);let e;try{e=new s(t,{timeout:3e4}),g(e)}catch(r){let o=r instanceof Error?r.message:String(r);if(I(o)){C(t),h(t);try{e=new s(t,{timeout:3e4}),g(e)}catch(a){throw new Error(`Failed to create fresh DB after renaming corrupt file: ${a instanceof Error?a.message:String(a)}`)}}else throw r}this.#e=e,m.add(this.#e),this.initSchema(),this.prepareStatements()}get db(){return this.#e}get dbPath(){return this.#t}close(){m.delete(this.#e),_(this.#e)}withRetry(t){return b(t)}cleanup(){m.delete(this.#e),_(this.#e),D(this.#t)}};import{createHash as S}from"node:crypto";import{execFileSync as A}from"node:child_process";function Y(){let n=process.env.CONTEXT_MODE_SESSION_SUFFIX;if(n!==void 0)return n?`__${n}`:"";try{let t=process.cwd(),s=A("git",["worktree","list","--porcelain"],{encoding:"utf-8",timeout:2e3,stdio:["ignore","pipe","ignore"]}).split(/\r?\n/).find(e=>e.startsWith("worktree "))?.replace("worktree ","")?.trim();if(s&&t!==s)return`__${S("sha256").update(t).digest("hex").slice(0,8)}`}catch{}return""}var x=1e3,M=5,i={insertEvent:"insertEvent",getEvents:"getEvents",getEventsByType:"getEventsByType",getEventsByPriority:"getEventsByPriority",getEventsByTypeAndPriority:"getEventsByTypeAndPriority",getEventCount:"getEventCount",checkDuplicate:"checkDuplicate",evictLowestPriority:"evictLowestPriority",updateMetaLastEvent:"updateMetaLastEvent",ensureSession:"ensureSession",getSessionStats:"getSessionStats",incrementCompactCount:"incrementCompactCount",upsertResume:"upsertResume",getResume:"getResume",markResumeConsumed:"markResumeConsumed",deleteEvents:"deleteEvents",deleteMeta:"deleteMeta",deleteResume:"deleteResume",getOldSessions:"getOldSessions"},f=class extends E{constructor(t){super(t?.dbPath??y("session"))}stmt(t){return this.stmts.get(t)}initSchema(){try{let s=this.db.pragma("table_xinfo(session_events)").find(e=>e.name==="data_hash");s&&s.hidden!==0&&this.db.exec("DROP TABLE session_events")}catch{}this.db.exec(`
|
|
2
|
+
CREATE TABLE IF NOT EXISTS session_events (
|
|
3
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
4
|
+
session_id TEXT NOT NULL,
|
|
5
|
+
type TEXT NOT NULL,
|
|
6
|
+
category TEXT NOT NULL,
|
|
7
|
+
priority INTEGER NOT NULL DEFAULT 2,
|
|
8
|
+
data TEXT NOT NULL,
|
|
9
|
+
source_hook TEXT NOT NULL,
|
|
10
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
11
|
+
data_hash TEXT NOT NULL DEFAULT ''
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
CREATE INDEX IF NOT EXISTS idx_session_events_session ON session_events(session_id);
|
|
15
|
+
CREATE INDEX IF NOT EXISTS idx_session_events_type ON session_events(session_id, type);
|
|
16
|
+
CREATE INDEX IF NOT EXISTS idx_session_events_priority ON session_events(session_id, priority);
|
|
17
|
+
|
|
18
|
+
CREATE TABLE IF NOT EXISTS session_meta (
|
|
19
|
+
session_id TEXT PRIMARY KEY,
|
|
20
|
+
project_dir TEXT NOT NULL,
|
|
21
|
+
started_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
22
|
+
last_event_at TEXT,
|
|
23
|
+
event_count INTEGER NOT NULL DEFAULT 0,
|
|
24
|
+
compact_count INTEGER NOT NULL DEFAULT 0
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
CREATE TABLE IF NOT EXISTS session_resume (
|
|
28
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
29
|
+
session_id TEXT NOT NULL UNIQUE,
|
|
30
|
+
snapshot TEXT NOT NULL,
|
|
31
|
+
event_count INTEGER NOT NULL,
|
|
32
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
33
|
+
consumed INTEGER NOT NULL DEFAULT 0
|
|
34
|
+
);
|
|
35
|
+
`)}prepareStatements(){this.stmts=new Map;let t=(s,e)=>{this.stmts.set(s,this.db.prepare(e))};t(i.insertEvent,`INSERT INTO session_events (session_id, type, category, priority, data, source_hook, data_hash)
|
|
36
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`),t(i.getEvents,`SELECT id, session_id, type, category, priority, data, source_hook, created_at, data_hash
|
|
37
|
+
FROM session_events WHERE session_id = ? ORDER BY id ASC LIMIT ?`),t(i.getEventsByType,`SELECT id, session_id, type, category, priority, data, source_hook, created_at, data_hash
|
|
38
|
+
FROM session_events WHERE session_id = ? AND type = ? ORDER BY id ASC LIMIT ?`),t(i.getEventsByPriority,`SELECT id, session_id, type, category, priority, data, source_hook, created_at, data_hash
|
|
39
|
+
FROM session_events WHERE session_id = ? AND priority >= ? ORDER BY id ASC LIMIT ?`),t(i.getEventsByTypeAndPriority,`SELECT id, session_id, type, category, priority, data, source_hook, created_at, data_hash
|
|
40
|
+
FROM session_events WHERE session_id = ? AND type = ? AND priority >= ? ORDER BY id ASC LIMIT ?`),t(i.getEventCount,"SELECT COUNT(*) AS cnt FROM session_events WHERE session_id = ?"),t(i.checkDuplicate,`SELECT 1 FROM (
|
|
41
|
+
SELECT type, data_hash FROM session_events
|
|
42
|
+
WHERE session_id = ? ORDER BY id DESC LIMIT ?
|
|
43
|
+
) AS recent
|
|
44
|
+
WHERE recent.type = ? AND recent.data_hash = ?
|
|
45
|
+
LIMIT 1`),t(i.evictLowestPriority,`DELETE FROM session_events WHERE id = (
|
|
46
|
+
SELECT id FROM session_events WHERE session_id = ?
|
|
47
|
+
ORDER BY priority ASC, id ASC LIMIT 1
|
|
48
|
+
)`),t(i.updateMetaLastEvent,`UPDATE session_meta
|
|
49
|
+
SET last_event_at = datetime('now'), event_count = event_count + 1
|
|
50
|
+
WHERE session_id = ?`),t(i.ensureSession,"INSERT OR IGNORE INTO session_meta (session_id, project_dir) VALUES (?, ?)"),t(i.getSessionStats,`SELECT session_id, project_dir, started_at, last_event_at, event_count, compact_count
|
|
51
|
+
FROM session_meta WHERE session_id = ?`),t(i.incrementCompactCount,"UPDATE session_meta SET compact_count = compact_count + 1 WHERE session_id = ?"),t(i.upsertResume,`INSERT INTO session_resume (session_id, snapshot, event_count)
|
|
52
|
+
VALUES (?, ?, ?)
|
|
53
|
+
ON CONFLICT(session_id) DO UPDATE SET
|
|
54
|
+
snapshot = excluded.snapshot,
|
|
55
|
+
event_count = excluded.event_count,
|
|
56
|
+
created_at = datetime('now'),
|
|
57
|
+
consumed = 0`),t(i.getResume,"SELECT snapshot, event_count, consumed FROM session_resume WHERE session_id = ?"),t(i.markResumeConsumed,"UPDATE session_resume SET consumed = 1 WHERE session_id = ?"),t(i.deleteEvents,"DELETE FROM session_events WHERE session_id = ?"),t(i.deleteMeta,"DELETE FROM session_meta WHERE session_id = ?"),t(i.deleteResume,"DELETE FROM session_resume WHERE session_id = ?"),t(i.getOldSessions,"SELECT session_id FROM session_meta WHERE started_at < datetime('now', ? || ' days')")}insertEvent(t,s,e="PostToolUse"){let r=S("sha256").update(s.data).digest("hex").slice(0,16).toUpperCase(),o=this.db.transaction(()=>{if(this.stmt(i.checkDuplicate).get(t,M,s.type,r))return;this.stmt(i.getEventCount).get(t).cnt>=x&&this.stmt(i.evictLowestPriority).run(t),this.stmt(i.insertEvent).run(t,s.type,s.category,s.priority,s.data,e,r),this.stmt(i.updateMetaLastEvent).run(t)});this.withRetry(()=>o())}getEvents(t,s){let e=s?.limit??1e3,r=s?.type,o=s?.minPriority;return r&&o!==void 0?this.stmt(i.getEventsByTypeAndPriority).all(t,r,o,e):r?this.stmt(i.getEventsByType).all(t,r,e):o!==void 0?this.stmt(i.getEventsByPriority).all(t,o,e):this.stmt(i.getEvents).all(t,e)}getEventCount(t){return this.stmt(i.getEventCount).get(t).cnt}ensureSession(t,s){this.stmt(i.ensureSession).run(t,s)}getSessionStats(t){return this.stmt(i.getSessionStats).get(t)??null}incrementCompactCount(t){this.stmt(i.incrementCompactCount).run(t)}upsertResume(t,s,e){this.stmt(i.upsertResume).run(t,s,e??0)}getResume(t){return this.stmt(i.getResume).get(t)??null}markResumeConsumed(t){this.stmt(i.markResumeConsumed).run(t)}deleteSession(t){this.db.transaction(()=>{this.stmt(i.deleteEvents).run(t),this.stmt(i.deleteResume).run(t),this.stmt(i.deleteMeta).run(t)})()}cleanupOldSessions(t=7){let s=`-${t}`,e=this.stmt(i.getOldSessions).all(s);for(let{session_id:r}of e)this.deleteSession(r);return e.length}};export{f as SessionDB,Y as getWorktreeSuffix};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import{writeFileSync as j}from"node:fs";function w(G){let _={},H="";for(let V of G){if(V.category==="prompt"){H=V.data;continue}if(!_[V.category])_[V.category]=[];_[V.category].push(V)}let J=new Set;for(let V of _.file||[]){let L=(V.data.includes(" in ")?V.data.split(" in ").pop():V.data)?.split(/[/\\]/).pop()?.trim();if(L&&!L.includes("*"))J.add(L)}return{grouped:_,lastPrompt:H,fileNames:J}}function M(G,_){let{grouped:H,lastPrompt:J,fileNames:V}=w(G),z=[];if(z.push("# Session Resume"),z.push(""),z.push(`Events: ${G.length} | Timestamp: ${new Date().toISOString()}`),z.push(""),V.size>0){z.push("## Active Files"),z.push("");for(let L of V)z.push(`- ${L}`);z.push("")}if(H.rule?.length>0){z.push("## Project Rules"),z.push("");for(let L of H.rule)if(L.type==="rule_content"){let B=L.data.replace(/^(#{1,3}) /gm,($,K)=>"#".repeat(K.length+3)+" ");z.push(B),z.push("")}else z.push(`- ${L.data}`);z.push("")}if(H.task?.length>0){let L=[],B={};for(let U of H.task)try{let Y=JSON.parse(U.data);if(Y.subject)L.push(Y.subject);else if(Y.taskId&&Y.status)B[Y.taskId]=Y.status}catch{L.push(U.data)}let $=new Set(["completed","deleted","failed"]),K=Object.keys(B).sort((U,Y)=>Number(U)-Number(Y)),Q=[],X=[];for(let U=0;U<L.length;U++){let Y=K[U],Z=Y?B[Y]||"pending":"pending";if($.has(Z))X.push(L[U]);else Q.push(L[U])}if(Q.length>0){z.push("## Tasks In Progress"),z.push("");for(let U of Q)z.push(`- ${U}`);z.push("")}if(X.length>0){z.push("## Tasks Completed"),z.push("");for(let U of X)z.push(`- ${U}`);z.push("")}}if(H.decision?.length>0){z.push("## User Decisions"),z.push("");for(let L of H.decision)z.push(`- ${L.data}`);z.push("")}if(H.git?.length>0){z.push("## Git Operations"),z.push("");for(let L of H.git)z.push(`- ${L.data}`);z.push("")}if(H.env?.length>0||H.cwd?.length>0){if(z.push("## Environment"),z.push(""),H.cwd?.length>0)z.push(`- cwd: ${H.cwd[H.cwd.length-1].data}`);for(let L of H.env||[])z.push(`- ${L.data}`);z.push("")}if(H.error?.length>0){z.push("## Errors Encountered"),z.push("");for(let L of H.error)z.push(`- ${L.data}`);z.push("")}if(H.mcp?.length>0){let L={};for(let B of H.mcp){let $=B.data.split(":")[0].trim();L[$]=(L[$]||0)+1}z.push("## MCP Tool Usage"),z.push("");for(let[B,$]of Object.entries(L))z.push(`- ${B}: ${$} calls`);z.push("")}if(H.subagent?.length>0){z.push("## Subagent Tasks"),z.push("");for(let L of H.subagent)z.push(`- ${L.data}`);z.push("")}if(H.skill?.length>0){let L=new Set(H.skill.map((B)=>B.data));z.push("## Active Skills"),z.push(""),z.push(`- ${[...L].join(", ")}`),z.push("")}if(H.intent?.length>0)z.push("## Session Intent"),z.push(""),z.push(`- ${H.intent[H.intent.length-1].data}`),z.push("");if(H.role?.length>0)z.push("## User Role"),z.push(""),z.push(`- ${H.role[H.role.length-1].data}`),z.push("");if(H.data?.length>0){z.push("## Data References"),z.push("");for(let L of H.data)z.push(`- ${L.data}`);z.push("")}if(H.plan?.length>0){let L=H.plan.some((Q)=>Q.type==="plan_approved"),B=H.plan.some((Q)=>Q.type==="plan_rejected"),$=H.plan[H.plan.length-1],K=$.type==="plan_enter"||$.type==="plan_file_write";if(z.push("## Plan Mode"),z.push(""),L)z.push("- Status: APPROVED AND EXECUTED");else if(B)z.push("- Status: REJECTED BY USER");else if(K)z.push("- Status: ACTIVE (in planning)");else z.push("- Status: COMPLETED");for(let Q of H.plan)z.push(`- ${Q.data}`);z.push("")}if(J)z.push("## Last User Prompt"),z.push(""),z.push(J),z.push("");return j(_,z.join(`
|
|
2
|
+
`),"utf-8"),{grouped:H,lastPrompt:J,fileNames:V}}function R(G,_,H){let{grouped:J,lastPrompt:V,fileNames:z}=_,L=G==="compact",B=`
|
|
3
|
+
<session_knowledge source="${L?"compact":"continue"}">`;if(B+=`
|
|
4
|
+
<session_guide>`,V){let K=V.length>300?V.substring(0,297)+"...":V;B+=`
|
|
5
|
+
## Last Request`,B+=`
|
|
6
|
+
${K}`,B+=`
|
|
7
|
+
`}if(J.task?.length>0){let K=[],Q={};for(let X of J.task)try{let U=JSON.parse(X.data);if(U.subject)K.push(U.subject);else if(U.taskId&&U.status)Q[U.taskId]=U.status}catch{}if(K.length>0){let X=new Set(["completed","deleted","failed"]),U=Object.keys(Q).sort((Z,T)=>Number(Z)-Number(T)),Y=[];for(let Z=0;Z<K.length;Z++){let T=U[Z],W=T?Q[T]||"pending":"pending";if(!X.has(W))Y.push(K[Z])}if(Y.length>0){B+=`
|
|
8
|
+
## Pending Tasks`;for(let Z of Y)B+=`
|
|
9
|
+
- ${Z}`;B+=`
|
|
10
|
+
`}}}if(J.decision?.length>0){B+=`
|
|
11
|
+
## Key Decisions`;for(let K of J.decision){let Q=K.data.length>150?K.data.substring(0,147)+"...":K.data;B+=`
|
|
12
|
+
- ${Q}`}B+=`
|
|
13
|
+
`}if(z.size>0)B+=`
|
|
14
|
+
## Files Modified`,B+=`
|
|
15
|
+
${[...z].join(", ")}`,B+=`
|
|
16
|
+
`;if(J.error?.length>0){B+=`
|
|
17
|
+
## Unresolved Errors`;for(let K of J.error){let Q=K.data.length>150?K.data.substring(0,147)+"...":K.data;B+=`
|
|
18
|
+
- ${Q}`}B+=`
|
|
19
|
+
`}if(J.git?.length>0){let K=[...new Set(J.git.map((Q)=>Q.data))];B+=`
|
|
20
|
+
## Git`,B+=`
|
|
21
|
+
${K.join(", ")}`,B+=`
|
|
22
|
+
`}if(J.rule?.length>0){let K=J.rule.filter((X)=>X.type!=="rule_content").map((X)=>{return X.data.split(/[/\\]/).slice(-2).join("/")}),Q=[...new Set(K)];if(Q.length>0)B+=`
|
|
23
|
+
## Project Rules`,B+=`
|
|
24
|
+
${Q.join(", ")}`,B+=`
|
|
25
|
+
`}if(J.mcp?.length>0){let K={};for(let Q of J.mcp){let X=Q.data.split(":")[0].trim();K[X]=(K[X]||0)+1}B+=`
|
|
26
|
+
## MCP Tools Used`,B+=`
|
|
27
|
+
${Object.entries(K).map(([Q,X])=>`${Q}(${X})`).join(", ")}`,B+=`
|
|
28
|
+
`}if(J.subagent?.length>0){B+=`
|
|
29
|
+
## Subagent Tasks`;for(let K of J.subagent){let Q=K.data.length>120?K.data.substring(0,117)+"...":K.data;B+=`
|
|
30
|
+
- ${Q}`}B+=`
|
|
31
|
+
`}if(J.skill?.length>0){let K=[...new Set(J.skill.map((Q)=>Q.data))];B+=`
|
|
32
|
+
## Skills Used`,B+=`
|
|
33
|
+
${K.join(", ")}`,B+=`
|
|
34
|
+
`}if(J.env?.length>0||J.cwd?.length>0){if(B+=`
|
|
35
|
+
## Environment`,J.cwd?.length>0)B+=`
|
|
36
|
+
cwd: ${J.cwd[J.cwd.length-1].data}`;for(let K of J.env||[])B+=`
|
|
37
|
+
${K.data}`;B+=`
|
|
38
|
+
`}if(J.data?.length>0){B+=`
|
|
39
|
+
## Data References`;for(let K of J.data){let Q=K.data.length>150?K.data.substring(0,147)+"...":K.data;B+=`
|
|
40
|
+
- ${Q}`}B+=`
|
|
41
|
+
`}if(J.intent?.length>0)B+=`
|
|
42
|
+
## Session Intent`,B+=`
|
|
43
|
+
${J.intent[J.intent.length-1].data}`,B+=`
|
|
44
|
+
`;if(J.role?.length>0)B+=`
|
|
45
|
+
## User Role`,B+=`
|
|
46
|
+
${J.role[J.role.length-1].data}`,B+=`
|
|
47
|
+
`;if(J.plan?.length>0){let K=J.plan.some((Z)=>Z.type==="plan_approved"),Q=J.plan.some((Z)=>Z.type==="plan_rejected"),X=J.plan.some((Z)=>Z.type==="plan_file_write"),U=J.plan[J.plan.length-1],Y=U.type==="plan_enter"||U.type==="plan_file_write";if(B+=`
|
|
48
|
+
## Plan Mode`,K)B+=`
|
|
49
|
+
- Status: APPROVED AND EXECUTED`,B+=`
|
|
50
|
+
- The plan was approved and executed. Do NOT re-enter plan mode or re-propose the same plan.`;else if(Q)B+=`
|
|
51
|
+
- Status: REJECTED BY USER`,B+=`
|
|
52
|
+
- The user rejected the previous plan. Ask what they want changed before re-planning.`;else if(Y){if(B+=`
|
|
53
|
+
- Status: ACTIVE (in planning phase)`,X)B+=`
|
|
54
|
+
- Plan file has been written. Awaiting user approval via ExitPlanMode.`}else B+=`
|
|
55
|
+
- Status: COMPLETED`,B+=`
|
|
56
|
+
- The plan has been executed. Do NOT re-enter plan mode or re-propose the same plan.`;B+=`
|
|
57
|
+
`}B+=`
|
|
58
|
+
</session_guide>`,B+=`
|
|
59
|
+
<session_search>`,B+=`
|
|
60
|
+
Detailed session data is indexed in context-mode FTS5 (source: "session-events").`;let $=H?H("ctx_search"):"ctx_search";if(B+=`
|
|
61
|
+
Use ${$}(queries: [...], source: "session-events") when you need specifics.`,B+=`
|
|
62
|
+
Do NOT call ctx_index() — data is already indexed.`,B+=`
|
|
63
|
+
</session_search>`,V&&L)B+=`
|
|
64
|
+
<continue_from>Continue working on the last request. Do NOT ask the user to repeat themselves.</continue_from>`;return B+=`
|
|
65
|
+
</session_knowledge>`,B}function D(G,_){return G.db.prepare(`SELECT session_id, type, category, priority, data, source_hook, created_at
|
|
66
|
+
FROM session_events WHERE session_id = ? ORDER BY created_at ASC`).all(_)}function y(G){let _=G.db.prepare(`SELECT m.session_id FROM session_meta m
|
|
67
|
+
JOIN session_events e ON m.session_id = e.session_id
|
|
68
|
+
GROUP BY m.session_id
|
|
69
|
+
ORDER BY m.started_at DESC LIMIT 1`).get();if(!_)return[];return D(G,_.session_id)}export{M as writeSessionEventsFile,w as groupEvents,D as getSessionEvents,y as getLatestSessionEvents,R as buildSessionDirective};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function o(t){return t==null?"":String(t)}function l(t){return t==null?"":typeof t=="string"?t:JSON.stringify(t)}function c(t){let{tool_name:e,tool_input:n,tool_response:s}=t,r=[];if(e==="Read"){let i=String(n.file_path??"");return/CLAUDE\.md$|\.claude[\\/]/i.test(i)&&(r.push({type:"rule",category:"rule",data:o(i),priority:1}),s&&s.length>0&&r.push({type:"rule_content",category:"rule",data:o(s),priority:1})),r.push({type:"file_read",category:"file",data:o(i),priority:1}),r}if(e==="Edit"){let i=String(n.file_path??"");return r.push({type:"file_edit",category:"file",data:o(i),priority:1}),r}if(e==="NotebookEdit"){let i=String(n.notebook_path??"");return r.push({type:"file_edit",category:"file",data:o(i),priority:1}),r}if(e==="Write"){let i=String(n.file_path??"");return r.push({type:"file_write",category:"file",data:o(i),priority:1}),r}if(e==="Glob"){let i=String(n.pattern??"");return r.push({type:"file_glob",category:"file",data:o(i),priority:3}),r}if(e==="Grep"){let i=String(n.pattern??""),a=String(n.path??"");return r.push({type:"file_search",category:"file",data:o(`${i} in ${a}`),priority:3}),r}return r}function u(t){if(t.tool_name!=="Bash")return[];let n=String(t.tool_input.command??"").match(/\bcd\s+("([^"]+)"|'([^']+)'|(\S+))/);if(!n)return[];let s=n[2]??n[3]??n[4]??"";return[{type:"cwd",category:"cwd",data:o(s),priority:2}]}function d(t){let{tool_name:e,tool_input:n,tool_response:s,tool_output:r}=t,i=String(s??""),a=r?.isError===!0;return!(e==="Bash"&&/exit code [1-9]|error:|Error:|FAIL|failed/i.test(i))&&!a?[]:[{type:"error_tool",category:"error",data:o(i),priority:2}]}var g=[{pattern:/\bgit\s+checkout\b/,operation:"branch"},{pattern:/\bgit\s+commit\b/,operation:"commit"},{pattern:/\bgit\s+merge\s+\S+/,operation:"merge"},{pattern:/\bgit\s+rebase\b/,operation:"rebase"},{pattern:/\bgit\s+stash\b/,operation:"stash"},{pattern:/\bgit\s+push\b/,operation:"push"},{pattern:/\bgit\s+pull\b/,operation:"pull"},{pattern:/\bgit\s+log\b/,operation:"log"},{pattern:/\bgit\s+diff\b/,operation:"diff"},{pattern:/\bgit\s+status\b/,operation:"status"},{pattern:/\bgit\s+branch\b/,operation:"branch"},{pattern:/\bgit\s+reset\b/,operation:"reset"},{pattern:/\bgit\s+add\b/,operation:"add"},{pattern:/\bgit\s+cherry-pick\b/,operation:"cherry-pick"},{pattern:/\bgit\s+tag\b/,operation:"tag"},{pattern:/\bgit\s+fetch\b/,operation:"fetch"},{pattern:/\bgit\s+clone\b/,operation:"clone"},{pattern:/\bgit\s+worktree\b/,operation:"worktree"}];function b(t){if(t.tool_name!=="Bash")return[];let e=String(t.tool_input.command??""),n=g.find(s=>s.pattern.test(e));return n?[{type:"git",category:"git",data:o(n.operation),priority:2}]:[]}function y(t){return new Set(["TodoWrite","TaskCreate","TaskUpdate"]).has(t.tool_name)?[{type:t.tool_name==="TaskUpdate"?"task_update":t.tool_name==="TaskCreate"?"task_create":"task",category:"task",data:o(JSON.stringify(t.tool_input)),priority:1}]:[]}function f(t){if(t.tool_name==="EnterPlanMode")return[{type:"plan_enter",category:"plan",data:"entered plan mode",priority:2}];if(t.tool_name==="ExitPlanMode"){let e=[],n=t.tool_input.allowedPrompts,s=Array.isArray(n)&&n.length>0?`exited plan mode (allowed: ${l(n.map(i=>typeof i=="object"&&i!==null&&"prompt"in i?String(i.prompt):String(i)).join(", "))})`:"exited plan mode";e.push({type:"plan_exit",category:"plan",data:o(s),priority:2});let r=String(t.tool_response??"").toLowerCase();return r.includes("approved")||r.includes("approve")?e.push({type:"plan_approved",category:"plan",data:"plan approved by user",priority:1}):(r.includes("rejected")||r.includes("decline")||r.includes("denied"))&&e.push({type:"plan_rejected",category:"plan",data:o(`plan rejected: ${t.tool_response??""}`),priority:2}),e}if(t.tool_name==="Write"||t.tool_name==="Edit"){let e=String(t.tool_input.file_path??"");if(/[/\\]\.claude[/\\]plans[/\\]/.test(e))return[{type:"plan_file_write",category:"plan",data:o(`plan file: ${e.split(/[/\\]/).pop()??e}`),priority:2}]}return[]}var h=[/\bsource\s+\S*activate\b/,/\bexport\s+\w+=/,/\bnvm\s+use\b/,/\bpyenv\s+(shell|local|global)\b/,/\bconda\s+activate\b/,/\brbenv\s+(shell|local|global)\b/,/\bnpm\s+install\b/,/\bnpm\s+ci\b/,/\bpip\s+install\b/,/\bbun\s+install\b/,/\byarn\s+(add|install)\b/,/\bpnpm\s+(add|install)\b/,/\bcargo\s+(install|add)\b/,/\bgo\s+(install|get)\b/,/\brustup\b/,/\basdf\b/,/\bvolta\b/,/\bdeno\s+install\b/];function _(t){if(t.tool_name!=="Bash")return[];let e=String(t.tool_input.command??"");if(!h.some(r=>r.test(e)))return[];let s=e.replace(/\bexport\s+(\w+)=\S*/g,"export $1=***");return[{type:"env",category:"env",data:o(s),priority:2}]}function m(t){if(t.tool_name!=="Skill")return[];let e=String(t.tool_input.skill??"");return[{type:"skill",category:"skill",data:o(e),priority:3}]}function S(t){if(t.tool_name!=="Agent")return[];let e=o(String(t.tool_input.prompt??t.tool_input.description??"")),n=t.tool_response?o(String(t.tool_response)):"",s=n.length>0;return[{type:s?"subagent_completed":"subagent_launched",category:"subagent",data:o(s?`[completed] ${e} \u2192 ${n}`:`[launched] ${e}`),priority:s?2:3}]}function k(t){let{tool_name:e,tool_input:n}=t;if(!e.startsWith("mcp__"))return[];let s=e.split("__"),r=s[s.length-1]||e,i=Object.values(n).find(p=>typeof p=="string"),a=i?`: ${o(String(i))}`:"";return[{type:"mcp",category:"mcp",data:o(`${r}${a}`),priority:3}]}function E(t){if(t.tool_name!=="AskUserQuestion")return[];let e=t.tool_input.questions,n=Array.isArray(e)&&e.length>0?String(e[0].question??""):"",s=o(String(t.tool_response??"")),r=n?`Q: ${o(n)} \u2192 A: ${s}`:`answer: ${s}`;return[{type:"decision_question",category:"decision",data:o(r),priority:2}]}function v(t){if(t.tool_name!=="EnterWorktree")return[];let e=String(t.tool_input.name??"unnamed");return[{type:"worktree",category:"env",data:o(`entered worktree: ${e}`),priority:2}]}var x=[/\b(don'?t|do not|never|always|instead|rather|prefer)\b/i,/\b(use|switch to|go with|pick|choose)\s+\w+\s+(instead|over|not)\b/i,/\b(no,?\s+(use|do|try|make))\b/i,/\b(hayır|hayir|evet|böyle|boyle|degil|değil|yerine|kullan)\b/i];function w(t){return x.some(n=>n.test(t))?[{type:"decision",category:"decision",data:o(t),priority:2}]:[]}var T=[/\b(act as|you are|behave like|pretend|role of|persona)\b/i,/\b(senior|staff|principal|lead)\s+(engineer|developer|architect)\b/i,/\b(gibi davran|rolünde|olarak çalış)\b/i];function R(t){return T.some(n=>n.test(t))?[{type:"role",category:"role",data:o(t),priority:3}]:[]}var A=[{mode:"investigate",pattern:/\b(why|how does|explain|understand|what is|analyze|debug|look into)\b/i},{mode:"implement",pattern:/\b(create|add|build|implement|write|make|develop|fix)\b/i},{mode:"discuss",pattern:/\b(think about|consider|should we|what if|pros and cons|opinion)\b/i},{mode:"review",pattern:/\b(review|check|audit|verify|test|validate)\b/i}];function I(t){let e=A.find(({pattern:n})=>n.test(t));return e?[{type:"intent",category:"intent",data:o(e.mode),priority:4}]:[]}function $(t){return t.length<=1024?[]:[{type:"data",category:"data",data:o(t),priority:4}]}function P(t){try{let e=[];return e.push(...c(t)),e.push(...u(t)),e.push(...d(t)),e.push(...b(t)),e.push(..._(t)),e.push(...y(t)),e.push(...f(t)),e.push(...m(t)),e.push(...S(t)),e.push(...k(t)),e.push(...E(t)),e.push(...v(t)),e}catch{return[]}}function H(t){try{let e=[];return e.push(...w(t)),e.push(...R(t)),e.push(...I(t)),e.push(...$(t)),e}catch{return[]}}export{P as extractEvents,H as extractUserEvents};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{execFileSync as N}from"node:child_process";import{createHash as G}from"node:crypto";import{join as C}from"node:path";import{mkdirSync as J}from"node:fs";import{homedir as L}from"node:os";function M(){let b=process.env.CONTEXT_MODE_SESSION_SUFFIX;if(b!==void 0)return b?`__${b}`:"";try{let q=process.cwd(),z=N("git",["worktree","list","--porcelain"],{encoding:"utf-8",timeout:2000,stdio:["ignore","pipe","ignore"]}).split(/\r?\n/).find((B)=>B.startsWith("worktree "))?.replace("worktree ","")?.trim();if(z&&q!==z)return`__${G("sha256").update(q).digest("hex").slice(0,8)}`}catch{}return""}var E={configDir:process.env.PUKU_CONFIG_DIR??process.env.CONTEXT_MODE_CONFIG_DIR??".puku-cli",projectDirEnv:"PUKU_PROJECT_DIR",sessionIdEnv:"PUKU_SESSION_ID"},$={configDir:".gemini",projectDirEnv:"GEMINI_PROJECT_DIR",sessionIdEnv:void 0},A={configDir:".vscode",projectDirEnv:"VSCODE_CWD",sessionIdEnv:void 0},F={configDir:".cursor",projectDirEnv:"CURSOR_CWD",sessionIdEnv:"CURSOR_SESSION_ID"},R={configDir:".codex",projectDirEnv:void 0,sessionIdEnv:void 0},w={configDir:".kiro",projectDirEnv:void 0,sessionIdEnv:void 0};function y(){return new Promise((b,q)=>{let z="";process.stdin.setEncoding("utf-8"),process.stdin.on("data",(B)=>{z+=B}),process.stdin.on("end",()=>b(z.replace(/^\uFEFF/,""))),process.stdin.on("error",q),process.stdin.resume()})}function I(b=E){return process.env[b.projectDirEnv]||process.cwd()}function H(b,q=E){if(typeof b?.cwd==="string"&&b.cwd.length>0)return b.cwd;if(Array.isArray(b?.workspace_roots)&&b.workspace_roots.length>0)return String(b.workspace_roots[0]);return I(q)}function W(b,q=E){if(b.transcript_path){let z=b.transcript_path.match(/([a-f0-9-]{36})\.jsonl$/);if(z)return z[1]}if(b.conversation_id)return b.conversation_id;if(b.sessionId)return b.sessionId;if(b.session_id)return b.session_id;if(q.sessionIdEnv&&process.env[q.sessionIdEnv])return process.env[q.sessionIdEnv];return`pid-${process.ppid}`}function v(b=E){let q=I(b),z=G("sha256").update(q).digest("hex").slice(0,16),B=C(L(),b.configDir,"context-mode","sessions");return J(B,{recursive:!0}),C(B,`${z}${M()}.db`)}function K(b=E){let q=I(b),z=G("sha256").update(q).digest("hex").slice(0,16),B=C(L(),b.configDir,"context-mode","sessions");return J(B,{recursive:!0}),C(B,`${z}${M()}-events.md`)}function O(b=E){let q=I(b),z=G("sha256").update(q).digest("hex").slice(0,16),B=C(L(),b.configDir,"context-mode","sessions");return J(B,{recursive:!0}),C(B,`${z}${M()}.cleanup`)}export{y as readStdin,W as getSessionId,K as getSessionEventsPath,v as getSessionDBPath,I as getProjectDir,H as getInputProjectDir,O as getCleanupFlagPath,A as VSCODE_OPTS,w as KIRO_OPTS,$ as GEMINI_OPTS,F as CURSOR_OPTS,R as CODEX_OPTS};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{join as q}from"node:path";import{pathToFileURL as B}from"node:url";import{existsSync as C}from"node:fs";function V(v){let z=C(q(v,"session-db.bundle.mjs"))?v:q(v,".."),E=q(z,".."),G=q(E,"build","session");async function w(H,I){let A=q(z,H);if(C(A))return await import(B(A).href);let J=q(G,I);return await import(B(J).href)}return{async loadSessionDB(){return await w("session-db.bundle.mjs","db.js")},async loadExtract(){return await w("session-extract.bundle.mjs","extract.js")},async loadSnapshot(){return await w("session-snapshot.bundle.mjs","snapshot.js")}}}export{V as createSessionLoaders};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
function a(t){return t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}var N=10;function h(t,r=4){return[...new Set(t.filter(o=>o.length>0))].slice(0,r).map(o=>o.length>80?o.slice(0,80):o)}function m(t,r){if(r.length===0)return"";let s=r.map(n=>`"${a(n)}"`).join(", ");return`
|
|
2
|
+
For full details:
|
|
3
|
+
${a(t)}(
|
|
4
|
+
queries: [${s}],
|
|
5
|
+
source: "session-events"
|
|
6
|
+
)`}function x(t,r){if(t.length===0)return"";let s=new Map;for(let l of t){let b=l.data,p=s.get(b);p||(p={ops:new Map},s.set(b,p));let g;l.type==="file_write"?g="write":l.type==="file_read"?g="read":l.type==="file_edit"?g="edit":g=l.type,p.ops.set(g,(p.ops.get(g)??0)+1)}let o=Array.from(s.entries()).slice(-N),u=[],i=[];for(let[l,{ops:b}]of o){let p=Array.from(b.entries()).map(([S,y])=>`${S}\xD7${y}`).join(", "),g=l.split("/").pop()??l;u.push(` ${a(g)} (${a(p)})`),i.push(`${g} ${Array.from(b.keys()).join(" ")}`)}let e=h(i);return[` <files count="${s.size}">`,...u,m(r,e)," </files>"].join(`
|
|
7
|
+
`)}function M(t,r){if(t.length===0)return"";let s=[],n=[];for(let i of t)s.push(` ${a(i.data)}`),n.push(i.data);let o=h(n);return[` <errors count="${t.length}">`,...s,m(r,o)," </errors>"].join(`
|
|
8
|
+
`)}function A(t,r){if(t.length===0)return"";let s=new Set,n=[],o=[];for(let e of t)s.has(e.data)||(s.add(e.data),n.push(` ${a(e.data)}`),o.push(e.data));if(n.length===0)return"";let u=h(o);return[` <decisions count="${n.length}">`,...n,m(r,u)," </decisions>"].join(`
|
|
9
|
+
`)}function D(t,r){if(t.length===0)return"";let s=new Set,n=[],o=[];for(let e of t)s.has(e.data)||(s.add(e.data),e.type==="rule_content"?n.push(` ${a(e.data)}`):n.push(` ${a(e.data)}`),o.push(e.data));if(n.length===0)return"";let u=h(o);return[` <rules count="${n.length}">`,...n,m(r,u)," </rules>"].join(`
|
|
10
|
+
`)}function F(t,r){if(t.length===0)return"";let s=[],n=[];for(let i of t)s.push(` ${a(i.data)}`),n.push(i.data);let o=h(n);return[` <git count="${t.length}">`,...s,m(r,o)," </git>"].join(`
|
|
11
|
+
`)}function R(t){if(t.length===0)return"";let r=[],s={};for(let e of t)try{let c=JSON.parse(e.data);typeof c.subject=="string"?r.push(c.subject):typeof c.taskId=="string"&&typeof c.status=="string"&&(s[c.taskId]=c.status)}catch{}if(r.length===0)return"";let n=new Set(["completed","deleted","failed"]),o=Object.keys(s).sort((e,c)=>Number(e)-Number(c)),u=[];for(let e=0;e<r.length;e++){let c=o[e],l=c?s[c]??"pending":"pending";n.has(l)||u.push(r[e])}if(u.length===0)return"";let i=[];for(let e of u)i.push(` [pending] ${a(e)}`);return i.join(`
|
|
12
|
+
`)}function J(t,r){let s=R(t);if(!s)return"";let n=[];for(let e of t)try{let c=JSON.parse(e.data);typeof c.subject=="string"&&n.push(c.subject)}catch{}let o=h(n);return[` <task_state count="${s.split(`
|
|
13
|
+
`).length}">`,s,m(r,o)," </task_state>"].join(`
|
|
14
|
+
`)}function X(t,r,s){if(t.length===0&&r.length===0)return"";let n=[],o=[];if(t.length>0){let e=t[t.length-1];n.push(` cwd: ${a(e.data)}`),o.push("working directory")}for(let e of r)n.push(` ${a(e.data)}`),o.push(e.data);let u=h(o);return[" <environment>",...n,m(s,u)," </environment>"].join(`
|
|
15
|
+
`)}function z(t,r){if(t.length===0)return"";let s=[],n=[];for(let i of t){let e=i.type==="subagent_completed"?"completed":i.type==="subagent_launched"?"launched":"unknown";s.push(` [${e}] ${a(i.data)}`),n.push(`subagent ${i.data}`)}let o=h(n);return[` <subagents count="${t.length}">`,...s,m(r,o)," </subagents>"].join(`
|
|
16
|
+
`)}function G(t,r){if(t.length===0)return"";let s=new Map;for(let e of t){let c=e.data.split(":")[0].trim();s.set(c,(s.get(c)??0)+1)}let n=[],o=[];for(let[e,c]of s)n.push(` ${a(e)} (${c}\xD7)`),o.push(`skill ${e} invocation`);let u=h(o);return[` <skills count="${t.length}">`,...n,m(r,u)," </skills>"].join(`
|
|
17
|
+
`)}function Q(t){if(t.length===0)return"";let r=t[t.length-1];return` <intent mode="${a(r.data)}"/>`}function H(t,r){let s=r?.compactCount??1,n=r?.searchTool??"ctx_search",o=new Date().toISOString(),u=[],i=[],e=[],c=[],l=[],b=[],p=[],g=[],S=[],y=[],k=[];for(let d of t)switch(d.category){case"file":u.push(d);break;case"task":i.push(d);break;case"rule":e.push(d);break;case"decision":c.push(d);break;case"cwd":l.push(d);break;case"error":b.push(d);break;case"env":p.push(d);break;case"git":g.push(d);break;case"subagent":S.push(d);break;case"intent":y.push(d);break;case"skill":k.push(d);break}let f=[];f.push(` <how_to_search>
|
|
18
|
+
Each section below contains a summary of prior work.
|
|
19
|
+
For FULL DETAILS, run the exact tool call shown under each section.
|
|
20
|
+
Do NOT ask the user to re-explain prior work. Search first.
|
|
21
|
+
Do NOT invent your own queries \u2014 use the ones provided.
|
|
22
|
+
</how_to_search>`);let $=x(u,n);$&&f.push($);let v=M(b,n);v&&f.push(v);let w=A(c,n);w&&f.push(w);let E=D(e,n);E&&f.push(E);let q=F(g,n);q&&f.push(q);let L=J(i,n);L&&f.push(L);let _=X(l,p,n);_&&f.push(_);let j=z(S,n);j&&f.push(j);let T=G(k,n);T&&f.push(T);let O=Q(y);O&&f.push(O);let B=`<session_resume events="${t.length}" compact_count="${s}" generated_at="${o}">`,C="</session_resume>",I=f.join(`
|
|
23
|
+
|
|
24
|
+
`);return I?`${B}
|
|
25
|
+
|
|
26
|
+
${I}
|
|
27
|
+
|
|
28
|
+
${C}`:`${B}
|
|
29
|
+
${C}`}export{H as buildResumeSnapshot,R as renderTaskState};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{createRequire as E}from"node:module";var U=E(import.meta.url);import"./suppress-stderr.mjs";import"./ensure-deps.mjs";import{createRoutingBlock as R}from"./routing-block.mjs";import{createToolNamer as y}from"./core/tool-naming.mjs";import{readStdin as B,getSessionId as O,getSessionDBPath as _,getSessionEventsPath as x,getCleanupFlagPath as j}from"./session-helpers.mjs";import{writeSessionEventsFile as k,buildSessionDirective as C,getSessionEvents as D,getLatestSessionEvents as v}from"./session-directive.mjs";import{createSessionLoaders as P}from"./session-loaders.mjs";import{join as $,dirname as m}from"node:path";import{fileURLToPath as b}from"node:url";import{readFileSync as p,unlinkSync as F,readdirSync as g,rmSync as u,statSync as h}from"node:fs";import{homedir as S}from"node:os";var w=y(),I=R(w),l=m(b(import.meta.url)),{loadSessionDB:T}=P(l),L=I;try{let V=await B(),W=JSON.parse(V),X=W.source??"startup";if(X==="compact"){let{SessionDB:Q}=await T(),Y=_(),q=new Q({dbPath:Y}),z=O(W),A=q.getResume(z);if(A&&!A.consumed)q.markResumeConsumed(z);let G=D(q,z);if(G.length>0){let J=k(G,x());L+=C("compact",J,w)}q.close()}else if(X==="resume"){try{F(j())}catch{}let{SessionDB:Q}=await T(),Y=_(),q=new Q({dbPath:Y}),z=v(q);if(z.length>0){let A=k(z,x());L+=C("resume",A,w)}q.close()}else if(X==="startup"){let{SessionDB:Q}=await T(),Y=_(),q=new Q({dbPath:Y});try{F(x())}catch{}q.cleanupOldSessions(7),q.db.exec("DELETE FROM session_events WHERE session_id NOT IN (SELECT session_id FROM session_meta)");let z=O(W),A=process.env.PUKU_PROJECT_DIR||process.cwd();q.ensureSession(z,A);let G=[$(S(),".claude","CLAUDE.md"),$(A,"CLAUDE.md"),$(A,".claude","CLAUDE.md")];for(let J of G)try{let Z=p(J,"utf-8");if(Z.trim())q.insertEvent(z,{type:"rule",category:"rule",data:J,priority:1}),q.insertEvent(z,{type:"rule_content",category:"rule",data:Z,priority:1})}catch{}q.close();try{let J=process.env.PUKU_PLUGIN_ROOT;if(J){let Z=J.match(/^(.*[\\/]plugins[\\/]cache[\\/][^\\/]+[\\/][^\\/]+[\\/])/);if(Z){let H=Z[1],M=J.replace(H,"").replace(/[\\/]/g,""),c=3600000,N=Date.now();for(let K of g(H)){if(K===M)continue;try{let f=h($(H,K));if(N-f.mtimeMs>3600000)u($(H,K),{recursive:!0,force:!0})}catch{}}}}}catch{}}}catch(V){try{let{appendFileSync:W}=await import("node:fs"),{join:X}=await import("node:path"),{homedir:Q}=await import("node:os");W(X(Q(),".puku-cli","context-mode","sessionstart-debug.log"),`[${new Date().toISOString()}] ${V?.message||V}
|
|
3
|
+
${V?.stack||""}
|
|
4
|
+
`)}catch{}}console.log(JSON.stringify({hookSpecificOutput:{hookEventName:"SessionStart",additionalContext:L}}));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{closeSync as g,openSync as h}from"node:fs";import{devNull as i}from"node:os";try{g(2),h(i,"w")}catch{process.stderr.write=()=>!0}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import"./suppress-stderr.mjs";import"./ensure-deps.mjs";import{readStdin as Y,getSessionId as Z,getSessionDBPath as $}from"./session-helpers.mjs";import{createSessionLoaders as w}from"./session-loaders.mjs";import{dirname as y}from"node:path";import{fileURLToPath as H}from"node:url";var K=y(H(import.meta.url)),{loadSessionDB:M,loadExtract:T}=w(K);try{let G=await Y(),A=JSON.parse(G),F=A.prompt??A.message??"",q=(F||"").trim(),J=q.startsWith("<task-notification>")||q.startsWith("<system-reminder>")||q.startsWith("<context_guidance>")||q.startsWith("<tool-result>");if(q.length>0&&!J){let{SessionDB:N}=await M(),{extractUserEvents:Q}=await T(),V=$(),z=new N({dbPath:V}),C=Z(A);z.ensureSession(C,process.env.PUKU_PROJECT_DIR||process.cwd()),z.insertEvent(C,{type:"user_prompt",category:"prompt",data:F,priority:1},"UserPromptSubmit");let W=Q(q);for(let X of W)z.insertEvent(C,X,"UserPromptSubmit");z.close()}}catch{}
|