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.
Files changed (75) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/README.md +157 -57
  5. package/README_CN.md +157 -57
  6. package/bootstrap-lite.md +125 -50
  7. package/bootstrap.md +169 -123
  8. package/cli.mjs +80 -427
  9. package/gemini-extension.json +1 -1
  10. package/hooks/hooks-claude.json +10 -0
  11. package/hooks/hooks.json +10 -0
  12. package/package.json +1 -1
  13. package/scripts/advisor-state.mjs +222 -0
  14. package/scripts/capability-registry.mjs +59 -0
  15. package/scripts/cli-codex-backup.mjs +59 -0
  16. package/scripts/cli-codex-config.mjs +94 -0
  17. package/scripts/cli-codex.mjs +90 -222
  18. package/scripts/cli-config.mjs +1 -0
  19. package/scripts/cli-doctor-render.mjs +28 -0
  20. package/scripts/cli-doctor.mjs +370 -0
  21. package/scripts/cli-host-detect.mjs +94 -0
  22. package/scripts/cli-lifecycle-hosts.mjs +123 -0
  23. package/scripts/cli-lifecycle.mjs +213 -0
  24. package/scripts/cli-messages.mjs +76 -52
  25. package/scripts/cli-toml.mjs +30 -0
  26. package/scripts/closeout-state.mjs +213 -0
  27. package/scripts/delivery-gate.mjs +256 -0
  28. package/scripts/guard-rules.mjs +147 -0
  29. package/scripts/guard.mjs +218 -168
  30. package/scripts/notify-context.mjs +78 -23
  31. package/scripts/notify-events.mjs +5 -1
  32. package/scripts/notify-route.mjs +111 -0
  33. package/scripts/notify-shared.mjs +0 -2
  34. package/scripts/notify-source.mjs +113 -0
  35. package/scripts/notify-ui.mjs +40 -6
  36. package/scripts/notify.mjs +137 -65
  37. package/scripts/plan-contract.mjs +210 -0
  38. package/scripts/project-storage.mjs +235 -0
  39. package/scripts/ralph-loop.mjs +9 -58
  40. package/scripts/replay-state.mjs +210 -0
  41. package/scripts/review-state.mjs +220 -0
  42. package/scripts/runtime-context.mjs +74 -0
  43. package/scripts/turn-state.mjs +173 -0
  44. package/scripts/verify-state.mjs +226 -0
  45. package/scripts/visual-state.mjs +244 -0
  46. package/scripts/workflow-core.mjs +165 -0
  47. package/scripts/workflow-plan-files.mjs +249 -0
  48. package/scripts/workflow-recommendation.mjs +335 -0
  49. package/scripts/workflow-state.mjs +113 -0
  50. package/skills/_meta/SKILL.md +1 -1
  51. package/skills/commands/auto/SKILL.md +48 -67
  52. package/skills/commands/build/SKILL.md +67 -0
  53. package/skills/commands/clean/SKILL.md +10 -8
  54. package/skills/commands/commit/SKILL.md +8 -4
  55. package/skills/commands/help/SKILL.md +18 -11
  56. package/skills/commands/idea/SKILL.md +55 -0
  57. package/skills/commands/init/SKILL.md +16 -8
  58. package/skills/commands/loop/SKILL.md +6 -5
  59. package/skills/commands/plan/SKILL.md +118 -0
  60. package/skills/commands/prd/SKILL.md +22 -15
  61. package/skills/commands/verify/SKILL.md +32 -9
  62. package/skills/commands/wiki/SKILL.md +11 -11
  63. package/skills/hello-review/SKILL.md +9 -0
  64. package/skills/hello-subagent/SKILL.md +5 -3
  65. package/skills/hello-ui/SKILL.md +36 -8
  66. package/skills/hello-verify/SKILL.md +12 -3
  67. package/skills/helloagents/SKILL.md +36 -20
  68. package/templates/DESIGN.md +25 -4
  69. package/templates/STATE.md +3 -0
  70. package/templates/plans/contract.json +48 -0
  71. package/templates/plans/plan.md +23 -0
  72. package/templates/plans/tasks.md +3 -3
  73. package/skills/commands/design/SKILL.md +0 -108
  74. package/skills/commands/review/SKILL.md +0 -16
  75. package/templates/plans/design.md +0 -14
@@ -1,37 +1,37 @@
1
1
  import { join, dirname } from 'node:path';
2
- import { existsSync, copyFileSync, readdirSync } from 'node:fs';
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 const CODEX_PLUGIN_CONFIG_HEADER = `[plugins."${CODEX_PLUGIN_KEY}"]`;
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
- const bootstrapContent = safeRead(join(pkgRoot, 'bootstrap-lite.md'));
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 = upsertTopLevelTomlKey(toml, 'notify', `["node", "${normalizePath(join(pkgRoot, 'scripts', 'notify.mjs'))}", "codex-notify"]`);
280
- toml = installCodexDeveloperInstructions(configPath, toml);
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 backupToml = readCodexBackup(configPath, CODEX_CONFIG_BASENAME);
296
- let toml = safeRead(configPath) || '';
297
- if (toml.includes('helloagents') || toml.includes('HelloAGENTS')) {
298
- toml = removeTopLevelTomlLines(toml, (line) => {
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 = upsertTopLevelTomlKey(
376
- toml,
377
- 'notify',
378
- `["node", "${normalizePath(join(pluginRoot, 'scripts', 'notify.mjs'))}", "codex-notify"]`,
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 backupToml = readCodexBackup(configPath, CODEX_CONFIG_BASENAME);
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);
@@ -7,6 +7,7 @@ export const DEFAULTS = {
7
7
  ralph_loop_enabled: true,
8
8
  guard_enabled: true,
9
9
  kb_create_mode: 1,
10
+ project_store_mode: 'local',
10
11
  commit_attribution: '',
11
12
  install_mode: 'standby',
12
13
  };
@@ -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
+ }