@phnx-labs/agents-cli 1.22.40 → 1.22.42

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 (201) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +14 -3
  3. package/dist/bin/agents +0 -0
  4. package/dist/bootstrap.js +0 -1
  5. package/dist/cli/command-registry.d.ts +2 -0
  6. package/dist/cli/command-registry.js +5 -2
  7. package/dist/commands/accounts.d.ts +29 -0
  8. package/dist/commands/accounts.js +220 -29
  9. package/dist/commands/alias.js +1 -1
  10. package/dist/commands/auth.d.ts +9 -0
  11. package/dist/commands/auth.js +104 -0
  12. package/dist/commands/browser-sessions-picker.js +42 -62
  13. package/dist/commands/browser.d.ts +15 -0
  14. package/dist/commands/browser.js +145 -78
  15. package/dist/commands/computer-actions.d.ts +1 -1
  16. package/dist/commands/computer-actions.js +1 -1
  17. package/dist/commands/computer-sessions-picker.js +32 -55
  18. package/dist/commands/computer.d.ts +1 -1
  19. package/dist/commands/computer.js +2 -2
  20. package/dist/commands/doctor.d.ts +1 -1
  21. package/dist/commands/doctor.js +3 -3
  22. package/dist/commands/feed.js +4 -12
  23. package/dist/commands/hooks.js +1 -1
  24. package/dist/commands/import.js +1 -1
  25. package/dist/commands/insights.js +163 -85
  26. package/dist/commands/inspect.js +2 -2
  27. package/dist/commands/mine.js +1 -1
  28. package/dist/commands/org.d.ts +6 -0
  29. package/dist/commands/org.js +174 -0
  30. package/dist/commands/packages.js +1 -1
  31. package/dist/commands/prune.js +1 -1
  32. package/dist/commands/routines.js +1 -1
  33. package/dist/commands/run-account-picker.d.ts +19 -0
  34. package/dist/commands/run-account-picker.js +81 -0
  35. package/dist/commands/secrets.js +87 -97
  36. package/dist/commands/sessions-picker-factory.d.ts +40 -0
  37. package/dist/commands/sessions-picker-factory.js +67 -0
  38. package/dist/commands/sessions-picker.d.ts +1 -0
  39. package/dist/commands/sessions-picker.js +27 -5
  40. package/dist/commands/sessions-share.d.ts +25 -0
  41. package/dist/commands/sessions-share.js +166 -0
  42. package/dist/commands/sessions.js +2 -0
  43. package/dist/commands/setup-browser.js +5 -5
  44. package/dist/commands/setup-mine.js +1 -1
  45. package/dist/commands/setup-preferences.js +4 -4
  46. package/dist/commands/setup.js +5 -3
  47. package/dist/commands/sync.js +1 -1
  48. package/dist/commands/versions.js +1 -1
  49. package/dist/commands/view.js +1 -1
  50. package/dist/commands/webhook.js +14 -9
  51. package/dist/lib/account-capabilities.d.ts +10 -0
  52. package/dist/lib/account-capabilities.js +34 -0
  53. package/dist/lib/agent-spec/agents.d.ts +584 -0
  54. package/dist/lib/agent-spec/agents.js +3127 -0
  55. package/dist/lib/agent-spec/provider.js +1 -1
  56. package/dist/lib/agents.d.ts +2 -584
  57. package/dist/lib/agents.js +2 -3127
  58. package/dist/lib/browser/cdp.js +4 -0
  59. package/dist/lib/browser/chrome.js +12 -1
  60. package/dist/lib/browser/drivers/local.d.ts +8 -2
  61. package/dist/lib/browser/drivers/local.js +8 -2
  62. package/dist/lib/browser/drivers/ssh.d.ts +8 -2
  63. package/dist/lib/browser/drivers/ssh.js +11 -4
  64. package/dist/lib/browser/hygiene.d.ts +1 -1
  65. package/dist/lib/browser/hygiene.js +5 -1
  66. package/dist/lib/browser/profiles.d.ts +77 -4
  67. package/dist/lib/browser/profiles.js +121 -12
  68. package/dist/lib/browser/runtime-state.d.ts +11 -5
  69. package/dist/lib/browser/runtime-state.js +13 -9
  70. package/dist/lib/browser/service.d.ts +91 -30
  71. package/dist/lib/browser/service.js +342 -207
  72. package/dist/lib/browser/types.d.ts +96 -4
  73. package/dist/lib/browser/types.js +51 -0
  74. package/dist/lib/catchup.js +1 -1
  75. package/dist/lib/computer/actions.d.ts +1 -1
  76. package/dist/lib/computer/actions.js +1 -1
  77. package/dist/lib/{computer-rpc.js → computer/computer-rpc.js} +5 -5
  78. package/dist/lib/computer/dispatch.d.ts +1 -1
  79. package/dist/lib/computer/download.d.ts +1 -1
  80. package/dist/lib/computer/download.js +3 -3
  81. package/dist/lib/{ssh-tunnel.d.ts → computer/ssh-tunnel.d.ts} +1 -1
  82. package/dist/lib/{ssh-tunnel.js → computer/ssh-tunnel.js} +12 -12
  83. package/dist/lib/daemon/daemon.js +1 -1
  84. package/dist/lib/{runner.d.ts → daemon/runner.d.ts} +10 -10
  85. package/dist/lib/{runner.js → daemon/runner.js} +59 -118
  86. package/dist/lib/daemon-webhooks.d.ts +3 -1
  87. package/dist/lib/daemon-webhooks.js +12 -7
  88. package/dist/lib/device-config.js +1 -1
  89. package/dist/lib/devices/doctor-findings.d.ts +1 -1
  90. package/dist/lib/devices/doctor-findings.js +3 -3
  91. package/dist/lib/devices/fleet-inventory.js +1 -1
  92. package/dist/lib/devices/harness-inventory.js +1 -1
  93. package/dist/lib/devices/registry.js +4 -22
  94. package/dist/lib/doctor-diff.d.ts +1 -1
  95. package/dist/lib/doctor-diff.js +1 -1
  96. package/dist/lib/drift.js +1 -1
  97. package/dist/lib/entitlement.d.ts +31 -0
  98. package/dist/lib/entitlement.js +137 -0
  99. package/dist/lib/exec.js +39 -202
  100. package/dist/lib/feed/feed.js +2 -8
  101. package/dist/lib/fs-atomic.d.ts +7 -0
  102. package/dist/lib/fs-atomic.js +9 -0
  103. package/dist/lib/harness/adapter.d.ts +160 -0
  104. package/dist/lib/harness/adapter.js +47 -0
  105. package/dist/lib/harness/adapters/claude.d.ts +2 -0
  106. package/dist/lib/harness/adapters/claude.js +110 -0
  107. package/dist/lib/harness/adapters/codex.d.ts +2 -0
  108. package/dist/lib/harness/adapters/codex.js +83 -0
  109. package/dist/lib/harness/adapters/copilot.d.ts +2 -0
  110. package/dist/lib/harness/adapters/copilot.js +23 -0
  111. package/dist/lib/harness/adapters/cursor.d.ts +2 -0
  112. package/dist/lib/harness/adapters/cursor.js +38 -0
  113. package/dist/lib/harness/adapters/droid.d.ts +2 -0
  114. package/dist/lib/harness/adapters/droid.js +17 -0
  115. package/dist/lib/harness/adapters/grok.d.ts +2 -0
  116. package/dist/lib/harness/adapters/grok.js +14 -0
  117. package/dist/lib/harness/adapters/kimi.d.ts +2 -0
  118. package/dist/lib/harness/adapters/kimi.js +49 -0
  119. package/dist/lib/harness/adapters/muse.d.ts +2 -0
  120. package/dist/lib/harness/adapters/muse.js +44 -0
  121. package/dist/lib/harness/adapters/opencode.d.ts +2 -0
  122. package/dist/lib/harness/adapters/opencode.js +14 -0
  123. package/dist/lib/harness/exec-config-version.d.ts +8 -0
  124. package/dist/lib/harness/exec-config-version.js +22 -0
  125. package/dist/lib/harness/index.d.ts +1 -0
  126. package/dist/lib/harness/index.js +34 -0
  127. package/dist/lib/{hooks.d.ts → hooks/install.d.ts} +1 -1
  128. package/dist/lib/{hooks.js → hooks/install.js} +11 -11
  129. package/dist/lib/import.js +1 -1
  130. package/dist/lib/installations/index.d.ts +4 -4
  131. package/dist/lib/installations/index.js +3 -4
  132. package/dist/lib/installations/migrate.js +6 -6
  133. package/dist/lib/{shims.d.ts → installations/shims.d.ts} +2 -2
  134. package/dist/lib/{shims.js → installations/shims.js} +12 -114
  135. package/dist/lib/installations/store.d.ts +141 -3
  136. package/dist/lib/installations/store.js +475 -5
  137. package/dist/lib/installations/versions.d.ts +1 -126
  138. package/dist/lib/installations/versions.js +5 -465
  139. package/dist/lib/isolation-boundary-report.d.ts +1 -1
  140. package/dist/lib/isolation-boundary-report.js +1 -1
  141. package/dist/lib/mailbox-gc.js +2 -3
  142. package/dist/lib/menubar/MenubarHelper.app/Contents/CodeResources +0 -0
  143. package/dist/lib/menubar/MenubarHelper.app/Contents/MacOS/MenubarHelper +0 -0
  144. package/dist/lib/monitors/dispatch.d.ts +1 -1
  145. package/dist/lib/monitors/dispatch.js +2 -2
  146. package/dist/lib/monitors/state.d.ts +1 -1
  147. package/dist/lib/observe-aliases.d.ts +2 -2
  148. package/dist/lib/observe-aliases.js +2 -11
  149. package/dist/lib/plugins/plugins.js +1 -1
  150. package/dist/lib/plugins/skills.js +1 -1
  151. package/dist/lib/prix-account.d.ts +158 -0
  152. package/dist/lib/prix-account.js +214 -0
  153. package/dist/lib/project-key.js +7 -0
  154. package/dist/lib/project-launch.js +1 -1
  155. package/dist/lib/refresh.js +2 -2
  156. package/dist/lib/resource-inventory.d.ts +1 -1
  157. package/dist/lib/resource-inventory.js +1 -1
  158. package/dist/lib/rules/rules.js +1 -1
  159. package/dist/lib/scheduling/routines.js +1 -1
  160. package/dist/lib/secrets/Agents CLI.app/Contents/CodeResources +0 -0
  161. package/dist/lib/secrets/Agents CLI.app/Contents/MacOS/Agents CLI +0 -0
  162. package/dist/lib/secrets/bundles.d.ts +1 -1
  163. package/dist/lib/secrets/bundles.js +1 -1
  164. package/dist/lib/secrets/headless.d.ts +16 -0
  165. package/dist/lib/secrets/headless.js +21 -0
  166. package/dist/lib/secrets/remote.d.ts +9 -7
  167. package/dist/lib/secrets/remote.js +18 -9
  168. package/dist/lib/self-heal/checks/hook-runtime.js +1 -1
  169. package/dist/lib/self-heal/checks/path.js +1 -1
  170. package/dist/lib/self-heal/checks/shadowing.js +1 -1
  171. package/dist/lib/self-heal/checks/shims.js +1 -1
  172. package/dist/lib/session/discover.d.ts +39 -0
  173. package/dist/lib/session/discover.js +3 -3
  174. package/dist/lib/session/parse.js +24 -42
  175. package/dist/lib/session/recovery.js +1 -1
  176. package/dist/lib/session/share-html.d.ts +55 -0
  177. package/dist/lib/session/share-html.js +319 -0
  178. package/dist/lib/settings-manifest.d.ts +2 -0
  179. package/dist/lib/settings-manifest.js +81 -3
  180. package/dist/lib/share/publish.d.ts +38 -0
  181. package/dist/lib/share/publish.js +81 -8
  182. package/dist/lib/staleness/prune.d.ts +1 -1
  183. package/dist/lib/staleness/prune.js +1 -1
  184. package/dist/lib/staleness/writers/hooks.js +1 -1
  185. package/dist/lib/startup/command-registry.d.ts +2 -1
  186. package/dist/lib/startup/command-registry.js +5 -3
  187. package/dist/lib/teams/agents.js +2 -19
  188. package/dist/lib/teams/parsers.js +20 -26
  189. package/dist/lib/teams/registry.js +2 -21
  190. package/dist/lib/triggers/handlers.d.ts +37 -2
  191. package/dist/lib/triggers/handlers.js +57 -6
  192. package/dist/lib/triggers/webhook.d.ts +80 -6
  193. package/dist/lib/triggers/webhook.js +128 -4
  194. package/dist/lib/types.d.ts +1 -1
  195. package/dist/lib/uninstall.js +1 -1
  196. package/dist/lib/version.d.ts +9 -2
  197. package/dist/lib/version.js +11 -9
  198. package/dist/lib/wrap.d.ts +33 -0
  199. package/dist/lib/wrap.js +70 -0
  200. package/package.json +1 -1
  201. /package/dist/lib/{computer-rpc.d.ts → computer/computer-rpc.d.ts} +0 -0
@@ -0,0 +1,47 @@
1
+ /**
2
+ * The four config-dir env keys a harness pins to its version home. Every
3
+ * per-harness branch in the old buildExecEnv deleted the ones it does NOT set,
4
+ * so its own config pointer never leaks into a foreign harness's invocation.
5
+ * (XDG_CONFIG_HOME / XDG_DATA_HOME — Muse/Cursor — are deliberately absent: the
6
+ * old code sets them but never strips them, and this preserves that exactly.)
7
+ */
8
+ export const CONFIG_DIR_ENV_KEYS = [
9
+ 'CLAUDE_CONFIG_DIR',
10
+ 'CODEX_HOME',
11
+ 'COPILOT_HOME',
12
+ 'KIMI_CODE_HOME',
13
+ ];
14
+ /**
15
+ * Strip every config-dir env key except the one(s) this harness sets. `keep=[]`
16
+ * (the default / no-config-dir harness) deletes all four — the old `else` arm.
17
+ */
18
+ export function stripForeignConfigDir(result, keep = []) {
19
+ for (const key of CONFIG_DIR_ENV_KEYS) {
20
+ if (!keep.includes(key))
21
+ delete result[key];
22
+ }
23
+ }
24
+ const REGISTRY = new Map();
25
+ /**
26
+ * The no-behavior adapter — a harness with no managed config-dir env and no
27
+ * launch-arg quirks. buildExecEnv strips all four config-dir keys for it (the old
28
+ * `else` arm) by falling back to {@link stripForeignConfigDir} when an adapter
29
+ * omits `applyExecConfigEnv`.
30
+ */
31
+ function defaultAdapter(id) {
32
+ return { id };
33
+ }
34
+ export function registerHarnessAdapter(adapter) {
35
+ REGISTRY.set(adapter.id, adapter);
36
+ }
37
+ /**
38
+ * The behavior adapter for a harness. Every `AgentId` resolves to an adapter —
39
+ * one with real behavior when registered, else the id-only default (the old
40
+ * `else` arm). Callers therefore never name-check a harness.
41
+ */
42
+ export function resolveHarnessAdapter(id) {
43
+ return REGISTRY.get(id) ?? defaultAdapter(id);
44
+ }
45
+ export function listHarnessAdapters() {
46
+ return [...REGISTRY.keys()].sort();
47
+ }
@@ -0,0 +1,2 @@
1
+ import type { HarnessAdapter } from '../adapter.js';
2
+ export declare const claudeAdapter: HarnessAdapter;
@@ -0,0 +1,110 @@
1
+ import * as path from 'path';
2
+ import { stripForeignConfigDir } from '../adapter.js';
3
+ export const claudeAdapter = {
4
+ id: 'claude',
5
+ applyExecConfigEnv(result, ctx) {
6
+ const { versionHome } = ctx;
7
+ // The per-account `claude setup-token` only resolves when there is a version
8
+ // home to key it to; version===null (claude unresolved / not installed) yields
9
+ // null, exactly as the routines path treats it (`runner.ts:1017-1021`). The
10
+ // token decision below runs even then, so an ambient inherited value is stripped
11
+ // on the routines/provisioned path regardless of whether a version resolved.
12
+ // resolveClaudeSetupToken is injected (see ExecConfigEnvCtx) to keep this
13
+ // adapter import-leaf — importing claude-account-token here would drag the
14
+ // secrets/sqlite graph into shims.ts.
15
+ const setupToken = versionHome ? ctx.resolveClaudeSetupToken(versionHome) : null;
16
+ if (versionHome) {
17
+ result.CLAUDE_CONFIG_DIR = path.join(versionHome, '.claude');
18
+ // A managed pin lives in a per-version dir; Claude Code's own background
19
+ // auto-updater would rewrite that pinned binary in place (and has left it
20
+ // half-swapped and broken). Disable it so a pin stays a pin. Honor an
21
+ // explicit user value — from process.env (already in result) or from
22
+ // options.env (spread over result below).
23
+ if (result.DISABLE_AUTOUPDATER === undefined) {
24
+ result.DISABLE_AUTOUPDATER = '1';
25
+ }
26
+ }
27
+ // The `auth` bundle's setup-token exists so a run with NO human present
28
+ // authenticates without the Touch-ID-gated login item — usage probes,
29
+ // routines, dispatched runs (claude-account-token.ts). An interactive run
30
+ // has a human at the TTY, and their own per-version login is the credential
31
+ // they established and expect; overriding it made `/status` report
32
+ // `Auth token: CLAUDE_CODE_OAUTH_TOKEN` on a personal machine and took every
33
+ // hand-driven session off that login. macOS cannot cheaply confirm a home's
34
+ // login first (probing the Keychain raises an authorization sheet per
35
+ // installed version on the `agents run` hot path — agents.ts
36
+ // `isClaudeCredentialFileBlank`), so interactive simply defers to Claude
37
+ // Code, which prompts a present human to log in if the login is missing.
38
+ if (ctx.interactive) {
39
+ // Drop an INHERITED copy of OUR OWN setup-token: an interactive launch from
40
+ // inside a headless agent's shell inherits that agent's injected value via
41
+ // sanitizeProcessEnv(process.env) and would keep authenticating as it.
42
+ // Matched by VALUE, so a token the user exported deliberately is a different
43
+ // string and is left alone (#2383). This is NARROWER than the non-interactive
44
+ // path below, which overwrites-or-deletes unconditionally and never inspects
45
+ // the inherited value — a DIFFERENT account's inherited setup-token passing
46
+ // through this equality check is the adjacent hole RUSH-2360 leaves as
47
+ // follow-up (it does not silently run on a *shared, rotating* token, which is
48
+ // what caused the RUSH-1822 logout storm).
49
+ if (setupToken && result.CLAUDE_CODE_OAUTH_TOKEN === setupToken) {
50
+ delete result.CLAUDE_CODE_OAUTH_TOKEN;
51
+ }
52
+ }
53
+ else {
54
+ // Non-interactive (routines, dispatched, provisioned box): mirror the routines
55
+ // path (`runner.ts:1017-1021`) UNCONDITIONALLY. Inject the per-account
56
+ // setup-token when one resolves — it replaces any ambient shared value
57
+ // inherited from the launcher. When NONE resolves, STRIP the ambient
58
+ // CLAUDE_CODE_OAUTH_TOKEN so a run on a provisioned box can never silently
59
+ // authenticate as the shared, rotating token an earlier version of this path
60
+ // let through — the RUSH-1822 fleet-wide-logout hazard, tracked by RUSH-2360.
61
+ // A missing login then fails loud (401) against this home's own credential
62
+ // instead of quietly borrowing another's. options.env still wins below for an
63
+ // explicit caller override.
64
+ if (setupToken) {
65
+ result.CLAUDE_CODE_OAUTH_TOKEN = setupToken;
66
+ }
67
+ else {
68
+ delete result.CLAUDE_CODE_OAUTH_TOKEN;
69
+ }
70
+ }
71
+ stripForeignConfigDir(result, ['CLAUDE_CONFIG_DIR']);
72
+ },
73
+ shimConfigEnvBash(ctx) {
74
+ return `
75
+ # Claude stores OAuth credentials in the macOS keychain. Scope them to the
76
+ # selected version's config directory so switching versions also switches the
77
+ # live Claude account.
78
+ export CLAUDE_CONFIG_DIR="$VERSION_DIR/home/${ctx.configDirName}"
79
+ # Managed installs are pinned in a per-version dir; Claude Code's background
80
+ # auto-updater would rewrite the pinned binary in place. Disable it so a pin
81
+ # stays a pin. An explicit user value always wins.
82
+ export DISABLE_AUTOUPDATER="\${DISABLE_AUTOUPDATER:-1}"
83
+ # On Linux sandboxes (no keychain), fall back to a per-version token file.
84
+ # The env var always wins if already set; no-op on macOS.
85
+ if [ "\$(uname -s)" = "Linux" ] && [ -z "\${CLAUDE_CODE_OAUTH_TOKEN:-}" ] && [ -f "\$CLAUDE_CONFIG_DIR/.oauth_token" ]; then
86
+ CLAUDE_CODE_OAUTH_TOKEN=\$(cat "\$CLAUDE_CONFIG_DIR/.oauth_token")
87
+ export CLAUDE_CODE_OAUTH_TOKEN
88
+ fi
89
+ `;
90
+ },
91
+ routineModeArgs(cmd, ctx) {
92
+ const mode = ctx.mode;
93
+ if (mode === 'edit') {
94
+ const planIndex = cmd.indexOf('plan');
95
+ if (planIndex !== -1)
96
+ cmd[planIndex] = 'acceptEdits';
97
+ }
98
+ else if (mode === 'auto') {
99
+ const planIndex = cmd.indexOf('plan');
100
+ if (planIndex !== -1)
101
+ cmd[planIndex] = 'auto';
102
+ }
103
+ else if (mode === 'skip') {
104
+ // Replace --permission-mode plan with --dangerously-skip-permissions
105
+ const pmIndex = cmd.indexOf('--permission-mode');
106
+ if (pmIndex !== -1)
107
+ cmd.splice(pmIndex, 2, '--dangerously-skip-permissions');
108
+ }
109
+ },
110
+ };
@@ -0,0 +1,2 @@
1
+ import type { HarnessAdapter } from '../adapter.js';
2
+ export declare const codexAdapter: HarnessAdapter;
@@ -0,0 +1,83 @@
1
+ import * as os from 'os';
2
+ import * as path from 'path';
3
+ import { getHistoryDir } from '../../state.js';
4
+ import { resolveCodexHome, codexHomeShimBash } from '../../codex-home.js';
5
+ import { codexEditWritableRoots, codexPolicyArgs } from '../../codex-policy.js';
6
+ import { stripForeignConfigDir } from '../adapter.js';
7
+ /**
8
+ * Shim-script single-quoting — identical to the local `shellQuote` in shims.ts
9
+ * (always wraps in single quotes), NOT ssh-exec's variant (which leaves
10
+ * shell-safe strings unquoted). The generated shim's codex launch args must stay
11
+ * byte-for-byte what shims.ts produced, so the quoting moves with the logic.
12
+ */
13
+ function shimShellQuote(value) {
14
+ return `'${value.replace(/'/g, `'\\''`)}'`;
15
+ }
16
+ export const codexAdapter = {
17
+ id: 'codex',
18
+ applyExecConfigEnv(result, ctx) {
19
+ if (ctx.version && ctx.versionHome) {
20
+ // On macOS the deep versioned home overflows the Unix-socket SUN_LEN
21
+ // limit for codex's app-server control socket; resolve to a short,
22
+ // SUN_LEN-safe home (migrating once if needed). See codex-home.ts.
23
+ const versionedHome = path.join(ctx.versionHome, '.codex');
24
+ const agentsUserDir = path.dirname(getHistoryDir());
25
+ result.CODEX_HOME = resolveCodexHome(versionedHome, agentsUserDir, ctx.version);
26
+ }
27
+ stripForeignConfigDir(result, ['CODEX_HOME']);
28
+ },
29
+ shimConfigEnvBash(ctx) {
30
+ return codexHomeShimBash(`$VERSION_DIR/home/${ctx.configDirName}`, `$AGENTS_USER_DIR/.codex-homes/$VERSION`);
31
+ },
32
+ shimLaunchArgs() {
33
+ return ` ${[
34
+ '-c',
35
+ 'check_for_update_on_startup=false',
36
+ ...codexPolicyArgs('edit'),
37
+ ].map(shimShellQuote).join(' ')}`;
38
+ },
39
+ shimExecTail(launchArgs) {
40
+ // Codex is special: its `workspace-write` sandbox hardcodes any `.agents/`
41
+ // (and `.codex/`) directory read-only, but agents-cli keeps every worktree at
42
+ // `<repo>/.agents/worktrees/<slug>`, so an in-repo build under a static shim
43
+ // would hit `EROFS`. The shim resolves the repo's `.agents` from `$PWD` at RUN
44
+ // time — worktree-aware, mirroring repoAgentsDirForCwd — and passes it via
45
+ // Codex's own `--add-dir`. `--add-dir` is added only when the resolved
46
+ // `.agents` exists.
47
+ return `_repo_agents=""
48
+ case "$PWD" in
49
+ */.agents/worktrees/*) _repo_agents="\${PWD%%/.agents/worktrees/*}/.agents" ;;
50
+ *)
51
+ _d="$PWD"
52
+ # Stop before $HOME so a dotfiles repo at $HOME is not treated as the project
53
+ # root (mirrors repoRootForCwd's home exclusion in project-key.ts).
54
+ while [ -n "$_d" ] && [ "$_d" != "/" ] && [ "$_d" != "$HOME" ]; do
55
+ if [ -e "$_d/.git" ]; then _repo_agents="$_d/.agents"; break; fi
56
+ _d=$(dirname "$_d")
57
+ done
58
+ ;;
59
+ esac
60
+ if [ -n "$_repo_agents" ] && [ -d "$_repo_agents" ]; then
61
+ exec "$BINARY"${launchArgs} --add-dir "$_repo_agents" "$@"
62
+ fi
63
+ exec "$BINARY"${launchArgs} "$@"`;
64
+ },
65
+ execModeArgs(ctx) {
66
+ const policyMode = ctx.resolvedMode === 'plan' || ctx.resolvedMode === 'skip' ? ctx.resolvedMode : 'edit';
67
+ const writableRoots = [
68
+ ...codexEditWritableRoots(ctx.cwd),
69
+ ...ctx.addDirs,
70
+ ];
71
+ return codexPolicyArgs(policyMode, writableRoots);
72
+ },
73
+ routineModeArgs(cmd, ctx) {
74
+ const policyMode = ctx.mode === 'plan' || ctx.mode === 'skip' ? ctx.mode : 'edit';
75
+ const routineRoots = (ctx.config.allow?.dirs ?? []).map((dir) => {
76
+ if (dir.startsWith('-')) {
77
+ throw new Error(`allow.dirs entries must not start with '-': ${JSON.stringify(dir)}`);
78
+ }
79
+ return dir.replace(/^~/, os.homedir());
80
+ });
81
+ cmd.push(...codexPolicyArgs(policyMode, [...codexEditWritableRoots(), ...routineRoots]));
82
+ },
83
+ };
@@ -0,0 +1,2 @@
1
+ import type { HarnessAdapter } from '../adapter.js';
2
+ export declare const copilotAdapter: HarnessAdapter;
@@ -0,0 +1,23 @@
1
+ import * as path from 'path';
2
+ import { stripForeignConfigDir } from '../adapter.js';
3
+ export const copilotAdapter = {
4
+ id: 'copilot',
5
+ // Copilot honors COPILOT_HOME (relocates ~/.copilot, including settings,
6
+ // mcp-config.json, sessions, logs). Pin it at the per-version home so
7
+ // version switches isolate MCP servers, auth, and session history.
8
+ applyExecConfigEnv(result, ctx) {
9
+ if (ctx.versionHome) {
10
+ result.COPILOT_HOME = path.join(ctx.versionHome, '.copilot');
11
+ }
12
+ stripForeignConfigDir(result, ['COPILOT_HOME']);
13
+ },
14
+ shimConfigEnvBash(ctx) {
15
+ return `
16
+ # GitHub Copilot CLI honors COPILOT_HOME to relocate its config and state
17
+ # (settings.json, mcp-config.json, session-state/, logs/, plugins/). Point
18
+ # it at the versioned home so MCP servers, custom agents, and session
19
+ # history are isolated per copilot version.
20
+ export COPILOT_HOME="$VERSION_DIR/home/${ctx.configDirName}"
21
+ `;
22
+ },
23
+ };
@@ -0,0 +1,2 @@
1
+ import type { HarnessAdapter } from '../adapter.js';
2
+ export declare const cursorAdapter: HarnessAdapter;
@@ -0,0 +1,38 @@
1
+ import * as path from 'path';
2
+ import { stripForeignConfigDir } from '../adapter.js';
3
+ export const cursorAdapter = {
4
+ id: 'cursor',
5
+ // Cursor has no config-dir env var (only CURSOR_API_KEY / CURSOR_API_ENDPOINT).
6
+ // Its OAuth token — the login gate — lives at $XDG_CONFIG_HOME/cursor/auth.json
7
+ // (verified empirically: relocating XDG_CONFIG_HOME relocates the login;
8
+ // ~/.cursor/cli-config.json holds only account metadata, not the token). Pin
9
+ // XDG_CONFIG_HOME into the version home so each installed Cursor account
10
+ // authenticates from its own token, isolated per run — no global ~/.cursor
11
+ // symlink swap, so concurrent runs on different accounts never clobber one
12
+ // another. cli-config.json (HOME-relative) has no override and stays on the
13
+ // shared home; only the token is per-account, which is what gates the login.
14
+ applyExecConfigEnv(result, ctx) {
15
+ if (ctx.versionHome) {
16
+ result.XDG_CONFIG_HOME = path.join(ctx.versionHome, '.config');
17
+ }
18
+ stripForeignConfigDir(result);
19
+ },
20
+ execPreModeArgs(ctx) {
21
+ // A configured headless run is the workspace trust decision. Keep this
22
+ // narrower than --yolo/-f, which also bypasses permission checks.
23
+ return ctx.resolvedMode === 'edit' && !ctx.interactive ? ['--trust'] : undefined;
24
+ },
25
+ routineModeArgs(cmd, ctx) {
26
+ if (ctx.mode === 'plan') {
27
+ cmd.push('--plan');
28
+ }
29
+ else if (ctx.mode === 'skip') {
30
+ cmd.push('-f');
31
+ }
32
+ else {
33
+ // The configured cwd is the user's workspace trust decision. --trust is
34
+ // narrower than --yolo/-f because it does not bypass tool permissions.
35
+ cmd.push('--trust');
36
+ }
37
+ },
38
+ };
@@ -0,0 +1,2 @@
1
+ import type { HarnessAdapter } from '../adapter.js';
2
+ export declare const droidAdapter: HarnessAdapter;
@@ -0,0 +1,17 @@
1
+ // Droid has no config-dir env pin (exec strips the foreign keys via the registry
2
+ // fallback) and no shim config env. Its only harness quirk is routine autonomy.
3
+ export const droidAdapter = {
4
+ id: 'droid',
5
+ // droid exec defaults to read-only (plan). Escalate autonomy per mode.
6
+ routineModeArgs(cmd, ctx) {
7
+ if (ctx.mode === 'edit') {
8
+ cmd.push('--auto', 'low');
9
+ }
10
+ else if (ctx.mode === 'auto') {
11
+ cmd.push('--auto', 'high');
12
+ }
13
+ else if (ctx.mode === 'skip') {
14
+ cmd.push('--skip-permissions-unsafe');
15
+ }
16
+ },
17
+ };
@@ -0,0 +1,2 @@
1
+ import type { HarnessAdapter } from '../adapter.js';
2
+ export declare const grokAdapter: HarnessAdapter;
@@ -0,0 +1,14 @@
1
+ // Grok has no exec-time config-dir env pin (buildExecEnv's `else` strips the
2
+ // foreign keys — the registry fallback preserves that). It DOES relocate its
3
+ // whole config tree via GROK_HOME in the generated shim.
4
+ export const grokAdapter = {
5
+ id: 'grok',
6
+ shimConfigEnvBash() {
7
+ return `
8
+ # Grok Build uses GROK_HOME to isolate its entire configuration tree
9
+ # (skills, hooks, plugins, agents, memory, sessions, config.toml, MCP, etc.).
10
+ # This gives agents-cli full versioned isolation + resource sync for grok.
11
+ export GROK_HOME="$VERSION_DIR/home/.grok"
12
+ `;
13
+ },
14
+ };
@@ -0,0 +1,2 @@
1
+ import type { HarnessAdapter } from '../adapter.js';
2
+ export declare const kimiAdapter: HarnessAdapter;
@@ -0,0 +1,49 @@
1
+ import * as path from 'path';
2
+ import { stripForeignConfigDir } from '../adapter.js';
3
+ export const kimiAdapter = {
4
+ id: 'kimi',
5
+ // Kimi honors KIMI_CODE_HOME (relocates ~/.kimi-code, including config,
6
+ // skills, hooks, sessions). Pin it at the per-version home.
7
+ applyExecConfigEnv(result, ctx) {
8
+ if (ctx.versionHome) {
9
+ result.KIMI_CODE_HOME = path.join(ctx.versionHome, '.kimi-code');
10
+ }
11
+ stripForeignConfigDir(result, ['KIMI_CODE_HOME']);
12
+ },
13
+ shimConfigEnvBash(ctx) {
14
+ return `
15
+ # Kimi Code CLI honors KIMI_CODE_HOME to relocate ~/.kimi-code (config.toml,
16
+ # mcp.json, sessions, skills, hooks). Point it at the versioned home.
17
+ export KIMI_CODE_HOME="$VERSION_DIR/home/${ctx.configDirName}"
18
+ `;
19
+ },
20
+ execModeArgs(ctx) {
21
+ // kimi's headless prompt mode (`-p`/`--prompt`) is self-contained and REFUSES
22
+ // to be combined with any startup-mode flag: `--plan`, `--auto`, and `--yolo`
23
+ // all abort with "Cannot combine --prompt with --X" (verified against the live
24
+ // kimi CLI). The write-capable modes (edit/auto/skip) all collapse to kimi's
25
+ // default `-p` behavior, which already auto-approves tool calls, so we emit no
26
+ // mode flag. An interactive kimi run defers to the generic modeFlags path.
27
+ if (ctx.interactive)
28
+ return undefined;
29
+ // Plan can't reach here headless — resolveHeadlessMode already downgraded it to
30
+ // auto (kimi's headlessPlan:false); this asserts that invariant so a plan-mode
31
+ // run can never silently mutate the workspace.
32
+ if (ctx.resolvedMode === 'plan') {
33
+ throw new Error(`Internal error: kimi reached headless command build with resolved mode 'plan'; ` +
34
+ `resolveHeadlessMode should have downgraded it to auto (capabilities.headlessPlan is false).`);
35
+ }
36
+ // edit/auto/skip: emit no mode flag — `kimi -p` auto-runs.
37
+ return [];
38
+ },
39
+ routineModeArgs(_cmd, ctx) {
40
+ // kimi daemon jobs always run headless via `--prompt`, which cannot be
41
+ // combined with any startup-mode flag (--plan/--auto/--yolo all abort with
42
+ // "Cannot combine --prompt with --X"). edit/auto/skip reduce to kimi's default
43
+ // headless auto-run, so emit no flag. plan has no headless read-only
44
+ // equivalent, so resolveHeadlessMode downgrades a plan request to auto with a
45
+ // stderr warning (kimi's headlessPlan is false) — routines run headless, so
46
+ // interactive is always false here. The returned mode carries no flag either.
47
+ ctx.resolveHeadlessMode('kimi', ctx.mode, false);
48
+ },
49
+ };
@@ -0,0 +1,2 @@
1
+ import type { HarnessAdapter } from '../adapter.js';
2
+ export declare const museAdapter: HarnessAdapter;
@@ -0,0 +1,44 @@
1
+ import * as path from 'path';
2
+ import { stripForeignConfigDir } from '../adapter.js';
3
+ export const museAdapter = {
4
+ id: 'muse',
5
+ // Muse has no MUSE_CONFIG_DIR. Config is XDG-based:
6
+ // $XDG_CONFIG_HOME/muse (settings, skills, hooks, auth)
7
+ // $XDG_DATA_HOME/muse (sessions, plugins)
8
+ // Pin both into the version home so multi-version isolation matches
9
+ // Claude's CLAUDE_CONFIG_DIR / Codex's CODEX_HOME, and so Muse never
10
+ // resolves through the adopt-time ~/.config/muse symlink (SymlinkOrReparse).
11
+ applyExecConfigEnv(result, ctx) {
12
+ if (ctx.versionHome) {
13
+ result.XDG_CONFIG_HOME = path.join(ctx.versionHome, '.config');
14
+ result.XDG_DATA_HOME = path.join(ctx.versionHome, '.local', 'share');
15
+ }
16
+ stripForeignConfigDir(result);
17
+ },
18
+ shimConfigEnvBash() {
19
+ return `
20
+ # Muse Code has no MUSE_CONFIG_DIR. It resolves config via XDG:
21
+ # $XDG_CONFIG_HOME/muse (settings, skills, hooks, auth)
22
+ # $XDG_DATA_HOME/muse (sessions, plugins)
23
+ # Pin XDG into the version home so managed runs never walk the adopt-time
24
+ # ~/.config/muse -> version-home symlink — Muse refuses agent-definition
25
+ # sources that are SymlinkOrReparse (exit 1). Same idea as CLAUDE_CONFIG_DIR.
26
+ export XDG_CONFIG_HOME="$VERSION_DIR/home/.config"
27
+ export XDG_DATA_HOME="$VERSION_DIR/home/.local/share"
28
+ `;
29
+ },
30
+ // muse exec: plan ≈ no non-shell writes; auto skips approval prompts but
31
+ // keeps the OS sandbox; skip is --yolo (no approval, no sandbox, trust).
32
+ routineModeArgs(cmd, ctx) {
33
+ if (ctx.mode === 'plan') {
34
+ cmd.push('--disable-write');
35
+ }
36
+ else if (ctx.mode === 'auto') {
37
+ cmd.push('--disable-approval');
38
+ }
39
+ else if (ctx.mode === 'skip') {
40
+ cmd.push('--yolo');
41
+ }
42
+ // edit: default on-request approval + sandbox
43
+ },
44
+ };
@@ -0,0 +1,2 @@
1
+ import type { HarnessAdapter } from '../adapter.js';
2
+ export declare const opencodeAdapter: HarnessAdapter;
@@ -0,0 +1,14 @@
1
+ // OpenCode has no exec-time config-dir env pin (buildExecEnv's `else` strips the
2
+ // foreign keys — the registry fallback preserves that). It reads config-directory
3
+ // resources from OPENCODE_CONFIG_DIR, pinned in the generated shim.
4
+ export const opencodeAdapter = {
5
+ id: 'opencode',
6
+ shimConfigEnvBash() {
7
+ return `
8
+ # OpenCode reads plugins, agents, commands, and other config-directory
9
+ # resources from OPENCODE_CONFIG_DIR. Point it at the versioned global config
10
+ # tree where agents-cli syncs OpenCode resources.
11
+ export OPENCODE_CONFIG_DIR="$VERSION_DIR/home/.config/opencode"
12
+ `;
13
+ },
14
+ };
@@ -0,0 +1,8 @@
1
+ import type { AgentId } from '../types.js';
2
+ export interface ResolvedConfigVersion {
3
+ /** The version to pin, or null when unresolved / not installed. */
4
+ version: string | null;
5
+ /** The version home for that version, or null. */
6
+ versionHome: string | null;
7
+ }
8
+ export declare function resolveConfigVersion(agent: AgentId, cwd: string, optionsVersion?: string): ResolvedConfigVersion;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Shared version resolution for the exec-time config-dir env pin. Every
3
+ * config-dir harness branch in the old buildExecEnv computed this identically:
4
+ * an explicit `--version` is used unconditionally; an auto-resolved version is
5
+ * only pinned when it is actually installed on disk.
6
+ *
7
+ * The caller (buildExecEnv) invokes this and passes the result into the adapter
8
+ * via ExecConfigEnvCtx — the adapters MUST NOT import installations/versions
9
+ * themselves, because that module imports shims.ts and shims.ts imports the
10
+ * harness barrel, which would close an import cycle (versions → shims → harness →
11
+ * adapter → versions). That cycle forced esbuild/tsx to emit CJS for part of the
12
+ * graph and broke sqlite.ts's top-level await in subprocess-spawning tests.
13
+ */
14
+ import { getVersionHomePath, isVersionInstalled, resolveVersion } from '../installations/versions.js';
15
+ export function resolveConfigVersion(agent, cwd, optionsVersion) {
16
+ const resolvedVersion = optionsVersion ?? resolveVersion(agent, cwd);
17
+ const version = optionsVersion
18
+ ? resolvedVersion
19
+ : (resolvedVersion && isVersionInstalled(agent, resolvedVersion) ? resolvedVersion : null);
20
+ const versionHome = version ? getVersionHomePath(agent, version) : null;
21
+ return { version: version ?? null, versionHome };
22
+ }
@@ -0,0 +1 @@
1
+ export { type HarnessAdapter, type ExecConfigEnvCtx, type ShimConfigEnvCtx, type ExecLaunchArgsCtx, type RoutineLaunchCtx, CONFIG_DIR_ENV_KEYS, stripForeignConfigDir, registerHarnessAdapter, resolveHarnessAdapter, listHarnessAdapters, } from './adapter.js';
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Harness adapter barrel — importing this registers every built-in adapter, the
3
+ * same pattern as lib/channels/providers/index.ts. Consumers import
4
+ * `resolveHarnessAdapter` from here (not from ./adapter.js directly) so the
5
+ * registration side-effect has run before the first resolve.
6
+ *
7
+ * A harness with no config-env / launch quirks needs no adapter file: every
8
+ * `AgentId` still resolves (to the id-only default), so call sites never
9
+ * name-check a harness.
10
+ */
11
+ import { registerHarnessAdapter } from './adapter.js';
12
+ import { claudeAdapter } from './adapters/claude.js';
13
+ import { codexAdapter } from './adapters/codex.js';
14
+ import { copilotAdapter } from './adapters/copilot.js';
15
+ import { kimiAdapter } from './adapters/kimi.js';
16
+ import { museAdapter } from './adapters/muse.js';
17
+ import { cursorAdapter } from './adapters/cursor.js';
18
+ import { grokAdapter } from './adapters/grok.js';
19
+ import { opencodeAdapter } from './adapters/opencode.js';
20
+ import { droidAdapter } from './adapters/droid.js';
21
+ for (const adapter of [
22
+ claudeAdapter,
23
+ codexAdapter,
24
+ copilotAdapter,
25
+ kimiAdapter,
26
+ museAdapter,
27
+ cursorAdapter,
28
+ grokAdapter,
29
+ opencodeAdapter,
30
+ droidAdapter,
31
+ ]) {
32
+ registerHarnessAdapter(adapter);
33
+ }
34
+ export { CONFIG_DIR_ENV_KEYS, stripForeignConfigDir, registerHarnessAdapter, resolveHarnessAdapter, listHarnessAdapters, } from './adapter.js';
@@ -28,7 +28,7 @@ export declare function toPortableCommand(absPath: string, home?: string, sep?:
28
28
  * outside version homes are user-owned and remain untouched.
29
29
  */
30
30
  export declare function deduplicateVersionHookCommands(commands: string[], activeVersionHome: string): string[];
31
- import type { AgentId, HookCacheConfig, HookMatches, InstalledHook, ManifestHook } from './types.js';
31
+ import type { AgentId, HookCacheConfig, HookMatches, InstalledHook, ManifestHook } from '../types.js';
32
32
  export type HookEntry = {
33
33
  name: string;
34
34
  scriptPath: string;
@@ -16,10 +16,10 @@ import * as TOML from 'smol-toml';
16
16
  import { execFile, execFileSync } from 'child_process';
17
17
  import { promisify } from 'util';
18
18
  import { fileURLToPath } from 'url';
19
- import { AGENTS, agentConfigDirName, isAgentHardDeprecated } from './agents.js';
20
- import { supports, explainSkip, capableAgents } from './capabilities.js';
21
- import { getHooksDir as getSystemHooksDir, getUserHooksDir, getUserAgentsDir, getSystemAgentsDir, getProjectAgentsDir, getTrashHooksDir, getEnabledExtraRepos, getResolvedRulesDir, getUserRulesDir, getPerfDir } from './state.js';
22
- import { collectSubruleHooksFromState } from './rules/compose.js';
19
+ import { AGENTS, agentConfigDirName, isAgentHardDeprecated } from '../agents.js';
20
+ import { supports, explainSkip, capableAgents } from '../capabilities.js';
21
+ import { getHooksDir as getSystemHooksDir, getUserHooksDir, getUserAgentsDir, getSystemAgentsDir, getProjectAgentsDir, getTrashHooksDir, getEnabledExtraRepos, getResolvedRulesDir, getUserRulesDir, getPerfDir } from '../state.js';
22
+ import { collectSubruleHooksFromState } from '../rules/compose.js';
23
23
  function getCentralHooksDir() { return getUserHooksDir(); }
24
24
  /**
25
25
  * Resolve a hook script's absolute path. Checks user dir first, then enabled
@@ -267,9 +267,9 @@ function collapseVersionHookEntries(entries, activeVersionHome) {
267
267
  return true;
268
268
  });
269
269
  }
270
- import { getEffectiveHome, getGlobalDefault, getVersionHomePath, isVersionIsolated, listInstalledVersions, resolveVersion, } from './installations/versions.js';
271
- import { generateHookShim, getHookShimPath, isValidHookShimName, parseCacheConfig, removeHookShim } from './hooks/cache.js';
272
- import { getHookShimsDir } from './state.js';
270
+ import { getEffectiveHome, getGlobalDefault, getVersionHomePath, isVersionIsolated, listInstalledVersions, resolveVersion, } from '../installations/versions.js';
271
+ import { generateHookShim, getHookShimPath, isValidHookShimName, parseCacheConfig, removeHookShim } from './cache.js';
272
+ import { getHookShimsDir } from '../state.js';
273
273
  function hookContentHash(scriptPath) {
274
274
  return crypto.createHash('sha256').update(fs.readFileSync(scriptPath)).digest('hex');
275
275
  }
@@ -3250,13 +3250,13 @@ function registerHooksForHermes(versionHome, manifest, resolveScript, managedPre
3250
3250
  const execFileAsync = promisify(execFile);
3251
3251
  function resolveSessionTrackerRoot() {
3252
3252
  const here = path.dirname(fileURLToPath(import.meta.url));
3253
- // Built/installed layout: dist/lib/ -> dist/session-tracker
3254
- const built = path.resolve(here, '..', 'session-tracker');
3253
+ // Built/installed layout: dist/lib/hooks/ -> dist/session-tracker
3254
+ const built = path.resolve(here, '..', '..', 'session-tracker');
3255
3255
  if (fs.existsSync(path.join(built, 'dist', 'hook.sh'))) {
3256
3256
  return built;
3257
3257
  }
3258
- // Source layout: apps/cli/src/lib/ -> repo root -> packages/session-tracker
3259
- const source = path.resolve(here, '..', '..', '..', '..', 'packages', 'session-tracker');
3258
+ // Source layout: apps/cli/src/lib/hooks/ -> repo root -> packages/session-tracker
3259
+ const source = path.resolve(here, '..', '..', '..', '..', '..', 'packages', 'session-tracker');
3260
3260
  if (fs.existsSync(path.join(source, 'src', 'hook.sh'))) {
3261
3261
  return source;
3262
3262
  }
@@ -22,7 +22,7 @@ import * as path from 'path';
22
22
  import { AGENTS, resolveNativeBinaryPath } from './agents.js';
23
23
  import { getUserAgentsDir, getVersionsDir } from './state.js';
24
24
  import { setGlobalDefault } from './installations/versions.js';
25
- import { createShim, createVersionedAlias, ensureShimCurrent, switchHomeFileSymlinks, assertIsolationBoundary } from './shims.js';
25
+ import { createShim, createVersionedAlias, ensureShimCurrent, switchHomeFileSymlinks, assertIsolationBoundary } from './installations/shims.js';
26
26
  const IMPORT_VERSION_RE = /^(?:latest|[A-Za-z0-9._+-]{1,64})$/;
27
27
  export function isValidImportVersion(version) {
28
28
  return IMPORT_VERSION_RE.test(version);
@@ -7,8 +7,8 @@
7
7
  * it, so the internal split can change without breaking callers (the Cursor
8
8
  * per-installation isolation track consumes exactly this).
9
9
  */
10
- export { INSTALLATION_RECORD_FILE, INSTALLATION_SCHEMA, type Installation, type InstallationRelease, type UpdateOutcome, type UpdateStrategyId, } from './types.js';
11
- export { createInstallation, ensureInstallation, installationDir, installationRecordPath, listInstallationLabels, listInstallations, mintInstallationId, readInstallation, recordRelease, writeInstallation, } from './store.js';
12
- export { InstallationAmbiguousError, InstallationNotFoundError, describeInstallation, resolveInstallation, type ResolveInstallationOptions, } from './resolve.js';
13
- export { assertValidRelease, selectUpdateStrategy, supportsPinnedUpdate, type UpdateStrategy, } from './strategies.js';
10
+ export { type Installation, type InstallationRelease, type UpdateOutcome, type UpdateStrategyId, } from './types.js';
11
+ export { createInstallation, listInstallations, recordRelease, } from './store.js';
12
+ export { describeInstallation, resolveInstallation, type ResolveInstallationOptions, } from './resolve.js';
13
+ export { selectUpdateStrategy, supportsPinnedUpdate, type UpdateStrategy, } from './strategies.js';
14
14
  export { updateInstallation, type UpdateInstallationOptions } from './update.js';