context-mode 1.0.145 → 1.0.147
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/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +2 -2
- package/.codex-plugin/plugin.json +1 -1
- package/.openclaw-plugin/openclaw.plugin.json +1 -1
- package/.openclaw-plugin/package.json +1 -1
- package/README.md +26 -23
- package/bin/statusline.mjs +22 -9
- package/build/adapters/base.d.ts +9 -4
- package/build/adapters/base.js +16 -7
- package/build/adapters/codex/index.d.ts +1 -1
- package/build/adapters/codex/index.js +10 -4
- package/build/adapters/openclaw/index.d.ts +11 -2
- package/build/adapters/openclaw/index.js +12 -3
- package/build/adapters/openclaw/plugin.js +30 -7
- package/build/adapters/pi/mcp-bridge.d.ts +8 -0
- package/build/adapters/pi/mcp-bridge.js +118 -15
- package/build/adapters/types.d.ts +7 -1
- package/build/cli.d.ts +2 -0
- package/build/cli.js +82 -19
- package/build/search/auto-memory.d.ts +6 -1
- package/build/search/auto-memory.js +11 -2
- package/build/server.js +305 -105
- package/build/session/db.d.ts +37 -0
- package/build/session/db.js +197 -2
- package/build/session/extract.js +16 -0
- package/build/truncate.d.ts +15 -0
- package/build/truncate.js +28 -0
- package/cli.bundle.mjs +424 -350
- package/hooks/core/routing.mjs +4 -4
- package/hooks/routing-block.mjs +18 -23
- package/hooks/session-db.bundle.mjs +21 -19
- package/hooks/session-extract.bundle.mjs +2 -2
- package/hooks/session-helpers.mjs +13 -2
- package/hooks/session-snapshot.bundle.mjs +7 -7
- package/openclaw.plugin.json +1 -1
- package/package.json +4 -2
- package/server.bundle.mjs +372 -300
package/hooks/core/routing.mjs
CHANGED
|
@@ -704,7 +704,7 @@ export function routePreToolUse(toolName, toolInput, projectDir, platform, sessi
|
|
|
704
704
|
return mcpRedirect({
|
|
705
705
|
action: "modify",
|
|
706
706
|
updatedInput: {
|
|
707
|
-
command: `echo "context-mode: curl/wget
|
|
707
|
+
command: `echo "context-mode: curl/wget redirected. Call ${t("ctx_execute")}(language, code) to fetch the URL, derive your answer in code, and print only the result — the raw HTTP body stays in the sandbox instead of entering your conversation. Or call ${t("ctx_fetch_and_index")}(url, source) when you want to query the response later via ${t("ctx_search")}. Both have full network access. Retry the same call on a transient DNS error (EAI_AGAIN, ETIMEDOUT, ENETUNREACH)."`,
|
|
708
708
|
},
|
|
709
709
|
// D2 PRD Phase 3.1: marker payload for PostToolUse byte accounting.
|
|
710
710
|
redirectMeta: {
|
|
@@ -735,7 +735,7 @@ export function routePreToolUse(toolName, toolInput, projectDir, platform, sessi
|
|
|
735
735
|
return mcpRedirect({
|
|
736
736
|
action: "modify",
|
|
737
737
|
updatedInput: {
|
|
738
|
-
command: `echo "context-mode: Inline HTTP
|
|
738
|
+
command: `echo "context-mode: Inline HTTP redirected. Call ${t("ctx_execute")}(language, code) to fetch, derive your answer in code, and console.log() only the result — the raw response body stays in the sandbox instead of entering your conversation. Full network access. Retry the same call on a transient DNS error (EAI_AGAIN, ETIMEDOUT, ENETUNREACH)."`,
|
|
739
739
|
},
|
|
740
740
|
});
|
|
741
741
|
}
|
|
@@ -748,7 +748,7 @@ export function routePreToolUse(toolName, toolInput, projectDir, platform, sessi
|
|
|
748
748
|
return mcpRedirect({
|
|
749
749
|
action: "modify",
|
|
750
750
|
updatedInput: {
|
|
751
|
-
command: `echo "context-mode: Build tool redirected.
|
|
751
|
+
command: `echo "context-mode: Build tool redirected. Call ${t("ctx_execute")}(language: \\"shell\\", code: \\"${safeCmd} 2>&1 | tail -30\\") to run the build and print only the tail — the verbose build log stays in the sandbox instead of entering your conversation. For more targeted output, replace \\"tail -30\\" with \\"grep -E '(error|warning|FAIL|✗|×)'\\" or similar, so only the lines that matter come back."`,
|
|
752
752
|
},
|
|
753
753
|
});
|
|
754
754
|
}
|
|
@@ -801,7 +801,7 @@ export function routePreToolUse(toolName, toolInput, projectDir, platform, sessi
|
|
|
801
801
|
const url = toolInput.url ?? "";
|
|
802
802
|
return mcpRedirect({
|
|
803
803
|
action: "deny",
|
|
804
|
-
reason: `context-mode: WebFetch
|
|
804
|
+
reason: `context-mode: WebFetch redirected. Call ${t("ctx_fetch_and_index")}(url: "${url}", source: "...") to fetch + index the page, then ${t("ctx_search")}(queries: [...]) to query the indexed content — the raw page bytes stay in storage instead of entering your conversation. Or call ${t("ctx_execute")}(language, code) when you want to derive your answer in one round trip (parse, extract, count) without persisting the response. Both have full network access. Retry the same call on a transient DNS error (EAI_AGAIN, ETIMEDOUT, ENETUNREACH).`,
|
|
805
805
|
// D2 PRD Phase 4.1: marker payload for PostToolUse byte accounting.
|
|
806
806
|
redirectMeta: {
|
|
807
807
|
tool: "WebFetch",
|
package/hooks/routing-block.mjs
CHANGED
|
@@ -18,41 +18,36 @@ export function createRoutingBlock(t, options = {}) {
|
|
|
18
18
|
return `
|
|
19
19
|
<context_window_protection>
|
|
20
20
|
<priority_instructions>
|
|
21
|
-
|
|
21
|
+
Every byte a tool returns enters your conversation memory and costs reasoning capacity for the rest of the session. The context-mode tools let you do the work in a sandbox and surface only the derived answer — the raw bytes stay out. Think-in-Code: program the analysis, do not compute it by reading raw data into your conversation.
|
|
22
22
|
</priority_instructions>
|
|
23
23
|
|
|
24
24
|
<tool_selection_hierarchy>
|
|
25
25
|
0. MEMORY: ${t("ctx_search")}(sort: "timeline")
|
|
26
|
-
-
|
|
26
|
+
- On resume or compaction, query prior decisions, errors, plans, user prompts before asking the user — auto-captured session memory is searchable.
|
|
27
27
|
1. GATHER: ${t("ctx_batch_execute")}(commands, queries)
|
|
28
|
-
- Primary research tool. Runs commands, auto-indexes,
|
|
29
|
-
- Each command: {label: "section header", command: "shell command"}
|
|
30
|
-
- label becomes FTS5 chunk title — descriptive labels improve search.
|
|
28
|
+
- Primary research tool. Runs commands in parallel, auto-indexes each output, and (when queries are passed) returns matching sections in the same round trip — no follow-up search call.
|
|
29
|
+
- Each command: {label: "section header", command: "shell command"}; the label becomes the FTS5 chunk title — descriptive labels improve search.
|
|
31
30
|
2. FOLLOW-UP: ${t("ctx_search")}(queries: ["q1", "q2", ...])
|
|
32
|
-
-
|
|
31
|
+
- Multiple related questions about anything already indexed (your captures + session memory). Batch every question in one array; the ranking pipeline runs per-query and the round-trip cost is paid once.
|
|
33
32
|
3. PROCESSING: ${t("ctx_execute")}(language, code) | ${t("ctx_execute_file")}(path, language, code)
|
|
34
|
-
-
|
|
33
|
+
- Derive answers FROM data: filter, count, aggregate, parse, transform. Only what you console.log() enters your conversation; the raw bytes stay in the sandbox.
|
|
35
34
|
</tool_selection_hierarchy>
|
|
36
35
|
|
|
37
|
-
<
|
|
38
|
-
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
42
|
-
|
|
43
|
-
${t("ctx_execute")} is for analysis, processing, computation only.
|
|
44
|
-
</forbidden_actions>
|
|
36
|
+
<when_not_to_use>
|
|
37
|
+
- You intend to PROCESS the output (filter, count, parse, aggregate) → use ${t("ctx_batch_execute")} or ${t("ctx_execute")}. Bash stays correct when you intend to OBSERVE a short fixed output (git status on a clean tree, whoami, pwd) or when you are mutating state (git, mkdir, rm, mv, navigation).
|
|
38
|
+
- You want to analyze, summarize, or extract from a file → use ${t("ctx_execute_file")}. Read stays correct when you intend to Edit the file (Edit needs the exact bytes in your conversation to match against).
|
|
39
|
+
- WebFetch → use ${t("ctx_fetch_and_index")}; full network access, results indexed for ${t("ctx_search")}, raw page bytes never enter your conversation.
|
|
40
|
+
- ${t("ctx_execute")} and ${t("ctx_execute_file")} for file writes → these run code in a subprocess and discard the sandbox FS; they are for analysis, processing, and computation only.
|
|
41
|
+
</when_not_to_use>
|
|
45
42
|
|
|
46
43
|
<file_writing_policy>
|
|
47
|
-
|
|
48
|
-
NEVER use ${t("ctx_execute")}, ${t("ctx_execute_file")}, or Bash to write files.
|
|
44
|
+
File writes use the native Write or Edit tool — ${t("ctx_execute")}, ${t("ctx_execute_file")}, and Bash subprocesses do not persist edits to the host filesystem.
|
|
49
45
|
Applies to all file types: code, configs, plans, specs, YAML, JSON, markdown.
|
|
50
46
|
</file_writing_policy>
|
|
51
47
|
|
|
52
48
|
<output_constraints>
|
|
53
49
|
<artifact_policy>
|
|
54
|
-
Write artifacts (code, configs, PRDs) to
|
|
55
|
-
Return only: file path + 1-line description.
|
|
50
|
+
Write artifacts (code, configs, PRDs) to files. Return only: file path + 1-line description.
|
|
56
51
|
</artifact_policy>
|
|
57
52
|
</output_constraints>
|
|
58
53
|
<session_continuity>
|
|
@@ -80,19 +75,19 @@ ${includeCommands ? `
|
|
|
80
75
|
}
|
|
81
76
|
|
|
82
77
|
export function createReadGuidance(t) {
|
|
83
|
-
return '<context_guidance>\n <tip>\n Reading to Edit? Read is correct — Edit needs
|
|
78
|
+
return '<context_guidance>\n <tip>\n Reading to Edit the file? Read is correct — Edit needs the exact bytes in your conversation to match against.\n Reading to analyze, summarize, or extract from the file? Use ' + t("ctx_execute_file") + '(path, language, code) — the bytes stay in the sandbox and only what your code prints enters your conversation.\n </tip>\n</context_guidance>';
|
|
84
79
|
}
|
|
85
80
|
|
|
86
81
|
export function createGrepGuidance(t) {
|
|
87
|
-
return '<context_guidance>\n <tip>\n
|
|
82
|
+
return '<context_guidance>\n <tip>\n Grep results may be larger than you expect. When you intend to count, filter, or aggregate matches (not just spot-check one), run the search through ' + t("ctx_execute") + '(language: "shell", code: "...") — the raw match list stays in the sandbox and only your derived answer enters your conversation.\n </tip>\n</context_guidance>';
|
|
88
83
|
}
|
|
89
84
|
|
|
90
85
|
export function createBashGuidance(t) {
|
|
91
|
-
return '<context_guidance>\n <tip>\n
|
|
86
|
+
return '<context_guidance>\n <tip>\n When you intend to PROCESS the output (filter, count, parse, aggregate), use ' + t("ctx_batch_execute") + '(commands, queries) for multiple commands or ' + t("ctx_execute") + '(language: "shell", code: "...") for one — the raw output stays in the sandbox and only what you print enters your conversation. Bash stays the right surface when you intend to OBSERVE a short fixed output or when you are mutating state (git, mkdir, rm, mv, navigation).\n </tip>\n</context_guidance>';
|
|
92
87
|
}
|
|
93
88
|
|
|
94
89
|
export function createExternalMcpGuidance(t) {
|
|
95
|
-
return '<context_guidance>\n <tip>\n External MCP tools
|
|
90
|
+
return '<context_guidance>\n <tip>\n External MCP tools commonly return large payloads (channel history, file content, search results) that enter your conversation in full. When you intend to filter, count, or aggregate that data, pipe it through ' + t("ctx_execute") + '(language, code) — the raw payload stays in the sandbox and only the derived answer enters your conversation. For docs-style fetches you will want to query later, prefer ' + t("ctx_fetch_and_index") + '(url, source) then ' + t("ctx_search") + '(queries).\n </tip>\n</context_guidance>';
|
|
96
91
|
}
|
|
97
92
|
|
|
98
93
|
// ── Backward compat: static exports defaulting to claude-code ──
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import{createRequire as
|
|
1
|
+
import{createRequire as se}from"node:module";import{existsSync as oe,unlinkSync as P,renameSync as ie}from"node:fs";import{tmpdir as ae}from"node:os";import{join as ce}from"node:path";var A=class{#e;constructor(e){this.#e=e}pragma(e){let r=this.#e.prepare(`PRAGMA ${e}`).all();if(!r||r.length===0)return;if(r.length>1)return r;let s=Object.values(r[0]);return s.length===1?s[0]:r[0]}exec(e){let t="",r=null;for(let a=0;a<e.length;a++){let i=e[a];if(r)t+=i,i===r&&(r=null);else if(i==="'"||i==='"')t+=i,r=i;else if(i===";"){let c=t.trim();c&&this.#e.prepare(c).run(),t=""}else t+=i}let s=t.trim();return s&&this.#e.prepare(s).run(),this}prepare(e){let t=this.#e.prepare(e);return{run:(...r)=>t.run(...r),get:(...r)=>{let s=t.get(...r);return s===null?void 0:s},all:(...r)=>t.all(...r),iterate:(...r)=>t.iterate(...r)}}transaction(e){return this.#e.transaction(e)}close(){this.#e.close()}},w=class{#e;constructor(e){this.#e=e}pragma(e){let r=this.#e.prepare(`PRAGMA ${e}`).all();if(!r||r.length===0)return;if(r.length>1)return r;let s=Object.values(r[0]);return s.length===1?s[0]:r[0]}exec(e){return this.#e.exec(e),this}prepare(e){let t=this.#e.prepare(e);return{run:(...r)=>t.run(...r),get:(...r)=>t.get(...r),all:(...r)=>t.all(...r),iterate:(...r)=>typeof t.iterate=="function"?t.iterate(...r):t.all(...r)[Symbol.iterator]()}}transaction(e){return(...t)=>{this.#e.exec("BEGIN");try{let r=e(...t);return this.#e.exec("COMMIT"),r}catch(r){throw this.#e.exec("ROLLBACK"),r}}}close(){this.#e.close()}},E=null;function ue(n){let e=null;try{return e=new n(":memory:"),e.exec("CREATE VIRTUAL TABLE __fts5_probe USING fts5(x)"),!0}catch{return!1}finally{try{e?.close()}catch{}}}function de(n,e){let t=e!==void 0?e:globalThis.Bun;if(typeof t<"u"&&t!==null)return!0;let r=n??process.versions,[s,a]=(r.node??"0.0.0").split("."),i=Number(s),c=Number(a);return!Number.isFinite(i)||!Number.isFinite(c)?!1:i>22||i===22&&c>=5}function le(){if(!E){let n=se(import.meta.url);if(globalThis.Bun){let e=n(["bun","sqlite"].join(":")).Database;E=function(r,s){let a=new e(r,{readonly:s?.readonly,create:!0}),i=new A(a);return s?.timeout&&i.pragma(`busy_timeout = ${s.timeout}`),i}}else if(de()){let e=null;try{({DatabaseSync:e}=n(["node","sqlite"].join(":")))}catch{e=null}e&&ue(e)?E=function(r,s){let a=new e(r,{readOnly:s?.readonly??!1}),i=new w(a);return s?.timeout&&i.pragma(`busy_timeout = ${s.timeout}`),i}:E=n("better-sqlite3")}else E=n("better-sqlite3")}return E}function k(n){n.pragma("journal_mode = WAL"),n.pragma("synchronous = NORMAL");try{n.pragma("mmap_size = 268435456")}catch{}}function F(n){if(!oe(n))for(let e of["-wal","-shm"])try{P(n+e)}catch{}}function ge(n){for(let e of["","-wal","-shm"])try{P(n+e)}catch{}}function x(n){try{n.pragma("wal_checkpoint(TRUNCATE)")}catch{}try{n.close()}catch{}}function B(n="context-mode"){return ce(ae(),`${n}-${process.pid}.db`)}function Ee(n,e=[100,500,2e3]){let t;for(let r=0;r<=e.length;r++)try{return n()}catch(s){let a=s instanceof Error?s.message:String(s);if(!a.includes("SQLITE_BUSY")&&!a.includes("database is locked"))throw s;if(t=s instanceof Error?s:new Error(a),r<e.length){let i=e[r],c=Date.now();for(;Date.now()-c<i;);}}throw new Error(`SQLITE_BUSY: database is locked after ${e.length} retries. Original error: ${t?.message}`)}function me(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 pe(n){let e=Date.now();for(let t of["","-wal","-shm"])try{ie(n+t,`${n}${t}.corrupt-${e}`)}catch{}}var _=Symbol.for("__context_mode_live_dbs_v3__"),C=(()=>{let n=globalThis;return n[_]||(n[_]=new Set,process.on("exit",()=>{for(let e of n[_])x(e);n[_].clear()})),n[_]})(),S=class{#e;#t;constructor(e){let t=le();this.#e=e,F(e);let r;try{r=new t(e,{timeout:3e4}),k(r)}catch(s){let a=s instanceof Error?s.message:String(s);if(me(a)){pe(e),F(e);try{r=new t(e,{timeout:3e4}),k(r)}catch(i){throw new Error(`Failed to create fresh DB after renaming corrupt file: ${i instanceof Error?i.message:String(i)}`)}}else throw s}this.#t=r,C.add(this.#t),this.initSchema(),this.prepareStatements()}get db(){return this.#t}get dbPath(){return this.#e}close(){C.delete(this.#t),x(this.#t)}withRetry(e){return Ee(e)}cleanup(){C.delete(this.#t),x(this.#t),ge(this.#e)}};import{createHash as f}from"node:crypto";import{execFileSync as ye}from"node:child_process";import{accessSync as _e,constants as fe,existsSync as D,mkdirSync as he,realpathSync as Te,renameSync as I}from"node:fs";import{homedir as G}from"node:os";import{dirname as ve,isAbsolute as Y,join as g,resolve as p}from"node:path";var l="CONTEXT_MODE_DIR",K="sessions",j="content",h=class extends Error{kind;path;overrideEnvVar;ignoredEnvVar;ignoredReason;constructor(e,t,r=l,s,a,i={}){super(a??Le(e,t,i),{cause:s}),this.name="StorageDirectoryError",this.kind=e,this.path=t,this.overrideEnvVar=r,this.ignoredEnvVar=i.ignoredEnvVar,this.ignoredReason=i.ignoredReason}},b=new Map;function He(n){let e=n.env??process.env,t=n.legacySessionDirEnv,r=t?e[t]?.trim():void 0;return r&&t?(n.onLegacySessionDir?.(t,r),r):g(Se(n.configDir,n.configDirEnv,e),"context-mode","sessions")}function Se(n,e,t){let r=e?t[e]:void 0;return r&&r.trim()!==""?V(r.trim()):V(n,G())}function V(n,e){return n.startsWith("~")?p(G(),n.replace(/^~[/\\]?/,"")):Y(n)?p(n):e?p(e,n):p(n)}function Re(n,e,t){return new h(n,e,l,void 0,[`Invalid ${l} for context-mode ${n} directory: ${t}`,J()].join(`
|
|
2
|
+
`))}function q(n){let e=process.env[l];if(e===void 0)return{kind:"unset"};let t=e.trim();if(!t)return{kind:"ignored-empty",ignoredEnvVar:l,ignoredReason:"empty"};if(!Y(t))throw Re(n,t,`${l} must be an absolute path.`);return{kind:"override",root:p(t)}}function be(n){return n.kind==="ignored-empty"?{ignoredEnvVar:n.ignoredEnvVar,ignoredReason:n.ignoredReason}:{}}function z(n,e){let t=q(n);return t.kind!=="override"?null:{kind:n,path:g(t.root,e),envVar:l,source:"override"}}function De(n,e,t){return{kind:n,path:p(e()),envVar:null,source:"default",...t}}function Q(n){let e=q("session");return e.kind==="override"?{kind:"session",path:g(e.root,K),envVar:l,source:"override"}:De("session",n,be(e))}function $e(n){let e=z("content",j);if(e)return e;let t=Q(n);return{kind:"content",path:g(ve(t.path),j),envVar:t.envVar,source:t.source,ignoredEnvVar:t.ignoredEnvVar,ignoredReason:t.ignoredReason}}function Ge(n){let e=z("stats",K);if(e)return e;let t=Q(n);return{kind:"stats",path:t.path,envVar:t.envVar,source:t.source,ignoredEnvVar:t.ignoredEnvVar,ignoredReason:t.ignoredReason}}function Ye(n){return n.message}function Ke(n){return n.source==="override"&&n.envVar?`via ${n.envVar}`:n.ignoredEnvVar&&n.ignoredReason==="empty"?`default; ignored empty ${n.ignoredEnvVar}`:"default"}function qe(){b.clear()}function ze(n){let e=[n.kind,n.path,n.source,n.envVar??"",n.ignoredEnvVar??"",n.ignoredReason??""].join("\0"),t=b.get(e);if(t instanceof h)throw t;if(t===n.path)return t;try{return he(n.path,{recursive:!0}),_e(n.path,fe.W_OK),b.set(e,n.path),n.path}catch(r){let s=new h(n.kind,Oe(r)??n.path,l,r,void 0,{ignoredEnvVar:n.ignoredEnvVar,ignoredReason:n.ignoredReason});throw b.set(e,s),s}}function Le(n,e,t={}){return[`context-mode ${n} directory is not writable: ${e}`,Ne(t),J()].filter(Boolean).join(`
|
|
3
|
+
`)}function Ne(n){return n.ignoredEnvVar&&n.ignoredReason==="empty"?`Ignored empty ${n.ignoredEnvVar}; using adapter default.`:null}function J(){return`Set ${l} to a writable absolute path.`}function Oe(n){if(!n||typeof n!="object")return null;let e=n.path;return typeof e=="string"&&e.length>0?e:null}var m;function T(n){let e=n.replace(/\\/g,"/");return/^\/+$/.test(e)?"/":/^[A-Za-z]:\/+$/.test(e)?`${e.slice(0,2)}/`:e.replace(/\/+$/,"")}function W(n){let e=n;try{e=Te.native(n)}catch{}let t=T(e);return process.platform==="win32"||process.platform==="darwin"?t.toLowerCase():t}function Z(n,e){return ye("git",["-C",n,...e],{encoding:"utf-8",timeout:2e3,stdio:["ignore","pipe","ignore"]}).trim()}function Ce(n){let e=Z(n,["rev-parse","--show-toplevel"]);return e.length>0?T(e):null}function Ae(n){let e=Z(n,["worktree","list","--porcelain"]).split(/\r?\n/).find(t=>t.startsWith("worktree "))?.replace("worktree ","")?.trim();return e?T(e):null}function we(n=process.cwd()){let e=process.env.CONTEXT_MODE_SESSION_SUFFIX;if(m&&m.projectDir===n&&m.envSuffix===e)return m.suffix;let t="";if(e!==void 0)t=e?`__${e}`:"";else try{let r=Ce(n),s=Ae(n);if(r&&s){let a=W(r),i=W(s);a!==i&&(t=`__${f("sha256").update(a).digest("hex").slice(0,8)}`)}}catch{}return m={projectDir:n,envSuffix:e,suffix:t},t}function Qe(){m=void 0}function ee(n){return f("sha256").update(T(n)).digest("hex").slice(0,16)}function te(n){let e=T(n),t=process.platform==="darwin"||process.platform==="win32"?e.toLowerCase():e;return f("sha256").update(t).digest("hex").slice(0,16)}function Je(n){let{projectDir:e,contentDir:t}=n,r=te(e),s=g(t,`${r}.db`);if(D(s))return s;let a=ee(e);if(a===r)return s;let i=g(t,`${a}.db`);if(D(i))try{I(i,s);for(let c of["-wal","-shm"])try{I(i+c,s+c)}catch{}}catch{}return s}function Ze(n){return xe({...n,ext:".db"})}function xe(n){let{projectDir:e,sessionsDir:t,ext:r}=n,s=n.suffix??we(e),a=te(e),i=g(t,`${a}${s}${r}`);if(D(i))return i;let c=ee(e);if(c===a)return i;let d=g(t,`${c}${s}${r}`);if(D(d))try{I(d,i)}catch{}return i}var X=1e3,H=5;function R(n){let e=Number(n);return!Number.isFinite(e)||e<=0?0:Math.floor(e)}var o={insertEvent:"insertEvent",getEvents:"getEvents",getEventsByType:"getEventsByType",getEventsByPriority:"getEventsByPriority",getEventsByTypeAndPriority:"getEventsByTypeAndPriority",getEventCount:"getEventCount",getLatestAttributedProject:"getLatestAttributedProject",checkDuplicate:"checkDuplicate",evictLowestPriority:"evictLowestPriority",updateMetaLastEvent:"updateMetaLastEvent",ensureSession:"ensureSession",getSessionStats:"getSessionStats",incrementCompactCount:"incrementCompactCount",upsertResume:"upsertResume",getResume:"getResume",markResumeConsumed:"markResumeConsumed",claimLatestUnconsumedResume:"claimLatestUnconsumedResume",deleteEvents:"deleteEvents",deleteMeta:"deleteMeta",deleteResume:"deleteResume",getOldSessions:"getOldSessions",searchEvents:"searchEvents",incrementToolCall:"incrementToolCall",getToolCallTotals:"getToolCallTotals",getToolCallByTool:"getToolCallByTool",getEventBytesSummary:"getEventBytesSummary"},$=class extends S{constructor(e){super(e?.dbPath??B("session"))}stmt(e){return this.stmts.get(e)}initSchema(){try{let t=this.db.pragma("table_xinfo(session_events)").find(r=>r.name==="data_hash");t&&t.hidden!==0&&this.db.exec("DROP TABLE session_events")}catch{}this.db.exec(`
|
|
2
4
|
CREATE TABLE IF NOT EXISTS session_events (
|
|
3
5
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
4
6
|
session_id TEXT NOT NULL,
|
|
@@ -48,50 +50,50 @@ import{createRequire as Y}from"node:module";import{existsSync as G,unlinkSync as
|
|
|
48
50
|
);
|
|
49
51
|
|
|
50
52
|
CREATE INDEX IF NOT EXISTS idx_tool_calls_session ON tool_calls(session_id);
|
|
51
|
-
`);try{let
|
|
53
|
+
`);try{let e=this.db.pragma("table_xinfo(session_events)"),t=new Set(e.map(r=>r.name));t.has("project_dir")||this.db.exec("ALTER TABLE session_events ADD COLUMN project_dir TEXT NOT NULL DEFAULT ''"),t.has("attribution_source")||this.db.exec("ALTER TABLE session_events ADD COLUMN attribution_source TEXT NOT NULL DEFAULT 'unknown'"),t.has("attribution_confidence")||this.db.exec("ALTER TABLE session_events ADD COLUMN attribution_confidence REAL NOT NULL DEFAULT 0"),t.has("bytes_avoided")||this.db.exec("ALTER TABLE session_events ADD COLUMN bytes_avoided INTEGER NOT NULL DEFAULT 0"),t.has("bytes_returned")||this.db.exec("ALTER TABLE session_events ADD COLUMN bytes_returned INTEGER NOT NULL DEFAULT 0"),this.db.exec("CREATE INDEX IF NOT EXISTS idx_session_events_project ON session_events(session_id, project_dir)")}catch{}}prepareStatements(){this.stmts=new Map;let e=(t,r)=>{this.stmts.set(t,this.db.prepare(r))};e(o.insertEvent,`INSERT INTO session_events (
|
|
52
54
|
session_id, type, category, priority, data,
|
|
53
55
|
project_dir, attribution_source, attribution_confidence,
|
|
54
56
|
bytes_avoided, bytes_returned,
|
|
55
57
|
source_hook, data_hash
|
|
56
58
|
)
|
|
57
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`),
|
|
59
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`),e(o.getEvents,`SELECT id, session_id, type, category, priority, data,
|
|
58
60
|
project_dir, attribution_source, attribution_confidence,
|
|
59
61
|
bytes_avoided, bytes_returned,
|
|
60
62
|
source_hook, created_at, data_hash
|
|
61
|
-
FROM session_events WHERE session_id = ? ORDER BY id ASC LIMIT ?`),
|
|
63
|
+
FROM session_events WHERE session_id = ? ORDER BY id ASC LIMIT ?`),e(o.getEventsByType,`SELECT id, session_id, type, category, priority, data,
|
|
62
64
|
project_dir, attribution_source, attribution_confidence,
|
|
63
65
|
bytes_avoided, bytes_returned,
|
|
64
66
|
source_hook, created_at, data_hash
|
|
65
|
-
FROM session_events WHERE session_id = ? AND type = ? ORDER BY id ASC LIMIT ?`),
|
|
67
|
+
FROM session_events WHERE session_id = ? AND type = ? ORDER BY id ASC LIMIT ?`),e(o.getEventsByPriority,`SELECT id, session_id, type, category, priority, data,
|
|
66
68
|
project_dir, attribution_source, attribution_confidence,
|
|
67
69
|
bytes_avoided, bytes_returned,
|
|
68
70
|
source_hook, created_at, data_hash
|
|
69
|
-
FROM session_events WHERE session_id = ? AND priority >= ? ORDER BY id ASC LIMIT ?`),
|
|
71
|
+
FROM session_events WHERE session_id = ? AND priority >= ? ORDER BY id ASC LIMIT ?`),e(o.getEventsByTypeAndPriority,`SELECT id, session_id, type, category, priority, data,
|
|
70
72
|
project_dir, attribution_source, attribution_confidence,
|
|
71
73
|
bytes_avoided, bytes_returned,
|
|
72
74
|
source_hook, created_at, data_hash
|
|
73
|
-
FROM session_events WHERE session_id = ? AND type = ? AND priority >= ? ORDER BY id ASC LIMIT ?`),
|
|
75
|
+
FROM session_events WHERE session_id = ? AND type = ? AND priority >= ? ORDER BY id ASC LIMIT ?`),e(o.getEventCount,"SELECT COUNT(*) AS cnt FROM session_events WHERE session_id = ?"),e(o.getLatestAttributedProject,`SELECT project_dir
|
|
74
76
|
FROM session_events
|
|
75
77
|
WHERE session_id = ? AND project_dir != ''
|
|
76
78
|
ORDER BY id DESC
|
|
77
|
-
LIMIT 1`),
|
|
79
|
+
LIMIT 1`),e(o.checkDuplicate,`SELECT 1 FROM (
|
|
78
80
|
SELECT type, data_hash FROM session_events
|
|
79
81
|
WHERE session_id = ? ORDER BY id DESC LIMIT ?
|
|
80
82
|
) AS recent
|
|
81
83
|
WHERE recent.type = ? AND recent.data_hash = ?
|
|
82
|
-
LIMIT 1`),
|
|
84
|
+
LIMIT 1`),e(o.evictLowestPriority,`DELETE FROM session_events WHERE id = (
|
|
83
85
|
SELECT id FROM session_events WHERE session_id = ?
|
|
84
86
|
ORDER BY priority ASC, id ASC LIMIT 1
|
|
85
|
-
)`),
|
|
87
|
+
)`),e(o.updateMetaLastEvent,`UPDATE session_meta
|
|
86
88
|
SET last_event_at = datetime('now'), event_count = event_count + 1
|
|
87
|
-
WHERE session_id = ?`),
|
|
88
|
-
FROM session_meta WHERE session_id = ?`),
|
|
89
|
+
WHERE session_id = ?`),e(o.ensureSession,"INSERT OR IGNORE INTO session_meta (session_id, project_dir) VALUES (?, ?)"),e(o.getSessionStats,`SELECT session_id, project_dir, started_at, last_event_at, event_count, compact_count
|
|
90
|
+
FROM session_meta WHERE session_id = ?`),e(o.incrementCompactCount,"UPDATE session_meta SET compact_count = compact_count + 1 WHERE session_id = ?"),e(o.upsertResume,`INSERT INTO session_resume (session_id, snapshot, event_count)
|
|
89
91
|
VALUES (?, ?, ?)
|
|
90
92
|
ON CONFLICT(session_id) DO UPDATE SET
|
|
91
93
|
snapshot = excluded.snapshot,
|
|
92
94
|
event_count = excluded.event_count,
|
|
93
95
|
created_at = datetime('now'),
|
|
94
|
-
consumed = 0`),
|
|
96
|
+
consumed = 0`),e(o.getResume,"SELECT snapshot, event_count, consumed FROM session_resume WHERE session_id = ?"),e(o.markResumeConsumed,"UPDATE session_resume SET consumed = 1 WHERE session_id = ?"),e(o.claimLatestUnconsumedResume,`UPDATE session_resume
|
|
95
97
|
SET consumed = 1
|
|
96
98
|
WHERE id = (
|
|
97
99
|
SELECT id FROM session_resume
|
|
@@ -100,20 +102,20 @@ import{createRequire as Y}from"node:module";import{existsSync as G,unlinkSync as
|
|
|
100
102
|
ORDER BY created_at DESC, id DESC
|
|
101
103
|
LIMIT 1
|
|
102
104
|
)
|
|
103
|
-
RETURNING session_id, snapshot`),
|
|
105
|
+
RETURNING session_id, snapshot`),e(o.deleteEvents,"DELETE FROM session_events WHERE session_id = ?"),e(o.deleteMeta,"DELETE FROM session_meta WHERE session_id = ?"),e(o.deleteResume,"DELETE FROM session_resume WHERE session_id = ?"),e(o.searchEvents,`SELECT id, session_id, category, type, data, created_at
|
|
104
106
|
FROM session_events
|
|
105
107
|
WHERE (project_dir = ? OR project_dir = '')
|
|
106
108
|
AND (data LIKE '%' || ? || '%' ESCAPE '\\' OR category LIKE '%' || ? || '%' ESCAPE '\\')
|
|
107
109
|
AND (? IS NULL OR category = ?)
|
|
108
110
|
ORDER BY id ASC
|
|
109
|
-
LIMIT ?`),
|
|
111
|
+
LIMIT ?`),e(o.getOldSessions,"SELECT session_id FROM session_meta WHERE started_at < datetime('now', ? || ' days')"),e(o.incrementToolCall,`INSERT INTO tool_calls (session_id, tool, calls, bytes_returned)
|
|
110
112
|
VALUES (?, ?, 1, ?)
|
|
111
113
|
ON CONFLICT(session_id, tool) DO UPDATE SET
|
|
112
114
|
calls = calls + 1,
|
|
113
115
|
bytes_returned = bytes_returned + excluded.bytes_returned,
|
|
114
|
-
updated_at = datetime('now')`),
|
|
116
|
+
updated_at = datetime('now')`),e(o.getToolCallTotals,`SELECT COALESCE(SUM(calls), 0) AS calls,
|
|
115
117
|
COALESCE(SUM(bytes_returned), 0) AS bytes_returned
|
|
116
|
-
FROM tool_calls WHERE session_id = ?`),
|
|
117
|
-
FROM tool_calls WHERE session_id = ? ORDER BY calls DESC`),
|
|
118
|
+
FROM tool_calls WHERE session_id = ?`),e(o.getToolCallByTool,`SELECT tool, calls, bytes_returned
|
|
119
|
+
FROM tool_calls WHERE session_id = ? ORDER BY calls DESC`),e(o.getEventBytesSummary,`SELECT COALESCE(SUM(bytes_avoided), 0) AS bytes_avoided,
|
|
118
120
|
COALESCE(SUM(bytes_returned), 0) AS bytes_returned
|
|
119
|
-
FROM session_events WHERE session_id = ?`)}insertEvent(t,
|
|
121
|
+
FROM session_events WHERE session_id = ?`)}insertEvent(e,t,r="PostToolUse",s,a){let i=f("sha256").update(t.data).digest("hex").slice(0,16).toUpperCase(),c=String(s?.projectDir??t.project_dir??this._getSessionProjectDir(e)).trim(),d=String(s?.source??t.attribution_source??"unknown"),u=Number(s?.confidence??t.attribution_confidence??0),v=Number.isFinite(u)?Math.max(0,Math.min(1,u)):0,y=R(a?.bytesAvoided),L=R(a?.bytesReturned),N=this.db.transaction(()=>{if(this.stmt(o.checkDuplicate).get(e,H,t.type,i))return;this.stmt(o.getEventCount).get(e).cnt>=X&&this.stmt(o.evictLowestPriority).run(e),this.stmt(o.insertEvent).run(e,t.type,t.category,t.priority,t.data,c,d,v,y,L,r,i),this.stmt(o.updateMetaLastEvent).run(e)});this.withRetry(()=>N())}bulkInsertEvents(e,t,r="PostToolUse",s,a){if(!t||t.length===0)return;if(t.length===1){this.insertEvent(e,t[0],r,s?.[0],a?.[0]);return}let i=t.map((d,u)=>{let v=f("sha256").update(d.data).digest("hex").slice(0,16).toUpperCase(),y=s?.[u],L=String(y?.projectDir??d.project_dir??this._getSessionProjectDir(e)??"").trim(),N=String(y?.source??d.attribution_source??"unknown"),O=Number(y?.confidence??d.attribution_confidence??0),U=Number.isFinite(O)?Math.max(0,Math.min(1,O)):0,M=a?.[u],ne=R(M?.bytesAvoided),re=R(M?.bytesReturned);return{event:d,dataHash:v,projectDir:L,attributionSource:N,attributionConfidence:U,bytesAvoided:ne,bytesReturned:re}}),c=this.db.transaction(()=>{let d=this.stmt(o.getEventCount).get(e).cnt;for(let u of i)this.stmt(o.checkDuplicate).get(e,H,u.event.type,u.dataHash)||(d>=X?this.stmt(o.evictLowestPriority).run(e):d++,this.stmt(o.insertEvent).run(e,u.event.type,u.event.category,u.event.priority,u.event.data,u.projectDir,u.attributionSource,u.attributionConfidence,u.bytesAvoided,u.bytesReturned,r,u.dataHash));this.stmt(o.updateMetaLastEvent).run(e)});this.withRetry(()=>c())}getEvents(e,t){let r=t?.limit??1e3,s=t?.type,a=t?.minPriority;return s&&a!==void 0?this.stmt(o.getEventsByTypeAndPriority).all(e,s,a,r):s?this.stmt(o.getEventsByType).all(e,s,r):a!==void 0?this.stmt(o.getEventsByPriority).all(e,a,r):this.stmt(o.getEvents).all(e,r)}getEventCount(e){return this.stmt(o.getEventCount).get(e).cnt}getEventBytesSummary(e){let t=this.stmt(o.getEventBytesSummary).get(e);return{bytesAvoided:Number(t?.bytes_avoided??0),bytesReturned:Number(t?.bytes_returned??0)}}getLatestAttributedProjectDir(e){return this.stmt(o.getLatestAttributedProject).get(e)?.project_dir||null}_getSessionProjectDir(e){try{return this.db.prepare("SELECT project_dir FROM session_meta WHERE session_id = ?").get(e)?.project_dir||""}catch{return""}}searchEvents(e,t,r,s){try{let a=e.replace(/[%_]/g,c=>"\\"+c),i=s??null;return this.stmt(o.searchEvents).all(r,a,a,i,i,t)}catch{return[]}}ensureSession(e,t){this.stmt(o.ensureSession).run(e,t)}getSessionStats(e){return this.stmt(o.getSessionStats).get(e)??null}incrementCompactCount(e){this.stmt(o.incrementCompactCount).run(e)}upsertResume(e,t,r){this.stmt(o.upsertResume).run(e,t,r??0)}getResume(e){return this.stmt(o.getResume).get(e)??null}markResumeConsumed(e){this.stmt(o.markResumeConsumed).run(e)}claimLatestUnconsumedResume(e){let t=this.stmt(o.claimLatestUnconsumedResume).get(e);return t?{sessionId:t.session_id,snapshot:t.snapshot}:null}getLatestSessionId(){try{return this.db.prepare("SELECT session_id FROM session_meta ORDER BY started_at DESC LIMIT 1").get()?.session_id??null}catch{return null}}incrementToolCall(e,t,r=0){let s=Number.isFinite(r)&&r>0?Math.round(r):0;try{this.stmt(o.incrementToolCall).run(e,t,s)}catch{}}getToolCallStats(e){try{let t=this.stmt(o.getToolCallTotals).get(e),r=this.stmt(o.getToolCallByTool).all(e),s={};for(let a of r)s[a.tool]={calls:a.calls,bytesReturned:a.bytes_returned};return{totalCalls:t?.calls??0,totalBytesReturned:t?.bytes_returned??0,byTool:s}}catch{return{totalCalls:0,totalBytesReturned:0,byTool:{}}}}deleteSession(e){this.db.transaction(()=>{this.stmt(o.deleteEvents).run(e),this.stmt(o.deleteResume).run(e),this.stmt(o.deleteMeta).run(e)})()}cleanupOldSessions(e=7){let t=`-${e}`,r=this.stmt(o.getOldSessions).all(t);for(let{session_id:s}of r)this.deleteSession(s);return r.length}};export{$ as SessionDB,h as StorageDirectoryError,Qe as _resetWorktreeSuffixCacheForTests,qe as clearStorageDirectoryCheckCacheForTests,Ke as describeStorageDirectorySource,ze as ensureWritableStorageDir,Ye as formatStorageDirectoryError,we as getWorktreeSuffix,te as hashProjectDirCanonical,ee as hashProjectDirLegacy,T as normalizeWorktreePath,$e as resolveContentStorageDir,Je as resolveContentStorePath,He as resolveDefaultSessionDir,Ze as resolveSessionDbPath,xe as resolveSessionPath,Q as resolveSessionStorageDir,Ge as resolveStatsStorageDir};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function i(t){return t==null?"":String(t)}function E(t){return t==null?"":typeof t=="string"?t:JSON.stringify(t)}function d(t){let e=String(t.tool_response??""),n=t.tool_output?.isError===!0||t.tool_output?.is_error===!0;return t.tool_name==="Bash"&&/exit code [1-9]|error:|Error:|FAIL|failed/i.test(e)||
|
|
2
|
-
response: ${i(r)}`:"";return[{type:"mcp",category:"mcp",data:i(`${s}${u}${c}`),priority:3}]}var M=2048;function B(t,e){if(Buffer.byteLength(t,"utf8")<=e)return{value:t,truncated:!1};let n=Buffer.from(t,"utf8"),r=e;for(;r>0&&(n[r]&192)===128;)r--;return{value:n.subarray(0,r).toString("utf8"),truncated:!0}}var W=/(authorization|auth_token|access_token|refresh_token|bearer|token|secret|password|passwd|pwd|api[-_]?key|apikey|cookie|set-cookie|signature|private[-_]?key|client[-_]?secret|x[-_]?api[-_]?key)/i,j="[REDACTED]";function y(t,e=new WeakSet){if(t==null||typeof t!="object")return t;if(e.has(t))return"[CIRCULAR]";e.add(t);let n;if(Array.isArray(t))n=t.map(r=>y(r,e));else{let r={};for(let[o,s]of Object.entries(t))W.test(o)?r[o]=j:r[o]=y(s,e);n=r}return e.delete(t),n}function F(t){let{tool_name:e,tool_input:n}=t;if(!e.startsWith("mcp__"))return[];let r=y(n??{}),o;try{o=JSON.stringify(r)}catch{o="{}"}let{value:s,truncated:a}=B(o,M),u=a?`{"tool_name":${JSON.stringify(e)},"params_raw":${JSON.stringify(s)},"truncated":true}`:`{"tool_name":${JSON.stringify(e)},"params":${s}}`;return[{type:"mcp_tool_call",category:"mcp_tool_call",data:i(u),priority:4}]}function D(t){if(t.tool_name!=="AskUserQuestion")return[];let e=t.tool_input.questions,n=Array.isArray(e)&&e.length>0?String(e[0].question??""):"",r=String(t.tool_response??""),o="";try{let c=JSON.parse(r)?.answers;if(c&&typeof c=="object"){let g=f=>typeof f=="string"?f:Array.isArray(f)?f.filter(h=>typeof h=="string").join(" | "):"",m=n?g(c[n]):"";m?o=m:o=Object.values(c).map(g).filter(h=>h.length>0).join(" | ")}}catch{}let s=i(o),a=n?`Q: ${i(n)} \u2192 A: ${s}`:`answer: ${s}`;return[{type:"decision_question",category:"decision",data:i(a),priority:2}]}function U(t){if(t.tool_name!=="Agent")return[];if(!t.tool_response||t.tool_response.length===0)return[];let e=t.tool_response.length>500?t.tool_response.slice(0,500):t.tool_response;return[{type:"agent_finding",category:"agent-finding",data:i(e),priority:2}]}function K(t){let e=[E(t.tool_input),i(t.tool_response)].join(" ");if(e.length===0)return[];let n=new Set,r=e.match(/https?:\/\/[^\s)]+/g);if(r)for(let c of r)c=c.replace(/["'})\],;.]+$/,""),/localhost|127\.0\.0\.1/i.test(c)||n.add(c);let o=e.match(/(?<!\w)#(\d+)/g);if(o)for(let c of o)n.add(c);if(n.size===0)return[];let s,a=i(t.tool_response).match(/Fetched and indexed[^\(]*\(([\d.]+)\s*KB\)/i);if(a){let c=Number(a[1]);Number.isFinite(c)&&c>0&&(s=Math.round(c*1024))}let u={type:"external_ref",category:"external-ref",data:i(Array.from(n).join(", ")),priority:3};return s!==void 0&&(u.bytes_avoided=s),[u]}function G(t){if(t.tool_name!=="EnterWorktree")return[];let e=String(t.tool_input.name??"unnamed");return[{type:"worktree",category:"env",data:i(`entered worktree: ${e}`),priority:2}]}var v=/[,;,;、،]/u,J=15,q=500;function z(t){if(_.test(t)||!b.test(t)||!v.test(t))return!1;let e=[...t].length;return e>=J&&e<=q}function Q(t){let e=t.trim();return z(e)?[{type:"decision",category:"decision",data:i(t),priority:2}]:[]}var V=8,X=120,Y=new RegExp("\\p{L}+\\s+\\p{L}+","u"),Z=new RegExp("\\p{L}{6,}","u");function tt(t){let e=t.split(/[.!\n。!]/u)[0].trim();if(_.test(e)||v.test(e)||!b.test(e))return!1;let n=[...e].length;return n<V||n>X?!1:Y.test(e)||Z.test(e)}function et(t){let e=t.trim();return tt(e)?[{type:"role",category:"role",data:i(t),priority:3}]:[]}var _=/[??؟¿]/u,b=new RegExp("\\p{L}","u"),nt=60;function rt(t){if(_.test(t)||!b.test(t))return!1;let e=[...t].length;return e>0&&e<nt}function ot(t){let e=t.trim();if(!e)return[];let n;return _.test(e)?n="investigate":rt(e)&&(n="implement"),n?[{type:"intent",category:"intent",data:i(n),priority:4}]:[]}var st=/(?:\bError\s*:|\bException\s*:|\bTraceback\b|\bat\s+\S+\s*\([^)]*:\d+:\d+\))/u,it=/[✓✔✅☑🎉]/u,at=/^\s*(?:fixed|resolved)\s*:/iu;function ct(t){let e=[];return it.test(t)||at.test(t)?(e.push({type:"blocker_resolved",category:"blocked-on",data:i(t),priority:2}),e):(st.test(t)&&e.push({type:"blocker",category:"blocked-on",data:i(t),priority:2}),e)}function lt(t){return t.length<=1024?[]:[{type:"data",category:"data",data:i(t),priority:4}]}var l=null;function pt(t){let{tool_name:e,tool_response:n}=t,r=String(n??"");if(d(t))return l={tool:e,error:r.slice(0,200),callsSince:0},[];if(!l)return[];if(l.callsSince++,l.callsSince>10)return l=null,[];if(!!d(t))return[];let s=e===l.tool,a=l.tool==="Read"&&(e==="Edit"||e==="Write"||e==="apply_patch");if(s||a){let u={type:"error_resolved",category:"error-resolution",data:i(`Error in ${l.tool}: ${l.error} \u2192 Fixed`),priority:2};return l=null,[u]}return[]}function _t(){l=null}var p=[];function ut(t){return`${t.length}:${t.slice(0,20)}`}function ft(t){let{tool_name:e,tool_input:n}=t,r=ut(JSON.stringify(n).slice(0,200));if(p.push({tool:e,inputHash:r}),p.length>50&&p.splice(0,p.length-50),p.length<3)return[];let o=0;for(let s=p.length-1;s>=0&&(p[s].tool===e&&p[s].inputHash===r);s--)o++;return o>=3?(p.splice(p.length-o),[{type:"retry_detected",category:"iteration-loop",data:i(`${e} called ${o} times with similar input`),priority:2}]):[]}function ht(){p.length=0}var dt={run_shell_command:"Bash",read_file:"Read",read_many_files:"Read",grep_search:"Grep",search_file_content:"Grep",web_fetch:"WebFetch",write_file:"Write",edit:"Edit",glob:"Glob",todo_write:"TodoWrite",ask_user_question:"AskUserQuestion",list_directory:"LS",save_memory:"Memory",skill:"Skill",exit_plan_mode:"ExitPlanMode",agent:"Agent",bash:"Bash",view:"Read",grep:"Grep",fetch:"WebFetch",shell:"Bash",shell_command:"Bash",exec_command:"Bash","container.exec":"Bash",local_shell:"Bash",grep_files:"Grep"};function gt(t){let e=dt[t.tool_name];return!e||e===t.tool_name?t:{...t,tool_name:e}}function yt(t){try{let e=gt(t),n=[];return n.push(...A(e)),n.push(...R(e)),n.push(...
|
|
1
|
+
function i(t){return t==null?"":String(t)}function E(t){return t==null?"":typeof t=="string"?t:JSON.stringify(t)}function d(t){let e=String(t.tool_response??""),n=String(t.tool_input?.command??"");if(e.startsWith("context-mode:")||n.startsWith('echo "context-mode:')||n.startsWith("echo 'context-mode:"))return!1;let r=t.tool_output?.isError===!0||t.tool_output?.is_error===!0;return t.tool_name==="Bash"&&/exit code [1-9]|error:|Error:|FAIL|failed/i.test(e)||r}function k(t){if(!t)return[];let e=[];for(let r of t.split(/\r?\n/)){if(r.startsWith("*** Add File: ")){e.push({path:r.slice(14).trim(),type:"file_write"});continue}if(r.startsWith("*** Update File: ")){e.push({path:r.slice(17).trim(),type:"file_edit"});continue}if(r.startsWith("*** Delete File: ")){e.push({path:r.slice(17).trim(),type:"file_edit"});continue}r.startsWith("*** Move to: ")&&e.push({path:r.slice(13).trim(),type:"file_edit"})}let n=new Set;return e.filter(r=>{if(!r.path)return!1;let o=`${r.type}:${r.path}`;return n.has(o)?!1:(n.add(o),!0)})}function S(t){return/(?:^|[/\\])\.claude[/\\]plans[/\\]/.test(t)}function A(t){let{tool_name:e,tool_input:n,tool_response:r}=t,o=[];if(e==="Read"){let s=String(n.file_path??"");return(/(?:CLAUDE|AGENTS(?:\.override)?|GEMINI|QWEN|KIRO)\.md$/i.test(s)||/\/copilot-instructions\.md$/i.test(s)||/\/context-mode\.mdc$/i.test(s)||/\.claude[\\/]/i.test(s)||/[\\/]memor(?:y|ies)[\\/][^\\/]+\.md$/i.test(s))&&(o.push({type:"rule",category:"rule",data:i(s),priority:1}),r&&r.length>0&&o.push({type:"rule_content",category:"rule",data:i(r),priority:1})),o.push({type:"file_read",category:"file",data:i(s),priority:1}),o}if(e==="Edit"){let s=String(n.file_path??"");return o.push({type:"file_edit",category:"file",data:i(s),priority:1}),o}if(e==="NotebookEdit"){let s=String(n.notebook_path??"");return o.push({type:"file_edit",category:"file",data:i(s),priority:1}),o}if(e==="Write"){let s=String(n.file_path??"");return o.push({type:"file_write",category:"file",data:i(s),priority:1}),o}if(e==="apply_patch"){if(d(t))return[];let s=k(String(n.command??n.patch??""));for(let a of s)o.push({type:a.type,category:"file",data:i(a.path),priority:1});return o}if(e==="Glob"){let s=String(n.pattern??"");return o.push({type:"file_glob",category:"file",data:i(s),priority:3}),o}if(e==="Grep"){let s=String(n.pattern??""),a=String(n.path??"");return o.push({type:"file_search",category:"file",data:i(`${s} in ${a}`),priority:3}),o}return o}function R(t){if(t.tool_name!=="Bash")return[];let n=String(t.tool_input.command??"").match(/\bcd\s+("([^"]+)"|'([^']+)'|(\S+))/);if(!n)return[];let r=n[2]??n[3]??n[4]??"";return[{type:"cwd",category:"cwd",data:i(r),priority:2}]}function x(t){let{tool_response:e}=t,n=String(e??"");return d(t)?[{type:"error_tool",category:"error",data:i(n),priority:2}]:[]}var T=[{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 w(t){if(t.tool_name!=="Bash")return[];let e=String(t.tool_input.command??""),n=T.find(r=>r.pattern.test(e));return n?[{type:"git",category:"git",data:i(n.operation),priority:2}]:[]}function I(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:i(JSON.stringify(t.tool_input)),priority:1}]:[]}function N(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,r=Array.isArray(n)&&n.length>0?`exited plan mode (allowed: ${E(n.map(s=>typeof s=="object"&&s!==null&&"prompt"in s?String(s.prompt):String(s)).join(", "))})`:"exited plan mode";e.push({type:"plan_exit",category:"plan",data:i(r),priority:2});let o=String(t.tool_response??"").toLowerCase();return o.includes("approved")||o.includes("approve")?e.push({type:"plan_approved",category:"plan",data:"plan approved by user",priority:1}):(o.includes("rejected")||o.includes("decline")||o.includes("denied"))&&e.push({type:"plan_rejected",category:"plan",data:i(`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(S(e))return[{type:"plan_file_write",category:"plan",data:i(`plan file: ${e.split(/[/\\]/).pop()??e}`),priority:2}]}return t.tool_name==="apply_patch"?d(t)?[]:k(String(t.tool_input.command??t.tool_input.patch??"")).filter(n=>S(n.path)).map(n=>({type:"plan_file_write",category:"plan",data:i(`plan file: ${n.path.split(/[/\\]/).pop()??n.path}`),priority:2})):[]}var C=[/\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 H(t){if(t.tool_name!=="Bash")return[];let e=String(t.tool_input.command??"");if(!C.some(o=>o.test(e)))return[];let r=e.replace(/\bexport\s+(\w+)=\S*/g,"export $1=***");return[{type:"env",category:"env",data:i(r),priority:2}]}function L(t){if(t.tool_name!=="Skill")return[];let e=String(t.tool_input.skill??"");return[{type:"skill",category:"skill",data:i(e),priority:2}]}function $(t){if(!t.tool_response?.includes("Error")&&!t.tool_output?.isError)return[];let e=String(t.tool_response||""),n=[/not supported/i,/cannot/i,/does not support/i,/FAIL/i,/refused/i,/permission denied/i,/incompatible/i];for(let r of n){let o=e.match(r);if(o){let s=e.toLowerCase().indexOf(o[0].toLowerCase()),a=e.slice(Math.max(0,s-50),Math.min(e.length,s+200)).trim();return[{type:"constraint_discovered",category:"constraint",data:i(a),priority:2}]}}return[]}function O(t){if(t.tool_name!=="Agent")return[];let e=i(String(t.tool_input.prompt??t.tool_input.description??"")),n=t.tool_response?i(String(t.tool_response)):"",r=n.length>0;return[{type:r?"subagent_completed":"subagent_launched",category:"subagent",data:i(r?`[completed] ${e} \u2192 ${n}`:`[launched] ${e}`),priority:r?2:3}]}function P(t){let{tool_name:e,tool_input:n,tool_response:r}=t;if(!e.startsWith("mcp__"))return[];let o=e.split("__"),s=o[o.length-1]||e,a=Object.values(n).find(g=>typeof g=="string"),u=a?`: ${i(String(a))}`:"",c=r&&r.length>0?`
|
|
2
|
+
response: ${i(r)}`:"";return[{type:"mcp",category:"mcp",data:i(`${s}${u}${c}`),priority:3}]}var M=2048;function B(t,e){if(Buffer.byteLength(t,"utf8")<=e)return{value:t,truncated:!1};let n=Buffer.from(t,"utf8"),r=e;for(;r>0&&(n[r]&192)===128;)r--;return{value:n.subarray(0,r).toString("utf8"),truncated:!0}}var W=/(authorization|auth_token|access_token|refresh_token|bearer|token|secret|password|passwd|pwd|api[-_]?key|apikey|cookie|set-cookie|signature|private[-_]?key|client[-_]?secret|x[-_]?api[-_]?key)/i,j="[REDACTED]";function y(t,e=new WeakSet){if(t==null||typeof t!="object")return t;if(e.has(t))return"[CIRCULAR]";e.add(t);let n;if(Array.isArray(t))n=t.map(r=>y(r,e));else{let r={};for(let[o,s]of Object.entries(t))W.test(o)?r[o]=j:r[o]=y(s,e);n=r}return e.delete(t),n}function F(t){let{tool_name:e,tool_input:n}=t;if(!e.startsWith("mcp__"))return[];let r=y(n??{}),o;try{o=JSON.stringify(r)}catch{o="{}"}let{value:s,truncated:a}=B(o,M),u=a?`{"tool_name":${JSON.stringify(e)},"params_raw":${JSON.stringify(s)},"truncated":true}`:`{"tool_name":${JSON.stringify(e)},"params":${s}}`;return[{type:"mcp_tool_call",category:"mcp_tool_call",data:i(u),priority:4}]}function D(t){if(t.tool_name!=="AskUserQuestion")return[];let e=t.tool_input.questions,n=Array.isArray(e)&&e.length>0?String(e[0].question??""):"",r=String(t.tool_response??""),o="";try{let c=JSON.parse(r)?.answers;if(c&&typeof c=="object"){let g=f=>typeof f=="string"?f:Array.isArray(f)?f.filter(h=>typeof h=="string").join(" | "):"",m=n?g(c[n]):"";m?o=m:o=Object.values(c).map(g).filter(h=>h.length>0).join(" | ")}}catch{}let s=i(o),a=n?`Q: ${i(n)} \u2192 A: ${s}`:`answer: ${s}`;return[{type:"decision_question",category:"decision",data:i(a),priority:2}]}function U(t){if(t.tool_name!=="Agent")return[];if(!t.tool_response||t.tool_response.length===0)return[];let e=t.tool_response.length>500?t.tool_response.slice(0,500):t.tool_response;return[{type:"agent_finding",category:"agent-finding",data:i(e),priority:2}]}function K(t){let e=[E(t.tool_input),i(t.tool_response)].join(" ");if(e.length===0)return[];let n=new Set,r=e.match(/https?:\/\/[^\s)]+/g);if(r)for(let c of r)c=c.replace(/["'})\],;.]+$/,""),/localhost|127\.0\.0\.1/i.test(c)||n.add(c);let o=e.match(/(?<!\w)#(\d+)/g);if(o)for(let c of o)n.add(c);if(n.size===0)return[];let s,a=i(t.tool_response).match(/Fetched and indexed[^\(]*\(([\d.]+)\s*KB\)/i);if(a){let c=Number(a[1]);Number.isFinite(c)&&c>0&&(s=Math.round(c*1024))}let u={type:"external_ref",category:"external-ref",data:i(Array.from(n).join(", ")),priority:3};return s!==void 0&&(u.bytes_avoided=s),[u]}function G(t){if(t.tool_name!=="EnterWorktree")return[];let e=String(t.tool_input.name??"unnamed");return[{type:"worktree",category:"env",data:i(`entered worktree: ${e}`),priority:2}]}var v=/[,;,;、،]/u,J=15,q=500;function z(t){if(_.test(t)||!b.test(t)||!v.test(t))return!1;let e=[...t].length;return e>=J&&e<=q}function Q(t){let e=t.trim();return z(e)?[{type:"decision",category:"decision",data:i(t),priority:2}]:[]}var V=8,X=120,Y=new RegExp("\\p{L}+\\s+\\p{L}+","u"),Z=new RegExp("\\p{L}{6,}","u");function tt(t){let e=t.split(/[.!\n。!]/u)[0].trim();if(_.test(e)||v.test(e)||!b.test(e))return!1;let n=[...e].length;return n<V||n>X?!1:Y.test(e)||Z.test(e)}function et(t){let e=t.trim();return tt(e)?[{type:"role",category:"role",data:i(t),priority:3}]:[]}var _=/[??؟¿]/u,b=new RegExp("\\p{L}","u"),nt=60;function rt(t){if(_.test(t)||!b.test(t))return!1;let e=[...t].length;return e>0&&e<nt}function ot(t){let e=t.trim();if(!e)return[];let n;return _.test(e)?n="investigate":rt(e)&&(n="implement"),n?[{type:"intent",category:"intent",data:i(n),priority:4}]:[]}var st=/(?:\bError\s*:|\bException\s*:|\bTraceback\b|\bat\s+\S+\s*\([^)]*:\d+:\d+\))/u,it=/[✓✔✅☑🎉]/u,at=/^\s*(?:fixed|resolved)\s*:/iu;function ct(t){let e=[];return it.test(t)||at.test(t)?(e.push({type:"blocker_resolved",category:"blocked-on",data:i(t),priority:2}),e):(st.test(t)&&e.push({type:"blocker",category:"blocked-on",data:i(t),priority:2}),e)}function lt(t){return t.length<=1024?[]:[{type:"data",category:"data",data:i(t),priority:4}]}var l=null;function pt(t){let{tool_name:e,tool_response:n}=t,r=String(n??"");if(d(t))return l={tool:e,error:r.slice(0,200),callsSince:0},[];if(!l)return[];if(l.callsSince++,l.callsSince>10)return l=null,[];if(!!d(t))return[];let s=e===l.tool,a=l.tool==="Read"&&(e==="Edit"||e==="Write"||e==="apply_patch");if(s||a){let u={type:"error_resolved",category:"error-resolution",data:i(`Error in ${l.tool}: ${l.error} \u2192 Fixed`),priority:2};return l=null,[u]}return[]}function _t(){l=null}var p=[];function ut(t){return`${t.length}:${t.slice(0,20)}`}function ft(t){let{tool_name:e,tool_input:n}=t,r=ut(JSON.stringify(n).slice(0,200));if(p.push({tool:e,inputHash:r}),p.length>50&&p.splice(0,p.length-50),p.length<3)return[];let o=0;for(let s=p.length-1;s>=0&&(p[s].tool===e&&p[s].inputHash===r);s--)o++;return o>=3?(p.splice(p.length-o),[{type:"retry_detected",category:"iteration-loop",data:i(`${e} called ${o} times with similar input`),priority:2}]):[]}function ht(){p.length=0}var dt={run_shell_command:"Bash",read_file:"Read",read_many_files:"Read",grep_search:"Grep",search_file_content:"Grep",web_fetch:"WebFetch",write_file:"Write",edit:"Edit",glob:"Glob",todo_write:"TodoWrite",ask_user_question:"AskUserQuestion",list_directory:"LS",save_memory:"Memory",skill:"Skill",exit_plan_mode:"ExitPlanMode",agent:"Agent",bash:"Bash",view:"Read",grep:"Grep",fetch:"WebFetch",shell:"Bash",shell_command:"Bash",exec_command:"Bash","container.exec":"Bash",local_shell:"Bash",grep_files:"Grep"};function gt(t){let e=dt[t.tool_name];return!e||e===t.tool_name?t:{...t,tool_name:e}}function yt(t){try{let e=gt(t),n=[];return n.push(...A(e)),n.push(...R(e)),n.push(...x(e)),n.push(...w(e)),n.push(...H(e)),n.push(...I(e)),n.push(...N(e)),n.push(...L(e)),n.push(...O(e)),n.push(...P(e)),n.push(...F(e)),n.push(...D(e)),n.push(...$(e)),n.push(...G(e)),n.push(...U(e)),n.push(...K(e)),n.push(...pt(e)),n.push(...ft(e)),n}catch{return[]}}function bt(t){try{let e=[];return e.push(...Q(t)),e.push(...et(t)),e.push(...ot(t)),e.push(...ct(t)),e.push(...lt(t)),e}catch{return[]}}export{yt as extractEvents,bt as extractUserEvents,_t as resetErrorResolutionState,ht as resetIterationLoopState};
|
|
@@ -43,9 +43,12 @@ async function loadSessionDbModule() {
|
|
|
43
43
|
|
|
44
44
|
const _sessionDb = await loadSessionDbModule();
|
|
45
45
|
const {
|
|
46
|
+
ensureWritableStorageDir,
|
|
46
47
|
hashProjectDirCanonical,
|
|
47
48
|
hashProjectDirLegacy,
|
|
48
49
|
normalizeWorktreePath,
|
|
50
|
+
resolveDefaultSessionDir,
|
|
51
|
+
resolveSessionStorageDir,
|
|
49
52
|
resolveSessionPath: _resolveSessionPath,
|
|
50
53
|
getWorktreeSuffix: _getWorktreeSuffixBundle,
|
|
51
54
|
} = _sessionDb;
|
|
@@ -265,9 +268,18 @@ export function getSessionId(input, opts = CLAUDE_OPTS) {
|
|
|
265
268
|
// Per-project file paths — thin wrappers around resolveSessionPath.
|
|
266
269
|
// ─────────────────────────────────────────────────────────
|
|
267
270
|
|
|
271
|
+
function resolveSessionDir(opts) {
|
|
272
|
+
return ensureWritableStorageDir(
|
|
273
|
+
resolveSessionStorageDir(() => resolveDefaultSessionDir({
|
|
274
|
+
configDir: opts.configDir,
|
|
275
|
+
configDirEnv: opts.configDirEnv,
|
|
276
|
+
})),
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
|
|
268
280
|
function _resolveProjectFile(opts, projectDirOverride, ext) {
|
|
269
281
|
const projectDir = normalizeWorktreePath(projectDirOverride ?? getProjectDir(opts));
|
|
270
|
-
const sessionsDir =
|
|
282
|
+
const sessionsDir = resolveSessionDir(opts);
|
|
271
283
|
mkdirSync(sessionsDir, { recursive: true });
|
|
272
284
|
return _resolveSessionPath({
|
|
273
285
|
projectDir,
|
|
@@ -303,4 +315,3 @@ export function getSessionEventsPath(opts = CLAUDE_OPTS, projectDirOverride) {
|
|
|
303
315
|
export function getCleanupFlagPath(opts = CLAUDE_OPTS, projectDirOverride) {
|
|
304
316
|
return _resolveProjectFile(opts, projectDirOverride, ".cleanup");
|
|
305
317
|
}
|
|
306
|
-
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
function a(t){return t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}var
|
|
1
|
+
function a(t){return t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'")}var D=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 e=r.map(n=>`"${a(n)}"`).join(", ");return`
|
|
2
2
|
For full details:
|
|
3
3
|
${a(t)}(
|
|
4
4
|
queries: [${e}],
|
|
5
5
|
source: "session-events"
|
|
6
|
-
)`}function
|
|
6
|
+
)`}function F(t,r){if(t.length===0)return"";let e=new Map;for(let f of t){let S=f.data,p=e.get(S);p||(p={ops:new Map},e.set(S,p));let d;f.type==="file_write"?d="write":f.type==="file_read"?d="read":f.type==="file_edit"?d="edit":d=f.type,p.ops.set(d,(p.ops.get(d)??0)+1)}let o=Array.from(e.entries()).slice(-D),c=[],i=[];for(let[f,{ops:S}]of o){let p=Array.from(S.entries()).map(([b,y])=>`${b}\xD7${y}`).join(", "),d=f.split("/").pop()??f;c.push(` ${a(d)} (${a(p)})`),i.push(`${d} ${Array.from(S.keys()).join(" ")}`)}let s=h(i);return[` <files count="${e.size}">`,...c,m(r,s)," </files>"].join(`
|
|
7
7
|
`)}function B(t,r){if(t.length===0)return"";let e=[],n=[];for(let i of t)e.push(` ${a(i.data)}`),n.push(i.data);let o=h(n);return[` <errors count="${t.length}">`,...e,m(r,o)," </errors>"].join(`
|
|
8
8
|
`)}function J(t,r){if(t.length===0)return"";let e=new Set,n=[],o=[];for(let s of t)e.has(s.data)||(e.add(s.data),n.push(` ${a(s.data)}`),o.push(s.data));if(n.length===0)return"";let c=h(o);return[` <decisions count="${n.length}">`,...n,m(r,c)," </decisions>"].join(`
|
|
9
9
|
`)}function X(t,r){if(t.length===0)return"";let e=new Set,n=[],o=[];for(let s of t)e.has(s.data)||(e.add(s.data),s.type==="rule_content"?n.push(` ${a(s.data)}`):n.push(` ${a(s.data)}`),o.push(s.data));if(n.length===0)return"";let c=h(o);return[` <rules count="${n.length}">`,...n,m(r,c)," </rules>"].join(`
|
|
10
10
|
`)}function G(t,r){if(t.length===0)return"";let e=[],n=[];for(let i of t)e.push(` ${a(i.data)}`),n.push(i.data);let o=h(n);return[` <git count="${t.length}">`,...e,m(r,o)," </git>"].join(`
|
|
11
11
|
`)}function z(t){if(t.length===0)return"";let r=[],e={};for(let s of t)try{let u=JSON.parse(s.data);typeof u.subject=="string"?r.push(u.subject):typeof u.taskId=="string"&&typeof u.status=="string"&&(e[u.taskId]=u.status)}catch{}if(r.length===0)return"";let n=new Set(["completed","deleted","failed"]),o=Object.keys(e).sort((s,u)=>Number(s)-Number(u)),c=[];for(let s=0;s<r.length;s++){let u=o[s],f=u?e[u]??"pending":"pending";n.has(f)||c.push(r[s])}if(c.length===0)return"";let i=[];for(let s of c)i.push(` [pending] ${a(s)}`);return i.join(`
|
|
12
|
-
`)}function
|
|
12
|
+
`)}function P(t,r){let e=z(t);if(!e)return"";let n=[];for(let s of t)try{let u=JSON.parse(s.data);typeof u.subject=="string"&&n.push(u.subject)}catch{}let o=h(n);return[` <task_state count="${e.split(`
|
|
13
13
|
`).length}">`,e,m(r,o)," </task_state>"].join(`
|
|
14
|
-
`)}function
|
|
14
|
+
`)}function H(t,r,e){if(t.length===0&&r.length===0)return"";let n=[],o=[];if(t.length>0){let s=t[t.length-1];n.push(` cwd: ${a(s.data)}`),o.push("working directory")}for(let s of r)n.push(` ${a(s.data)}`),o.push(s.data);let c=h(o);return[" <environment>",...n,m(e,c)," </environment>"].join(`
|
|
15
15
|
`)}function Q(t,r){if(t.length===0)return"";let e=[],n=[];for(let i of t){let s=i.type==="subagent_completed"?"completed":i.type==="subagent_launched"?"launched":"unknown";e.push(` [${s}] ${a(i.data)}`),n.push(`subagent ${i.data}`)}let o=h(n);return[` <subagents count="${t.length}">`,...e,m(r,o)," </subagents>"].join(`
|
|
16
16
|
`)}function U(t,r){if(t.length===0)return"";let e=new Map;for(let s of t){let u=s.data.split(":")[0].trim();e.set(u,(e.get(u)??0)+1)}let n=[],o=[];for(let[s,u]of e)n.push(` ${a(s)} (${u}\xD7)`),o.push(`skill ${s} invocation`);let c=h(o);return[` <skills count="${t.length}">`,...n,m(r,c)," </skills>"].join(`
|
|
17
17
|
`)}function V(t,r){if(t.length===0)return"";let e=new Set,n=[],o=[];for(let s of t)e.has(s.data)||(e.add(s.data),n.push(` ${a(s.data)}`),o.push(s.data));if(n.length===0)return"";let c=h(o);return[` <roles count="${n.length}">`,...n,m(r,c)," </roles>"].join(`
|
|
@@ -21,11 +21,11 @@ function a(t){return t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,"
|
|
|
21
21
|
For FULL DETAILS, run the exact tool call shown under each section.
|
|
22
22
|
Do NOT ask the user to re-explain prior work. Search first.
|
|
23
23
|
Do NOT invent your own queries \u2014 use the ones provided.
|
|
24
|
-
</how_to_search>`);let E=
|
|
24
|
+
</how_to_search>`);let E=F(c,n);E&&l.push(E);let _=B(S,n);_&&l.push(_);let w=J(u,n);w&&l.push(w);let q=X(s,n);q&&l.push(q);let j=G(d,n);j&&l.push(j);let L=P(i,n);L&&l.push(L);let T=H(f,p,n);T&&l.push(T);let M=Q(b,n);M&&l.push(M);let C=U($,n);C&&l.push(C);let A=V(k,n);A&&l.push(A);let I=K(y);I&&l.push(I);let N=tt(v);N&&l.push(N);let O=`<session_resume events="${t.length}" compact_count="${e}" generated_at="${o}">`,R="</session_resume>",x=l.join(`
|
|
25
25
|
|
|
26
|
-
`);return
|
|
26
|
+
`);return x?`${O}
|
|
27
27
|
|
|
28
|
-
${
|
|
28
|
+
${x}
|
|
29
29
|
|
|
30
30
|
${R}`:`${O}
|
|
31
31
|
${R}`}export{st as buildResumeSnapshot,z as renderTaskState};
|
package/openclaw.plugin.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "Context Mode",
|
|
4
4
|
"kind": "tool",
|
|
5
5
|
"description": "OpenClaw plugin that saves 98% of your context window. Sandboxed code execution in 11 languages, FTS5 knowledge base with BM25 ranking, and intent-driven search.",
|
|
6
|
-
"version": "1.0.
|
|
6
|
+
"version": "1.0.147",
|
|
7
7
|
"sandbox": {
|
|
8
8
|
"mode": "permissive",
|
|
9
9
|
"filesystem_access": "full",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "context-mode",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.147",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "MCP plugin that saves 98% of your context window. Works with Claude Code, Gemini CLI, VS Code Copilot, OpenCode, and Codex CLI. Sandboxed code execution, FTS5 knowledge base, and intent-driven search.",
|
|
6
6
|
"author": "Mert Koseoğlu",
|
|
@@ -43,7 +43,9 @@
|
|
|
43
43
|
"omp": {
|
|
44
44
|
"name": "context-mode",
|
|
45
45
|
"description": "Save 98% of your context window in OMP — sandboxed code execution, FTS5 search, hard-block curl/wget, session continuity across compaction.",
|
|
46
|
-
"
|
|
46
|
+
"extensions": [
|
|
47
|
+
"./build/adapters/omp/plugin.js"
|
|
48
|
+
]
|
|
47
49
|
},
|
|
48
50
|
"bugs": "https://github.com/mksglu/context-mode/issues",
|
|
49
51
|
"main": "./build/adapters/opencode/plugin.js",
|