@arjunkhera/atlas 0.4.55 → 0.4.57

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "atlas",
3
- "version": "0.4.55",
3
+ "version": "0.4.57",
4
4
  "description": "Atlas: the delivery lifecycle, its crews and the Atlas tools, for any repository.",
5
5
  "author": {
6
6
  "name": "Arjun Khera"
@@ -6,7 +6,11 @@
6
6
  // The catalog is one folder on the Mac, ~/.atlas/catalog. It holds one entry
7
7
  // that pins an exact npm version, so nothing moves Atlas to another version
8
8
  // without `atlas upgrade`. The installer writes that one file and asks Claude
9
- // Code to add the catalog and install the plugin. It writes no settings file.
9
+ // Code to add the catalog and install the plugin. On a Mac it writes no
10
+ // settings file. With --cloud it also sets one key, env.MCP_TIMEOUT, in the
11
+ // user settings file, so the tools server has time for the refresh at
12
+ // session start (item ade7d96a, decision c71facc9; the owner asked on
13
+ // 7 November 2026 to make it the same for every project).
10
14
  import { execFileSync } from 'node:child_process';
11
15
  import { createHash } from 'node:crypto';
12
16
  import { cpSync, existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from 'node:fs';
@@ -32,6 +36,35 @@ export function repoOf(packageRoot) {
32
36
  export const catalogDir = (env) => join(env.HOME, '.atlas', 'catalog');
33
37
  export const catalogFile = (env) => join(catalogDir(env), '.claude-plugin', 'marketplace.json');
34
38
 
39
+ // The start time that a cloud setup gives each tools server, in ms. Claude
40
+ // Code reads MCP_TIMEOUT from the env block of its user settings file too
41
+ // (probe of 7 November 2026: a server that starts in 40 s failed with no
42
+ // value and served its tool with this one).
43
+ export const CLOUD_MCP_TIMEOUT = '90000';
44
+ export const userSettingsFile = (env) => join(env.CLAUDE_CONFIG_DIR || join(env.HOME, '.claude'), 'settings.json');
45
+
46
+ // What a cloud install does to the user settings file. It adds the key only
47
+ // when no value is set, here or in the environment, and it never rewrites a
48
+ // file it cannot read.
49
+ export function cloudTimeout(env) {
50
+ const file = userSettingsFile(env);
51
+ if (env.MCP_TIMEOUT) return { file, state: 'environment' };
52
+ let settings = {};
53
+ if (existsSync(file)) {
54
+ try { settings = JSON.parse(readFileSync(file, 'utf8')); } catch { return { file, state: 'unreadable' }; }
55
+ if (!settings || typeof settings !== 'object' || Array.isArray(settings)) return { file, state: 'unreadable' };
56
+ }
57
+ if (settings.env && (typeof settings.env !== 'object' || Array.isArray(settings.env))) return { file, state: 'unreadable' };
58
+ if (settings.env?.MCP_TIMEOUT !== undefined) return { file, state: 'set' };
59
+ return { file, state: 'add', text: `${JSON.stringify({ ...settings, env: { ...(settings.env ?? {}), MCP_TIMEOUT: CLOUD_MCP_TIMEOUT } }, null, 2)}\n` };
60
+ }
61
+ const TIMEOUT_NOTE = {
62
+ add: 'adds env.MCP_TIMEOUT = "90000", the start time for the refresh',
63
+ set: 'unchanged: it already sets env.MCP_TIMEOUT',
64
+ environment: 'unchanged: the environment sets MCP_TIMEOUT',
65
+ unreadable: 'unchanged: the file is not a settings object, so Atlas does not touch it',
66
+ };
67
+
35
68
  // The one file the installer writes. `local` puts a copy of the package inside
36
69
  // the catalog instead of naming npm; CI and a development Mac use it.
37
70
  export function catalogFor({ name, version, local = false }) {
@@ -105,6 +138,7 @@ export async function install({ packageRoot, options = {}, line = console.log, e
105
138
  const file = catalogFile(env);
106
139
  const before = existsSync(file) ? readFileSync(file, 'utf8') : null;
107
140
  const after = `${JSON.stringify(catalog, null, 2)}\n`;
141
+ const timeout = options.cloud ? cloudTimeout(env) : null;
108
142
 
109
143
  line(`Install Atlas ${version} for every folder on this Mac.`);
110
144
  line('');
@@ -114,6 +148,7 @@ export async function install({ packageRoot, options = {}, line = console.log, e
114
148
  `write ${file} (${before === null ? 'new file' : before === after ? 'unchanged' : 'changed'}; it pins ${local ? 'a local copy' : `exactly ${version}`})`,
115
149
  `claude plugin marketplace add ${catalogDir(env)}`,
116
150
  `claude plugin install ${PLUGIN_ID} --scope user`,
151
+ timeout ? `write ${timeout.file} (${TIMEOUT_NOTE[timeout.state]})` : null,
117
152
  'atlas doctor',
118
153
  ].filter(Boolean);
119
154
  steps.forEach((step, index) => line(` ${index + 1}. ${step}`));
@@ -121,7 +156,7 @@ export async function install({ packageRoot, options = {}, line = console.log, e
121
156
  line('Claude Code itself then writes two keys into ~/.claude/settings.json, and nothing else:');
122
157
  line(` extraKnownMarketplaces.${CATALOG_NAME} (the catalog folder)`);
123
158
  line(` enabledPlugins["${PLUGIN_ID}"] = true`);
124
- line('This command writes no settings file of its own.');
159
+ line(timeout ? 'With --cloud, this command writes only the MCP_TIMEOUT key named above into a settings file.' : 'This command writes no settings file of its own.');
125
160
  if (before !== null && before !== after) { line(''); line('The catalog file changes from:'); line(before); line('to:'); line(after); }
126
161
  if (!options.yes && !(await ask('Go ahead?'))) { line('Nothing was changed.'); return 1; }
127
162
 
@@ -140,6 +175,13 @@ export async function install({ packageRoot, options = {}, line = console.log, e
140
175
  exec('claude', hasCatalog ? ['plugin', 'marketplace', 'update', CATALOG_NAME] : ['plugin', 'marketplace', 'add', catalogDir(env)]);
141
176
  const installArgs = ['plugin', 'install', PLUGIN_ID, '--scope', 'user'];
142
177
  exec('claude', installArgs);
178
+ // Read the file again now: `claude plugin install` has just written its
179
+ // own keys into it, and a copy read before that would drop them (0.4.56).
180
+ const now = timeout ? cloudTimeout(env) : null;
181
+ if (now?.state === 'add') {
182
+ mkdirSync(join(now.file, '..'), { recursive: true });
183
+ writeFileSync(now.file, now.text);
184
+ }
143
185
  line('');
144
186
  // A cloud setup script runs before any session: the key comes from the
145
187
  // environment variable, and no tools server has started yet (item 92cfbba3).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arjunkhera/atlas",
3
- "version": "0.4.55",
3
+ "version": "0.4.57",
4
4
  "description": "Atlas: the delivery lifecycle, its crews and the Atlas tools, as a Claude Code plugin for any repository.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",