agent-shim 11.78.0 → 11.79.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -57,7 +57,7 @@ That's it — with no further configuration, everything in `~/.claude` that isn'
57
57
  - **An identity** is a login: the thing that owns credentials and daemon state, selected with `agent-shim run @<name>` or, once `agent-shim shim enable` has run, `claude @<name>`.
58
58
  - **A configuration profile** is a reusable, named bundle of sharing rules, independent of any identity, resolved per working directory via directory rules or a committed `.agent-shim.json`.
59
59
 
60
- A third, optional thing sits on top of identities: **a pool** is a named list of them. Select `pool:<name>` where an identity name goes (`claude @pool:subs`) and agent-shim picks the member whose unused quota is closest to expiring, skipping any that are refused right now, using the usage it already records. A pool can instead declare `--preference listed`, which tries the members in the order the pool lists them, skipping only one that is refused right now. A member entry may itself name another pool (`pool:<name>`), which is ranked with its own policy and contributes its pick at that position, so "this identity first, then the fleet" nests the fleet rather than copying its member list; cycles are refused. See [docs/configuration-model.md](docs/configuration-model.md#pools-picking-an-account-at-launch).
60
+ A third, optional thing sits on top of identities: **a pool** is a named list of them. Select `pool:<name>` where an identity name goes (`claude @pool:subs`) and agent-shim picks the member whose unused quota is closest to expiring, skipping any that are refused right now, using the usage it already records. A pool can instead declare `--preference listed`, which tries the members in the order the pool lists them, skipping only one that is refused right now. A member entry may itself name another pool (`pool:<name>`), which is ranked with its own policy and contributes its pick at that position, so "this identity first, then the fleet" nests the fleet rather than copying its member list; cycles are refused. See [docs/configuration-model.md](docs/configuration-model.md#pools-picking-an-account-at-launch). On a terminal, `agent-shim run` asks which identity to run as when none resolves, when a pool pick would change account, or when the identity is refused right now (`--pick` forces the question, `--no-pick` never asks); see [docs/configuration-model.md](docs/configuration-model.md#choosing-the-identity-at-launch-the-picker).
61
61
 
62
62
  Every top-level entry in `~/.claude` is classified into one of five categories, shipped as a default map (`config/categories.default.json`):
63
63
 
@@ -200,6 +200,7 @@ agent-shim run [@<identity>] [launch flags] [claude arguments]
200
200
  # --claude-version <version> run exactly this installed Claude Code version
201
201
  # --delay <duration> wait this long after the launcher's own output before starting claude; --[no-]pause waits for a key press instead
202
202
  # --[no-]explain with @pool:<name>, list every member the pick ranked and why, not only the one picked
203
+ # --[no-]pick on a terminal, ask which identity to run as, even when one resolved (--no-pick never asks); a launch also asks by itself when no identity resolves, a pool pick would change account or organisation, or the identity is refused right now
203
204
  # --native run the real claude with nothing from agent-shim applied; cannot be combined with the flags above
204
205
  claude @<identity> ... # the same, once `agent-shim shim enable` has run
205
206
  ```
package/dist/cli.cjs CHANGED
@@ -38198,7 +38198,7 @@ var init_package = __esm({
38198
38198
  "package.json"() {
38199
38199
  package_default = {
38200
38200
  name: "agent-shim",
38201
- version: "11.78.0",
38201
+ version: "11.79.0",
38202
38202
  description: "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
38203
38203
  license: "MIT",
38204
38204
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -67175,7 +67175,8 @@ var init_argv = __esm({
67175
67175
  { flag: "--remote-control", key: "remoteControl" },
67176
67176
  { flag: "--wait", key: "wait" },
67177
67177
  { flag: "--pause", key: "pause" },
67178
- { flag: "--explain", key: "explain" }
67178
+ { flag: "--explain", key: "explain" },
67179
+ { flag: "--pick", key: "pick" }
67179
67180
  ];
67180
67181
  LAUNCHER_FLAG_NAMES = [
67181
67182
  ...VALUED_FLAGS,
@@ -69956,7 +69957,7 @@ function decideLaunch(params, readOnly) {
69956
69957
  const configDirEscapeHatchApplies = env.CLAUDE_CONFIG_DIR !== void 0 && env.CLAUDE_CONFIG_DIR !== "";
69957
69958
  const decidedIdentity = decideIdentity({
69958
69959
  env,
69959
- argv0Identity: parsedArgv.identity,
69960
+ argv0Identity: params.pickedIdentity ?? parsedArgv.identity,
69960
69961
  directoryPinnedIdentity: params.directoryPinnedIdentity,
69961
69962
  readActiveIdentityFile: () => {
69962
69963
  const raw = fs31.readFileUtf8(paths.activeIdentityFile);
@@ -157820,6 +157821,241 @@ function buildProgram(deps) {
157820
157821
  // src/runClaude.ts
157821
157822
  init_cliError();
157822
157823
  init_configProfilesStore();
157824
+
157825
+ // src/launcher/pickerPrompt.ts
157826
+ function promptsIdentityPicker(prompts) {
157827
+ return {
157828
+ pick: async (request7) => {
157829
+ const answer = await prompts.select({
157830
+ message: request7.message,
157831
+ options: request7.entries.map((entry) => ({ value: entry.value, label: entry.label })),
157832
+ ...request7.initial === void 0 ? {} : { initialValue: request7.initial }
157833
+ });
157834
+ return prompts.isCancel(answer) ? { kind: "cancelled" } : { kind: "picked", value: answer };
157835
+ }
157836
+ };
157837
+ }
157838
+
157839
+ // src/launcher/runPicker.ts
157840
+ init_cliError();
157841
+ init_schema();
157842
+ init_account();
157843
+ init_candidateText();
157844
+ init_pick();
157845
+ init_poolPick();
157846
+ init_identity();
157847
+ init_launchReport();
157848
+ init_hold();
157849
+
157850
+ // src/launcher/pickerEntries.ts
157851
+ var PART_SEPARATOR = " | ";
157852
+ function pickerLabel(facts) {
157853
+ const name = [facts.rank === void 0 ? void 0 : `${String(facts.rank)}.`, facts.identity, facts.heading, facts.picked === true ? "(picked)" : void 0].filter((part) => part !== void 0).join(" ");
157854
+ return [name, facts.detail, facts.account, facts.quota].filter((part) => part !== void 0).join(PART_SEPARATOR);
157855
+ }
157856
+
157857
+ // src/launcher/pickerDecision.ts
157858
+ init_claudeSubcommand();
157859
+ function decidePicker(facts) {
157860
+ if (!facts.interactive || facts.configDirEscapeHatch || facts.pick === false) {
157861
+ return void 0;
157862
+ }
157863
+ if (facts.pick === true) {
157864
+ return "requested";
157865
+ }
157866
+ if (facts.unattended) {
157867
+ return void 0;
157868
+ }
157869
+ const { selection } = facts;
157870
+ switch (selection.kind) {
157871
+ case "none":
157872
+ return "no-identity";
157873
+ case "identity":
157874
+ return selection.limited ? "no-eligible-identity" : void 0;
157875
+ case "pool":
157876
+ if (selection.outcome === "none-eligible") {
157877
+ return facts.waiting ? void 0 : "no-eligible-identity";
157878
+ }
157879
+ return selection.outcome === "changes-account" ? "account-change" : void 0;
157880
+ default:
157881
+ return selection;
157882
+ }
157883
+ }
157884
+ var TERMINATOR4 = "--";
157885
+ var UNATTENDED_FLAGS = /* @__PURE__ */ new Set(["-p", "--print", "--bg"]);
157886
+ function isUnattendedLaunch(passthrough) {
157887
+ const end = passthrough.indexOf(TERMINATOR4);
157888
+ const head = end === -1 ? passthrough : passthrough.slice(0, end);
157889
+ return head.some((token) => UNATTENDED_FLAGS.has(token)) || isClaudeSubcommand(passthrough);
157890
+ }
157891
+
157892
+ // src/launcher/runPicker.ts
157893
+ init_pool();
157894
+ var IdentityPickerCancelledError = class extends CliError {
157895
+ exitCode = LAUNCH_CANCELLED_EXIT;
157896
+ constructor() {
157897
+ super("launch cancelled at the identity picker: no identity was chosen.");
157898
+ this.name = "IdentityPickerCancelledError";
157899
+ }
157900
+ };
157901
+ function memberTexts(member, nowMs) {
157902
+ if (member === void 0) {
157903
+ return {};
157904
+ }
157905
+ const billing = { login: member.account, snapshot: member.snapshot, provider: void 0, nowMs };
157906
+ const account = accountRows(billing)[0]?.value;
157907
+ const quotaRow2 = quotaRows(billing)[0];
157908
+ return {
157909
+ ...account === void 0 ? {} : { account },
157910
+ ...quotaRow2 === void 0 ? {} : { quota: quotaRow2.detail === void 0 ? quotaRow2.value : `${quotaRow2.value} (${quotaRow2.detail})` }
157911
+ };
157912
+ }
157913
+ function refusalOf(candidate) {
157914
+ return candidate.class === "ineligible" ? candidate.reasons[0] : void 0;
157915
+ }
157916
+ function accountsDiffer(members2, left, right) {
157917
+ const keyOf3 = (identity) => {
157918
+ const account = members2.find((member) => member.identity === identity)?.account;
157919
+ return account === void 0 ? void 0 : loginKeyOf(account);
157920
+ };
157921
+ const leftKey = keyOf3(left);
157922
+ const rightKey = keyOf3(right);
157923
+ return leftKey !== void 0 && rightKey !== void 0 && leftKey !== rightKey;
157924
+ }
157925
+ function poolContext(params, poolName, resuming, nowMs) {
157926
+ const { paths, usageFs } = params;
157927
+ const { sticky } = readStickyPick(usageFs, paths.usagePicksFile, params.cwd);
157928
+ const { ranking } = rankPoolGraph({
157929
+ fs: usageFs,
157930
+ paths,
157931
+ pools: params.pools ?? {},
157932
+ poolName,
157933
+ nowMs,
157934
+ resuming,
157935
+ identityExists: (name) => loadIdentity(paths.identitiesDir, name, params.fs) !== void 0,
157936
+ ...sticky === void 0 ? {} : { sticky }
157937
+ });
157938
+ const pick2 = ranking.pick?.identity;
157939
+ const named = [.../* @__PURE__ */ new Set([...ranking.candidates.map((candidate) => candidate.identity), ...sticky === void 0 ? [] : [sticky.identity]])].filter(isIdentityName);
157940
+ const members2 = loadPoolMembers(usageFs, paths, named, nowMs);
157941
+ const changes = pick2 !== void 0 && sticky !== void 0 && sticky.identity !== pick2 && accountsDiffer(members2, sticky.identity, pick2);
157942
+ return {
157943
+ selection: { kind: "pool", outcome: pick2 === void 0 ? "none-eligible" : changes ? "changes-account" : "keeps-account" },
157944
+ entries: ranking.candidates.map((candidate, index) => ({
157945
+ value: candidate.identity,
157946
+ label: pickerLabel({
157947
+ identity: candidate.identity,
157948
+ rank: index + 1,
157949
+ heading: candidateHeading(candidate),
157950
+ picked: candidate.identity === pick2,
157951
+ detail: refusalOf(candidate),
157952
+ ...memberTexts(members2.find((member) => member.identity === candidate.identity), nowMs)
157953
+ })
157954
+ })),
157955
+ initial: pick2,
157956
+ poolPick: pick2,
157957
+ message: (reason) => poolMessage(reason, poolName, pick2, sticky)
157958
+ };
157959
+ }
157960
+ function poolMessage(reason, poolName, pick2, sticky) {
157961
+ switch (reason) {
157962
+ case "account-change":
157963
+ return `Pool "${poolName}" would run this launch as ${pick2 ?? "(none)"}, a different account from ${sticky?.identity ?? "(none)"}, which this directory last ran as. Which identity should it run as?`;
157964
+ case "no-eligible-identity":
157965
+ return `Every member of pool "${poolName}" is refused right now. Which identity should this launch run as?`;
157966
+ case "requested":
157967
+ case "no-identity":
157968
+ return `Pool "${poolName}" is selected for this launch. Which identity should it run as?`;
157969
+ default:
157970
+ return reason;
157971
+ }
157972
+ }
157973
+ function identityContext(params, resuming, nowMs) {
157974
+ const { paths, usageFs } = params;
157975
+ const members2 = loadPoolMembers(usageFs, paths, params.identityNames(), nowMs);
157976
+ const { candidates } = rankPool({ members: members2, nowMs, resuming, preference: "listed" });
157977
+ const named = params.decision.name;
157978
+ const limited = named !== void 0 && candidates.some((candidate) => candidate.identity === named && candidate.class === "ineligible");
157979
+ const identityEntries = candidates.map((candidate) => ({
157980
+ value: candidate.identity,
157981
+ label: pickerLabel({ identity: candidate.identity, detail: refusalOf(candidate), ...memberTexts(members2.find((member) => member.identity === candidate.identity), nowMs) })
157982
+ }));
157983
+ const poolEntries = Object.entries(params.pools ?? {}).map(([name, pool]) => ({
157984
+ value: `pool:${name}`,
157985
+ label: pickerLabel({ identity: `pool:${name}`, detail: `members ${pool.identities.map(poolMemberIdentity).join(", ")}` })
157986
+ }));
157987
+ return {
157988
+ selection: named === void 0 ? { kind: "none" } : { kind: "identity", limited },
157989
+ entries: [...identityEntries, ...poolEntries],
157990
+ initial: named,
157991
+ poolPick: void 0,
157992
+ message: (reason) => {
157993
+ switch (reason) {
157994
+ case "no-identity":
157995
+ return "No identity is selected for this launch. Which identity should it run as?";
157996
+ case "no-eligible-identity":
157997
+ return `${named ?? "The selected identity"} is refused right now. Which identity should this launch run as?`;
157998
+ case "requested":
157999
+ case "account-change":
158000
+ return "Which identity should this launch run as?";
158001
+ default:
158002
+ return reason;
158003
+ }
158004
+ }
158005
+ };
158006
+ }
158007
+ async function runIdentityPicker(params) {
158008
+ if (!params.interactive) {
158009
+ return { kind: "unchanged" };
158010
+ }
158011
+ const nowMs = params.now();
158012
+ const resuming = isResuming(params.parsed.rest);
158013
+ const context = params.decision.pool === void 0 ? identityContext(params, resuming, nowMs) : poolContext(params, params.decision.pool, resuming, nowMs);
158014
+ const reason = decidePicker({
158015
+ interactive: params.interactive,
158016
+ unattended: isUnattendedLaunch(params.parsed.rest),
158017
+ pick: params.parsed.pick,
158018
+ configDirEscapeHatch: params.decision.configDirEscapeHatch,
158019
+ waiting: params.parsed.wait === true,
158020
+ selection: context.selection
158021
+ });
158022
+ if (reason === void 0) {
158023
+ return { kind: "unchanged" };
158024
+ }
158025
+ const request7 = { message: context.message(reason), entries: context.entries, ...context.initial === void 0 ? {} : { initial: context.initial } };
158026
+ const answer = await params.picker.pick(request7);
158027
+ if (answer.kind === "cancelled") {
158028
+ return { kind: "cancelled" };
158029
+ }
158030
+ const chosen = answer.value;
158031
+ if (chosen === (params.decision.pool === void 0 ? params.decision.name : context.poolPick)) {
158032
+ return { kind: "unchanged" };
158033
+ }
158034
+ if (params.decision.pool !== void 0 && poolNameOf(chosen) === void 0) {
158035
+ recordStickyPick(params.usageFs, params.paths.usagePicksFile, params.cwd, chosen, nowMs);
158036
+ }
158037
+ return { kind: "selected", selector: chosen };
158038
+ }
158039
+
158040
+ // src/launchPicker.ts
158041
+ init_realPorts();
158042
+ async function pickLaunchIdentity(params) {
158043
+ return await runIdentityPicker({
158044
+ parsed: params.parsed,
158045
+ decision: params.decision,
158046
+ interactive: process.stdin.isTTY && process.stdout.isTTY,
158047
+ paths: params.paths,
158048
+ fs: realFsPort,
158049
+ usageFs: params.farm.runtime.fs,
158050
+ pools: params.farm.pools,
158051
+ cwd: params.farm.runtime.cwd,
158052
+ now: params.farm.runtime.now,
158053
+ identityNames: () => listIdentities(params.paths).flatMap((listing) => "problem" in listing ? [] : [listing.name]),
158054
+ picker: promptsIdentityPicker(realPromptsPort)
158055
+ });
158056
+ }
158057
+
158058
+ // src/runClaude.ts
157823
158059
  init_launchWiring();
157824
158060
  init_paths();
157825
158061
 
@@ -158589,6 +158825,7 @@ function otherLaunchFlags(parsed) {
158589
158825
  ...parsed.skipPermissions === void 0 ? [] : ["--[no-]skip-permissions"],
158590
158826
  ...parsed.remoteControl === void 0 ? [] : ["--[no-]remote-control"],
158591
158827
  ...parsed.wait === void 0 ? [] : ["--[no-]wait"],
158828
+ ...parsed.pick === void 0 ? [] : ["--[no-]pick"],
158592
158829
  ...parsed.categoryFlags.length === 0 ? [] : ["--category"],
158593
158830
  ...parsed.shareFlags.length === 0 ? [] : ["--share"],
158594
158831
  ...parsed.hideFlags.length === 0 ? [] : ["--hide"]
@@ -158654,13 +158891,19 @@ async function runClaude(argvOverride) {
158654
158891
  }
158655
158892
  }
158656
158893
  }
158657
- await refreshPools({
158658
- paths,
158659
- cwd: process.cwd(),
158660
- poolNames: identityDecision.pool === void 0 ? [] : [identityDecision.pool],
158661
- spawnDaemon: spawnDetachedSupervisor,
158662
- log: realLogPort.warn
158663
- });
158894
+ const refreshUsage = async (poolName2) => {
158895
+ await refreshPools({ paths, cwd: process.cwd(), poolNames: poolName2 === void 0 ? [] : [poolName2], spawnDaemon: spawnDetachedSupervisor, log: realLogPort.warn });
158896
+ };
158897
+ await refreshUsage(identityDecision.pool);
158898
+ const picked = await pickLaunchIdentity({ paths, farm, parsed: nativeArgv, decision: identityDecision });
158899
+ if (picked.kind === "cancelled") {
158900
+ throw new IdentityPickerCancelledError();
158901
+ }
158902
+ const pickedIdentity = picked.kind === "selected" ? picked.selector : void 0;
158903
+ const launchDecision = pickedIdentity === void 0 ? identityDecision : decideIdentity({ env: procForDecision.env, argv0Identity: pickedIdentity, readActiveIdentityFile: () => void 0 });
158904
+ if (launchDecision.pool !== identityDecision.pool) {
158905
+ await refreshUsage(launchDecision.pool);
158906
+ }
158664
158907
  const prepareParams = {
158665
158908
  ...realPrepareLaunchParams(paths, {
158666
158909
  proc: argvOverride === void 0 ? realProcPort : { ...realProcPort, argv: argvOverride },
@@ -158669,10 +158912,11 @@ async function runClaude(argvOverride) {
158669
158912
  farm,
158670
158913
  allowMissingConfigProfile
158671
158914
  }),
158915
+ ...pickedIdentity === void 0 ? {} : { pickedIdentity },
158672
158916
  // Wired here rather than in realPrepareLaunchParams because the port re-invokes this very binary: correct for the agent-shim command line, wrong for a library host whose own executable is not agent-shim.
158673
158917
  update: realLaunchUpdatePort(paths)
158674
158918
  };
158675
- const poolName = identityDecision.pool;
158919
+ const poolName = launchDecision.pool;
158676
158920
  if (poolName !== void 0 && farm.pools !== void 0 && supervisesLaunch(farm.pools[poolName], nativeArgv.rest)) {
158677
158921
  const code = await runSupervised({
158678
158922
  paths,
package/dist/index.cjs CHANGED
@@ -4764,7 +4764,7 @@ var init_package = __esm({
4764
4764
  "package.json"() {
4765
4765
  package_default = {
4766
4766
  name: "agent-shim",
4767
- version: "11.78.0",
4767
+ version: "11.79.0",
4768
4768
  description: "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
4769
4769
  license: "MIT",
4770
4770
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -10726,7 +10726,8 @@ var init_argv = __esm({
10726
10726
  { flag: "--remote-control", key: "remoteControl" },
10727
10727
  { flag: "--wait", key: "wait" },
10728
10728
  { flag: "--pause", key: "pause" },
10729
- { flag: "--explain", key: "explain" }
10729
+ { flag: "--explain", key: "explain" },
10730
+ { flag: "--pick", key: "pick" }
10730
10731
  ];
10731
10732
  LAUNCHER_FLAG_NAMES = [
10732
10733
  ...VALUED_FLAGS,
@@ -11812,7 +11813,7 @@ function decideLaunch(params, readOnly) {
11812
11813
  const configDirEscapeHatchApplies = env.CLAUDE_CONFIG_DIR !== void 0 && env.CLAUDE_CONFIG_DIR !== "";
11813
11814
  const decidedIdentity = decideIdentity({
11814
11815
  env,
11815
- argv0Identity: parsedArgv.identity,
11816
+ argv0Identity: params.pickedIdentity ?? parsedArgv.identity,
11816
11817
  directoryPinnedIdentity: params.directoryPinnedIdentity,
11817
11818
  readActiveIdentityFile: () => {
11818
11819
  const raw = fs14.readFileUtf8(paths.activeIdentityFile);
package/dist/index.mjs CHANGED
@@ -4740,7 +4740,7 @@ var init_package = __esm({
4740
4740
  "package.json"() {
4741
4741
  package_default = {
4742
4742
  name: "agent-shim",
4743
- version: "11.78.0",
4743
+ version: "11.79.0",
4744
4744
  description: "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
4745
4745
  license: "MIT",
4746
4746
  author: "Joseph Mearman <joseph@mearman.co.uk>",
@@ -10699,7 +10699,8 @@ var init_argv = __esm({
10699
10699
  { flag: "--remote-control", key: "remoteControl" },
10700
10700
  { flag: "--wait", key: "wait" },
10701
10701
  { flag: "--pause", key: "pause" },
10702
- { flag: "--explain", key: "explain" }
10702
+ { flag: "--explain", key: "explain" },
10703
+ { flag: "--pick", key: "pick" }
10703
10704
  ];
10704
10705
  LAUNCHER_FLAG_NAMES = [
10705
10706
  ...VALUED_FLAGS,
@@ -11787,7 +11788,7 @@ function decideLaunch(params, readOnly) {
11787
11788
  const configDirEscapeHatchApplies = env.CLAUDE_CONFIG_DIR !== void 0 && env.CLAUDE_CONFIG_DIR !== "";
11788
11789
  const decidedIdentity = decideIdentity({
11789
11790
  env,
11790
- argv0Identity: parsedArgv.identity,
11791
+ argv0Identity: params.pickedIdentity ?? parsedArgv.identity,
11791
11792
  directoryPinnedIdentity: params.directoryPinnedIdentity,
11792
11793
  readActiveIdentityFile: () => {
11793
11794
  const raw = fs14.readFileUtf8(paths.activeIdentityFile);
@@ -14032,6 +14032,8 @@ interface PrepareLaunchParams {
14032
14032
  readonly log: LogPort;
14033
14033
  /** Discovers the real `claude` binary to spawn. Injected so `runLauncher` never depends on `src/versionDiscovery.ts`'s own filesystem/PATH inputs directly — the caller (`src/cli.ts`) wires the real discovery, tests wire a fake that returns a fixed path. */
14034
14034
  readonly resolveClaudeBinary: ClaudeBinaryResolver;
14035
+ /** The identity (or `pool:<name>`) the person chose at the identity picker, which takes the place of whatever the arguments named: the question was asked because that choice was not settled. */
14036
+ readonly pickedIdentity?: string;
14035
14037
  /** An identity pinned to `$PWD` by a directory rule. Accepted as an already-resolved value — the rules-loading code that produces it lands in Phase 4/5. */
14036
14038
  readonly directoryPinnedIdentity?: string;
14037
14039
  /** A directory rule's `configProfile` selection for `$PWD`. Accepted as an already-resolved value for the same reason. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-shim",
3
- "version": "11.78.0",
3
+ "version": "11.79.0",
4
4
  "description": "A profile manager and launcher for Claude Code that lets one person run multiple logins from one machine while controlling what gets shared between them.",
5
5
  "license": "MIT",
6
6
  "author": "Joseph Mearman <joseph@mearman.co.uk>",