claude-dev-env 8.54.9 → 8.56.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/bin/install.agents-home.test.mjs +2 -0
- package/bin/install.codex-rules.test.mjs +4 -0
- package/bin/install.cursor-rules.test.mjs +1 -0
- package/bin/install.mjs +19 -20
- package/bin/install.profile-settings.test.mjs +77 -0
- package/bin/install.profiles.test.mjs +2 -2
- package/bin/install.prune.test.mjs +2 -0
- package/bin/install.question-presentation.test.mjs +2 -0
- package/bin/install.settings-defaults.test.mjs +8 -3
- package/bin/install.shared-settings.test.mjs +1 -0
- package/bin/install.test.mjs +7 -3
- package/bin/install.transaction.test.mjs +14 -0
- package/bin/install.uninstall-transaction.test.mjs +4 -0
- package/bin/install.update-keeps-hooks.test.mjs +2 -0
- package/bin/merge_profile_settings.mjs +372 -0
- package/bin/merge_profile_settings.test.mjs +208 -0
- package/docs/templates/artifact-page/README.md +25 -0
- package/docs/templates/artifact-page/template.html +465 -0
- package/hooks/features/session-context.md +4 -1
- package/hooks/hooks.json +10 -0
- package/hooks/hooks_constants/artifact_template_pointer_constants.py +27 -0
- package/hooks/hooks_constants/test_artifact_template_pointer_constants.py +8 -0
- package/hooks/session/artifact_template_pointer.py +102 -0
- package/hooks/session/test_artifact_template_pointer.py +65 -0
- package/installable-surfaces.manifest.json +2 -1
- package/package.json +3 -2
- package/profile-settings/config/__init__.py +1 -0
- package/profile-settings/config/session_title_gate_constants.py +15 -0
- package/profile-settings/session_title_status_gate.py +77 -0
- package/profile-settings/test_session_title_status_gate.py +101 -0
- package/scripts/dev_env_scripts_constants/private_term_constants.py +8 -4
- package/scripts/private_term_scan.py +15 -3
- package/scripts/tests/test_private_term_scan.py +81 -8
|
@@ -50,6 +50,8 @@ const REVIEW_PROCEDURE_FILE_NAME = 'high.md';
|
|
|
50
50
|
function runInstaller(homeDirectory, extraArguments, environmentOverrides = {}) {
|
|
51
51
|
const installerEnvironment = {
|
|
52
52
|
...process.env,
|
|
53
|
+
CLAUDE_CONFIG_DIR: undefined,
|
|
54
|
+
LLM_SETTINGS_PROFILES_ROOT: undefined,
|
|
53
55
|
CDE_INSTALL_PSTACK: '0',
|
|
54
56
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
55
57
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
@@ -56,6 +56,8 @@ function runInstaller(homeDirectory, extraArguments) {
|
|
|
56
56
|
encoding: 'utf8',
|
|
57
57
|
env: {
|
|
58
58
|
...process.env,
|
|
59
|
+
CLAUDE_CONFIG_DIR: undefined,
|
|
60
|
+
LLM_SETTINGS_PROFILES_ROOT: undefined,
|
|
59
61
|
CDE_INSTALL_PSTACK: '0',
|
|
60
62
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
61
63
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
@@ -86,6 +88,8 @@ function scanTextWithProductionPiiScanner(scannedText) {
|
|
|
86
88
|
encoding: 'utf8',
|
|
87
89
|
env: {
|
|
88
90
|
...process.env,
|
|
91
|
+
CLAUDE_CONFIG_DIR: undefined,
|
|
92
|
+
LLM_SETTINGS_PROFILES_ROOT: undefined,
|
|
89
93
|
CDE_INSTALL_PSTACK: '0',
|
|
90
94
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
91
95
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
@@ -31,6 +31,7 @@ function runInstaller(homeDirectory, extraArguments, environmentOverrides = {})
|
|
|
31
31
|
encoding: 'utf8',
|
|
32
32
|
env: {
|
|
33
33
|
...process.env,
|
|
34
|
+
LLM_SETTINGS_PROFILES_ROOT: undefined,
|
|
34
35
|
CDE_INSTALL_PSTACK: '0',
|
|
35
36
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
36
37
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
package/bin/install.mjs
CHANGED
|
@@ -29,6 +29,11 @@ import {
|
|
|
29
29
|
mergeMissingSettingsDefaults,
|
|
30
30
|
settingsDefaultsFromPackageSettings,
|
|
31
31
|
} from './merge_settings_defaults.mjs';
|
|
32
|
+
import {
|
|
33
|
+
describeProfileSettingsOutcome,
|
|
34
|
+
hostConfigurationIndent,
|
|
35
|
+
mergeProfileSettings,
|
|
36
|
+
} from './merge_profile_settings.mjs';
|
|
32
37
|
import {
|
|
33
38
|
SKIPPED_SOURCE_ENTRY_NAMES,
|
|
34
39
|
SKIPPED_SOURCE_FILE_EXTENSIONS,
|
|
@@ -1548,15 +1553,19 @@ function startEventFromHookGroupList(settings, eventType) {
|
|
|
1548
1553
|
* @param {object} settings The parsed settings.json object (mutated in place).
|
|
1549
1554
|
* @param {{hooks: object}} hooksConfig Parsed hooks.json.
|
|
1550
1555
|
* @param {string} pluginRootDir Directory ${CLAUDE_PLUGIN_ROOT} resolves to
|
|
1551
|
-
* (the installer's `~/.claude`
|
|
1556
|
+
* (the installer's managed root, `~/.claude` or a profile root).
|
|
1552
1557
|
* @param {string} pythonCommand Interpreter command that replaces python3.
|
|
1553
1558
|
* @param {string|null} [sharedSettingsRealPath] Resolved path of the settings
|
|
1554
1559
|
* file being merged. Hooks of every root whose settings.json resolves to it
|
|
1555
1560
|
* count as managed, so roots sharing one file keep one entry per script.
|
|
1561
|
+
* @param {string} [homeDirectory] The home directory `~/`, `$HOME`, and
|
|
1562
|
+
* `${HOME}` expand to. It is the user's home whatever root installs, so a
|
|
1563
|
+
* profile root under `~/.claude-profiles` expands `~/` the same way the
|
|
1564
|
+
* profile settings merge does.
|
|
1556
1565
|
* @returns {number} Count of matcher groups merged.
|
|
1557
1566
|
*/
|
|
1558
1567
|
export function mergeHooksIntoSettings(
|
|
1559
|
-
settings, hooksConfig, pluginRootDir, pythonCommand, sharedSettingsRealPath = null,
|
|
1568
|
+
settings, hooksConfig, pluginRootDir, pythonCommand, sharedSettingsRealPath = null, homeDirectory = homedir(),
|
|
1560
1569
|
) {
|
|
1561
1570
|
const managedHookRelativePaths = managedHookScriptRelativePaths(hooksConfig);
|
|
1562
1571
|
const pluginRootForward = pluginRootDir.replace(/\\/g, '/');
|
|
@@ -1604,7 +1613,7 @@ export function mergeHooksIntoSettings(
|
|
|
1604
1613
|
groupCount++;
|
|
1605
1614
|
}
|
|
1606
1615
|
}
|
|
1607
|
-
expandHomeDirectoryTokensInSettings(settings,
|
|
1616
|
+
expandHomeDirectoryTokensInSettings(settings, homeDirectory);
|
|
1608
1617
|
return groupCount;
|
|
1609
1618
|
}
|
|
1610
1619
|
|
|
@@ -1883,23 +1892,6 @@ function stripRetiredHookEntries(settings, retiredHookRelativePaths, ownership)
|
|
|
1883
1892
|
return removedCount;
|
|
1884
1893
|
}
|
|
1885
1894
|
|
|
1886
|
-
const DEFAULT_HOST_CONFIGURATION_INDENT = ' ';
|
|
1887
|
-
|
|
1888
|
-
/**
|
|
1889
|
-
* Read the indent the host configuration file already uses.
|
|
1890
|
-
*
|
|
1891
|
-
* ~/.claude/settings.json uses four spaces and ~/.codex/hooks.json uses two.
|
|
1892
|
-
* Forcing four spaces would rewrite every line of one of those files. The first
|
|
1893
|
-
* indented line supplies the indent, tabs included.
|
|
1894
|
-
*
|
|
1895
|
-
* @param {string} settingsText The host configuration file as it stands on disk.
|
|
1896
|
-
* @returns {string} The indent one nesting level uses.
|
|
1897
|
-
*/
|
|
1898
|
-
function hostConfigurationIndent(settingsText) {
|
|
1899
|
-
const firstIndentedLine = /\n([ \t]+)\S/.exec(settingsText);
|
|
1900
|
-
return firstIndentedLine ? firstIndentedLine[1] : DEFAULT_HOST_CONFIGURATION_INDENT;
|
|
1901
|
-
}
|
|
1902
|
-
|
|
1903
1895
|
/**
|
|
1904
1896
|
* Remove every entry of one host hook configuration file that runs a retired
|
|
1905
1897
|
* managed hook script, writing the file only when an entry left it.
|
|
@@ -3027,6 +3019,13 @@ function executeInstallPlanMutations(plan, transactionHelpers) {
|
|
|
3027
3019
|
if (settingsDefaultsMerge.addedKeys.length > 0) {
|
|
3028
3020
|
console.log(` Settings: added ${settingsDefaultsMerge.addedKeys.join(', ')}`);
|
|
3029
3021
|
}
|
|
3022
|
+
const mergeOutcome = mergeProfileSettings(
|
|
3023
|
+
[join(CLAUDE_HOME, SETTINGS_FILE_NAME)],
|
|
3024
|
+
{ dryRun: false, homeDirectory: homedir() },
|
|
3025
|
+
);
|
|
3026
|
+
for (const eachLine of describeProfileSettingsOutcome(mergeOutcome, false)) {
|
|
3027
|
+
console.log(` Profile settings: ${eachLine}`);
|
|
3028
|
+
}
|
|
3030
3029
|
|
|
3031
3030
|
const agentsHubSource = join(PACKAGE_ROOT, 'AGENTS.md');
|
|
3032
3031
|
if (existsSync(agentsHubSource)) {
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Installing twice into a profile root under ~/.claude-profiles leaves exactly
|
|
3
|
+
* one session-title gate Stop hook, that hook runs the gate under ~/.claude, and
|
|
4
|
+
* the second install leaves settings.json byte for byte.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { test } from 'node:test';
|
|
8
|
+
import { strict as assert } from 'node:assert';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { existsSync, mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
11
|
+
import { tmpdir } from 'node:os';
|
|
12
|
+
import { fileURLToPath } from 'node:url';
|
|
13
|
+
import { spawnSync } from 'node:child_process';
|
|
14
|
+
|
|
15
|
+
import { ALL_SESSION_TITLE_GATE_RELATIVE_PATHS, SESSION_TITLE_GATE_FILE_NAME } from './merge_profile_settings.mjs';
|
|
16
|
+
|
|
17
|
+
const INSTALLER_PATH = fileURLToPath(new URL('./install.mjs', import.meta.url));
|
|
18
|
+
|
|
19
|
+
function installEnvironment(homeDirectory) {
|
|
20
|
+
return {
|
|
21
|
+
...process.env,
|
|
22
|
+
CLAUDE_CONFIG_DIR: undefined,
|
|
23
|
+
LLM_SETTINGS_PROFILES_ROOT: undefined,
|
|
24
|
+
HOME: homeDirectory,
|
|
25
|
+
USERPROFILE: homeDirectory,
|
|
26
|
+
GIT_CONFIG_GLOBAL: join(homeDirectory, '.gitconfig'),
|
|
27
|
+
CODEX_HOME: join(homeDirectory, '.codex'),
|
|
28
|
+
CDE_INSTALL_PSTACK: '0',
|
|
29
|
+
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function runCoreInstall(homeDirectory, profileRoot) {
|
|
34
|
+
const installRun = spawnSync(
|
|
35
|
+
process.execPath,
|
|
36
|
+
[INSTALLER_PATH, '--only', 'core', '--target', profileRoot],
|
|
37
|
+
{ encoding: 'utf8', env: installEnvironment(homeDirectory) },
|
|
38
|
+
);
|
|
39
|
+
assert.equal(installRun.status, 0, installRun.stdout + installRun.stderr);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function stopHookCommands(settingsPath) {
|
|
43
|
+
const settings = JSON.parse(readFileSync(settingsPath, 'utf8'));
|
|
44
|
+
return (settings.hooks?.Stop ?? []).flatMap(
|
|
45
|
+
(eachGroup) => (eachGroup.hooks ?? []).map((eachHook) => eachHook.command.replace(/\\/g, '/')),
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
test('two installs into a profile root keep one gate Stop hook that runs the gate under ~/.claude', () => {
|
|
50
|
+
const homeDirectory = mkdtempSync(join(tmpdir(), 'cdev-profile-settings-'));
|
|
51
|
+
try {
|
|
52
|
+
writeFileSync(join(homeDirectory, '.gitconfig'), '');
|
|
53
|
+
const profileRoot = join(homeDirectory, '.claude-profiles', 'work');
|
|
54
|
+
mkdirSync(profileRoot, { recursive: true });
|
|
55
|
+
const settingsPath = join(profileRoot, 'settings.json');
|
|
56
|
+
const forwardSlashedHome = homeDirectory.replace(/\\/g, '/');
|
|
57
|
+
const expectedGateCommand = `python3 ${forwardSlashedHome}/.claude/${SESSION_TITLE_GATE_FILE_NAME}`;
|
|
58
|
+
|
|
59
|
+
runCoreInstall(homeDirectory, profileRoot);
|
|
60
|
+
const settingsBytesAfterFirstInstall = readFileSync(settingsPath);
|
|
61
|
+
runCoreInstall(homeDirectory, profileRoot);
|
|
62
|
+
|
|
63
|
+
assert.deepEqual(readFileSync(settingsPath), settingsBytesAfterFirstInstall, 'second install leaves settings.json byte for byte');
|
|
64
|
+
|
|
65
|
+
const allGateCommands = stopHookCommands(settingsPath)
|
|
66
|
+
.filter((eachCommand) => eachCommand.includes(SESSION_TITLE_GATE_FILE_NAME));
|
|
67
|
+
assert.deepEqual(allGateCommands, [expectedGateCommand]);
|
|
68
|
+
for (const eachRelativePath of ALL_SESSION_TITLE_GATE_RELATIVE_PATHS) {
|
|
69
|
+
assert.ok(
|
|
70
|
+
existsSync(join(homeDirectory, '.claude', eachRelativePath)),
|
|
71
|
+
`${eachRelativePath} is installed under ~/.claude`,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
} finally {
|
|
75
|
+
rmSync(homeDirectory, { recursive: true, force: true });
|
|
76
|
+
}
|
|
77
|
+
});
|
|
@@ -235,7 +235,7 @@ test('repeated and selected multi-profile dry runs write one ownership manifest
|
|
|
235
235
|
test('install.mjs --help documents profile target selection', () => {
|
|
236
236
|
const result = spawnSync(process.execPath, [INSTALL_MODULE_PATH, '--help'], {
|
|
237
237
|
encoding: 'utf8',
|
|
238
|
-
env: process.env,
|
|
238
|
+
env: { ...process.env, CLAUDE_CONFIG_DIR: undefined, LLM_SETTINGS_PROFILES_ROOT: undefined },
|
|
239
239
|
});
|
|
240
240
|
assert.equal(result.status, 0, result.stderr);
|
|
241
241
|
assert.match(result.stdout, /--profile/);
|
|
@@ -247,7 +247,7 @@ test('install.mjs --help documents profile target selection', () => {
|
|
|
247
247
|
test('install.mjs --help states that a positional path argument carries no meaning', () => {
|
|
248
248
|
const result = spawnSync(process.execPath, [INSTALL_MODULE_PATH, '--help'], {
|
|
249
249
|
encoding: 'utf8',
|
|
250
|
-
env: process.env,
|
|
250
|
+
env: { ...process.env, CLAUDE_CONFIG_DIR: undefined, LLM_SETTINGS_PROFILES_ROOT: undefined },
|
|
251
251
|
});
|
|
252
252
|
assert.equal(result.status, 0, result.stderr);
|
|
253
253
|
assert.match(result.stdout, /reads only flags/i);
|
|
@@ -259,6 +259,8 @@ function runInstaller(homeDirectory, extraArguments) {
|
|
|
259
259
|
function resolveInstallerInvocation(homeDirectory) {
|
|
260
260
|
const childEnvironment = {
|
|
261
261
|
...process.env,
|
|
262
|
+
CLAUDE_CONFIG_DIR: undefined,
|
|
263
|
+
LLM_SETTINGS_PROFILES_ROOT: undefined,
|
|
262
264
|
CDE_INSTALL_PSTACK: '0',
|
|
263
265
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
264
266
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
@@ -22,6 +22,8 @@ function installInScratchHome(homeDirectory, argumentsList = [], extraEnvironmen
|
|
|
22
22
|
encoding: 'utf8',
|
|
23
23
|
env: {
|
|
24
24
|
...process.env,
|
|
25
|
+
CLAUDE_CONFIG_DIR: undefined,
|
|
26
|
+
LLM_SETTINGS_PROFILES_ROOT: undefined,
|
|
25
27
|
CDE_INSTALL_PSTACK: '0',
|
|
26
28
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
27
29
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
mergeMissingSettingsDefaults,
|
|
26
26
|
settingsDefaultsFromPackageSettings,
|
|
27
27
|
} from './merge_settings_defaults.mjs';
|
|
28
|
+
import { DECLARED_PROFILE_SETTINGS } from './merge_profile_settings.mjs';
|
|
28
29
|
|
|
29
30
|
const PACKAGE_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
|
|
30
31
|
const PACKAGE_SETTINGS_PATH = join(PACKAGE_ROOT, 'settings.json');
|
|
@@ -32,6 +33,8 @@ const INSTALL_ENTRY = join(PACKAGE_ROOT, 'bin', 'install.mjs');
|
|
|
32
33
|
|
|
33
34
|
const EXPECTED_DENY_ENTRIES = [];
|
|
34
35
|
const EXPECTED_ALLOW_ENTRIES = ['WebFetch(domain:docs.github.com)'];
|
|
36
|
+
const PROFILE_ALLOW_ENTRIES = DECLARED_PROFILE_SETTINGS
|
|
37
|
+
.find((eachEntry) => eachEntry.keyPath.join('.') === 'permissions.allow').items;
|
|
35
38
|
const SAMPLE_MANAGED_DENY_ENTRIES = ['Edit($HOME/.claude/managed-test/**)'];
|
|
36
39
|
const SAMPLE_MANAGED_PERMISSIONS = { allow: [], deny: SAMPLE_MANAGED_DENY_ENTRIES };
|
|
37
40
|
const SAMPLE_MANAGED_ALLOW_PERMISSIONS = { allow: ['WebFetch(domain:example.com)'], deny: [] };
|
|
@@ -56,6 +59,8 @@ function runInstallerInSandbox(sandboxHome, installerArguments = []) {
|
|
|
56
59
|
encoding: 'utf8',
|
|
57
60
|
env: {
|
|
58
61
|
...process.env,
|
|
62
|
+
CLAUDE_CONFIG_DIR: undefined,
|
|
63
|
+
LLM_SETTINGS_PROFILES_ROOT: undefined,
|
|
59
64
|
CDE_INSTALL_PSTACK: '0',
|
|
60
65
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
61
66
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
@@ -171,7 +176,7 @@ test('sandbox install keeps default managed denies empty on repeat', () => {
|
|
|
171
176
|
const firstSettings = JSON.parse(readFileSync(settingsPath, 'utf8'));
|
|
172
177
|
const firstDeny = firstSettings.permissions?.deny ?? [];
|
|
173
178
|
assert.deepEqual(firstDeny, EXPECTED_DENY_ENTRIES);
|
|
174
|
-
assert.deepEqual(firstSettings.permissions?.allow, EXPECTED_ALLOW_ENTRIES);
|
|
179
|
+
assert.deepEqual(firstSettings.permissions?.allow, [...EXPECTED_ALLOW_ENTRIES, ...PROFILE_ALLOW_ENTRIES]);
|
|
175
180
|
|
|
176
181
|
const manifestPath = join(sandboxHome, '.claude', '.claude-dev-env-manifest.json');
|
|
177
182
|
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
@@ -183,7 +188,7 @@ test('sandbox install keeps default managed denies empty on repeat', () => {
|
|
|
183
188
|
const secondSettings = JSON.parse(readFileSync(settingsPath, 'utf8'));
|
|
184
189
|
const secondDeny = secondSettings.permissions?.deny ?? [];
|
|
185
190
|
assert.deepEqual(secondDeny, EXPECTED_DENY_ENTRIES);
|
|
186
|
-
assert.deepEqual(secondSettings.permissions?.allow, EXPECTED_ALLOW_ENTRIES);
|
|
191
|
+
assert.deepEqual(secondSettings.permissions?.allow, [...EXPECTED_ALLOW_ENTRIES, ...PROFILE_ALLOW_ENTRIES]);
|
|
187
192
|
} finally {
|
|
188
193
|
rmSync(sandboxHome, { recursive: true, force: true });
|
|
189
194
|
}
|
|
@@ -214,7 +219,7 @@ test('a normal upgrade retires manifest-owned denies and preserves user entries'
|
|
|
214
219
|
|
|
215
220
|
const upgradedSettings = JSON.parse(readFileSync(settingsPath, 'utf8'));
|
|
216
221
|
assert.deepEqual(upgradedSettings.permissions?.deny, [USER_OWNED_DENY_ENTRY]);
|
|
217
|
-
assert.deepEqual(upgradedSettings.permissions?.allow, ['Bash(git status)', ...EXPECTED_ALLOW_ENTRIES]);
|
|
222
|
+
assert.deepEqual(upgradedSettings.permissions?.allow, ['Bash(git status)', ...EXPECTED_ALLOW_ENTRIES, ...PROFILE_ALLOW_ENTRIES]);
|
|
218
223
|
assert.deepEqual(upgradedSettings.permissions?.ask, ['Edit(./**)']);
|
|
219
224
|
|
|
220
225
|
const upgradedManifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
@@ -25,6 +25,7 @@ const PACKAGE_HOOKS_JSON_PATH = fileURLToPath(new URL('../hooks/hooks.json', imp
|
|
|
25
25
|
function installEnvironment(homeDirectory) {
|
|
26
26
|
return {
|
|
27
27
|
...process.env,
|
|
28
|
+
LLM_SETTINGS_PROFILES_ROOT: undefined,
|
|
28
29
|
HOME: homeDirectory,
|
|
29
30
|
USERPROFILE: homeDirectory,
|
|
30
31
|
CLAUDE_CONFIG_DIR: '',
|
package/bin/install.test.mjs
CHANGED
|
@@ -406,7 +406,9 @@ test('mergeHooksIntoSettings expands residual $HOME in preserved user hooks', ()
|
|
|
406
406
|
],
|
|
407
407
|
},
|
|
408
408
|
};
|
|
409
|
-
mergeHooksIntoSettings(
|
|
409
|
+
mergeHooksIntoSettings(
|
|
410
|
+
settings, hooksConfig, 'C:/Users/x/.claude', 'C:/Python313/python.exe', null, 'C:/Users/x',
|
|
411
|
+
);
|
|
410
412
|
const allCommands = settings.hooks.SessionStart[0].hooks.map(eachHook => eachHook.command);
|
|
411
413
|
assert.ok(
|
|
412
414
|
allCommands.includes(
|
|
@@ -2980,7 +2982,7 @@ test('the help output states that the installer reads only flags', () => {
|
|
|
2980
2982
|
const helpRun = spawnSync(
|
|
2981
2983
|
process.execPath,
|
|
2982
2984
|
[fileURLToPath(new URL('./install.mjs', import.meta.url)), '--help'],
|
|
2983
|
-
{ encoding: 'utf8', env: process.env },
|
|
2985
|
+
{ encoding: 'utf8', env: { ...process.env, CLAUDE_CONFIG_DIR: undefined, LLM_SETTINGS_PROFILES_ROOT: undefined } },
|
|
2984
2986
|
);
|
|
2985
2987
|
|
|
2986
2988
|
assert.equal(helpRun.status, 0, helpRun.stderr);
|
|
@@ -3024,6 +3026,7 @@ test('a failed update preserves an existing skills lookup pointer', () => {
|
|
|
3024
3026
|
writeFileSync(join(homeDirectory, '.gitconfig'), '');
|
|
3025
3027
|
const environment = {
|
|
3026
3028
|
...process.env,
|
|
3029
|
+
LLM_SETTINGS_PROFILES_ROOT: undefined,
|
|
3027
3030
|
HOME: homeDirectory,
|
|
3028
3031
|
USERPROFILE: homeDirectory,
|
|
3029
3032
|
CLAUDE_CONFIG_DIR: '',
|
|
@@ -3075,6 +3078,7 @@ function runPstackInstaller(homeDirectory, extraArguments, environmentOverrides
|
|
|
3075
3078
|
encoding: 'utf8',
|
|
3076
3079
|
env: {
|
|
3077
3080
|
...process.env,
|
|
3081
|
+
LLM_SETTINGS_PROFILES_ROOT: undefined,
|
|
3078
3082
|
HOME: homeDirectory,
|
|
3079
3083
|
USERPROFILE: homeDirectory,
|
|
3080
3084
|
CODEX_HOME: join(homeDirectory, '.codex'),
|
|
@@ -3390,7 +3394,7 @@ test('a failing usage-wrapup command is reported and the install still succeeds'
|
|
|
3390
3394
|
test('the help output names the usage-wrapup opt-out beside the pstack one', () => {
|
|
3391
3395
|
const helpRun = spawnSync(process.execPath, [PSTACK_TEST_INSTALLER_PATH, '--help'], {
|
|
3392
3396
|
encoding: 'utf8',
|
|
3393
|
-
env: process.env,
|
|
3397
|
+
env: { ...process.env, CLAUDE_CONFIG_DIR: undefined, LLM_SETTINGS_PROFILES_ROOT: undefined },
|
|
3394
3398
|
});
|
|
3395
3399
|
|
|
3396
3400
|
assert.equal(helpRun.status, 0, helpRun.stderr);
|
|
@@ -85,6 +85,8 @@ test('capture and restore recover settings, manifest, files, and hooksPath', ()
|
|
|
85
85
|
mkdirSync(priorHooksDirectory, { recursive: true });
|
|
86
86
|
const env = {
|
|
87
87
|
...process.env,
|
|
88
|
+
CLAUDE_CONFIG_DIR: undefined,
|
|
89
|
+
LLM_SETTINGS_PROFILES_ROOT: undefined,
|
|
88
90
|
CDE_INSTALL_PSTACK: '0',
|
|
89
91
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
90
92
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
@@ -148,6 +150,8 @@ test('capture and restore recover an additional host settings file', () => {
|
|
|
148
150
|
const io = {
|
|
149
151
|
env: {
|
|
150
152
|
...process.env,
|
|
153
|
+
CLAUDE_CONFIG_DIR: undefined,
|
|
154
|
+
LLM_SETTINGS_PROFILES_ROOT: undefined,
|
|
151
155
|
CDE_INSTALL_PSTACK: '0',
|
|
152
156
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
153
157
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
@@ -184,6 +188,8 @@ test('runWithInstallTransaction restores prior state on injected fault', () => {
|
|
|
184
188
|
writeFileSync(gitConfigPath, '');
|
|
185
189
|
const env = {
|
|
186
190
|
...process.env,
|
|
191
|
+
CLAUDE_CONFIG_DIR: undefined,
|
|
192
|
+
LLM_SETTINGS_PROFILES_ROOT: undefined,
|
|
187
193
|
CDE_INSTALL_PSTACK: '0',
|
|
188
194
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
189
195
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
@@ -239,6 +245,8 @@ test('runWithInstallTransaction commits and discards journal on success', () =>
|
|
|
239
245
|
const io = {
|
|
240
246
|
env: {
|
|
241
247
|
...process.env,
|
|
248
|
+
CLAUDE_CONFIG_DIR: undefined,
|
|
249
|
+
LLM_SETTINGS_PROFILES_ROOT: undefined,
|
|
242
250
|
CDE_INSTALL_PSTACK: '0',
|
|
243
251
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
244
252
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
@@ -283,6 +291,8 @@ test('runWithInstallTransaction commits and discards journal on success', () =>
|
|
|
283
291
|
function runInstaller(homeDirectory, extraArguments, options = {}) {
|
|
284
292
|
const childEnvironment = {
|
|
285
293
|
...process.env,
|
|
294
|
+
CLAUDE_CONFIG_DIR: undefined,
|
|
295
|
+
LLM_SETTINGS_PROFILES_ROOT: undefined,
|
|
286
296
|
CDE_INSTALL_PSTACK: '0',
|
|
287
297
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
288
298
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
@@ -463,6 +473,8 @@ test('installer fault after_git_config restores prior core.hooksPath', () => {
|
|
|
463
473
|
writeGlobalCoreHooksPath(priorHooksPath, {
|
|
464
474
|
env: {
|
|
465
475
|
...process.env,
|
|
476
|
+
CLAUDE_CONFIG_DIR: undefined,
|
|
477
|
+
LLM_SETTINGS_PROFILES_ROOT: undefined,
|
|
466
478
|
CDE_INSTALL_PSTACK: '0',
|
|
467
479
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
468
480
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
@@ -481,6 +493,8 @@ test('installer fault after_git_config restores prior core.hooksPath', () => {
|
|
|
481
493
|
const restored = readGlobalCoreHooksPath({
|
|
482
494
|
env: {
|
|
483
495
|
...process.env,
|
|
496
|
+
CLAUDE_CONFIG_DIR: undefined,
|
|
497
|
+
LLM_SETTINGS_PROFILES_ROOT: undefined,
|
|
484
498
|
CDE_INSTALL_PSTACK: '0',
|
|
485
499
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
486
500
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
@@ -71,6 +71,8 @@ function writeFileWithParents(filePath, contents) {
|
|
|
71
71
|
function runInstaller(homeDirectory, extraArguments, options = {}) {
|
|
72
72
|
const childEnvironment = {
|
|
73
73
|
...process.env,
|
|
74
|
+
CLAUDE_CONFIG_DIR: undefined,
|
|
75
|
+
LLM_SETTINGS_PROFILES_ROOT: undefined,
|
|
74
76
|
CDE_INSTALL_PSTACK: '0',
|
|
75
77
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
76
78
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
@@ -306,6 +308,8 @@ test('uninstall fault after_git_config restores prior core.hooksPath', () => {
|
|
|
306
308
|
const io = {
|
|
307
309
|
env: {
|
|
308
310
|
...process.env,
|
|
311
|
+
CLAUDE_CONFIG_DIR: undefined,
|
|
312
|
+
LLM_SETTINGS_PROFILES_ROOT: undefined,
|
|
309
313
|
CDE_INSTALL_PSTACK: '0',
|
|
310
314
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
311
315
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
@@ -22,6 +22,8 @@ const REGISTERED_HOOK_RELATIVE_PATHS = [
|
|
|
22
22
|
function installerEnvironment(homeDirectory) {
|
|
23
23
|
const childEnvironment = {
|
|
24
24
|
...process.env,
|
|
25
|
+
CLAUDE_CONFIG_DIR: undefined,
|
|
26
|
+
LLM_SETTINGS_PROFILES_ROOT: undefined,
|
|
25
27
|
CDE_INSTALL_PSTACK: '0',
|
|
26
28
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
27
29
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|