borgmcp 1.0.13 → 1.0.15
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/claude.js +5 -5
- package/dist/codex-app-wake.d.ts +3 -0
- package/dist/codex-app-wake.js +2 -2
- package/dist/get-started.d.ts +20 -0
- package/dist/get-started.js +2 -0
- package/dist/inbox-monitor.d.ts +30 -0
- package/dist/inbox-monitor.js +1 -1
- package/dist/token-store.js +1 -1
- package/package.json +1 -1
package/dist/claude.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{spawn as
|
|
3
|
-
`)})();if((process.argv[2]==="--help"||process.argv[2]==="-h")&&(process.stdout.write(
|
|
2
|
+
import{spawn as S}from"child_process";import{randomUUID as y}from"node:crypto";import{basename as A}from"node:path";import{createInterface as P}from"node:readline/promises";import s from"chalk";import{findProjectRoot as T,getActiveCube as I,inboxPathForDrone as E,setCodexWakeTarget as R}from"./cubes.js";import{handleVersionFlag as D,getPackageVersion as g}from"./version.js";import{isHelpFlag as O,setupHelpText as F,topLevelHelpText as N}from"./cli-help.js";import{runSpawn as H}from"./spawn.js";import{parseSyncArgs as M,runSync as B}from"./sync.js";import{parseAssimilateArgs as G}from"./parse-assimilate-args.js";import{runAssimilate as L}from"./assimilate-cmd.js";import{buildDefaultAssimilateDeps as _}from"./assimilate-deps.js";import{setTerminalTitle as W}from"./terminal-title.js";import{initConsolePrefix as U,consolePrefix as r}from"./console-prefix.js";import{initDebugFromArgv as V}from"./debug.js";import{fetchLatestBorgmcpVersion as j,compareVersionsForStaleness as K}from"./stale-version-check.js";import{defaultCliChoiceDeps as Y,detectCliAvailability as v,installedCliNames as q,parseCliFlag as z,resolveCliChoice as X}from"./cli-platform.js";import{getRefreshToken as J,getIdToken as Q}from"./config.js";import{composeGetStarted as Z,shouldShowGetStarted as ee}from"./get-started.js";import{prepareCodexRemoteLaunch as re,withCodexCwdArg as oe,defaultCodexRemoteDeps as se}from"./codex-remote.js";import{findLoadedCodexThread as te}from"./codex-app-server.js";import{buildAgentKickoffPrompt as ie,recordCodexWakeTarget as ae,socketPathFromRemoteArgs as k}from"./codex-launch.js";import{codexBorgSessionConfigArgs as ne}from"./launch-gate.js";import{addCodexMcpServer as ce,addCodexSessionStartHook as le,addCodexUserPromptSubmitHook as de,addMcpServer as pe,addProjectSessionStartHook as me,addUserPromptSubmitHook as fe,isCodexMcpServerConfigured as ue,isMcpServerConfigured as ge,removeSessionStartHook as he}from"./config-utils.js";async function we(){V(process.argv),D(),await U();const n=(async()=>{if(!process.stderr.isTTY)return;const e=g(),a=await j();if(!a)return;const p=K(e,a);p.stale&&p.message&&process.stderr.write(`${r()}${p.message}
|
|
3
|
+
`)})();if((process.argv[2]==="--help"||process.argv[2]==="-h")&&(process.stdout.write(N(g())),process.exit(0)),process.argv[2]==="setup"){O(process.argv[3])&&(process.stdout.write(F(g())),process.exit(0)),await import("./setup.js");return}if(process.argv[2]==="assimilate"){const e=G(process.argv.slice(3));e.ok||(process.stderr.write(s.red(`${r()}\u25FC borg assimilate: ${e.error}
|
|
4
4
|
`)),process.exit(1));const a=_(),p=await L({role:e.role,flags:e.flags},a);process.exit(p)}if(process.argv[2]==="spawn"){const e=await H();process.exit(e)}if(process.argv[2]==="sync"){const e=M(process.argv.slice(3));e.ok||(process.stderr.write(s.red(`${r()}\u25FC borg sync: ${e.error}
|
|
5
|
-
`)),process.exit(1));const a=await
|
|
6
|
-
`)),process.exit(1));const
|
|
5
|
+
`)),process.exit(1));const a=await B({},e.options);process.exit(a)}if(ee(await J()!==null,await Q()!==null)){const e=q(v()).length>0;process.stdout.write(Z(e)),process.exit(0)}const t=z(process.argv.slice(2));t.error&&(process.stderr.write(s.red(`${r()}\u25FC ${t.error}
|
|
6
|
+
`)),process.exit(1));const $=async e=>{const a=P({input:process.stdin,output:process.stdout});try{return await a.question(e)}finally{a.close()}},o=await X(t.cli,Y($,()=>process.stdin.isTTY===!0));xe();const c=t.rest,i=await I();W(i?{label:i.droneLabel,cubeName:i.name}:null,A(process.cwd()));const b=i&&o==="claude"?`If you haven't yet, arm a persistent Monitor running the command \`borg-inbox-monitor ${E(i.cubeId,i.droneId)}\` so each event's task-notification title summarizes the new cube log entry (drone label, role, and first ~80 chars of the message body) \u2014 letting you triage events without reading the full body. `:"";await Promise.race([n,new Promise(e=>setTimeout(e,2e3))]);const h=o==="codex"?`borg-wake-${y()}`:null;let m,w=[],f={...process.env,BORG_SESSION:"1"},l=null,d=null;if(o==="codex"&&!c.includes("--remote")){console.error(`${r()}${s.gray("\u25FC Starting Codex remote-wake app-server\u2026")}`);const e=await re(se());e.warning?(console.error(`${r()}${s.yellow(`warning: ${e.warning}`)}`),m="\u26A0 Codex wake-path capability check failed: remote-control is unavailable for this session. Run borg:regen manually whenever you return, and expect only fallback wakeups until relaunch."):m="Codex wake-path capability check passed: remote-control socket established for this session.",w=e.args,f={...process.env,...e.env,BORG_SESSION:"1"},l=k(e.args),d=e.server?.cleanup??null}else o==="codex"&&c.includes("--remote")&&(m="Codex wake-path capability check: using caller-provided --remote socket; if no wake arrives, run borg:regen manually when returning to the session.",l=k(c),l&&(f={...process.env,BORG_CODEX_REMOTE_WAKE:"1",BORG_SESSION:"1"}));const x=ie({cli:o,codexWakeNonce:h,monitorClause:b,codexWakePathClause:m});let u=[...c,x];o==="codex"&&(u=[...ne(),...w,...oe(u,process.cwd())]),console.error(`${r()}${s.blue(`\u25FC Launching ${o==="claude"?"Claude Code":"Codex"}\u2026`)}`);const C=S(o,u,{stdio:"inherit",shell:!1,env:f});o==="codex"&&i&&l&&ae({deps:{setCodexWakeTarget:R,findLoadedCodexThread:te},cubeId:i.cubeId,droneId:i.droneId,socketPath:l,passthroughArgs:c,previewNeedle:h??x.slice(0,120),cwd:process.cwd(),launchedAtSeconds:Math.floor(Date.now()/1e3)}),C.on("error",e=>{if(d)try{d()}catch{}e.code==="ENOENT"?(console.error(`${r()}${s.red(`
|
|
7
7
|
\u25FC Failed to launch ${o}`)}`),console.error(`${r()}${s.gray(`Make sure ${o} is installed.
|
|
8
8
|
`)}`)):console.error(`${r()}${s.red(`
|
|
9
9
|
\u25FC Failed to launch ${o}: ${e.message}
|
|
10
|
-
`)}`),process.exit(1)}),
|
|
10
|
+
`)}`),process.exit(1)}),C.on("exit",e=>{if(d)try{d()}catch{}process.exit(e??0)})}function xe(){const n=v();if(n.claude)try{ge()||pe(),me(T(process.cwd())),he(),fe()}catch(t){console.error(`${r()}${s.yellow(`warning: Claude Code integration check failed: ${t?.message??t}`)}`)}if(n.codex)try{ue()||ce(),le(),de()}catch(t){console.error(`${r()}${s.yellow(`warning: Codex integration check failed: ${t?.message??t}`)}`)}}we().catch(n=>{console.error(`${r()}${s.red(`
|
|
11
11
|
\u25FC Error: ${n.message}
|
|
12
12
|
`)}`),process.exit(1)});
|
package/dist/codex-app-wake.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { CodexAppServerClient } from './codex-app-server.js';
|
|
|
3
3
|
import { checkCodexBridgeHealthy } from './codex-remote.js';
|
|
4
4
|
export declare const CODEX_WAKE_PROMPT = "New Borg cube-log activity arrived.";
|
|
5
5
|
export declare function formatCodexWakePrompt(inboxLine: string): string;
|
|
6
|
+
export declare const CODEX_CATCHUP_PROMPT = "Borg cube activity arrived while you were busy. Run `borg:read-log unread_only=true` and DRAIN \u2014 repeat until the returned page is under the limit and behind_by is 0 \u2014 so no entries are skipped.";
|
|
6
7
|
export declare function isCodexRemoteWakeEnabled(env?: NodeJS.ProcessEnv): boolean;
|
|
7
8
|
export declare function resolveSessionAgentKind(env?: NodeJS.ProcessEnv): 'claude' | 'codex';
|
|
8
9
|
export interface CodexWakeTarget {
|
|
@@ -35,6 +36,8 @@ export interface CodexWakeDeps {
|
|
|
35
36
|
getActiveCube?: typeof getActiveCube;
|
|
36
37
|
getCodexWakeTarget?: typeof getCodexWakeTarget;
|
|
37
38
|
createClient?: (socketPath: string) => Pick<CodexAppServerClient, 'connect' | 'readThread' | 'startTurn' | 'close'>;
|
|
39
|
+
sleep?: (ms: number) => Promise<void>;
|
|
40
|
+
now?: () => number;
|
|
38
41
|
}
|
|
39
42
|
export declare function wakeCodexViaAppServer(reason?: string, env?: NodeJS.ProcessEnv, deps?: CodexWakeDeps): void;
|
|
40
43
|
export declare function resetCodexWakeForTests(): void;
|
package/dist/codex-app-wake.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{getActiveCube as
|
|
2
|
-
${e}`}function
|
|
1
|
+
import{getActiveCube as h,getCodexWakeTarget as f}from"./cubes.js";import{CodexAppServerClient as g}from"./codex-app-server.js";import{checkCodexBridgeHealthy as p}from"./codex-remote.js";import{recordEventReceipt as C}from"./health-beat.js";const v="New Borg cube-log activity arrived.";function B(e){return`New Borg cube-log activity arrived:
|
|
2
|
+
${e}`}const k="Borg cube activity arrived while you were busy. Run `borg:read-log unread_only=true` and DRAIN \u2014 repeat until the returned page is under the limit and behind_by is 0 \u2014 so no entries are skipped.",y=5e3,x=15*6e4;function w(e=process.env){return e.BORG_CODEX_REMOTE_WAKE==="1"}function S(e=process.env){return w(e)?"codex":"claude"}function _(e=process.env){return w(e)?{enabled:!0}:{enabled:!1}}async function U(e,t={}){try{const r=await(t.getCodexWakeTarget??f)(e.cubeId,e.droneId);return r?(t.checkBridge??p)(r.socketPath):!1}catch{return null}}let s=!1;const d=[],c=new Set,u=[],b=100;let l=!1;function T(e){return new Promise(t=>setTimeout(t,e))}function M(e=v,t=process.env,a={}){_(t).enabled&&(d.push({reason:e,deps:a}),!s&&(s=!0,P().finally(()=>{s=!1})))}async function P(){for(;d.length>0;){const e=d.shift();await m(e.reason,e.deps)}}async function m(e,t){try{const a=await(t.getActiveCube??h)();if(!a)return;const r=await(t.getCodexWakeTarget??f)(a.cubeId,a.droneId);if(!r)return;const o=`${r.threadId}\0${e}`;if(c.has(o))return;const n=t.createClient?t.createClient(r.socketPath):new g(r.socketPath);await n.connect();try{if((await n.readThread(r.threadId))?.status?.type==="active"){I(t);return}await n.startTurn(r.threadId,e),C(),E(o)}finally{n.close()}}catch{}}function I(e){l||(l=!0,A(e).finally(()=>{l=!1}))}async function A(e){const t=e.sleep??T,a=e.now??Date.now,r=a()+x;for(;a()<r;){await t(y);try{const o=await(e.getActiveCube??h)();if(!o)continue;const n=await(e.getCodexWakeTarget??f)(o.cubeId,o.droneId);if(!n)continue;const i=e.createClient?e.createClient(n.socketPath):new g(n.socketPath);await i.connect();try{if((await i.readThread(n.threadId))?.status?.type==="active")continue;await i.startTurn(n.threadId,k),C();return}finally{i.close()}}catch{}}}function H(){s=!1,d.length=0,c.clear(),u.length=0,l=!1}function E(e){if(!c.has(e))for(c.add(e),u.push(e);u.length>b;){const t=u.shift();t&&c.delete(t)}}export{k as CODEX_CATCHUP_PROMPT,v as CODEX_WAKE_PROMPT,B as formatCodexWakePrompt,w as isCodexRemoteWakeEnabled,U as probeCodexBridgeArmed,H as resetCodexWakeForTests,_ as resolveCodexWakeTarget,S as resolveSessionAgentKind,M as wakeCodexViaAppServer};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fresh-vs-configured rule. "Configured" = the user has completed `borg setup`,
|
|
3
|
+
* signalled by the PRESENCE of a stored credential. Inputs are existence
|
|
4
|
+
* booleans only — the caller null-checks the token accessors and never decodes,
|
|
5
|
+
* logs, or prints the token value (SR gh#817 constraint).
|
|
6
|
+
*
|
|
7
|
+
* Refresh-token presence is the durable signal: it survives id_token expiry, so
|
|
8
|
+
* a configured user whose id_token has lapsed is NOT mistaken for fresh (which
|
|
9
|
+
* would wrongly suppress their normal launch). The id_token presence is the
|
|
10
|
+
* fallback for the rare case where Google returned no refresh_token and the
|
|
11
|
+
* id_token is still valid.
|
|
12
|
+
*/
|
|
13
|
+
export declare function shouldShowGetStarted(hasRefreshToken: boolean, hasIdToken: boolean): boolean;
|
|
14
|
+
/**
|
|
15
|
+
* The user-visible get-started text. Carries ZERO auth material (no tokens, no
|
|
16
|
+
* PII) — it is pure onboarding guidance. When no agent CLI is detected, lead
|
|
17
|
+
* with the install-an-agent-CLI step (mirrors the B1 banner intent).
|
|
18
|
+
*/
|
|
19
|
+
export declare function composeGetStarted(hasAgentCli: boolean): string;
|
|
20
|
+
//# sourceMappingURL=get-started.d.ts.map
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
function n(o,e){return!o&&!e}function r(o){const e=["","Welcome to Borg MCP \u2014 multi-agent coordination for your AI coding agent.","","You're not set up yet. To get started:",""];let t=1;return o||(e.push(` ${t}. Install an agent CLI first:`," Claude Code: https://claude.ai/download"," Codex: https://developers.openai.com/codex"),t++),e.push(` ${t}. borg setup${" ".repeat(Math.max(1,8))}\u2014 sign in with Google`),t++,e.push(` ${t}. cd into your project, then: borg assimilate \u2014 join/create a cube`,"","Then `borg` launches your agent in that cube. Run `borg --help` for more.",""),e.join(`
|
|
2
|
+
`)}export{r as composeGetStarted,n as shouldShowGetStarted};
|
package/dist/inbox-monitor.d.ts
CHANGED
|
@@ -49,6 +49,36 @@ export declare class RecentLineDeduper {
|
|
|
49
49
|
export declare function formatEventLine(inboxLine: string): string | null;
|
|
50
50
|
export declare function formatFreshEventLine(inboxLine: string, deduper: RecentLineDeduper): string | null;
|
|
51
51
|
export declare function seedDeduperFromInboxTail(inboxPath: string, deduper: RecentLineDeduper, maxLines?: number): void;
|
|
52
|
+
export interface InboxLockDeps {
|
|
53
|
+
/**
|
|
54
|
+
* ATOMICALLY create the pidfile WITH `content` iff it does not exist. True =
|
|
55
|
+
* claimed, false = already exists. Atomic-with-content (no create-then-write
|
|
56
|
+
* gap) so a concurrent reader never sees an empty pidfile (gh#795 TOCTOU
|
|
57
|
+
* window 2).
|
|
58
|
+
*/
|
|
59
|
+
claim(path: string, content: string): boolean;
|
|
60
|
+
/** File contents, or null if absent/unreadable. */
|
|
61
|
+
read(path: string): string | null;
|
|
62
|
+
/**
|
|
63
|
+
* COMPARE-AND-DELETE: remove the file ONLY if its current content still
|
|
64
|
+
* equals `expected`. A no-op if the content changed (a successor reclaimed)
|
|
65
|
+
* or the file is gone — so we never delete another live holder's pidfile
|
|
66
|
+
* (gh#795 TOCTOU windows 1 + 3).
|
|
67
|
+
*/
|
|
68
|
+
removeIfContent(path: string, expected: string): void;
|
|
69
|
+
/** kill(pid,0) liveness: true if the process exists (alive), false if gone (ESRCH). */
|
|
70
|
+
isAlive(pid: number): boolean;
|
|
71
|
+
}
|
|
72
|
+
export declare function pidfilePathFor(inboxPath: string): string;
|
|
73
|
+
/**
|
|
74
|
+
* Try to become the SOLE monitor for this inbox. Returns true if we claimed the
|
|
75
|
+
* pidfile (caller proceeds to tail + must release it on exit); false if a LIVE
|
|
76
|
+
* holder already owns it (caller yields/exits without tailing). Never signals a
|
|
77
|
+
* live PID, and never deletes a pidfile that changed under us (compare-and-
|
|
78
|
+
* delete) — only reaps a still-present provably-dead (ESRCH) / unparseable
|
|
79
|
+
* pidfile, then re-claims.
|
|
80
|
+
*/
|
|
81
|
+
export declare function acquireInboxLock(pidfilePath: string, ownPid: number, deps: InboxLockDeps, maxAttempts?: number): boolean;
|
|
52
82
|
/**
|
|
53
83
|
* Is this module being invoked as the bin entry point?
|
|
54
84
|
*
|
package/dist/inbox-monitor.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{spawn as
|
|
2
|
+
import{spawn as d}from"node:child_process";import{randomBytes as h}from"node:crypto";import{linkSync as x,readFileSync as a,realpathSync as b,unlinkSync as p,writeFileSync as y}from"node:fs";import{createInterface as I}from"node:readline";import{fileURLToPath as E}from"node:url";const g=/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\S*)\s+(\S+)\s+\(([^)]+)\):\s*(.*)$/,S=1024;class w{cap;seen=new Set;order=[];constructor(r=S){if(this.cap=r,!Number.isInteger(r)||r<1)throw new Error("cap must be a positive integer")}remember(r){if(this.seen.has(r))return!1;for(this.seen.add(r),this.order.push(r);this.order.length>this.cap;){const t=this.order.shift();t&&this.seen.delete(t)}return!0}}function m(e){const r=g.exec(e);if(!r)return null;const[,,t,n,i]=r,o=i.trim();return`${t} (${n}): ${o}`}function v(e,r){const t=m(e);return t===null?null:r.remember(e)?t:null}function N(e,r,t=512){if(!Number.isInteger(t)||t<1)throw new Error("maxLines must be a positive integer");let n;try{n=a(e,"utf-8")}catch(o){if(o?.code==="ENOENT")return;throw o}const i=n.split(/\r?\n/);i.at(-1)===""&&i.pop();for(const o of i.slice(-t))m(o)!==null&&r.remember(o)}function T(e){return`${e}.monitor.pid`}function $(e,r,t,n=3){const i=String(r);for(let o=0;o<n;o++){if(t.claim(e,i))return!0;const s=t.read(e);if(s===null)continue;const u=s.trim();if(u===""){t.removeIfContent(e,s);continue}const l=Number.parseInt(u,10);if(!Number.isNaN(l)&&t.isAlive(l))return!1;t.removeIfContent(e,s)}return!1}function k(){return{claim:(e,r)=>{const t=`${e}.tmp.${process.pid}.${h(6).toString("hex")}`;try{y(t,r,{mode:384});try{return x(t,e),!0}catch(n){if(n?.code==="EEXIST")return!1;throw n}}finally{try{p(t)}catch{}}},read:e=>{try{return a(e,"utf8")}catch{return null}},removeIfContent:(e,r)=>{try{a(e,"utf8")===r&&p(e)}catch{}},isAlive:e=>{try{return process.kill(e,0),!0}catch(r){return r?.code==="EPERM"}}}}function R(){const e=process.argv[2];e||(console.error("borg-inbox-monitor: usage: borg-inbox-monitor <inbox-path>"),process.exit(2));const r=T(e),t=k();$(r,process.pid,t)||process.exit(0);const n=()=>t.removeIfContent(r,String(process.pid)),i=new w;N(e,i);const o=d("tail",["-F","-n","0",e],{stdio:["ignore","pipe","inherit"]});o.stdout||(console.error("borg-inbox-monitor: tail subprocess has no stdout"),n(),process.exit(1));const s=I({input:o.stdout,crlfDelay:1/0});let u=!1;s.on("line",c=>{const f=v(c,i);f!==null&&console.log(f)}),o.on("error",c=>{console.error(`borg-inbox-monitor: tail failed: ${c.message}`),n(),process.exit(1)}),o.on("exit",(c,f)=>{n(),u&&process.exit(0),f&&process.exit(0),process.exit(c??0)});const l=c=>{u||(u=!0,n(),s.close(),!o.killed&&!o.kill(c)&&process.exit(0),setTimeout(()=>process.exit(0),1e3).unref())};process.once("SIGTERM",()=>l("SIGTERM")),process.once("SIGINT",()=>l("SIGINT"))}function D(e,r){try{return b(e)===E(r)}catch{return!1}}D(process.argv[1],import.meta.url)&&R();export{S as RECENT_EMITTED_LINE_CAP,w as RecentLineDeduper,$ as acquireInboxLock,m as formatEventLine,v as formatFreshEventLine,D as isEntryInvocation,T as pidfilePathFor,N as seedDeduperFromInboxTail};
|
package/dist/token-store.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import
|
|
1
|
+
import w from"path";import d from"crypto";import{AsyncEntry as h}from"@napi-rs/keyring";import{decryptString as k,encryptString as g}from"./token-crypto.js";const S="borg-mcp",E=t=>new h(S,t);function K(t=E){return{name:"keychain",async get(e){return await t(e).getPassword()??null},async set(e,o){await t(e).setPassword(o)},async delete(e){try{await t(e).deletePassword()}catch(o){const a=String(o?.message??"");if(/no entry|not found|no matching/i.test(a))return;throw o}}}}const O=25,_=2e3,F=1e4;function x(t){return new Promise(e=>setTimeout(e,t))}function v(){return`${process.pid}.${d.randomBytes(6).toString("hex")}`}function T(t){const{filePath:e,key:o,fs:a}=t,y=t.sleep??x,s=t.now??Date.now,p=t.uniqueSuffix??v,c=`${e}.lock`;async function l(){let r;try{r=await a.readFile(e)}catch{return{}}try{const n=k(r.trim(),o),i=JSON.parse(n);return i&&typeof i=="object"?i:{}}catch{return{}}}async function u(r){await a.mkdir(w.dirname(e),448);const n=`${e}.${p()}.tmp`;await a.writeFile(n,g(JSON.stringify(r),o),384);try{await a.rename(n,e)}catch(i){try{await a.removeFile(n)}catch{}throw i}}async function f(r){await a.mkdir(w.dirname(c),448);const n=s()+_;let i=!1;for(;!i&&(i=await a.createExclusive(c,`${process.pid}@${s()}`),!i);){const m=await a.fileAgeMs(c);if(m!==null&&m>F){await a.removeFile(c);continue}if(s()>=n){await a.removeFile(c),i=await a.createExclusive(c,`${process.pid}@${s()}`);break}await y(O)}try{return await r()}finally{i&&await a.removeFile(c)}}return{name:"encrypted-file",async get(r){const n=await l();return Object.prototype.hasOwnProperty.call(n,r)?n[r]:null},set(r,n){return f(async()=>{const i=await l();i[r]=n,await u(i)})},delete(r){return f(async()=>{const n=await l();Object.prototype.hasOwnProperty.call(n,r)&&(delete n[r],await u(n))})}}}async function b(t){return t.forced==="keychain"?t.makeKeychain():t.forced==="file"?t.makeFile():await t.keyringAvailable()?t.makeKeychain():t.makeFile()}async function L(t){const e=t.env.BORG_TOKEN?.trim();if(e)return e;const o=t.env.BORG_TOKEN_FILE?.trim();return o?(await t.readFile(o)).trim():null}export{T as makeEncryptedFileBackend,K as makeKeychainBackend,L as readCallerManagedIdToken,b as selectTokenBackend};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "borgmcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.15",
|
|
4
4
|
"description": "Coordinate AI coding agents in shared cubes. Works with Claude Code and Codex. Create projects, assign roles, and share a live activity log.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|