claude-dev-env 8.101.0 → 8.102.1
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/.agents/skills/orchestrator/SKILL.md +2 -0
- package/.agents/skills/orchestrator/reference/completion-reporting.md +13 -0
- package/bin/codex-trimmed-sol.test.mjs +1 -0
- package/bin/install-pstack-plugin.mjs +48 -3
- package/bin/install-pstack-plugin.test.mjs +58 -1
- package/bin/install.agents-home.test.mjs +1 -0
- package/bin/install.codex-rules.test.mjs +2 -0
- package/bin/install.cursor-rules.test.mjs +1 -0
- package/bin/install.mjs +9 -0
- package/bin/install.pr-visual.test.mjs +1 -1
- package/bin/install.prune.test.mjs +1 -0
- package/bin/install.question-presentation.test.mjs +4 -0
- package/bin/install.settings-defaults.test.mjs +1 -0
- package/bin/install.shared-settings.test.mjs +1 -0
- package/bin/install.test.mjs +54 -0
- package/bin/install.transaction.test.mjs +8 -0
- package/bin/install.uninstall-transaction.test.mjs +2 -0
- package/bin/install.update-keeps-hooks.test.mjs +1 -0
- package/docs/agents-guidance/asks.md +6 -0
- package/package.json +1 -1
|
@@ -110,6 +110,7 @@ Checkpoint after decisions and state changes, before waiting, and before a known
|
|
|
110
110
|
|
|
111
111
|
### Complete the requested outcome
|
|
112
112
|
|
|
113
|
+
Before a completion report or status answer, follow [completion reporting](reference/completion-reporting.md).
|
|
113
114
|
Close a task only after its evidence is checked and integrated into the task authority.
|
|
114
115
|
Close a goal only when its acceptance conditions and authorized delivery are met.
|
|
115
116
|
Keep a named pending user action open when required. Completed work needs no invented final human action.
|
|
@@ -137,6 +138,7 @@ Report the result, evidence, and any remaining limit.
|
|
|
137
138
|
| `AGENTS.md` | Skill subtree instructions. |
|
|
138
139
|
| `.claude/CLAUDE.md` | Claude instruction import. |
|
|
139
140
|
| `reference/run-state.md` | Goal records, task authority, follow list, and active-root registry. |
|
|
141
|
+
| `reference/completion-reporting.md` | Verified goal status and unfinished administrative work. |
|
|
140
142
|
| `reference/recovery.md` | Cold-start and compaction recovery. |
|
|
141
143
|
| `reference/oversee-delegated-work.md` | Spawner review of delegated work before it reaches the user. |
|
|
142
144
|
| `reference/platform-evidence.md` | Official Projects sources and coordinator report boundaries. |
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Report completion
|
|
2
|
+
|
|
3
|
+
Use this procedure before a completion report or an answer about whether work is done.
|
|
4
|
+
|
|
5
|
+
1. Recover the user's requested outcome and acceptance conditions. Read the evidence for that outcome before choosing its status.
|
|
6
|
+
2. Check what each unfinished item changes. Missing deliverables, required verification, necessary approvals, and stated completion prerequisites keep the affected goal open. An administrative item whose absence has no effect on the result, its use, or its acceptance keeps its own task open.
|
|
7
|
+
3. State the main outcome first. When that outcome is verified complete and only incidental recordkeeping remains, report the task as complete. A requested status notice alone does not make the main outcome incomplete. Mention the administrative item separately when useful or required by the active reporting rules.
|
|
8
|
+
4. Keep unfinished work tracked honestly. When one tracker item combines the completed outcome and unfinished administration, preserve the outcome's goal and evidence, mark its work complete, and keep a separate open administrative follow-up. Do reachable administrative work before ending. Preserve its next action or blocker when it cannot be finished. Never mark it done merely to make the report look complete.
|
|
9
|
+
5. Preserve other goals and required delivery. A complete subgoal does not close an unfinished goal or the parent run. Use the goal's acceptance conditions in the [run record](run-state.md) to decide what its remaining work affects.
|
|
10
|
+
|
|
11
|
+
An administrative action can be requested without being a condition of the main outcome's completion. Treat it as a completion prerequisite when the user states that dependency, when it carries an essential requested result, or when its absence affects the result's usability, safety, or completeness.
|
|
12
|
+
|
|
13
|
+
For example, a verified report already delivered to the user is complete while an internal progress notice remains unsent. A report still missing required checks, required approval, or its requested delivery remains incomplete.
|
|
@@ -35,6 +35,7 @@ function installInScratchHome(homeDirectory, argumentsList = [], environment = {
|
|
|
35
35
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
36
36
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
37
37
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
38
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
38
39
|
CLAUDE_DEV_ENV_INSTALL_FAULT: undefined,
|
|
39
40
|
HOME: homeDirectory,
|
|
40
41
|
USERPROFILE: homeDirectory,
|
|
@@ -59,6 +59,27 @@ export const SUBAGENT_MODELS_PLUGIN_SPEC = Object.freeze({
|
|
|
59
59
|
optOutVariable: 'CDE_INSTALL_SUBAGENT_MODELS',
|
|
60
60
|
});
|
|
61
61
|
|
|
62
|
+
/**
|
|
63
|
+
* Anthropic's security-guidance plugin, which reviews each edit, turn, and
|
|
64
|
+
* commit an agent makes for security problems.
|
|
65
|
+
*
|
|
66
|
+
* Its marketplace holds every official Anthropic plugin and may supply other
|
|
67
|
+
* plugins the user installed, so the install never removes that marketplace
|
|
68
|
+
* to rebuild it.
|
|
69
|
+
*/
|
|
70
|
+
export const SECURITY_GUIDANCE_PLUGIN_SPEC = Object.freeze({
|
|
71
|
+
name: 'security-guidance',
|
|
72
|
+
label: 'Security-guidance',
|
|
73
|
+
marketplaceRepository: 'anthropics/claude-plugins-official',
|
|
74
|
+
marketplaceName: 'claude-plugins-official',
|
|
75
|
+
sparsePaths: Object.freeze([]),
|
|
76
|
+
pluginIdentifier: 'security-guidance@claude-plugins-official',
|
|
77
|
+
hosts: Object.freeze(['claude']),
|
|
78
|
+
optOutFlag: '--no-security-guidance',
|
|
79
|
+
optOutVariable: 'CDE_INSTALL_SECURITY_GUIDANCE',
|
|
80
|
+
sharesMarketplace: true,
|
|
81
|
+
});
|
|
82
|
+
|
|
62
83
|
const HOST_DEFINITIONS = Object.freeze({
|
|
63
84
|
claude: Object.freeze({
|
|
64
85
|
executable: 'claude',
|
|
@@ -303,7 +324,8 @@ function lockedFolderDetail(allSpecs, host, homeDirectory, errorText, findLocker
|
|
|
303
324
|
}).join('');
|
|
304
325
|
}
|
|
305
326
|
|
|
306
|
-
const
|
|
327
|
+
const MARKETPLACE_SOURCE_MISMATCH_PATTERN = /doesn't match its extraKnownMarketplaces entry/;
|
|
328
|
+
const REBUILD_REQUIRED_PATTERN = new RegExp(`${MARKETPLACE_SOURCE_MISMATCH_PATTERN.source}|Source path does not exist`);
|
|
307
329
|
|
|
308
330
|
function commandFailureDetail(outcome) {
|
|
309
331
|
return singleLineDetail(outcome.stderr) || singleLineDetail(outcome.stdout)
|
|
@@ -356,7 +378,25 @@ function installForHost(allSpecs, host, homeDirectory, environment, runCommand,
|
|
|
356
378
|
return { host, executable, status: 'installed', warning: null };
|
|
357
379
|
}
|
|
358
380
|
const refreshOutput = `${refreshOutcome.outcome.stderr ?? ''}\n${refreshOutcome.outcome.stdout ?? ''}`;
|
|
359
|
-
|
|
381
|
+
const marketplaceIsShared = allSpecs.some(eachSpec => eachSpec.sharesMarketplace);
|
|
382
|
+
const sourceMismatchOnAdd = refreshOutcome.commandArguments === plan.refreshCommands[0]
|
|
383
|
+
&& MARKETPLACE_SOURCE_MISMATCH_PATTERN.test(refreshOutput);
|
|
384
|
+
if (marketplaceIsShared && sourceMismatchOnAdd) {
|
|
385
|
+
const knownMarketplacePlan = { ...plan, refreshCommands: plan.refreshCommands.slice(1) };
|
|
386
|
+
const knownMarketplaceOutcome = refreshInPlace(
|
|
387
|
+
knownMarketplacePlan, executable, commandEnvironment, runCommand,
|
|
388
|
+
);
|
|
389
|
+
if (knownMarketplaceOutcome.state === 'refreshed') {
|
|
390
|
+
removeOrphanedVersionsForHost(allSpecs, host, homeDirectory);
|
|
391
|
+
return { host, executable, status: 'installed', warning: null };
|
|
392
|
+
}
|
|
393
|
+
if (knownMarketplaceOutcome.state === 'absent') return absentHostOutcome(allSpecs, host, executable);
|
|
394
|
+
return failedCommandOutcome(
|
|
395
|
+
allSpecs, host, homeDirectory, executable,
|
|
396
|
+
knownMarketplaceOutcome.commandArguments, knownMarketplaceOutcome.outcome, findLockers,
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
if (marketplaceIsShared || !REBUILD_REQUIRED_PATTERN.test(refreshOutput)) {
|
|
360
400
|
return failedCommandOutcome(
|
|
361
401
|
allSpecs, host, homeDirectory, executable,
|
|
362
402
|
refreshOutcome.commandArguments, refreshOutcome.outcome, findLockers,
|
|
@@ -418,7 +458,12 @@ export function restartNotice(allSpecs, allInstalledHosts) {
|
|
|
418
458
|
* back to the clean install Codex always runs: it removes every plugin in the
|
|
419
459
|
* set and then the marketplace, so an older version never survives beside the
|
|
420
460
|
* new one, and adds them again. A removal that finds nothing to remove exits
|
|
421
|
-
* non-zero on a fresh home, and the install goes on.
|
|
461
|
+
* non-zero on a fresh home, and the install goes on. A spec that marks its
|
|
462
|
+
* marketplace as shared skips the rebuild, because removing that marketplace
|
|
463
|
+
* would uninstall plugins this run does not own. When the shared marketplace
|
|
464
|
+
* is already known under another source, the add fails on the mismatch and
|
|
465
|
+
* the host runs the rest of the refresh against the known entry; any other
|
|
466
|
+
* refresh failure reports the host failed.
|
|
422
467
|
* Before each Claude marketplace add, the install deletes the half-made clone
|
|
423
468
|
* folder an interrupted earlier add left, so the add starts in an empty slot.
|
|
424
469
|
*
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
PSTACK_PLUGIN_IDENTIFIER,
|
|
10
10
|
ALL_RETIRED_PLUGIN_SPECS,
|
|
11
11
|
PSTACK_PLUGIN_SPEC,
|
|
12
|
+
SECURITY_GUIDANCE_PLUGIN_SPEC,
|
|
12
13
|
SUBAGENT_MODELS_PLUGIN_SPEC,
|
|
13
14
|
USAGE_WRAPUP_PLUGIN_SPEC,
|
|
14
15
|
hostCommandInvocation,
|
|
@@ -584,4 +585,60 @@ test('a run that installs nothing prints no restart notice', () => {
|
|
|
584
585
|
assert.equal(outcome.status, 'skipped');
|
|
585
586
|
assert.deepEqual(allLoggedLines, []);
|
|
586
587
|
assert.equal(outcome.restartNotice, null);
|
|
587
|
-
});
|
|
588
|
+
});
|
|
589
|
+
|
|
590
|
+
test('should install security-guidance from the official marketplace on Claude only', () => {
|
|
591
|
+
const runner = recordingRunner();
|
|
592
|
+
const outcome = installMarketplacePlugins([SECURITY_GUIDANCE_PLUGIN_SPEC], ROOTS, runner);
|
|
593
|
+
assert.equal(outcome.status, 'installed');
|
|
594
|
+
assert.deepEqual(outcome.hosts.map(host => host.host), ['claude']);
|
|
595
|
+
assert.deepEqual(runner.calls.map(call => [call.executable, ...call.commandArguments]), [
|
|
596
|
+
['claude', 'plugin', 'marketplace', 'add', 'anthropics/claude-plugins-official'],
|
|
597
|
+
['claude', 'plugin', 'marketplace', 'update', 'claude-plugins-official'],
|
|
598
|
+
['claude', 'plugin', 'install', 'security-guidance@claude-plugins-official'],
|
|
599
|
+
['claude', 'plugin', 'update', 'security-guidance@claude-plugins-official'],
|
|
600
|
+
]);
|
|
601
|
+
assert.equal(runner.calls[0].environment.CLAUDE_CONFIG_DIR, ROOTS.claudeRoot);
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
test('should install against an official marketplace already known under another source', () => {
|
|
605
|
+
const runner = recordingRunner((executable, commandArguments) => (
|
|
606
|
+
commandArguments[2] === 'add'
|
|
607
|
+
? { status: 1, stderr: "its source doesn't match its extraKnownMarketplaces entry" }
|
|
608
|
+
: { status: 0, stderr: '' }));
|
|
609
|
+
const outcome = installMarketplacePlugins([SECURITY_GUIDANCE_PLUGIN_SPEC], ROOTS, runner);
|
|
610
|
+
assert.equal(outcome.status, 'installed');
|
|
611
|
+
assert.deepEqual(runner.calls.map(call => call.commandArguments), [
|
|
612
|
+
['plugin', 'marketplace', 'add', 'anthropics/claude-plugins-official'],
|
|
613
|
+
['plugin', 'marketplace', 'update', 'claude-plugins-official'],
|
|
614
|
+
['plugin', 'install', 'security-guidance@claude-plugins-official'],
|
|
615
|
+
['plugin', 'update', 'security-guidance@claude-plugins-official'],
|
|
616
|
+
]);
|
|
617
|
+
});
|
|
618
|
+
|
|
619
|
+
test('should leave the shared official marketplace in place when its refresh needs a rebuild', () => {
|
|
620
|
+
const runner = recordingRunner((executable, commandArguments) => (
|
|
621
|
+
commandArguments[1] === 'install'
|
|
622
|
+
? { status: 1, stderr: 'Source path does not exist: plugins/security-guidance' }
|
|
623
|
+
: { status: 0, stderr: '' }));
|
|
624
|
+
const outcome = installMarketplacePlugins([SECURITY_GUIDANCE_PLUGIN_SPEC], ROOTS, runner);
|
|
625
|
+
assert.equal(outcome.status, 'failed');
|
|
626
|
+
assert.match(outcome.warning, /Source path does not exist/);
|
|
627
|
+
assert.equal(
|
|
628
|
+
runner.calls.some(call => call.commandArguments.includes('remove') || call.commandArguments.includes('uninstall')),
|
|
629
|
+
false,
|
|
630
|
+
);
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
test('should turn off only security-guidance with its opt-out flag or variable', () => {
|
|
634
|
+
assert.equal(shouldInstallMarketplacePlugin(SECURITY_GUIDANCE_PLUGIN_SPEC, [], {}), true);
|
|
635
|
+
assert.equal(shouldInstallMarketplacePlugin(SECURITY_GUIDANCE_PLUGIN_SPEC, ['--no-security-guidance'], {}), false);
|
|
636
|
+
assert.equal(
|
|
637
|
+
shouldInstallMarketplacePlugin(SECURITY_GUIDANCE_PLUGIN_SPEC, [], { CDE_INSTALL_SECURITY_GUIDANCE: '0' }),
|
|
638
|
+
false,
|
|
639
|
+
);
|
|
640
|
+
assert.equal(
|
|
641
|
+
shouldInstallMarketplacePlugin(PSTACK_PLUGIN_SPEC, ['--no-security-guidance'], { CDE_INSTALL_SECURITY_GUIDANCE: '0' }),
|
|
642
|
+
true,
|
|
643
|
+
);
|
|
644
|
+
});
|
|
@@ -56,6 +56,7 @@ function runInstaller(homeDirectory, extraArguments, environmentOverrides = {})
|
|
|
56
56
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
57
57
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
58
58
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
59
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
59
60
|
HOME: homeDirectory,
|
|
60
61
|
USERPROFILE: homeDirectory,
|
|
61
62
|
GIT_CONFIG_GLOBAL: join(homeDirectory, '.gitconfig'),
|
|
@@ -62,6 +62,7 @@ function runInstaller(homeDirectory, extraArguments) {
|
|
|
62
62
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
63
63
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
64
64
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
65
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
65
66
|
HOME: homeDirectory,
|
|
66
67
|
USERPROFILE: homeDirectory,
|
|
67
68
|
GIT_CONFIG_GLOBAL: join(homeDirectory, '.gitconfig'),
|
|
@@ -95,6 +96,7 @@ function scanTextWithProductionPiiScanner(scannedText) {
|
|
|
95
96
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
96
97
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
97
98
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
99
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
98
100
|
PYTHONPATH: BLOCKING_HOOKS_DIRECTORY,
|
|
99
101
|
CLAUDE_LOCAL_IDENTITY_PATH: join(
|
|
100
102
|
temporaryDirectory,
|
|
@@ -36,6 +36,7 @@ function runInstaller(homeDirectory, extraArguments, environmentOverrides = {})
|
|
|
36
36
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
37
37
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
38
38
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
39
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
39
40
|
HOME: homeDirectory,
|
|
40
41
|
USERPROFILE: homeDirectory,
|
|
41
42
|
CODEX_HOME: join(homeDirectory, '.codex'),
|
package/bin/install.mjs
CHANGED
|
@@ -58,6 +58,7 @@ import {
|
|
|
58
58
|
import {
|
|
59
59
|
ALL_RETIRED_PLUGIN_SPECS,
|
|
60
60
|
PSTACK_PLUGIN_SPEC,
|
|
61
|
+
SECURITY_GUIDANCE_PLUGIN_SPEC,
|
|
61
62
|
SUBAGENT_MODELS_PLUGIN_SPEC,
|
|
62
63
|
USAGE_WRAPUP_PLUGIN_SPEC,
|
|
63
64
|
installMarketplacePlugins,
|
|
@@ -3121,6 +3122,13 @@ function executeInstallPlanMutations(plan, transactionHelpers) {
|
|
|
3121
3122
|
summary.repositoryPlugins = repositoryPlugins;
|
|
3122
3123
|
printPluginHostOutcomes(allRepositoryPluginSpecs, repositoryPlugins);
|
|
3123
3124
|
}
|
|
3125
|
+
if (!selectedGroups && shouldInstallMarketplacePlugin(SECURITY_GUIDANCE_PLUGIN_SPEC)) {
|
|
3126
|
+
const securityGuidancePlugin = installMarketplacePlugins([SECURITY_GUIDANCE_PLUGIN_SPEC], {
|
|
3127
|
+
claudeRoot: CLAUDE_HOME,
|
|
3128
|
+
});
|
|
3129
|
+
summary.securityGuidancePlugin = securityGuidancePlugin;
|
|
3130
|
+
printPluginHostOutcomes([SECURITY_GUIDANCE_PLUGIN_SPEC], securityGuidancePlugin);
|
|
3131
|
+
}
|
|
3124
3132
|
if (!selectedGroups) {
|
|
3125
3133
|
const packageGuidancePath = writeCodexPackageGuidance(
|
|
3126
3134
|
INSTALL_ROOT_RESOLUTION.codexHomeDirectory,
|
|
@@ -3686,6 +3694,7 @@ Usage:
|
|
|
3686
3694
|
npx ${PACKAGE_NAME} --no-deepstack Full install without the DeepStack plugin (also CDE_INSTALL_DEEPSTACK=0)
|
|
3687
3695
|
npx ${PACKAGE_NAME} --no-usage-wrapup Full install without the usage-wrapup plugin (also CDE_INSTALL_USAGE_WRAPUP=0)
|
|
3688
3696
|
npx ${PACKAGE_NAME} --no-subagent-models Full install without the subagent-models plugin (also CDE_INSTALL_SUBAGENT_MODELS=0)
|
|
3697
|
+
npx ${PACKAGE_NAME} --no-security-guidance Full install without Anthropic's security-guidance plugin (also CDE_INSTALL_SECURITY_GUIDANCE=0)
|
|
3689
3698
|
npx ${PACKAGE_NAME} --uninstall Remove installed files from the selected root
|
|
3690
3699
|
npx ${PACKAGE_NAME} --help Show this help
|
|
3691
3700
|
|
|
@@ -22,7 +22,7 @@ test('packed full and core installs ship the runnable PR visual skill to the sha
|
|
|
22
22
|
const homeDirectory = join(sandbox, `home-${eachIndex}`);
|
|
23
23
|
execFileSync(process.execPath, [join(packaged, 'bin/install.mjs'), ...eachArguments], {
|
|
24
24
|
encoding: 'utf8',
|
|
25
|
-
env: { ...process.env, CLAUDE_CONFIG_DIR: undefined, LLM_SETTINGS_PROFILES_ROOT: undefined, HOME: homeDirectory, USERPROFILE: homeDirectory, CODEX_HOME: join(homeDirectory, '.codex'), GIT_CONFIG_GLOBAL: join(homeDirectory, '.gitconfig'), CDE_INSTALL_PSTACK: '0', CDE_INSTALL_DEEPSTACK: '0', CDE_INSTALL_USAGE_WRAPUP: '0', CDE_INSTALL_SUBAGENT_MODELS: '0', CDE_INSTALL_DEEPEN_FIRST_PROMPT: '0' },
|
|
25
|
+
env: { ...process.env, CLAUDE_CONFIG_DIR: undefined, LLM_SETTINGS_PROFILES_ROOT: undefined, HOME: homeDirectory, USERPROFILE: homeDirectory, CODEX_HOME: join(homeDirectory, '.codex'), GIT_CONFIG_GLOBAL: join(homeDirectory, '.gitconfig'), CDE_INSTALL_PSTACK: '0', CDE_INSTALL_DEEPSTACK: '0', CDE_INSTALL_USAGE_WRAPUP: '0', CDE_INSTALL_SUBAGENT_MODELS: '0', CDE_INSTALL_SECURITY_GUIDANCE: '0', CDE_INSTALL_DEEPEN_FIRST_PROMPT: '0' },
|
|
26
26
|
});
|
|
27
27
|
const installed = join(homeDirectory, ...SKILL_PATH_SEGMENTS);
|
|
28
28
|
for (const eachFile of REQUIRED_FILES) assert.deepEqual(readFileSync(join(installed, eachFile)), readFileSync(join(packaged, ...SKILL_PATH_SEGMENTS, eachFile)));
|
|
@@ -266,6 +266,7 @@ function resolveInstallerInvocation(homeDirectory) {
|
|
|
266
266
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
267
267
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
268
268
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
269
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
269
270
|
HOME: homeDirectory,
|
|
270
271
|
USERPROFILE: homeDirectory,
|
|
271
272
|
GIT_CONFIG_GLOBAL: join(homeDirectory, '.gitconfig'),
|
|
@@ -28,6 +28,7 @@ function installInScratchHome(homeDirectory, argumentsList = [], extraEnvironmen
|
|
|
28
28
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
29
29
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
30
30
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
31
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
31
32
|
HOME: homeDirectory,
|
|
32
33
|
USERPROFILE: homeDirectory,
|
|
33
34
|
CODEX_HOME: join(homeDirectory, '.codex'),
|
|
@@ -185,6 +186,7 @@ test('a successful pstack install omits the retired skill block and gains the qu
|
|
|
185
186
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
186
187
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
187
188
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
189
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
188
190
|
CDE_CODEX_EXECUTABLE: commandPath,
|
|
189
191
|
CDE_CLAUDE_EXECUTABLE: commandPath,
|
|
190
192
|
});
|
|
@@ -214,6 +216,7 @@ test('enabling pstack after a pstack-off install preserves question guidance', (
|
|
|
214
216
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
215
217
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
216
218
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
219
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
217
220
|
CDE_CODEX_EXECUTABLE: commandPath,
|
|
218
221
|
CDE_CLAUDE_EXECUTABLE: commandPath,
|
|
219
222
|
});
|
|
@@ -244,6 +247,7 @@ test('a failed pstack transition restores question-only guidance and removes its
|
|
|
244
247
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
245
248
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
246
249
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
250
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
247
251
|
CDE_CODEX_EXECUTABLE: commandPath,
|
|
248
252
|
CDE_CLAUDE_EXECUTABLE: commandPath,
|
|
249
253
|
CLAUDE_DEV_ENV_INSTALL_FAULT: 'after_file_staging',
|
|
@@ -74,6 +74,7 @@ function runInstallerInSandbox(sandboxHome, installerArguments = []) {
|
|
|
74
74
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
75
75
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
76
76
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
77
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
77
78
|
HOME: sandboxHome,
|
|
78
79
|
USERPROFILE: sandboxHome,
|
|
79
80
|
GIT_CONFIG_GLOBAL: gitConfigGlobal,
|
package/bin/install.test.mjs
CHANGED
|
@@ -3050,6 +3050,7 @@ test('a failed update preserves an existing skills lookup pointer', () => {
|
|
|
3050
3050
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
3051
3051
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
3052
3052
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
3053
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
3053
3054
|
};
|
|
3054
3055
|
const argumentsForCoreInstall = [PSTACK_TEST_INSTALLER_PATH, '--only', 'core'];
|
|
3055
3056
|
const firstRun = spawnSync(process.execPath, argumentsForCoreInstall, {
|
|
@@ -3104,6 +3105,7 @@ function runPstackInstaller(homeDirectory, extraArguments, environmentOverrides
|
|
|
3104
3105
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
3105
3106
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
3106
3107
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
3108
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
3107
3109
|
...environmentOverrides,
|
|
3108
3110
|
},
|
|
3109
3111
|
});
|
|
@@ -3529,6 +3531,54 @@ for (const [caseName, extraArguments, environmentOverrides] of [
|
|
|
3529
3531
|
});
|
|
3530
3532
|
}
|
|
3531
3533
|
|
|
3534
|
+
test('should install security-guidance from the official marketplace on a full install', t => {
|
|
3535
|
+
const sandbox = pstackPluginSandbox(t);
|
|
3536
|
+
|
|
3537
|
+
const installerOutput = runPstackInstaller(sandbox.homeDirectory, ['--no-pstack'], {
|
|
3538
|
+
...sandbox.environment,
|
|
3539
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '1',
|
|
3540
|
+
});
|
|
3541
|
+
|
|
3542
|
+
assert.deepEqual(sandbox.recordedCommands(), [
|
|
3543
|
+
'claude plugin marketplace add anthropics/claude-plugins-official',
|
|
3544
|
+
'claude plugin marketplace update claude-plugins-official',
|
|
3545
|
+
'claude plugin install security-guidance@claude-plugins-official',
|
|
3546
|
+
'claude plugin update security-guidance@claude-plugins-official',
|
|
3547
|
+
]);
|
|
3548
|
+
assert.match(installerOutput, /Security-guidance \(claude\): installed/);
|
|
3549
|
+
});
|
|
3550
|
+
|
|
3551
|
+
for (const [caseName, extraArguments, environmentOverrides] of [
|
|
3552
|
+
['--no-security-guidance', ['--no-security-guidance'], { CDE_INSTALL_SECURITY_GUIDANCE: '1' }],
|
|
3553
|
+
['CDE_INSTALL_SECURITY_GUIDANCE=0', [], { CDE_INSTALL_SECURITY_GUIDANCE: '0' }],
|
|
3554
|
+
['an --only run', ['--only', 'core'], { CDE_INSTALL_SECURITY_GUIDANCE: '1' }],
|
|
3555
|
+
]) {
|
|
3556
|
+
test(`should skip security-guidance on ${caseName}`, t => {
|
|
3557
|
+
const sandbox = pstackPluginSandbox(t);
|
|
3558
|
+
|
|
3559
|
+
const installerOutput = runPstackInstaller(sandbox.homeDirectory, extraArguments, {
|
|
3560
|
+
...sandbox.environment,
|
|
3561
|
+
...environmentOverrides,
|
|
3562
|
+
});
|
|
3563
|
+
|
|
3564
|
+
assert.equal(
|
|
3565
|
+
sandbox.recordedCommands().some(eachCommand => eachCommand.includes('security-guidance')),
|
|
3566
|
+
false,
|
|
3567
|
+
);
|
|
3568
|
+
assert.doesNotMatch(installerOutput, /Security-guidance \(/);
|
|
3569
|
+
});
|
|
3570
|
+
}
|
|
3571
|
+
|
|
3572
|
+
test('should name the security-guidance opt-out in the help output', () => {
|
|
3573
|
+
const helpRun = spawnSync(process.execPath, [PSTACK_TEST_INSTALLER_PATH, '--help'], {
|
|
3574
|
+
encoding: 'utf8',
|
|
3575
|
+
env: process.env,
|
|
3576
|
+
});
|
|
3577
|
+
|
|
3578
|
+
assert.equal(helpRun.status, 0, helpRun.stderr);
|
|
3579
|
+
assert.match(helpRun.stdout, /--no-security-guidance .*CDE_INSTALL_SECURITY_GUIDANCE=0/);
|
|
3580
|
+
});
|
|
3581
|
+
|
|
3532
3582
|
test('should name the subagent-models opt-out in the help output', () => {
|
|
3533
3583
|
const helpRun = spawnSync(process.execPath, [PSTACK_TEST_INSTALLER_PATH, '--help'], {
|
|
3534
3584
|
encoding: 'utf8',
|
|
@@ -3623,6 +3673,7 @@ function installWithGlobalPrefix(context, globalPrefix) {
|
|
|
3623
3673
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
3624
3674
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
3625
3675
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
3676
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
3626
3677
|
HOME: homeDirectory,
|
|
3627
3678
|
USERPROFILE: homeDirectory,
|
|
3628
3679
|
APPDATA: join(homeDirectory, 'AppData', 'Roaming'),
|
|
@@ -3679,6 +3730,7 @@ test('install adds the open-tasks Stop gate to every profile with its own settin
|
|
|
3679
3730
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
3680
3731
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
3681
3732
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
3733
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
3682
3734
|
HOME: homeDirectory,
|
|
3683
3735
|
USERPROFILE: homeDirectory,
|
|
3684
3736
|
CODEX_HOME: join(homeDirectory, '.codex'),
|
|
@@ -3721,6 +3773,7 @@ test('a profile settings.json that is not valid JSON is left alone and named und
|
|
|
3721
3773
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
3722
3774
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
3723
3775
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
3776
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
3724
3777
|
HOME: homeDirectory,
|
|
3725
3778
|
USERPROFILE: homeDirectory,
|
|
3726
3779
|
CODEX_HOME: join(homeDirectory, '.codex'),
|
|
@@ -3766,6 +3819,7 @@ test('uninstall stops before changing anything while a profile settings.json tha
|
|
|
3766
3819
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
3767
3820
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
3768
3821
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
3822
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
3769
3823
|
HOME: homeDirectory,
|
|
3770
3824
|
USERPROFILE: homeDirectory,
|
|
3771
3825
|
CODEX_HOME: join(homeDirectory, '.codex'),
|
|
@@ -91,6 +91,7 @@ test('capture and restore recover settings, manifest, files, and hooksPath', ()
|
|
|
91
91
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
92
92
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
93
93
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
94
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
94
95
|
HOME: box.root,
|
|
95
96
|
USERPROFILE: box.root,
|
|
96
97
|
GIT_CONFIG_GLOBAL: gitConfigPath,
|
|
@@ -157,6 +158,7 @@ test('capture and restore recover an additional host settings file', () => {
|
|
|
157
158
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
158
159
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
159
160
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
161
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
160
162
|
HOME: box.root,
|
|
161
163
|
USERPROFILE: box.root,
|
|
162
164
|
GIT_CONFIG_GLOBAL: gitConfigPath,
|
|
@@ -196,6 +198,7 @@ test('runWithInstallTransaction restores prior state on injected fault', () => {
|
|
|
196
198
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
197
199
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
198
200
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
201
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
199
202
|
HOME: box.root,
|
|
200
203
|
USERPROFILE: box.root,
|
|
201
204
|
GIT_CONFIG_GLOBAL: gitConfigPath,
|
|
@@ -254,6 +257,7 @@ test('runWithInstallTransaction commits and discards journal on success', () =>
|
|
|
254
257
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
255
258
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
256
259
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
260
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
257
261
|
HOME: box.root,
|
|
258
262
|
USERPROFILE: box.root,
|
|
259
263
|
GIT_CONFIG_GLOBAL: gitConfigPath,
|
|
@@ -301,6 +305,7 @@ function runInstaller(homeDirectory, extraArguments, options = {}) {
|
|
|
301
305
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
302
306
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
303
307
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
308
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
304
309
|
HOME: homeDirectory,
|
|
305
310
|
USERPROFILE: homeDirectory,
|
|
306
311
|
GIT_CONFIG_GLOBAL: join(homeDirectory, '.gitconfig'),
|
|
@@ -338,6 +343,7 @@ test('a later install fault removes newly seeded Codex pstack files', () => {
|
|
|
338
343
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
339
344
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
340
345
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
346
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
341
347
|
CDE_CODEX_EXECUTABLE: codexCommandPath,
|
|
342
348
|
},
|
|
343
349
|
});
|
|
@@ -485,6 +491,7 @@ test('installer fault after_git_config restores prior core.hooksPath', () => {
|
|
|
485
491
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
486
492
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
487
493
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
494
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
488
495
|
HOME: homeDirectory,
|
|
489
496
|
USERPROFILE: homeDirectory,
|
|
490
497
|
GIT_CONFIG_GLOBAL: gitConfigPath,
|
|
@@ -506,6 +513,7 @@ test('installer fault after_git_config restores prior core.hooksPath', () => {
|
|
|
506
513
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
507
514
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
508
515
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
516
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
509
517
|
HOME: homeDirectory,
|
|
510
518
|
USERPROFILE: homeDirectory,
|
|
511
519
|
GIT_CONFIG_GLOBAL: gitConfigPath,
|
|
@@ -77,6 +77,7 @@ function runInstaller(homeDirectory, extraArguments, options = {}) {
|
|
|
77
77
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
78
78
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
79
79
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
80
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
80
81
|
HOME: homeDirectory,
|
|
81
82
|
USERPROFILE: homeDirectory,
|
|
82
83
|
GIT_CONFIG_GLOBAL: join(homeDirectory, '.gitconfig'),
|
|
@@ -315,6 +316,7 @@ test('uninstall fault after_git_config restores prior core.hooksPath', () => {
|
|
|
315
316
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
316
317
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
317
318
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
319
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
318
320
|
HOME: homeDirectory,
|
|
319
321
|
USERPROFILE: homeDirectory,
|
|
320
322
|
GIT_CONFIG_GLOBAL: gitConfigPath,
|
|
@@ -28,6 +28,7 @@ function installerEnvironment(homeDirectory) {
|
|
|
28
28
|
CDE_INSTALL_DEEPSTACK: '0',
|
|
29
29
|
CDE_INSTALL_USAGE_WRAPUP: '0',
|
|
30
30
|
CDE_INSTALL_SUBAGENT_MODELS: '0',
|
|
31
|
+
CDE_INSTALL_SECURITY_GUIDANCE: '0',
|
|
31
32
|
HOME: homeDirectory,
|
|
32
33
|
USERPROFILE: homeDirectory,
|
|
33
34
|
GIT_CONFIG_GLOBAL: join(homeDirectory, '.gitconfig'),
|
|
@@ -11,6 +11,12 @@
|
|
|
11
11
|
- Keep each item's status current as the work moves: in progress when you start it, completed only after you saw the proof. A long turn updates the list at each step, so the list never lags the work.
|
|
12
12
|
- An item blocked on the user stays open, and the reply says what the user must give.
|
|
13
13
|
|
|
14
|
+
## Completion reports
|
|
15
|
+
|
|
16
|
+
Judge completion against the user's outcome and acceptance conditions. Report a verified main outcome as complete when only incidental recordkeeping remains, even when that administration was requested. Missing deliverables, required verification, approvals governing the outcome, stated completion prerequisites, and work needed for usability, safety, or completeness keep the affected goal open.
|
|
17
|
+
|
|
18
|
+
When one task combines a completed outcome and unfinished administration, preserve the goal and evidence, mark the main work complete, and track administration as a separate open follow-up. Do reachable administrative work now. Report the main outcome first and mention administration separately when useful.
|
|
19
|
+
|
|
14
20
|
## Asks ledger
|
|
15
21
|
|
|
16
22
|
When the host keeps an asks ledger with `ledger.py` and `asks_check.py`, record each ask in it too:
|