@wooojin/forgen 0.4.6 → 0.4.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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://claude.ai/schemas/claude-plugin.json",
3
3
  "name": "forgen",
4
- "version": "0.4.6",
4
+ "version": "0.4.7",
5
5
  "description": "Claude Code harness — the more you use Claude, the better it gets",
6
6
  "author": {
7
7
  "name": "jang-ujin",
package/CHANGELOG.md CHANGED
@@ -7,6 +7,44 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.4.7] — 2026-05-15 — fgx --codex 권한 플래그 수정
11
+
12
+ ### Fixed
13
+ - `fgx --codex` 실행 시 `error: unexpected argument '--dangerously-skip-permissions' found`로
14
+ 기동이 즉시 실패하던 버그를 수정. Codex CLI 는 동일 목적의 플래그가
15
+ `--dangerously-bypass-approvals-and-sandbox` 라 Claude 전용 플래그를 그대로
16
+ 주입하면 거부됨.
17
+ - `HostRuntime.dangerousSkipFlag` 추상화를 도입해 `src/fgx.ts` 가 런타임별로
18
+ 올바른 플래그를 선택하도록 변경 (claude 동작은 회귀 없음).
19
+ - 경고 배너와 `[forgen] Mode:` 라벨도 선택된 플래그/런타임에 맞춰 동적으로 출력.
20
+ - **Windows 빌드 깨짐 (v0.4.4부터 누적)** 수정: `scripts/copy-assets.js`,
21
+ `src/cli.ts`, `src/host/install-orchestrator.ts` 가 `new URL(...).pathname` 으로
22
+ 파일 경로를 만들었는데 Windows 에서 `/D:/...` 형태가 그대로 노출되어
23
+ `mkdirSync` 가 `D:\D:\...` 로 해석 → ENOENT. `fileURLToPath()` 로 일괄 교체.
24
+ - **Linux CI test 잡 회귀** 수정: `npm run build` 만으로는 `hooks/hooks.json` 이
25
+ 생성되지 않아 (prepack 시점에만 생성) `claude-code-compat.test.ts` 등이
26
+ 실패. `.github/workflows/ci.yml` 의 test 잡에 `node scripts/prepack-hooks.cjs`
27
+ 단계를 추가하여 CI 환경에서도 hooks.json 이 준비된 상태로 vitest 가 돌도록.
28
+
29
+ ### CI / Platform Coverage
30
+ - `ci.yml` test 잡을 OS × Node 매트릭스로 확장:
31
+ ubuntu-latest × {20, 22}, macos-latest × {20, 22}, ubuntu-24.04-arm × 22.
32
+ 이전엔 vitest 풀 매트릭스가 ubuntu-latest 만 돌았음.
33
+ - **Windows**: hooks-portability 잡 (Node 20.x, 22.x × windows-latest) 에서
34
+ 빌드 + postinstall + 21/21 hook 로드를 검증. 풀 vitest 는 다수 통합
35
+ 테스트가 `/tmp` / POSIX path / bash spawn 가정에 묶여 있어 cross-platform
36
+ 재작성이 별도 트랙. 현재 Windows 사용자의 실사용 경로 (`npm i -g` +
37
+ Claude/Codex hook 발동) 는 보장됨.
38
+ - `actions/checkout` 에 `fetch-depth: 0` 추가 — `tests/git-stats.test.ts`
39
+ 가 실 git log 30일 윈도우를 분석.
40
+ - CI 환경 의존 테스트 (`rate-limit-spawn-integration`, `claude-integration`
41
+ 의 6-live / 3-live) 에 `it.skipIf(!!process.env.CI)` 가드.
42
+
43
+ ### Verified
44
+ - vitest 2442/2442 PASS, Docker e2e 77/77 PASS.
45
+ - `node dist/fgx.js --codex` / `--claude` 직접 기동 확인 — Codex CLI 가 플래그 수용.
46
+ - `npm run build` + `prepack-hooks` 후 `hooks/hooks.json` 21/21 active 재생성 확인.
47
+
10
48
  ## [0.4.6] — 2026-05-14 — Unattended Execution Resilience
11
49
 
12
50
  긴 무인 실행 (`forge-loop --goal-only` 새벽 실행, eval N=33+ sequential measurement)
package/dist/cli.js CHANGED
@@ -195,7 +195,7 @@ const commands = [
195
195
  console.log('Usage:\n forgen parity codex [--dry-run]\n\nNotes:\n - source 체크아웃에서만 작동합니다 (tests/ 디렉토리 필요).\n - npm install 로 설치된 패키지에서는 run-parity.sh 가 없습니다.');
196
196
  return;
197
197
  }
198
- const here = path.dirname(new URL(import.meta.url).pathname);
198
+ const here = path.dirname(fileURLToPath(import.meta.url));
199
199
  const scriptPath = path.resolve(here, '..', 'tests', 'e2e', 'codex', 'run-parity.sh');
200
200
  if (!fs.existsSync(scriptPath)) {
201
201
  console.error('[forgen] run-parity.sh 는 source 체크아웃에서만 작동. 직접 git clone 후 실행하세요.');
package/dist/fgx.js CHANGED
@@ -11,9 +11,10 @@ const args = process.argv.slice(2);
11
11
  // 이미 포함되어 있으면 중복 추가하지 않음
12
12
  const launchContext = resolveLaunchContext(args);
13
13
  const runtime = launchContext.runtime;
14
+ const skipFlag = getHostRuntime(runtime).dangerousSkipFlag;
14
15
  const launchArgs = [...launchContext.args];
15
- if (!launchArgs.includes('--dangerously-skip-permissions')) {
16
- launchArgs.unshift('--dangerously-skip-permissions');
16
+ if (!launchArgs.includes(skipFlag)) {
17
+ launchArgs.unshift(skipFlag);
17
18
  }
18
19
  async function main() {
19
20
  // Security warning — fgx bypasses all Claude Code permission checks.
@@ -23,8 +24,8 @@ async function main() {
23
24
  // alias `fgx` unknowingly run with zero guardrails. Users who rely on
24
25
  // the profile trust policy should NOT use `fgx`. Surface the mismatch
25
26
  // loudly (harness.ts also prints the Trust 상승 warning downstream).
26
- console.warn('\n ⚠ fgx: ALL permission checks are disabled (--dangerously-skip-permissions)');
27
- console.warn('Claude Code will execute tools without asking for confirmation.');
27
+ console.warn(`\n ⚠ fgx: ALL permission checks are disabled (${skipFlag})`);
28
+ console.warn(`${getHostRuntime(runtime).displayName} will execute tools without asking for confirmation.`);
28
29
  console.warn(' ⚠ Use only in trusted environments. If your profile trust policy is');
29
30
  console.warn(' ⚠ "가드레일 우선" or "승인 완화", consider `forgen` (no flag) instead.\n');
30
31
  // fgx는 서브커맨드 없이 바로 Claude Code 실행 전용
@@ -43,7 +44,7 @@ async function main() {
43
44
  if (v1.session) {
44
45
  console.log(`[forgen] Trust: ${v1.session.effective_trust_policy}`);
45
46
  }
46
- console.log('[forgen] Mode: dangerously-skip-permissions');
47
+ console.log(`[forgen] Mode: ${skipFlag.replace(/^--/, '')}`);
47
48
  const runtimeLabel = getHostRuntime(runtime).displayName;
48
49
  console.log(`[forgen] Starting ${runtimeLabel}...\n`);
49
50
  await spawnClaude(launchArgs, context, runtime);
@@ -33,5 +33,11 @@ export interface HostRuntime {
33
33
  * - 'pre-baked-file': pkgRoot/hooks/hooks.json 읽고 ${CLAUDE_PLUGIN_ROOT} 치환 (Claude — 빌드 산출물 재사용)
34
34
  */
35
35
  readonly hookInjectionStrategy: 'generate' | 'pre-baked-file';
36
+ /**
37
+ * 권한 전수 우회용 CLI 플래그 (fgx 등 dangerously-skip 모드에서 사용).
38
+ * Claude: --dangerously-skip-permissions
39
+ * Codex: --dangerously-bypass-approvals-and-sandbox
40
+ */
41
+ readonly dangerousSkipFlag: string;
36
42
  }
37
43
  export declare function getHostRuntime(runtime: RuntimeHost): HostRuntime;
@@ -25,6 +25,7 @@ const claudeRuntime = {
25
25
  return args ? `node ${quoteArg(fullScript)} ${args}` : `node ${quoteArg(fullScript)}`;
26
26
  },
27
27
  hookInjectionStrategy: 'pre-baked-file',
28
+ dangerousSkipFlag: '--dangerously-skip-permissions',
28
29
  };
29
30
  const codexRuntime = {
30
31
  id: 'codex',
@@ -38,6 +39,7 @@ const codexRuntime = {
38
39
  return args ? `${base} ${args}` : base;
39
40
  },
40
41
  hookInjectionStrategy: 'generate',
42
+ dangerousSkipFlag: '--dangerously-bypass-approvals-and-sandbox',
41
43
  };
42
44
  const RUNTIMES = {
43
45
  claude: claudeRuntime,
@@ -12,6 +12,7 @@
12
12
  */
13
13
  import * as path from 'node:path';
14
14
  import * as readline from 'node:readline';
15
+ import { fileURLToPath } from 'node:url';
15
16
  import { detectAvailableHosts } from '../core/host-detect.js';
16
17
  import { planClaudeInstall } from './install-claude.js';
17
18
  import { planCodexInstall } from './install-codex.js';
@@ -121,6 +122,6 @@ export function renderResult(result, dryRun) {
121
122
  }
122
123
  /** pkgRoot resolve from binary location (dist/cli.js → pkgRoot). */
123
124
  export function resolvePkgRootFromBinary(metaUrl) {
124
- const here = path.dirname(new URL(metaUrl).pathname);
125
+ const here = path.dirname(fileURLToPath(metaUrl));
125
126
  return path.resolve(here, '..');
126
127
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wooojin/forgen",
3
- "version": "0.4.6",
3
+ "version": "0.4.7",
4
4
  "preferGlobal": true,
5
5
  "main": "dist/lib.js",
6
6
  "types": "./dist/lib.d.ts",
package/plugin.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://claude.ai/schemas/claude-plugin.json",
3
3
  "name": "forgen",
4
- "version": "0.4.6",
4
+ "version": "0.4.7",
5
5
  "description": "Claude Code harness — the more you use Claude, the better it gets",
6
6
  "author": {
7
7
  "name": "jang-ujin",