helloagents 3.0.2-beta.1 → 3.0.7
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 +147 -45
- package/README_CN.md +148 -46
- package/bootstrap-lite.md +104 -46
- package/bootstrap.md +143 -112
- 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 +2 -12
- 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 +100 -0
- package/scripts/cli-codex.mjs +34 -156
- package/scripts/cli-config.mjs +1 -0
- package/scripts/cli-doctor-render.mjs +28 -0
- package/scripts/cli-doctor.mjs +367 -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/closeout-state.mjs +213 -0
- package/scripts/delivery-gate.mjs +256 -0
- package/scripts/guard-rules.mjs +122 -0
- package/scripts/guard.mjs +190 -168
- package/scripts/notify-context.mjs +77 -17
- 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 +120 -59
- 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/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/commands/auto/SKILL.md +37 -71
- 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 +19 -11
- package/skills/commands/idea/SKILL.md +55 -0
- package/skills/commands/init/SKILL.md +6 -3
- package/skills/commands/loop/SKILL.md +6 -5
- package/skills/commands/plan/SKILL.md +116 -0
- package/skills/commands/prd/SKILL.md +20 -15
- package/skills/commands/verify/SKILL.md +32 -9
- package/skills/commands/wiki/SKILL.md +59 -0
- package/skills/hello-review/SKILL.md +9 -0
- package/skills/hello-subagent/SKILL.md +4 -3
- package/skills/hello-ui/SKILL.md +36 -8
- package/skills/hello-verify/SKILL.md +10 -2
- package/skills/helloagents/SKILL.md +24 -13
- 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,39 @@
|
|
|
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_DEVELOPER_INSTRUCTIONS,
|
|
11
|
+
CODEX_MANAGED_TOML_COMMENT,
|
|
12
|
+
CODEX_PLUGIN_CONFIG_HEADER,
|
|
13
|
+
installCodexDeveloperInstructions,
|
|
14
|
+
isManagedCodexBackupInstruction,
|
|
15
|
+
isManagedCodexModelInstruction,
|
|
16
|
+
isManagedCodexNotify,
|
|
17
|
+
removeCodexPluginConfig,
|
|
18
|
+
uninstallCodexDeveloperInstructions,
|
|
19
|
+
upsertCodexPluginConfig,
|
|
20
|
+
} from './cli-codex-config.mjs';
|
|
8
21
|
import {
|
|
9
22
|
upsertTopLevelTomlKey,
|
|
10
|
-
upsertTopLevelTomlBlock,
|
|
11
23
|
readTopLevelTomlLine,
|
|
12
|
-
readTopLevelTomlBlock,
|
|
13
24
|
ensureTopLevelTomlLine,
|
|
14
|
-
ensureTopLevelTomlBlock,
|
|
15
25
|
readTomlKeyInSection,
|
|
16
26
|
removeTomlKeyInSection,
|
|
17
|
-
removeTopLevelTomlBlock,
|
|
18
27
|
ensureTomlKeyInSection,
|
|
19
|
-
stripTomlSection,
|
|
20
28
|
removeTopLevelTomlLines,
|
|
21
29
|
} from './cli-toml.mjs';
|
|
22
30
|
|
|
23
31
|
export const CODEX_MARKETPLACE_NAME = 'local-plugins';
|
|
24
32
|
export const CODEX_PLUGIN_NAME = 'helloagents';
|
|
25
33
|
export const CODEX_PLUGIN_KEY = `${CODEX_PLUGIN_NAME}@${CODEX_MARKETPLACE_NAME}`;
|
|
26
|
-
export
|
|
27
|
-
export const CODEX_MANAGED_TOML_COMMENT = '# helloagents-managed';
|
|
34
|
+
export { CODEX_DEVELOPER_INSTRUCTIONS, CODEX_MANAGED_TOML_COMMENT, CODEX_PLUGIN_CONFIG_HEADER };
|
|
28
35
|
export const CODEX_RUNTIME_CARRIER = 'AGENTS.md';
|
|
29
|
-
const CODEX_BACKUP_TIMESTAMP_RE = /^\d{8}-\d{6}$/;
|
|
30
36
|
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
37
|
export const CODEX_RUNTIME_ENTRIES = [
|
|
36
38
|
'.codex-plugin',
|
|
37
39
|
'assets',
|
|
@@ -46,142 +48,6 @@ export const CODEX_RUNTIME_ENTRIES = [
|
|
|
46
48
|
'templates',
|
|
47
49
|
];
|
|
48
50
|
|
|
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
51
|
function getDefaultCodexMarketplace() {
|
|
186
52
|
return {
|
|
187
53
|
name: CODEX_MARKETPLACE_NAME,
|
|
@@ -251,6 +117,13 @@ function buildCodexRuntimeCarrier(bootstrapContent) {
|
|
|
251
117
|
return normalized ? `${normalized}\n` : '';
|
|
252
118
|
}
|
|
253
119
|
|
|
120
|
+
function injectCodexRuntimeCarrier(filePath, bootstrapPath) {
|
|
121
|
+
const bootstrapContent = safeRead(bootstrapPath);
|
|
122
|
+
if (!bootstrapContent) return false;
|
|
123
|
+
injectMarkedContent(filePath, buildCodexRuntimeCarrier(bootstrapContent).trimEnd());
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
|
|
254
127
|
function writeCodexRuntimeCarrier(filePath, bootstrapPath) {
|
|
255
128
|
const bootstrapContent = safeRead(bootstrapPath);
|
|
256
129
|
if (!bootstrapContent) return false;
|
|
@@ -258,24 +131,26 @@ function writeCodexRuntimeCarrier(filePath, bootstrapPath) {
|
|
|
258
131
|
return true;
|
|
259
132
|
}
|
|
260
133
|
|
|
134
|
+
function stripCodexModelInstructions(toml = '') {
|
|
135
|
+
return removeTopLevelTomlLines(
|
|
136
|
+
toml,
|
|
137
|
+
(line) => line.startsWith('model_instructions_file ='),
|
|
138
|
+
).text;
|
|
139
|
+
}
|
|
140
|
+
|
|
261
141
|
export function installCodexStandby(home, pkgRoot) {
|
|
262
142
|
const codexDir = join(home, '.codex');
|
|
263
143
|
if (!existsSync(codexDir)) return false;
|
|
264
144
|
ensureDir(codexDir);
|
|
265
145
|
|
|
266
146
|
const codexAgentsPath = join(codexDir, CODEX_RUNTIME_CARRIER);
|
|
267
|
-
|
|
268
|
-
if (bootstrapContent) {
|
|
269
|
-
injectMarkedContent(
|
|
270
|
-
codexAgentsPath,
|
|
271
|
-
buildCodexRuntimeCarrier(bootstrapContent).trimEnd(),
|
|
272
|
-
);
|
|
273
|
-
}
|
|
147
|
+
injectCodexRuntimeCarrier(codexAgentsPath, join(pkgRoot, 'bootstrap-lite.md'));
|
|
274
148
|
|
|
275
149
|
const configPath = join(codexDir, 'config.toml');
|
|
276
150
|
let toml = safeRead(configPath) || '';
|
|
277
151
|
ensureTimestampedBackup(configPath, CODEX_CONFIG_BASENAME);
|
|
278
152
|
|
|
153
|
+
toml = stripCodexModelInstructions(toml);
|
|
279
154
|
toml = upsertTopLevelTomlKey(toml, 'notify', `["node", "${normalizePath(join(pkgRoot, 'scripts', 'notify.mjs'))}", "codex-notify"]`);
|
|
280
155
|
toml = installCodexDeveloperInstructions(configPath, toml);
|
|
281
156
|
safeWrite(configPath, toml);
|
|
@@ -366,12 +241,14 @@ export function installCodexGlobal(home, pkgRoot) {
|
|
|
366
241
|
join(installedPluginRoot, CODEX_RUNTIME_CARRIER),
|
|
367
242
|
join(installedPluginRoot, 'bootstrap.md'),
|
|
368
243
|
);
|
|
244
|
+
injectCodexRuntimeCarrier(join(codexDir, CODEX_RUNTIME_CARRIER), join(pkgRoot, 'bootstrap.md'));
|
|
369
245
|
|
|
370
246
|
ensureDir(join(home, '.agents', 'plugins'));
|
|
371
247
|
updateCodexMarketplace(marketplaceFile);
|
|
372
248
|
|
|
373
249
|
let toml = safeRead(configPath) || '';
|
|
374
250
|
ensureTimestampedBackup(configPath, CODEX_CONFIG_BASENAME);
|
|
251
|
+
toml = stripCodexModelInstructions(toml);
|
|
375
252
|
toml = upsertTopLevelTomlKey(
|
|
376
253
|
toml,
|
|
377
254
|
'notify',
|
|
@@ -395,6 +272,7 @@ export function uninstallCodexGlobal(home) {
|
|
|
395
272
|
removeIfExists(pluginRoot);
|
|
396
273
|
removeIfExists(pluginCacheRoot);
|
|
397
274
|
removeCodexMarketplaceEntry(marketplaceFile);
|
|
275
|
+
removeMarkedContent(join(codexDir, 'AGENTS.md'));
|
|
398
276
|
|
|
399
277
|
const backupToml = readCodexBackup(configPath, CODEX_CONFIG_BASENAME);
|
|
400
278
|
let toml = safeRead(configPath) || '';
|
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
|
+
}
|