therookie 0.4.39 → 0.4.40

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "therookie",
3
- "version": "0.4.39",
3
+ "version": "0.4.40",
4
4
  "description": "Persistent memory for Claude Code and Codex CLI — teach your AI once and it remembers across sessions, tools, and machines. The AI new hire that remembers what you teach it.",
5
5
  "license": "MIT",
6
6
  "keywords": [
package/src/cli.js CHANGED
@@ -18,8 +18,8 @@ import { runOrphanExtract } from './commands/orphan-extract.js'
18
18
  const HELP = `rookie — the Rookie Skill/Hook 설치 관리자
19
19
 
20
20
  사용:
21
- rookie init [--local] [--force] [--yes] [--deep-scan] [--claude-md | --no-claude-md]
22
- rookie login [--local] [--claude-md | --no-claude-md]
21
+ rookie init [--local] [--force] [--yes] [--deep-scan] [--claude-md | --no-claude-md] [--codex-md | --no-codex-md]
22
+ rookie login [--local] [--claude-md | --no-claude-md] [--codex-md | --no-codex-md]
23
23
  rookie update [--force] [--claude-md | --no-claude-md] [--codex-md | --no-codex-md]
24
24
  rookie link [--local]
25
25
  rookie save [--file <body.json>] [--json] # 또는 stdin. --json = 서버 raw 응답 출력
@@ -5,6 +5,7 @@ import { confirm } from '../prompt.js'
5
5
  import { loadConfig } from '../config.js'
6
6
  import { applyCodexSetup } from '../lib/deploy-artifacts.js'
7
7
  import { runCodexMdStep } from '../lib/claude-md-block.js'
8
+ import { codexHomeDir } from '../lib/codex-home.js'
8
9
 
9
10
  // Codex config.toml 에 더루키 SessionStart hook 을 동의 기반으로 등록한다(managed 블록만).
10
11
  // 명시적 Codex-only 재설정 진입점 — 내부 write 는 applyCodexSetup(3층 adapter) 공유(spec §4 item 6).
@@ -19,7 +20,7 @@ export async function runCodexSetup(flags) {
19
20
  console.error(`✗ hook 스크립트가 없습니다(${hookScript}). \`rookie login\` 또는 \`rookie update\` 를 먼저 실행하세요.`)
20
21
  process.exit(1)
21
22
  }
22
- const configPath = join(homedir(), '.codex', 'config.toml')
23
+ const configPath = join(codexHomeDir(), 'config.toml')
23
24
 
24
25
  console.log('\nCodex 설정 파일에 더루키 SessionStart hook 을 등록합니다:')
25
26
  console.log(` ${configPath}`)
@@ -12,7 +12,7 @@ import { apiGet, apiPostNoAuth } from '../api.js'
12
12
  import { applyToolSetup, pendingToolSetup } from '../lib/apply-tool-setup.js'
13
13
  import { renderDetected, renderConnectOutcome, toolName } from '../lib/connect-ui.js'
14
14
  import { resolveEndpoint } from '../lib/resolve-endpoint.js'
15
- import { runClaudeMdStep } from '../lib/claude-md-block.js'
15
+ import { runClaudeMdStep, runCodexMdStep } from '../lib/claude-md-block.js'
16
16
 
17
17
  async function pickChoice(prompt, options, autoValue) {
18
18
  console.log(prompt)
@@ -179,4 +179,9 @@ export async function runInit(flags) {
179
179
  const { lines } = await runClaudeMdStep({ mode: 'connect', flags, interactive, confirmFn: confirm })
180
180
  for (const line of lines) console.log(line)
181
181
  }
182
+ // 2026-09-29 두목 결정 — Codex 전역 지시 파일도 첫 연결에서 기본 적용(끄기 ROOKIE_NO_CODEX_MD=1).
183
+ if (scope === 'global' && report.applied.some((a) => a.id === 'codex')) {
184
+ const { lines } = await runCodexMdStep({ mode: 'connect', flags, interactive, confirmFn: confirm })
185
+ for (const line of lines) console.log(line)
186
+ }
182
187
  }
@@ -10,7 +10,7 @@ import { renderDetected, renderConnectOutcome, toolName } from '../lib/connect-u
10
10
  import { confirm } from '../prompt.js'
11
11
  import { resolveEndpoint } from '../lib/resolve-endpoint.js'
12
12
  import { accountLine, accountWarning } from '../lib/account-ui.js'
13
- import { runClaudeMdStep } from '../lib/claude-md-block.js'
13
+ import { runClaudeMdStep, runCodexMdStep } from '../lib/claude-md-block.js'
14
14
 
15
15
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms))
16
16
 
@@ -170,4 +170,14 @@ export async function runLogin(flags) {
170
170
  })
171
171
  for (const line of lines) console.log(line)
172
172
  }
173
+ // 2026-09-29 두목 결정 — Codex 전역 지시 파일도 첫 연결에서 기본 적용(끄기 ROOKIE_NO_CODEX_MD=1).
174
+ if (scope === 'global' && report.applied.some((a) => a.id === 'codex')) {
175
+ const { lines } = await runCodexMdStep({
176
+ mode: 'connect',
177
+ flags,
178
+ interactive: !!process.stdin.isTTY && !flags.yes,
179
+ confirmFn: confirm,
180
+ })
181
+ for (const line of lines) console.log(line)
182
+ }
173
183
  }
package/src/detect.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { readFileSync, existsSync, readdirSync, accessSync, constants } from 'node:fs'
2
2
  import { homedir } from 'node:os'
3
3
  import { join } from 'node:path'
4
+ import { codexHomeDir } from './lib/codex-home.js'
4
5
 
5
6
  // 통일 연결 흐름(spec 2026-06-29-unified-connect-flow §3 D1): 이 컴퓨터에 깔린 AI 도구를 감지한다.
6
7
  // registry 형 — Cursor/Gemini 등은 entry 추가만으로 확장. boolean 반환 금지.
@@ -44,7 +45,7 @@ function defaultHasCli(name, env = process.env, platform = process.platform) {
44
45
  export function detectInstalledTools({ home = homedir(), env = process.env, hasCli = defaultHasCli } = {}) {
45
46
  return TOOL_REGISTRY.map((t) => {
46
47
  const cli = t.cliNames.some((n) => hasCli(n, env))
47
- const dir = existsSync(join(home, t.homeDir))
48
+ const dir = existsSync(t.id === 'codex' ? codexHomeDir({ home, env }) : join(home, t.homeDir))
48
49
  const present = cli || dir
49
50
  const signal = cli ? 'strong' : dir ? 'weak' : 'none'
50
51
  const reason = cli ? `${t.id} CLI 발견` : dir ? `~/${t.homeDir} 존재` : '없음'
@@ -3,13 +3,14 @@ import { homedir } from 'node:os'
3
3
  import { join } from 'node:path'
4
4
  import { installSharedHookRuntime, applyClaudeSetup, applyCodexSetup } from './deploy-artifacts.js'
5
5
  import { ROOKIE_BEGIN } from './codex-config.js'
6
+ import { codexHomeDir } from './codex-home.js'
6
7
 
7
8
  // 도구가 이미 rookie 로 설정됐는지. init 의 도구-추가 모드(early-return 우회) 판정용.
8
- export function isToolConfigured(id, { scope, home = homedir(), cwd = process.cwd() } = {}) {
9
+ export function isToolConfigured(id, { scope, home = homedir(), cwd = process.cwd(), env = process.env } = {}) {
9
10
  const base = scope === 'global' ? home : cwd
10
11
  if (id === 'claude') return existsSync(join(base, '.claude', 'skills', 'rookie', 'SKILL.md'))
11
12
  if (id === 'codex') {
12
- const cfg = join(home, '.codex', 'config.toml')
13
+ const cfg = join(codexHomeDir({ home, env }), 'config.toml')
13
14
  return existsSync(cfg) && readFileSync(cfg, 'utf8').includes(ROOKIE_BEGIN)
14
15
  }
15
16
  return false
@@ -18,6 +18,7 @@ import {
18
18
  import { homedir } from 'node:os'
19
19
  import { join, dirname, basename } from 'node:path'
20
20
  import { fileURLToPath } from 'node:url'
21
+ import { codexHomeDir } from './codex-home.js'
21
22
 
22
23
  const __dirname = dirname(fileURLToPath(import.meta.url))
23
24
  export const DEFAULT_TEMPLATE_PATH = join(__dirname, '..', '..', 'templates', 'claude-md', 'rookie-block.md')
@@ -76,7 +77,7 @@ export function claudeTarget({ home = homedir() } = {}) {
76
77
  // (2026-09-29 codex 0.153.4 바이너리 strings + codex exec 실측).
77
78
  export function codexTarget({ home = homedir(), env = process.env } = {}) {
78
79
  return {
79
- dir: env.CODEX_HOME ? env.CODEX_HOME : join(home, '.codex'),
80
+ dir: codexHomeDir({ home, env }),
80
81
  candidates: ['AGENTS.override.md', 'AGENTS.md'],
81
82
  createName: 'AGENTS.md',
82
83
  needles: [SAME_INTENT_NEEDLE, 'rookie_recall'],
@@ -0,0 +1,8 @@
1
+ import { homedir } from 'node:os'
2
+ import { join } from 'node:path'
3
+
4
+ // Codex 설정 폴더. Codex 는 $CODEX_HOME 이 있으면 그 폴더를 쓴다(2026-09-29 바이너리 strings 실측).
5
+ // config.toml·AGENTS.md·감지가 모두 이 한 곳을 보게 한다 — 갈리면 hook 과 지시 블록이 서로 다른 폴더에 들어간다.
6
+ export function codexHomeDir({ home = homedir(), env = process.env } = {}) {
7
+ return env.CODEX_HOME ? env.CODEX_HOME : join(home, '.codex')
8
+ }
@@ -1,5 +1,6 @@
1
1
  import { readFileSync, writeFileSync, existsSync, mkdirSync, chmodSync, cpSync } from 'node:fs'
2
2
  import { homedir } from 'node:os'
3
+ import { codexHomeDir } from './codex-home.js'
3
4
  import { join, dirname } from 'node:path'
4
5
  import { fileURLToPath } from 'node:url'
5
6
  import { apiGet } from '../api.js'
@@ -163,8 +164,8 @@ export async function applyClaudeSetup({ scope, cfg, home, cwd } = {}) {
163
164
 
164
165
  // ── 3층: Codex adapter — ~/.codex/config.toml 의 managed 블록(upsertCodexHookBlock).
165
166
  // scope=global 전제(D3): Codex config 는 항상 전역이고 전역 hook 을 문다. 호출 게이트는 오케스트레이터 책임.
166
- export function applyCodexSetup({ home = homedir() } = {}) {
167
- const codexDir = join(home, '.codex')
167
+ export function applyCodexSetup({ home = homedir(), env = process.env } = {}) {
168
+ const codexDir = codexHomeDir({ home, env })
168
169
  const configPath = join(codexDir, 'config.toml')
169
170
  const hookScript = join(home, '.rookie', 'bin', 'session-start.sh')
170
171
  const existing = existsSync(configPath) ? readFileSync(configPath, 'utf8') : ''
package/version.json CHANGED
@@ -1,4 +1,4 @@
1
1
  {
2
- "cli_version": "0.4.39",
2
+ "cli_version": "0.4.40",
3
3
  "skill_version": "1.40.1"
4
4
  }