flower-trellis 0.4.5-beta.2 → 0.4.5-beta.3
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/package.json
CHANGED
|
@@ -17,6 +17,7 @@ from pathlib import Path
|
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
ACTIONABLE_STATUSES = {"update_available", "project_out_of_sync"}
|
|
20
|
+
SELF_CHECK_TIMEOUT_SECONDS = 30
|
|
20
21
|
|
|
21
22
|
|
|
22
23
|
def _debug(message: str) -> None:
|
|
@@ -57,7 +58,7 @@ def _run_self_check(project_dir: Path) -> dict | None:
|
|
|
57
58
|
text=True,
|
|
58
59
|
encoding="utf-8",
|
|
59
60
|
errors="replace",
|
|
60
|
-
timeout=
|
|
61
|
+
timeout=SELF_CHECK_TIMEOUT_SECONDS,
|
|
61
62
|
cwd=str(project_dir),
|
|
62
63
|
)
|
|
63
64
|
except (subprocess.TimeoutExpired, FileNotFoundError, PermissionError) as exc:
|
|
@@ -84,6 +85,8 @@ def _format_context(data: dict) -> str:
|
|
|
84
85
|
out_of_sync_reasons = project.get("outOfSyncReasons") or []
|
|
85
86
|
lines = [
|
|
86
87
|
"<flower-update>",
|
|
88
|
+
"priority: blocking_confirmation_required",
|
|
89
|
+
"instruction_scope: first_assistant_reply",
|
|
87
90
|
f"status: {data.get('status')}",
|
|
88
91
|
f"policy: {data.get('policy')}",
|
|
89
92
|
f"current_flower: {current.get('flowerVersion')}",
|
|
@@ -114,11 +117,22 @@ def _format_context(data: dict) -> str:
|
|
|
114
117
|
return "\n".join(lines)
|
|
115
118
|
|
|
116
119
|
|
|
117
|
-
def
|
|
120
|
+
def _system_message(data: dict) -> str:
|
|
121
|
+
"""生成 Codex / Claude Code 更容易注意到的短系统提示。"""
|
|
122
|
+
ai = data.get("ai") or {}
|
|
123
|
+
command = (data.get("commands") or {}).get("recommended") or ai.get("command")
|
|
124
|
+
if ai.get("mode") == "ask" and command:
|
|
125
|
+
return "flower-trellis 发现可执行更新;必须先询问用户是否执行 recommended_command,确认前禁止运行。"
|
|
126
|
+
if command:
|
|
127
|
+
return "flower-trellis 发现可执行更新;已注入 recommended_command。"
|
|
128
|
+
return "flower-trellis update context injected"
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _emit_context(context: str, system_message: str) -> None:
|
|
118
132
|
"""输出 Codex / Claude Code 都接受的 SessionStart hook JSON。"""
|
|
119
133
|
result = {
|
|
120
134
|
"suppressOutput": True,
|
|
121
|
-
"systemMessage":
|
|
135
|
+
"systemMessage": system_message,
|
|
122
136
|
"hookSpecificOutput": {
|
|
123
137
|
"hookEventName": "SessionStart",
|
|
124
138
|
"additionalContext": context,
|
|
@@ -138,7 +152,7 @@ def main() -> None:
|
|
|
138
152
|
data = _run_self_check(_project_dir(hook_input))
|
|
139
153
|
if not data or data.get("status") not in ACTIONABLE_STATUSES:
|
|
140
154
|
return
|
|
141
|
-
_emit_context(_format_context(data))
|
|
155
|
+
_emit_context(_format_context(data), _system_message(data))
|
|
142
156
|
|
|
143
157
|
|
|
144
158
|
if __name__ == "__main__":
|
package/src/lib/claude-tweaks.js
CHANGED
|
@@ -4,6 +4,7 @@ import { FLOWER_UPDATE_HOOK_REL } from "./flower-assets.js";
|
|
|
4
4
|
|
|
5
5
|
const WORKFLOW_HOOK_SCRIPT = ".claude/hooks/inject-workflow-state.py";
|
|
6
6
|
const DEFAULT_COMMAND = `python3 ${FLOWER_UPDATE_HOOK_REL}`;
|
|
7
|
+
const FLOWER_UPDATE_TIMEOUT = 30;
|
|
7
8
|
|
|
8
9
|
/** 容错读取 Claude settings JSON。 */
|
|
9
10
|
function readSettings(settingsPath) {
|
|
@@ -45,6 +46,20 @@ function hasFlowerHook(hooks) {
|
|
|
45
46
|
);
|
|
46
47
|
}
|
|
47
48
|
|
|
49
|
+
/** 将已有 flower update hook 的超时迁移到当前预算。 */
|
|
50
|
+
function normalizeFlowerHookTimeout(hooks) {
|
|
51
|
+
let changed = false;
|
|
52
|
+
for (const hook of hooks) {
|
|
53
|
+
if (hook?.type !== "command" || typeof hook.command !== "string") continue;
|
|
54
|
+
if (!hook.command.includes(FLOWER_UPDATE_HOOK_REL)) continue;
|
|
55
|
+
if (hook.timeout !== FLOWER_UPDATE_TIMEOUT) {
|
|
56
|
+
hook.timeout = FLOWER_UPDATE_TIMEOUT;
|
|
57
|
+
changed = true;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return changed;
|
|
61
|
+
}
|
|
62
|
+
|
|
48
63
|
/** 合并 Claude startup hook,并确保 clear / compact 不运行 update hook。 */
|
|
49
64
|
function mergeClaudeHooks(settingsPath) {
|
|
50
65
|
const config = readSettings(settingsPath);
|
|
@@ -71,8 +86,9 @@ function mergeClaudeHooks(settingsPath) {
|
|
|
71
86
|
if (group.hooks.length !== before) changed = true;
|
|
72
87
|
}
|
|
73
88
|
|
|
89
|
+
changed = normalizeFlowerHookTimeout(startup.hooks) || changed;
|
|
74
90
|
if (!hasFlowerHook(startup.hooks)) {
|
|
75
|
-
startup.hooks.push({ type: "command", command, timeout:
|
|
91
|
+
startup.hooks.push({ type: "command", command, timeout: FLOWER_UPDATE_TIMEOUT });
|
|
76
92
|
changed = true;
|
|
77
93
|
}
|
|
78
94
|
|
package/src/lib/self-check.js
CHANGED
|
@@ -28,6 +28,8 @@ function readProjectTrellisVersion(target) {
|
|
|
28
28
|
|
|
29
29
|
/** 判断远程探测缓存是否仍在 interval 内。 */
|
|
30
30
|
function isRemoteCacheFresh(updateCheck, now = new Date()) {
|
|
31
|
+
if (updateCheck.lastStatus === "offline" || updateCheck.lastErrorCode) return false;
|
|
32
|
+
if (!updateCheck.lastRemote) return false;
|
|
31
33
|
if (!updateCheck.lastCheckedAt) return false;
|
|
32
34
|
const checkedAt = new Date(updateCheck.lastCheckedAt).getTime();
|
|
33
35
|
if (!Number.isFinite(checkedAt)) return false;
|
|
@@ -332,7 +334,6 @@ export async function buildSelfCheck(target, options = {}) {
|
|
|
332
334
|
if (!tags) {
|
|
333
335
|
if (writeCache && manifest) {
|
|
334
336
|
writeUpdateCheck(absoluteTarget, {
|
|
335
|
-
lastCheckedAt: now.toISOString(),
|
|
336
337
|
lastStatus: "offline",
|
|
337
338
|
lastErrorCode: "fetch_failed",
|
|
338
339
|
});
|
package/src/lib/update-check.js
CHANGED
|
@@ -17,8 +17,8 @@ import { flowerVersion } from "./versions.js";
|
|
|
17
17
|
const REGISTRY = "https://registry.npmjs.org";
|
|
18
18
|
/** 待检测的包名(即本包)。 */
|
|
19
19
|
const PKG = "flower-trellis";
|
|
20
|
-
/** 网络探测超时(毫秒)——
|
|
21
|
-
const TIMEOUT_MS =
|
|
20
|
+
/** 网络探测超时(毫秒)—— 启动检查有 hook 总预算兜底,5s 可降低 registry 偶发慢响应误判。 */
|
|
21
|
+
const TIMEOUT_MS = 5000;
|
|
22
22
|
|
|
23
23
|
/**
|
|
24
24
|
* 取 npm 上 flower-trellis 的 dist-tags;任何失败(离线/超时/非 200/解析异常)一律
|