therookie 0.4.25 → 0.4.26
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 +1 -1
- package/src/lib/codex-config.js +37 -3
- package/src/lib/deploy-artifacts.js +10 -2
- package/version.json +1 -1
package/package.json
CHANGED
package/src/lib/codex-config.js
CHANGED
|
@@ -46,13 +46,36 @@ function block(paths, platform = process.platform) {
|
|
|
46
46
|
return lines.join('\n')
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
// rookie 가 managed 블록 안에 쓰는 TOML 테이블. 이 밖의 테이블이 블록 안에서
|
|
50
|
+
// 발견되면 사용자 설정이 흘러들어온 것이다 — 덮지 않고 마커 밖으로 옮긴다.
|
|
51
|
+
// (2026-09-02 실사고: 두목의 [shell_environment_policy.set] 4줄이 마커 안에 있어
|
|
52
|
+
// 블록 교체와 함께 지워졌다. "수동 편집 금지" 주석만으로는 못 막는다.)
|
|
53
|
+
const ROOKIE_TABLE = /^\[\[?hooks\.(SessionStart|UserPromptSubmit)(\.hooks)?\]\]?$/
|
|
54
|
+
|
|
55
|
+
function splitForeignLines(inner) {
|
|
56
|
+
const own = []
|
|
57
|
+
const foreign = []
|
|
58
|
+
let inForeign = false
|
|
59
|
+
for (const line of inner.split('\n')) {
|
|
60
|
+
const t = line.trim()
|
|
61
|
+
if (/^\[.*\]$/.test(t)) inForeign = !ROOKIE_TABLE.test(t)
|
|
62
|
+
;(inForeign ? foreign : own).push(line)
|
|
63
|
+
}
|
|
64
|
+
return foreign.join('\n').trim()
|
|
65
|
+
}
|
|
66
|
+
|
|
49
67
|
// 기존 managed 블록이 있으면 교체, 없으면 끝에 append. 마커 밖은 보존.
|
|
50
|
-
|
|
68
|
+
// 마커 **안**에 있던 남의 설정도 잃지 않는다 — 마커 밖으로 옮기고 preserved 로 알린다.
|
|
69
|
+
export function upsertCodexHookBlockDetailed(
|
|
70
|
+
existingToml,
|
|
71
|
+
hookPaths,
|
|
72
|
+
platform = process.platform
|
|
73
|
+
) {
|
|
51
74
|
const fresh = block(hookPaths, platform)
|
|
52
75
|
const begin = existingToml.indexOf(ROOKIE_BEGIN)
|
|
53
76
|
if (begin === -1) {
|
|
54
77
|
const base = existingToml.replace(/\s*$/, '')
|
|
55
|
-
return (base ? base + '\n\n' : '') + fresh + '\n'
|
|
78
|
+
return { toml: (base ? base + '\n\n' : '') + fresh + '\n', preserved: '' }
|
|
56
79
|
}
|
|
57
80
|
const endIdx = existingToml.indexOf(ROOKIE_END, begin)
|
|
58
81
|
if (endIdx === -1) {
|
|
@@ -62,7 +85,18 @@ export function upsertCodexHookBlock(existingToml, hookPaths, platform = process
|
|
|
62
85
|
err.code = 'MALFORMED_CODEX_MARKER'
|
|
63
86
|
throw err
|
|
64
87
|
}
|
|
88
|
+
const inner = existingToml.slice(begin + ROOKIE_BEGIN.length, endIdx)
|
|
89
|
+
const preserved = splitForeignLines(inner)
|
|
65
90
|
const before = existingToml.slice(0, begin)
|
|
66
91
|
const after = existingToml.slice(endIdx + ROOKIE_END.length)
|
|
67
|
-
|
|
92
|
+
let toml = before + fresh + after
|
|
93
|
+
if (preserved) {
|
|
94
|
+
// 마커 **뒤**에 둔다 — 다음 재실행 때 다시 삼켜지지 않는다.
|
|
95
|
+
toml = toml.replace(/\s*$/, '') + '\n\n' + preserved + '\n'
|
|
96
|
+
}
|
|
97
|
+
return { toml, preserved }
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function upsertCodexHookBlock(existingToml, hookPaths, platform = process.platform) {
|
|
101
|
+
return upsertCodexHookBlockDetailed(existingToml, hookPaths, platform).toml
|
|
68
102
|
}
|
|
@@ -4,7 +4,7 @@ import { join, dirname } from 'node:path'
|
|
|
4
4
|
import { fileURLToPath } from 'node:url'
|
|
5
5
|
import { apiGet } from '../api.js'
|
|
6
6
|
import { saveClientManifest } from './manifest.js'
|
|
7
|
-
import {
|
|
7
|
+
import { upsertCodexHookBlockDetailed } from './codex-config.js'
|
|
8
8
|
import { claudeHookCommand, escapeJsonStringValue } from './hook-command.js'
|
|
9
9
|
import { mergeHooks } from './merge-hooks.js'
|
|
10
10
|
import { syncSkillAssets } from './skill-installer.js'
|
|
@@ -170,11 +170,19 @@ export function applyCodexSetup({ home = homedir() } = {}) {
|
|
|
170
170
|
const existing = existsSync(configPath) ? readFileSync(configPath, 'utf8') : ''
|
|
171
171
|
let next
|
|
172
172
|
try {
|
|
173
|
-
|
|
173
|
+
const upserted = upsertCodexHookBlockDetailed(existing, {
|
|
174
174
|
sessionStart: hookScript,
|
|
175
175
|
// 인격 대기열 소비자 — 짝이 없으면 파일만 쌓인다(spec 2026-09-02).
|
|
176
176
|
promptSubmit: join(homedir(), '.rookie', 'bin', 'user-prompt-skill-gate.sh'),
|
|
177
177
|
})
|
|
178
|
+
next = upserted.toml
|
|
179
|
+
// 마커 안에 흘러든 사용자 설정을 밖으로 옮겼으면 조용히 넘기지 않는다.
|
|
180
|
+
if (upserted.preserved) {
|
|
181
|
+
console.log(
|
|
182
|
+
'⚠ managed 블록 안에 있던 설정을 블록 밖으로 옮겼습니다(지우지 않았습니다) — 위치를 확인하세요:'
|
|
183
|
+
)
|
|
184
|
+
for (const line of upserted.preserved.split('\n')) console.log(` ${line}`)
|
|
185
|
+
}
|
|
178
186
|
} catch (e) {
|
|
179
187
|
// marker 손상(begin 만 있고 end 없음) → 파일을 건드리지 않고 경고 신호만 반환(사용자 config 보호).
|
|
180
188
|
if (e?.code === 'MALFORMED_CODEX_MARKER') return { configPath, hookScript, error: 'malformed_marker' }
|
package/version.json
CHANGED