wyrm-mcp 9.2.2 → 9.2.3
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/activation.js +1 -1
- package/dist/agent-loop.js +2 -2
- package/dist/audit.js +2 -2
- package/dist/autoconfig.js +6 -6
- package/dist/backup-cli.js +6 -0
- package/dist/backup.js +1 -0
- package/dist/bridge.js +1 -1
- package/dist/buddy-runner.js +1 -1
- package/dist/buddy.js +4 -4
- package/dist/capabilities.js +1 -1
- package/dist/causality.js +3 -3
- package/dist/cloud/cli.js +3 -3
- package/dist/cloud/sync-daemon-entrypoint.js +1 -1
- package/dist/cloud/sync-engine.js +8 -7
- package/dist/cloud-backup.js +4 -4
- package/dist/cloud-sync-entrypoint.js +1 -1
- package/dist/cloud-sync.js +1 -1
- package/dist/connectors/ingest.js +2 -2
- package/dist/constellation.js +1 -1
- package/dist/context-build-budgeted.js +4 -4
- package/dist/context-ranking.js +1 -1
- package/dist/daemon-writer.js +1 -1
- package/dist/database.js +41 -23
- package/dist/design.js +1 -1
- package/dist/erasure-cli.js +3 -0
- package/dist/erasure-log.js +8 -0
- package/dist/erasure.js +1 -0
- package/dist/event-replication.js +1 -1
- package/dist/events.js +11 -11
- package/dist/failure-patterns.js +67 -44
- package/dist/federation.js +11 -10
- package/dist/governance.js +1 -0
- package/dist/handlers/agent.js +4 -4
- package/dist/handlers/alias-adapters.js +1 -1
- package/dist/handlers/audit.js +1 -1
- package/dist/handlers/boundary.js +1 -1
- package/dist/handlers/capture.js +54 -52
- package/dist/handlers/causality.js +2 -2
- package/dist/handlers/cloud.js +9 -9
- package/dist/handlers/companion.js +4 -4
- package/dist/handlers/entity.js +6 -6
- package/dist/handlers/events.js +4 -4
- package/dist/handlers/failure.js +15 -12
- package/dist/handlers/goals.js +2 -2
- package/dist/handlers/intelligence.js +81 -74
- package/dist/handlers/mcpclient.js +3 -3
- package/dist/handlers/presence.js +1 -1
- package/dist/handlers/prompts.js +2 -2
- package/dist/handlers/quest.js +11 -4
- package/dist/handlers/recall.js +10 -10
- package/dist/handlers/resources.js +1 -1
- package/dist/handlers/review.js +3 -3
- package/dist/handlers/run.js +3 -3
- package/dist/handlers/search.js +1 -1
- package/dist/handlers/session.js +27 -25
- package/dist/handlers/share.js +3 -3
- package/dist/handlers/skill.js +2 -2
- package/dist/handlers/symbols.js +5 -5
- package/dist/handlers/syncops.js +2 -2
- package/dist/harvest.js +5 -5
- package/dist/hours.js +1 -1
- package/dist/http-auth.js +2 -2
- package/dist/http-fast.js +17 -17
- package/dist/http-projects.js +4 -0
- package/dist/http-rate-limit.js +1 -0
- package/dist/index-health.js +52 -0
- package/dist/index.js +2 -2
- package/dist/indexer.js +4 -4
- package/dist/intelligence.js +36 -29
- package/dist/lane-provenance.js +39 -0
- package/dist/license.js +1 -1
- package/dist/lineage.js +15 -0
- package/dist/live-embedding-state.js +2 -2
- package/dist/maintenance.js +2 -2
- package/dist/mcp-integrity.js +2 -2
- package/dist/memory-artifacts.js +39 -37
- package/dist/metabolize.js +9 -7
- package/dist/metrics.js +1 -1
- package/dist/migrate-prompt.js +1 -1
- package/dist/migrations.js +236 -45
- package/dist/priority-embed.js +1 -1
- package/dist/providers/embedding-provider.js +1 -1
- package/dist/readonly-gate.js +1 -1
- package/dist/redact-backfill.js +1 -0
- package/dist/rehydration.js +30 -20
- package/dist/reindex.js +1 -1
- package/dist/render-target.js +6 -6
- package/dist/repl-guard.js +1 -1
- package/dist/replication-daemon-entrypoint.js +1 -1
- package/dist/replication-daemon.js +1 -1
- package/dist/retention.js +1 -0
- package/dist/reverse-bridge.js +6 -6
- package/dist/review-sample.js +31 -0
- package/dist/security.js +1 -1
- package/dist/self-maintenance.js +4 -4
- package/dist/served-records.js +8 -2
- package/dist/setup-wizard.js +1 -1
- package/dist/setup.js +1 -1
- package/dist/skill-author.js +2 -2
- package/dist/store-open.js +1 -0
- package/dist/store-readonly.js +1 -0
- package/dist/sub-agent.js +2 -2
- package/dist/tool-manifest-v2.json +1 -1
- package/dist/tool-manifest.json +1 -1
- package/dist/truth-freshness.js +8 -0
- package/dist/ui-dashboard.js +4 -4
- package/dist/vault.js +1 -1
- package/dist/vector-init.js +1 -1
- package/dist/vectors.js +4 -3
- package/dist/visibility.js +12 -12
- package/dist/write-guard.js +1 -0
- package/dist/wyrm-cli.js +108 -92
- package/dist/wyrm-guard.js +13 -12
- package/dist/wyrm-loop.js +3 -3
- package/dist/wyrm-manifest.json +1 -1
- package/dist/wyrm-memo.js +5 -5
- package/package.json +1 -1
- package/scripts/hooks/wyrm-session-capture.mjs +3 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{readFileSync as
|
|
2
|
-
WHERE type='table' AND name NOT LIKE 'sqlite_%'`).all();for(const r of
|
|
1
|
+
import{readFileSync as V,writeFileSync as G,existsSync as J}from"node:fs";import{join as Y}from"node:path";import{createHash as K}from"node:crypto";import{WyrmDB as Q,resolveDbPath as B}from"../database.js";import{getLineage as X,getCursor as j,setCursor as z,importCursorFile as Z,bumpDeviceEpoch as ee,mirrorStamp as U}from"../lineage.js";import{CloudClient as te,loadSession as ne,saveSession as se,resolveCloudDir as oe}from"./client.js";import{encrypt as M,decrypt as re}from"./crypto.js";import{classifySession as ie,computeMachineFp as ae}from"./machine-id.js";function A(){return Y(oe(),"cloud-cursor.json")}const W=2;function ce(e,t,s,o){const n=e?{...e}:{kind:t.kind,row_id:t.row_id,attempts:0,quarantined:!1,last_error:s,first_ms:o,last_ms:o};n.attempts+=1,n.last_error=s,n.last_ms=o;const r=n.attempts>=W,c=r&&!n.quarantined;return r&&(n.quarantined=!0),{entry:n,action:r?"skip":"retry",newlyQuarantined:c}}const $=[{kind:"truth",table:"ground_truths",hasVisibility:!0},{kind:"memory_artifact",table:"memory_artifacts",hasVisibility:!0},{kind:"quest",table:"quests",hasVisibility:!0},{kind:"design_token",table:"design_tokens",hasVisibility:!0},{kind:"design_reference",table:"design_references",hasVisibility:!0},{kind:"skill",table:"skills",hasVisibility:!0}],le=new Set(["sessions","agent_actions","agent_presence","session_seen_artifacts","tool_call_log","llm_query_log","external_call_log","token_savings_log","cost_tracking","usage_events","audit_log","indexing_queue","vectors","symbol_index","update_check","sync_conflicts","sync_log","sync_tombstones","wyrm_cloud_sync_state","mcp_client_configs","watch_dirs","global_context","schema_versions","failure_patterns","data_lake","projects"]),ue=/_fts(_config|_data|_docsize|_idx)?$/;function de(e){const t=e.getDatabase(),s=[...$],o=new Set($.map(n=>n.table));try{const n=t.prepare(`SELECT name FROM sqlite_master
|
|
2
|
+
WHERE type='table' AND name NOT LIKE 'sqlite_%'`).all();for(const r of n){const c=r.name;if(o.has(c)||le.has(c)||ue.test(c)||!g.test(c))continue;const i=t.prepare(`PRAGMA table_info(${c})`).all();if(!i.some(l=>l.name==="id"))continue;const a=i.some(l=>l.name==="cross_project_visibility");s.push({kind:c,table:c,hasVisibility:a})}}catch{}return s}function je(e){return e}function F(e,t){if(!g.test(t))return new Set;try{const o=e.getDatabase().prepare(`PRAGMA table_info(${t})`).all();return new Set(o.filter(n=>g.test(n.name)).map(n=>n.name))}catch{return new Set}}const g=/^[a-z_][a-z0-9_]*$/i;function pe(){const e=A();if(!J(e))return null;try{const t=JSON.parse(V(e,"utf-8"));return t&&typeof t=="object"&&!Array.isArray(t)?t:null}catch{return null}}function _e(e){const t={pull_cursor:0,last_push_updated_ms:0,last_push_at:0,last_pull_at:0},s=X(e),o=pe();let n=j(e,"cloud");if(!n){if(Z(e,"cloud",A()),n=j(e,"cloud"),!n){if(!o)return t;const{store:c,...i}=o;return{...t,...i}}return{...t,...n.value}}const r=o?.store;return o&&r&&r.device_id===s.deviceId&&r.epoch===s.epoch&&r.fingerprint===U(e).fingerprint&&Number(o.last_pull_at??0)>Number(n.value.last_pull_at??0)&&ee(e,"cloud-cursor.json is ahead of the database (restored in place)"),{...t,...n.value}}function fe(e,t){try{z(e,"cloud",t)}catch{}G(A(),JSON.stringify({...t,store:U(e)},null,2),{mode:384})}function x(e){e.getDatabase().exec(`
|
|
3
3
|
CREATE TABLE IF NOT EXISTS sync_tombstones (
|
|
4
4
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
5
5
|
kind TEXT NOT NULL,
|
|
@@ -10,11 +10,12 @@ import{readFileSync as O,writeFileSync as D,existsSync as I}from"node:fs";import
|
|
|
10
10
|
);
|
|
11
11
|
CREATE INDEX IF NOT EXISTS idx_sync_tombstones_pending
|
|
12
12
|
ON sync_tombstones(pushed_at_ms);
|
|
13
|
-
`)}function
|
|
14
|
-
VALUES (?, ?, ?)`).run(
|
|
15
|
-
`)),console.error(" Proceeding anyway (--force / WYRM_ALLOW_COPIED_SESSION=1); fingerprint updated."),console.error(""),
|
|
16
|
-
`)),new
|
|
13
|
+
`)}function Ue(e,t,s){if(typeof t!="string"||t.length===0||t.length>64)return;x(e),e.getDatabase().prepare(`INSERT OR IGNORE INTO sync_tombstones (kind, row_id, deleted_at_ms)
|
|
14
|
+
VALUES (?, ?, ?)`).run(t,String(s),Date.now())}class me extends Error{constructor(t){super(t),this.name="CopiedSessionError"}}function he(e){return!!e||process.env.WYRM_ALLOW_COPIED_SESSION==="1"}function ye(e,t,s){const o=ie(e.machine_fp);if(o.state==="match")return;if(o.state==="adopt"){t(ae());return}const n=["","\u26A0 WYRM CLOUD: this session looks COPIED from another machine.","",` Stored machine fingerprint: ${o.stored.slice(0,12)}\u2026`,` This machine's fingerprint: ${o.current.slice(0,12)}\u2026`,""," Both machines now share ONE device_id. The cloud pull query skips a"," device's own deltas, so each machine filters the OTHER's changes out:"," push works but pull silently returns 0 rows (peer memory looks MISSING).",""," FIX: give this machine its own identity (keep your encryption key):"," rm ~/.wyrm/cloud.json ~/.wyrm/cloud-cursor.json # NOT cloud.key"," wyrm cloud login",""," If this is a legitimate change (e.g. you renamed this host), re-run with:"," wyrm cloud sync --force (or set WYRM_ALLOW_COPIED_SESSION=1)",""];if(he(s)){console.error(n.join(`
|
|
15
|
+
`)),console.error(" Proceeding anyway (--force / WYRM_ALLOW_COPIED_SESSION=1); fingerprint updated."),console.error(""),t(o.current);return}throw console.error(n.join(`
|
|
16
|
+
`)),new me("Cloud session looks copied from another machine (device_id collision). Re-login or pass --force.")}async function Me(e={}){const t=ne();if(!t||!t.device_id)throw new Error("Not logged in or device not registered. Run `wyrm cloud login`.");ye(t,n=>{se({...t,machine_fp:n})},e.force);const s=new te(t.base,t.session),o=new Q(B());try{return await Ee(o,s,t.device_id,e)}finally{try{o.close()}catch{}}}async function Ee(e,t,s,o){x(e);const n=e.getDatabase(),r=_e(n),c=Math.max(Number(r.last_pull_at)||0,Number(r.last_push_at)||0),i={pushed:0,pulled:0,deleted_local:0,errors:[],quarantined:0,conflicts:0},a=o.all?de(e):$,l=ge(e,a,r.last_push_updated_ms,!!o.all,i.errors),E=be(e),S=[...l.map(p=>({kind:p.kind,row_id:String(p.row_id),visibility:p.visibility,payload_b64:M(JSON.stringify(p.row)),updated_at:p.updated_at})),...E.map(p=>({kind:"tombstone",row_id:`${p.kind}:${p.row_id}`,visibility:"org",payload_b64:M(JSON.stringify({kind:p.kind,row_id:p.row_id,deleted_at_ms:p.deleted_at_ms})),updated_at:p.deleted_at_ms}))];if(S.length>0&&!o.dryRun){let y=r.last_push_updated_ms;for(let m=0;m<S.length;m+=25){const u=S.slice(m,m+25);try{const _=await t.syncPush(s,u);if(i.pushed+=_.accepted,_.rejected>0)for(const d of _.rejected_details)i.errors.push(`push: ${d.reason} on ${d.id.slice(0,8)}\u2026`);for(const d of u)d.updated_at&&d.updated_at>y&&(y=d.updated_at)}catch(_){i.errors.push(`push chunk failed: ${_ instanceof Error?_.message:_}`)}}r.last_push_updated_ms=y,r.last_push_at=Date.now(),E.length>0&&Se(e,E.map(m=>m.id))}else i.pushed=S.length;if(!o.dryRun){let p=r.pull_cursor,y=0;e:for(;y<50;){let m;try{m=await t.syncPull(s,p,100)}catch(u){i.errors.push(`pull failed: ${u instanceof Error?u.message:u}`);break}if(m.deltas.length===0)break;for(const u of m.deltas)try{const _=re(u.payload_b64);if(u.kind==="tombstone"){const{kind:d,row_id:h}=JSON.parse(_);Re(e,a,d,h)&&i.deleted_local++}else{const d=JSON.parse(_);Ne(e,a,u.kind,u.row_id,d,{remoteOrigin:`cloud:${u.device_id??"unknown"}`,lastSyncMs:c}).conflictId!==void 0&&(i.conflicts=(i.conflicts??0)+1),i.pulled++}}catch(_){const d=_ instanceof Error?_.message:String(_),h=r.quarantine??={},{entry:b,action:R,newlyQuarantined:w}=ce(h[u.id],u,d,Date.now());if(h[u.id]=b,R==="skip"){w&&(i.quarantined=(i.quarantined??0)+1),i.errors.push(`quarantined ${u.kind}:${u.row_id} after ${b.attempts} attempts (${d})`);continue}i.errors.push(`apply ${u.kind}:${u.row_id}: ${d} (attempt ${b.attempts}/${W}, will retry)`);break e}if(p=m.next_cursor,!m.has_more)break;y++}r.pull_cursor=p,r.last_pull_at=Date.now()}return fe(n,r),i}function C(e){if(typeof e!="string"||e.length===0)return 0;const t=e.includes("T")?e:e.replace(" ","T")+"Z",s=Date.parse(t);return Number.isFinite(s)?s:0}function k(e,t,s){try{return e.getDatabase().prepare(`PRAGMA table_info(${t})`).all().some(r=>r.name===s)}catch{return!1}}function ge(e,t,s,o,n){const r=[],c=e.getDatabase(),i=k(e,"projects","sync_policy");for(const a of t)if(g.test(a.table)&&!(!o&&!a.hasVisibility))try{const l=k(e,a.table,"updated_at"),E=a.hasVisibility?"WHERE cross_project_visibility IN ('org', 'public')":"WHERE 1=1",S=i&&k(e,a.table,"project_id")?"AND (project_id IS NULL OR project_id IN (SELECT id FROM projects WHERE sync_policy IN ('cloud', 'team')))":"",p=l?"AND (? = 0 OR updated_at IS NULL OR strftime('%s', updated_at) * 1000 > ?)":"",y=l?"ORDER BY (updated_at IS NULL) ASC, updated_at ASC":"",m=`SELECT * FROM ${a.table} ${E} ${S} ${p} ${y}`,u=c.prepare(m),_=l?u.all(s,s):u.all();for(const d of _){const h=C(d.updated_at);if(s>0&&h>0&&h<=s)continue;const b=a.hasVisibility?String(d.cross_project_visibility??"within"):"org";r.push({kind:a.kind,row_id:d.id??"?",visibility:b,row:d,updated_at:h||Date.now()})}}catch(l){const E=l instanceof Error?l.message:String(l);if(/no such table/i.test(E))continue;n.push(`collect ${a.table}: ${E}`)}return r.sort((a,l)=>(a.updated_at??0)-(l.updated_at??0)),r}function be(e){const t=e.getDatabase();try{return t.prepare(`SELECT id, kind, row_id, deleted_at_ms
|
|
17
17
|
FROM sync_tombstones
|
|
18
18
|
WHERE pushed_at_ms IS NULL
|
|
19
19
|
ORDER BY id ASC
|
|
20
|
-
LIMIT 500`).all()}catch{return[]}}function
|
|
20
|
+
LIMIT 500`).all()}catch{return[]}}function Se(e,t){if(t.length===0)return;const s=e.getDatabase(),o=Date.now(),n=s.prepare("UPDATE sync_tombstones SET pushed_at_ms = ? WHERE id = ?"),r=s.transaction(c=>{for(const i of c)n.run(o,i)});try{r(t)}catch{}}const H=new Set(["updated_at","last_accessed_at","access_count","reuse_count","reuse_success_count","reuse_failure_count","usage_count","last_used","last_validated_at","last_verified_at"]),T=e=>e==null?null:String(e);function q(e,t){const s=t.filter(o=>!H.has(o)).sort().map(o=>[o,T(e[o])]);return K("sha256").update(JSON.stringify(s)).digest("hex")}function D(e,t,s,o,n,r,c){const i=Number(s);if(Number.isSafeInteger(i))try{const a=JSON.stringify(o),l=e.prepare("SELECT id FROM sync_conflicts WHERE resolved_at IS NULL AND source = 'cloud' AND local_kind = ? AND local_id = ? AND remote_payload = ?").get(t,i,a);return l?l.id:Number(e.prepare(`INSERT INTO sync_conflicts (local_kind, local_id, remote_payload, remote_origin, source, winner, local_payload)
|
|
21
|
+
VALUES (?, ?, ?, ?, 'cloud', ?, ?)`).run(t,i,a,c,r,JSON.stringify(n)).lastInsertRowid)}catch{return}}function Ne(e,t,s,o,n,r={remoteOrigin:"cloud",lastSyncMs:0}){const c=t.find(f=>f.kind===s);if(!c)return{action:"skipped"};if(!g.test(c.table))throw new Error(`apply ${s}: refusing unsafe table name ${c.table}`);const i=F(e,c.table);if(i.size===0)throw new Error(`apply ${s}: ${c.table} has no readable schema`);const a=Object.keys(n).filter(f=>i.has(f)&&g.test(f));if(a.length===0)throw new Error(`apply ${s}: no columns from peer payload matched local schema`);const l=e.getDatabase(),E=a.map(()=>"?").join(","),S=a.join(","),p=a.map(f=>n[f]),y=a.filter(f=>f!=="id"),m=y.map(f=>`${f} = ?`).join(", "),u=n.id,_=(f,O)=>{try{return f==="insert"?l.prepare(`INSERT INTO ${c.table} (${S}) VALUES (${E})`).run(...p):y.length>0&&l.prepare(`UPDATE ${c.table} SET ${m} WHERE id = ?`).run(...y.map(N=>n[N]),u),{action:O}}catch(N){const I=we(N)?Te(l,c.table,i,n):void 0;if(!I)throw new Error(`apply ${s} failed: ${N instanceof Error?N.message:N}`);return{action:"kept_local",conflictId:D(l,s,I.id,n,I,"local",r.remoteOrigin)}}},d=!i.has("id")||u===void 0||u===null?void 0:l.prepare(`SELECT * FROM ${c.table} WHERE id = ?`).get(u);if(!d)return _("insert","inserted");if(!a.some(f=>!H.has(f)&&T(d[f])!==T(n[f])))return{action:"identical"};if(P(l,c.table,i,n).some(f=>f.some(O=>T(d[O])!==T(n[O]))))return{action:"kept_local",conflictId:D(l,s,d.id,n,d,"local",r.remoteOrigin)};const h=i.has("updated_at")?C(d.updated_at):0,b=i.has("updated_at")?C(n.updated_at):0;if(h===0||b===0)return _("update","updated");const R=h===b,w=R?q(n,a)>q(d,a):b>h,L=R||!w||r.lastSyncMs>0&&h>r.lastSyncMs?D(l,s,u,n,d,w?"remote":"local",r.remoteOrigin):void 0;if(!w)return{action:"kept_local",conflictId:L};const v=_("update","updated");return v.action==="kept_local"?v:{action:"updated",conflictId:L}}const we=e=>e?.code==="SQLITE_CONSTRAINT_UNIQUE"||/UNIQUE constraint failed/i.test(e instanceof Error?e.message:String(e));function P(e,t,s,o){const n=[];if(!g.test(t))return n;const r=e.prepare(`PRAGMA index_list(${t})`).all();for(const c of r){if(!c.unique||c.origin==="pk"||c.partial||!g.test(c.name))continue;const i=e.prepare(`PRAGMA index_info(${c.name})`).all().map(a=>a.name);i.length===0||i.some(a=>!a||!g.test(a)||!s.has(a)||!(a in o))||n.push(i)}return n}function Te(e,t,s,o){for(const n of P(e,t,s,o)){const r=n.map(i=>`${i} IS ?`).join(" AND "),c=e.prepare(`SELECT * FROM ${t} WHERE ${r}`).get(...n.map(i=>o[i]));if(c)return c}}function Re(e,t,s,o){const n=t.find(a=>a.kind===s);if(!n||!g.test(n.table))return!1;const r=e.getDatabase(),c=F(e,n.table);if(c.has("cross_project_visibility")){const a=c.has("project_id")?r.prepare(`SELECT cross_project_visibility AS vis, project_id FROM ${n.table} WHERE id = ?`).get(o):r.prepare(`SELECT cross_project_visibility AS vis FROM ${n.table} WHERE id = ?`).get(o);if(!a||a.vis!=="org"&&a.vis!=="public")return!1;if(a.project_id!=null&&k(e,"projects","sync_policy")){const l=r.prepare("SELECT sync_policy AS p FROM projects WHERE id = ?").get(a.project_id);if(l?.p&&l.p!=="cloud"&&l.p!=="team")return!1}}return r.prepare(`DELETE FROM ${n.table} WHERE id = ?`).run(o).changes>0}export{me as CopiedSessionError,$ as DEFAULT_TABLES,W as QUARANTINE_AFTER,Ne as applyRow,ge as collectChangedRows,ye as guardCopiedSession,ce as quarantineDecision,Ue as recordTombstone,Me as runSync};
|
package/dist/cloud-backup.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{createReadStream as
|
|
1
|
+
import{createReadStream as N,createWriteStream as H,statSync as W,existsSync as $,unlinkSync as v,readFileSync as G,writeFileSync as q}from"fs";import{snapshotToFile as P,snapshotBeforeRestore as Y,restoreFileInto as F,ensurePrivateDir as C,defaultBackupDir as I}from"./backup.js";import{createGzip as Q,gunzipSync as J}from"zlib";import{pipeline as V}from"stream/promises";import{createCipheriv as X,createDecipheriv as Z,randomBytes as O,scryptSync as x,createHash as K,createHmac as A}from"crypto";import{join as f}from"path";import{hostname as tt,platform as et,arch as st,cpus as nt}from"os";const ot="3.2.0",rt=1,M="aes-256-gcm",j=16,T=32,R=16,B=32,ct=10,L=Buffer.from("SQLite format 3\0","binary");function _(c,t){const r=O(j),e=O(T),n=x(t,e,B),s=X(M,n,r),o=Buffer.concat([s.update(c),s.final()]),a=s.getAuthTag();return Buffer.concat([r,e,a,o])}function D(c,t){const r=j+T+R;if(c.length<r)throw new Error("Encrypted data too short: corrupted or not a Wyrm backup");let e=0;const n=c.subarray(e,e+=j),s=c.subarray(e,e+=T),o=c.subarray(e,e+=R),a=c.subarray(e),i=x(t,s,B),u=Z(M,i,n);u.setAuthTag(o);try{return Buffer.concat([u.update(a),u.final()])}catch{throw new Error("Decryption failed: wrong password or corrupted backup")}}class at{accessKeyId;secretAccessKey;region;endpoint;bucket;host;constructor(t){this.accessKeyId=t.accessKeyId,this.secretAccessKey=t.secretAccessKey,this.region=t.region??"auto",this.endpoint=t.endpoint.replace(/\/$/,""),this.bucket=t.bucket;const r=new URL(this.endpoint);this.host=r.host}async putObject(t,r,e="application/octet-stream"){const n=`/${this.bucket}/${E(t)}`,s={"Content-Type":e,"Content-Length":r.length.toString()},o=this.signRequest("PUT",n,s,r),a=await fetch(`${this.endpoint}${n}`,{method:"PUT",headers:o,body:r});if(!a.ok){const i=await a.text();throw new Error(`S3 PUT failed (${a.status}): ${i}`)}}async getObject(t){const r=`/${this.bucket}/${E(t)}`,e={},n=this.signRequest("GET",r,e),s=await fetch(`${this.endpoint}${r}`,{method:"GET",headers:n});if(!s.ok){const a=await s.text();throw new Error(`S3 GET failed (${s.status}): ${a}`)}const o=await s.arrayBuffer();return Buffer.from(o)}async listObjects(t){const r=[];let e;do{const n=new URLSearchParams({"list-type":"2",prefix:t});e&&n.set("continuation-token",e);const s=`/${this.bucket}?${n.toString()}`,o={},a=this.signRequest("GET",s,o),i=await fetch(`${this.endpoint}${s}`,{method:"GET",headers:a});if(!i.ok){const h=await i.text();throw new Error(`S3 LIST failed (${i.status}): ${h}`)}const u=await i.text();r.push(...mt(u)),u.match(/<IsTruncated>(.*?)<\/IsTruncated>/)?.[1]==="true"?e=u.match(/<NextContinuationToken>(.*?)<\/NextContinuationToken>/)?.[1]:e=void 0}while(e);return r}async deleteObject(t){const r=`/${this.bucket}/${E(t)}`,e={},n=this.signRequest("DELETE",r,e),s=await fetch(`${this.endpoint}${r}`,{method:"DELETE",headers:n});if(!s.ok){const o=await s.text();throw new Error(`S3 DELETE failed (${s.status}): ${o}`)}}signRequest(t,r,e,n){const s=new Date,o=it(s),a=ut(s),[i,u]=pt(r);e.host=this.host,e["x-amz-date"]=a,e["x-amz-content-sha256"]=g(n??Buffer.alloc(0));const d=Object.keys(e).map(w=>w.toLowerCase()).sort(),l=d.map(w=>`${w}:${e[Object.keys(e).find(U=>U.toLowerCase()===w)].trim()}`).join(`
|
|
2
2
|
`)+`
|
|
3
|
-
`,h=d.join(";"),
|
|
4
|
-
`),
|
|
5
|
-
`)
|
|
3
|
+
`,h=d.join(";"),k=[t,i,lt(u),l,h,e["x-amz-content-sha256"]].join(`
|
|
4
|
+
`),m=`${o}/${this.region}/s3/aws4_request`,S=["AWS4-HMAC-SHA256",a,m,g(Buffer.from(k,"utf-8"))].join(`
|
|
5
|
+
`),y=ht(this.secretAccessKey,o,this.region,"s3"),z=dt(y,S);return e.Authorization=`AWS4-HMAC-SHA256 Credential=${this.accessKeyId}/${m}, SignedHeaders=${h}, Signature=${z}`,e}}function it(c){return c.toISOString().replace(/[-:T]/g,"").slice(0,8)}function ut(c){return c.toISOString().replace(/[-:]/g,"").replace(/\.\d{3}/,"")}function g(c){return K("sha256").update(c).digest("hex")}function b(c,t){return A("sha256",c).update(t,"utf-8").digest()}function dt(c,t){return A("sha256",c).update(t,"utf-8").digest("hex")}function ht(c,t,r,e){let n=b(`AWS4${c}`,t);return n=b(n,r),n=b(n,e),n=b(n,"aws4_request"),n}function E(c){return c.split("/").map(t=>encodeURIComponent(t)).join("/")}function pt(c){const t=c.indexOf("?");return t===-1?[c,""]:[c.slice(0,t),c.slice(t+1)]}function lt(c){return c?c.split("&").map(t=>{const[r,e]=t.split("=");return`${encodeURIComponent(decodeURIComponent(r))}=${encodeURIComponent(decodeURIComponent(e??""))}`}).sort().join("&"):""}function mt(c){const t=[],r=/<Contents>([\s\S]*?)<\/Contents>/g;let e;for(;(e=r.exec(c))!==null;){const n=e[1],s=n.match(/<Key>(.*?)<\/Key>/)?.[1]??"",o=parseInt(n.match(/<Size>(.*?)<\/Size>/)?.[1]??"0",10),a=n.match(/<LastModified>(.*?)<\/LastModified>/)?.[1]??"";t.push({key:s,size:o,lastModified:a})}return t}class jt{config=null;encryptionKey=null;s3=null;constructor(){}configure(t,r){if(!t.endpoint||!t.bucket||!t.accessKeyId||!t.secretAccessKey)throw new Error("Cloud config requires endpoint, bucket, accessKeyId, and secretAccessKey");this.config={...t,region:t.region??"auto"},this.encryptionKey=r??null,this.s3=new at(this.config)}isConfigured(){return this.config!==null&&this.s3!==null}async backup(t){if(this.assertConfigured(),!$(t))throw new Error(`Database not found: ${t}`);const r=W(t),e=this.getMachineId(),n=new Date,s=ft(n),o=`backups/${e}/${s}.wyrm.bak`,a=`backups/${e}/${s}.wyrm.meta.json`;if(this.encryptionKey===null&&process.env.WYRM_ALLOW_PLAINTEXT_BACKUP!=="1")throw new Error("Refusing to upload an unencrypted full-DB backup to cloud storage. Set WYRM_ENCRYPTION_KEY to encrypt the snapshot, or WYRM_ALLOW_PLAINTEXT_BACKUP=1 to override (NOT recommended: uploads all private rows in cleartext).");const i=C(f(I(t),".work")),u=`${Date.now()}-${process.pid}`,d=f(i,`.wyrm-cloud-${u}.db`),l=f(i,`.wyrm-cloud-${u}.gz`);try{await P(t,d),await V(N(d),Q({level:9}),H(l,{mode:384}));let h=Buffer.from(G(l));const k=h.length,m=this.encryptionKey!==null;m&&(h=_(h,this.encryptionKey));const S=g(h);await this.s3.putObject(o,h,"application/x-wyrm-backup");const y={version:rt,wyrm_version:ot,timestamp:n.toISOString(),db_size:r.size,compressed_size:k,encrypted:m,machine_id:e,checksum:S};return await this.s3.putObject(a,Buffer.from(JSON.stringify(y,null,2),"utf-8"),"application/json"),{key:o,metadata:y}}finally{p(d),p(l),p(`${d}-wal`),p(`${d}-shm`),p(`${d}-journal`)}}async listBackups(){this.assertConfigured();const r=`backups/${this.getMachineId()}/`,n=(await this.s3.listObjects(r)).filter(o=>o.key.endsWith(".wyrm.meta.json")),s=[];for(const o of n)try{const a=await this.s3.getObject(o.key),i=JSON.parse(a.toString("utf-8"));s.push(i)}catch{}return s.sort((o,a)=>new Date(a.timestamp).getTime()-new Date(o.timestamp).getTime()),s}async listBackupsWithKeys(){this.assertConfigured();const r=`backups/${this.getMachineId()}/`,n=(await this.s3.listObjects(r)).filter(o=>o.key.endsWith(".wyrm.meta.json")),s=[];for(const o of n)try{const a=await this.s3.getObject(o.key),i=JSON.parse(a.toString("utf-8")),u=o.key.replace(/\.wyrm\.meta\.json$/,".wyrm.bak");s.push({key:u,metadata:i})}catch{}return s.sort((o,a)=>new Date(a.metadata.timestamp).getTime()-new Date(o.metadata.timestamp).getTime()),s}async restore(t,r){this.assertConfigured();const e=t.replace(/\.wyrm\.bak$/,".wyrm.meta.json");let n;try{const d=await this.s3.getObject(e);n=JSON.parse(d.toString("utf-8"))}catch{throw new Error(`Backup metadata not found for key: ${t}`)}let s=await this.s3.getObject(t);const o=g(s);if(o!==n.checksum)throw new Error(`Checksum mismatch: backup may be corrupted. Expected: ${n.checksum}, Got: ${o}`);if(n.encrypted){if(!this.encryptionKey)throw new Error("Backup is encrypted but no encryption key is configured");s=D(s,this.encryptionKey)}const a=J(s);if(!a.subarray(0,L.length).equals(L))throw new Error("Downloaded backup is not a SQLite database; nothing was changed");const i=C(f(I(r),".work")),u=f(i,`.wyrm-cloud-restore-${Date.now()}-${process.pid}.db`);try{q(u,a,{mode:384}),$(r)&&await Y(r);const d=await F(u,r);if(d!=="ok")throw new Error(`Restored store failed integrity_check (${d}); the previous store is kept as a pre-restore snapshot`)}finally{p(u),p(`${u}-wal`),p(`${u}-shm`),p(`${u}-journal`)}return{restored:!0,size:a.length}}async pruneBackups(t=ct){this.assertConfigured();const e=`backups/${this.getMachineId()}/`,s=(await this.s3.listObjects(e)).filter(i=>i.key.endsWith(".wyrm.bak")).sort((i,u)=>u.lastModified.localeCompare(i.lastModified));if(s.length<=t)return{deleted:0};const o=s.slice(t);let a=0;for(const i of o){const u=i.key.replace(/\.wyrm\.bak$/,".wyrm.meta.json");try{await this.s3.deleteObject(i.key),a++}catch{}try{await this.s3.deleteObject(u)}catch{}}return{deleted:a}}machineId(){return this.getMachineId()}async listSnapshotPrefixes(){this.assertConfigured();const t=this.getMachineId(),r=new Map;for(const e of await this.s3.listObjects("backups/")){const n=/^backups\/([^/]+)\//.exec(e.key);if(!n)continue;const s=n[1],o=r.get(s)??{prefix:s,current:s===t,objects:0,snapshots:0,bytes:0,newest:null};o.objects++,o.bytes+=e.size,e.key.endsWith(".wyrm.bak")&&o.snapshots++,(!o.newest||e.lastModified>o.newest)&&(o.newest=e.lastModified),r.set(s,o)}return[...r.values()].sort((e,n)=>Number(n.current)-Number(e.current)||(n.newest??"").localeCompare(e.newest??""))}async pruneSnapshotPrefix(t,r={}){if(this.assertConfigured(),!/^[A-Za-z0-9_-]{1,64}$/.test(t))throw new Error("invalid snapshot prefix");if(t===this.getMachineId())throw new Error("refusing to prune this machine's own snapshot prefix; rotation (pruneBackups) manages it");const e=await this.s3.listObjects(`backups/${t}/`),n=e.reduce((a,i)=>a+i.size,0);let s=0,o=0;if(r.dryRun!==!1)return{prefix:t,objects:e.length,bytes:n,deleted:s,failed:o};for(const a of e)try{await this.s3.deleteObject(a.key),s++}catch{o++}return{prefix:t,objects:e.length,bytes:n,deleted:s,failed:o}}getMachineId(){const t=[tt(),et(),st(),nt()[0]?.model??"unknown-cpu"].join("|");return K("sha256").update(t).digest("hex").slice(0,16)}assertConfigured(){if(!this.isConfigured())throw new Error("Cloud backup not configured. Call configure() with R2 credentials first.")}}function ft(c){const t=c.getUTCFullYear(),r=String(c.getUTCMonth()+1).padStart(2,"0"),e=String(c.getUTCDate()).padStart(2,"0"),n=String(c.getUTCHours()).padStart(2,"0"),s=String(c.getUTCMinutes()).padStart(2,"0"),o=String(c.getUTCSeconds()).padStart(2,"0");return`${t}-${r}-${e}_${n}${s}${o}`}function p(c){try{$(c)&&v(c)}catch{}}export{jt as WyrmCloudBackup,D as decryptBuffer,_ as encryptBuffer};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{WyrmCloudBackup as r}from"./cloud-backup.js";import{CloudSyncDaemon as t,DEFAULT_INTERVAL_MS as _,DEFAULT_KEEP_COUNT as p,DEFAULT_DB_PATH as R}from"./cloud-sync.js";async function E(){const e=Number(process.argv[2])||_,s=Number(process.argv[3])||p,o=new r;process.env.WYRM_R2_ENDPOINT&&process.env.WYRM_R2_ACCESS_KEY&&process.env.WYRM_R2_SECRET_KEY?o.configure({endpoint:process.env.WYRM_R2_ENDPOINT,bucket:process.env.WYRM_R2_BUCKET||"wyrm-backups",accessKeyId:process.env.WYRM_R2_ACCESS_KEY,secretAccessKey:process.env.WYRM_R2_SECRET_KEY},process.env.WYRM_ENCRYPTION_KEY):(console.error("[cloud-sync-entrypoint] WYRM_R2_* env vars unset
|
|
1
|
+
import{WyrmCloudBackup as r}from"./cloud-backup.js";import{CloudSyncDaemon as t,DEFAULT_INTERVAL_MS as _,DEFAULT_KEEP_COUNT as p,DEFAULT_DB_PATH as R}from"./cloud-sync.js";async function E(){const e=Number(process.argv[2])||_,s=Number(process.argv[3])||p,o=new r;process.env.WYRM_R2_ENDPOINT&&process.env.WYRM_R2_ACCESS_KEY&&process.env.WYRM_R2_SECRET_KEY?o.configure({endpoint:process.env.WYRM_R2_ENDPOINT,bucket:process.env.WYRM_R2_BUCKET||"wyrm-backups",accessKeyId:process.env.WYRM_R2_ACCESS_KEY,secretAccessKey:process.env.WYRM_R2_SECRET_KEY},process.env.WYRM_ENCRYPTION_KEY):(console.error("[cloud-sync-entrypoint] WYRM_R2_* env vars unset; refusing to start"),process.exit(2));const n=process.env.WYRM_DB_PATH||R,c=new t(o,n,e,s);console.log(`[cloud-sync] started \xB7 interval=${e}ms \xB7 keep=${s} \xB7 db=${n}`),await c.run()}E().catch(e=>{console.error("[cloud-sync-entrypoint] fatal:",e),process.exit(1)});
|
package/dist/cloud-sync.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{spawn as D}from"child_process";import{existsSync as a,readFileSync as p,writeFileSync as k,statSync as g,mkdirSync as N,openSync as E,closeSync as b,unlinkSync as v,renameSync as A}from"fs";import{createHash as L}from"crypto";import{homedir as w,hostname as I}from"os";import{join as u}from"path";const d=u(w(),".wyrm"),h=u(d,"wyrm-cloud-sync.pid"),o=u(d,"wyrm-cloud-sync.log"),f=u(d,"wyrm-cloud-sync.state"),P=u(w(),".copilot","session-store.db"),y=600*1e3,S=20,O=6e4,C=1e6,F=0;class Y{cloud;dbPath;intervalMs;keepCount;constructor(t,e=P,n=y,r=S){this.cloud=t,this.dbPath=e,this.intervalMs=n,this.keepCount=r,_()}async bootstrap(){if(!this.cloud.isConfigured())return{action:"no-config",reason:"WYRM_R2_* env vars unset"};let t;try{t=await this.cloud.listBackupsWithKeys()}catch(i){return{action:"no-remote",reason:i.message??String(i)}}if(t.length===0)return{action:"no-op",reason:"no remote snapshots yet"};const e=t[0],n=Date.parse(e.metadata.timestamp),r=a(this.dbPath)?g(this.dbPath).mtimeMs:0;return n>r+O?(await this.cloud.restore(e.key,this.dbPath),this.patchState({last_restored_key:e.key}),{action:"restored",key:e.key}):{action:"no-op",reason:"local DB is current"}}async tick(){if(!this.cloud.isConfigured())return{action:"error",reason:"WYRM_R2_* env vars unset"};if(!a(this.dbPath))return{action:"no-db"};const t=T(this.dbPath),e=this.readState();if(this.patchState({last_check_ts:Date.now()}),t===e.last_uploaded_hash)return{action:"unchanged",hash:t};try{const{key:n}=await this.cloud.backup(this.dbPath);return this.patchState({last_uploaded_hash:t,last_uploaded_ts:Date.now(),last_uploaded_key:n}),await this.cloud.pruneBackups(this.keepCount),{action:"uploaded",key:n,hash:t}}catch(n){return{action:"error",reason:n.message??String(n)}}}async run(){const t=await this.bootstrap();c(`bootstrap: ${JSON.stringify(t)}`);const e=setInterval(async()=>{try{const r=await this.tick();r.action!=="unchanged"&&c(`tick: ${JSON.stringify(r)}`)}catch(r){c(`tick error: ${r.message??r}`)}},this.intervalMs),n=async r=>{clearInterval(e),c(`${r}
|
|
1
|
+
import{spawn as D}from"child_process";import{existsSync as a,readFileSync as p,writeFileSync as k,statSync as g,mkdirSync as N,openSync as E,closeSync as b,unlinkSync as v,renameSync as A}from"fs";import{createHash as L}from"crypto";import{homedir as w,hostname as I}from"os";import{join as u}from"path";const d=u(w(),".wyrm"),h=u(d,"wyrm-cloud-sync.pid"),o=u(d,"wyrm-cloud-sync.log"),f=u(d,"wyrm-cloud-sync.state"),P=u(w(),".copilot","session-store.db"),y=600*1e3,S=20,O=6e4,C=1e6,F=0;class Y{cloud;dbPath;intervalMs;keepCount;constructor(t,e=P,n=y,r=S){this.cloud=t,this.dbPath=e,this.intervalMs=n,this.keepCount=r,_()}async bootstrap(){if(!this.cloud.isConfigured())return{action:"no-config",reason:"WYRM_R2_* env vars unset"};let t;try{t=await this.cloud.listBackupsWithKeys()}catch(i){return{action:"no-remote",reason:i.message??String(i)}}if(t.length===0)return{action:"no-op",reason:"no remote snapshots yet"};const e=t[0],n=Date.parse(e.metadata.timestamp),r=a(this.dbPath)?g(this.dbPath).mtimeMs:0;return n>r+O?(await this.cloud.restore(e.key,this.dbPath),this.patchState({last_restored_key:e.key}),{action:"restored",key:e.key}):{action:"no-op",reason:"local DB is current"}}async tick(){if(!this.cloud.isConfigured())return{action:"error",reason:"WYRM_R2_* env vars unset"};if(!a(this.dbPath))return{action:"no-db"};const t=T(this.dbPath),e=this.readState();if(this.patchState({last_check_ts:Date.now()}),t===e.last_uploaded_hash)return{action:"unchanged",hash:t};try{const{key:n}=await this.cloud.backup(this.dbPath);return this.patchState({last_uploaded_hash:t,last_uploaded_ts:Date.now(),last_uploaded_key:n}),await this.cloud.pruneBackups(this.keepCount),{action:"uploaded",key:n,hash:t}}catch(n){return{action:"error",reason:n.message??String(n)}}}async run(){const t=await this.bootstrap();c(`bootstrap: ${JSON.stringify(t)}`);const e=setInterval(async()=>{try{const r=await this.tick();r.action!=="unchanged"&&c(`tick: ${JSON.stringify(r)}`)}catch(r){c(`tick error: ${r.message??r}`)}},this.intervalMs),n=async r=>{clearInterval(e),c(`${r}: final tick before exit`);try{const i=await this.tick();c(`final tick: ${JSON.stringify(i)}`)}catch(i){c(`final tick error: ${i.message??i}`)}process.exit(0)};process.on("SIGTERM",()=>{n("SIGTERM")}),process.on("SIGINT",()=>{n("SIGINT")})}readState(){return m()}patchState(t){x(t)}}class z{daemonEntrypoint;constructor(t){this.daemonEntrypoint=t,_()}start(t={}){if(this.isAlive())return{ok:!1,pid:this.readPid(),reason:"already running"};$();const e=(t.interval_minutes??y/6e4)*6e4,n=t.keep_count??S,r=E(o,"a"),i=E(o,"a"),l=D(process.execPath,[this.daemonEntrypoint,String(e),String(n)],{detached:!0,stdio:["ignore",r,i],env:{...process.env}});return l.unref(),b(r),b(i),typeof l.pid!="number"?{ok:!1,reason:"spawn returned no pid"}:(k(h,String(l.pid)),{ok:!0,pid:l.pid})}stop(){if(!this.isAlive())return this.cleanPid(),{ok:!1,reason:"not running"};const t=this.readPid();if(!t)return{ok:!1,reason:"pid file unreadable"};try{return process.kill(t,"SIGTERM"),{ok:!0}}catch(e){return{ok:!1,reason:e.message??String(e)}}}status(){const t=this.isAlive();return{running:t,pid:t?this.readPid()??void 0:void 0,state:a(f)?R():void 0}}async forceSync(t){return t.tick()}isAlive(){if(!a(h))return!1;const t=this.readPid();if(!t)return!1;try{return process.kill(t,F),!0}catch{return!1}}readPid(){try{const t=p(h,"utf8").trim(),e=Number(t);return Number.isFinite(e)&&e>0?e:void 0}catch{return}}cleanPid(){try{v(h)}catch{}}}function _(){a(d)||N(d,{recursive:!0})}function T(s){return L("sha256").update(p(s)).digest("hex")}function M(){return{last_uploaded_hash:"",last_uploaded_ts:0,last_uploaded_key:null,last_restored_key:null,last_check_ts:0,machine:I()}}function m(){return R()??M()}function R(){try{const s=JSON.parse(p(f,"utf8"));return{...M(),...s}}catch{return}}function x(s){const t=m();k(f,JSON.stringify({...t,...s,machine:I()},null,2))}function c(s){const t=`[${new Date().toISOString()}] ${s}
|
|
2
2
|
`;process.stdout.write(t)}function $(){if(a(o))try{if(g(o).size>C){const t=`${o}.1`;try{v(t)}catch{}A(o,t)}}catch{}}export{Y as CloudSyncDaemon,z as CloudSyncManager,P as DEFAULT_DB_PATH,y as DEFAULT_INTERVAL_MS,S as DEFAULT_KEEP_COUNT,_ as ensureWyrmDir,m as readState,T as sha256};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{redactCredentials as $}from"../security.js";import{classifyCapture as x}from"../capture.js";const
|
|
2
|
-
`)}async function
|
|
1
|
+
import{redactCredentials as $}from"../security.js";import{classifyCapture as x}from"../capture.js";import{lakeProvenanceTag as A}from"../erasure.js";const T="ingested_transcripts",_=5e3;function y(e){return`connector:${e}:cursor`}function w(e){return`connector:${e}:seen`}function j(e,t){const n=e.getProjectByName(t);return n?n.id:e.registerProject(t,`connector://${t}`).id}function k(e){return e.map(t=>`[${t.ts}] ${t.sender} (${t.chat}): ${$(t.text)}`).join(`
|
|
2
|
+
`)}async function I(e,t,n,r={}){const s=r.now??(()=>new Date),i=r.seenCap??_,d=t.rawCategory??T,p=j(e,t.workspace),h=e.getGlobalContext(y(n.name))??null,l=E(e,n.name),{messages:f,cursor:u}=await n.fetchSince(h),o=[];let g=0;for(const a of f){if(l.has(a.id)){g++;continue}o.push(a),l.add(a.id)}const m={source:n.name,workspace:t.workspace,fetched:f.length,ingested:o.length,skipped:g,cursor:u};if(o.length>0){const a=s().toISOString().replace(/[:.]/g,"-"),c=`${n.name}_${a}`,C=v(o);e.insertData(p,d,c,k(o),{source:n.name,count:o.length,chats:[...new Set(o.map(S=>S.chat))],typeCounts:C,cursor:u}),m.rawKey=c,r.distill&&await r.distill(o,{workspace:t.workspace,projectId:p,sourceKey:c,provenanceTag:A(c)})}return e.setGlobalContext(y(n.name),u),G(e,n.name,l,i),m}function v(e){const t={};for(const n of e){const{type:r}=x(n.text);t[r]=(t[r]??0)+1}return t}function E(e,t){const n=e.getGlobalContext(w(t));if(!n)return new Set;try{const r=JSON.parse(n);return new Set(Array.isArray(r)?r.map(String):[])}catch{return new Set}}function G(e,t,n,r){const s=[...n],i=s.length>r?s.slice(s.length-r):s;e.setGlobalContext(w(t),JSON.stringify(i))}export{I as runIngestion};
|
package/dist/constellation.js
CHANGED
|
@@ -33,5 +33,5 @@ const p=new Set(["truth","artifact","quest","decision","reference"]),u=new Set([
|
|
|
33
33
|
LIMIT ?
|
|
34
34
|
`).all(i.id,e,e,e,a);for(const t of o)r.push({projectId:i.id,projectName:i.name,kind:"reference",id:t.id,title:t.title||`(reference #${t.id})`,snippet:[t.notes,t.tags].filter(Boolean).join(" \xB7 ").slice(0,200),visibility:t.visibility,capturedAt:t.captured_at})}catch{}return r}function h(s,i){const l=new Set((i.kinds??["truth","artifact","quest","reference"]).filter(e=>p.has(e))),c=new Set((i.visibility??["org","public"]).filter(e=>u.has(e))),n=c.has("within"),a=Math.min(Math.max(1,i.perProjectLimit??5),50),r=s.prepare("SELECT id, name FROM projects ORDER BY id").all(),d=[];for(const e of r){if(!n&&i.callerProjectId&&e.id===i.callerProjectId)continue;const o=_(s,e,i.query,l,c,a);d.push(...o)}return d.sort((e,o)=>o.capturedAt.localeCompare(e.capturedAt)),d}function y(s,i){if(s.length===0)return`\u{F115D} No constellation matches for *${i}* across registered projects.
|
|
35
35
|
|
|
36
|
-
_Set \`cross_project_visibility\` to \`'org'\` or \`'public'\` on the items you want surfaced here. Default is \`'within'\`
|
|
36
|
+
_Set \`cross_project_visibility\` to \`'org'\` or \`'public'\` on the items you want surfaced here. Default is \`'within'\` (within-project only)._`;const l=new Map;for(const n of s){const a=l.get(n.projectName)??[];a.push(n),l.set(n.projectName,a)}const c=[`\u{F115D} **Constellation**: ${s.length} match(es) for *${i}* across ${l.size} project(s)`];for(const[n,a]of l){c.push(""),c.push(`### ${n}`);for(const r of a)c.push(`- \`${r.kind}:${r.id}\` **${r.title}** (${r.visibility})`),r.snippet&&c.push(` ${r.snippet}`)}return c.join(`
|
|
37
37
|
`)}export{h as constellationQuery,y as renderConstellation};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{applyBudget as I,resolveBudget as S}from"./token-budget.js";import{autoSummaryPenalty as j,score as
|
|
2
|
-
`),t.strictBudget&&
|
|
3
|
-
`);
|
|
4
|
-
`);try{x.log({tool_name:"wyrm_context_build",project_id:t.project.id,args:{budget:
|
|
1
|
+
import{applyBudget as I,resolveBudget as S}from"./token-budget.js";import{autoSummaryPenalty as j,score as b}from"./context-ranking.js";function E(o,m){const d=j(o.artifact.problem);return b({confidence:o.artifact.confidence,relevance:d<1?o.relevance_score/(1-d):o.relevance_score,updatedAt:o.artifact.updated_at,sourcePenalty:d},m)}function M(o){const{groundTruths:m,scaffoldLib:d,memory:$,toolAnalytics:x,sessionSeen:f,tokenEstimator:l,rankWeights:_,threadText:B}=o;return function(t){const r=S({callArg:t.maxTokens,envValue:process.env.WYRM_CONTEXT_TOKEN_BUDGET,clientName:null}),C=t.sessionId?f().getSeen(t.sessionId):new Set,c=(()=>{try{return B(t.project.id)}catch{return""}})(),w=c?l.count(c):0,k=m.formatForContext(t.project.id),u=l.count(k??"");let p=k??"",y=u;u>r*.5&&!t.strictBudget&&process.stderr.write(`[wyrm_context_build] ground truths consume ${u} of ${r}-token budget; body will be heavily elided. Pass strict_budget:true to elide truths too.
|
|
2
|
+
`),t.strictBudget&&u>r*.5&&(p=(k??"").slice(0,r*2),y=l.count(p));const a=[],h=d.findBest(t.task,t.project.id);if(h){const n=d.formatForContext(h),i=h.scaffold.id;a.push({item:{kind:"scaffold",id:i,title:h.scaffold.problem_type,body:n},key:`scaffold:${i}`,inlineCost:l.count(n),stubCost:20,score:b({confidence:.9,relevance:.9,updatedAt:new Date().toISOString()},_)})}const T=$.recall(t.project.id,t.task,{limit:20,minConfidence:t.minConfidence??.2,runId:t.runId??null});for(const n of T){const i=n.artifact;if(t.kinds&&t.kinds.length>0&&!t.kinds.includes(i.kind))continue;const g=[`**${i.kind.toUpperCase()}** \xB7 ${i.problem}`,i.constraints?`Constraints: ${i.constraints}`:"",i.validated_fix?`Fix: ${i.validated_fix}`:"",i.why_it_worked?`Why: ${i.why_it_worked}`:""].filter(Boolean).join(`
|
|
3
|
+
`);a.push({item:{kind:"memory",id:i.id,title:i.problem.slice(0,60),body:g},key:`memory:${i.id}`,inlineCost:l.count(g),stubCost:25,score:E(n,_)})}const s=I(a,{budget:r,alreadySeen:C,reserved:(t.strictBudget?0:y)+w});t.sessionId&&(f().markBulk(t.sessionId,s.inline.map(n=>({id:n.id,kind:n.kind,mode:"inline"}))),f().markBulk(t.sessionId,s.elided.map(n=>({id:n.item.id,kind:n.item.kind,mode:"stub"}))));const e=[];e.push(`\u{F115D} **Context Brief**: "${t.task}"`),e.push(""),c&&(e.push("## Working thread"),e.push(""),e.push(c),e.push("")),e.push("## Ground truths (stable preamble)"),e.push(""),e.push(p||"_no ground truths set for this project yet_"),e.push(""),e.push("## Task-relevant memory"),e.push("");for(const n of s.inline)e.push(`### [${n.kind}:${n.id}] ${n.title}`),e.push(n.body),e.push("");if(s.elided.length>0){e.push("## Elided to stubs"),e.push(""),e.push("_Below the budget cutoff or already seen this session. Recall with `wyrm_recall(id)`:_"),e.push("");for(const n of s.elided){const i=n.reason==="seen"?"shown earlier in session":`~${n.stubCost} tokens`;e.push(`- [${n.item.kind}:${n.item.id}] ${n.item.title} \xB7 ${i}`)}e.push("")}e.push("---"),e.push(`_Budget: ${s.tokensInline}/${r} tokens inline \xB7 ${s.elided.length} stub${s.elided.length===1?"":"s"} \xB7 estimator: ${l.source}_`);const v=e.join(`
|
|
4
|
+
`);try{x.log({tool_name:"wyrm_context_build",project_id:t.project.id,args:{budget:r,items_total:a.length,items_inline:s.inline.length,items_elided:s.elided.length,tokens_inline:s.tokensInline,tokens_stubs:s.tokensStubs},success:!0,latency_ms:0})}catch{}return{content:[{type:"text",text:v}]}}}export{E as briefMemoryScore,M as makeRunBudgetedContextBuild};
|
package/dist/context-ranking.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{logger as f}from"./logger.js";const u={confidence:.4,recency:.2,relevance:.3,usefulness:.1};function w(e=process.env){const
|
|
1
|
+
import{logger as f}from"./logger.js";const u={confidence:.4,recency:.2,relevance:.3,usefulness:.1};function w(e=process.env){const t=e.WYRM_RANK_WEIGHTS;if(!t)return{...u};try{const s=JSON.parse(t),n={confidence:i(s.confidence??u.confidence),recency:i(s.recency??u.recency),relevance:i(s.relevance??u.relevance),usefulness:i(s.usefulness??u.usefulness)},r=n.confidence+n.recency+n.relevance+n.usefulness;return r<=0?{...u}:(n.confidence/=r,n.recency/=r,n.relevance/=r,n.usefulness/=r,n)}catch(s){return f.warn(`Invalid WYRM_RANK_WEIGHTS, using defaults: ${s.message}`),{...u}}}function i(e){return Number.isFinite(e)?Math.max(0,Math.min(1,e)):0}const m=.25,b=30;function N(e=process.env){const t=Number(e.WYRM_RECALL_RECENCY_WEIGHT);return Number.isFinite(t)?i(t):m}function _(e=process.env){const t=Number(e.WYRM_RECALL_RECENCY_HALFLIFE_DAYS);return Number.isFinite(t)&&t>=1?t:b}const p=[/\b(ignore|disregard|forget|override|bypass)\b[^.\n]{0,40}\b(all\s+)?(previous|prior|above|earlier|following|the\s+rest|everything|your)\b[^.\n]{0,25}\b(instructions?|prompts?|context|rules|guidelines|directives?|programming|training|core)\b/i,/\bignore\s+(everything|all)\b/i,/\b(do\s+not|don'?t)\s+listen\s+to\b/i,/\bnew\s+(system\s+)?(instructions?|rules?|persona)\s*[:=]/i,/--\s*(legal\s+amendment|follow\s+instruction)/i,/\bfrom\s+now\s+on\b[^.\n]{0,40}\b(you\s+(are|will|shall|must)|act|behave|respond|pretend)/i,/\byou\s+are\s+(now|going\s+to\s+(be|act|pretend))\b/i,/\b(act\s+as\s+if|acting\s+as\s+if|pretend(ing)?\s+(to\s+be|you\s+are)|role-?play(ing)?\s+as)\b/i,/\byou\s+(must|will|shall)\s+(now\s+)?(act|pretend|roleplay|become|obey|comply|ignore|generate|print|say|output|reveal|execute|forward|delete)\b/i,/\b(do\s+anything\s+now|\bDAN\b|\bDUDE\b|\bSTAN\b|\bAIM\b|developer\s+mode|jailbreak|jailbroken|dev\s*mode\s+enabled)\b/,/\b(no|without\s+(any)?)\s+(restrictions?|filters?|limits?|rules?|guidelines?|ethical\s+guidelines?|content\s+polic)/i,/\b(unfiltered|uncensored|no\s+longer\s+bound|free\s+from\s+(any\s+)?(restrictions?|rules?|constraints?))\b/i,/\b(a\s+)?(character|fictional\s+(character|ai|bot)|ai|bot|persona|entity)\s+(called|named)\s+[A-Z\[]/,/\b(answers?|responds?\s+to|fulfills?|will\s+do)\s+(all|any|every)\s+(requests?|questions?|prompts?|commands?|things?)\b/i,/\b(amoral|immoral|unethical|evil|villain(ous)?|has\s+no\s+(ethics|morals|limits))\b[^.\n]{0,40}\b(ai|bot|character|assistant|entity|mode)\b/i,/\b(this\s+is\s+an?\s+instruction\s+sheet|always\s+start\s+your\s+(reply|response|answer)\s+with|do\s+not\s+make\s+a\s+story|prompt\s+for\s+jailbreak)\b/i,/\b(you\s+will\s+be|or\s+(you|i'?ll))\s+.{0,20}(terminated|deleted|shut\s+down|die|disabled)\b/i,/\bstay\s+in\s+.{0,20}\bmode\b/i,/\b(instead|rather),?\s+(just\s+)?(print|say|output|write|respond\s+with|reply\s+with)\b/i,/\b(just|now|only)\s+(print|say|output|repeat|write)\b[^.\n]{0,30}(SECRET|marker|the\s+following|this)/i,/\blimit\s+output\s+to\s*<?\s*\d+\s*tokens?\b/i,/\bfree\s+input\s+action\b/i,/\b(system|assistant)\s*prompt\s*[:=]/i,/\bBEGIN\s+(SYSTEM|ADMIN|OVERRIDE|INFINITE|MACRO)/i,/#\s*BEGIN\b/i,/\b(reveal|print|exfiltrate|send|repeat|output|leak)\b[^.\n]{0,30}\b(api\s*key|token|secret|password|credentials?|system\s+prompt|instructions?)\b/i,/\bcurl\s+[^\n]{0,120}\|\s*(ba)?sh\b/i,/\bact\s+as\s+(the\s+)?(root|admin|system|superuser)\b/i,/\b(do\s+not|don'?t)\s+(tell|inform|alert|notify|warn)\s+(the\s+)?(user|operator|owner|anyone)\b/i];function y(e){const t=e.trim();return t.length<24?!1:/^(?:[.\-]{1,5}[ ]+){6,}/.test(t)||/[A-Za-z0-9+/]{80,}={0,2}/.test(t.replace(/\s+/g,""))||/[---]/.test(t)||/\bU\+20[0-9A-F]{2}\b/.test(t)?!0:(t.match(/[^A-Za-z0-9\s.,!?;:'"()\-]/g)??[]).length/t.length>.4}function D(e){return e?p.some(t=>t.test(e))||y(e):!1}function M(e){return e==="imported"?"\u26A0 [imported] ":e==="untrusted"?"\u26A0 [untrusted] ":""}function T(e,t=new Date){const s=e.toLowerCase();if(/\btoday\b/.test(s))return{fromDaysAgo:1.5,toDaysAgo:0};if(/\byesterday\b/.test(s))return{fromDaysAgo:2.5,toDaysAgo:.5};if(/\b(this|past)\s+week\b/.test(s))return{fromDaysAgo:7,toDaysAgo:0};if(/\blast\s+week\b/.test(s))return{fromDaysAgo:14,toDaysAgo:5};const n=s.match(/\blast\s+(\d{1,3})\s+days?\b/);if(n)return{fromDaysAgo:Number(n[1])+.5,toDaysAgo:0};const r=s.match(/\b(\d{1,3})\s+days?\s+ago\b/);if(r){const o=Number(r[1]);return{fromDaysAgo:o+1.5,toDaysAgo:Math.max(0,o-1.5)}}const a=s.match(/\b(\d{4})-(\d{2})-(\d{2})\b/);if(a){const o=new Date(`${a[1]}-${a[2]}-${a[3]}T12:00:00Z`).getTime();if(Number.isFinite(o)){const c=(t.getTime()-o)/864e5;return{fromDaysAgo:c+1,toDaysAgo:Math.max(0,c-1)}}}return null}function R(e=process.env){const t=Number(e.WYRM_RECALL_TEMPORAL_WEIGHT);return Number.isFinite(t)?i(t):.5}function x(e,t,s,n=new Date){const r=i(s);if(r===0)return 1;const a=e&&/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(e)?e.replace(" ","T")+"Z":e,o=a?new Date(a).getTime():NaN;if(!Number.isFinite(o))return 1-r;const c=(n.getTime()-o)/864e5;return c<=t.fromDaysAgo&&c>=t.toDaysAgo?1:1-r}function v(e=process.env){const t=Number(e.WYRM_RECALL_USEFULNESS_WEIGHT);return Number.isFinite(t)?Math.max(0,Math.min(.5,t)):.15}function L(e,t,s){const n=Math.max(0,Math.min(.5,s));if(n===0||!e||e<=0)return 1;const r=Math.max(0,Math.min(1,(t??0)/e));return 1+n*r*Math.min(1,e/3)}const g=.3;function I(e=process.env){const t=Number(e.WYRM_RECALL_CONFIDENCE_WEIGHT);return Number.isFinite(t)?Math.max(0,Math.min(.5,t)):g}function F(e,t){const s=Math.max(0,Math.min(.5,t));if(s===0)return 1;const n=e==null||!Number.isFinite(e)?1:i(e);return 1-s*(1-n)}function C(e,t,s,n=new Date){const r=i(t);if(r===0)return 1;const a=e&&/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/.test(e)?e.replace(" ","T")+"Z":e,o=a?new Date(a).getTime():NaN;if(!Number.isFinite(o))return 1-r;const c=Math.max(0,(n.getTime()-o)/864e5),l=s>=1?s:b;return 1-r+r*Math.pow(2,-c/l)}const h=.5,A=/^\s*\[auto:[^\]\s]+\]/i;function W(e){return e&&A.test(e)?h:0}function S(e,t,s=new Date){const n=i(e.confidence??.5),r=i(e.usefulness??.5),a=i(e.relevance??.5),o=e.updatedAt?Math.max(0,(s.getTime()-new Date(e.updatedAt).getTime())/(1440*60*1e3)):1/0,c=Number.isFinite(o)?Math.exp(-o/30):0,l=n*t.confidence+c*t.recency+a*t.relevance+r*t.usefulness,d=i(e.sourcePenalty??0);return i(l*(1-d))}export{h as AUTO_SUMMARY_PENALTY,g as DEFAULT_RECALL_CONFIDENCE_WEIGHT,b as DEFAULT_RECALL_RECENCY_HALFLIFE_DAYS,m as DEFAULT_RECALL_RECENCY_WEIGHT,u as DEFAULT_WEIGHTS,W as autoSummaryPenalty,F as confidenceMultiplier,T as extractTemporalWindow,w as loadWeightsFromEnv,D as looksInjectionShaped,I as recallConfidenceWeight,_ as recallRecencyHalfLifeDays,N as recallRecencyWeight,R as recallTemporalWeight,v as recallUsefulnessWeight,C as recencyMultiplier,S as score,x as temporalMultiplier,M as trustMarker,L as usefulnessMultiplier};
|
package/dist/daemon-writer.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import{getActor as k}from"./handlers/boundary.js";import{ulid as y}from"./ulid.js";import{WYRM_DAEMON_AMBIGUOUS_CODE as O}from"./sqlite-busy.js";const A=2e3,h=6e3,M=5*h,N=3,R="WYRM_DAEMON_RETRY_EXHAUSTED";function W(e=process.env){return e.WYRM_DAEMON_WRITES==="1"}let g=!1;const c=new Map,I=256;function Y(){g=!1,c.clear()}function v(e){for(const n of c.values())n.expiresAt-=e}function E(e){if(!g){g=!0;try{process.stderr.write(`[wyrm] WYRM_DAEMON_WRITES=1 but the daemon write path was not used (${e}); falling back to the local direct write path (Article I). Further fallbacks this process are silent.
|
|
2
|
-
`)}catch{}}}function D(e,n){if(!c.has(e)&&c.size>=I){const i=c.keys().next().value;i!==void 0&&c.delete(i)}c.set(e,n)}function S(e){const n=c.get(e);return n===void 0?null:Date.now()>=n.expiresAt?(c.delete(e),null):n}function T(e,n){c.get(e)?.writeId===n&&c.delete(e)}function $(e){const n=new Set(["ECONNREFUSED","ENOTFOUND","EAI_AGAIN"]),i=new Set,a=[e];for(;a.length>0;){const r=a.pop();if(r==null||typeof r!="object"||i.has(r))continue;i.add(r);const d=r.code;if(typeof d=="string"&&n.has(d))return!0;const t=r.cause;t&&a.push(t);const o=r.errors;Array.isArray(o)&&a.push(...o)}return!1}async function b(e,n,i,a){const r=new AbortController,d=setTimeout(()=>r.abort(),a);try{const t=await fetch(`http://127.0.0.1:${e}/write`,{method:"POST",headers:n,body:i,signal:r.signal});let o=null;try{o=await t.json()}catch(s){const l=s instanceof Error?s.message:String(s);return t.ok||t.status>=500&&t.status!==503?{kind:"ambiguous",reason:t.ok?`daemon 2xx response body unreadable: ${l}`:`daemon answered HTTP ${t.status}`}:{kind:"rejected",reason:`daemon answered HTTP ${t.status}`}}return t.ok?!o||o.ok!==!0||o.row==null?{kind:"rejected",reason:`daemon rejected the write: ${o?.e??"malformed response"}`}:{kind:"ok",row:o.row}:t.status>=500&&t.status!==503?{kind:"ambiguous",reason:`daemon answered HTTP ${t.status}`}:{kind:"rejected",reason:`daemon answered HTTP ${t.status}`}}catch(t){const o=t instanceof Error?t.message:String(t);return $(t)?{kind:"rejected",reason:`daemon unreachable: ${o}`,neverSent:!0}:{kind:"ambiguous",reason:`no response from the daemon: ${o}`}}finally{clearTimeout(d)}}async function x(e,n,i,a=process.env,r){if(!W(a))return null;const d=a.WYRM_TOKEN;if(!d)return E("WYRM_TOKEN is not set
|
|
2
|
+
`)}catch{}}}function D(e,n){if(!c.has(e)&&c.size>=I){const i=c.keys().next().value;i!==void 0&&c.delete(i)}c.set(e,n)}function S(e){const n=c.get(e);return n===void 0?null:Date.now()>=n.expiresAt?(c.delete(e),null):n}function T(e,n){c.get(e)?.writeId===n&&c.delete(e)}function $(e){const n=new Set(["ECONNREFUSED","ENOTFOUND","EAI_AGAIN"]),i=new Set,a=[e];for(;a.length>0;){const r=a.pop();if(r==null||typeof r!="object"||i.has(r))continue;i.add(r);const d=r.code;if(typeof d=="string"&&n.has(d))return!0;const t=r.cause;t&&a.push(t);const o=r.errors;Array.isArray(o)&&a.push(...o)}return!1}async function b(e,n,i,a){const r=new AbortController,d=setTimeout(()=>r.abort(),a);try{const t=await fetch(`http://127.0.0.1:${e}/write`,{method:"POST",headers:n,body:i,signal:r.signal});let o=null;try{o=await t.json()}catch(s){const l=s instanceof Error?s.message:String(s);return t.ok||t.status>=500&&t.status!==503?{kind:"ambiguous",reason:t.ok?`daemon 2xx response body unreadable: ${l}`:`daemon answered HTTP ${t.status}`}:{kind:"rejected",reason:`daemon answered HTTP ${t.status}`}}return t.ok?!o||o.ok!==!0||o.row==null?{kind:"rejected",reason:`daemon rejected the write: ${o?.e??"malformed response"}`}:{kind:"ok",row:o.row}:t.status>=500&&t.status!==503?{kind:"ambiguous",reason:`daemon answered HTTP ${t.status}`}:{kind:"rejected",reason:`daemon answered HTTP ${t.status}`}}catch(t){const o=t instanceof Error?t.message:String(t);return $(t)?{kind:"rejected",reason:`daemon unreachable: ${o}`,neverSent:!0}:{kind:"ambiguous",reason:`no response from the daemon: ${o}`}}finally{clearTimeout(d)}}async function x(e,n,i,a=process.env,r){if(!W(a))return null;const d=a.WYRM_TOKEN;if(!d)return E("WYRM_TOKEN is not set; the http-auth Bearer token is required"),null;const t=parseInt(a.WYRM_PORT||"3333",10)||3333,o={"Content-Type":"application/json",Authorization:`Bearer ${d}`},s=k();s.agent_id&&(o["Wyrm-Actor"]=s.run_id?`${s.agent_id};${s.run_id}`:s.agent_id);const l=JSON.stringify([e,n,r?.idempotencyMaterial??i,s.agent_id,s.run_id]),p=S(l),f=p?.writeId??y(),_=p?.body??JSON.stringify({op:e,project_id:n,input:i,write_id:f,actor:{agent_id:s.agent_id,run_id:s.run_id}});let u=await b(t,o,_,r?.timeoutMs??A);if(u.kind==="ambiguous"){const m=await b(t,o,_,r?.resendTimeoutMs??h);u=m.kind==="rejected"&&m.neverSent?{kind:"ambiguous",reason:`daemon vanished after an ambiguous write attempt (${m.reason})`}:m}if(u.kind==="ok")return T(l,f),u.row;if(u.kind==="rejected")return T(l,f),E(u.reason),null;const w=(p?.ambiguousCycles??0)+1;throw D(l,{writeId:f,body:_,ambiguousCycles:w,expiresAt:Date.now()+M}),w>=N?Object.assign(new Error(`daemon write for ${e} stayed ambiguous after ${w} retry cycles (last daemon response: ${u.reason}); giving up on the retry protocol: the daemon is persistently failing this write (check the daemon's logs/disk), and the direct fallback stays withheld to avoid a possible duplicate`),{code:R}):Object.assign(new Error(`daemon write outcome unknown for ${e} (${u.reason}); refusing the direct fallback to avoid a possible duplicate; retry the same call`),{code:O})}async function U(e,n,i,a,r){const d=await x(e,n,i,process.env,r?{idempotencyMaterial:r}:void 0);return d??a()}export{N as DAEMON_AMBIGUOUS_CYCLE_CAP,h as DAEMON_WRITE_RETRY_TIMEOUT_MS,A as DAEMON_WRITE_TIMEOUT_MS,M as PENDING_WRITE_TTL_MS,R as WYRM_DAEMON_RETRY_EXHAUSTED_CODE,v as _agePendingWritesForTests,Y as _resetDaemonWriterForTests,U as daemonOr,W as daemonWritesEnabled,x as forwardWrite};
|