claude-dev-env 8.85.0 → 8.85.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.
|
@@ -3,9 +3,6 @@ import { dirname, join, resolve } from 'node:path';
|
|
|
3
3
|
|
|
4
4
|
export const SKILL_LOAD_BLOCK_START = '<!-- claude-dev-env skill load: start -->';
|
|
5
5
|
export const SKILL_LOAD_BLOCK_END = '<!-- claude-dev-env skill load: end -->';
|
|
6
|
-
export const SKILL_LOAD_INSTRUCTION = 'Load the pstack:poteto-mode skill before your first tool call or reply: '
|
|
7
|
-
+ 'open its SKILL.md from your skills list and follow it. This binds every Codex agent, '
|
|
8
|
-
+ 'including a helper started with spawn_agent, whatever its task message says.';
|
|
9
6
|
export const PACKAGE_GUIDANCE_BLOCK_START = '<!-- claude-dev-env package guidance: start -->';
|
|
10
7
|
export const PACKAGE_GUIDANCE_BLOCK_END = '<!-- claude-dev-env package guidance: end -->';
|
|
11
8
|
export const QUESTION_PRESENTATION_BLOCK_START = '<!-- claude-dev-env question presentation: start -->';
|
|
@@ -39,17 +36,24 @@ function withBlockReplaced(guidanceText, blockStart, blockEnd, block) {
|
|
|
39
36
|
}
|
|
40
37
|
|
|
41
38
|
/**
|
|
42
|
-
* Return
|
|
39
|
+
* Return guidance text with every complete skill-load block removed.
|
|
43
40
|
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
* the text is replaced where it stands; otherwise the block goes first.
|
|
41
|
+
* When a block is the start of the remaining text, one following blank line is
|
|
42
|
+
* removed with it. A start marker with no end marker stays.
|
|
47
43
|
*/
|
|
48
|
-
export function
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
44
|
+
export function withoutSkillLoadBlock(guidanceText) {
|
|
45
|
+
let remainingText = guidanceText;
|
|
46
|
+
let removedBlockCount = 0;
|
|
47
|
+
while (remainingText.includes(SKILL_LOAD_BLOCK_START)) {
|
|
48
|
+
const blockStartsAtTop = remainingText.startsWith(SKILL_LOAD_BLOCK_START);
|
|
49
|
+
const replacedText = withBlockReplaced(remainingText, SKILL_LOAD_BLOCK_START, SKILL_LOAD_BLOCK_END, '');
|
|
50
|
+
if (replacedText === null || replacedText === remainingText) break;
|
|
51
|
+
removedBlockCount += 1;
|
|
52
|
+
remainingText = blockStartsAtTop && replacedText.startsWith('\n')
|
|
53
|
+
? replacedText.slice(1)
|
|
54
|
+
: replacedText;
|
|
55
|
+
}
|
|
56
|
+
return removedBlockCount === 0 ? guidanceText : remainingText;
|
|
53
57
|
}
|
|
54
58
|
|
|
55
59
|
function withPackageGuidanceBlock(guidanceText, packageGuidanceText) {
|
|
@@ -84,7 +88,7 @@ function writeCodexGuidanceFile(codexHome, allPackageGuidancePaths, transformGui
|
|
|
84
88
|
const isPackageGuidanceLink = agentsEntry?.isSymbolicLink() ?? false;
|
|
85
89
|
if (isPackageGuidanceLink && !linksToPackageGuidance(agentsPath, allPackageGuidancePaths)) return null;
|
|
86
90
|
const currentText = agentsEntry && !isPackageGuidanceLink ? readFileSync(agentsPath, 'utf8') : '';
|
|
87
|
-
const updatedText = transformGuidance(currentText);
|
|
91
|
+
const updatedText = transformGuidance(withoutSkillLoadBlock(currentText));
|
|
88
92
|
if (!isPackageGuidanceLink && updatedText === currentText) return null;
|
|
89
93
|
mkdirSync(codexHome, { recursive: true });
|
|
90
94
|
if (isPackageGuidanceLink) unlinkSync(agentsPath);
|
|
@@ -93,29 +97,24 @@ function writeCodexGuidanceFile(codexHome, allPackageGuidancePaths, transformGui
|
|
|
93
97
|
}
|
|
94
98
|
|
|
95
99
|
/**
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
* The skill-load block goes first, and the package-guidance block holds the
|
|
99
|
-
* current guidance text. A symbolic link that points at the package guidance
|
|
100
|
-
* (the shared agents-home copy, or the retired copy under the Claude home) is
|
|
101
|
-
* replaced by a regular file holding both blocks, so Codex keeps both after
|
|
102
|
-
* the package moves its guidance. A link to any other file is left alone.
|
|
100
|
+
* Remove a skill-load block and write package guidance into CODEX_HOME/AGENTS.md.
|
|
103
101
|
*
|
|
104
|
-
*
|
|
102
|
+
* Link handling matches writeCodexPackageGuidance. Returns the file path when
|
|
103
|
+
* the file changed, and null otherwise.
|
|
105
104
|
*/
|
|
106
105
|
export function writeCodexAgentsGuidance(codexHome, packageGuidanceText, allPackageGuidancePaths) {
|
|
107
|
-
return
|
|
108
|
-
codexHome,
|
|
109
|
-
allPackageGuidancePaths,
|
|
110
|
-
currentText => withPackageGuidanceBlock(withSkillLoadBlock(currentText), packageGuidanceText),
|
|
111
|
-
);
|
|
106
|
+
return writeCodexPackageGuidance(codexHome, packageGuidanceText, allPackageGuidancePaths);
|
|
112
107
|
}
|
|
113
108
|
|
|
114
109
|
/**
|
|
115
110
|
* Keep CODEX_HOME/AGENTS.md carrying the package guidance, with no skill-load block.
|
|
116
111
|
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
112
|
+
* An existing skill-load block is removed. A symbolic link that points at the
|
|
113
|
+
* package guidance, the shared agents-home copy or the retired copy under the
|
|
114
|
+
* Claude home, is replaced by a regular file. A link to any other file is left
|
|
115
|
+
* alone.
|
|
116
|
+
*
|
|
117
|
+
* Returns the file path when the file changed, and null otherwise.
|
|
119
118
|
*/
|
|
120
119
|
export function writeCodexPackageGuidance(codexHome, packageGuidanceText, allPackageGuidancePaths) {
|
|
121
120
|
return writeCodexGuidanceFile(
|
|
@@ -10,11 +10,10 @@ import {
|
|
|
10
10
|
QUESTION_PRESENTATION_BLOCK_START,
|
|
11
11
|
SKILL_LOAD_BLOCK_END,
|
|
12
12
|
SKILL_LOAD_BLOCK_START,
|
|
13
|
-
SKILL_LOAD_INSTRUCTION,
|
|
14
13
|
removeCodexDeepenGuidance,
|
|
15
14
|
removeCodexPackageGuidance,
|
|
16
15
|
removeCodexQuestionGuidance,
|
|
17
|
-
|
|
16
|
+
withoutSkillLoadBlock,
|
|
18
17
|
DEEPEN_GUIDANCE_BLOCK_END,
|
|
19
18
|
DEEPEN_GUIDANCE_BLOCK_START,
|
|
20
19
|
DEEPEN_GUIDANCE_TEXT,
|
|
@@ -24,7 +23,10 @@ import {
|
|
|
24
23
|
writeCodexQuestionGuidance,
|
|
25
24
|
} from './codex-skill-load-block.mjs';
|
|
26
25
|
|
|
27
|
-
const
|
|
26
|
+
const STALE_SKILL_LOAD_SENTENCE = 'Load the pstack:poteto-mode skill before your first tool call or reply: '
|
|
27
|
+
+ 'open its SKILL.md from your skills list and follow it. This binds every Codex agent, '
|
|
28
|
+
+ 'including a helper started with spawn_agent, whatever its task message says.';
|
|
29
|
+
const STALE_SKILL_LOAD_BLOCK = `${SKILL_LOAD_BLOCK_START}\n${STALE_SKILL_LOAD_SENTENCE}\n${SKILL_LOAD_BLOCK_END}\n`;
|
|
28
30
|
const PACKAGE_GUIDANCE = 'Status\n\nChanged / proof / blocked.\n';
|
|
29
31
|
const QUESTION_POLICY = '# Present questions clearly\n\nAsk one question.\n';
|
|
30
32
|
|
|
@@ -52,34 +54,44 @@ function writeGuidance(homes) {
|
|
|
52
54
|
return writeCodexAgentsGuidance(homes.codexHome, PACKAGE_GUIDANCE, homes.allPackageGuidancePaths);
|
|
53
55
|
}
|
|
54
56
|
|
|
55
|
-
test('
|
|
56
|
-
assert.
|
|
57
|
-
assert.
|
|
57
|
+
test('a complete skill-load block is removed and the lines around it stay', () => {
|
|
58
|
+
assert.equal(withoutSkillLoadBlock(`Intro\n${STALE_SKILL_LOAD_BLOCK}Outro\n`), 'Intro\nOutro\n');
|
|
59
|
+
assert.equal(withoutSkillLoadBlock(`${STALE_SKILL_LOAD_BLOCK}\nNotes\n`), 'Notes\n');
|
|
60
|
+
assert.equal(
|
|
61
|
+
withoutSkillLoadBlock(`${STALE_SKILL_LOAD_BLOCK}\n${STALE_SKILL_LOAD_BLOCK}\nNotes\n`),
|
|
62
|
+
'Notes\n',
|
|
63
|
+
);
|
|
64
|
+
assert.equal(
|
|
65
|
+
withoutSkillLoadBlock(`${SKILL_LOAD_BLOCK_START}\nHalf a block\n`),
|
|
66
|
+
`${SKILL_LOAD_BLOCK_START}\nHalf a block\n`,
|
|
67
|
+
);
|
|
58
68
|
});
|
|
59
69
|
|
|
60
|
-
test('a missing Codex guidance file is created holding the
|
|
70
|
+
test('a missing Codex guidance file is created holding the package guidance', (context) => {
|
|
61
71
|
const homes = makeHomes(context);
|
|
62
72
|
|
|
63
73
|
const writtenPath = writeGuidance(homes);
|
|
64
74
|
|
|
65
75
|
assert.equal(writtenPath, homes.agentsPath);
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
);
|
|
76
|
+
const rendered = readFileSync(homes.agentsPath, 'utf8');
|
|
77
|
+
assert.equal(rendered, guidanceBlock(PACKAGE_GUIDANCE));
|
|
78
|
+
assert.equal(rendered.includes('pstack:poteto-mode'), false);
|
|
79
|
+
assert.equal(rendered.includes(SKILL_LOAD_BLOCK_START), false);
|
|
70
80
|
});
|
|
71
81
|
|
|
72
|
-
test('existing guidance keeps
|
|
82
|
+
test('existing guidance keeps its lines and gains the package guidance', (context) => {
|
|
73
83
|
const homes = makeHomes(context);
|
|
74
84
|
mkdirSync(homes.codexHome);
|
|
75
85
|
writeFileSync(homes.agentsPath, '# pstack model configuration\n\nbug-fix: gpt-6-astra\n');
|
|
76
86
|
|
|
77
87
|
writeGuidance(homes);
|
|
78
88
|
|
|
89
|
+
const rendered = readFileSync(homes.agentsPath, 'utf8');
|
|
79
90
|
assert.equal(
|
|
80
|
-
|
|
81
|
-
|
|
91
|
+
rendered,
|
|
92
|
+
`# pstack model configuration\n\nbug-fix: gpt-6-astra\n\n${guidanceBlock(PACKAGE_GUIDANCE)}`,
|
|
82
93
|
);
|
|
94
|
+
assert.equal(rendered.includes('pstack:poteto-mode'), false);
|
|
83
95
|
});
|
|
84
96
|
|
|
85
97
|
test('a repeat install leaves the file unchanged and reports no write', (context) => {
|
|
@@ -93,20 +105,43 @@ test('a repeat install leaves the file unchanged and reports no write', (context
|
|
|
93
105
|
assert.equal(readFileSync(homes.agentsPath, 'utf8'), afterFirstInstall);
|
|
94
106
|
});
|
|
95
107
|
|
|
96
|
-
test('
|
|
97
|
-
const
|
|
108
|
+
test('a stale skill-load sentence is removed and question and deepen blocks stay', (context) => {
|
|
109
|
+
const homes = makeHomes(context);
|
|
110
|
+
mkdirSync(homes.codexHome);
|
|
111
|
+
const questionBlock = `${QUESTION_PRESENTATION_BLOCK_START}\n${QUESTION_POLICY}${QUESTION_PRESENTATION_BLOCK_END}\n`;
|
|
112
|
+
const deepenBlock = `${DEEPEN_GUIDANCE_BLOCK_START}\n${DEEPEN_GUIDANCE_TEXT}\n${DEEPEN_GUIDANCE_BLOCK_END}\n`;
|
|
113
|
+
writeFileSync(
|
|
114
|
+
homes.agentsPath,
|
|
115
|
+
`${STALE_SKILL_LOAD_BLOCK}\n${guidanceBlock('Old guidance\n')}${questionBlock}${deepenBlock}`,
|
|
116
|
+
);
|
|
98
117
|
|
|
99
|
-
|
|
118
|
+
writeGuidance(homes);
|
|
119
|
+
|
|
120
|
+
const rendered = readFileSync(homes.agentsPath, 'utf8');
|
|
121
|
+
assert.equal(rendered.includes(STALE_SKILL_LOAD_SENTENCE), false);
|
|
122
|
+
assert.equal(rendered.includes('pstack:poteto-mode'), false);
|
|
123
|
+
assert.equal(rendered.includes(SKILL_LOAD_BLOCK_START), false);
|
|
124
|
+
assert.ok(rendered.includes(guidanceBlock(PACKAGE_GUIDANCE)));
|
|
125
|
+
assert.ok(rendered.includes(questionBlock));
|
|
126
|
+
assert.ok(rendered.includes(deepenBlock));
|
|
100
127
|
});
|
|
101
128
|
|
|
102
|
-
test('a start marker with no end marker
|
|
129
|
+
test('a start marker with no end marker stays and no skill name is added', (context) => {
|
|
130
|
+
const homes = makeHomes(context);
|
|
103
131
|
const broken = `${SKILL_LOAD_BLOCK_START}\nHalf a block\n`;
|
|
132
|
+
mkdirSync(homes.codexHome);
|
|
133
|
+
writeFileSync(homes.agentsPath, broken);
|
|
134
|
+
|
|
135
|
+
writeGuidance(homes);
|
|
104
136
|
|
|
105
|
-
|
|
137
|
+
const rendered = readFileSync(homes.agentsPath, 'utf8');
|
|
138
|
+
assert.ok(rendered.startsWith(broken));
|
|
139
|
+
assert.equal(rendered.includes('pstack:poteto-mode'), false);
|
|
140
|
+
assert.ok(rendered.includes(PACKAGE_GUIDANCE_BLOCK_START));
|
|
106
141
|
});
|
|
107
142
|
|
|
108
143
|
for (const linkName of ['retiredGuidancePath', 'sharedGuidancePath']) {
|
|
109
|
-
test(`a link to package guidance at ${linkName} becomes a file with
|
|
144
|
+
test(`a link to package guidance at ${linkName} becomes a file with the package block`, (context) => {
|
|
110
145
|
const homes = makeHomes(context);
|
|
111
146
|
mkdirSync(homes.codexHome);
|
|
112
147
|
symlinkSync(homes[linkName], homes.agentsPath);
|
|
@@ -115,24 +150,21 @@ for (const linkName of ['retiredGuidancePath', 'sharedGuidancePath']) {
|
|
|
115
150
|
|
|
116
151
|
assert.equal(writtenPath, homes.agentsPath);
|
|
117
152
|
assert.equal(lstatSync(homes.agentsPath).isSymbolicLink(), false);
|
|
118
|
-
assert.equal(
|
|
119
|
-
|
|
120
|
-
`${EXPECTED_BLOCK}\n${guidanceBlock(PACKAGE_GUIDANCE)}`,
|
|
121
|
-
);
|
|
153
|
+
assert.equal(readFileSync(homes.agentsPath, 'utf8'), guidanceBlock(PACKAGE_GUIDANCE));
|
|
154
|
+
assert.equal(readFileSync(homes.agentsPath, 'utf8').includes('pstack:poteto-mode'), false);
|
|
122
155
|
});
|
|
123
156
|
}
|
|
124
157
|
|
|
125
|
-
test('a converted file takes the new package guidance
|
|
158
|
+
test('a converted file takes the new package guidance and drops a stale skill-load block', (context) => {
|
|
126
159
|
const homes = makeHomes(context);
|
|
127
160
|
mkdirSync(homes.codexHome);
|
|
128
|
-
writeFileSync(homes.agentsPath, `${
|
|
161
|
+
writeFileSync(homes.agentsPath, `${STALE_SKILL_LOAD_BLOCK}\n${guidanceBlock('Old guidance\n')}`);
|
|
129
162
|
|
|
130
163
|
writeGuidance(homes);
|
|
131
164
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
);
|
|
165
|
+
const rendered = readFileSync(homes.agentsPath, 'utf8');
|
|
166
|
+
assert.equal(rendered, guidanceBlock(PACKAGE_GUIDANCE));
|
|
167
|
+
assert.equal(rendered.includes('pstack:poteto-mode'), false);
|
|
136
168
|
});
|
|
137
169
|
|
|
138
170
|
test('a link to a file the package does not own is left alone', (context) => {
|
package/bin/install.mjs
CHANGED
|
@@ -2927,13 +2927,13 @@ function executeInstallPlanMutations(plan, transactionHelpers) {
|
|
|
2927
2927
|
allUserOwnedPreferencePaths.add(eachPath);
|
|
2928
2928
|
}
|
|
2929
2929
|
}
|
|
2930
|
-
const
|
|
2930
|
+
const codexGuidancePath = writeCodexAgentsGuidance(
|
|
2931
2931
|
INSTALL_ROOT_RESOLUTION.codexHomeDirectory,
|
|
2932
2932
|
packageGuidanceText,
|
|
2933
2933
|
allPackageGuidancePaths,
|
|
2934
2934
|
);
|
|
2935
|
-
if (
|
|
2936
|
-
console.log(` \u2713 ${
|
|
2935
|
+
if (codexGuidancePath) {
|
|
2936
|
+
console.log(` \u2713 ${codexGuidancePath} (Codex package guidance)`);
|
|
2937
2937
|
}
|
|
2938
2938
|
}
|
|
2939
2939
|
printPluginHostOutcomes([PSTACK_PLUGIN_SPEC], pstackPlugin);
|
|
@@ -171,7 +171,7 @@ test('a selected Claude profile receives the source rule and its Codex guidance'
|
|
|
171
171
|
assert.ok(readFileSync(join(profileDirectory, '.codex', 'AGENTS.md'), 'utf8').includes(readFileSync(policyPath, 'utf8')));
|
|
172
172
|
});
|
|
173
173
|
|
|
174
|
-
test('a successful pstack install
|
|
174
|
+
test('a successful pstack install omits the retired skill block and gains the question block', (context) => {
|
|
175
175
|
const homeDirectory = makeScratchHome(context);
|
|
176
176
|
const commandPath = join(homeDirectory, process.platform === 'win32' ? 'codex.cmd' : 'codex');
|
|
177
177
|
writeFileSync(
|
|
@@ -191,7 +191,7 @@ test('a successful pstack install retains its skill block and gains the question
|
|
|
191
191
|
|
|
192
192
|
assert.equal(installation.status, 0, installation.stdout + installation.stderr);
|
|
193
193
|
const guidanceText = readFileSync(join(homeDirectory, '.codex', 'AGENTS.md'), 'utf8');
|
|
194
|
-
assert.
|
|
194
|
+
assert.doesNotMatch(guidanceText, /<!-- claude-dev-env skill load: start -->/);
|
|
195
195
|
assert.match(guidanceText, /<!-- claude-dev-env question presentation: start -->/);
|
|
196
196
|
assert.ok(guidanceText.includes(readFileSync(policyPath, 'utf8')));
|
|
197
197
|
});
|
|
@@ -221,7 +221,7 @@ test('enabling pstack after a pstack-off install preserves question guidance', (
|
|
|
221
221
|
assert.equal(secondInstallation.status, 0, secondInstallation.stdout + secondInstallation.stderr);
|
|
222
222
|
const updatedGuidance = readFileSync(codexGuidancePath, 'utf8');
|
|
223
223
|
assert.ok(updatedGuidance.includes(firstGuidance));
|
|
224
|
-
assert.
|
|
224
|
+
assert.doesNotMatch(updatedGuidance, /<!-- claude-dev-env skill load: start -->/);
|
|
225
225
|
assert.match(updatedGuidance, /^feature, refactoring: gpt-6-sol$/m);
|
|
226
226
|
assert.match(readFileSync(join(homeDirectory, '.codex', 'pstack-models.md'), 'utf8'), /^session hook: on$/m);
|
|
227
227
|
});
|
package/bin/install.test.mjs
CHANGED
|
@@ -57,12 +57,12 @@ 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_START,
|
|
60
61
|
PACKAGE_GUIDANCE_BLOCK_END,
|
|
61
62
|
PACKAGE_GUIDANCE_BLOCK_START,
|
|
62
|
-
SKILL_LOAD_BLOCK_START,
|
|
63
|
-
SKILL_LOAD_INSTRUCTION,
|
|
64
63
|
QUESTION_PRESENTATION_BLOCK_START,
|
|
65
|
-
|
|
64
|
+
SKILL_LOAD_BLOCK_END,
|
|
65
|
+
SKILL_LOAD_BLOCK_START,
|
|
66
66
|
} from './codex-skill-load-block.mjs';
|
|
67
67
|
|
|
68
68
|
|
|
@@ -3124,6 +3124,17 @@ function pstackPluginSandbox(t) {
|
|
|
3124
3124
|
};
|
|
3125
3125
|
}
|
|
3126
3126
|
|
|
3127
|
+
const STALE_SKILL_LOAD_SENTENCE = 'Load the pstack:poteto-mode skill before your first tool call or reply: '
|
|
3128
|
+
+ 'open its SKILL.md from your skills list and follow it. This binds every Codex agent, '
|
|
3129
|
+
+ 'including a helper started with spawn_agent, whatever its task message says.';
|
|
3130
|
+
|
|
3131
|
+
function assertOmitsSkillLoadSentence(codexGuidance) {
|
|
3132
|
+
assert.equal(codexGuidance.includes(SKILL_LOAD_BLOCK_START), false);
|
|
3133
|
+
assert.equal(codexGuidance.includes(SKILL_LOAD_BLOCK_END), false);
|
|
3134
|
+
assert.equal(codexGuidance.includes('pstack:poteto-mode'), false);
|
|
3135
|
+
assert.equal(codexGuidance.includes(STALE_SKILL_LOAD_SENTENCE), false);
|
|
3136
|
+
}
|
|
3137
|
+
|
|
3127
3138
|
test('a full install adds the pstack marketplace and plugin on both hosts', t => {
|
|
3128
3139
|
const sandbox = pstackPluginSandbox(t);
|
|
3129
3140
|
|
|
@@ -3145,9 +3156,10 @@ test('a full install adds the pstack marketplace and plugin on both hosts', t =>
|
|
|
3145
3156
|
const sheet = readFileSync(join(codexHome, 'pstack-models.md'), 'utf8');
|
|
3146
3157
|
const agents = readFileSync(join(codexHome, 'AGENTS.md'), 'utf8');
|
|
3147
3158
|
assert.match(sheet, /^session hook: on$/m);
|
|
3159
|
+
assert.match(agents, /^# pstack model configuration\n/);
|
|
3148
3160
|
assert.match(agents, /^feature, refactoring: gpt-6-sol$/m);
|
|
3149
3161
|
assert.doesNotMatch(agents, /^session hook:/m);
|
|
3150
|
-
|
|
3162
|
+
assertOmitsSkillLoadSentence(agents);
|
|
3151
3163
|
assert.equal(existsSync(join(sandbox.homeDirectory, '.claude', 'pstack-models.md')), false);
|
|
3152
3164
|
const manifestPath = join(sandbox.homeDirectory, '.claude', '.claude-dev-env-manifest.json');
|
|
3153
3165
|
const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
@@ -3159,14 +3171,19 @@ test('a repeat install preserves Codex pstack configuration', t => {
|
|
|
3159
3171
|
const sandbox = pstackPluginSandbox(t);
|
|
3160
3172
|
const codexHome = join(sandbox.homeDirectory, '.codex');
|
|
3161
3173
|
runPstackInstaller(sandbox.homeDirectory, [], sandbox.environment);
|
|
3162
|
-
writeFileSync(
|
|
3174
|
+
writeFileSync(
|
|
3175
|
+
join(codexHome, 'AGENTS.md'),
|
|
3176
|
+
`${SKILL_LOAD_BLOCK_START}\n${STALE_SKILL_LOAD_SENTENCE}\n${SKILL_LOAD_BLOCK_END}\nCustom Codex guidance\n`,
|
|
3177
|
+
);
|
|
3163
3178
|
writeFileSync(join(codexHome, 'pstack-models.md'), 'session hook: off\n');
|
|
3164
3179
|
|
|
3165
3180
|
runPstackInstaller(sandbox.homeDirectory, [], sandbox.environment);
|
|
3166
3181
|
|
|
3167
3182
|
const codexGuidance = readFileSync(join(codexHome, 'AGENTS.md'), 'utf8');
|
|
3168
|
-
assert.ok(codexGuidance.startsWith(
|
|
3183
|
+
assert.ok(codexGuidance.startsWith('Custom Codex guidance\n'));
|
|
3184
|
+
assertOmitsSkillLoadSentence(codexGuidance);
|
|
3169
3185
|
assert.ok(codexGuidance.includes(QUESTION_PRESENTATION_BLOCK_START));
|
|
3186
|
+
assert.ok(codexGuidance.includes(DEEPEN_GUIDANCE_BLOCK_START));
|
|
3170
3187
|
assert.equal(readFileSync(join(codexHome, 'pstack-models.md'), 'utf8'), 'session hook: off\n');
|
|
3171
3188
|
});
|
|
3172
3189
|
|
|
@@ -3185,7 +3202,7 @@ test('a Codex guidance link to the retired Claude copy becomes a file Codex can
|
|
|
3185
3202
|
);
|
|
3186
3203
|
assert.equal(lstatSync(codexAgentsPath).isSymbolicLink(), false);
|
|
3187
3204
|
const codexGuidance = readFileSync(codexAgentsPath, 'utf8');
|
|
3188
|
-
|
|
3205
|
+
assertOmitsSkillLoadSentence(codexGuidance);
|
|
3189
3206
|
assert.ok(codexGuidance.includes(packageGuidance));
|
|
3190
3207
|
});
|
|
3191
3208
|
|
|
@@ -3248,8 +3265,9 @@ test('a fresh full install writes the package guidance into Codex AGENTS.md', t
|
|
|
3248
3265
|
|
|
3249
3266
|
const codexGuidance = readFileSync(join(sandbox.homeDirectory, '.codex', 'AGENTS.md'), 'utf8');
|
|
3250
3267
|
assertHoldsPackageGuidance(codexGuidance);
|
|
3251
|
-
|
|
3268
|
+
assertOmitsSkillLoadSentence(codexGuidance);
|
|
3252
3269
|
assert.ok(codexGuidance.includes(QUESTION_PRESENTATION_BLOCK_START));
|
|
3270
|
+
assert.ok(codexGuidance.includes(DEEPEN_GUIDANCE_BLOCK_START));
|
|
3253
3271
|
});
|
|
3254
3272
|
|
|
3255
3273
|
test('--no-pstack writes package and question guidance without the skill-load block', t => {
|
|
@@ -3329,9 +3347,10 @@ test('a pstack install after a --no-pstack install seeds the Codex model sheet',
|
|
|
3329
3347
|
assert.match(readFileSync(join(codexHome, 'pstack-models.md'), 'utf8'), /^session hook: on$/m);
|
|
3330
3348
|
const codexGuidance = readFileSync(join(codexHome, 'AGENTS.md'), 'utf8');
|
|
3331
3349
|
assert.match(codexGuidance, /^feature, refactoring: gpt-6-sol$/m);
|
|
3332
|
-
|
|
3350
|
+
assertOmitsSkillLoadSentence(codexGuidance);
|
|
3333
3351
|
assertHoldsPackageGuidance(codexGuidance);
|
|
3334
3352
|
assert.ok(codexGuidance.includes(QUESTION_PRESENTATION_BLOCK_START));
|
|
3353
|
+
assert.ok(codexGuidance.includes(DEEPEN_GUIDANCE_BLOCK_START));
|
|
3335
3354
|
});
|
|
3336
3355
|
|
|
3337
3356
|
const USAGE_WRAPUP_CLAUDE_COMMANDS = Object.freeze([
|