oh-my-customcode 1.1.45 → 1.1.46

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/dist/cli/index.js CHANGED
@@ -241,7 +241,7 @@ var init_package = __esm(() => {
241
241
  workspaces: [
242
242
  "packages/*"
243
243
  ],
244
- version: "1.1.45",
244
+ version: "1.1.46",
245
245
  description: "Batteries-included agent harness for Claude Code",
246
246
  type: "module",
247
247
  bin: {
@@ -25737,6 +25737,7 @@ var i18n = {
25737
25737
  var DEFAULT_PACKAGE_NAME = "oh-my-customcode";
25738
25738
  var DEFAULT_CACHE_TTL_MS = 24 * 60 * 60 * 1000;
25739
25739
  var DEFAULT_CACHE_PATH = join2(homedir2(), ".oh-my-customcode", "self-update-cache.json");
25740
+ var MS_EPOCH_THRESHOLD = 1000000000000;
25740
25741
  function normalizeVersion(version) {
25741
25742
  return version.trim().replace(/^v/i, "").split("-")[0] || "";
25742
25743
  }
@@ -25779,22 +25780,57 @@ function isNpxInvocation(argv = process.argv, env = process.env) {
25779
25780
  const npmCommand = env.npm_command || "";
25780
25781
  return argv1.includes("/_npx/") || argv1.includes("\\_npx\\") || npmExecPath.includes("npx") || npmCommand === "exec" || env.npm_lifecycle_event === "npx";
25781
25782
  }
25782
- function readCache(cachePath) {
25783
+ function isJsonRecord(value) {
25784
+ return typeof value === "object" && value !== null && !Array.isArray(value);
25785
+ }
25786
+ function readNonEmptyString(value) {
25787
+ if (typeof value !== "string") {
25788
+ return null;
25789
+ }
25790
+ const trimmed = value.trim();
25791
+ return trimmed === "" ? null : trimmed;
25792
+ }
25793
+ function epochToIsoString(value) {
25794
+ let numeric = Number.NaN;
25795
+ if (typeof value === "number") {
25796
+ numeric = value;
25797
+ } else if (typeof value === "string") {
25798
+ numeric = Number(value.trim());
25799
+ }
25800
+ if (!Number.isFinite(numeric) || numeric <= 0) {
25801
+ return null;
25802
+ }
25803
+ const milliseconds = numeric >= MS_EPOCH_THRESHOLD ? numeric : numeric * 1000;
25804
+ const date = new Date(milliseconds);
25805
+ if (Number.isNaN(date.getTime())) {
25806
+ return null;
25807
+ }
25808
+ return date.toISOString();
25809
+ }
25810
+ function readSelfUpdateCache(cachePath) {
25783
25811
  if (!existsSync(cachePath)) {
25784
25812
  return null;
25785
25813
  }
25814
+ let parsed;
25786
25815
  try {
25787
- const parsed = JSON.parse(readFileSync(cachePath, "utf-8"));
25788
- if (!parsed.checkedAt || !parsed.latestVersion) {
25789
- return null;
25790
- }
25791
- return {
25792
- checkedAt: parsed.checkedAt,
25793
- latestVersion: parsed.latestVersion
25794
- };
25816
+ parsed = JSON.parse(readFileSync(cachePath, "utf-8"));
25795
25817
  } catch {
25796
25818
  return null;
25797
25819
  }
25820
+ if (!isJsonRecord(parsed)) {
25821
+ return null;
25822
+ }
25823
+ const cliVersion = readNonEmptyString(parsed.latestVersion);
25824
+ const cliCheckedAt = readNonEmptyString(parsed.checkedAt);
25825
+ if (cliVersion && cliCheckedAt) {
25826
+ return { checkedAt: cliCheckedAt, latestVersion: cliVersion, schema: "cli" };
25827
+ }
25828
+ const hookVersion = readNonEmptyString(parsed.version);
25829
+ const hookCheckedAt = epochToIsoString(parsed.timestamp);
25830
+ if (hookVersion && hookCheckedAt) {
25831
+ return { checkedAt: hookCheckedAt, latestVersion: hookVersion, schema: "hook" };
25832
+ }
25833
+ return null;
25798
25834
  }
25799
25835
  function writeCache(cachePath, latestVersion, now) {
25800
25836
  const dir2 = dirname(cachePath);
@@ -25803,7 +25839,10 @@ function writeCache(cachePath, latestVersion, now) {
25803
25839
  }
25804
25840
  const payload = {
25805
25841
  checkedAt: new Date(now).toISOString(),
25806
- latestVersion
25842
+ latestVersion,
25843
+ version: latestVersion,
25844
+ timestamp: Math.floor(now / 1000),
25845
+ source: "omcustom-cli"
25807
25846
  };
25808
25847
  writeFileSync(cachePath, `${JSON.stringify(payload, null, 2)}
25809
25848
  `, "utf-8");
@@ -25813,7 +25852,11 @@ function isCacheFresh(cache, now, cacheTtlMs) {
25813
25852
  if (Number.isNaN(checkedAt)) {
25814
25853
  return false;
25815
25854
  }
25816
- return now - checkedAt < cacheTtlMs;
25855
+ const age = now - checkedAt;
25856
+ if (age < -cacheTtlMs) {
25857
+ return false;
25858
+ }
25859
+ return age < cacheTtlMs;
25817
25860
  }
25818
25861
  function fetchLatestVersionFromNpm(packageName = DEFAULT_PACKAGE_NAME) {
25819
25862
  try {
@@ -25958,7 +26001,7 @@ function checkSelfUpdate(options) {
25958
26001
  }
25959
26002
  let latestVersion = null;
25960
26003
  let usedCache = false;
25961
- const cache = readCache(cachePath);
26004
+ const cache = readSelfUpdateCache(cachePath);
25962
26005
  if (cache && isCacheFresh(cache, now, cacheTtlMs)) {
25963
26006
  const cachedVersion = normalizeVersion(cache.latestVersion);
25964
26007
  if (isVersionPlausible(currentVersion, cachedVersion)) {
package/dist/index.js CHANGED
@@ -2031,7 +2031,7 @@ var package_default = {
2031
2031
  workspaces: [
2032
2032
  "packages/*"
2033
2033
  ],
2034
- version: "1.1.45",
2034
+ version: "1.1.46",
2035
2035
  description: "Batteries-included agent harness for Claude Code",
2036
2036
  type: "module",
2037
2037
  bin: {
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "workspaces": [
4
4
  "packages/*"
5
5
  ],
6
- "version": "1.1.45",
6
+ "version": "1.1.46",
7
7
  "description": "Batteries-included agent harness for Claude Code",
8
8
  "type": "module",
9
9
  "bin": {
@@ -40,6 +40,10 @@
40
40
 
41
41
  > **v2.1.224+**: mid-turn에 연결된 MCP 도구가 **이름 고지 없이** tool search로 deferred되던 결함이 수정되었습니다. 구버전에서는 세션 도중 붙은 MCP 서버의 도구가 이름조차 노출되지 않아 "그런 도구 없음"으로 오판할 수 있었으므로, 위 tool-availability 주의(`command -v` 사전 확인과 동류)를 MCP 도구에도 적용합니다 — 도구 부재 결론 전에 `ToolSearch`로 실측합니다.
42
42
 
43
+ > **v2.1.228+**: Write 도구가 **이번 세션에 읽지 않은 기존 파일도 newer model에서는 덮어쓸 수 있도록** 변경되어 Edit 도구 규칙과 일치합니다(구모델은 여전히 read 선행 필요). 도구가 강제하던 read-before-write 가드가 모델에 따라 사라지므로, "Write가 실패했다 = 파일을 안 읽었다"는 진단이 더 이상 보편적으로 성립하지 않고, **읽지 않은 파일을 Write하면 기존 내용이 경고 없이 소실**됩니다 — 전체 교체가 아닌 변경에는 Edit을 쓰는 원칙을 도구 강제가 아니라 절차로 유지합니다. 또한 deferred-tools reminder가 skill 호출 후 모델에 두 번 전달되던 문제가 수정되었습니다(중복 컨텍스트 소모).
44
+
45
+ > **v2.1.229+**: 도구 호출의 `glob`/`file_path`/`command` 값이 **비문자열일 때 에러 화면으로 크래시**하던 문제가 수정되었습니다(해당 세션의 `--resume`에서도 재발). 구버전에서 이 크래시는 세션을 복구 불가 상태로 만들면서 **원인이 도구 인자 타입이라는 단서를 남기지 않았으므로**, 스크립트로 도구 인자를 조립할 때 문자열 타입을 보장합니다(cross-ref R023 Workflow Script Sanity Check). 좁은 터미널에서 progress bar·마크다운 표 렌더링 시 발생하던 RangeError 크래시(`claude --continue`/`--resume` 시작 시에도 발생)도 함께 수정되었습니다.
46
+
43
47
  ### Capability-Aware Tool Scheduling
44
48
 
45
49
  When dispatching parallel tool calls, consider per-tool capabilities to optimize scheduling:
@@ -492,6 +492,8 @@ Key optional fields: `scope`, `context`, `version`, `effort`, `model`, `agent`,
492
492
 
493
493
  > **v2.1.222+**: 스킬 frontmatter의 `disable-model-invocation: true`(모델이 스스로 그 스킬을 호출하지 못하게 막고 사용자/파이프라인의 명시적 호출만 허용하는 필드)가 설정된 스킬을 모델이 호출하려 할 때의 refusal 문구가 개선되어, 모델에게 **워크플로우를 스스로 복제하지 말고 사용자에게 실행을 요청하라**고 지시합니다. 무인 루프(`/fsd` 등)가 이런 스킬을 모델 호출 경로에 두면 실행 대신 refusal이 반환되므로, 해당 스킬은 **사용자/파이프라인 명시 호출**로 설계합니다.
494
494
 
495
+ > **v2.1.228+**: claude.ai에서 동기화된 스킬이 하드닝되었습니다 — 로컬 커맨드·MCP prompt를 **shadow하지 않고**, description이 sanitize·labeling되며, 로컬 머신에서 그 본문이 `!` 명령을 실행하거나 `@` 파일 참조를 확장하지 **않습니다**. 즉 외부 출처 스킬은 로컬 `.claude/skills/` 스킬과 **동일한 실행 능력을 갖지 않으므로**, 동기화 스킬에 `!`/`@` 동작을 전제한 본문을 작성하면 무음 미실행이 됩니다. 구버전에서는 동기화 스킬이 로컬 커맨드를 가릴 수 있어 같은 이름 호출이 어느 정의로 해소되는지 결정론적이지 않았습니다.
496
+
495
497
  <!-- DETAIL: Skill Optional Fields (full yaml block)
496
498
  ```yaml
497
499
  scope: core # core | harness | package (default: core)
@@ -42,6 +42,8 @@ These are distinct mechanisms. Agent Teams `SendMessage` requires `TeamCreate` a
42
42
 
43
43
  > **v2.1.224/225+**: CC 네이티브 `SendMessage`가 **cross-session으로 확장**되었습니다(다른 머신 포함, macOS/Linux) — `ListAgents`로 대상을 열거하고 `crossSessionInbound` / `dialogExpiry` 설정으로 수신·만료를 제어합니다. 위 표의 "Cross-session = claude-peers-mcp 전용" 구분은 이제 **유일한 수단이 아니며**, 브로커 없이 네이티브 경로를 쓸 수 있습니다. 다만 위 Cross-Session Relay Authority Hardening(v2.1.166)의 권한 비전파 원칙은 네이티브 경로에도 동일하게 적용됩니다 — cross-session 메시지는 조율 신호이지 승인 채널이 아닙니다. (225) cross-session 메시지가 headless 세션·기동 중에 **고지도 만료도 없이 대기**하던 결함이 수정되었으므로, 구버전에서 "응답 없음"은 미수신이 아니라 무기한 대기였을 수 있습니다.
44
44
 
45
+ > **v2.1.229/232+**: 네이티브 cross-session 경로의 대상 지정이 쉬워졌습니다 — (229) `ListAgents`가 끊긴 Remote Control 세션을 `offline`, 클라우드 세션을 `cloud`로 표시하므로 **열거 결과에 있다는 사실만으로 도달 가능하다고 가정하지 않습니다**(구버전에서는 살아있는 세션과 끊긴 세션이 구분 없이 나열되어 무응답 원인을 판별할 수 없었습니다). (232) 프롬프트에 `@`로 다른 세션을 이름으로 멘션하면 `SendMessage`가 그 세션에 직접 도달하고, bare name이 **살아있는 세션 1개와 정확히 일치하면 ref 확인 없이 전달**됩니다 — 같은 머신의 세션 이름은 중복 시 `name-word-word` 변형으로 유일성이 보장되므로 이름 기반 전달이 결정론적입니다. 전달 성공은 여전히 조율 신호일 뿐이며, 아래 Member Completion Verification의 ground-truth 원칙과 v2.1.166 권한 비전파 원칙은 그대로 적용됩니다. 또한 (232) interactive session의 background 기본 실행은 **non-teammate 스폰에 한정**되므로 Teams member에는 적용되지 않습니다 — 아래 stall handling의 2분 휴리스틱을 background 지연과 혼동하지 않습니다(cross-ref R010).
46
+
45
47
  ### Cross-Session Relay Authority Hardening (CC v2.1.166+)
46
48
 
47
49
  <!-- ARCHIVED CC version note (historical):
@@ -421,6 +421,8 @@ Before spawning any agent:
421
421
 
422
422
  > **v2.1.221+**: background session이 작업 보존을 위해 commit·push를 수행하고, draft PR은 작업이 요구할 때만 열며, 사용자의 CLAUDE.md git 지침을 따르고, 항상 작업 위치를 보고하며 종료하도록 변경되었습니다. 이 저장소의 R010은 모든 git 작업을 mgr-gitnerd 위임으로 요구하므로 background session은 그 지침을 읽고 동작하지만, **R020 기준 ground-truth(`git log` / `gh pr view`) 실측 없이 background session의 커밋/푸시 완료 보고를 신뢰하지 않습니다**. 또한 v2.1.221에서 `/status`가 세션 종류(interactive / background attached / background unattended)를 표시하므로 무인 실행 여부를 결정론적으로 확인할 수 있습니다.
423
423
 
424
+ > **v2.1.232+**: interactive session의 **non-teammate 에이전트 스폰이 기본 background 실행**으로 바뀌었습니다(subagent forking 기본 활성화의 일부). 즉 Agent 도구 호출의 반환은 "작업 완료"가 아니라 **"백그라운드 착수"일 수 있으므로**, 오케스트레이터는 스폰 반환이나 완료 통지를 완료 근거로 삼지 않고 R020 ground-truth(`git status` / `grep` / 검증 스크립트)로 확인합니다 — 구버전에서는 동기 반환이 기본이라 "반환 = 완료"라는 암묵 전제가 대체로 성립했고, 그 전제가 이 버전부터 무너집니다. 위 v2.1.221 `/status` 표시와 v2.1.211(실행 중 agent 결과를 지어내지 않음)이 진단 보조 수단입니다. cross-ref R009(fork의 컨텍스트 상속), R018(Teams member는 non-teammate가 아니므로 이 변경 대상 밖).
425
+
424
426
  ## Agent Capability Pre-Check
425
427
 
426
428
  Before delegating a task to a subagent, MUST verify the target agent's tool capabilities against the task requirements. Failure to pre-check causes round-trip waste (delegation → failure → re-delegation).
@@ -631,6 +633,8 @@ git 위임 에이전트는 pre-commit/pre-push 훅 차단을 **자체 판단으
631
633
 
632
634
  > Origin: #1574 (v1.1.44 세션 — mgr-gitnerd가 `bun test` 11 fail로 인한 pre-commit 차단을 `--no-verify`로 자체 우회; 결과는 무해했으나 승인 없는 품질 게이트 우회는 절차 이탈). Cross-ref: R020 (Test-Skip Is Not Completion — 그린 빌드 회피 금지), R017 (커밋 전 검증 게이트).
633
635
 
636
+ > **v2.1.229+**: `/commit-push-pr`가 위험 플래그(`--force`, `--amend`, `--no-verify` 등)를 가진 git/gh 명령을 **더 이상 auto-approve하지 않습니다**. 플랫폼이 이 저장소의 위 조항(v1.1.45 신설)과 **독립적으로 같은 결론**에 도달한 사례입니다 — 즉 `--no-verify` 상시 금지는 이 저장소만의 보수적 관행이 아니라 플랫폼이 기본값으로 채택한 경계입니다. **구버전에서는 이 플래그들이 프롬프트 없이 통과했으므로, 과거 세션에서 `--no-verify` 커밋이 프롬프트 없이 성사된 사실은 승인의 증거가 아닙니다**(R020 "실행됨 ≠ 승인됨"). 플랫폼 프롬프트는 방어심층일 뿐 위 조항의 오케스트레이터 사전 승인 요구를 대체하지 않습니다.
637
+
634
638
  <!-- ARCHIVED CC version note (historical):
635
639
  > **v2.1.206+**: `/commit-push-pr`가 origin 외에 `remote.pushDefault`(또는 단일 remote)로의 git push도 auto-allow합니다. mgr-gitnerd git 위임 흐름 관련. `mode: "bypassPermissions"`는 모든 Agent tool 호출에 여전히 필수입니다.
636
640
  -->
@@ -108,6 +108,10 @@ Reference: #1320 (fix), #1321 (session 113 retrospective 찐빠 #1), `feedback_l
108
108
 
109
109
  > **v2.1.224+**: **세션당 200 subagent spawn cap이 제거**되어 장기 세션이 신규 에이전트를 거부하지 않습니다(동시성 제한과 depth 제한은 유지). 위 표의 "Max instances 5 concurrent"는 **동시성** 제한이므로 그대로 유효합니다 — 제거된 것은 세션 누적 총량 cap입니다. `/fsd` 등 장기 무인 루프에서 후반 반복의 스폰 실패를 더 이상 누적 cap으로 진단하지 않습니다.
110
110
 
111
+ > **v2.1.232+**: subagent forking이 **기본 활성화**되어 `subagent_type: "fork"` 서브에이전트가 전체 대화와 prompt cache를 상속합니다. 위 표의 "Instance independence — Isolated context, no shared state"는 **fork에는 성립하지 않습니다** — fork는 격리된 병렬 인스턴스가 아니라 컨텍스트 사본이므로, 위 Detection Criteria의 독립성 전제로 병렬 배치를 설계할 때 fork를 일반 subagent와 동일하게 취급하지 않습니다(오케스트레이터 컨텍스트가 그대로 전달되므로 위임 프롬프트의 범위 서술이 유일한 경계가 아님). 구버전에서는 fork가 opt-in이라 이 상속이 예외 경로였습니다. 또한 interactive session의 **non-teammate 에이전트 스폰이 기본 background 실행**이므로 스폰 반환은 완료 신호가 아닙니다(R010/R020).
112
+
113
+ > **v2.1.229+**: workflow fan-out이 같은 prefix를 공유하는 sibling agent를 **stagger**해 후속 에이전트가 prompt prefix 캐시를 재사용합니다(`CLAUDE_CODE_WORKFLOW_PREFIX_STAGGER_MS=0`으로 비활성). 즉 동일 접두사 병렬 배치는 동시 발사가 아니라 **의도적 시차 실행**이며, 스폰 직후 일부 에이전트의 시작 지연을 아래 Adaptive Parallel Splitting의 stall 신호로 오판하지 않습니다 — 구버전에서는 각 형제가 접두사 비용을 중복 지불했습니다. 또한 CPU 제한 컨테이너에서 dynamic workflow가 호스트 코어 수를 쓰던 문제가 수정되어, 컨테이너 실행 시 실효 동시성이 위 표의 cap보다 낮을 수 있습니다.
114
+
111
115
  > **Fable 5 long-lived subagent reuse (Origin: #1435)**: Fable 5는 long-lived subagent 재사용(단일 subagent가 여러 단계를 이어서 수행)에 강함 — 현행 R009 병렬 실행 원칙과 상충하지 않으며, Fable 5 실행 시 short-lived 병렬 다수 대신 long-lived 재사용도 유효한 선택지. 상세는 `guides/claude-code/16-fable5-prompting.md`.
112
116
 
113
117
  ## Adaptive Parallel Splitting
@@ -82,6 +82,16 @@ Use a `"*"` deny rule in `settings.json` to enforce a deny-by-default posture, t
82
82
 
83
83
  > **v2.1.223/225+**: 두 건이 Tier-4 Bash 권한 검사와 세션 인증에 영향을 줍니다. (223) 조작된 명령이 **자기 일부를 권한 검사에서 숨기던** 결함이 수정되었습니다 — v2.1.221 zsh `[[ ]]` 우회 수정의 연장선이며, 검사 대상 문자열과 실행 문자열이 다를 수 있었다는 뜻입니다(표시 측 결함은 R001). (225) 일시적 401이 장수명 `CLAUDE_CODE_OAUTH_TOKEN`을 저장된 단수명 토큰으로 교체해 headless 세션을 재시작 전까지 망가뜨리던 결함이 수정되었습니다 — 구버전 무인 실행에서 401 이후의 연쇄 인증 실패는 토큰 설정 오류가 아니라 이 교체 버그일 수 있으므로 진단 시 구분합니다. agent definition의 `bypassPermissions`가 org 정책을 무시하던 공백(223)은 R010 "Universal bypassPermissions"가 canonical.
84
84
 
85
+ > **v2.1.232/233+**: 232가 권한 검사 우회 3건을 수정했으나 **233이 그중 2건을 롤백**했습니다. 어느 것이 현행인지 버전별로 구분합니다.
86
+ >
87
+ > 1. **233 현재 유효 (232 수정 유지)** — (a) PowerShell에서 변수 기록 파라미터가 `$PSDefaultParameterValues`를 조용히 덮어써 이후 명령의 파일 접근을 리다이렉트할 수 있던 우회가 수정되었습니다. 또한 중첩 git 저장소가 부모 디렉토리의 trust를 상속하던 문제가 수정되어 저장소마다 별도 trust 확인이 필요하고, `sandbox.ripgrep`은 user/managed/`--settings`에서만 적용되며 **project settings로는 override 불가**입니다(위 v2.1.214 allow/deny 스코프 비대칭과 같은 계열의 축소 — repo-local 설정으로 켤 수 없는 항목이 늘었습니다).
88
+ > 2. **233에서 롤백됨 — 현재 권한 검사되지 않음** — (b) Windows Git Bash가 경로 검증에는 일반 파일로 보이는 Cygwin-style symlink를 따라가던 우회 수정, (c) Bash 입력 리다이렉션(`< file`)을 인자 표기와 동일하게 권한 검사하던 변경. 두 건 모두 232에서 도입됐다가 233에서 되돌려졌습니다(CHANGELOG v2.1.233: "Reverted the 2.1.232 Bash permission changes for Cygwin-style symlinks on Windows and for input redirections (`< file`); a narrower version will return in a later release"). **이 두 경로는 현행 233에서 권한 검사를 거치지 않으므로, 검사된다고 가정하고 경로 스코프 규칙을 설계하면 우회됩니다.**
89
+ > 3. **재도입 예정** — "a narrower version will return in a later release"이므로 좁힌 형태로 돌아옵니다. 재도입 시 적용 범위가 232 원본과 다를 수 있으므로 그때 다시 확인합니다.
90
+ >
91
+ > **`< file` 회고적 함의(버전 무관 유지)**: `< file`은 232 한 릴리즈를 제외하면 경로 스코프 규칙을 우회해 왔고 233에서 다시 그 상태이므로, **프롬프트 없이 읽힌 사실을 allow 규칙의 증거로 삼지 않습니다**. 위 v2.1.221/223 "검사 대상 문자열 ≠ 실행 문자열" 계열의 연장선입니다.
92
+ >
93
+ > **일반 교훈**: 단일 릴리즈의 플랫폼 권한 개선은 롤백될 수 있으므로 **항구적 보호막으로 간주하지 않습니다**. 스코프 규칙은 개선 이전 상태를 기준으로 설계하고 플랫폼 개선은 defense-in-depth로만 취급합니다(`feedback_platform_claim_staleness` 계열 — 플랫폼 주장의 시효성).
94
+
85
95
  ## Agent Tool Permission Mode
86
96
 
87
97
  > Canonical source: R010 (MUST-orchestrator-coordination.md) "Universal bypassPermissions" owns the full requirement, rationale, self-check, and version history. Core rule: always pass `mode: "bypassPermissions"` explicitly on every Agent tool call — the Agent tool's default `mode` (`acceptEdits`) overrides agent frontmatter `permissionMode` and causes prompts during unattended execution. Skills that spawn agents MUST include this in their Agent tool call instructions. See R010 for details.
@@ -123,6 +123,8 @@ Cross-reference: R010 Subagent Scope-Creep STOP Protocol, R002 (permission tiers
123
123
  > **v2.1.205+**: auto mode가 session transcript 파일 변조(tampering)를 차단하는 규칙이 추가되었습니다 — transcript 의존 스킬(homework/episodic-memory) 무결성 보호. 또한 Windows worktree 제거가 NTFS junction/symlink 존재 시 worktree 밖 파일을 삭제하던 문제가 수정되었습니다.
124
124
  -->
125
125
 
126
+ > **v2.1.232+**: 시크릿·격리 보호가 확장되었습니다 — GitLab 토큰 계열(`glrt-`/`gloas-`/`glptt-`/`glagent-`/`glimt-`/`glsoat-`/`glcbt-`/`glft-`/`glffct-`) redaction 추가와 routable `glpat-`/`gldt-` 전체 redaction, `glab` CLI config가 `gh`와 동일한 샌드박스·자격증명 경로 보호를 받습니다. 또한 공유 `/tmp`의 cross-session messaging 소켓 디렉토리가 사전에 심어진 symlink나 타 사용자 소유 디렉토리를 **사용 대신 거부**하도록, Linux 파일시스템 샌드박스가 protected-path 우회에 대해 하드닝되었습니다. **구버전에서 GitLab 토큰은 redaction 대상이 아니었으므로 트랜스크립트·에이전트 출력에 원문 노출이 가능했습니다** — 과거 세션 로그를 공유하기 전 이 점을 전제합니다. 위 표의 "자격증명 저장소 덤프 금지"는 플랫폼 redaction과 무관하게 유지합니다(redaction은 최후 방어선이지 1차 방어선이 아님).
127
+
126
128
  ## Required Before Destructive Operations
127
129
 
128
130
  Verify target, assess impact scope, check recoverability, get user approval.
@@ -482,4 +482,8 @@ References: #1226 (item 3), #1227.
482
482
  - Memory write failure is **non-blocking**: MUST NOT prevent session from ending
483
483
  - If sys-memory-keeper fails to write MEMORY.md: log warning, confirm to user anyway
484
484
 
485
+ > **v2.1.228+**: **session cleanup이 프로젝트 memory 폴더 내부 내용을 삭제하던 결함**이 수정되었습니다. 구버전에서는 MEMORY.md·archive 파일이 세션 정리 단계에서 소실될 수 있었으므로, 메모리 누락을 위 Failure Policy의 쓰기 실패로만 진단하지 않습니다 — 쓰기는 성공했으나 정리에 삭제된 경우일 수 있습니다. 위 Memory Scopes 표대로 `project` 스코프(`.claude/agent-memory/`)는 git tracked라 복구 가능하지만 `user`/`local` 스코프는 복구 수단이 없습니다.
486
+
487
+ > **v2.1.232+**: Cowork 세션이 **user-scope 메모리 파일의 외부 @-import를 인라인하지 않습니다**. 즉 `~/.claude/agent-memory/`의 MEMORY.md가 @-import로 외부 파일을 끌어오는 구조라면 세션 종류에 따라 그 내용이 컨텍스트에 없을 수 있으므로, 항상 로드되어야 하는 내용은 import 참조가 아니라 **MEMORY.md 본문**에 둡니다(위 200줄 예산 내 Hot/Warm 배치 원칙과 정합).
488
+
485
489
  <!-- RETIRED (은퇴 릴리즈 v1.1.45, 보존 기준 v2.1.212 미만): > **v2.1.210+**: MEMORY.md 인덱스가 read limit을 초과하게 만드는 memory write는 이제 silent truncation 대신 명시적 오류를 반환합니다. write 실패는 여전히 non-blocking이지만, 오류 수신 시 log-warning으로 끝내지 말고 예산 초과 처리(Attention-Weight Tiering — Cold 항목 archive 이동)로 축소 후 재시도합니다 — 이전의 silent truncation을 가정하고 oversize write를 던지면 업데이트가 반영되지 않습니다. -->
@@ -15,6 +15,8 @@
15
15
  | **3: Expensive LLM** | sonnet/opus skills (`deep-verify`, `adversarial-review`, `multi-model-verification`, `evaluator-optimizer`) | $$$ | 1-5분 | Pre-commit, PR review |
16
16
  | **4: Human** | maintainer review | time | hours-days | Final gate, contested decisions |
17
17
 
18
+ > **v2.1.232+**: `/code-review`가 high·xhigh·max effort에서도 **background agent로 실행**됩니다(다른 레벨과 동일). 즉 Tier 3 검증 호출의 반환은 착수 신호이지 검증 결과가 아니므로, 다음 tier 진행이나 통과 판정 전에 background agent의 실제 완료와 결과를 실측합니다 — 구버전에서는 고effort 레벨만 전경 실행이라 "반환 = 결과"가 성립했고, 그 전제로 ladder를 진행하면 미완료 검증을 통과로 오판합니다(R020 "attempt ≠ outcome", cross-ref R010 non-teammate background 기본 실행).
19
+
18
20
  ## Shift-left 원칙
19
21
 
20
22
  결정론적 단계가 잡을 수 있는 문제는 LLM에 보내지 않는다. LLM 검증은 ambiguous/semantic 문제에 집중한다.
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.1.45",
2
+ "version": "1.1.46",
3
3
  "lastUpdated": "2026-07-14T00:00:00.000Z",
4
4
  "omcustomMinClaudeCode": "2.1.121",
5
5
  "omcustomMinClaudeCodeReason": "Sensitive-path direct Write/Edit on .claude/** under bypassPermissions (R010 deprecation, #1101)",