@agentconnect.md/daemon 1.0.0-rc.296 → 1.0.0-rc.298

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.
Files changed (28) hide show
  1. package/dist/{acp-host-03mQVw2Q.js → acp-host-DezWSmEG.js} +2 -2
  2. package/dist/{acp-host-03mQVw2Q.js.map → acp-host-DezWSmEG.js.map} +1 -1
  3. package/dist/{agent-list-DHFLd9ux.js → agent-list-Da9Osn4O.js} +2 -2
  4. package/dist/{agent-list-DHFLd9ux.js.map → agent-list-Da9Osn4O.js.map} +1 -1
  5. package/dist/{chat-IRJd4_lj.js → chat-D8QIIHor.js} +3 -3
  6. package/dist/{chat-IRJd4_lj.js.map → chat-D8QIIHor.js.map} +1 -1
  7. package/dist/{load-agents-8AzZXdVx.js → dist-Cq1Kimg_.js} +18 -399
  8. package/dist/dist-Cq1Kimg_.js.map +1 -0
  9. package/dist/gh-token-BfPlYQav.js +97 -0
  10. package/dist/gh-token-BfPlYQav.js.map +1 -0
  11. package/dist/{git-credential-DLRF9bOx.js → git-credential-DhWn1IBJ.js} +26 -8
  12. package/dist/git-credential-DhWn1IBJ.js.map +1 -0
  13. package/dist/{gitcred-server-Dhp-tyEI.js → gitcred-server-KXxLyYxc.js} +107 -55
  14. package/dist/gitcred-server-KXxLyYxc.js.map +1 -0
  15. package/dist/index.js +9 -5
  16. package/dist/index.js.map +1 -1
  17. package/dist/load-agents-gTqVkOwl.js +401 -0
  18. package/dist/load-agents-gTqVkOwl.js.map +1 -0
  19. package/dist/{login-vU_lQeMG.js → login-ycknK_Ag.js} +4 -3
  20. package/dist/{login-vU_lQeMG.js.map → login-ycknK_Ag.js.map} +1 -1
  21. package/dist/run-foreground-B5Uw1HWo.js +2 -0
  22. package/dist/{run-foreground-DasVEmdw.js → run-foreground-qa22G1Nt.js} +172 -20
  23. package/dist/{run-foreground-DasVEmdw.js.map → run-foreground-qa22G1Nt.js.map} +1 -1
  24. package/package.json +1 -1
  25. package/dist/git-credential-DLRF9bOx.js.map +0 -1
  26. package/dist/gitcred-server-Dhp-tyEI.js.map +0 -1
  27. package/dist/load-agents-8AzZXdVx.js.map +0 -1
  28. package/dist/run-foreground-K-ATxgOm.js +0 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentconnect.md/daemon",
3
- "version": "1.0.0-rc.296",
3
+ "version": "1.0.0-rc.298",
4
4
  "description": "AgentConnect daemon — edge message + agent execution unit",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -1 +0,0 @@
1
- {"version":3,"file":"git-credential-DLRF9bOx.js","names":[],"sources":["../src/cli/git-credential.ts"],"sourcesContent":["/**\n * `agentconnect git-credential --agent <id>` — the git credential helper\n * (docs/designs/github-app-git-credentials.md §本地 helper 通道).\n *\n * Speaks git's credential-helper protocol on stdin/stdout and proxies to the\n * daemon's gitcred.sock; the token exists only on the reply pipe. Actions:\n * get → username=x-access-token / password=<token> (host must be github.com)\n * erase → forward to the daemon (invalidate the cached token git just had rejected)\n * store → no-op\n *\n * Exit style: on ANY failure print a human-actionable line to stderr and exit 1\n * — since #251 surfaces turn failures to end users, this text is user-facing.\n * NEVER print or log the token outside the protocol response.\n */\nimport { createConnection } from 'node:net'\nimport { resolveRoot } from '../paths.js'\nimport { gitcredSocketPath } from '../cp/gitcred-server.js'\n\ninterface HelperInput {\n protocol?: string\n host?: string\n path?: string\n password?: string\n}\n\nexport async function runGitCredential(action: string, agentId: string): Promise<void> {\n if (action === 'store') return // git offers the accepted credential back — nothing to do\n\n const input = parseStdin(await readStdin())\n\n if (action === 'erase') {\n await ipc({ op: 'erase', agentId, password: input.password }).catch(() => undefined) // best-effort\n return\n }\n if (action !== 'get') return // unknown actions are ignored per the helper contract\n\n if (input.host !== undefined && input.host.toLowerCase() !== 'github.com') {\n // Not ours — stay silent so git can try other helpers / fail cleanly.\n return\n }\n\n const res = await ipc({ op: 'get', agentId })\n if (!res.ok || !res.username || !res.password) {\n process.stderr.write(\n `agentconnect: no git credentials for agent ${agentId}: ${res.error ?? 'unknown error'}\\n` +\n `(the daemon must be running and connected to the control plane)\\n`\n )\n process.exitCode = 1\n return\n }\n // Path check is diagnostics-only (requires useHttpPath=true to even arrive):\n // token scope enforces the real boundary at GitHub. Tolerate case + .git +\n // LFS-ish subpaths; on a hard mismatch, hint at the rename story.\n if (input.path !== undefined) {\n const want = normalizeRepoPath(res.repoFullName ?? '')\n const got = normalizeRepoPath(input.path)\n if (want && got && got !== want && !got.startsWith(`${want}/`)) {\n process.stderr.write(\n `agentconnect: note — git asked for ${got} but this agent's repo is ${want} ` +\n `(repo renamed? recreate the agent to re-point it)\\n`\n )\n }\n }\n process.stdout.write(`username=${res.username}\\npassword=${res.password}\\n`)\n}\n\nfunction normalizeRepoPath(p: string): string {\n return p\n .replace(/^\\/+/, '')\n .replace(/\\.git$/i, '')\n .toLowerCase()\n}\n\nfunction parseStdin(text: string): HelperInput {\n const out: Record<string, string> = {}\n for (const line of text.split('\\n')) {\n const eq = line.indexOf('=')\n if (eq > 0) out[line.slice(0, eq)] = line.slice(eq + 1)\n }\n return out\n}\n\nfunction readStdin(): Promise<string> {\n return new Promise((resolve) => {\n let buf = ''\n process.stdin.setEncoding('utf8')\n process.stdin.on('data', (c) => (buf += c))\n process.stdin.on('end', () => resolve(buf))\n process.stdin.on('error', () => resolve(buf))\n })\n}\n\ninterface IpcReply {\n ok: boolean\n username?: string\n password?: string\n repoFullName?: string\n error?: string\n}\n\nfunction ipc(msg: unknown): Promise<IpcReply> {\n const path = gitcredSocketPath(resolveRoot())\n return new Promise((resolve) => {\n const sock = createConnection(path)\n let buf = ''\n const fail = (error: string) => resolve({ ok: false, error })\n sock.setTimeout(15_000, () => {\n sock.destroy()\n fail('daemon did not answer in time')\n })\n sock.on('connect', () => sock.write(JSON.stringify(msg) + '\\n'))\n sock.on('data', (c) => {\n buf += c.toString('utf8')\n const nl = buf.indexOf('\\n')\n if (nl === -1) return\n sock.destroy()\n try {\n resolve(JSON.parse(buf.slice(0, nl)) as IpcReply)\n } catch {\n fail('malformed daemon reply')\n }\n })\n sock.on('error', (e) => fail(`cannot reach the daemon socket at ${path}: ${e.message}`))\n })\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAyBA,eAAsB,iBAAiB,QAAgB,SAAgC;CACrF,IAAI,WAAW,SAAS;CAExB,MAAM,QAAQ,WAAW,MAAM,UAAU,CAAC;CAE1C,IAAI,WAAW,SAAS;EACtB,MAAM,IAAI;GAAE,IAAI;GAAS;GAAS,UAAU,MAAM;EAAS,CAAC,CAAC,CAAC,YAAY,KAAA,CAAS;EACnF;CACF;CACA,IAAI,WAAW,OAAO;CAEtB,IAAI,MAAM,SAAS,KAAA,KAAa,MAAM,KAAK,YAAY,MAAM,cAE3D;CAGF,MAAM,MAAM,MAAM,IAAI;EAAE,IAAI;EAAO;CAAQ,CAAC;CAC5C,IAAI,CAAC,IAAI,MAAM,CAAC,IAAI,YAAY,CAAC,IAAI,UAAU;EAC7C,QAAQ,OAAO,MACb,8CAA8C,QAAQ,IAAI,IAAI,SAAS,gBAAgB,oEAEzF;EACA,QAAQ,WAAW;EACnB;CACF;CAIA,IAAI,MAAM,SAAS,KAAA,GAAW;EAC5B,MAAM,OAAO,kBAAkB,IAAI,gBAAgB,EAAE;EACrD,MAAM,MAAM,kBAAkB,MAAM,IAAI;EACxC,IAAI,QAAQ,OAAO,QAAQ,QAAQ,CAAC,IAAI,WAAW,GAAG,KAAK,EAAE,GAC3D,QAAQ,OAAO,MACb,sCAAsC,IAAI,4BAA4B,KAAK,qDAE7E;CAEJ;CACA,QAAQ,OAAO,MAAM,YAAY,IAAI,SAAS,aAAa,IAAI,SAAS,GAAG;AAC7E;AAEA,SAAS,kBAAkB,GAAmB;CAC5C,OAAO,EACJ,QAAQ,QAAQ,EAAE,CAAC,CACnB,QAAQ,WAAW,EAAE,CAAC,CACtB,YAAY;AACjB;AAEA,SAAS,WAAW,MAA2B;CAC7C,MAAM,MAA8B,CAAC;CACrC,KAAK,MAAM,QAAQ,KAAK,MAAM,IAAI,GAAG;EACnC,MAAM,KAAK,KAAK,QAAQ,GAAG;EAC3B,IAAI,KAAK,GAAG,IAAI,KAAK,MAAM,GAAG,EAAE,KAAK,KAAK,MAAM,KAAK,CAAC;CACxD;CACA,OAAO;AACT;AAEA,SAAS,YAA6B;CACpC,OAAO,IAAI,SAAS,YAAY;EAC9B,IAAI,MAAM;EACV,QAAQ,MAAM,YAAY,MAAM;EAChC,QAAQ,MAAM,GAAG,SAAS,MAAO,OAAO,CAAE;EAC1C,QAAQ,MAAM,GAAG,aAAa,QAAQ,GAAG,CAAC;EAC1C,QAAQ,MAAM,GAAG,eAAe,QAAQ,GAAG,CAAC;CAC9C,CAAC;AACH;AAUA,SAAS,IAAI,KAAiC;CAC5C,MAAM,OAAO,kBAAkB,YAAY,CAAC;CAC5C,OAAO,IAAI,SAAS,YAAY;EAC9B,MAAM,OAAO,iBAAiB,IAAI;EAClC,IAAI,MAAM;EACV,MAAM,QAAQ,UAAkB,QAAQ;GAAE,IAAI;GAAO;EAAM,CAAC;EAC5D,KAAK,WAAW,YAAc;GAC5B,KAAK,QAAQ;GACb,KAAK,+BAA+B;EACtC,CAAC;EACD,KAAK,GAAG,iBAAiB,KAAK,MAAM,KAAK,UAAU,GAAG,IAAI,IAAI,CAAC;EAC/D,KAAK,GAAG,SAAS,MAAM;GACrB,OAAO,EAAE,SAAS,MAAM;GACxB,MAAM,KAAK,IAAI,QAAQ,IAAI;GAC3B,IAAI,OAAO,IAAI;GACf,KAAK,QAAQ;GACb,IAAI;IACF,QAAQ,KAAK,MAAM,IAAI,MAAM,GAAG,EAAE,CAAC,CAAa;GAClD,QAAQ;IACN,KAAK,wBAAwB;GAC/B;EACF,CAAC;EACD,KAAK,GAAG,UAAU,MAAM,KAAK,qCAAqC,KAAK,IAAI,EAAE,SAAS,CAAC;CACzF,CAAC;AACH"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"gitcred-server-Dhp-tyEI.js","names":[],"sources":["../src/cp/git-credential.ts","../src/cp/gitcred-server.ts"],"sourcesContent":["/**\n * GitCredentialCache — daemon-side memory for CP-minted git credentials\n * (docs/designs/github-app-git-credentials.md §daemon 侧).\n *\n * Tokens live ONLY here (and transiently on helper stdout pipes): never disk,\n * never argv, never a log line. Expiry is tracked on the MONOTONIC clock as\n * `receivedAt + ttlSec` — a skewed wall clock must never resurrect a dead\n * token (`expiresAt` in the grant is observability only).\n *\n * Threshold nesting: entries are handed out only while >10min remain (the CP\n * serves grants with ≥15min, so a fresh grant always clears this). Per-agent\n * in-flight coalescing (the `cloneInFlight` pattern) keeps a cold cache from\n * fanning N concurrent helper/pull/prefetch calls into N WS REQs.\n *\n * Degradation: outside READY the fetch fails fast (see CpClient.requestGitCred)\n * and an UNEXPIRED cached token keeps serving — CP downtime only breaks remote\n * git once the hour runs out.\n */\nimport type { GitCredCapability, GitCredGrant } from '@agentconnect.md/protocol'\n\n/** Hand out only while more than this remains (nests under the CP's 15min floor). */\nconst HANDOUT_MIN_MS = 10 * 60 * 1000\n\n/** The widened scope set behind `GH_TOKEN` (P2.5 回写): git contents plus the\n * issue/PR scopes `gh issue comment` / `gh pr comment` need. The CP clamps\n * every capability to the agent's gitAccess — a read-only workspace gets a\n * read-only token, never a write scope. */\nconst GH_TOKEN_CAPABILITIES: readonly GitCredCapability[] = ['contents', 'issues', 'pull_requests']\n\n/** Cache-key prefix separating the GH_TOKEN grant from the plain git one —\n * different capability sets are different tokens with separate lifecycles. */\nconst GH_KEY = (agentId: string): string => `gh\\u0000${agentId}`\n\n/** Cache key for a repo-targeted COMMENT token (the GithubPoster's — issues/PR\n * write on the hook-watched repo, no contents). One per (agent, repo). */\nconst POST_KEY = (agentId: string, repo: string): string => `post\\u0000${agentId}\\u0000${repo.toLowerCase()}`\n\nexport class GitCredUnavailableError extends Error {\n constructor(\n message: string,\n /** Terminal (SCOPE_DENIED): stop asking for this agent until config changes. */\n readonly terminal: boolean\n ) {\n super(message)\n this.name = 'GitCredUnavailableError'\n }\n}\n\ninterface Entry {\n username: string\n token: string\n repoFullName: string\n access: 'read' | 'write'\n /** Monotonic deadline (ms on the injected monotonic clock). */\n expiresAtMono: number\n}\n\nexport interface GitCredentialCacheDeps {\n /** D→C `gitcred/request` — throws WireError-shaped errors (`code`, `retryable`). */\n request: (payload: {\n agentId: string\n reason?: 'clone' | 'fetch' | 'pull' | 'push' | 'helper'\n capabilities?: GitCredCapability[]\n repo?: string\n }) => Promise<GitCredGrant>\n log: { warn: (msg: string) => void }\n /** Monotonic ms; injectable for tests. */\n monoNow?: () => number\n}\n\nexport class GitCredentialCache {\n private readonly entries = new Map<string, Entry>()\n private readonly inflight = new Map<string, Promise<Entry>>()\n /** Agents the CP told us to stop asking for (SCOPE_DENIED — moved/mode-off). */\n private readonly denied = new Set<string>()\n private readonly monoNow: () => number\n\n constructor(private readonly deps: GitCredentialCacheDeps) {\n this.monoNow = deps.monoNow ?? (() => performance.now())\n }\n\n /** A live credential for the agent's workspace repo — cached, coalesced, or freshly pulled. */\n async get(agentId: string, reason: 'clone' | 'fetch' | 'pull' | 'push' | 'helper'): Promise<Entry> {\n return this.getKeyed(agentId, agentId, { agentId, reason })\n }\n\n /**\n * The widened GH_TOKEN grant (P2.5 回写) — same cache/coalesce/degradation\n * discipline as {@link get}, under its own key: a distinct capability set is\n * a distinct token. Injected into the agent's runtime env at host spawn;\n * expiry (≤1h, non-renewable) means write-back goes stale until the next\n * host spawn — the documented MVP limitation.\n */\n async getGhToken(agentId: string): Promise<Entry> {\n return this.getKeyed(GH_KEY(agentId), agentId, {\n agentId,\n reason: 'helper',\n capabilities: [...GH_TOKEN_CAPABILITIES]\n })\n }\n\n /**\n * The GithubPoster's comment token for a hook-watched repo (P3 出向): scoped\n * to `repo`, issues/pull_requests only — the CP refuses contents on repo-\n * targeted mints. Same cache/coalesce/degradation discipline as {@link get};\n * the token never enters the agent's environment.\n */\n async getPostToken(agentId: string, repo: string): Promise<Entry> {\n return this.getKeyed(POST_KEY(agentId, repo), agentId, {\n agentId,\n reason: 'helper',\n capabilities: ['issues', 'pull_requests'],\n repo\n })\n }\n\n private async getKeyed(\n key: string,\n agentId: string,\n payload: Parameters<GitCredentialCacheDeps['request']>[0]\n ): Promise<Entry> {\n if (this.denied.has(key)) {\n throw new GitCredUnavailableError('control plane denied git credentials for this agent', true)\n }\n const cached = this.entries.get(key)\n if (cached && cached.expiresAtMono - this.monoNow() > HANDOUT_MIN_MS) return cached\n\n let pending = this.inflight.get(key)\n if (!pending) {\n pending = this.fetch(key, payload).finally(() => this.inflight.delete(key))\n this.inflight.set(key, pending)\n }\n try {\n return await pending\n } catch (e) {\n // CP unreachable / transient: an UNEXPIRED cached token still serves.\n if (cached && cached.expiresAtMono > this.monoNow()) {\n this.deps.log.warn(`gitcred: refresh failed for agent ${agentId} — serving cached token`)\n return cached\n }\n throw e\n }\n }\n\n /**\n * Invalidate on rejection. Git calls the helper's `erase` with the failing\n * credential when the remote refuses it (GitHub revokes instantly on\n * uninstall/suspend) — matching on the presented password keeps a racing\n * fresh grant from being wiped by a stale erase.\n */\n invalidate(agentId: string, presentedPassword?: string): void {\n const entry = this.entries.get(agentId)\n if (!entry) return\n if (presentedPassword !== undefined && entry.token !== presentedPassword) return\n this.entries.delete(agentId)\n }\n\n /** agent/remove: drop the orphaned bearer tokens with the agent dir. */\n remove(agentId: string): void {\n for (const key of [agentId, GH_KEY(agentId)]) {\n this.entries.delete(key)\n this.denied.delete(key)\n }\n }\n\n private async fetch(key: string, payload: Parameters<GitCredentialCacheDeps['request']>[0]): Promise<Entry> {\n let grant: GitCredGrant\n try {\n grant = await this.deps.request(payload)\n } catch (e) {\n const code = (e as { code?: string }).code\n if (code === 'SCOPE_DENIED') {\n // Terminal: the agent moved daemons or left github-app mode. Stop\n // asking until the CP replicates a new spec (which clears the flag).\n this.denied.add(key)\n this.entries.delete(key)\n throw new GitCredUnavailableError((e as Error).message, true)\n }\n throw new GitCredUnavailableError((e as Error).message, false)\n }\n const entry: Entry = {\n username: grant.username,\n token: grant.token,\n repoFullName: grant.repoFullName,\n access: grant.access,\n expiresAtMono: this.monoNow() + grant.ttlSec * 1000\n }\n this.entries.set(key, entry)\n return entry\n }\n\n /** A replicated spec change may re-enable a previously denied agent. */\n clearDenied(agentId: string): void {\n this.denied.delete(agentId)\n this.denied.delete(GH_KEY(agentId))\n }\n}\n","/**\n * gitcred.sock — the local credential channel for agent-run git\n * (docs/designs/github-app-git-credentials.md §本地 helper 通道).\n *\n * A tiny newline-delimited-JSON server over a unix socket (0700 dir + 0600\n * socket, stale-socket cleanup — the `mcp/control-server.ts` pattern). The\n * `agentconnect git-credential` CLI subcommand connects per git invocation:\n * { op: 'get', agentId } → { ok, username, password } | { ok:false, error }\n * { op: 'erase', agentId, password? } → { ok: true }\n *\n * Trust model (design §信任模型 #1): same host + same OS user = ONE trust\n * domain. `agentId` here is routing, not authorization — any same-user process\n * can already read every workspace on this daemon. Tokens transit the socket\n * and helper stdout only; nothing lands on disk.\n *\n * Alongside the socket the daemon (re)writes two SECRET-FREE files per boot:\n * the shim `run/git-credential-helper.sh` (pins the current node + CLI path so\n * `.git/config` survives daemon upgrades) and per-agent gitconfig includes for\n * the session-env channel (see workspace/git-injection.ts).\n */\nimport { createServer, type Server, type Socket } from 'node:net'\nimport { chmodSync, mkdirSync, rmSync, writeFileSync } from 'node:fs'\nimport { createRequire } from 'node:module'\nimport { dirname, join } from 'node:path'\nimport { GitCredentialCache, GitCredUnavailableError } from './git-credential.js'\n\nexport function gitcredSocketPath(root: string): string {\n return join(root, 'run', 'gitcred.sock')\n}\n\nexport function gitcredShimPath(root: string): string {\n return join(root, 'run', 'git-credential-helper.sh')\n}\n\ninterface GitCredIpcRequest {\n op: 'get' | 'erase'\n agentId: string\n password?: string\n}\n\nexport class GitCredServer {\n private server?: Server\n\n constructor(\n private readonly cache: GitCredentialCache,\n private readonly path: string,\n private readonly log: { info: (m: string) => void; warn: (m: string) => void }\n ) {}\n\n start(): void {\n const dir = dirname(this.path)\n mkdirSync(dir, { recursive: true, mode: 0o700 })\n try {\n chmodSync(dir, 0o700) // defeat a loose umask; best-effort on non-POSIX\n } catch {\n /* best-effort */\n }\n rmSync(this.path, { force: true }) // a stale socket from a crash makes listen() throw\n\n const server = createServer((sock) => this.serve(sock))\n server.listen(this.path, () => {\n try {\n chmodSync(this.path, 0o600)\n } catch {\n /* best-effort */\n }\n this.log.info(`gitcred: helper socket at ${this.path}`)\n })\n server.on('error', (e) => this.log.warn(`gitcred: socket error: ${e.message}`))\n this.server = server\n }\n\n stop(): void {\n this.server?.close()\n rmSync(this.path, { force: true })\n }\n\n private serve(sock: Socket): void {\n let buf = ''\n sock.on('data', (chunk) => {\n buf += chunk.toString('utf8')\n const nl = buf.indexOf('\\n')\n if (nl === -1) return\n const line = buf.slice(0, nl)\n buf = buf.slice(nl + 1)\n void this.handle(line, sock)\n })\n sock.on('error', () => sock.destroy())\n }\n\n private async handle(line: string, sock: Socket): Promise<void> {\n const reply = (msg: unknown) => {\n sock.write(JSON.stringify(msg) + '\\n')\n sock.end()\n }\n let req: GitCredIpcRequest\n try {\n req = JSON.parse(line) as GitCredIpcRequest\n } catch {\n return reply({ ok: false, error: 'malformed request' })\n }\n if (req.op === 'erase') {\n // Git presents the rejected credential — GitHub revokes instantly on\n // uninstall/suspend, and this is how the daemon cache learns.\n this.cache.invalidate(req.agentId, req.password)\n return reply({ ok: true })\n }\n if (req.op !== 'get' || typeof req.agentId !== 'string') {\n return reply({ ok: false, error: 'unsupported op' })\n }\n try {\n const cred = await this.cache.get(req.agentId, 'helper')\n return reply({ ok: true, username: cred.username, password: cred.token })\n } catch (e) {\n const msg =\n e instanceof GitCredUnavailableError ? e.message : `git credentials unavailable: ${(e as Error).message}`\n return reply({ ok: false, error: msg })\n }\n }\n}\n\n/**\n * (Re)write the secret-free shim `.git/config` helper lines exec through. The\n * absolute node + CLI paths are re-pinned every daemon boot, so repo configs\n * keep working across upgrades/relocations. Quoted throughout — a home dir\n * with a space (macOS \"/Users/John Smith/…\") must not word-split.\n */\nexport function writeGitcredShim(root: string, cliEntry: string): string {\n const shim = gitcredShimPath(root)\n mkdirSync(dirname(shim), { recursive: true, mode: 0o700 })\n const q = (v: string) => `'${v.replaceAll(\"'\", \"'\\\\''\")}'`\n // Production runs the built dist (a .js entry node executes directly). A dev\n // daemon runs under tsx with a .ts argv[1] — route the shim through the tsx\n // CLI then, or plain `node entry.ts` would die resolving .js-suffixed imports.\n const argv = [q(process.execPath)]\n if (cliEntry.endsWith('.ts')) {\n const req = createRequire(import.meta.url)\n argv.push(q(req.resolve('tsx/cli')))\n }\n argv.push(q(cliEntry))\n const body = [\n '#!/bin/sh',\n '# agentconnect git credential helper shim — regenerated on daemon start; NO secrets.',\n `AGENTCONNECT_ROOT=${q(root)} \\\\`,\n ` exec ${argv.join(' ')} git-credential \"$@\"`,\n ''\n ].join('\\n')\n writeFileSync(shim, body, { mode: 0o755 })\n return shim\n}\n"],"mappings":"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"}