helloagents 3.0.3-beta.1 → 3.0.8-beta.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/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +157 -57
- package/README_CN.md +157 -57
- package/bootstrap-lite.md +125 -50
- package/bootstrap.md +169 -123
- package/cli.mjs +80 -427
- package/gemini-extension.json +1 -1
- package/hooks/hooks-claude.json +10 -0
- package/hooks/hooks.json +10 -0
- package/package.json +1 -1
- package/scripts/advisor-state.mjs +222 -0
- package/scripts/capability-registry.mjs +59 -0
- package/scripts/cli-codex-backup.mjs +59 -0
- package/scripts/cli-codex-config.mjs +94 -0
- package/scripts/cli-codex.mjs +90 -222
- package/scripts/cli-config.mjs +1 -0
- package/scripts/cli-doctor-render.mjs +28 -0
- package/scripts/cli-doctor.mjs +370 -0
- package/scripts/cli-host-detect.mjs +94 -0
- package/scripts/cli-lifecycle-hosts.mjs +123 -0
- package/scripts/cli-lifecycle.mjs +213 -0
- package/scripts/cli-messages.mjs +76 -52
- package/scripts/cli-toml.mjs +30 -0
- package/scripts/closeout-state.mjs +213 -0
- package/scripts/delivery-gate.mjs +256 -0
- package/scripts/guard-rules.mjs +147 -0
- package/scripts/guard.mjs +218 -168
- package/scripts/notify-context.mjs +78 -23
- package/scripts/notify-events.mjs +5 -1
- package/scripts/notify-route.mjs +111 -0
- package/scripts/notify-shared.mjs +0 -2
- package/scripts/notify-source.mjs +113 -0
- package/scripts/notify-ui.mjs +40 -6
- package/scripts/notify.mjs +137 -65
- package/scripts/plan-contract.mjs +210 -0
- package/scripts/project-storage.mjs +235 -0
- package/scripts/ralph-loop.mjs +9 -58
- package/scripts/replay-state.mjs +210 -0
- package/scripts/review-state.mjs +220 -0
- package/scripts/runtime-context.mjs +74 -0
- package/scripts/turn-state.mjs +173 -0
- package/scripts/verify-state.mjs +226 -0
- package/scripts/visual-state.mjs +244 -0
- package/scripts/workflow-core.mjs +165 -0
- package/scripts/workflow-plan-files.mjs +249 -0
- package/scripts/workflow-recommendation.mjs +335 -0
- package/scripts/workflow-state.mjs +113 -0
- package/skills/_meta/SKILL.md +1 -1
- package/skills/commands/auto/SKILL.md +48 -67
- package/skills/commands/build/SKILL.md +67 -0
- package/skills/commands/clean/SKILL.md +10 -8
- package/skills/commands/commit/SKILL.md +8 -4
- package/skills/commands/help/SKILL.md +18 -11
- package/skills/commands/idea/SKILL.md +55 -0
- package/skills/commands/init/SKILL.md +16 -8
- package/skills/commands/loop/SKILL.md +6 -5
- package/skills/commands/plan/SKILL.md +118 -0
- package/skills/commands/prd/SKILL.md +22 -15
- package/skills/commands/verify/SKILL.md +32 -9
- package/skills/commands/wiki/SKILL.md +11 -11
- package/skills/hello-review/SKILL.md +9 -0
- package/skills/hello-subagent/SKILL.md +5 -3
- package/skills/hello-ui/SKILL.md +36 -8
- package/skills/hello-verify/SKILL.md +12 -3
- package/skills/helloagents/SKILL.md +36 -20
- package/templates/DESIGN.md +25 -4
- package/templates/STATE.md +3 -0
- package/templates/plans/contract.json +48 -0
- package/templates/plans/plan.md +23 -0
- package/templates/plans/tasks.md +3 -3
- package/skills/commands/design/SKILL.md +0 -108
- package/skills/commands/review/SKILL.md +0 -16
- package/templates/plans/design.md +0 -14
package/scripts/cli-codex.mjs
CHANGED
|
@@ -1,37 +1,37 @@
|
|
|
1
1
|
import { join, dirname } from 'node:path';
|
|
2
|
-
import { existsSync
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
3
|
import {
|
|
4
4
|
ensureDir, safeRead, safeWrite, removeIfExists,
|
|
5
5
|
readJsonOrThrow, copyEntries,
|
|
6
6
|
createLink, removeLink, injectMarkedContent, removeMarkedContent,
|
|
7
7
|
} from './cli-utils.mjs';
|
|
8
|
+
import { ensureTimestampedBackup, readCodexBackup, removeCodexBackup } from './cli-codex-backup.mjs';
|
|
9
|
+
import {
|
|
10
|
+
CODEX_MANAGED_TOML_COMMENT,
|
|
11
|
+
CODEX_PLUGIN_CONFIG_HEADER,
|
|
12
|
+
isManagedCodexHooks,
|
|
13
|
+
installCodexManagedTopLevelConfig,
|
|
14
|
+
isManagedCodexBackupInstruction,
|
|
15
|
+
isManagedCodexModelInstruction,
|
|
16
|
+
isManagedCodexNotify,
|
|
17
|
+
removeCodexPluginConfig,
|
|
18
|
+
restoreCodexTopLevelConfig,
|
|
19
|
+
upsertCodexPluginConfig,
|
|
20
|
+
} from './cli-codex-config.mjs';
|
|
8
21
|
import {
|
|
9
|
-
upsertTopLevelTomlKey,
|
|
10
|
-
upsertTopLevelTomlBlock,
|
|
11
22
|
readTopLevelTomlLine,
|
|
12
|
-
readTopLevelTomlBlock,
|
|
13
|
-
ensureTopLevelTomlLine,
|
|
14
|
-
ensureTopLevelTomlBlock,
|
|
15
23
|
readTomlKeyInSection,
|
|
16
24
|
removeTomlKeyInSection,
|
|
17
|
-
removeTopLevelTomlBlock,
|
|
18
25
|
ensureTomlKeyInSection,
|
|
19
|
-
stripTomlSection,
|
|
20
26
|
removeTopLevelTomlLines,
|
|
21
27
|
} from './cli-toml.mjs';
|
|
22
28
|
|
|
23
29
|
export const CODEX_MARKETPLACE_NAME = 'local-plugins';
|
|
24
30
|
export const CODEX_PLUGIN_NAME = 'helloagents';
|
|
25
31
|
export const CODEX_PLUGIN_KEY = `${CODEX_PLUGIN_NAME}@${CODEX_MARKETPLACE_NAME}`;
|
|
26
|
-
export
|
|
27
|
-
export const CODEX_MANAGED_TOML_COMMENT = '# helloagents-managed';
|
|
32
|
+
export { CODEX_MANAGED_TOML_COMMENT, CODEX_PLUGIN_CONFIG_HEADER };
|
|
28
33
|
export const CODEX_RUNTIME_CARRIER = 'AGENTS.md';
|
|
29
|
-
const CODEX_BACKUP_TIMESTAMP_RE = /^\d{8}-\d{6}$/;
|
|
30
34
|
const CODEX_CONFIG_BASENAME = 'config.toml';
|
|
31
|
-
const CODEX_DEVELOPER_INSTRUCTIONS_BACKUP_BASENAME = 'developer_instructions';
|
|
32
|
-
export const CODEX_DEVELOPER_INSTRUCTIONS = `CRITICAL: These are HelloAGENTS global defaults for Codex. Use them as the baseline for main-agent behavior. Spawned sub-agents should focus on the delegated task unless they are explicitly required to follow main-agent-only workflow.
|
|
33
|
-
If the current workspace contains a project-level AGENTS.md or other repo-specific instructions, treat those as the more specific and authoritative instructions. Use these global defaults only where they do not conflict. Standby/global behavior is determined by the active workspace instructions, not by this global default block.
|
|
34
|
-
If work was already in progress and earlier context was compressed, first restore the active project state from the most relevant project state files or other project-local context artifacts, then continue from the actual interruption point without restarting the workflow or repeating completed steps.`;
|
|
35
35
|
export const CODEX_RUNTIME_ENTRIES = [
|
|
36
36
|
'.codex-plugin',
|
|
37
37
|
'assets',
|
|
@@ -46,142 +46,6 @@ export const CODEX_RUNTIME_ENTRIES = [
|
|
|
46
46
|
'templates',
|
|
47
47
|
];
|
|
48
48
|
|
|
49
|
-
function formatBackupTimestamp(date = new Date()) {
|
|
50
|
-
const pad = (value, size = 2) => String(value).padStart(size, '0');
|
|
51
|
-
return `${date.getFullYear()}${pad(date.getMonth() + 1)}${pad(date.getDate())}-${pad(date.getHours())}${pad(date.getMinutes())}${pad(date.getSeconds())}`;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function getTimestampedBackupPath(filePath, backupBaseName) {
|
|
55
|
-
return join(dirname(filePath), `${backupBaseName}_${formatBackupTimestamp()}.bak`);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function listTimestampedBackups(directory, backupBaseName) {
|
|
59
|
-
if (!existsSync(directory)) return [];
|
|
60
|
-
return readdirSync(directory)
|
|
61
|
-
.filter((name) => name.startsWith(`${backupBaseName}_`) && name.endsWith('.bak'))
|
|
62
|
-
.filter((name) => CODEX_BACKUP_TIMESTAMP_RE.test(name.slice(backupBaseName.length + 1, -4)))
|
|
63
|
-
.sort();
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function getLatestTimestampedBackupPath(filePath, backupBaseName) {
|
|
67
|
-
const directory = dirname(filePath);
|
|
68
|
-
const backups = listTimestampedBackups(directory, backupBaseName);
|
|
69
|
-
const latest = backups.at(-1);
|
|
70
|
-
return latest ? join(directory, latest) : '';
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function readLatestTimestampedBackup(filePath, backupBaseName) {
|
|
74
|
-
const backupPath = getLatestTimestampedBackupPath(filePath, backupBaseName);
|
|
75
|
-
return backupPath ? safeRead(backupPath) || '' : '';
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function removeLatestTimestampedBackup(filePath, backupBaseName) {
|
|
79
|
-
const backupPath = getLatestTimestampedBackupPath(filePath, backupBaseName);
|
|
80
|
-
if (backupPath) removeIfExists(backupPath);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function ensureTimestampedBackup(filePath, backupBaseName) {
|
|
84
|
-
if (!existsSync(filePath)) return '';
|
|
85
|
-
const existingBackup = getLatestTimestampedBackupPath(filePath, backupBaseName);
|
|
86
|
-
if (existingBackup) return existingBackup;
|
|
87
|
-
const backupPath = getTimestampedBackupPath(filePath, backupBaseName);
|
|
88
|
-
copyFileSync(filePath, backupPath);
|
|
89
|
-
return backupPath;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
function readCodexBackup(filePath, backupBaseName) {
|
|
93
|
-
const latest = readLatestTimestampedBackup(filePath, backupBaseName);
|
|
94
|
-
if (latest) return latest;
|
|
95
|
-
const legacyPath = `${filePath}.bak`;
|
|
96
|
-
return safeRead(legacyPath) || '';
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
function removeCodexBackup(filePath, backupBaseName) {
|
|
100
|
-
removeLatestTimestampedBackup(filePath, backupBaseName);
|
|
101
|
-
removeIfExists(`${filePath}.bak`);
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function isManagedCodexStandbyInstructionPath(normalized = '') {
|
|
105
|
-
return /\/\.codex\/AGENTS\.md/i.test(normalized)
|
|
106
|
-
|| /\/\.codex\/helloagents\/bootstrap-lite\.md/i.test(normalized);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function isManagedCodexGlobalInstructionPath(normalized = '') {
|
|
110
|
-
return /\/plugins\/helloagents\/AGENTS\.md/i.test(normalized)
|
|
111
|
-
|| /\/plugins\/helloagents\/bootstrap\.md/i.test(normalized);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function upsertCodexPluginConfig(text) {
|
|
115
|
-
const stripped = stripTomlSection(text, CODEX_PLUGIN_CONFIG_HEADER).text.trimEnd();
|
|
116
|
-
const block = `${CODEX_PLUGIN_CONFIG_HEADER}\nenabled = true`;
|
|
117
|
-
return stripped ? `${stripped}\n\n${block}\n` : `${block}\n`;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function removeCodexPluginConfig(text) {
|
|
121
|
-
return stripTomlSection(text, CODEX_PLUGIN_CONFIG_HEADER).text;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function isManagedCodexModelInstruction(line = '') {
|
|
125
|
-
const normalized = String(line || '').replace(/\\/g, '/');
|
|
126
|
-
return line.includes('model_instructions_file')
|
|
127
|
-
&& (
|
|
128
|
-
line.includes(CODEX_MANAGED_TOML_COMMENT)
|
|
129
|
-
|| isManagedCodexStandbyInstructionPath(normalized)
|
|
130
|
-
|| isManagedCodexGlobalInstructionPath(normalized)
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function isManagedCodexNotify(line = '') {
|
|
135
|
-
return line.includes('codex-notify') || (line.includes('helloagents') && line.includes('notify'));
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function isManagedCodexBackupInstruction(line = '') {
|
|
139
|
-
return line.includes(CODEX_MANAGED_TOML_COMMENT);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
function formatManagedCodexDeveloperInstructions() {
|
|
143
|
-
return `"""\n${CODEX_DEVELOPER_INSTRUCTIONS}\n"""`;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function backupUserCodexDeveloperInstructions(configPath, existingBlock) {
|
|
147
|
-
if (!existingBlock || existingBlock.includes('HelloAGENTS')) return;
|
|
148
|
-
const backupPath = getTimestampedBackupPath(configPath, CODEX_DEVELOPER_INSTRUCTIONS_BACKUP_BASENAME);
|
|
149
|
-
safeWrite(backupPath, `${existingBlock}\n`);
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function sanitizeCodexDeveloperInstructionsBackup(block = '') {
|
|
153
|
-
const normalized = String(block || '').trim();
|
|
154
|
-
if (!normalized.startsWith('developer_instructions =')) return '';
|
|
155
|
-
if (normalized.includes(CODEX_DEVELOPER_INSTRUCTIONS)) return '';
|
|
156
|
-
return normalized;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
function readCodexDeveloperInstructionsBackup(configPath) {
|
|
160
|
-
return sanitizeCodexDeveloperInstructionsBackup(
|
|
161
|
-
readCodexBackup(configPath, CODEX_DEVELOPER_INSTRUCTIONS_BACKUP_BASENAME),
|
|
162
|
-
);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
function removeCodexDeveloperInstructionsBackup(configPath) {
|
|
166
|
-
removeCodexBackup(configPath, CODEX_DEVELOPER_INSTRUCTIONS_BACKUP_BASENAME);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function installCodexDeveloperInstructions(configPath, toml) {
|
|
170
|
-
const existing = readTopLevelTomlBlock(toml, 'developer_instructions');
|
|
171
|
-
backupUserCodexDeveloperInstructions(configPath, existing);
|
|
172
|
-
return upsertTopLevelTomlBlock(toml, 'developer_instructions', formatManagedCodexDeveloperInstructions());
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
function uninstallCodexDeveloperInstructions(configPath, toml) {
|
|
176
|
-
const existing = readTopLevelTomlBlock(toml, 'developer_instructions');
|
|
177
|
-
if (!existing.includes('HelloAGENTS')) return toml;
|
|
178
|
-
let next = removeTopLevelTomlBlock(toml, 'developer_instructions');
|
|
179
|
-
const backupDeveloperInstructions = readCodexDeveloperInstructionsBackup(configPath);
|
|
180
|
-
next = ensureTopLevelTomlBlock(next, 'developer_instructions', backupDeveloperInstructions);
|
|
181
|
-
removeCodexDeveloperInstructionsBackup(configPath);
|
|
182
|
-
return next;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
49
|
function getDefaultCodexMarketplace() {
|
|
186
50
|
return {
|
|
187
51
|
name: CODEX_MARKETPLACE_NAME,
|
|
@@ -242,15 +106,18 @@ function removeCodexMarketplaceEntry(marketplaceFile) {
|
|
|
242
106
|
return true;
|
|
243
107
|
}
|
|
244
108
|
|
|
245
|
-
function normalizePath(path) {
|
|
246
|
-
return path.replace(/\\/g, '/');
|
|
247
|
-
}
|
|
248
|
-
|
|
249
109
|
function buildCodexRuntimeCarrier(bootstrapContent) {
|
|
250
110
|
const normalized = String(bootstrapContent || '').trim();
|
|
251
111
|
return normalized ? `${normalized}\n` : '';
|
|
252
112
|
}
|
|
253
113
|
|
|
114
|
+
function injectCodexRuntimeCarrier(filePath, bootstrapPath) {
|
|
115
|
+
const bootstrapContent = safeRead(bootstrapPath);
|
|
116
|
+
if (!bootstrapContent) return false;
|
|
117
|
+
injectMarkedContent(filePath, buildCodexRuntimeCarrier(bootstrapContent).trimEnd());
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
|
|
254
121
|
function writeCodexRuntimeCarrier(filePath, bootstrapPath) {
|
|
255
122
|
const bootstrapContent = safeRead(bootstrapPath);
|
|
256
123
|
if (!bootstrapContent) return false;
|
|
@@ -258,26 +125,73 @@ function writeCodexRuntimeCarrier(filePath, bootstrapPath) {
|
|
|
258
125
|
return true;
|
|
259
126
|
}
|
|
260
127
|
|
|
128
|
+
function cleanupCodexManagedConfig(configPath, { removePluginConfig = false } = {}) {
|
|
129
|
+
const backupToml = readCodexBackup(configPath, CODEX_CONFIG_BASENAME);
|
|
130
|
+
let toml = safeRead(configPath) || '';
|
|
131
|
+
|
|
132
|
+
const currentModelInstructions = readTopLevelTomlLine(toml, 'model_instructions_file');
|
|
133
|
+
const currentNotify = readTopLevelTomlLine(toml, 'notify');
|
|
134
|
+
const currentCodexHooks = readTomlKeyInSection(toml, '[features]', 'codex_hooks');
|
|
135
|
+
|
|
136
|
+
const shouldRestoreModelInstructions = isManagedCodexModelInstruction(currentModelInstructions);
|
|
137
|
+
const shouldRestoreNotify = isManagedCodexNotify(currentNotify);
|
|
138
|
+
const shouldRestoreCodexHooks = isManagedCodexHooks(currentCodexHooks);
|
|
139
|
+
|
|
140
|
+
if (removePluginConfig) {
|
|
141
|
+
toml = removeCodexPluginConfig(toml);
|
|
142
|
+
}
|
|
143
|
+
if (shouldRestoreModelInstructions) {
|
|
144
|
+
toml = removeTopLevelTomlLines(toml, (line) =>
|
|
145
|
+
line.startsWith('model_instructions_file =') && isManagedCodexModelInstruction(line)).text;
|
|
146
|
+
}
|
|
147
|
+
if (shouldRestoreNotify) {
|
|
148
|
+
toml = removeTopLevelTomlLines(toml, (line) =>
|
|
149
|
+
line.startsWith('notify =') && isManagedCodexNotify(line)).text;
|
|
150
|
+
}
|
|
151
|
+
if (shouldRestoreCodexHooks) {
|
|
152
|
+
toml = removeTomlKeyInSection(toml, '[features]', 'codex_hooks');
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const backupModelInstructions = readTopLevelTomlLine(backupToml, 'model_instructions_file');
|
|
156
|
+
const backupNotify = readTopLevelTomlLine(backupToml, 'notify');
|
|
157
|
+
const backupCodexHooks = readTomlKeyInSection(backupToml, '[features]', 'codex_hooks');
|
|
158
|
+
|
|
159
|
+
toml = restoreCodexTopLevelConfig(toml, {
|
|
160
|
+
modelInstructionsLine: shouldRestoreModelInstructions && !isManagedCodexBackupInstruction(backupModelInstructions)
|
|
161
|
+
? backupModelInstructions
|
|
162
|
+
: '',
|
|
163
|
+
notifyLine: shouldRestoreNotify && !isManagedCodexNotify(backupNotify)
|
|
164
|
+
? backupNotify
|
|
165
|
+
: '',
|
|
166
|
+
});
|
|
167
|
+
toml = ensureTomlKeyInSection(
|
|
168
|
+
toml,
|
|
169
|
+
'[features]',
|
|
170
|
+
'codex_hooks',
|
|
171
|
+
shouldRestoreCodexHooks && !isManagedCodexHooks(backupCodexHooks)
|
|
172
|
+
? backupCodexHooks
|
|
173
|
+
: '',
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
return toml;
|
|
177
|
+
}
|
|
178
|
+
|
|
261
179
|
export function installCodexStandby(home, pkgRoot) {
|
|
262
180
|
const codexDir = join(home, '.codex');
|
|
263
181
|
if (!existsSync(codexDir)) return false;
|
|
264
182
|
ensureDir(codexDir);
|
|
265
183
|
|
|
266
184
|
const codexAgentsPath = join(codexDir, CODEX_RUNTIME_CARRIER);
|
|
267
|
-
|
|
268
|
-
if (bootstrapContent) {
|
|
269
|
-
injectMarkedContent(
|
|
270
|
-
codexAgentsPath,
|
|
271
|
-
buildCodexRuntimeCarrier(bootstrapContent).trimEnd(),
|
|
272
|
-
);
|
|
273
|
-
}
|
|
185
|
+
injectCodexRuntimeCarrier(codexAgentsPath, join(pkgRoot, 'bootstrap-lite.md'));
|
|
274
186
|
|
|
275
187
|
const configPath = join(codexDir, 'config.toml');
|
|
276
188
|
let toml = safeRead(configPath) || '';
|
|
277
189
|
ensureTimestampedBackup(configPath, CODEX_CONFIG_BASENAME);
|
|
278
190
|
|
|
279
|
-
toml =
|
|
280
|
-
|
|
191
|
+
toml = installCodexManagedTopLevelConfig(toml, {
|
|
192
|
+
modelInstructionsPath: codexAgentsPath,
|
|
193
|
+
notifyScriptPath: join(pkgRoot, 'scripts', 'notify.mjs'),
|
|
194
|
+
});
|
|
281
195
|
safeWrite(configPath, toml);
|
|
282
196
|
|
|
283
197
|
createLink(pkgRoot, join(codexDir, 'helloagents'));
|
|
@@ -292,34 +206,10 @@ export function uninstallCodexStandby(home) {
|
|
|
292
206
|
removeMarkedContent(join(codexDir, 'AGENTS.md'));
|
|
293
207
|
|
|
294
208
|
const configPath = join(codexDir, 'config.toml');
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
if (!line) return false;
|
|
300
|
-
if (line.startsWith('model_instructions_file =') && isManagedCodexModelInstruction(line)) return true;
|
|
301
|
-
if (line.startsWith('notify =') && line.includes('codex-notify')) return true;
|
|
302
|
-
return false;
|
|
303
|
-
}).text;
|
|
304
|
-
toml = uninstallCodexDeveloperInstructions(configPath, toml);
|
|
305
|
-
toml = removeTomlKeyInSection(toml, '[features]', 'codex_hooks');
|
|
306
|
-
const backupModelInstructions = readTopLevelTomlLine(backupToml, 'model_instructions_file');
|
|
307
|
-
const backupNotify = readTopLevelTomlLine(backupToml, 'notify');
|
|
308
|
-
toml = ensureTopLevelTomlLine(
|
|
309
|
-
toml,
|
|
310
|
-
'model_instructions_file',
|
|
311
|
-
isManagedCodexBackupInstruction(backupModelInstructions) ? '' : backupModelInstructions,
|
|
312
|
-
);
|
|
313
|
-
toml = ensureTopLevelTomlLine(
|
|
314
|
-
toml,
|
|
315
|
-
'notify',
|
|
316
|
-
isManagedCodexNotify(backupNotify) ? '' : backupNotify,
|
|
317
|
-
);
|
|
318
|
-
toml = ensureTomlKeyInSection(toml, '[features]', 'codex_hooks', readTomlKeyInSection(backupToml, '[features]', 'codex_hooks'));
|
|
319
|
-
if (toml.trim()) safeWrite(configPath, toml);
|
|
320
|
-
else removeIfExists(configPath);
|
|
321
|
-
changed = true;
|
|
322
|
-
}
|
|
209
|
+
const toml = cleanupCodexManagedConfig(configPath);
|
|
210
|
+
if (toml.trim()) safeWrite(configPath, toml);
|
|
211
|
+
else removeIfExists(configPath);
|
|
212
|
+
changed = true;
|
|
323
213
|
removeCodexBackup(configPath, CODEX_CONFIG_BASENAME);
|
|
324
214
|
removeIfExists(join(codexDir, 'hooks.json'));
|
|
325
215
|
removeLink(join(codexDir, 'helloagents'));
|
|
@@ -366,19 +256,19 @@ export function installCodexGlobal(home, pkgRoot) {
|
|
|
366
256
|
join(installedPluginRoot, CODEX_RUNTIME_CARRIER),
|
|
367
257
|
join(installedPluginRoot, 'bootstrap.md'),
|
|
368
258
|
);
|
|
259
|
+
const homeCarrierPath = join(codexDir, CODEX_RUNTIME_CARRIER);
|
|
260
|
+
injectCodexRuntimeCarrier(homeCarrierPath, join(pkgRoot, 'bootstrap.md'));
|
|
369
261
|
|
|
370
262
|
ensureDir(join(home, '.agents', 'plugins'));
|
|
371
263
|
updateCodexMarketplace(marketplaceFile);
|
|
372
264
|
|
|
373
265
|
let toml = safeRead(configPath) || '';
|
|
374
266
|
ensureTimestampedBackup(configPath, CODEX_CONFIG_BASENAME);
|
|
375
|
-
toml =
|
|
376
|
-
|
|
377
|
-
'notify',
|
|
378
|
-
|
|
379
|
-
);
|
|
267
|
+
toml = installCodexManagedTopLevelConfig(toml, {
|
|
268
|
+
modelInstructionsPath: homeCarrierPath,
|
|
269
|
+
notifyScriptPath: join(pluginRoot, 'scripts', 'notify.mjs'),
|
|
270
|
+
});
|
|
380
271
|
toml = upsertCodexPluginConfig(toml);
|
|
381
|
-
toml = installCodexDeveloperInstructions(configPath, toml);
|
|
382
272
|
safeWrite(configPath, toml);
|
|
383
273
|
|
|
384
274
|
return true;
|
|
@@ -395,31 +285,9 @@ export function uninstallCodexGlobal(home) {
|
|
|
395
285
|
removeIfExists(pluginRoot);
|
|
396
286
|
removeIfExists(pluginCacheRoot);
|
|
397
287
|
removeCodexMarketplaceEntry(marketplaceFile);
|
|
288
|
+
removeMarkedContent(join(codexDir, 'AGENTS.md'));
|
|
398
289
|
|
|
399
|
-
const
|
|
400
|
-
let toml = safeRead(configPath) || '';
|
|
401
|
-
toml = removeCodexPluginConfig(toml);
|
|
402
|
-
toml = uninstallCodexDeveloperInstructions(configPath, toml);
|
|
403
|
-
toml = removeTomlKeyInSection(toml, '[features]', 'codex_hooks');
|
|
404
|
-
toml = removeTopLevelTomlLines(toml, (line) =>
|
|
405
|
-
line.startsWith('model_instructions_file =')
|
|
406
|
-
&& isManagedCodexModelInstruction(line)).text;
|
|
407
|
-
toml = removeTopLevelTomlLines(toml, (line) =>
|
|
408
|
-
line.startsWith('notify =')
|
|
409
|
-
&& line.includes('/plugins/helloagents/scripts/notify.mjs')).text;
|
|
410
|
-
const backupModelInstructions = readTopLevelTomlLine(backupToml, 'model_instructions_file');
|
|
411
|
-
const backupNotify = readTopLevelTomlLine(backupToml, 'notify');
|
|
412
|
-
toml = ensureTopLevelTomlLine(
|
|
413
|
-
toml,
|
|
414
|
-
'model_instructions_file',
|
|
415
|
-
isManagedCodexBackupInstruction(backupModelInstructions) ? '' : backupModelInstructions,
|
|
416
|
-
);
|
|
417
|
-
toml = ensureTopLevelTomlLine(
|
|
418
|
-
toml,
|
|
419
|
-
'notify',
|
|
420
|
-
isManagedCodexNotify(backupNotify) ? '' : backupNotify,
|
|
421
|
-
);
|
|
422
|
-
toml = ensureTomlKeyInSection(toml, '[features]', 'codex_hooks', readTomlKeyInSection(backupToml, '[features]', 'codex_hooks'));
|
|
290
|
+
const toml = cleanupCodexManagedConfig(configPath, { removePluginConfig: true });
|
|
423
291
|
if (toml.trim()) safeWrite(configPath, toml);
|
|
424
292
|
else removeIfExists(configPath);
|
|
425
293
|
removeCodexBackup(configPath, CODEX_CONFIG_BASENAME);
|
package/scripts/cli-config.mjs
CHANGED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export function printDoctorText(runtime, report) {
|
|
2
|
+
console.log(`\nHelloAGENTS doctor\n`)
|
|
3
|
+
console.log(runtime.msg(
|
|
4
|
+
`配置:\n package_version: ${report.config.packageVersion}\n install_mode: ${report.config.installMode}\n tracked_host_modes: ${JSON.stringify(report.config.trackedHostModes)}`,
|
|
5
|
+
`Config:\n package_version: ${report.config.packageVersion}\n install_mode: ${report.config.installMode}\n tracked_host_modes: ${JSON.stringify(report.config.trackedHostModes)}`,
|
|
6
|
+
))
|
|
7
|
+
|
|
8
|
+
for (const entry of report.hosts) {
|
|
9
|
+
console.log(`\n${entry.label}:`)
|
|
10
|
+
console.log(` status: ${entry.status}`)
|
|
11
|
+
console.log(` detected_mode: ${entry.detectedMode}`)
|
|
12
|
+
console.log(` tracked_mode: ${entry.trackedMode}`)
|
|
13
|
+
for (const [key, value] of Object.entries(entry.checks)) {
|
|
14
|
+
console.log(` ${key}: ${value ? 'ok' : 'missing'}`)
|
|
15
|
+
}
|
|
16
|
+
for (const note of entry.notes) {
|
|
17
|
+
console.log(` note: ${note}`)
|
|
18
|
+
}
|
|
19
|
+
for (const issue of entry.issues) {
|
|
20
|
+
console.log(` issue[${issue.code}]: ${issue.message}`)
|
|
21
|
+
}
|
|
22
|
+
if (entry.suggestedFix) {
|
|
23
|
+
console.log(` suggested_fix: ${entry.suggestedFix}`)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
console.log(`\nSummary: ok=${report.summary.ok} drift=${report.summary.drift} manual-plugin=${report.summary['manual-plugin']} not-installed=${report.summary['not-installed']} issues=${report.summary.issueCount}\n`)
|
|
28
|
+
}
|