claude-dev-env 8.89.0 → 8.90.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.
Files changed (86) hide show
  1. package/.agents/skills/pr-visual/README.md +29 -0
  2. package/.agents/skills/pr-visual/SKILL.md +62 -0
  3. package/.agents/skills/pr-visual/assets/icons.symbols +27 -0
  4. package/.agents/skills/pr-visual/assets/viewer.html +147 -0
  5. package/.agents/skills/pr-visual/fixtures/bar.scene.json +193 -0
  6. package/.agents/skills/pr-visual/fixtures/flow.scene.json +201 -0
  7. package/.agents/skills/pr-visual/fixtures/head/metrics.json +16 -0
  8. package/.agents/skills/pr-visual/fixtures/integrated.scene.json +239 -0
  9. package/.agents/skills/pr-visual/fixtures/line.scene.json +193 -0
  10. package/.agents/skills/pr-visual/fixtures/scatter.scene.json +193 -0
  11. package/.agents/skills/pr-visual/fixtures/snapshot.json +21 -0
  12. package/.agents/skills/pr-visual/references/evidence.md +9 -0
  13. package/.agents/skills/pr-visual/references/formats.md +30 -0
  14. package/.agents/skills/pr-visual/references/scene-contract.md +48 -0
  15. package/.agents/skills/pr-visual/references/visual-contract.md +23 -0
  16. package/.agents/skills/pr-visual/scripts/collect.py +111 -0
  17. package/.agents/skills/pr-visual/scripts/metrics.py +99 -0
  18. package/.agents/skills/pr-visual/scripts/render.py +133 -0
  19. package/.agents/skills/pr-visual/scripts/test_collect.py +58 -0
  20. package/.agents/skills/pr-visual/scripts/test_metrics.py +47 -0
  21. package/.agents/skills/pr-visual/scripts/test_render.py +77 -0
  22. package/.agents/skills/pr-visual/scripts/verify.py +218 -0
  23. package/.agents/skills/pr-visual/scripts/visual_config/config/constants.py +104 -0
  24. package/bin/codex-skill-load-block.mjs +0 -25
  25. package/bin/codex-skill-load-block.test.mjs +5 -17
  26. package/bin/codex-trimmed-sol.test.mjs +0 -1
  27. package/bin/cursor-native-hooks.test.mjs +3 -3
  28. package/bin/ever-shipped-skills.mjs +1 -0
  29. package/bin/install-deepstack-plugin.mjs +42 -25
  30. package/bin/install-deepstack-plugin.test.mjs +37 -11
  31. package/bin/install-pstack-plugin.mjs +58 -11
  32. package/bin/install-pstack-plugin.test.mjs +54 -21
  33. package/bin/install.agents-home.test.mjs +0 -1
  34. package/bin/install.codex-rules.test.mjs +0 -2
  35. package/bin/install.cursor-rules.test.mjs +90 -26
  36. package/bin/install.mjs +30 -36
  37. package/bin/install.pr-visual.test.mjs +40 -0
  38. package/bin/install.prompt-context.test.mjs +3 -4
  39. package/bin/install.prune.test.mjs +0 -1
  40. package/bin/install.question-presentation.test.mjs +0 -4
  41. package/bin/install.settings-defaults.test.mjs +0 -1
  42. package/bin/install.shared-settings.test.mjs +0 -1
  43. package/bin/install.test.mjs +14 -44
  44. package/bin/install.transaction.test.mjs +0 -8
  45. package/bin/install.uninstall-transaction.test.mjs +0 -2
  46. package/bin/install.update-keeps-hooks.test.mjs +0 -1
  47. package/docs/BDD_SCENARIO_QUALITY.md +1 -1
  48. package/docs/BDD_TEST_LAYOUT.md +1 -1
  49. package/docs/CODE_RULES.md +1 -1
  50. package/docs/rule-guides/deepstack-wording.md +3 -5
  51. package/docs/rule-guides/session-title.md +5 -4
  52. package/hooks/blocking/session_title_turn_gate.py +287 -0
  53. package/hooks/blocking/test_session_title_format_gate.py +5 -0
  54. package/hooks/blocking/test_session_title_turn_gate.py +264 -0
  55. package/hooks/features/conduct-gates.md +3 -0
  56. package/hooks/features/session-context.md +0 -4
  57. package/hooks/hooks.json +5 -5
  58. package/hooks/hooks_constants/mod_handoff_constants.py +0 -2
  59. package/hooks/hooks_constants/session_title_constants.py +41 -3
  60. package/hooks/lifecycle/nested_project_hooks.py +2 -2
  61. package/hooks/lifecycle/test_nested_project_hooks.py +2 -2
  62. package/hooks/session/compaction_user_messages.py +2 -2
  63. package/package.json +2 -2
  64. package/rules/deepstack-wording.md +3 -3
  65. package/scripts/ci/install-playtest.mjs +58 -314
  66. package/scripts/ci/install-playtest.test.mjs +24 -6
  67. package/scripts/policy_lint/adapter_configuration.py +1 -0
  68. package/scripts/policy_lint/config/constants.py +1 -0
  69. package/scripts/test_deepstack_review_criterion.py +2 -3
  70. package/scripts/test_deepstack_wording_rule.py +6 -4
  71. package/scripts/tests/test_adapter_configuration.py +8 -0
  72. package/.agents/skills/deepen/SKILL.md +0 -26
  73. package/commands/deepen.md +0 -14
  74. package/docs/decisions/deepstack-gate.md +0 -32
  75. package/hooks/hooks_constants/deepen_first_prompt_constants.py +0 -187
  76. package/hooks/session/deepen_default_rewrite.py +0 -128
  77. package/hooks/session/deepen_first_prompt.py +0 -383
  78. package/hooks/session/deepen_role_gate.py +0 -171
  79. package/hooks/session/deepen_turn_marker.py +0 -75
  80. package/hooks/session/fixtures/deepstack_replay.json +0 -15
  81. package/hooks/session/grade_deepstack_replay.py +0 -78
  82. package/hooks/session/test_deepen_default_rewrite.py +0 -90
  83. package/hooks/session/test_deepen_first_prompt.py +0 -452
  84. package/hooks/session/test_deepen_role_gate.py +0 -83
  85. package/hooks/session/test_deepen_turn_marker.py +0 -59
  86. package/hooks/session/test_grade_deepstack_replay.py +0 -47
@@ -36,7 +36,6 @@ 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_DEEPEN_FIRST_PROMPT: '0',
40
39
  HOME: homeDirectory,
41
40
  USERPROFILE: homeDirectory,
42
41
  CODEX_HOME: join(homeDirectory, '.codex'),
@@ -144,10 +143,11 @@ test('seeds one editable policy and one native Codex routing hook', () => {
144
143
  const allCodexStopCommands = firstCodexHooks.hooks.Stop.flatMap(group => group.hooks.map(hook => hook.command));
145
144
  assert.equal(allCodexStopCommands.length, 1, 'Codex gets the open tasks Stop gate and no other Stop hook');
146
145
  assert.match(allCodexStopCommands[0], /open_tasks_stop_gate\.py/);
147
- assert.ok(
148
- firstCodexHooks.hooks.UserPromptSubmit.some(group =>
146
+ assert.equal(
147
+ (firstCodexHooks.hooks.UserPromptSubmit ?? []).some(group =>
149
148
  group.hooks.some(hook => String(hook.command).includes('deepen_first_prompt.py')),
150
149
  ),
150
+ false,
151
151
  );
152
152
  assert.equal(
153
153
  firstCodexHooks.hooks.PreToolUse.some(group => group.matcher === 'Write|Edit|MultiEdit|apply_patch'),
@@ -290,6 +290,7 @@ test('Codex reinstall removes omitted package hooks and preserves user configura
290
290
  const suffixCommand = `python "${join(codexHome, 'hooks', 'blocking', 'pre_tool_use_dispatcher.py.backup')}"`;
291
291
  hooksByEvent.PreToolUse.push({ matcher: 'suffix', hooks: [{ type: 'command', command: suffixCommand }] });
292
292
  hooksByEvent.CustomEvent = { metadata: 'keep-event' };
293
+ hooksByEvent.PostToolUse = [{ matcher: 'Write', hooks: [{ type: 'command', command: 'python user-post-tool-use.py' }] }];
293
294
  const expectedUserHooks = JSON.parse(JSON.stringify(hooksByEvent));
294
295
  for (const eachGroup of Object.values(expectedUserHooks).flat()) {
295
296
  if (eachGroup.hooks && eachGroup.metadata) eachGroup.hooks.shift();
@@ -306,21 +307,20 @@ test('Codex reinstall removes omitted package hooks and preserves user configura
306
307
  ['Agent|Task', 'multi_agent_v1__spawn_agent'].includes(eachGroup.matcher));
307
308
  assert.equal(allSpawnGroups.length, 2);
308
309
  migratedHooks.hooks.PreToolUse = migratedHooks.hooks.PreToolUse.filter(eachGroup => !allSpawnGroups.includes(eachGroup));
309
- const allPackagePromptCommands = migratedHooks.hooks.UserPromptSubmit
310
+ const allPackagePromptCommands = (migratedHooks.hooks.UserPromptSubmit ?? [])
310
311
  .flatMap(eachGroup => eachGroup.hooks)
311
312
  .map(eachHook => eachHook.command);
312
- assert.ok(allPackagePromptCommands.some(eachCommand => eachCommand.includes('deepen_first_prompt.py')));
313
+ assert.equal(allPackagePromptCommands.some(eachCommand => eachCommand.includes('deepen_first_prompt.py')), false);
313
314
  delete migratedHooks.hooks.UserPromptSubmit;
314
315
  const allPackageStopGroups = migratedHooks.hooks.Stop.filter(eachGroup =>
315
316
  eachGroup.hooks.some(eachHook => eachHook.command.includes('open_tasks_stop_gate.py')));
316
317
  assert.equal(allPackageStopGroups.length, 1);
317
318
  migratedHooks.hooks.Stop = migratedHooks.hooks.Stop.filter(eachGroup => !allPackageStopGroups.includes(eachGroup));
318
- const allPackagePostToolUseCommands = migratedHooks.hooks.PostToolUse
319
- .flatMap(eachGroup => eachGroup.hooks)
320
- .map(eachHook => eachHook.command);
321
- assert.equal(allPackagePostToolUseCommands.length, 1);
322
- assert.match(allPackagePostToolUseCommands[0], /owned_pr_review_loop\.py/);
323
- delete migratedHooks.hooks.PostToolUse;
319
+ const allPackagePostToolUseGroups = migratedHooks.hooks.PostToolUse.filter(eachGroup =>
320
+ eachGroup.hooks.some(eachHook => eachHook.command.includes('owned_pr_review_loop.py')));
321
+ assert.equal(allPackagePostToolUseGroups.length, 1);
322
+ assert.equal(allPackagePostToolUseGroups[0].hooks.length, 1);
323
+ migratedHooks.hooks.PostToolUse = migratedHooks.hooks.PostToolUse.filter(eachGroup => !allPackagePostToolUseGroups.includes(eachGroup));
324
324
  assert.deepEqual(migratedHooks, { enabled: false, metadata: 'keep-file', hooks: expectedUserHooks });
325
325
  assert.equal(readFileSync(configPath, 'utf8'), disabledConfig);
326
326
  const firstInstall = readFileSync(codexHooksPath, 'utf8');
@@ -367,27 +367,91 @@ test('uninstall removes the routing hook and keeps a Codex user hook', () => {
367
367
  }
368
368
  });
369
369
 
370
- test('should ship the deepen skill to Cursor and the deepen block to Codex, and remove both on uninstall', () => {
371
- const homeDirectory = mkdtempSync(join(tmpdir(), 'cdev-deepen-surfaces-'));
370
+ const RETIRED_DEEPEN_CODEX_BLOCK = '<!-- claude-dev-env deepen: start -->\nDeepen the first interactive user task.\n<!-- claude-dev-env deepen: end -->\n';
371
+
372
+ function allSettingsHookCommands(settingsPath) {
373
+ const settings = JSON.parse(readFileSync(settingsPath, 'utf8'));
374
+ return Object.values(settings.hooks ?? {})
375
+ .flatMap(allGroups => allGroups)
376
+ .flatMap(group => group.hooks ?? [])
377
+ .map(hook => String(hook.command));
378
+ }
379
+
380
+ function assertNoDeepenPieceInstalled(homeDirectory, cursorSkillPath, codexGuidancePath, settingsPath) {
381
+ assert.equal(existsSync(cursorSkillPath), false, 'the Cursor deepen skill is gone');
382
+ assert.equal(existsSync(join(homeDirectory, '.claude', 'skills', 'deepen')), false, 'the Claude deepen skill is gone');
383
+ assert.equal(existsSync(join(homeDirectory, '.claude', 'commands', 'deepen.md')), false, 'the /deepen command is gone');
384
+ const codexGuidance = existsSync(codexGuidancePath) ? readFileSync(codexGuidancePath, 'utf8') : '';
385
+ assert.doesNotMatch(codexGuidance, /claude-dev-env deepen/);
386
+ assert.equal(
387
+ allSettingsHookCommands(settingsPath).some(command => command.includes('deepen_first_prompt.py')),
388
+ false,
389
+ 'settings.json runs no deepen hook',
390
+ );
391
+ const cursorHooksPath = join(homeDirectory, DEFAULT_CURSOR_DIRECTORY_NAME, 'hooks.json');
392
+ const cursorHooksText = existsSync(cursorHooksPath) ? readFileSync(cursorHooksPath, 'utf8') : '';
393
+ assert.equal(cursorHooksText.includes('deepen_first_prompt.py'), false, 'Cursor runs no deepen hook');
394
+ const installedHookPath = join(homeDirectory, '.claude', 'hooks', 'session', 'deepen_first_prompt.py');
395
+ if (existsSync(installedHookPath)) {
396
+ assert.match(readFileSync(installedHookPath, 'utf8'), /claude-dev-env retired hook stand-in/);
397
+ }
398
+ }
399
+
400
+ test('a full install over an old deepen install removes every deepen piece, and a repeat install keeps them out', () => {
401
+ const homeDirectory = mkdtempSync(join(tmpdir(), 'cdev-deepen-retired-'));
372
402
  try {
373
- const sourceSkillPath = join(PACKAGE_DIRECTORY, '.agents', 'skills', 'deepen', 'SKILL.md');
403
+ const claudeDirectory = join(homeDirectory, '.claude');
374
404
  const cursorSkillPath = join(homeDirectory, DEFAULT_CURSOR_DIRECTORY_NAME, 'skills', 'deepen', 'SKILL.md');
375
405
  const codexGuidancePath = join(homeDirectory, '.codex', 'AGENTS.md');
376
- const manifestPath = join(homeDirectory, '.claude', '.claude-dev-env-manifest.json');
406
+ const manifestPath = join(claudeDirectory, '.claude-dev-env-manifest.json');
407
+ const settingsPath = join(claudeDirectory, 'settings.json');
408
+ const retiredPluginVersion = join(claudeDirectory, 'plugins', 'cache', 'claude-dev-env', 'deepen-first-prompt', '0.1.0');
409
+ const fakeClaudeLogPath = join(homeDirectory, 'fake-claude.log');
410
+ const orphanedMarkerPath = join(retiredPluginVersion, '.orphaned_at');
411
+ const isWindows = process.platform === 'win32';
412
+ const fakeClaudePath = join(homeDirectory, isWindows ? 'fake-claude.cmd' : 'fake-claude.sh');
413
+ writeFileSync(
414
+ fakeClaudePath,
415
+ isWindows
416
+ ? `@echo off\r\n>>"${fakeClaudeLogPath}" echo %*\r\ntype nul > "${orphanedMarkerPath}"\r\n`
417
+ : `#!/bin/sh\necho "$@" >> '${fakeClaudeLogPath}'\ntouch '${orphanedMarkerPath}'\n`,
418
+ { mode: 0o755 },
419
+ );
420
+ const environment = { CDE_CLAUDE_EXECUTABLE: fakeClaudePath };
377
421
 
378
- runInstaller(homeDirectory, []);
422
+ runInstaller(homeDirectory, [], environment);
423
+
424
+ mkdirSync(dirname(cursorSkillPath), { recursive: true });
425
+ writeFileSync(cursorSkillPath, '# deepen\n');
426
+ const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
427
+ manifest.files.push(cursorSkillPath);
428
+ writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
429
+ writeFileSync(codexGuidancePath, `${readFileSync(codexGuidancePath, 'utf8')}${RETIRED_DEEPEN_CODEX_BLOCK}`);
430
+ const settings = JSON.parse(readFileSync(settingsPath, 'utf8'));
431
+ const reminderCommand = settings.hooks.UserPromptSubmit
432
+ .flatMap(group => group.hooks)
433
+ .map(hook => hook.command)
434
+ .find(command => command.includes('skill_loaded_reminder.py'));
435
+ settings.hooks.UserPromptSubmit.push({
436
+ matcher: '',
437
+ hooks: [{ type: 'command', command: reminderCommand.replace('skill_loaded_reminder.py', 'deepen_first_prompt.py'), timeout: 10 }],
438
+ });
439
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
440
+ const cursorHooksPath = join(homeDirectory, DEFAULT_CURSOR_DIRECTORY_NAME, 'hooks.json');
441
+ const cursorHooks = JSON.parse(readFileSync(cursorHooksPath, 'utf8'));
442
+ cursorHooks.hooks.beforeSubmitPrompt = [{ command: "python3 '/old/hooks/session/deepen_first_prompt.py'", timeout: 10 }];
443
+ writeFileSync(cursorHooksPath, JSON.stringify(cursorHooks, null, 2));
444
+ mkdirSync(retiredPluginVersion, { recursive: true });
379
445
 
380
- assert.equal(readFileSync(cursorSkillPath, 'utf8'), readFileSync(sourceSkillPath, 'utf8'));
381
- assert.equal(JSON.parse(readFileSync(manifestPath, 'utf8')).files.includes(cursorSkillPath), true);
382
- const codexGuidance = readFileSync(codexGuidancePath, 'utf8');
383
- assert.match(codexGuidance, /<!-- claude-dev-env deepen: start -->/);
384
- assert.match(codexGuidance, /CDE_DEEPEN:v1/);
446
+ runInstaller(homeDirectory, [], environment);
385
447
 
386
- runInstaller(homeDirectory, ['--uninstall']);
448
+ assertNoDeepenPieceInstalled(homeDirectory, cursorSkillPath, codexGuidancePath, settingsPath);
449
+ assert.match(readFileSync(fakeClaudeLogPath, 'utf8'), /^plugin uninstall deepen-first-prompt@claude-dev-env\r?$/m);
450
+ assert.equal(existsSync(retiredPluginVersion), false, 'the retired plugin cache is gone');
451
+
452
+ runInstaller(homeDirectory, [], environment);
387
453
 
388
- assert.equal(existsSync(cursorSkillPath), false);
389
- const remainingGuidance = existsSync(codexGuidancePath) ? readFileSync(codexGuidancePath, 'utf8') : '';
390
- assert.doesNotMatch(remainingGuidance, /claude-dev-env deepen/);
454
+ assertNoDeepenPieceInstalled(homeDirectory, cursorSkillPath, codexGuidancePath, settingsPath);
391
455
  } finally {
392
456
  rmSync(homeDirectory, { recursive: true, force: true });
393
457
  }
@@ -579,7 +643,7 @@ test('a full install writes only native Cursor hooks: AGENTS.md on sessionStart
579
643
  assert.equal(gateCommands.length, 1);
580
644
  assert.deepEqual(cursorHooks.hooks.stop.filter(entry => entry.command === userStopEntry.command), [userStopEntry]);
581
645
  assert.equal(execSync(gateCommands[0], { input: '{"conversation_id": "c-1", "status": "completed"}', encoding: 'utf8' }), '');
582
- assert.deepEqual(cursorHooks.hooks.beforeSubmitPrompt, [{ command: "python3 '/old/hooks/session/deepen_first_prompt.py'", timeout: 10 }]);
646
+ assert.equal(cursorHooks.hooks.beforeSubmitPrompt, undefined);
583
647
 
584
648
  runInstaller(homeDirectory, ['--uninstall']);
585
649
  const remainingHooks = JSON.parse(readFileSync(cursorHooksPath, 'utf8'));
package/bin/install.mjs CHANGED
@@ -55,17 +55,19 @@ import {
55
55
  ALL_CODEX_NATIVE_POST_TOOL_USE_HOOK_SCRIPT_NAMES,
56
56
  } from './install-constants.mjs';
57
57
  import {
58
+ ALL_RETIRED_PLUGIN_SPECS,
58
59
  PSTACK_PLUGIN_SPEC,
59
- DEEPEN_FIRST_PROMPT_PLUGIN_SPEC,
60
60
  SUBAGENT_MODELS_PLUGIN_SPEC,
61
61
  USAGE_WRAPUP_PLUGIN_SPEC,
62
62
  installMarketplacePlugins,
63
+ removeRetiredMarketplacePlugins,
63
64
  shouldInstallMarketplacePlugin,
64
65
  } from './install-pstack-plugin.mjs';
65
66
  import {
66
67
  DEEPSTACK_PLUGIN_SPEC,
67
68
  installDeepStackForHosts,
68
69
  removeDeepStackCursorHooks,
70
+ removeRetiredCursorFirstTaskHook,
69
71
  } from './install-deepstack-plugin.mjs';
70
72
  import { seedCodexPstackModels } from './seed-codex-pstack-models.mjs';
71
73
  import {
@@ -86,7 +88,6 @@ import {
86
88
  removeCodexPackageGuidance,
87
89
  removeCodexQuestionGuidance,
88
90
  writeCodexAgentsGuidance,
89
- writeCodexDeepenGuidance,
90
91
  writeCodexPackageGuidance,
91
92
  writeCodexQuestionGuidance,
92
93
  } from './codex-skill-load-block.mjs';
@@ -248,8 +249,8 @@ export const CORE_SKILLS = [
248
249
  'issue-tracker',
249
250
  'task-build',
250
251
  'eli5',
251
- 'deepen',
252
252
  'efficient-review',
253
+ 'pr-visual',
253
254
  ];
254
255
 
255
256
  export function collectPackageSourceConflicts(packageDirectory) {
@@ -1299,6 +1300,7 @@ export const RETIRED_HOOK_REGISTRATION_RELATIVE_PATHS = new Set([
1299
1300
  'blocking/artifact_look_gate.py',
1300
1301
  'blocking/session_title_stop_gate.py',
1301
1302
  'session/issue_tracker_session_starter.py',
1303
+ 'session/deepen_first_prompt.py',
1302
1304
  ]);
1303
1305
 
1304
1306
  export const MOVED_HOOK_RELATIVE_PATHS = new Set([
@@ -1998,7 +2000,7 @@ export function pruneRetiredHookEntriesFromSettings(
1998
2000
  return removedCount;
1999
2001
  }
2000
2002
 
2001
- const RETIRED_HOOK_STAND_IN_MARKER = 'claude-dev-env retired hook stand-in';
2003
+ export const RETIRED_HOOK_STAND_IN_MARKER = 'claude-dev-env retired hook stand-in';
2002
2004
 
2003
2005
  const RETIRED_HOOK_STAND_IN_SOURCE = `"""${RETIRED_HOOK_STAND_IN_MARKER}.
2004
2006
 
@@ -2571,10 +2573,12 @@ function pruneStaleFilesAcrossManagedRoots(priorInstalledFiles, currentInstalled
2571
2573
  }
2572
2574
  const cursorInstallDirectory = INSTALL_ROOT_RESOLUTION.cursorInstallDirectory;
2573
2575
  const retiredCursorSyncManifestPath = join(cursorInstallDirectory, '.sync-manifest.json');
2574
- const isRetiredCursorRuleFile = priorFile => resolve(priorFile) === retiredCursorSyncManifestPath
2575
- || isInsideDirectory(resolve(priorFile), INSTALL_ROOT_RESOLUTION.cursorRulesInstallDirectory);
2576
+ const retiredCursorSkillsDirectory = join(cursorInstallDirectory, MANAGED_SKILLS_DIRECTORY_NAME);
2577
+ const isRetiredCursorFile = priorFile => resolve(priorFile) === retiredCursorSyncManifestPath
2578
+ || isInsideDirectory(resolve(priorFile), INSTALL_ROOT_RESOLUTION.cursorRulesInstallDirectory)
2579
+ || isInsideDirectory(resolve(priorFile), retiredCursorSkillsDirectory);
2576
2580
  const retiredCursorRulesOutcome = pruneStaleInstalledFiles(
2577
- priorInstalledFiles?.filter(isRetiredCursorRuleFile) ?? null,
2581
+ priorInstalledFiles?.filter(isRetiredCursorFile) ?? null,
2578
2582
  currentInstalledFiles,
2579
2583
  cursorInstallDirectory,
2580
2584
  join(backupRoot, 'cursor'),
@@ -3015,23 +3019,6 @@ function executeInstallPlanMutations(plan, transactionHelpers) {
3015
3019
  }
3016
3020
  summary.skills = { created: skillsCreated, updated: skillsUpdated, pruned: 0, paths: skillPaths };
3017
3021
  allInstalledFiles.push(...skillPaths);
3018
- if (copiedSkillNames.has('deepen')) {
3019
- for (const sourceRoot of allSourceRoots) {
3020
- const deepenSourceDirectory = join(
3021
- resolvePackageManagedDirectory(sourceRoot, MANAGED_SKILLS_DIRECTORY_NAME),
3022
- 'deepen',
3023
- );
3024
- if (!existsSync(deepenSourceDirectory)) continue;
3025
- const cursorDeepenDirectory = join(
3026
- INSTALL_ROOT_RESOLUTION.cursorInstallDirectory,
3027
- 'skills',
3028
- 'deepen',
3029
- );
3030
- const cursorSkillStats = copyTree(deepenSourceDirectory, cursorDeepenDirectory);
3031
- allInstalledFiles.push(...cursorSkillStats.paths);
3032
- break;
3033
- }
3034
- }
3035
3022
  if (!selectedGroups) {
3036
3023
  summary.retiredSessionContinuity = {
3037
3024
  changedPaths: removeRetiredSessionContinuityHooks(),
@@ -3088,12 +3075,6 @@ function executeInstallPlanMutations(plan, transactionHelpers) {
3088
3075
  claudeRoot: CLAUDE_HOME,
3089
3076
  codexHome: INSTALL_ROOT_RESOLUTION.codexHomeDirectory,
3090
3077
  cursorDirectory: INSTALL_ROOT_RESOLUTION.cursorInstallDirectory,
3091
- firstTaskHookPath: join(
3092
- INSTALL_ROOT_RESOLUTION.hooksInstallDirectory,
3093
- 'session',
3094
- 'deepen_first_prompt.py',
3095
- ),
3096
- pythonCommand,
3097
3078
  formatPathArgument: commandArgumentFromPath,
3098
3079
  });
3099
3080
  summary.deepStackPlugin = deepStackPlugin;
@@ -3106,10 +3087,27 @@ function executeInstallPlanMutations(plan, transactionHelpers) {
3106
3087
  allActionNeededLines.push(`DeepStack (cursor): failed — ${cursorOutcome.warning}`);
3107
3088
  }
3108
3089
  }
3090
+ if (!selectedGroups) {
3091
+ const retiredCursorHooksPath = removeRetiredCursorFirstTaskHook(
3092
+ INSTALL_ROOT_RESOLUTION.cursorInstallDirectory,
3093
+ );
3094
+ if (retiredCursorHooksPath) {
3095
+ console.log(` Retired first-task hook removed from ${retiredCursorHooksPath}`);
3096
+ }
3097
+ const retiredPlugins = removeRetiredMarketplacePlugins(ALL_RETIRED_PLUGIN_SPECS, {
3098
+ claudeRoot: CLAUDE_HOME,
3099
+ });
3100
+ summary.retiredPlugins = retiredPlugins;
3101
+ for (const eachIdentifier of retiredPlugins.removedIdentifiers) {
3102
+ console.log(` Retired plugin uninstalled: ${eachIdentifier}`);
3103
+ }
3104
+ for (const eachFailure of retiredPlugins.failedRemovals) {
3105
+ console.warn(` Warning: retired plugin ${eachFailure.pluginIdentifier} was not uninstalled: ${eachFailure.detail}`);
3106
+ }
3107
+ }
3109
3108
  const allRepositoryPluginSpecs = [
3110
3109
  USAGE_WRAPUP_PLUGIN_SPEC,
3111
3110
  SUBAGENT_MODELS_PLUGIN_SPEC,
3112
- DEEPEN_FIRST_PROMPT_PLUGIN_SPEC,
3113
3111
  ].filter(eachSpec => shouldInstallMarketplacePlugin(eachSpec));
3114
3112
  if (!selectedGroups && allRepositoryPluginSpecs.length > 0) {
3115
3113
  const repositoryPlugins = installMarketplacePlugins(allRepositoryPluginSpecs, {
@@ -3133,10 +3131,7 @@ function executeInstallPlanMutations(plan, transactionHelpers) {
3133
3131
  readFileSync(join(PACKAGE_ROOT, 'rules', 'question-presentation.md'), 'utf8'),
3134
3132
  );
3135
3133
  if (questionGuidancePath) allCodexGuidancePaths.push(questionGuidancePath);
3136
- const deepenGuidancePath = writeCodexDeepenGuidance(
3137
- INSTALL_ROOT_RESOLUTION.codexHomeDirectory,
3138
- );
3139
- if (deepenGuidancePath) allCodexGuidancePaths.push(deepenGuidancePath);
3134
+ removeCodexDeepenGuidance(INSTALL_ROOT_RESOLUTION.codexHomeDirectory);
3140
3135
  const solPromptPath = installCodexSolPrompt(
3141
3136
  INSTALL_ROOT_RESOLUTION.codexHomeDirectory,
3142
3137
  join(PACKAGE_ROOT, SOL_PROMPT_DIRECTORY_NAME, SOL_PROMPT_FILE_NAME),
@@ -3686,7 +3681,6 @@ Usage:
3686
3681
  npx ${PACKAGE_NAME} --no-deepstack Full install without the DeepStack plugin (also CDE_INSTALL_DEEPSTACK=0)
3687
3682
  npx ${PACKAGE_NAME} --no-usage-wrapup Full install without the usage-wrapup plugin (also CDE_INSTALL_USAGE_WRAPUP=0)
3688
3683
  npx ${PACKAGE_NAME} --no-subagent-models Full install without the subagent-models plugin (also CDE_INSTALL_SUBAGENT_MODELS=0)
3689
- npx ${PACKAGE_NAME} --no-deepen-first-prompt Full install without the deepen-first-prompt plugin (also CDE_INSTALL_DEEPEN_FIRST_PROMPT=0)
3690
3684
  npx ${PACKAGE_NAME} --uninstall Remove installed files from the selected root
3691
3685
  npx ${PACKAGE_NAME} --help Show this help
3692
3686
 
@@ -0,0 +1,40 @@
1
+ import { strict as assert } from 'node:assert';
2
+ import { execFileSync } from 'node:child_process';
3
+ import { existsSync, mkdtempSync, readFileSync, realpathSync, rmSync } from 'node:fs';
4
+ import { tmpdir } from 'node:os';
5
+ import { dirname, join } from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { test } from 'node:test';
8
+
9
+ const PACKAGE_DIRECTORY = dirname(dirname(fileURLToPath(import.meta.url)));
10
+ const SKILL_PATH_SEGMENTS = ['.agents', 'skills', 'pr-visual'];
11
+ const REQUIRED_FILES = ['SKILL.md', 'scripts/collect.py', 'scripts/render.py', 'scripts/metrics.py', 'scripts/verify.py', 'scripts/visual_config/config/constants.py', 'assets/viewer.html', 'assets/icons.symbols', 'fixtures/bar.scene.json', 'fixtures/integrated.scene.json', 'references/formats.md'];
12
+ const INSTALL_MODES = [[], ['--only', 'core']];
13
+ const NPM_EXECUTABLE = process.platform === 'win32' ? 'npm.cmd' : 'npm';
14
+
15
+ test('packed full and core installs ship the runnable PR visual skill to the shared agents home', () => {
16
+ const sandbox = mkdtempSync(join(tmpdir(), 'cde-pr-visual-'));
17
+ try {
18
+ const packed = JSON.parse(execFileSync(NPM_EXECUTABLE, ['pack', '--json', '--ignore-scripts', '--offline', '--cache', join(sandbox, 'npm-cache'), '--pack-destination', sandbox], { cwd: PACKAGE_DIRECTORY, encoding: 'utf8', shell: process.platform === 'win32' }));
19
+ execFileSync('tar', ['-xzf', join(sandbox, packed[0].filename), '-C', sandbox]);
20
+ const packaged = join(sandbox, 'package');
21
+ for (const [eachIndex, eachArguments] of INSTALL_MODES.entries()) {
22
+ const homeDirectory = join(sandbox, `home-${eachIndex}`);
23
+ execFileSync(process.execPath, [join(packaged, 'bin/install.mjs'), ...eachArguments], {
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' },
26
+ });
27
+ const installed = join(homeDirectory, ...SKILL_PATH_SEGMENTS);
28
+ for (const eachFile of REQUIRED_FILES) assert.deepEqual(readFileSync(join(installed, eachFile)), readFileSync(join(packaged, ...SKILL_PATH_SEGMENTS, eachFile)));
29
+ assert.equal(realpathSync(join(homeDirectory, '.claude/skills/pr-visual')), realpathSync(installed));
30
+ const manifest = JSON.parse(readFileSync(join(homeDirectory, '.claude/.claude-dev-env-manifest.json'), 'utf8'));
31
+ assert.ok(manifest.skills.includes('pr-visual'));
32
+ const visual = join(sandbox, `visual-${eachIndex}.html`);
33
+ execFileSync(process.platform === 'win32' ? 'python' : 'python3', [join(installed, 'scripts/render.py'), join(installed, 'fixtures/integrated.scene.json'), '--out', visual]);
34
+ assert.ok(existsSync(visual));
35
+ assert.match(readFileSync(visual, 'utf8'), /Duration \(ms\)/);
36
+ }
37
+ } finally {
38
+ rmSync(sandbox, { recursive: true, force: true });
39
+ }
40
+ });
@@ -35,12 +35,11 @@ test('reinstall drops the retired style reminder and keeps one skill reminder ho
35
35
  mergeHooksIntoSettings(settings, hooksConfig, 'C:/Users/example/.claude', 'python');
36
36
 
37
37
  const userPromptHooks = settings.hooks.UserPromptSubmit.flatMap(eachGroup => eachGroup.hooks);
38
- assert.equal(userPromptHooks.length, 5);
38
+ assert.equal(userPromptHooks.length, 4);
39
39
  assert.equal(userPromptHooks[0].command, userCommand);
40
40
  assert.match(userPromptHooks[1].command, /session\/skill_loaded_reminder\.py$/);
41
- assert.match(userPromptHooks[2].command, /session\/deepen_first_prompt\.py$/);
42
- assert.match(userPromptHooks[3].command, /lifecycle\/nested_project_hooks\.py$/);
43
- assert.match(userPromptHooks[4].command, /blocking\/chat_reply_gate\.py$/);
41
+ assert.match(userPromptHooks[2].command, /lifecycle\/nested_project_hooks\.py$/);
42
+ assert.match(userPromptHooks[3].command, /blocking\/chat_reply_gate\.py$/);
44
43
  assert.ok(userPromptHooks.every(eachHook => !eachHook.command.includes('style_reminder_prompt')));
45
44
 
46
45
  const firstMerge = JSON.stringify(settings);
@@ -266,7 +266,6 @@ 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_DEEPEN_FIRST_PROMPT: '0',
270
269
  HOME: homeDirectory,
271
270
  USERPROFILE: homeDirectory,
272
271
  GIT_CONFIG_GLOBAL: join(homeDirectory, '.gitconfig'),
@@ -28,7 +28,6 @@ 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_DEEPEN_FIRST_PROMPT: '0',
32
31
  HOME: homeDirectory,
33
32
  USERPROFILE: homeDirectory,
34
33
  CODEX_HOME: join(homeDirectory, '.codex'),
@@ -186,7 +185,6 @@ test('a successful pstack install omits the retired skill block and gains the qu
186
185
  CDE_INSTALL_DEEPSTACK: '0',
187
186
  CDE_INSTALL_USAGE_WRAPUP: '0',
188
187
  CDE_INSTALL_SUBAGENT_MODELS: '0',
189
- CDE_INSTALL_DEEPEN_FIRST_PROMPT: '0',
190
188
  CDE_CODEX_EXECUTABLE: commandPath,
191
189
  CDE_CLAUDE_EXECUTABLE: commandPath,
192
190
  });
@@ -216,7 +214,6 @@ test('enabling pstack after a pstack-off install preserves question guidance', (
216
214
  CDE_INSTALL_DEEPSTACK: '0',
217
215
  CDE_INSTALL_USAGE_WRAPUP: '0',
218
216
  CDE_INSTALL_SUBAGENT_MODELS: '0',
219
- CDE_INSTALL_DEEPEN_FIRST_PROMPT: '0',
220
217
  CDE_CODEX_EXECUTABLE: commandPath,
221
218
  CDE_CLAUDE_EXECUTABLE: commandPath,
222
219
  });
@@ -247,7 +244,6 @@ test('a failed pstack transition restores question-only guidance and removes its
247
244
  CDE_INSTALL_DEEPSTACK: '0',
248
245
  CDE_INSTALL_USAGE_WRAPUP: '0',
249
246
  CDE_INSTALL_SUBAGENT_MODELS: '0',
250
- CDE_INSTALL_DEEPEN_FIRST_PROMPT: '0',
251
247
  CDE_CODEX_EXECUTABLE: commandPath,
252
248
  CDE_CLAUDE_EXECUTABLE: commandPath,
253
249
  CLAUDE_DEV_ENV_INSTALL_FAULT: 'after_file_staging',
@@ -70,7 +70,6 @@ function runInstallerInSandbox(sandboxHome, installerArguments = []) {
70
70
  CDE_INSTALL_DEEPSTACK: '0',
71
71
  CDE_INSTALL_USAGE_WRAPUP: '0',
72
72
  CDE_INSTALL_SUBAGENT_MODELS: '0',
73
- CDE_INSTALL_DEEPEN_FIRST_PROMPT: '0',
74
73
  HOME: sandboxHome,
75
74
  USERPROFILE: sandboxHome,
76
75
  GIT_CONFIG_GLOBAL: gitConfigGlobal,
@@ -34,7 +34,6 @@ function installEnvironment(homeDirectory) {
34
34
  CDE_INSTALL_DEEPSTACK: '0',
35
35
  CDE_INSTALL_USAGE_WRAPUP: '0',
36
36
  CDE_INSTALL_SUBAGENT_MODELS: '0',
37
- CDE_INSTALL_DEEPEN_FIRST_PROMPT: '0',
38
37
  };
39
38
  }
40
39
 
@@ -57,6 +57,7 @@ import {
57
57
  } from './install.mjs';
58
58
  import { EVER_SHIPPED_SKILL_NAMES } from './ever-shipped-skills.mjs';
59
59
  import {
60
+ DEEPEN_GUIDANCE_BLOCK_END,
60
61
  DEEPEN_GUIDANCE_BLOCK_START,
61
62
  PACKAGE_GUIDANCE_BLOCK_END,
62
63
  PACKAGE_GUIDANCE_BLOCK_START,
@@ -257,9 +258,9 @@ test('CORE_SKILLS ships ELI5 as the leaf presentation skill', () => {
257
258
  assert.equal(INSTALL_GROUPS.core.skills.includes('eli5'), true);
258
259
  });
259
260
 
260
- test('CORE_SKILLS ships deepen so the first-task skill installs with core', () => {
261
- assert.ok(CORE_SKILLS.includes('deepen'), 'deepen must be in CORE_SKILLS');
262
- assert.equal(INSTALL_GROUPS.core.skills.includes('deepen'), true);
261
+ test('CORE_SKILLS leaves out the retired deepen skill', () => {
262
+ assert.equal(CORE_SKILLS.includes('deepen'), false);
263
+ assert.equal(INSTALL_GROUPS.core.skills.includes('deepen'), false);
263
264
  });
264
265
 
265
266
  test('CORE_SKILLS ships efficient-review so a core install includes the skill', () => {
@@ -1243,6 +1244,7 @@ test('retired hook registrations stay managed so reinstall removes them', () =>
1243
1244
  'blocking/artifact_look_gate.py',
1244
1245
  'blocking/session_title_stop_gate.py',
1245
1246
  'session/issue_tracker_session_starter.py',
1247
+ 'session/deepen_first_prompt.py',
1246
1248
  ]);
1247
1249
  const shippedHooks = JSON.parse(
1248
1250
  readFileSync(new URL('../hooks/hooks.json', import.meta.url), 'utf8')
@@ -3048,7 +3050,6 @@ test('a failed update preserves an existing skills lookup pointer', () => {
3048
3050
  CDE_INSTALL_DEEPSTACK: '0',
3049
3051
  CDE_INSTALL_USAGE_WRAPUP: '0',
3050
3052
  CDE_INSTALL_SUBAGENT_MODELS: '0',
3051
- CDE_INSTALL_DEEPEN_FIRST_PROMPT: '0',
3052
3053
  };
3053
3054
  const argumentsForCoreInstall = [PSTACK_TEST_INSTALLER_PATH, '--only', 'core'];
3054
3055
  const firstRun = spawnSync(process.execPath, argumentsForCoreInstall, {
@@ -3103,7 +3104,6 @@ function runPstackInstaller(homeDirectory, extraArguments, environmentOverrides
3103
3104
  CDE_INSTALL_DEEPSTACK: '0',
3104
3105
  CDE_INSTALL_USAGE_WRAPUP: '0',
3105
3106
  CDE_INSTALL_SUBAGENT_MODELS: '0',
3106
- CDE_INSTALL_DEEPEN_FIRST_PROMPT: '0',
3107
3107
  ...environmentOverrides,
3108
3108
  },
3109
3109
  });
@@ -3213,10 +3213,7 @@ test('a full install adds DeepStack for Claude, Codex, and Cursor', t => {
3213
3213
  hooks.hooks.sessionStart.filter(entry => entry.command.includes('session-start.sh')).length,
3214
3214
  1,
3215
3215
  );
3216
- assert.equal(
3217
- hooks.hooks.beforeSubmitPrompt.filter(entry => entry.command.includes('deepen_first_prompt.py')).length,
3218
- 1,
3219
- );
3216
+ assert.equal(JSON.stringify(hooks).includes('deepen_first_prompt.py'), false, 'no retired first-task hook');
3220
3217
  assert.equal(JSON.stringify(hooks).includes('"hooks":[{'), false, 'no Claude-style group entries');
3221
3218
  const sheet = readFileSync(join(sandbox.homeDirectory, '.codex', 'deepstack-models.md'), 'utf8');
3222
3219
  assert.match(sheet, /^session hook: on$/m);
@@ -3228,7 +3225,8 @@ test('a repeat install preserves Codex pstack configuration', t => {
3228
3225
  runPstackInstaller(sandbox.homeDirectory, [], sandbox.environment);
3229
3226
  writeFileSync(
3230
3227
  join(codexHome, 'AGENTS.md'),
3231
- `${SKILL_LOAD_BLOCK_START}\n${STALE_SKILL_LOAD_SENTENCE}\n${SKILL_LOAD_BLOCK_END}\nCustom Codex guidance\n`,
3228
+ `${SKILL_LOAD_BLOCK_START}\n${STALE_SKILL_LOAD_SENTENCE}\n${SKILL_LOAD_BLOCK_END}\nCustom Codex guidance\n`
3229
+ + `${DEEPEN_GUIDANCE_BLOCK_START}\nDeepen the first interactive user task.\n${DEEPEN_GUIDANCE_BLOCK_END}\n`,
3232
3230
  );
3233
3231
  writeFileSync(join(codexHome, 'pstack-models.md'), 'session hook: off\n');
3234
3232
 
@@ -3238,7 +3236,7 @@ test('a repeat install preserves Codex pstack configuration', t => {
3238
3236
  assert.ok(codexGuidance.startsWith('Custom Codex guidance\n'));
3239
3237
  assertOmitsSkillLoadSentence(codexGuidance);
3240
3238
  assert.ok(codexGuidance.includes(QUESTION_PRESENTATION_BLOCK_START));
3241
- assert.ok(codexGuidance.includes(DEEPEN_GUIDANCE_BLOCK_START));
3239
+ assert.equal(codexGuidance.includes(DEEPEN_GUIDANCE_BLOCK_START), false);
3242
3240
  assert.equal(readFileSync(join(codexHome, 'pstack-models.md'), 'utf8'), 'session hook: off\n');
3243
3241
  });
3244
3242
 
@@ -3322,7 +3320,7 @@ test('a fresh full install writes the package guidance into Codex AGENTS.md', t
3322
3320
  assertHoldsPackageGuidance(codexGuidance);
3323
3321
  assertOmitsSkillLoadSentence(codexGuidance);
3324
3322
  assert.ok(codexGuidance.includes(QUESTION_PRESENTATION_BLOCK_START));
3325
- assert.ok(codexGuidance.includes(DEEPEN_GUIDANCE_BLOCK_START));
3323
+ assert.equal(codexGuidance.includes(DEEPEN_GUIDANCE_BLOCK_START), false);
3326
3324
  });
3327
3325
 
3328
3326
  test('--no-pstack writes package and question guidance without the skill-load block', t => {
@@ -3405,7 +3403,7 @@ test('a pstack install after a --no-pstack install seeds the Codex model sheet',
3405
3403
  assertOmitsSkillLoadSentence(codexGuidance);
3406
3404
  assertHoldsPackageGuidance(codexGuidance);
3407
3405
  assert.ok(codexGuidance.includes(QUESTION_PRESENTATION_BLOCK_START));
3408
- assert.ok(codexGuidance.includes(DEEPEN_GUIDANCE_BLOCK_START));
3406
+ assert.equal(codexGuidance.includes(DEEPEN_GUIDANCE_BLOCK_START), false);
3409
3407
  });
3410
3408
 
3411
3409
  const USAGE_WRAPUP_CLAUDE_COMMANDS = Object.freeze([
@@ -3483,18 +3481,16 @@ test('the help output names the usage-wrapup opt-out beside the pstack one', ()
3483
3481
 
3484
3482
  assert.equal(helpRun.status, 0, helpRun.stderr);
3485
3483
  assert.match(helpRun.stdout, /--no-pstack .*\n.*--no-deepstack .*CDE_INSTALL_DEEPSTACK=0.*\n.*--no-usage-wrapup .*CDE_INSTALL_USAGE_WRAPUP=0/);
3486
- assert.match(helpRun.stdout, /--no-deepen-first-prompt .*CDE_INSTALL_DEEPEN_FIRST_PROMPT=0/);
3484
+ assert.doesNotMatch(helpRun.stdout, /--no-deepen-first-prompt/);
3487
3485
  });
3488
3486
 
3489
3487
  const REPOSITORY_PLUGIN_CLAUDE_COMMANDS = Object.freeze([
3490
3488
  'claude plugin uninstall usage-wrapup@claude-dev-env',
3491
3489
  'claude plugin uninstall subagent-models@claude-dev-env',
3492
- 'claude plugin uninstall deepen-first-prompt@claude-dev-env',
3493
3490
  'claude plugin marketplace remove claude-dev-env',
3494
- 'claude plugin marketplace add jl-cmd-projects/claude-dev-env --sparse .claude-plugin packages/usage-wrapup packages/subagent-models packages/deepen-first-prompt',
3491
+ 'claude plugin marketplace add jl-cmd-projects/claude-dev-env --sparse .claude-plugin packages/usage-wrapup packages/subagent-models',
3495
3492
  'claude plugin install usage-wrapup@claude-dev-env',
3496
3493
  'claude plugin install subagent-models@claude-dev-env',
3497
- 'claude plugin install deepen-first-prompt@claude-dev-env',
3498
3494
  ]);
3499
3495
 
3500
3496
  test('should install subagent-models beside usage-wrapup with one marketplace add on a full install', t => {
@@ -3504,13 +3500,12 @@ test('should install subagent-models beside usage-wrapup with one marketplace ad
3504
3500
  ...sandbox.environment,
3505
3501
  CDE_INSTALL_USAGE_WRAPUP: '1',
3506
3502
  CDE_INSTALL_SUBAGENT_MODELS: '1',
3507
- CDE_INSTALL_DEEPEN_FIRST_PROMPT: '1',
3508
3503
  });
3509
3504
 
3510
3505
  assert.deepEqual(usageWrapupCommands(sandbox.recordedCommands()), REPOSITORY_PLUGIN_CLAUDE_COMMANDS);
3511
3506
  assert.match(installerOutput, /Usage-wrapup \(claude\): installed/);
3512
3507
  assert.match(installerOutput, /Subagent-models \(claude\): installed/);
3513
- assert.match(installerOutput, /Deepen-first-prompt \(claude\): installed/);
3508
+ assert.doesNotMatch(installerOutput, /Deepen-first-prompt \(/);
3514
3509
  });
3515
3510
 
3516
3511
  for (const [caseName, extraArguments, environmentOverrides] of [
@@ -3534,27 +3529,6 @@ for (const [caseName, extraArguments, environmentOverrides] of [
3534
3529
  });
3535
3530
  }
3536
3531
 
3537
- for (const [caseName, extraArguments, environmentOverrides] of [
3538
- ['--no-deepen-first-prompt', ['--no-deepen-first-prompt'], { CDE_INSTALL_DEEPEN_FIRST_PROMPT: '1' }],
3539
- ['CDE_INSTALL_DEEPEN_FIRST_PROMPT=0', [], { CDE_INSTALL_DEEPEN_FIRST_PROMPT: '0' }],
3540
- ['an --only run', ['--only', 'core'], { CDE_INSTALL_DEEPEN_FIRST_PROMPT: '1' }],
3541
- ]) {
3542
- test(`should skip deepen-first-prompt on ${caseName}`, t => {
3543
- const sandbox = pstackPluginSandbox(t);
3544
-
3545
- const installerOutput = runPstackInstaller(sandbox.homeDirectory, extraArguments, {
3546
- ...sandbox.environment,
3547
- ...environmentOverrides,
3548
- });
3549
-
3550
- assert.equal(
3551
- sandbox.recordedCommands().some(eachCommand => eachCommand.includes('deepen-first-prompt')),
3552
- false,
3553
- );
3554
- assert.doesNotMatch(installerOutput, /Deepen-first-prompt \(/);
3555
- });
3556
- }
3557
-
3558
3532
  test('should name the subagent-models opt-out in the help output', () => {
3559
3533
  const helpRun = spawnSync(process.execPath, [PSTACK_TEST_INSTALLER_PATH, '--help'], {
3560
3534
  encoding: 'utf8',
@@ -3649,7 +3623,6 @@ function installWithGlobalPrefix(context, globalPrefix) {
3649
3623
  CDE_INSTALL_DEEPSTACK: '0',
3650
3624
  CDE_INSTALL_USAGE_WRAPUP: '0',
3651
3625
  CDE_INSTALL_SUBAGENT_MODELS: '0',
3652
- CDE_INSTALL_DEEPEN_FIRST_PROMPT: '0',
3653
3626
  HOME: homeDirectory,
3654
3627
  USERPROFILE: homeDirectory,
3655
3628
  APPDATA: join(homeDirectory, 'AppData', 'Roaming'),
@@ -3706,7 +3679,6 @@ test('install adds the open-tasks Stop gate to every profile with its own settin
3706
3679
  CDE_INSTALL_DEEPSTACK: '0',
3707
3680
  CDE_INSTALL_USAGE_WRAPUP: '0',
3708
3681
  CDE_INSTALL_SUBAGENT_MODELS: '0',
3709
- CDE_INSTALL_DEEPEN_FIRST_PROMPT: '0',
3710
3682
  HOME: homeDirectory,
3711
3683
  USERPROFILE: homeDirectory,
3712
3684
  CODEX_HOME: join(homeDirectory, '.codex'),
@@ -3749,7 +3721,6 @@ test('a profile settings.json that is not valid JSON is left alone and named und
3749
3721
  CDE_INSTALL_DEEPSTACK: '0',
3750
3722
  CDE_INSTALL_USAGE_WRAPUP: '0',
3751
3723
  CDE_INSTALL_SUBAGENT_MODELS: '0',
3752
- CDE_INSTALL_DEEPEN_FIRST_PROMPT: '0',
3753
3724
  HOME: homeDirectory,
3754
3725
  USERPROFILE: homeDirectory,
3755
3726
  CODEX_HOME: join(homeDirectory, '.codex'),
@@ -3795,7 +3766,6 @@ test('uninstall stops before changing anything while a profile settings.json tha
3795
3766
  CDE_INSTALL_DEEPSTACK: '0',
3796
3767
  CDE_INSTALL_USAGE_WRAPUP: '0',
3797
3768
  CDE_INSTALL_SUBAGENT_MODELS: '0',
3798
- CDE_INSTALL_DEEPEN_FIRST_PROMPT: '0',
3799
3769
  HOME: homeDirectory,
3800
3770
  USERPROFILE: homeDirectory,
3801
3771
  CODEX_HOME: join(homeDirectory, '.codex'),