helloagents 3.0.28 → 3.0.30
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/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/README.md +50 -37
- package/README_CN.md +50 -35
- package/bootstrap-lite.md +8 -8
- package/bootstrap.md +12 -10
- package/gemini-extension.json +1 -1
- package/install.ps1 +5 -5
- package/install.sh +5 -5
- package/package.json +1 -1
- package/scripts/advisor-state.mjs +1 -1
- package/scripts/cli-branch.mjs +7 -3
- package/scripts/cli-codex.mjs +6 -5
- package/scripts/cli-deepseek.mjs +131 -0
- package/scripts/cli-doctor-codex.mjs +10 -5
- package/scripts/cli-doctor-render.mjs +16 -0
- package/scripts/cli-doctor.mjs +78 -5
- package/scripts/cli-host-detect.mjs +29 -0
- package/scripts/cli-hosts.mjs +8 -0
- package/scripts/cli-lifecycle-hosts.mjs +28 -2
- package/scripts/cli-lifecycle.mjs +1 -1
- package/scripts/cli-messages.mjs +28 -15
- package/scripts/cli-runtime-carrier.mjs +3 -3
- package/scripts/cli-utils.mjs +9 -0
- package/scripts/notify-events.mjs +1 -0
- package/scripts/notify-route.mjs +3 -4
- package/scripts/notify-source.mjs +1 -0
- package/scripts/notify.mjs +6 -1
- package/scripts/plan-contract.mjs +1 -1
- package/scripts/project-storage.mjs +4 -4
- package/scripts/replay-state.mjs +22 -4
- package/scripts/runtime-context.mjs +14 -2
- package/scripts/runtime-scope.mjs +144 -2
- package/scripts/session-capsule.mjs +14 -0
- package/scripts/turn-state.mjs +7 -0
- package/skills/commands/build/SKILL.md +1 -1
- package/skills/commands/commit/SKILL.md +2 -2
- package/skills/commands/global/SKILL.md +71 -0
- package/skills/commands/help/SKILL.md +16 -15
- package/skills/commands/init/SKILL.md +14 -31
- package/skills/commands/wiki/SKILL.md +1 -1
- package/skills/hello-review/SKILL.md +1 -1
- package/skills/hello-ui/SKILL.md +5 -5
- package/skills/helloagents/SKILL.md +6 -5
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
import { spawnSync } from 'node:child_process'
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
installClaudeStandby,
|
|
5
|
+
installDeepseekGlobal,
|
|
6
|
+
installDeepseekStandby,
|
|
7
|
+
installGeminiStandby,
|
|
8
|
+
uninstallClaudeStandby,
|
|
9
|
+
uninstallDeepseekGlobal,
|
|
10
|
+
uninstallDeepseekStandby,
|
|
11
|
+
uninstallGeminiStandby,
|
|
12
|
+
} from './cli-hosts.mjs'
|
|
4
13
|
import {
|
|
5
14
|
cleanupCodexGlobalResidueForStandby,
|
|
6
15
|
installCodexGlobal,
|
|
@@ -91,6 +100,10 @@ function installHostStandby(runtime, host) {
|
|
|
91
100
|
installGeminiStandby(runtime.home, runtime.pkgRoot)
|
|
92
101
|
return {}
|
|
93
102
|
}
|
|
103
|
+
if (host === 'deepseek') {
|
|
104
|
+
installDeepseekStandby(runtime.home, runtime.pkgRoot)
|
|
105
|
+
return {}
|
|
106
|
+
}
|
|
94
107
|
if (!installCodexStandby(runtime.home, runtime.pkgRoot)) return { skipped: true }
|
|
95
108
|
cleanupCodexGlobalResidueForStandby(runtime.home)
|
|
96
109
|
return {}
|
|
@@ -117,6 +130,10 @@ function installHostGlobal(runtime, host) {
|
|
|
117
130
|
'Gemini CLI extension auto-install failed. Run manually: gemini extensions install https://github.com/hellowind777/helloagents',
|
|
118
131
|
)
|
|
119
132
|
}
|
|
133
|
+
if (host === 'deepseek') {
|
|
134
|
+
installDeepseekGlobal(runtime.home, runtime.pkgRoot)
|
|
135
|
+
return {}
|
|
136
|
+
}
|
|
120
137
|
uninstallCodexStandby(runtime.home)
|
|
121
138
|
return installCodexGlobal(runtime.home, runtime.pkgRoot) ? {} : { skipped: true }
|
|
122
139
|
}
|
|
@@ -124,6 +141,7 @@ function installHostGlobal(runtime, host) {
|
|
|
124
141
|
function cleanupHostStandby(runtime, host) {
|
|
125
142
|
if (host === 'claude') return { skipped: !uninstallClaudeStandby(runtime.home) }
|
|
126
143
|
if (host === 'gemini') return { skipped: !uninstallGeminiStandby(runtime.home) }
|
|
144
|
+
if (host === 'deepseek') return { skipped: !uninstallDeepseekStandby(runtime.home) }
|
|
127
145
|
const standbyCleaned = uninstallCodexStandby(runtime.home)
|
|
128
146
|
const globalResidueCleaned = uninstallCodexGlobal(runtime.home)
|
|
129
147
|
return { skipped: !(standbyCleaned || globalResidueCleaned) }
|
|
@@ -150,6 +168,7 @@ function cleanupHostGlobal(runtime, host) {
|
|
|
150
168
|
'Gemini CLI extension auto-remove failed. Run manually: gemini extensions uninstall helloagents',
|
|
151
169
|
)
|
|
152
170
|
}
|
|
171
|
+
if (host === 'deepseek') return { skipped: !uninstallDeepseekGlobal(runtime.home) }
|
|
153
172
|
return { skipped: !uninstallCodexGlobal(runtime.home) }
|
|
154
173
|
}
|
|
155
174
|
|
|
@@ -175,12 +194,18 @@ function installStandby(runtime) {
|
|
|
175
194
|
console.log(runtime.msg(' - Codex CLI 未检测到,跳过', ' - Codex CLI not detected, skipped'))
|
|
176
195
|
results.codex = { skipped: true }
|
|
177
196
|
}
|
|
197
|
+
if (installDeepseekStandby(runtime.home, runtime.pkgRoot)) {
|
|
198
|
+
runtime.ok(runtime.msg('DeepSeek TUI 已配置(standby 模式)', 'DeepSeek TUI configured (standby mode)'))
|
|
199
|
+
results.deepseek = {}
|
|
200
|
+
} else {
|
|
201
|
+
results.deepseek = { skipped: true }
|
|
202
|
+
}
|
|
178
203
|
return results
|
|
179
204
|
}
|
|
180
205
|
|
|
181
206
|
function installGlobal(runtime) {
|
|
182
207
|
const results = {}
|
|
183
|
-
for (const host of ['claude', 'gemini', 'codex']) {
|
|
208
|
+
for (const host of ['claude', 'gemini', 'codex', 'deepseek']) {
|
|
184
209
|
const result = installHostGlobal(runtime, host)
|
|
185
210
|
reportHostAction(runtime, 'install', host, 'global', result)
|
|
186
211
|
results[host] = result
|
|
@@ -198,6 +223,7 @@ export function uninstallAllHosts(runtime) {
|
|
|
198
223
|
cleanupHostGlobal(runtime, 'gemini')
|
|
199
224
|
uninstallCodexStandby(runtime.home)
|
|
200
225
|
uninstallCodexGlobal(runtime.home)
|
|
226
|
+
uninstallDeepseekStandby(runtime.home)
|
|
201
227
|
}
|
|
202
228
|
|
|
203
229
|
export function runHostLifecycle(runtime, action, host, mode) {
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
import { installAllHosts, runHostLifecycle, uninstallAllHosts } from './cli-lifecycle-hosts.mjs'
|
|
11
11
|
import { ensureDir, safeJson, safeWrite } from './cli-utils.mjs'
|
|
12
12
|
|
|
13
|
-
export const HOSTS = ['claude', 'gemini', 'codex']
|
|
13
|
+
export const HOSTS = ['claude', 'gemini', 'codex', 'deepseek']
|
|
14
14
|
|
|
15
15
|
const runtime = {
|
|
16
16
|
home: '',
|
package/scripts/cli-messages.mjs
CHANGED
|
@@ -19,6 +19,18 @@ function codexGlobalStatus({ home, msg }) {
|
|
|
19
19
|
: msg('安装 Codex CLI 后重新运行 npm install -g helloagents', 'Install Codex CLI then re-run npm install -g helloagents')
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
function deepseekStandbyStatus({ home, msg }) {
|
|
23
|
+
return existsSync(join(home, '.deepseek'))
|
|
24
|
+
? msg('已自动配置(~/.deepseek/AGENTS.md)', 'Auto-configured (~/.deepseek/AGENTS.md)')
|
|
25
|
+
: msg('安装 DeepSeek TUI 后重新运行 npm install -g helloagents', 'Install DeepSeek TUI then re-run npm install -g helloagents')
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function deepseekGlobalStatus({ home, msg }) {
|
|
29
|
+
return existsSync(join(home, '.deepseek'))
|
|
30
|
+
? msg('已自动切到受管全局载体(~/.deepseek/AGENTS.md)', 'Managed global carrier applied (~/.deepseek/AGENTS.md)')
|
|
31
|
+
: msg('安装 DeepSeek TUI 后重新运行 npm install -g helloagents', 'Install DeepSeek TUI then re-run npm install -g helloagents')
|
|
32
|
+
}
|
|
33
|
+
|
|
22
34
|
function pluginCommands() {
|
|
23
35
|
return [
|
|
24
36
|
' Claude Code: /plugin marketplace add hellowind777/helloagents',
|
|
@@ -49,34 +61,34 @@ function renderInstallMessage(context, mode, state) {
|
|
|
49
61
|
if (mode === 'global') {
|
|
50
62
|
if (install) {
|
|
51
63
|
return msg(
|
|
52
|
-
`\n ✅ HelloAGENTS 已安装(global 模式)!\n\n Claude Code / Gemini CLI: 已自动尝试宿主原生插件/扩展安装\n Codex: ${codexGlobalStatus(context)}(~/.agents/plugins/marketplace.json + ~/plugins/helloagents)\n\n ${restartHint(msg)}\n\n 若宿主命令不可用,请手动执行:\n${pluginCommands()}\n\n 切换模式:\n helloagents --standby 标准模式(默认,非插件安装)`,
|
|
53
|
-
`\n ✅ HelloAGENTS installed (global mode)!\n\n Claude Code / Gemini CLI: native plugin/extension install attempted automatically\n Codex: ${codexGlobalStatus(context)} (~/.agents/plugins/marketplace.json + ~/plugins/helloagents)\n\n ${restartHint(msg)}\n\n If a host command is unavailable, run manually:\n${pluginCommands()}\n\n Switch modes:\n helloagents --standby Standby mode (default, non-plugin install)`,
|
|
64
|
+
`\n ✅ HelloAGENTS 已安装(global 模式)!\n\n Claude Code / Gemini CLI: 已自动尝试宿主原生插件/扩展安装\n Codex: ${codexGlobalStatus(context)}(~/.agents/plugins/marketplace.json + ~/plugins/helloagents)\n DeepSeek TUI: ${deepseekGlobalStatus(context)}\n\n ${restartHint(msg)}\n\n 若宿主命令不可用,请手动执行:\n${pluginCommands()}\n\n 切换模式:\n helloagents --standby 标准模式(默认,非插件安装)`,
|
|
65
|
+
`\n ✅ HelloAGENTS installed (global mode)!\n\n Claude Code / Gemini CLI: native plugin/extension install attempted automatically\n Codex: ${codexGlobalStatus(context)} (~/.agents/plugins/marketplace.json + ~/plugins/helloagents)\n DeepSeek TUI: ${deepseekGlobalStatus(context)}\n\n ${restartHint(msg)}\n\n If a host command is unavailable, run manually:\n${pluginCommands()}\n\n Switch modes:\n helloagents --standby Standby mode (default, non-plugin install)`,
|
|
54
66
|
)
|
|
55
67
|
}
|
|
56
68
|
return msg(
|
|
57
69
|
refresh
|
|
58
|
-
? ` global 模式已刷新。\n Claude Code / Gemini 已自动尝试刷新宿主插件/扩展;Codex
|
|
59
|
-
: ` 所有项目将自动启用完整 HelloAGENTS 规则。\n Claude Code / Gemini 已自动尝试安装宿主插件/扩展;Codex
|
|
70
|
+
? ` global 模式已刷新。\n Claude Code / Gemini 已自动尝试刷新宿主插件/扩展;Codex 原生本地插件已重装并同步最新文件;DeepSeek TUI 受管全局载体已同步。\n ${restartHint(msg)}`
|
|
71
|
+
: ` 所有项目将自动启用完整 HelloAGENTS 规则。\n Claude Code / Gemini 已自动尝试安装宿主插件/扩展;Codex 已自动安装原生本地插件;DeepSeek TUI 已切到受管全局载体。\n ${restartHint(msg)}\n\n若宿主命令不可用,请手动执行:\n${pluginCommands()}`,
|
|
60
72
|
refresh
|
|
61
|
-
? ` Global mode refreshed.\n Claude Code / Gemini native plugin/extension refresh was attempted automatically; Codex native local-plugin files were reinstalled and synced.\n ${restartHint(msg)}`
|
|
62
|
-
: ` All projects will use full HelloAGENTS rules.\n Claude Code / Gemini native plugin/extension install was attempted automatically; Codex now uses the native local-plugin path automatically.\n ${restartHint(msg)}\n\nIf a host command is unavailable, run manually:\n${pluginCommands()}`,
|
|
73
|
+
? ` Global mode refreshed.\n Claude Code / Gemini native plugin/extension refresh was attempted automatically; Codex native local-plugin files were reinstalled and synced; the managed DeepSeek TUI global carrier was refreshed.\n ${restartHint(msg)}`
|
|
74
|
+
: ` All projects will use full HelloAGENTS rules.\n Claude Code / Gemini native plugin/extension install was attempted automatically; Codex now uses the native local-plugin path automatically; DeepSeek TUI now uses the managed global carrier.\n ${restartHint(msg)}\n\nIf a host command is unavailable, run manually:\n${pluginCommands()}`,
|
|
63
75
|
)
|
|
64
76
|
}
|
|
65
77
|
|
|
66
78
|
if (install) {
|
|
67
79
|
return msg(
|
|
68
|
-
`\n ✅ HelloAGENTS 已安装(standby 模式)!\n\n Claude Code: 已自动配置(~/.claude/CLAUDE.md + hooks)\n Gemini CLI: 已自动配置(~/.gemini/GEMINI.md)\n Codex: ${codexStandbyStatus(context)}\n\n ${restartHint(msg)}\n\n standby 模式下,hello-* 技能不会自动触发。\n 在项目中使用 ~wiki
|
|
69
|
-
`\n ✅ HelloAGENTS installed (standby mode)!\n\n Claude Code: Auto-configured (~/.claude/CLAUDE.md + hooks)\n Gemini CLI: Auto-configured (~/.gemini/GEMINI.md)\n Codex: ${codexStandbyStatus(context)}\n\n ${restartHint(msg)}\n\n In standby mode, hello-* skills won't auto-trigger.\n Use ~wiki to create or sync the KB only
|
|
80
|
+
`\n ✅ HelloAGENTS 已安装(standby 模式)!\n\n Claude Code: 已自动配置(~/.claude/CLAUDE.md + hooks)\n Gemini CLI: 已自动配置(~/.gemini/GEMINI.md)\n Codex: ${codexStandbyStatus(context)}\n DeepSeek TUI: ${deepseekStandbyStatus(context)}\n\n ${restartHint(msg)}\n\n standby 模式下,hello-* 技能不会自动触发。\n 在项目中使用 ~wiki 或 ~init 仅创建/同步知识库;用 ~global 初始化项目级全局模式;也可用 ~command 按需调用。\n\n 切换模式:\n helloagents --global 项目级全局模式(自动尝试 Claude/Gemini 插件或扩展;Codex 自动装原生本地插件;DeepSeek 使用受管 AGENTS 载体)`,
|
|
81
|
+
`\n ✅ HelloAGENTS installed (standby mode)!\n\n Claude Code: Auto-configured (~/.claude/CLAUDE.md + hooks)\n Gemini CLI: Auto-configured (~/.gemini/GEMINI.md)\n Codex: ${codexStandbyStatus(context)}\n DeepSeek TUI: ${deepseekStandbyStatus(context)}\n\n ${restartHint(msg)}\n\n In standby mode, hello-* skills won't auto-trigger.\n Use ~wiki or ~init to create or sync the KB only; use ~global to initialize project-level global mode; ~command stays available on demand.\n\n Switch modes:\n helloagents --global Project-level global mode (auto-attempts Claude/Gemini plugins or extensions; native local plugin auto-install for Codex; DeepSeek uses a managed AGENTS carrier)`,
|
|
70
82
|
)
|
|
71
83
|
}
|
|
72
84
|
|
|
73
85
|
return msg(
|
|
74
86
|
refresh
|
|
75
87
|
? ` standby 模式已刷新,CLI 注入与链接已同步最新文件。\n ${restartHint(msg)}\n ${removeHint(msg)}`
|
|
76
|
-
: ` 项目可通过 ~wiki
|
|
88
|
+
: ` 项目可通过 ~wiki 或 ~init 创建/同步知识库;用 ~global 初始化项目级全局模式;未初始化时仅注入轻量规则。\n ${restartHint(msg)}\n ${removeHint(msg)}`,
|
|
77
89
|
refresh
|
|
78
90
|
? ` Standby mode refreshed; injected files and links were synchronized.\n ${restartHint(msg)}\n ${removeHint(msg)}`
|
|
79
|
-
: ` Projects can use ~wiki
|
|
91
|
+
: ` Projects can use ~wiki or ~init to create/sync the KB; use ~global to initialize project-level global mode. Projects that are not initialized get lite rules only.\n ${restartHint(msg)}\n ${removeHint(msg)}`,
|
|
80
92
|
)
|
|
81
93
|
}
|
|
82
94
|
|
|
@@ -84,33 +96,34 @@ function renderHelp({ pkgVersion, msg }) {
|
|
|
84
96
|
return `
|
|
85
97
|
HelloAGENTS v${pkgVersion} — The orchestration kernel for AI CLIs
|
|
86
98
|
|
|
87
|
-
${msg('安装', 'Install')}:
|
|
99
|
+
${msg('安装', 'Install')}:
|
|
88
100
|
npm install -g helloagents ${msg('(安装命令并同步稳定运行根目录;CLI 部署需显式执行 helloagents install ...)', '(installs the command and syncs the stable runtime root; deploy to CLIs explicitly with helloagents install ...)')}
|
|
89
101
|
HELLOAGENTS=codex:global npm install -g helloagents
|
|
90
102
|
helloagents-js ${msg('(受管宿主配置的跨平台稳定入口)', '(cross-platform stable entrypoint for managed host configs)')}
|
|
91
103
|
|
|
92
104
|
${msg('模式切换', 'Mode switching')}:
|
|
93
|
-
helloagents --global ${msg('
|
|
105
|
+
helloagents --global ${msg('项目级全局模式(自动尝试 Claude/Gemini 插件或扩展;Codex 自动装原生本地插件;DeepSeek 使用受管 AGENTS 载体)', 'Project-level global mode (auto-attempts Claude/Gemini plugins or extensions; native local plugin auto-install for Codex; DeepSeek uses a managed AGENTS carrier)')}
|
|
94
106
|
helloagents --standby ${msg('标准模式(非插件安装,hello-* 不自动触发,默认)', "Standby mode (non-plugin install, hello-* won't auto-trigger, default)")}
|
|
95
107
|
|
|
96
108
|
${msg('单 CLI 管理', 'Scoped CLI management')}:
|
|
97
109
|
helloagents install codex --standby
|
|
110
|
+
helloagents install deepseek --standby
|
|
98
111
|
helloagents install --all --global
|
|
99
112
|
helloagents update codex
|
|
100
113
|
helloagents cleanup claude --global
|
|
101
114
|
helloagents uninstall gemini
|
|
102
|
-
${msg('支持: claude | gemini | codex | --all;省略模式时优先沿用该 CLI 已记录/已检测的模式,否则回退 standby', 'Hosts: claude | gemini | codex | --all; omit mode to reuse the tracked/detected mode for that CLI, then fall back to standby')}
|
|
115
|
+
${msg('支持: claude | gemini | codex | deepseek | --all;省略模式时优先沿用该 CLI 已记录/已检测的模式,否则回退 standby', 'Hosts: claude | gemini | codex | deepseek | --all; omit mode to reuse the tracked/detected mode for that CLI, then fall back to standby')}
|
|
103
116
|
|
|
104
117
|
${msg('分支切换', 'Branch switching')}:
|
|
105
118
|
helloagents switch-branch beta
|
|
106
119
|
helloagents switch-branch beta claude --global
|
|
107
|
-
helloagents branch
|
|
120
|
+
helloagents branch beta --all --standby
|
|
108
121
|
${msg('先通过 npm 安装指定 ref,再通过 npm 脚本同步宿主 CLI', 'Installs the requested ref with npm first, then syncs host CLIs through npm scripts')}
|
|
109
122
|
|
|
110
123
|
${msg('诊断', 'Diagnostics')}:
|
|
111
124
|
helloagents doctor
|
|
112
125
|
helloagents doctor codex --json
|
|
113
|
-
${msg('检查 carrier、链接、hooks、配置注入、Codex
|
|
126
|
+
${msg('检查 carrier、链接、hooks、配置注入、Codex 插件安装、DeepSeek 原生 doctor 摘要、受管 model_instructions_file 指向、Codex hook trust 本机状态与版本漂移', 'Checks carriers, links, hooks, config injections, Codex plugin installation, DeepSeek native doctor summaries, managed model_instructions_file targeting, machine-local Codex hook trust state, and version drift')}
|
|
114
127
|
|
|
115
128
|
${msg('Codex /goal', 'Codex /goal')}:
|
|
116
129
|
helloagents codex goals status
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { join } from 'node:path'
|
|
2
2
|
|
|
3
|
-
import { safeJson } from './cli-utils.mjs'
|
|
3
|
+
import { safeJson, withCarrierProfile } from './cli-utils.mjs'
|
|
4
4
|
|
|
5
5
|
export function readCarrierSettings(home) {
|
|
6
6
|
return safeJson(join(home, '.helloagents', 'helloagents.json')) || {}
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
export function buildRuntimeCarrier(bootstrapContent, settings = {}) {
|
|
9
|
+
export function buildRuntimeCarrier(bootstrapContent, settings = {}, options = {}) {
|
|
10
10
|
void settings
|
|
11
11
|
const normalized = String(bootstrapContent || '').trim()
|
|
12
12
|
if (!normalized) return ''
|
|
13
13
|
|
|
14
|
-
return
|
|
14
|
+
return withCarrierProfile(normalized, options.profile || '')
|
|
15
15
|
}
|
package/scripts/cli-utils.mjs
CHANGED
|
@@ -54,8 +54,17 @@ export function removeLink(p) {
|
|
|
54
54
|
|
|
55
55
|
const MARKER = '<!-- HELLOAGENTS_START -->';
|
|
56
56
|
const MARKER_END = '<!-- HELLOAGENTS_END -->';
|
|
57
|
+
export const FULL_CARRIER_PROFILE_MARKER = '<!-- HELLOAGENTS_PROFILE: full -->';
|
|
57
58
|
const MARKER_RE = new RegExp(`\\n*${MARKER}[\\s\\S]*?${MARKER_END}\\n*`, 'g');
|
|
58
59
|
|
|
60
|
+
export function withCarrierProfile(content, profile = '') {
|
|
61
|
+
const normalized = String(content || '').trim();
|
|
62
|
+
if (!normalized) return '';
|
|
63
|
+
if (profile !== 'full') return `${normalized}\n`;
|
|
64
|
+
if (normalized.includes(FULL_CARRIER_PROFILE_MARKER)) return `${normalized}\n`;
|
|
65
|
+
return `${FULL_CARRIER_PROFILE_MARKER}\n${normalized}\n`;
|
|
66
|
+
}
|
|
67
|
+
|
|
59
68
|
/** Inject content wrapped in markers, preserving existing content outside markers. */
|
|
60
69
|
export function injectMarkedContent(filePath, content) {
|
|
61
70
|
const existing = safeRead(filePath) || '';
|
|
@@ -11,6 +11,7 @@ export function shouldIgnoreFormattedSubagent(lastMsg, outputFormatEnabled) {
|
|
|
11
11
|
export function resolveNotifyHost(argv = []) {
|
|
12
12
|
const args = Array.from(argv, (value) => String(value || ''));
|
|
13
13
|
const command = args[2] || args[0] || '';
|
|
14
|
+
if (args.includes('--deepseek')) return 'deepseek';
|
|
14
15
|
if (args.includes('--gemini')) return 'gemini';
|
|
15
16
|
if (args.includes('--codex') || command === 'codex-notify') return 'codex';
|
|
16
17
|
return 'claude';
|
package/scripts/notify-route.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { hasProjectFullCarrier } from './runtime-scope.mjs'
|
|
2
2
|
|
|
3
3
|
export function resolveRuntimeInstallMode(settings = {}, host = '') {
|
|
4
4
|
if (!settings || typeof settings !== 'object') return 'standby'
|
|
@@ -13,8 +13,7 @@ export function resolveBootstrapFile(cwd, settings = {}, host = '') {
|
|
|
13
13
|
const installMode = typeof settings === 'string'
|
|
14
14
|
? settings
|
|
15
15
|
: resolveRuntimeInstallMode(settings, host)
|
|
16
|
-
|
|
17
|
-
return (installMode === 'global' || isActivated) ? 'bootstrap.md' : 'bootstrap-lite.md'
|
|
16
|
+
return (installMode === 'global' || hasProjectFullCarrier(cwd, host)) ? 'bootstrap.md' : 'bootstrap-lite.md'
|
|
18
17
|
}
|
|
19
18
|
|
|
20
19
|
function shouldBypassRoute(prompt) {
|
|
@@ -23,7 +22,7 @@ function shouldBypassRoute(prompt) {
|
|
|
23
22
|
|
|
24
23
|
function buildHelpExtraRules(skillName) {
|
|
25
24
|
if (skillName !== 'help') return ''
|
|
26
|
-
return ' 这是 HelloAGENTS 的帮助命令,不是宿主 CLI 的内置帮助。仅显示 HelloAGENTS 的帮助和当前设置;优先使用当前会话上下文中已注入的“当前用户设置”、配置文件原始 JSON 或此前读取结果摘要,上下文不存在或缺少要展示的配置项时才读取一次 ~/.helloagents/helloagents.json
|
|
25
|
+
return ' 这是 HelloAGENTS 的帮助命令,不是宿主 CLI 的内置帮助。仅显示 HelloAGENTS 的帮助和当前设置;优先使用当前会话上下文中已注入的“当前用户设置”、配置文件原始 JSON 或此前读取结果摘要,上下文不存在或缺少要展示的配置项时才读取一次 ~/.helloagents/helloagents.json;自动激活技能说明仅在全局模式或已初始化项目时生效。不要调用宿主 CLI 的帮助工具(如 cli_help 或 /help),不要使用子代理,不要读取项目文件;若受工作区限制无法读取配置,必须明确说明并按已知默认值或已注入设置展示。'
|
|
27
26
|
}
|
|
28
27
|
|
|
29
28
|
function routeExplicitCommand({
|
package/scripts/notify.mjs
CHANGED
|
@@ -391,6 +391,7 @@ function cmdInject() {
|
|
|
391
391
|
const cwd = payload.cwd || process.cwd();
|
|
392
392
|
const settings = getSettings();
|
|
393
393
|
const bootstrapFile = resolveBootstrapFile(cwd, settings, HOST);
|
|
394
|
+
const shouldEnsureProjectLocal = bootstrapFile === 'bootstrap.md' || source === 'resume' || source === 'compact';
|
|
394
395
|
|
|
395
396
|
startReplaySession(cwd, {
|
|
396
397
|
host: HOST,
|
|
@@ -398,6 +399,7 @@ function cmdInject() {
|
|
|
398
399
|
bootstrapFile,
|
|
399
400
|
installMode: settings.install_mode || '',
|
|
400
401
|
payload,
|
|
402
|
+
ensureProjectLocal: shouldEnsureProjectLocal,
|
|
401
403
|
});
|
|
402
404
|
if (!IS_SILENT) {
|
|
403
405
|
appendReplayEvent(cwd, {
|
|
@@ -413,7 +415,10 @@ function cmdInject() {
|
|
|
413
415
|
});
|
|
414
416
|
}
|
|
415
417
|
clearRouteContext({ cwd, payload });
|
|
416
|
-
clearTurnState(cwd, {
|
|
418
|
+
clearTurnState(cwd, {
|
|
419
|
+
payload,
|
|
420
|
+
ensureProjectLocal: shouldEnsureProjectLocal,
|
|
421
|
+
});
|
|
417
422
|
cleanupProjectSessions(cwd, {
|
|
418
423
|
minIntervalMs: IS_SILENT ? PROJECT_SESSION_CLEANUP_COOLDOWN_MS : 0,
|
|
419
424
|
});
|
|
@@ -5,7 +5,7 @@ import { resolveProjectPlanDir } from './project-storage.mjs'
|
|
|
5
5
|
|
|
6
6
|
export const PLAN_CONTRACT_FILE_NAME = 'contract.json'
|
|
7
7
|
const VALID_VERIFY_MODES = new Set(['test-first', 'review-first'])
|
|
8
|
-
const VALID_ADVISOR_SOURCES = new Set(['claude', 'codex', 'gemini'])
|
|
8
|
+
const VALID_ADVISOR_SOURCES = new Set(['claude', 'codex', 'gemini', 'deepseek'])
|
|
9
9
|
|
|
10
10
|
function normalizeStringArray(values) {
|
|
11
11
|
if (!Array.isArray(values)) return []
|
|
@@ -250,7 +250,7 @@ export function buildProjectStorageHint(cwd, options = {}) {
|
|
|
250
250
|
hints.push(`当前宿主未提供稳定会话标识,因此使用工作区默认位置 \`${summary.stateSessionToken}\``)
|
|
251
251
|
}
|
|
252
252
|
if (summary.usesSharedStore) {
|
|
253
|
-
hints.push(`项目存储:\`project_store_mode=repo-shared
|
|
253
|
+
hints.push(`项目存储:\`project_store_mode=repo-shared\`;项目本地存储/会话运行态目录仍是 \`${summary.promptActivationDir}\`,知识库/方案目录改为 \`${summary.promptStoreDir}\``)
|
|
254
254
|
}
|
|
255
255
|
return hints.join('。') + (hints.length > 0 ? '。' : '')
|
|
256
256
|
}
|
|
@@ -263,7 +263,7 @@ export function buildProjectStorageBlock(cwd, options = {}) {
|
|
|
263
263
|
|
|
264
264
|
const details = {
|
|
265
265
|
project_store_mode: summary.projectStoreMode,
|
|
266
|
-
|
|
266
|
+
project_local_dir: summary.promptActivationDir,
|
|
267
267
|
state_scope: summary.stateScope,
|
|
268
268
|
state_path: summary.promptStatePath,
|
|
269
269
|
state_workspace: summary.stateWorkspace,
|
|
@@ -281,9 +281,9 @@ export function buildProjectStorageBlock(cwd, options = {}) {
|
|
|
281
281
|
explanations.push('说明:当前宿主未提供稳定会话标识,因此使用工作区默认位置。')
|
|
282
282
|
}
|
|
283
283
|
if (summary.usesSharedStore) {
|
|
284
|
-
explanations.push('
|
|
284
|
+
explanations.push('说明:状态文件与会话产物写项目本地存储目录;`context.md`、`guidelines.md`、`DESIGN.md`、`verify.yaml`、`modules/`、`plans/`、`archive/` 写知识库/方案目录。')
|
|
285
285
|
} else {
|
|
286
|
-
explanations.push('说明:当前使用项目本地 `.helloagents/`
|
|
286
|
+
explanations.push('说明:当前使用项目本地 `.helloagents/` 作为知识、方案、状态和运行态目录。')
|
|
287
287
|
}
|
|
288
288
|
|
|
289
289
|
return [
|
package/scripts/replay-state.mjs
CHANGED
|
@@ -2,10 +2,11 @@ import { dirname } from 'node:path'
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
appendSessionEvent,
|
|
5
|
+
getRuntimeScope,
|
|
5
6
|
getSessionEventsPath,
|
|
6
7
|
resetSessionEvents,
|
|
7
8
|
} from './session-capsule.mjs'
|
|
8
|
-
import { getProjectSessionScope } from './runtime-scope.mjs'
|
|
9
|
+
import { ensureProjectLocalRuntime, getProjectSessionScope } from './runtime-scope.mjs'
|
|
9
10
|
|
|
10
11
|
function sanitizeReplayValue(value) {
|
|
11
12
|
if (typeof value === 'string') {
|
|
@@ -60,10 +61,27 @@ export function startReplaySession(cwd, {
|
|
|
60
61
|
bootstrapFile = '',
|
|
61
62
|
installMode = '',
|
|
62
63
|
payload = {},
|
|
64
|
+
ensureProjectLocal = false,
|
|
63
65
|
env,
|
|
64
66
|
ppid,
|
|
65
67
|
} = {}) {
|
|
66
|
-
const scope =
|
|
68
|
+
const scope = ensureProjectLocal
|
|
69
|
+
? {
|
|
70
|
+
...ensureProjectLocalRuntime(cwd, {
|
|
71
|
+
payload,
|
|
72
|
+
env,
|
|
73
|
+
ppid,
|
|
74
|
+
stateSeed: {
|
|
75
|
+
goal: '进入当前项目级执行流程',
|
|
76
|
+
doing: '正在初始化当前会话运行态',
|
|
77
|
+
context: '由运行时自动创建;后续按实际任务重写',
|
|
78
|
+
next: '根据当前用户请求继续执行当前流程',
|
|
79
|
+
},
|
|
80
|
+
}),
|
|
81
|
+
active: true,
|
|
82
|
+
scope: 'project-session',
|
|
83
|
+
}
|
|
84
|
+
: getProjectSessionScope(cwd, { payload, env, ppid })
|
|
67
85
|
if (!scope.active) return ''
|
|
68
86
|
|
|
69
87
|
const filePath = resetSessionEvents(cwd, { payload, env, ppid })
|
|
@@ -95,8 +113,8 @@ export function appendReplayEvent(cwd, {
|
|
|
95
113
|
env,
|
|
96
114
|
ppid,
|
|
97
115
|
} = {}) {
|
|
98
|
-
const scope =
|
|
99
|
-
if (!scope.active || !event) return ''
|
|
116
|
+
const scope = getRuntimeScope(cwd, { payload, env, ppid })
|
|
117
|
+
if (scope.scope !== 'project-session' || !scope.active || !event) return ''
|
|
100
118
|
|
|
101
119
|
return appendSessionEvent(cwd, sanitizeReplayValue({
|
|
102
120
|
event,
|
|
@@ -78,7 +78,8 @@ export function clearRouteContext(options = {}) {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
export function writeRouteContext({ cwd, skillName, sourceSkillName = skillName, payload = {}, env, ppid }) {
|
|
81
|
-
const
|
|
81
|
+
const shouldEnsureProjectLocal = skillName !== 'idea' && skillName !== 'help'
|
|
82
|
+
const scope = getRuntimeScope(cwd, { payload, env, ppid, ensureProjectLocal: shouldEnsureProjectLocal })
|
|
82
83
|
const context = {
|
|
83
84
|
cwd: normalizePath(cwd),
|
|
84
85
|
skillName,
|
|
@@ -91,7 +92,18 @@ export function writeRouteContext({ cwd, skillName, sourceSkillName = skillName,
|
|
|
91
92
|
key: scope.key,
|
|
92
93
|
updatedAt: Date.now(),
|
|
93
94
|
}
|
|
94
|
-
writeCapsuleSection(cwd, 'route', context, {
|
|
95
|
+
writeCapsuleSection(cwd, 'route', context, {
|
|
96
|
+
payload,
|
|
97
|
+
env,
|
|
98
|
+
ppid,
|
|
99
|
+
ensureProjectLocal: shouldEnsureProjectLocal,
|
|
100
|
+
stateSeed: {
|
|
101
|
+
goal: `执行 ~${sourceSkillName}`,
|
|
102
|
+
doing: `已进入 ~${sourceSkillName} 路由`,
|
|
103
|
+
context: '由运行时首次进入非只读命令时创建;后续按实际任务重写',
|
|
104
|
+
next: `读取并执行 ~${skillName} 对应流程`,
|
|
105
|
+
},
|
|
106
|
+
})
|
|
95
107
|
}
|
|
96
108
|
|
|
97
109
|
export function readRouteContext(options = {}) {
|
|
@@ -7,6 +7,7 @@ import { homedir } from 'node:os'
|
|
|
7
7
|
import { resolveSessionToken } from './session-token.mjs'
|
|
8
8
|
import { USER_RUNTIME_MAX_AGE_MS } from './runtime-ttl.mjs'
|
|
9
9
|
import { cleanupUserRuntimeRoot, getUserRuntimeRoot } from './runtime-user-cleanup.mjs'
|
|
10
|
+
import { FULL_CARRIER_PROFILE_MARKER } from './cli-utils.mjs'
|
|
10
11
|
|
|
11
12
|
export const PROJECT_DIR_NAME = '.helloagents'
|
|
12
13
|
export const PROJECT_SESSIONS_DIR_NAME = 'sessions'
|
|
@@ -143,6 +144,138 @@ export function getProjectRoot(cwd) {
|
|
|
143
144
|
return activeDir ? dirname(activeDir) : normalizePath(cwd || process.cwd())
|
|
144
145
|
}
|
|
145
146
|
|
|
147
|
+
function getCarrierPathForRoot(root, host = '') {
|
|
148
|
+
if (!root) return ''
|
|
149
|
+
if (host === 'codex' || host === 'deepseek') return join(root, 'AGENTS.md')
|
|
150
|
+
if (host === 'gemini') return join(root, '.gemini', 'GEMINI.md')
|
|
151
|
+
return join(root, 'CLAUDE.md')
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function getCarrierCandidatePaths(root, host = '', { anyHost = false } = {}) {
|
|
155
|
+
if (!root) return []
|
|
156
|
+
if (!anyHost) return [getCarrierPathForRoot(root, host)]
|
|
157
|
+
return [
|
|
158
|
+
join(root, 'AGENTS.md'),
|
|
159
|
+
join(root, 'CLAUDE.md'),
|
|
160
|
+
join(root, '.gemini', 'GEMINI.md'),
|
|
161
|
+
]
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function hasFullCarrierMarker(filePath = '') {
|
|
165
|
+
if (!filePath || !existsSync(filePath)) return false
|
|
166
|
+
try {
|
|
167
|
+
return readFileSync(filePath, 'utf-8').includes(FULL_CARRIER_PROFILE_MARKER)
|
|
168
|
+
} catch {
|
|
169
|
+
return false
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function findProjectCarrierRoot(cwd, host = '', options = {}) {
|
|
174
|
+
const normalizedCwd = normalizePath(cwd || process.cwd())
|
|
175
|
+
const gitRoot = resolveGitTopLevel(normalizedCwd)
|
|
176
|
+
const requireFullProfile = options.requireFullProfile === true
|
|
177
|
+
const anyHost = options.anyHost === true
|
|
178
|
+
let current = normalizedCwd
|
|
179
|
+
|
|
180
|
+
while (current) {
|
|
181
|
+
const candidates = getCarrierCandidatePaths(current, host, { anyHost })
|
|
182
|
+
const matched = candidates.some((filePath) =>
|
|
183
|
+
requireFullProfile ? hasFullCarrierMarker(filePath) : existsSync(filePath))
|
|
184
|
+
if (matched) return current
|
|
185
|
+
if (isUserHomeDir(current)) break
|
|
186
|
+
if (gitRoot && samePath(current, gitRoot)) break
|
|
187
|
+
|
|
188
|
+
const parent = dirname(current)
|
|
189
|
+
if (!parent || parent === current) break
|
|
190
|
+
current = parent
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return ''
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export function getProjectLocalRoot(cwd) {
|
|
197
|
+
const normalizedCwd = normalizePath(cwd || process.cwd())
|
|
198
|
+
const activeDir = findProjectActivationDir(normalizedCwd)
|
|
199
|
+
if (activeDir) return dirname(activeDir)
|
|
200
|
+
|
|
201
|
+
const fullCarrierRoot = findProjectCarrierRoot(normalizedCwd, '', {
|
|
202
|
+
anyHost: true,
|
|
203
|
+
requireFullProfile: true,
|
|
204
|
+
})
|
|
205
|
+
return fullCarrierRoot || resolveGitTopLevel(normalizedCwd) || normalizedCwd
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export function getProjectLocalDir(cwd) {
|
|
209
|
+
return join(getProjectLocalRoot(cwd), PROJECT_DIR_NAME)
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export function getProjectCarrierRoot(cwd) {
|
|
213
|
+
const normalizedCwd = normalizePath(cwd || process.cwd())
|
|
214
|
+
return findProjectCarrierRoot(normalizedCwd, '', { anyHost: true })
|
|
215
|
+
|| resolveGitTopLevel(normalizedCwd)
|
|
216
|
+
|| getProjectRoot(normalizedCwd)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export function getProjectCarrierPath(cwd, host = '') {
|
|
220
|
+
const normalizedCwd = normalizePath(cwd || process.cwd())
|
|
221
|
+
const carrierRoot = findProjectCarrierRoot(normalizedCwd, host, {
|
|
222
|
+
requireFullProfile: true,
|
|
223
|
+
}) || findProjectCarrierRoot(normalizedCwd, host)
|
|
224
|
+
|| getProjectCarrierRoot(normalizedCwd)
|
|
225
|
+
return getCarrierPathForRoot(carrierRoot, host)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export function hasProjectFullCarrier(cwd, host = '') {
|
|
229
|
+
const carrierPath = getProjectCarrierPath(cwd, host)
|
|
230
|
+
return hasFullCarrierMarker(carrierPath)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function buildInitialStateSnapshot({
|
|
234
|
+
goal = '继续当前非只读任务',
|
|
235
|
+
doing = '已进入当前任务执行流程',
|
|
236
|
+
context = '由运行时自动创建;后续按实际任务重写',
|
|
237
|
+
next = '根据当前用户请求继续执行,并按实际任务重写本状态文件',
|
|
238
|
+
} = {}) {
|
|
239
|
+
return [
|
|
240
|
+
'# 恢复快照',
|
|
241
|
+
'',
|
|
242
|
+
'## 主线目标',
|
|
243
|
+
goal,
|
|
244
|
+
'',
|
|
245
|
+
'## 正在做什么',
|
|
246
|
+
doing,
|
|
247
|
+
'',
|
|
248
|
+
'## 关键上下文',
|
|
249
|
+
context,
|
|
250
|
+
'',
|
|
251
|
+
'## 下一步',
|
|
252
|
+
next,
|
|
253
|
+
'',
|
|
254
|
+
'## 阻塞项',
|
|
255
|
+
'(无)',
|
|
256
|
+
'',
|
|
257
|
+
'## 方案',
|
|
258
|
+
'',
|
|
259
|
+
'## 已标记技能',
|
|
260
|
+
'',
|
|
261
|
+
].join('\n')
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export function ensureProjectLocalRuntime(cwd, options = {}) {
|
|
265
|
+
const normalizedCwd = normalizePath(cwd || process.cwd())
|
|
266
|
+
const localDir = getProjectLocalDir(normalizedCwd)
|
|
267
|
+
mkdirSync(localDir, { recursive: true })
|
|
268
|
+
|
|
269
|
+
const scope = getProjectSessionScope(normalizedCwd, options)
|
|
270
|
+
mkdirSync(dirname(scope.statePath), { recursive: true })
|
|
271
|
+
|
|
272
|
+
if (!existsSync(scope.statePath)) {
|
|
273
|
+
writeFileSync(scope.statePath, `${buildInitialStateSnapshot(options.stateSeed || {})}\n`, 'utf-8')
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return scope
|
|
277
|
+
}
|
|
278
|
+
|
|
146
279
|
function isUserHomeHelloagentsDir(dirPath) {
|
|
147
280
|
const homeCandidates = [
|
|
148
281
|
getHomeDir(),
|
|
@@ -368,7 +501,16 @@ function buildTransientRuntimeDir(cwd, options = {}) {
|
|
|
368
501
|
}
|
|
369
502
|
|
|
370
503
|
export function getRuntimeScope(cwd = process.cwd(), options = {}) {
|
|
371
|
-
const
|
|
504
|
+
const normalizedOptions = normalizeRuntimeOptions(options)
|
|
505
|
+
if (normalizedOptions.ensureProjectLocal === true) {
|
|
506
|
+
return {
|
|
507
|
+
...ensureProjectLocalRuntime(cwd, normalizedOptions),
|
|
508
|
+
active: true,
|
|
509
|
+
scope: 'project-session',
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
const projectScope = getProjectSessionScope(cwd, normalizedOptions)
|
|
372
514
|
if (projectScope.active) {
|
|
373
515
|
return {
|
|
374
516
|
...projectScope,
|
|
@@ -377,7 +519,7 @@ export function getRuntimeScope(cwd = process.cwd(), options = {}) {
|
|
|
377
519
|
}
|
|
378
520
|
|
|
379
521
|
return {
|
|
380
|
-
...buildTransientRuntimeDir(cwd,
|
|
522
|
+
...buildTransientRuntimeDir(cwd, normalizedOptions),
|
|
381
523
|
active: false,
|
|
382
524
|
scope: 'user-runtime',
|
|
383
525
|
}
|
|
@@ -2,6 +2,7 @@ import { existsSync, mkdirSync, rmSync, writeFileSync } from 'node:fs'
|
|
|
2
2
|
import { basename, dirname, join } from 'node:path'
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
|
+
ensureProjectLocalRuntime,
|
|
5
6
|
getProjectSessionScope,
|
|
6
7
|
getRuntimeScope,
|
|
7
8
|
readJsonFile,
|
|
@@ -44,6 +45,19 @@ function getEventSessionAlias(eventPayload = {}) {
|
|
|
44
45
|
|
|
45
46
|
function getScope(cwd, options = {}) {
|
|
46
47
|
const normalizedOptions = normalizeOptions(options)
|
|
48
|
+
const stateSeed = normalizedOptions.stateSeed && typeof normalizedOptions.stateSeed === 'object'
|
|
49
|
+
? normalizedOptions.stateSeed
|
|
50
|
+
: {}
|
|
51
|
+
if (normalizedOptions.ensureProjectLocal === true) {
|
|
52
|
+
return {
|
|
53
|
+
...ensureProjectLocalRuntime(cwd, {
|
|
54
|
+
...normalizedOptions,
|
|
55
|
+
stateSeed,
|
|
56
|
+
}),
|
|
57
|
+
active: true,
|
|
58
|
+
scope: 'project-session',
|
|
59
|
+
}
|
|
60
|
+
}
|
|
47
61
|
if (normalizedOptions.project === true) {
|
|
48
62
|
return {
|
|
49
63
|
...getProjectSessionScope(cwd, normalizedOptions),
|
package/scripts/turn-state.mjs
CHANGED
|
@@ -119,6 +119,13 @@ export function writeTurnState(cwd = process.cwd(), input = {}) {
|
|
|
119
119
|
payload: input.payload && typeof input.payload === 'object' ? input.payload : input,
|
|
120
120
|
env: input.env || process.env,
|
|
121
121
|
ppid: input.ppid ?? process.ppid,
|
|
122
|
+
ensureProjectLocal: true,
|
|
123
|
+
stateSeed: {
|
|
124
|
+
goal: '记录当前非只读任务状态',
|
|
125
|
+
doing: '正在写入 turn-state',
|
|
126
|
+
context: '由运行时在需要识别完成、等待或阻塞时自动创建',
|
|
127
|
+
next: '根据当前 turn-state 继续或等待后续动作',
|
|
128
|
+
},
|
|
122
129
|
}
|
|
123
130
|
const scope = getRuntimeScope(cwd, runtimeOptions)
|
|
124
131
|
const normalized = normalizeTurnState(input)
|