opencode-prompt-recorder 1.7.9 → 1.8.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/dist/index.js CHANGED
@@ -1,17 +1,17 @@
1
- import{mkdir as T,appendFile as V,writeFile as W,readFile as z,rename as lt}from"fs/promises";import{join as l,dirname as B,basename as gt}from"path";import{fileURLToPath as mt}from"url";import{readFile as et,rm as nt}from"fs/promises";import{basename as h,dirname as y,join as I}from"path";import{fileURLToPath as rt}from"url";var it="opencode-prompt-recorder";function st(n){console.error(`[prompt-recorder][autoUpdate] ${n}`)}var H=!1;function J(n,t){if(!t||H)return;H=!0;let r=new AbortController,i=setTimeout(()=>r.abort(),1e4);ot(r.signal).then(e=>{e.updated&&(st(`\u53D1\u73B0\u65B0\u7248\u672C: ${e.current} \u2192 ${e.latest}`),setTimeout(()=>{n.client.tui.showToast({body:{title:"Prompt Recorder \u66F4\u65B0",message:`${e.name} \u5DF2\u4ECE ${e.current} \u66F4\u65B0\u5230 ${e.latest}\uFF0C\u91CD\u542F OpenCode \u5B8C\u6210\u66F4\u65B0`,variant:"info"}})},5e3))}).catch(()=>{}).finally(()=>clearTimeout(i))}async function ot(n){let t=await at(it);if(!t)return{updated:!1};let r=await R(I(t,"package.json"));if(!r?.name||!r.version)return{updated:!1};let i=await pt(r.name,n);if(!i||!ft(i,r.version))return{updated:!1};let e=await ct(t,r.name);if(!e)return{updated:!1};try{await nt(e,{recursive:!0,force:!0})}catch{return{updated:!1,error:"remove_failed",name:r.name,current:r.version,latest:i}}return{updated:!0,name:r.name,current:r.version,latest:i}}async function at(n){let t=y(rt(import.meta.url));for(;;){if((await R(I(t,"package.json")))?.name===n)return h(t)==="dist"?y(t):t;let i=y(t);if(i===t)return;t=i}}async function ct(n,t){let r=y(n),i=h(r).startsWith("@")?y(r):r;if(h(i)!=="node_modules")return;let e=y(i),c=await R(I(e,"package.json")),d=ut(e,t)??c?.dependencies?.[t];if(!(!d||!dt(d)))return e}function ut(n,t){if(t.startsWith("@")){let[e,c]=t.split("/");if(!e||!c||h(y(n))!==e)return;let d=`${c}@`,m=h(n);return m.startsWith(d)?m.slice(d.length):void 0}let r=`${t}@`,i=h(n);return i.startsWith(r)?i.slice(r.length):void 0}function dt(n){let t=n.trim();return t?!!(t==="latest"||t==="*"||/^[~^]/.test(t)||/^(?:>=|>|<=|<)/.test(t)||/\s+(?:\|\||-|[<>=])\s+/.test(t)):!1}async function R(n){try{let t=JSON.parse(await et(n,"utf-8"));return t&&typeof t=="object"?t:void 0}catch{return}}async function pt(n,t){try{let r=await fetch(`https://registry.npmjs.org/${encodeURIComponent(n)}/latest`,{signal:t});if(!r.ok)return;let i=await r.json();if(!i||typeof i!="object")return;let e=i.version;return typeof e=="string"?e:void 0}catch{return}}function ft(n,t){let r=O(n),i=O(t);if(!r||!i)return!1;for(let e=0;e<3;e++)if(r.parts[e]!==i.parts[e])return r.parts[e]>i.parts[e];if(!r.pre.length&&i.pre.length)return!0;if(r.pre.length&&!i.pre.length)return!1;for(let e=0;e<Math.max(r.pre.length,i.pre.length);e++){let c=r.pre[e],d=i.pre[e];if(c===void 0)return!1;if(d===void 0)return!0;if(c===d)continue;let m=/^\d+$/.test(c)?Number(c):void 0,w=/^\d+$/.test(d)?Number(d):void 0;return m!==void 0&&w!==void 0?m>w:m!==void 0?!1:w!==void 0?!0:c>d}return!1}function O(n){let t=n.match(/^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+.+)?$/);if(t)return{parts:[Number(t[1]),Number(t[2]),Number(t[3])],pre:t[4]?.split(".")??[]}}var yt=B(mt(import.meta.url));async function A(n,t){if(process.env.PROMPT_RECORDER_DEBUG!=="1"&&process.env.PROMPT_RECORDER_DEBUG!=="true")return;let i=`[${new Date().toISOString()}] ${t}
2
- `;try{let e=l(n,".agent","prompts-log");await T(e,{recursive:!0}),await V(l(e,"log.txt"),i)}catch(e){console.error("debugLog failed:",e)}}async function ht(){try{return JSON.parse(await z(l(yt,"package.json"),"utf-8")).version}catch{return"unknown"}}var wt=/[<>:"/\\|?*\x00-\x1f]/g;function G(n){return n.split(`
3
- `)[0].trim().replace(/<[^>]*>/g,"").replace(/\s+/g," ").trim().replace(wt,"").substring(0,40).trim()||"untitled"}function $t(n){let t=n.trimStart();return t.startsWith("<system-reminder>")||t.startsWith("<system>")}function kt(n){let t=n.getFullYear().toString(),r=String(n.getMonth()+1).padStart(2,"0"),i=String(n.getDate()).padStart(2,"0"),e=String(n.getHours()).padStart(2,"0"),c=String(n.getMinutes()).padStart(2,"0");return{yyyy:t,MM:r,dd:i,HH:e,mm:c}}var bt=async n=>{J(n,!0);let{directory:t}=n,r=!1,i=new Map,e=new Map,c=new Set,d=new Set,m=1440*60*1e3,w=200,g=new Map,P=new Map;function K(){if(g.size<w)return;let a=Date.now();for(let[s,o]of g)a-o.time>m&&g.delete(s)}async function $(a,s){let o=B(a.filepath),p=gt(a.filepath).match(/^(\d{10})-/);if(!p)return;let u=l(o,`${p[1]}-${G(s)}.txt`);if(u!==a.filepath)try{await lt(a.filepath,u),a.filepath=u}catch{}}return{event:async({event:a})=>{if(a.type==="message.updated"){let s=a.properties.info,o=s?.role||s?.message?.role;s?.id&&o&&e.set(s.id,o)}if(a.type==="message.part.updated"){let s=a.properties.part;if(s?.type==="tool"&&s?.tool==="task"){let o=s.state?.metadata??s.metadata;if(o){let f=o.sessionId??o.sessionID;f&&(d.add(f),await A(t,`[prompt-recorder] tracked task session: ${f}`))}}if(s?.type==="text"&&s?.text){if(s.synthetic||s.ignored)return;let o=s.sessionID,f=s.messageID,p=s.text,u=e.get(f);if(u||(u=s.message?.role),u||(u=a.properties.info?.role),u||(u=a.properties.info?.message?.role),u==="user"&&p&&o){if($t(p)){await A(t,`[prompt-recorder] filtered system-injected: sessionID=${o}`);return}let M=`${f}:${p}`;if(c.has(M))return;c.add(M),await A(t,`[prompt-recorder] event=${a.type}, role=${u}, sessionID=${o}, textLength=${p.length}, textPreview=${p.substring(0,50)}`);let X=new Date,{yyyy:k,MM:b,dd:D,HH:_,mm:E}=kt(X),C=l(t,".agent","prompts"),L=d.has(o)?l(C,"task",k,b,D):l(C,k,b,D);await T(L,{recursive:!0});let Z=k.slice(-2),U=`============ ${k}-${b}-${D} ${_}:${E} ============`,x=g.get(o);if(x)x.time=Date.now(),await V(x.filepath,`
1
+ import{mkdir as L,appendFile as Z,writeFile as B,readFile as Y,rename as $e}from"fs/promises";import{join as l,dirname as q,basename as be}from"path";import{fileURLToPath as De}from"url";import{readFile as ue,rm as de}from"fs/promises";import{basename as h,dirname as y,join as T}from"path";import{fileURLToPath as pe}from"url";var fe="opencode-prompt-recorder",G=!1;function X(i,e){if(!e||G)return;G=!0;let r=new AbortController,s=setTimeout(()=>r.abort(),1e4);le(r.signal).then(n=>{n.updated&&setTimeout(()=>{i.client.tui.showToast({body:{title:"Prompt Recorder \u66F4\u65B0",message:`${n.name} \u5DF2\u4ECE ${n.current} \u66F4\u65B0\u5230 ${n.latest}\uFF0C\u91CD\u542F OpenCode \u5B8C\u6210\u66F4\u65B0`,variant:"info"}})},5e3)}).catch(()=>{}).finally(()=>clearTimeout(s))}async function le(i){let e=await ge(fe);if(!e)return{updated:!1};let r=await C(T(e,"package.json"));if(!r?.name||!r.version)return{updated:!1};let s=await we(r.name,i);if(!s||!ke(s,r.version))return{updated:!1};let n=await me(e,r.name);if(!n)return{updated:!1};try{await de(n,{recursive:!0,force:!0})}catch{return{updated:!1,error:"remove_failed",name:r.name,current:r.version,latest:s}}return{updated:!0,name:r.name,current:r.version,latest:s}}async function ge(i){let e=y(pe(import.meta.url));for(;;){if((await C(T(e,"package.json")))?.name===i)return h(e)==="dist"?y(e):e;let s=y(e);if(s===e)return;e=s}}async function me(i,e){let r=y(i),s=h(r).startsWith("@")?y(r):r;if(h(s)!=="node_modules")return;let n=y(s),c=await C(T(n,"package.json")),u=ye(n,e)??c?.dependencies?.[e];if(!(!u||!he(u)))return n}function ye(i,e){if(e.startsWith("@")){let[n,c]=e.split("/");if(!n||!c||h(y(i))!==n)return;let u=`${c}@`,m=h(i);return m.startsWith(u)?m.slice(u.length):void 0}let r=`${e}@`,s=h(i);return s.startsWith(r)?s.slice(r.length):void 0}function he(i){let e=i.trim();return e?!!(e==="latest"||e==="*"||/^[~^]/.test(e)||/^(?:>=|>|<=|<)/.test(e)||/\s+(?:\|\||-|[<>=])\s+/.test(e)):!1}async function C(i){try{let e=JSON.parse(await ue(i,"utf-8"));return e&&typeof e=="object"?e:void 0}catch{return}}async function we(i,e){try{let r=await fetch(`https://registry.npmjs.org/${encodeURIComponent(i)}/latest`,{signal:e});if(!r.ok)return;let s=await r.json();if(!s||typeof s!="object")return;let n=s.version;return typeof n=="string"?n:void 0}catch{return}}function ke(i,e){let r=V(i),s=V(e);if(!r||!s)return!1;for(let n=0;n<3;n++)if(r.parts[n]!==s.parts[n])return r.parts[n]>s.parts[n];if(!r.pre.length&&s.pre.length)return!0;if(r.pre.length&&!s.pre.length)return!1;for(let n=0;n<Math.max(r.pre.length,s.pre.length);n++){let c=r.pre[n],u=s.pre[n];if(c===void 0)return!1;if(u===void 0)return!0;if(c===u)continue;let m=/^\d+$/.test(c)?Number(c):void 0,w=/^\d+$/.test(u)?Number(u):void 0;return m!==void 0&&w!==void 0?m>w:m!==void 0?!1:w!==void 0?!0:c>u}return!1}function V(i){let e=i.match(/^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+.+)?$/);if(e)return{parts:[Number(e[1]),Number(e[2]),Number(e[3])],pre:e[4]?.split(".")??[]}}var Me=q(De(import.meta.url));async function U(i,e){if(process.env.PROMPT_RECORDER_DEBUG!=="1"&&process.env.PROMPT_RECORDER_DEBUG!=="true")return;let s=`[${new Date().toISOString()}] ${e}
2
+ `;try{let n=l(i,".agent","prompts-log");await L(n,{recursive:!0}),await Z(l(n,"log.txt"),s)}catch(n){console.error("debugLog failed:",n)}}var A="";async function Pe(){if(A)return A;try{return A=JSON.parse(await Y(l(Me,"package.json"),"utf-8")).version||"unknown",A}catch{return"unknown"}}var Se=/[<>:"/\\|?*\x00-\x1f]/g;function K(i){return i.split(`
3
+ `)[0].trim().replace(/<[^>]*>/g,"").replace(/\s+/g," ").trim().replace(Se,"").substring(0,40).trim()||"untitled"}function ve(i){let e=i.trimStart();return e.startsWith("<system-reminder>")||e.startsWith("<system>")}function Ae(i){let e=i.getFullYear().toString(),r=String(i.getMonth()+1).padStart(2,"0"),s=String(i.getDate()).padStart(2,"0"),n=String(i.getHours()).padStart(2,"0"),c=String(i.getMinutes()).padStart(2,"0");return{yyyy:e,MM:r,dd:s,HH:n,mm:c}}var xe=async i=>{X(i,!0);let{directory:e}=i,r=!1,s=new Map,n=new Map,c=new Map,u=new Map,m=1440*60*1e3,w=200,x=2e3,I=1440*60*1e3,g=new Map,_=new Map;function Q(){if(g.size<w)return;let o=Date.now();for(let[t,a]of g)o-a.time>m&&g.delete(t)}function ee(){let o=Date.now();if(c.size>x)for(let[t,a]of c)o-a>I&&c.delete(t);if(n.size>x)for(let[t,a]of n)o-a.time>I&&n.delete(t);if(u.size>x)for(let[t,a]of u)o-a>I&&u.delete(t)}async function D(o,t){let a=q(o.filepath),p=be(o.filepath).match(/^(\d{10})-/);if(!p)return;let d=l(a,`${p[1]}-${K(t)}.txt`);if(d!==o.filepath)try{await $e(o.filepath,d),o.filepath=d}catch(k){console.error(`[prompt-recorder] rename failed: ${o.filepath}`,k)}}async function te(o){let t=o.properties.info,a=t?.id,f=t?.role||t?.message?.role;a&&f&&n.set(a,{role:f,time:Date.now()})}async function ne(o){let t=o.properties.part;if(t?.type==="tool"&&t?.tool==="task"){let $=t.state?.metadata??t.metadata;if($){let b=$.sessionId??$.sessionID;b&&(u.set(b,Date.now()),await U(e,`[prompt-recorder] tracked task session: ${b}`))}}if(t?.type!=="text"||!t?.text||t.synthetic||t.ignored)return;let a=t.sessionID,f=t.messageID,p=t.text,d=n.get(f)?.role;if(d||(d=t.message?.role),d||(d=o.properties.info?.role),d||(d=o.properties.info?.message?.role),d!=="user"||!p||!a)return;if(ve(p)){await U(e,`[prompt-recorder] filtered system-injected: sessionID=${a}`);return}let k=`${f}:${p}`;if(c.has(k))return;c.set(k,Date.now()),ee(),await U(e,`[prompt-recorder] event=${o.type}, role=${d}, sessionID=${a}, textLength=${p.length}, textPreview=${p.substring(0,50)}`);let ie=new Date,{yyyy:M,MM:P,dd:S,HH:j,mm:F}=Ae(ie),N=l(e,".agent","prompts"),O=u.has(a)?l(N,"task",M,P,S):l(N,M,P,S);await L(O,{recursive:!0});let ae=M.slice(-2),H=`============ ${M}-${P}-${S} ${j}:${F} ============`,R=g.get(a);if(R)R.time=Date.now(),await Z(R.filepath,`
4
4
 
5
- ${U}
5
+ ${H}
6
6
 
7
- ${p}`);else{let Y=G(i.get(o)??p),q=`${Z}${b}${D}${_}${E}-${Y}.txt`,j=l(L,q),Q=`============ SessionID: ${o} ============`;await W(j,`${Q}
7
+ ${p}`);else{let $=K(s.get(a)??p),b=`${ae}${P}${S}${j}${F}-${$}.txt`,J=l(O,b),oe=`============ SessionID: ${a} ============`;await B(J,`${oe}
8
8
 
9
- ${U}
9
+ ${H}
10
10
 
11
- ${p}`),g.set(o,{filepath:j,time:Date.now()}),K();let F=P.get(o);if(F){P.delete(o);let v=g.get(o);v&&await $(v,F)}setTimeout(async()=>{try{let S=(await n.client.session.get({path:{id:o}}))?.data?.title;if(!S)return;let tt=i.get(o);if(S===tt)return;i.set(o,S);let N=g.get(o);N&&await $(N,S)}catch{}},5e3)}}}}if(a.type==="session.created"){let s=a.properties.info;if(s?.id&&s?.title){i.set(s.id,s.title);let o=g.get(s.id);o&&await $(o,s.title)}}if(a.type==="session.updated"){let s=a.properties.info;if(s?.id&&s?.title){let o=i.get(s.id);if(i.set(s.id,s.title),o!==s.title){let f=g.get(s.id);f?await $(f,s.title):P.set(s.id,s.title)}}if(!r)try{let o=await ht(),f=l(t,".agent"),p=l(f,"opencode-prompt-recorder-readme.txt"),u=`# OpenCode Prompt Recorder
11
+ ${p}`),g.set(a,{filepath:J,time:Date.now()}),Q();let W=_.get(a);if(W){_.delete(a);let E=g.get(a);E&&await D(E,W)}setTimeout(async()=>{try{let v=(await i.client.session.get({path:{id:a}}))?.data?.title;if(!v)return;let ce=s.get(a);if(v===ce)return;s.set(a,v);let z=g.get(a);z&&await D(z,v)}catch{}},5e3)}}async function re(o){let t=o.properties.info;if(t?.id&&t?.title){s.set(t.id,t.title);let a=g.get(t.id);a&&await D(a,t.title)}}async function se(o){let t=o.properties.info;if(t?.id&&t?.title){let a=s.get(t.id);if(s.set(t.id,t.title),a!==t.title){let f=g.get(t.id);f?await D(f,t.title):_.set(t.id,t.title)}}if(!r)try{let a=await Pe(),f=l(e,".agent"),p=l(f,"opencode-prompt-recorder-readme.txt"),d=`# OpenCode Prompt Recorder
12
12
 
13
13
  \u81EA\u52A8\u8BB0\u5F55\u7528\u6237\u63D0\u793A\u8BCD\u5230 .agent/prompts \u76EE\u5F55\u7684\u63D2\u4EF6\u3002
14
14
 
15
- \u7248\u672C\uFF1A${o}
15
+ \u7248\u672C\uFF1A${a}
16
16
  \u4F5C\u8005\uFF1Aanarckk
17
- \u9879\u76EE\u5730\u5740\uFF1Ahttps://github.com/anarckk/opencode-prompt-recorder`;try{if(await z(p,"utf-8")===u){r=!0;return}}catch{}await T(f,{recursive:!0}),await W(p,u),r=!0}catch{}}}}},Tt=bt;export{bt as OpenCodePromptRecorder,Tt as default};
17
+ \u9879\u76EE\u5730\u5740\uFF1Ahttps://github.com/anarckk/opencode-prompt-recorder`;try{if(await Y(p,"utf-8")===d){r=!0;return}}catch{}await L(f,{recursive:!0}),await B(p,d),r=!0}catch{}}return{event:async({event:o})=>{switch(o.type){case"message.updated":await te(o);break;case"message.part.updated":await ne(o);break;case"session.created":await re(o);break;case"session.updated":await se(o);break}}}},Fe=xe;export{xe as OpenCodePromptRecorder,Fe as default};
package/dist/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-prompt-recorder",
3
- "version": "1.7.9",
3
+ "version": "1.8.0",
4
4
  "description": "OpenCode plugin for recording user prompts. Automatically saves user messages to a local file system with organized directory structure.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -15,8 +15,8 @@
15
15
  "dist"
16
16
  ],
17
17
  "scripts": {
18
- "build": "if (Test-Path dist) { Remove-Item -Recurse -Force dist }; npx esbuild index.ts --bundle --platform=node --outdir=dist --format=esm --external:@opencode-ai/plugin --minify; Copy-Item package.json dist/",
19
- "build:uncompressed": "if (Test-Path dist) { Remove-Item -Recurse -Force dist }; npx esbuild index.ts --bundle --platform=node --outdir=dist --format=esm --external:@opencode-ai/plugin; Copy-Item package.json dist/",
18
+ "build": "node -e \"fs.rmSync('dist',{force:true,recursive:true})\" && npx esbuild index.ts --bundle --platform=node --outdir=dist --format=esm --external:@opencode-ai/plugin --minify && node -e \"fs.copyFileSync('package.json','dist/package.json')\"",
19
+ "build:uncompressed": "node -e \"fs.rmSync('dist',{force:true,recursive:true})\" && npx esbuild index.ts --bundle --platform=node --outdir=dist --format=esm --external:@opencode-ai/plugin && node -e \"fs.copyFileSync('package.json','dist/package.json')\"",
20
20
  "prepublishOnly": "npm run build",
21
21
  "publish": "node scripts/publish-npmjs.js",
22
22
  "test": "npx tsx test/index.ts"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-prompt-recorder",
3
- "version": "1.7.9",
3
+ "version": "1.8.0",
4
4
  "description": "OpenCode plugin for recording user prompts. Automatically saves user messages to a local file system with organized directory structure.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -15,8 +15,8 @@
15
15
  "dist"
16
16
  ],
17
17
  "scripts": {
18
- "build": "if (Test-Path dist) { Remove-Item -Recurse -Force dist }; npx esbuild index.ts --bundle --platform=node --outdir=dist --format=esm --external:@opencode-ai/plugin --minify; Copy-Item package.json dist/",
19
- "build:uncompressed": "if (Test-Path dist) { Remove-Item -Recurse -Force dist }; npx esbuild index.ts --bundle --platform=node --outdir=dist --format=esm --external:@opencode-ai/plugin; Copy-Item package.json dist/",
18
+ "build": "node -e \"fs.rmSync('dist',{force:true,recursive:true})\" && npx esbuild index.ts --bundle --platform=node --outdir=dist --format=esm --external:@opencode-ai/plugin --minify && node -e \"fs.copyFileSync('package.json','dist/package.json')\"",
19
+ "build:uncompressed": "node -e \"fs.rmSync('dist',{force:true,recursive:true})\" && npx esbuild index.ts --bundle --platform=node --outdir=dist --format=esm --external:@opencode-ai/plugin && node -e \"fs.copyFileSync('package.json','dist/package.json')\"",
20
20
  "prepublishOnly": "npm run build",
21
21
  "publish": "node scripts/publish-npmjs.js",
22
22
  "test": "npx tsx test/index.ts"