@uzysjung/agent-harness 26.169.0 → 26.170.0

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/index.js CHANGED
@@ -37,14 +37,15 @@ import {
37
37
  assetCliSupport,
38
38
  assetReachesCli,
39
39
  assetTrustTier,
40
- backupContent,
41
40
  backupFile,
41
+ backupFromCopy,
42
42
  backupIfLossyUtf8,
43
43
  backupOriginal,
44
44
  buildAssetEntries,
45
45
  buildAssetSpec,
46
46
  buildInstallLog,
47
47
  buildManifest,
48
+ claimBackupDir,
48
49
  claudeRecorded,
49
50
  claudeTargets,
50
51
  collectPolicyHashes,
@@ -104,7 +105,7 @@ import {
104
105
  targetsInclude,
105
106
  upsertHarnessImport,
106
107
  writeInstallLog
107
- } from "./chunk-SU2RUN2W.js";
108
+ } from "./chunk-MGFWOWF4.js";
108
109
 
109
110
  // node_modules/sisteransi/src/index.js
110
111
  var require_src = __commonJS({
@@ -802,6 +803,587 @@ import { join as join2 } from "path";
802
803
  init_esm_shims();
803
804
  import { existsSync, readFileSync, writeFileSync } from "fs";
804
805
  import { join } from "path";
806
+
807
+ // src/legacy-fingerprints.ts
808
+ init_esm_shims();
809
+ import { createHash } from "crypto";
810
+ function legacySectionKey(lines2) {
811
+ const out = lines2.map((l) => l.replace(/\r$/, "").trimEnd());
812
+ while (out.length > 1 && out.at(-1) === "") out.pop();
813
+ return createHash("sha256").update(out.join("\n")).digest("hex");
814
+ }
815
+ function legacyPreambleKey(text) {
816
+ const pre = [];
817
+ for (const line of text.split("\n")) {
818
+ if (/^## /.test(line)) break;
819
+ pre.push(line);
820
+ }
821
+ const head = pre.filter((l) => !/^# /.test(l));
822
+ return head.some((l) => l.trim() !== "") ? legacySectionKey(head) : null;
823
+ }
824
+ function rows(text) {
825
+ return text.split("\n").filter((l) => l !== "").map((l) => l.split(" "));
826
+ }
827
+ function keySet(text) {
828
+ return new Set(rows(text).map((r) => r[0] ?? ""));
829
+ }
830
+ var FILES = `
831
+ .claude/CLAUDE.md c8a0f19e0c84faec6fc0a999efbf205d72270a1f8bcb8d28894d564431405b52
832
+ .claude/CLAUDE.md c833b9a2b3e762563bdf8984520257579408de387ce3021ac2c606551f39aa75
833
+ .claude/CLAUDE.md 5a167acf64d246b278f878228f07cf76fe2a808e201d3d82c1c0274f50d736de
834
+ .claude/CLAUDE.md 7fbfe6999a82a880a3a0d34bdaf8e263cfd9c927ef5fb33873059182094d3f7f
835
+ .claude/CLAUDE.md 1dc65a4d8c0f2c47d541852f767d85dca41637d7b4009db6dbf41a0beb20ff68
836
+ .claude/CLAUDE.md db2c8bc13b4d9882c71ab1977e5fc5aa66fb031d5943faba587ce9eba100a0b8
837
+ .claude/CLAUDE.md dca32656dfd75c8676504836501607b7c821115a6dd14cba7baafb5c631cb1ff
838
+ .claude/CLAUDE.md 3aeeea1767e0f910adff08340895a524df829240df93d298bb3d0e327d0711e0
839
+ .claude/CLAUDE.md 16347e86e7c1699db212586685a640135891ec5787ba486e0a12562d85bc9b60
840
+ .claude/CLAUDE.md 71db56ff054601a03f8e287a965c1eb1be64d9db1fccc3b03c1f499c2f23119a
841
+ .claude/CLAUDE.md d92c6bbc4c2c1c7a2547e697f7f128b7918d4e2062c9af958b729e7cb0c58308
842
+ .claude/CLAUDE.md 7f94cca4a8ca2f257164ba9b44360d10f99030d3b636c667f65fd0a1771e123c
843
+ .claude/agents/build-error-resolver.md 28597d1e97a68701999704b789a97a20a28b121b7c27ee6a6e80ab43bcd514b8
844
+ .claude/agents/build-error-resolver.md a050a74ed31acba06b36e8c34bc35bc0e684b6b7ab01c891dfc2d13ba94f9824
845
+ .claude/agents/build-error-resolver.md 59f9eb1ae55c6a943d43610cc4e74d05018d681758ac19cb31d874c51605914e
846
+ .claude/agents/code-reviewer.md e112e5e0bbc501788e8a3bfd2771d34e31a8564bbd87391bff7401af1509782c
847
+ .claude/agents/data-analyst.md 1d75c07c51b8a000e536cd8a1c23e0609d93ea51b02cd48f9877610082cb2475
848
+ .claude/agents/implementer.md ba0ee71bf5ae6f8aeb461b0d6161fe0869a7c45820d49145b2abf27264af7dd2
849
+ .claude/agents/implementer.md a12f9132a55526208837e4960c96705df595c0e1cc2870eba1e56f2a87632de1
850
+ .claude/agents/plan-checker.md 405be32ad0d95d8d4cbc8cddb94e7b2be74981a4dadc160aa9200156b56d40df
851
+ .claude/agents/plan-checker.md 467ddec15189cc4273adacd08f97e7eabe1cc164901882f2dd5bba81fbf72327
852
+ .claude/agents/plan-checker.md f605005ba6ebf1e3494e47e257d68a2d34317d15a47b5c8b52317d9cf914b004
853
+ .claude/agents/plan-checker.md 86ad22297e6f1d75d42146685d759af10698cf763feb1c9484d1f0437262e833
854
+ .claude/agents/plan-checker.md 451181ce44f67f747f7190aa53932565df1ce6c934da4584f03f339502fb9265
855
+ .claude/agents/reviewer.md 4036905c0b8deff6555c9f6cbe962609c243d063c417196cca57fc6f87139cd6
856
+ .claude/agents/reviewer.md 1a0153a7fcc8a170f3f08f2a4e392ca72117d413d690441b930028ce923a6094
857
+ .claude/agents/reviewer.md 98c63bfe35afafb28b2543e5b3c662a5df58b66b877b753efc54b9af32208298
858
+ .claude/agents/security-reviewer.md eacaa50c2b2fdee398ba2e3c896c018ea8887d34701e5b841278ea2c1472cc19
859
+ .claude/agents/silent-failure-hunter.md 004ce0389356e0666d80c89cef39ad895ab326b3f7d19d34d23c70ab249a795d
860
+ .claude/agents/strategist.md b217c7bd273e672de44d4df123201cc5c10203fa9bafad84a370d4b7d32b7fc6
861
+ .claude/agents/strategist.md b8d0b387748b5403ee6a489c7e9969f864ebad9544d3d34ee9ff1b4d40f4662f
862
+ .claude/commands/ecc/checkpoint.md 7462e42241b4e38ca4826750567002420f014089b81406279248e22e5879f608
863
+ .claude/commands/ecc/e2e.md fdc040d9d32ca1c4bcc53ccca32042983f9132240fcaca5144de51e4385b9479
864
+ .claude/commands/ecc/eval.md 586ffc66cf889428ff46a86c0d8067f925d58899758eea5f129c9fa62ca55f5f
865
+ .claude/commands/ecc/evolve.md b4a635e1fc9e70f5f53c8bb36a1e8a385e249b5802afaffcc54e17cbacc1c8ca
866
+ .claude/commands/ecc/harness-audit.md ba76cdd30f6fdcf9b6286de753881eebe0e15306829bc3cf53af1591e4126771
867
+ .claude/commands/ecc/instinct-status.md 642b16d6b155f635b76800d78618f4525fc7db9fa298e947e7651e5b3d5fe85c
868
+ .claude/commands/ecc/promote.md b8e6e79dd43053a183b426e88e31631dfe6c812efd37241e26798b88b3febdab
869
+ .claude/commands/ecc/security-scan.md 440cb02294593a8cc86bb1e707fe43a28506f2833de6e20ec811cab12a543db3
870
+ .claude/commands/uzys/auto.md 39e06b3164527fc59bd1cdbf156cdf1f953aab188c68603bce7a396f51921b40
871
+ .claude/commands/uzys/build.md 3eed86d0f9bd8b60724d829a95578e7febab0043a6bdd6353993b2a55021a908
872
+ .claude/commands/uzys/plan.md e1c11ecaa804b6a333f669a8a375b06fc8ba245d9683aed0f172c3fdadf8b4b7
873
+ .claude/commands/uzys/review.md af4e3a4af894bc161f966c64fda60cdc83d815c174f3ad1f9c0a0d40d76a07b6
874
+ .claude/commands/uzys/ship.md 572a644f37c41e1844b95701fe116b2b6e71f22d0ef8593725ab2de24d61207d
875
+ .claude/commands/uzys/spec.md 91ec49031ec683dcd9c5a2befa9b8aca3c95ffb415928b95a2fefa113e102554
876
+ .claude/commands/uzys/test.md 63e58f69bb431a3995b9baae6f6c55f958ae0c46a3d89740ec551fab4b3bb920
877
+ .claude/hooks/agentshield-gate.sh 9493cb98409a5b7b4368307ecf535f39c32d933f8f012f79c9c2b6c2fa788012
878
+ .claude/hooks/checkpoint-snapshot.sh 8ef77c09baa3e24740b19a7d119b83e58559cafcd8e6ab4edfaacc4e42caffef
879
+ .claude/hooks/checkpoint-snapshot.sh f86e7f445cad48569353b9cbce6e162074fdb5224f4b0781734f5a200b94868c
880
+ .claude/hooks/gate-check.sh f04831db7fbce538cc9c9cbcada62a7917e621e6275365686c4849e39da14583
881
+ .claude/hooks/hito-counter.sh eb79ca20fcbaa070c621d5c985422e68e5dbe6b9f4c25f7bf81ae82fe77f6d49
882
+ .claude/hooks/karpathy-gate.sh e72ea3c24cbb953ea7786504362a45f8ec07473a89aeb2006bde2fe0fb6b51c7
883
+ .claude/hooks/mcp-pre-exec.sh 3a7b64149a45dca9e1c15a793e1e84cc28d1f7675d7b519c38cf4b4b27ef5219
884
+ .claude/hooks/mcp-pre-exec.sh ad7f79a13eae3b59e530f00c5ca37b05b01df6629d2c09034bb4f3ac55429120
885
+ .claude/hooks/protect-files.sh f18aef8b355be30afc14e097e8f152a0f00351342e9c1505859f400b445af242
886
+ .claude/hooks/protect-files.sh 0190071614b9466bd4f29189b99f839eceecb08b480f397e5937f8087e6aac08
887
+ .claude/hooks/protect-files.sh 416780a048c3bf674e4348e8982906ae768ca81480b46b56c0fad800d9f21d55
888
+ .claude/hooks/protect-files.sh 5408a423eaade935d984d187f6f93387869cba9423b4644120f30025df4a7b5d
889
+ .claude/hooks/session-start.sh 1c2ffddd804bc82bd456b6cf6e1566084f6c5b43d3596b418e982d073bdfdfb1
890
+ .claude/hooks/session-start.sh b82d19dda66419967708a9937746d03bdd099886f9e7ed9103254209017f1147
891
+ .claude/hooks/session-start.sh 894ebdc240b80b37da93b4124994471c1cb0a26d8592d7a621d8fa3a748e8c79
892
+ .claude/hooks/session-start.sh dfad4b1add755a7efa89cacd370ba418c629f64911d1e0da1bcb19502bbc5948
893
+ .claude/hooks/session-start.sh dcea99eab4c03341b2c571185e8433379e3c5bcfa5bed35d8f1979eee3a45c1a
894
+ .claude/hooks/session-start.sh 490b1d99f6d901d63e48a8122d67225f5c48cc835db0f410fed91c364666ba2e
895
+ .claude/hooks/session-start.sh 613156711d285ae2dc3ac6b1c26d72b7f92f90c80639c6aed1c5fe982bc68114
896
+ .claude/hooks/session-start.sh 238e4a9565b2cde0809fed3b49059fa5b3189ad1c2e86d4963fcbf5e73de7152
897
+ .claude/hooks/spec-drift-check.sh 48e2c5ed391086c842a9a647dcafe50d757513b993561c3137c9cf4ecf96f7b8
898
+ .claude/hooks/spec-drift-check.sh d5bbbfbc3da3bc3eb2d3ac06cc10dc02426ec9472f4fba68300b895c3ffb24ec
899
+ .claude/hooks/spec-drift-check.sh 43f01059a5cc1d779c9e80eb4207fb4e263d853f5a367dbfd45b0b77685d0e28
900
+ .claude/hooks/spec-drift-check.sh d979fffa4f45c4ac03940a70abfa63860bf2a22fbdac9469a43f64565a6abdd2
901
+ .claude/hooks/spec-drift-check.sh 1c7c81e4009866b204e03fd7c4eac87a1b66d7b467a747393dca2bab6793eee2
902
+ .claude/hooks/task-brief-nudge.sh a5bca92a610efab0d770c96e12d3f6996cb184ae0175005724635a9a920fefac
903
+ .claude/rules/api-contract.md ae12cbcacd6380d41d13ca87d0e6f5d589df9f8561f408618cb365e144afced3
904
+ .claude/rules/benchmark-parity.md 595149aec4ed190e7ea96c11c271fa6b743f7ad8c38910dffd2cc180d9a51e8f
905
+ .claude/rules/benchmark-parity.md ee33155ed0ac2c267d0ebacb5f89335cca7dd679c5b2d54ffec81c4738bd9be3
906
+ .claude/rules/benchmark-parity.md b602bc9fc5627ec1e964915240f15748bd13e5bd99737346dbd8d3d2e7c633a8
907
+ .claude/rules/benchmark-parity.md f98f9429c3250ba860b1d39ca304854de0c9e905cdd12fd068d57025e40350e3
908
+ .claude/rules/change-management.md d21082487eeef59664899f85df6098bd46e3c74dbba3f2ebf9e49cf5bab64c34
909
+ .claude/rules/change-management.md 62b7932f691664459d2d7b0971c6aaee22cfeb5f9103ca1145cc55631a072077
910
+ .claude/rules/change-management.md 264b79b82de252cfc933d63708ac8bdf9f18c74f388063d62960456dfa764e2f
911
+ .claude/rules/change-management.md 611bb3a89d47d5b43ac22de8be59edbdf9b700959901d1fa878dc0f89d9ec40e
912
+ .claude/rules/change-management.md d2977a144259dc744835d9bb6c3cfa8d1b390f5393c34d883ba0f67a6bc4dc3e
913
+ .claude/rules/change-management.md 20c548a1380f1e5e9aad5821e0bce0ae999a2dbcfc1f564a990bb30f3590d418
914
+ .claude/rules/change-management.md 0c46f2fe8a9045c14a93895a1614b068d04a4b0e96c183d46ab688e57885c6a6
915
+ .claude/rules/cli-development.md a0bfd2fe69336e8b3bf329a2029d926c96192bc24e784f22f7b99861358829b7
916
+ .claude/rules/cli-development.md b116324d53c7ed3b36d51474f17bd61eede610dff7abea4d3533656dd5cf9a34
917
+ .claude/rules/cli-development.md d5a267f7e22c9d292693857577c2e5819811147b561a38c15b450740d4dce98b
918
+ .claude/rules/cli-development.md 158b76f589d0588f07453b4c47bf9368117467843cda37ddc8bec7197cd671b3
919
+ .claude/rules/cli-development.md cc0545a04706c18304eb92c365d691986d511f02436f405894306e829b4f5b8e
920
+ .claude/rules/cli-development.md 27f7696b1ed13ae15f9e0bfb4bdf2206325f42d87cca6e1a6efcc76f6c9d32bf
921
+ .claude/rules/cli-development.md 73813a5f6f0111507430c1f83c9a099b870bc2a03c16a391817dc74444597eaa
922
+ .claude/rules/code-style.md 2e67fc49d4c8eacaa6dac9064cf566d7f3039509a5b6c5f03b5b2126b0043def
923
+ .claude/rules/data-analysis.md 81b87e41919f7a7a4b06ff459a127b1c44ff6804876856eac0b17da8b0568695
924
+ .claude/rules/database.md a421fe0ffea76ec480cd9cc90ef753ceef7bff3ad4f49ee7837786960b634ba5
925
+ .claude/rules/design-workflow.md 5b6a40c9004355420de2f647c782728e47eb6b01722d7453acf570b6aa002dc7
926
+ .claude/rules/design-workflow.md 49fc2c7efedac467d52031b3bedd7d33fec9c73dff45d20071a5456b82015cd3
927
+ .claude/rules/doc-governance.md 0618fa6f93d245cb46d42862b881fa840e54b196e759d748937d7098c60eed71
928
+ .claude/rules/doc-governance.md e3b2197e19609724e6301ff6035ec9d34e5a60b5385bb4f48a2b633c3c3ca2d5
929
+ .claude/rules/doc-governance.md 5569bb742cc2c0666b2431e3eb662d5fdeb99f8f7224506e0379ce618c4bdf61
930
+ .claude/rules/doc-governance.md d83292a77146ae96e7adcb2dd796811ad8af979526e8d81b1a33bce8cebe6b7b
931
+ .claude/rules/doc-governance.md 54157849bbf9897969745f1d162181b93f4dd9260ae18d4a890b6ad014232797
932
+ .claude/rules/doc-governance.md 8d508bf15bbc1e87b8d0820a6e54a6d5de4b243ae8859ee98b6657d60dfbc7c7
933
+ .claude/rules/doc-governance.md c6f2bb6210ae076acf15e6928a8bb20adbd9d40727433c462d5e1b5eb73803de
934
+ .claude/rules/doc-governance.md 5257f74d94188b18977670a4299658673e00d7b227c54ebb19e00ab019d9adfb
935
+ .claude/rules/doc-governance.md 364c147096985e1fad1a03457ac864a6e4839d8d9487a5c7f20fbaafeeb43eaa
936
+ .claude/rules/doc-governance.md 589e70962b426503098c5d1a60da4b11f9a0c97a654d3ccac900d58f02b7fb52
937
+ .claude/rules/doc-governance.md 7a79bba801a1fb3695566bc19c9bd2f89456219560d76ac4f2bcf405c238b6a1
938
+ .claude/rules/doc-governance.md 3360574fb55f332cf3de18ea32506326fb2880651a593c0bec0246337633fe80
939
+ .claude/rules/doc-governance.md c14e70d6fc5b0ca8e9385d293cccdc39512ec6e73fac6f34ed723572acbebd97
940
+ .claude/rules/error-handling.md 5ea6a188e3a925d5f1f38c1defb766bf71af7a408b58ecce208c7fd3059aa843
941
+ .claude/rules/gates-taxonomy.md 2276e03e41463f946d5b4867c953579aab91445bb781a4d24ecd9337d2f67e3d
942
+ .claude/rules/gates-taxonomy.md 8a5162bd03f20c92230e2bd84a879de5f5d24a5746e6489f3dc895891055f4a2
943
+ .claude/rules/git-policy.md 932e24935cdd20f088b4a3a75a493cb454e065c75e294283fd01a7a768bf9059
944
+ .claude/rules/git-policy.md 3c0cf97e7ec6d921cb8b066d6d34a9f70f57fbdb0c78e9ab11cb919a4251da0d
945
+ .claude/rules/git-policy.md 0d8d01c7b471b4623be31221e773b7298bf230aa102394e0384859db5393b0c6
946
+ .claude/rules/git-policy.md 1c83e7e9acd5967d31406fec70a231cd8de09d5931eb7ca8ebed68f428c3d081
947
+ .claude/rules/git-policy.md 421e837c323bed48fd7e51d02e3c27dd479037d67ecce9dbcc0da3b8c1e764b3
948
+ .claude/rules/git-policy.md 02e127647bee532d0ffc5b994eb2f554f42e96b10529618f953e9b27a3ec0ab2
949
+ .claude/rules/git-policy.md c4f5c1f4b33f3f91aebe673b736b3dc76db785a225d0214f29ab6ceccec26550
950
+ .claude/rules/git-policy.md e1ebe8b7abf6e61015bef44c6f848f13ae8cafe16384b765b35905efecf0a21b
951
+ .claude/rules/git-policy.md 469077325ea8c4a67dfe827014370bc099494998f55aa76f864f6411b40b07d8
952
+ .claude/rules/htmx.md 4faf811dcf5b2b85f899507b249db4853b328c73b2d45760106c1b2132b53c83
953
+ .claude/rules/nextjs.md 855eb2f49b830a89ebd9b92f29a05ea3348d6dda032d2a267c15a5c762371ea5
954
+ .claude/rules/no-false-ship.md 964853f056a2ed898b09648faaf5302d471d3e723dc8e15d387e32aba82eee14
955
+ .claude/rules/no-false-ship.md 2d760fd1f3387233703c04127bc595874a835ea46a50055d7c506cdbc7ece5cf
956
+ .claude/rules/no-false-ship.md 9098f58fe799367cb6cfc02779715b02c4f0a2e5c24539fb2d65f5eb36332762
957
+ .claude/rules/playwright-launch.md 770232379a9205f0466804b83edb4f53e1ccef2fcbc5e82b8e0c5b0a96fac783
958
+ .claude/rules/playwright-launch.md 1bf90d35a050a1f0d712f406329d687bf9bc7661ed0a183e83613bfaef895820
959
+ .claude/rules/playwright-launch.md 783be44da36bf9eaef56d0117d6cd19b7c0c1ef9242745b3f3f87721e84f2664
960
+ .claude/rules/pyside6.md 19c092d5fd7691818e9a759bb23173c9aa1f511c4766a67a9e7fa918b7062852
961
+ .claude/rules/shadcn.md af1fc4624cdede22a35d087b8a7fb4ef042302e2c998373c73f018736e68e5a4
962
+ .claude/rules/ship-checklist.md 14319e7639aa4827690099efd5ad228c997e56a9002eeba6c90e7f274c44bb12
963
+ .claude/rules/ship-checklist.md d371f417f9af32a72afa99e38378d5a95a085ea5c8ad106328cf41a5f61cf117
964
+ .claude/rules/ship-checklist.md 27d3885cc3944a1a4d92dbd8e0d51ac943d7971d2284db77244deafe007c2906
965
+ .claude/rules/ship-checklist.md 286fe3b971c1aa72bb41f610c576ef6d23a9778ed4ab4cbbb493d1f241494a44
966
+ .claude/rules/ship-checklist.md e5d1dc357c54026f473ffba52b6ae3746ef49173b8270fea6faf16fbc2ec7b10
967
+ .claude/rules/ship-checklist.md 6825d1ce40a817f9fa004256b17b0685eb1ccb69ea27641c97e53dd5e323e755
968
+ .claude/rules/ship-checklist.md e713a2738dad8a03d16f0cb1b24a7b207bb4a1445766f883391a0b4a8ad6a766
969
+ .claude/rules/ship-checklist.md 0d9988b3d6b387dd13738c5f1667a8f07e72929f5515168e2ef6e94ad4c0da88
970
+ .claude/rules/ship-checklist.md 1b42169da6e29bfee8ea695831154f672d7cabd8816d1993678c4955a43ed1e4
971
+ .claude/rules/ship-checklist.md 9423f862188ea0ddcb5ec9594e457988c23dc80a0bdba7ed6cc7630f8cc4623e
972
+ .claude/rules/ship-checklist.md be7e93da56b688c9b90d5392dc29b16197d5d4857152f073eb39d1c737952a02
973
+ .claude/rules/tauri.md dd429a144c71f1205384abb5c305b373908e8f6c2c4ae7d6b4dfa9fa707e972d
974
+ .claude/rules/test-policy.md d775453a9b0c3fd7f65eba039e512ec6fc92eda448a2218738da6bb1c85a3023
975
+ .claude/rules/test-policy.md a106e6952520eaa2cebedb9a20a47ee12a8bd0069639077f324cc1d93e3d5501
976
+ .claude/rules/test-policy.md 1b6f0c2fab4842c974c11dd53b22320fb5593870390e0c375625ec584196e580
977
+ .claude/rules/test-policy.md cc73a7e656c237c4313bfa814a9eadab5a44542ff8dbf250fceaf97d6ae1f05b
978
+ .claude/rules/test-policy.md 87660a29cbf43f49e24fd7f53124f0383c94c8333138d1cc1ab9dc233b5e8a4a
979
+ .claude/rules/test-policy.md 54426764c08cadc8c1b31bdaa5817f5c4aefc359d263bd13051949aec7858c0b
980
+ .claude/rules/test-policy.md 9f1e71e12db41a3b20653854c66adcb224c47e86d6a5815d3b7002418cae458b
981
+ .claude/rules/test-policy.md 95b9c6af6a63e4cc85488e109f42440b7f7d1892c73d5b96b7ab387354303cf4
982
+ .claude/rules/test-policy.md 3460db5bbfaea281e417c55b5a76236b10c64c38cf38fe16b934f6799c1268b5
983
+ .claude/rules/ui-components.md 836b66be19c773b3cfa2ee92ed29bd802d8883a55da21cf0be9b73e25a2c8ebe
984
+ .claude/skills/agent-introspection-debugging/SKILL.md aff0d52785d3013d9f98de95ca778bfcab7c566db20352ead42852a1659292d2
985
+ .claude/skills/agent-introspection-debugging/SKILL.md f03dc3838ba8b81ad6a87959a2d666f8d5915d3516cea60d12a65ce74685c54e
986
+ .claude/skills/asis-tobe-decision/SKILL.md 8880ea604b8458acd30b8dc515efc54a6a1640590c572d5f4be7034cbd2d7242
987
+ .claude/skills/audit-harness-fit/README.md 885c756b8fbe51d23747667d3d96ba8c76e1c0e5fb48030cd394b0dad4c304f5
988
+ .claude/skills/audit-harness-fit/README.md e1295cd42a0671d373d7d071374918abdc37aa294052ed6bde8511ac07e80039
989
+ .claude/skills/audit-harness-fit/README.md 2aa6eb69e9991d0156b140f5c4ca36dd87b32ad006aa8dc176f173e7a864ecb9
990
+ .claude/skills/audit-harness-fit/SKILL.md 6919e5c6fce93b4262392ddd9e0476b700e921e39a91ab646bf48f05f4fbe39a
991
+ .claude/skills/audit-harness-fit/SKILL.md ccf5817e3ebcc7575e409b4a1c397f2ef23d690e355490487b2bd829736d1ab5
992
+ .claude/skills/audit-harness-fit/SKILL.md 85c489aec23eb0b9f907c3b10395dabbe03add8300f6d365e886e02f833fd769
993
+ .claude/skills/audit-harness-fit/SKILL.md 5f20eaac20e77c3207978857e2424bcb86d5681362528eed7cc3a09afdffb845
994
+ .claude/skills/audit-harness-fit/SKILL.md 3c348fe635f8b389a349db3f686ebca4f49e1ef7058aa3b4c6e0211e51c12562
995
+ .claude/skills/audit-harness-fit/SKILL.md 9dfd4565013a630c0aa66c9396b4d4073fe70f8601bff89989ebe162da7beb76
996
+ .claude/skills/audit-harness-fit/SKILL.md a23c98c78fd9c5f4660dd73058d58eaf78aa49c107bbc0e3c60de73231f5c163
997
+ .claude/skills/audit-harness-fit/evals/scenarios.yaml 016257464f98f62433e2aba5a064405f41128b54eba05e3702cf44ce93d97ae6
998
+ .claude/skills/audit-harness-fit/evals/scenarios.yaml ac6355013fb7be658196e135ac449bfa5afdc564adb1d5d1ed10d65a64d16e04
999
+ .claude/skills/audit-harness-fit/evals/scenarios.yaml 714fe2ef457dd38fc9b3b354b7f2d616c5d7121770ef1dd889d008eaec661159
1000
+ .claude/skills/audit-harness-fit/references/apply.md e4803a5d6d6c0d32c9808172a03f0f555320ef29fdf73277dd4fc535c4474d77
1001
+ .claude/skills/audit-harness-fit/references/apply.md 97886bd748ef2e2d9a979dd0cf65c5acf81a90c2a19d08851ce87c66df933f92
1002
+ .claude/skills/audit-harness-fit/references/apply.md 6f38cb6673546bfe6609ff6ae18436e5487f93386ac1bfb4625f9c85997c36e6
1003
+ .claude/skills/audit-harness-fit/references/audit.md 39d077f20624e69582ac0e2df28d192c08e8246f8c7dfb8e471e7c461f1cc5f0
1004
+ .claude/skills/audit-harness-fit/references/audit.md 973605514d4eb560b79ff267058e6dbd47bd61b53752f3f91e7f49a4904eac4f
1005
+ .claude/skills/audit-harness-fit/references/audit.md 328d620140846005bf326998387e9305371bf95b5e95cb3a9e7272377e26277a
1006
+ .claude/skills/audit-harness-fit/references/audit.md 4b4eef5a9060ad0a7fb264b261c69802c1c3f0e7c61787ccca18be898c84c091
1007
+ .claude/skills/audit-harness-fit/references/audit.md b93eba13d00481e391fc05e70d894164661ae689f28b08d47514e2c35ebfc790
1008
+ .claude/skills/audit-harness-fit/references/official-criteria.md b80c77f12fdf1752f671eb1c0f8edb6f4f34c3777d6753b9af713f91cff77222
1009
+ .claude/skills/audit-harness-fit/references/populate.md 48227ddac79899f725769050f6105aff0b352d47f72b01341e836362db943ad3
1010
+ .claude/skills/audit-harness-fit/references/populate.md eabe235e5e097ad44a42588201ed89dca359e9fd1a301e29be02deb0338d38cf
1011
+ .claude/skills/audit-harness-fit/references/verification.md deff70dc0f419a760e8b280a2ae57b43a0ae859c17fb6627ea749741b855ff62
1012
+ .claude/skills/audit-harness-fit/references/verification.md aa367e0655a98ce575919e5c30687713187346a7976b97fc1081a99bbbef6ce3
1013
+ .claude/skills/audit-harness-fit/references/verification.md 18bd5f577b85cb043229ca9df160ec9c0f3fb70d01c3db5abb5ccbba7ae6dab1
1014
+ .claude/skills/audit-harness-fit/references/verification.md 695c1f08c6bee5de28d0edfec796df12ca5fbff8cdb473bafbda6fb7f3cff79a
1015
+ .claude/skills/audit-service-gaps/SKILL.md aefd2a47a0b9c2b6bd1846151e60cef0147d0bfbb4b1933da2431f980a0f2922
1016
+ .claude/skills/audit-service-gaps/SKILL.md ba9ac6df2315538935aff945f25a7596b3a9e478c4cdcb3a218ff404f4b612d7
1017
+ .claude/skills/audit-service-gaps/SKILL.md 81323cc7d4bda9f3739e8a72f566699d209f888aa216f77f106e77db975f231d
1018
+ .claude/skills/audit-service-gaps/SKILL.md bbc7782ea688ae74f12934145c1041f58a029eb07d9979c316849cb9fb88f56e
1019
+ .claude/skills/audit-service-gaps/references/modes-and-evidence.md fa73b3edf2c55f5caf47f1f2d930d8c2ccd737af0a2def5f40a1db942029275d
1020
+ .claude/skills/audit-service-gaps/references/worked-example.md e5f31f498e864dcaabe2a0d6a05fe1d64cd8be6a1b79a18de78bcbb42e06d658
1021
+ .claude/skills/chatgpt-delegate/SKILL.md 0e614e643bb8bad52db3663ff9394f77ef6c89a6c72c529796deeed824eca0f0
1022
+ .claude/skills/clear-korean-communication/SKILL.md a8afb5e0114332fd7831de12a12cd981e95726458df61f1a3fdb6160086aedc5
1023
+ .claude/skills/clear-korean-communication/SKILL.md fe480eb8357a79abcc1f6c5954c61f0a8b3e7479b9835b7fbdead18a9dac4b46
1024
+ .claude/skills/clear-korean-communication/SKILL.md a8a41bd88b2b04c931047f08614f8c431eb8e401fe366d110291201a9fb571e8
1025
+ .claude/skills/clear-korean-communication/references/pre-send-checklist.md 65f93177e9a442332c2c90f4e905c4d558b6349e47d5c86eee7705b76b71a1b9
1026
+ .claude/skills/clear-korean-communication/references/why-it-works.md d4439db6a1765fab5fa6875d0528fe715366c270ea35853ad8bb1404388200cb
1027
+ .claude/skills/clear-korean-communication/references/worked-examples.md d53369cf02c62147510bae3a0cfa878ce89013bed11a30c32cc675dd0a0df825
1028
+ .claude/skills/codex-consult/SKILL.md 0af4f6cd00739e62d73f7adc9c8ea85b0db3ee53432bc5605fbf6bf788a0cd13
1029
+ .claude/skills/codex-consult/SKILL.md 288d6d5f4135b8f3e1d8b06b42b68c238e63c9257f973ecdc4f86445d5619be1
1030
+ .claude/skills/codex-consult/SKILL.md 767b0d65ff96f0a10c2cd81335a5ded2a85394b8e8ab3aa1c7737c6296f22582
1031
+ .claude/skills/codex-consult/scripts/codex-ask.sh 64835a9e11094bc24d9e8f9044a98a699ca45155d516dba926ffb8c145cbf1f6
1032
+ .claude/skills/compaction-handoff/SKILL.md 1b19203ae45869dd43b7ca4b28c63bb5c4267aefc9a62abb17d29bdceee316a9
1033
+ .claude/skills/compaction-handoff/SKILL.md b484a4408f25f4b78bf2e7cd88b1b3fec7b969d6c4a03de8a3b8e072719fc74f
1034
+ .claude/skills/compaction-handoff/SKILL.md 42d8300cddc4bbe78b353c8ff846b5fd8ed2b4a68f1998982900fd31596c1755
1035
+ .claude/skills/compaction-handoff/SKILL.md 59191dc216233b74e5f5a72ed1041d8c236504a386e8b5df81dbf52062dbaad9
1036
+ .claude/skills/compaction-handoff/SKILL.md fe70142b0bbf21b5a7b6e9e5af8f0011e6b8e654746f97f4391384d5143c9701
1037
+ .claude/skills/continuous-learning-v2/SKILL.md 7629ed1a18ce078b57f22f407115a41a7f404aee73de17667ec5571b0001a8e4
1038
+ .claude/skills/continuous-learning-v2/SKILL.md 75485ddb37e2d1d6f056b404d9939bf46a2b409b1286aec209a510112e5b64b1
1039
+ .claude/skills/continuous-learning-v2/agents/observer-loop.sh 25ceefcc260c3599b6d12148d1a573110ace3091c723bdee3a3cf10692e5d4e2
1040
+ .claude/skills/continuous-learning-v2/agents/observer.md 320d50ff2965efeabd6f07c2be134e11da160293e958c1bc27c309d613839ad2
1041
+ .claude/skills/continuous-learning-v2/agents/session-guardian.sh ee6e4c0990f8d538cae1c85aa194e01e9ca2336e5d993ef68eb608b96cb0d82c
1042
+ .claude/skills/continuous-learning-v2/agents/start-observer.sh 6b1966e38eb0c96d61de5d204b87097592884364be59e5bea6007289e8068936
1043
+ .claude/skills/continuous-learning-v2/config.json 6f17e7a99aafe252ecd0b9212fb5f606be50b8ce1685f5a6435e46e87ffeb970
1044
+ .claude/skills/continuous-learning-v2/hooks/observe.sh 285c673af5a5f5fcc0839e924ccdb4b7326c593f9198f690c635b2fa7091feb6
1045
+ .claude/skills/continuous-learning-v2/hooks/observe.sh e632c2f486248b8b141059c23586d5ca0187df8c34f53d7597cd845713e06948
1046
+ .claude/skills/continuous-learning-v2/scripts/detect-project.sh 527917b87d8b35b38baf01ca96c6fc4cbeb91ed9a24c6f9c09e4f4d290555295
1047
+ .claude/skills/continuous-learning-v2/scripts/detect-project.sh a39677edd0ce1deb7628ed31610baafc16090a710233963d2b6a55db64167cf9
1048
+ .claude/skills/continuous-learning-v2/scripts/instinct-cli.py 777193745515c8dce35676b1696c90a85e2610705157205a0b54e8e453b69942
1049
+ .claude/skills/continuous-learning-v2/scripts/instinct-cli.py 0b060a762f0fc4ad56e45cbaa14c14fb9ab3f468763f6a32a17bb864fbd3fc30
1050
+ .claude/skills/continuous-learning-v2/scripts/lib/homunculus-dir.sh 99dfa99ae0f7c6e2e15ed5b5bf3c46e91a5f089f4060ba93d5da5e85e04fd308
1051
+ .claude/skills/continuous-learning-v2/scripts/migrate-homunculus.sh 34f121c143a676d330f06209618aae8cb08f8155298cb5fa70c893314bf9b303
1052
+ .claude/skills/continuous-learning-v2/scripts/test_parse_instinct.py acf556e8a8023347b35988bb490927a4e9f65f2579b03f26cad610687656605b
1053
+ .claude/skills/deep-research/SKILL.md 2d631427fc9aba27a318735f930bdb49f5c6ce416506340025eac01648f1df09
1054
+ .claude/skills/deep-research/SKILL.md 69be70af34e27112f192cbe201210c4cf541c24952670487213de715aa297b40
1055
+ .claude/skills/deep-research/SKILL.md b852bebb31908f352c5397bde6de06ee7ca3c0e1c866fae4dedbd5c4fbb27323
1056
+ .claude/skills/deep-research/agents/openai.yaml cb877e559cfe405d0e12bfc9bcaef657ab05a30ef698e6f3e486e39c5e0a6d2d
1057
+ .claude/skills/e2e-testing/SKILL.md f84ae93c159bf6ecef5a60c9735dc82d96bc5f977ef52eb71678b66722acf684
1058
+ .claude/skills/e2e-testing/agents/openai.yaml 5f50508a300616d77f39dc50a51de10cabd05ef7ae770e7948ef6c28f340cdf2
1059
+ .claude/skills/eval-harness/SKILL.md 03fc47842b35861231efdd1d15de291942915c372b8ffcc05a22e942d1233ced
1060
+ .claude/skills/eval-harness/SKILL.md 98f10c6cfc7fd041a358093f5c700b489d431879b90db778db7623a3c1c5404f
1061
+ .claude/skills/eval-harness/SKILL.md 12399b9de9e044273fd4dd6a8177bc4f17db008a33df83557ef56770b1466a56
1062
+ .claude/skills/eval-harness/agents/openai.yaml 6f2c19eb59062ca776286c2f6a6a7f1b552b4f927a2b48de888a7dbb2eeec6bd
1063
+ .claude/skills/explain-plainly/SKILL.md 7838e4f78b7d4d46d31a7c932f069fc66ec4bcd873e49fb57f37923be188fd0d
1064
+ .claude/skills/external-model-consult/SKILL.md b1d7db909a459708ed721f5a7eeeeebe48fb3d57448f763e7e0000df5426a241
1065
+ .claude/skills/external-model-consult/SKILL.md c33d6d2e02aa9631fcb4e91aae83b56834307b0290a984af55378d2f0011d7dd
1066
+ .claude/skills/external-model-consult/SKILL.md 24cafc7b50fde21eb874fc2178d3ebd7eca3b1c54e9278d60a088f9079b7b534
1067
+ .claude/skills/external-model-consult/SKILL.md 2d115e29ad53d778ac4d4f942ec2039b441ecc571d612d27cc725695641f4db1
1068
+ .claude/skills/external-model-consult/SKILL.md a4d429bcd4737fbb2a90de6b9beb9cdf0488fe385eb0f6fb395f0e76322dbb0e
1069
+ .claude/skills/external-model-consult/references/direct-calls.md 6bf094fe54bcb09285ba552371eabf1d743545eccdb118157a8aea987b7c8147
1070
+ .claude/skills/external-model-consult/references/direct-calls.md 966db9c1f80c367ffc81842b83326a67190cc97287e7d624c0c16ee65fd4b16e
1071
+ .claude/skills/external-model-consult/references/model-evidence.md 27dfc0eaac4bbf97dbe4430852e947d99a7bd895aeaa7f1d565915c2a2fdef1d
1072
+ .claude/skills/external-model-consult/references/prompt-templates.md 2277839d5eb9ecbf8535f51a1f1ca97d55816e47b6ea578f34e9637280b1b5ea
1073
+ .claude/skills/external-model-consult/scripts/codex-ask.sh 64835a9e11094bc24d9e8f9044a98a699ca45155d516dba926ffb8c145cbf1f6
1074
+ .claude/skills/external-model-consult/scripts/codex-ask.sh 75f24da435dff5ea7ed7636d8b121456d1e91806e9a114ea993862e173d84d72
1075
+ .claude/skills/external-model-consult/scripts/codex-ask.sh c644272c25f3d0d42ab63bc8c4acf81c1ae90ce1af5f7780977dd63f464fda7b
1076
+ .claude/skills/external-model-consult/scripts/gemini-ask.sh 6736c394de1d059908ebed770221b298f37d09e01aa3eb58991265c2d45915cc
1077
+ .claude/skills/external-model-consult/scripts/gemini-ask.sh a598276b4e2d9e4a54b704229822d8da49a6c54497c8f2471af5420b4c3017c3
1078
+ .claude/skills/external-model-consult/scripts/gemini-ask.sh 9c5eb72c61d140228dff796ff599f88982b76763abbf52aaa31486ddeb03e9e8
1079
+ .claude/skills/gap-analysis-e2e/SKILL.md ef28d245d354c07de60244778469fcc344385a584eddba33c67e9b096654ba4f
1080
+ .claude/skills/gap-analysis-e2e/SKILL.md 739e9a181eac99c749b585fc4f2b64a30dcd4783083422afde64ea85a9a2b062
1081
+ .claude/skills/gemini-consult/SKILL.md f096ad4e6a16e4e6d33ff7d817382e3f8c07311fd7c1f809ae91a951a9f58856
1082
+ .claude/skills/gemini-consult/SKILL.md 24c7f1a8855f5f44447015990991c47c80dc14fd9e373dd818084f8870ff8004
1083
+ .claude/skills/gemini-consult/SKILL.md 9ec900de7b699b73addd0e6259b4a2fc8bbf559d22662842424a1402cb581793
1084
+ .claude/skills/gemini-consult/SKILL.md 81cf4563f9fc790a64796a24e6f85f3b33bffc7e31989dbaebedcc2452984805
1085
+ .claude/skills/gemini-consult/scripts/gemini-ask.sh d9f4cc371e3e3b1919dd773d41b351484c9a3612487bee1ba314378a8486a39c
1086
+ .claude/skills/gemini-consult/scripts/gemini-ask.sh 87b065bec8c13b28dcc451235dcf9679d97af4f68ec678153e23ee14f7c94d0a
1087
+ .claude/skills/gemini-consult/scripts/gemini-ask.sh 6736c394de1d059908ebed770221b298f37d09e01aa3eb58991265c2d45915cc
1088
+ .claude/skills/gemini-delegate/SKILL.md e3d569add39fecf8c412d76c287e88054710f70b87ac38d88c20ad7b00b301fa
1089
+ .claude/skills/genspark-delegate/SKILL.md 3f495d55f1968730c9ce66009745530c16adee5110267e7b735f6a0333e2bcf2
1090
+ .claude/skills/gh-issue-workflow/ISSUE.template.md e004bcbf6199486d527feea43aa68be108bfc8fd3b13800bc543baa778291dc0
1091
+ .claude/skills/gh-issue-workflow/ISSUE.template.md c30fbe41d1d6ca15a82c031441c8b20a6db20cabd3d52c9c2c7ec70ca97d60fa
1092
+ .claude/skills/gh-issue-workflow/ISSUE.template.md 6c897058f7cfbc7b3eb5a3688f21a106fda39b7ded0f05570cff349214aca427
1093
+ .claude/skills/gh-issue-workflow/SKILL.md f2b906076945adce0cfd80dd9331420eea0bd1c1758b76e1f300c82811b06f50
1094
+ .claude/skills/gh-issue-workflow/SKILL.md 99736619cdb450870fb8b51e9ef3375fdd4c625b5d23e37c75078e40b1f1dd32
1095
+ .claude/skills/gh-issue-workflow/SKILL.md 00dc33d939b034dac6c653a07a64da5b362e350bd9133def2f11420c94353008
1096
+ .claude/skills/gh-issue-workflow/SKILL.md ea1012246121662e0604e296913b63e7ce5a02b902182c86102dabe5e13563fd
1097
+ .claude/skills/gh-issue-workflow/SKILL.md 0b1ce6a696c1388e928240ec787b449dd0b0a92749789fe28f8627fbb9aee880
1098
+ .claude/skills/gh-issue-workflow/SKILL.md 578c25a3687c7c6557c2bd115489f44a49d5668e2cb97e114a009d7066db7a72
1099
+ .claude/skills/gh-issue-workflow/SKILL.md 7128c3faddf72ce6285b3a0e7179da01d6a434659ccef6f9b51851b3f5f50d17
1100
+ .claude/skills/gh-issue-workflow/references/hierarchy.md 0e16e38d5919e5eed0aa044899895fb13c3846a333f3470d8001bda09ba959c4
1101
+ .claude/skills/gh-issue-workflow/references/operating-model.md c6feec997887d05d3385441258c464609e52c4bbebb7c0b7390a5d6016ad9a0a
1102
+ .claude/skills/gh-issue-workflow/references/readiness.md 08df321b014d96f8d5b5e0c7af7f36d09d719fb098bdaec7928af4a77c1866cb
1103
+ .claude/skills/harness-health-audit/SKILL.md 12932ba2e5b77a7efab0ae2d0fca334bf249503a583de5a3933105fba89c94ef
1104
+ .claude/skills/harness-health-audit/SKILL.md 6a843a002f9a7ca9c04816214509caccc1cc3f3661595939cc4096366847f09e
1105
+ .claude/skills/harness-health-audit/SKILL.md 16501e7db181780684612f4f38db80861e775cc1204f444169efdbc5d9165bb3
1106
+ .claude/skills/harness-health-audit/SKILL.md b481d7844303896a24a3a95269a035ee57690d8c15c5ad5e85f16227fa5f7f27
1107
+ .claude/skills/harness-health-audit/scripts/observation-digest.mjs cfedf96b819819142f2d69bdd6663bcbdd56301c429545b4f31cc2f358249cb8
1108
+ .claude/skills/harness-health-audit/scripts/observation-digest.mjs 7c9c42fed4c3ab1a0df6363386c34e03776a53f6b32aa1bef3c6899dcd77aa5f
1109
+ .claude/skills/humanize-korean/SKILL.md 7d0d77c25f5990f203480abc6a02772d534a40ebfff4ab4086cf5da3ed1b7afd
1110
+ .claude/skills/investor-materials/SKILL.md 0541ac8ede8d39c59a646834481d0de86312e598331b86dc7027ece0def3c193
1111
+ .claude/skills/investor-outreach/SKILL.md ab71ee37a1ff5f9b7f27908d33fc47f03e7897e6c87be3f8d7c0e4a8d73fefdd
1112
+ .claude/skills/market-research/SKILL.md 7ef3fa13d6272fd295eeb2aca9f6a2f09f6a8270cf33b0675fc5a0018cf6e406
1113
+ .claude/skills/market-research/agents/openai.yaml 42e1b1bf676506bc50027131cd8226b151f48a57551197308102dd01fd080943
1114
+ .claude/skills/model-orchestration/SKILL.md da6b448d0119e7dfd441f47c9afa267c227ac9301561ddf07c3fdc81bf494ff6
1115
+ .claude/skills/model-orchestration/SKILL.md d4ec28fa8e7bcf48607a17dc84a9fb873dd9f58f6ffef38ae5324f94477160a1
1116
+ .claude/skills/model-orchestration/SKILL.md 2282ac0ca6c06006d36616295dbbb78bb593b93e06712baf8be6b6466426c540
1117
+ .claude/skills/model-orchestration/SKILL.md 7a60184798f2c7ab28d81af37bf61d4785b0831836f0be1e933d279c1b552161
1118
+ .claude/skills/model-orchestration/SKILL.md 2210704bbb4ae972e74f1062512accd53882a405fb91adb0461ad9a2325774a6
1119
+ .claude/skills/model-orchestration/SKILL.md a4447594e45e598028c5f614cc46d1555c6cbf20e0edce1c9d8a30ca17798268
1120
+ .claude/skills/model-orchestration/SKILL.md d8d1982fbc76d572b2f6a3ffd07cba944d3e734987fc5bc66002de5f86accd3b
1121
+ .claude/skills/model-orchestration/SKILL.md a67b5948e8072a87669621feda866198ffadd7c76979fdc3a0b1d8cf2a4ac8bd
1122
+ .claude/skills/model-orchestration/SKILL.md 34add0d50a3ed2687b4ac092a4146928b841f5f6a8bbbfd09a42e2b59f4ef2cf
1123
+ .claude/skills/model-orchestration/SKILL.md 6320632e46180275ee36a9e0897fd616ceb1b8ce7ffdf0647c871b293ae5c846
1124
+ .claude/skills/model-orchestration/SKILL.md a22190744eccc76d1f2d8995a1d66395e4ee173935b2114a334eff95239c234b
1125
+ .claude/skills/model-orchestration/SKILL.md 19d64858ca267987eb9be129a588b7e76ed86b7f788accf019e3f2c2db493117
1126
+ .claude/skills/model-orchestration/SKILL.md 65f0e657979e6b6c0fdacdd5b2cc73f73bb0cdb866c7c8ae1f099c54747c46fc
1127
+ .claude/skills/model-orchestration/SKILL.md 78cb2ac0f153afc4deb3ccc88b40abc7bab1f2b9ab8138d2fd3998082f380178
1128
+ .claude/skills/multi-model-debate/SKILL.md b6e4e4855ca36bcc2a720d926be68008259e0604c8c9dcc8b00cdd65c2bc48ec
1129
+ .claude/skills/multi-model-debate/agents/openai.yaml 64eb836095ff28669ebfd41d133a63e29faec0542dfc90862e10ed7fd275071e
1130
+ .claude/skills/multi-model-debate/references/adapters.md 06d54103576b4de93b9856c26f773842cfbb81b9491fe95c55354bd324fe4c51
1131
+ .claude/skills/multi-model-debate/references/evaluation.md 34f14eeecf6912c8afe5eefa1431744351b7911525d0f6eb612120d31170b290
1132
+ .claude/skills/multi-model-debate/references/prompts.md 45b348552563a499e221edd6fd75fb1d8e77b389aa25a9cc56688547e68434dc
1133
+ .claude/skills/multi-model-debate/references/research.md d99201f4774c7b3648e5bb3953c2e2979af752c1ccd8fe5013c8b6bea155e949
1134
+ .claude/skills/multi-persona-review/SKILL.md 8fa6a0d476b50e1c6b14fc62c31b03c8ea983711d24cc21351589ebc8f1dcd57
1135
+ .claude/skills/multi-persona-review/SKILL.md f0ac01160ebf176617cbe9d606a2b258eef8741c05b4a972f813ac90dd6e9dba
1136
+ .claude/skills/multi-persona-review/SKILL.md 4f221fec547e838d4698c4e2eaf82d6ebabbc52004be8933131e84add66fb397
1137
+ .claude/skills/multi-persona-review/SKILL.md 5339755ba6c7d61b82a1e06f1dde8ef46f5ee263092a7cc5cc6d300ae9bc79b0
1138
+ .claude/skills/multi-persona-review/SKILL.md b23879e303b7d0c95d30a9369f20b1928f93c24114b891a29f8bb17816cfac20
1139
+ .claude/skills/multi-persona-review/SKILL.md 29b1022bf403005764c95670b6d29ea3695ca935261afbf248c452058b2e2d56
1140
+ .claude/skills/multi-persona-review/SKILL.md 17f9f1a0c224168fb4c773f87f8ad84a4d7db9082088e096262aa71e1916f0f6
1141
+ .claude/skills/multi-persona-review/SKILL.md 6da7f5ccfae30d3d7e4ee77f90a06d7de30a532b590482a01d779addd912864e
1142
+ .claude/skills/multi-persona-review/references/reviewer-design.md 327b70bdedff29868b6b3b88d2279db572a811eb19defe8ec0c724e3a007cb45
1143
+ .claude/skills/multi-persona-review/references/reviewer-design.md 4afc9d327f91139b4d272a54e1b1992766b7e0482b4479c76ca9b5284e28d7c8
1144
+ .claude/skills/multi-persona-review/references/worked-example.md 95b48adac8ae5a91cb60fb9d5c32c90365734225775f0f85f26fb72404345943
1145
+ .claude/skills/natural-korean/SKILL.md 0057cef32a4accff3efa155a4916ac65fc283ee766abb2951227da91fa8bdee0
1146
+ .claude/skills/nextjs-turbopack/SKILL.md f65da15aabeb9dca7ae08525739e72ab16e79a78ff4004f7cab6ad2de1c2a79b
1147
+ .claude/skills/north-star/NORTH_STAR.template.md f778da89c561cf92b987bc1d46e5eb8c979f2422882714b0a0602ccce62a7b5d
1148
+ .claude/skills/north-star/NORTH_STAR.template.md 401ac922beb41b5b3c6d19313d5a46184cc90808aa330e0e288108355b5f8aff
1149
+ .claude/skills/north-star/NORTH_STAR.template.md 23a071af1893e3be7860111d448d02a55f965519811bdadafdba4231607d66c3
1150
+ .claude/skills/north-star/NORTH_STAR.template.md 741efd7d4c477f95ecd1fca85656d4582a694b3753ece77378ddab8ba0f0b69e
1151
+ .claude/skills/north-star/SKILL.md f73b7ce6a73bb3666ff3c18557ba37248a844107d54ffbaf5bb3d562fc2e7f61
1152
+ .claude/skills/north-star/SKILL.md e335733ad2c6dab82d104f868c5ce3d3de99ee1f139330eba9ff497529bd9485
1153
+ .claude/skills/north-star/SKILL.md 5b1f8176bb264e5a426594704e640eb69605d6482d6ba93f53329e9fe08dadcb
1154
+ .claude/skills/north-star/SKILL.md e37ed854c29f26f64a96ccd4847e71723f5bab9a56d3c8f53a4f9815120085fe
1155
+ .claude/skills/north-star/SKILL.md b11245dfa084bcd8b1fa4f7eb186e7a6ed97b30905a1507992c35448af45cc62
1156
+ .claude/skills/north-star/SKILL.md fa4427fb57243aed96d639362d97c69202170dfa949bfb0818f4600b1cd8432f
1157
+ .claude/skills/north-star/SKILL.md 0616424076bb18c4388d9e48ac4e4bacb51106b0b8bdcf6be223e413e0c43bf9
1158
+ .claude/skills/north-star/references/roadmap-method.md 78b6d7e05e014c5c7ecd5680767ed2469c6a147faf053b09f448f63cebda9da7
1159
+ .claude/skills/north-star/references/roadmap-method.md fd58a20159eb0b14b69781ea2536be1fdebd78c9eb83658c2b76de78efd21bab
1160
+ .claude/skills/north-star/references/roadmap-method.md 32e812eac7356e15704d0eff162f3fe3d93f1de880c7107017c1d802463190b6
1161
+ .claude/skills/northstar-roadmap/SKILL.md 489e7a70f81d80c296dd9160debe7ef69381506f9ac00874cfb48e2b61e58736
1162
+ .claude/skills/northstar-roadmap/SKILL.md 9a632a49e6bbf877fee61d448046444d57127b75b4f76f9b8ddf8946c8b7990b
1163
+ .claude/skills/objective-brief/SKILL.md 4df0bbd72dd7ea698d7d9d3b10476c4c4ff3e6bc3d9a1d29531e083c9e9bf59a
1164
+ .claude/skills/objective-brief/SKILL.md 51fa706442849b5f74e71c23fab8952526dd3a60ab1d78a3fe53d2631f24e47d
1165
+ .claude/skills/objective-brief/SKILL.md 531c8f0f09492e4a1643a5de38dbc293be9981a5c81ebc7f783620d5380a5806
1166
+ .claude/skills/python-patterns/SKILL.md df0c0abbbd0e6a01811d1b1d10d8fa7a8a19ce73afdc9432d24843f62649cdd2
1167
+ .claude/skills/python-testing/SKILL.md b304a8c503af32644f97a889c5545ee4f90e91980462ad4ce33fee3dea6f414f
1168
+ .claude/skills/recurrence-prevention/SKILL.md ab537b5f35be053ffa930f99c5b3d972b80fd621d18eda8390506d01503f6d78
1169
+ .claude/skills/recurrence-prevention/SKILL.md 905324644b719f2cfc2744be0bb21922c9e4e6534a83c6b8cad980d6327b92be
1170
+ .claude/skills/recurrence-prevention/SKILL.md 40b8e5a14136cecf12a63cc2f709de2d80290e352aee88aa9a482200a3fd7295
1171
+ .claude/skills/recurrence-prevention/SKILL.md 8a26b9d530305497fe11b39e31eb7806d835953c2585fc15fcf51488d7fe6279
1172
+ .claude/skills/recurrence-prevention/SKILL.md 62fe94e2cd34d9c3c40871766619d5c37c957e89247c5d281e62c85de51326de
1173
+ .claude/skills/recurrence-prevention/SKILL.md a626f5760ffb7446695a578104baef9ba9259b3b41115b00d699c43d260c0295
1174
+ .claude/skills/recurrence-prevention/SKILL.md 9e44542d54006e02ae1d906346a90c0ad0e26c1797496e791c83f7bb0e867cc6
1175
+ .claude/skills/recurrence-prevention/SKILL.md c7c163aceb457535adb3c3052fe41355048716db2cbb0b4cc768ca6fd4533f26
1176
+ .claude/skills/recurrence-prevention/SKILL.md 46614922e61e79235493c80664da2f9e7d95d034c58c9a646b948a7c2a1f70b2
1177
+ .claude/skills/recurrence-prevention/references/failure-analysis.md 1dd840db9a2bc662ec9688833988d93e80d0be245e7edd727c2d065a9d7d9eca
1178
+ .claude/skills/recurrence-prevention/references/failure-analysis.md 5fc80d28b3f52e92843e9ef431a9dab74d8b43cb3cfd7ed5d2aa359ad00586bc
1179
+ .claude/skills/self-hosted-github-runner/SKILL.md 4e5b86b9c7c8527599cfd8be61f4ed3ab67d439bb791f4068d85e52c9327e5df
1180
+ .claude/skills/self-hosted-github-runner/SKILL.md a1394fde762c88fddc88db1502b15aabe88bdfc1c565e77bd3cdbb0512352d10
1181
+ .claude/skills/spec-scaling/SKILL.md fd28afb5558e2ba4168b0b16bc19b1c4d2fb732741649010a1601f751f9eafc5
1182
+ .claude/skills/spec-scaling/SKILL.md 93fe3ed443754bd368a45e71145434c1fd7efd349e25b0179bbb63774ac4ca0e
1183
+ .claude/skills/strategic-compact/SKILL.md c8e861a39fb84968aefa82783c1b25e61d1b625c29c0f5b2bb301f4652c93e9d
1184
+ .claude/skills/strategic-compact/SKILL.md 6bfc63c380eb89886335ad033f759a4ff3f1b1ae2c5a143598bb628e38c6e769
1185
+ .claude/skills/strategic-compact/suggest-compact.sh 62af1630b000713842e363447675ad5a94f72cddf47241df68fc9883de686689
1186
+ .claude/skills/task-brief/SKILL.md 69125822c0c7da8daa6e67117f0845e3388284b0d4b7cc2b69f440c9b865b454
1187
+ .claude/skills/task-brief/SKILL.md 0859fc0b6cf760edb83b4c41cb8156cc90b7c62f1d5b5dd364acd4c5f7935cc2
1188
+ .claude/skills/ui-visual-review/SKILL.md 4016297b69844f05a51c4669e62083b8d27a734f0daa24b3a03039979d6a28c7
1189
+ .claude/skills/ui-visual-review/SKILL.md 4c92c01e4d437150fe115406044d2ea9b8c942c2026f9e0d8d446667c4db7912
1190
+ .claude/skills/ui-visual-review/SKILL.md e9689dadb419979e2b62a3f1c84069f90b91ae95dd0a061dc759b3a60598aa32
1191
+ .claude/skills/ui-visual-review/SKILL.md 39371f46b46b7d8f51da0b9a28ca710156de634b6e066217e9618b1ecbe3f5ee
1192
+ .claude/skills/ui-visual-review/SKILL.md 2e23c9ba4e40a13db152ee750a33cadb6e32169daf51417c9a0a97b0ed021e45
1193
+ .claude/skills/ui-visual-review/SKILL.md 8d5c23460b4ba78c9b8077d9e6de59af5a38ea3035ca65f5cf645140ba523741
1194
+ .claude/skills/ultracode-service-audit/SKILL.md bdb3d151ca74e6129e547339b17192ba415701b46d889e0a1bf9f7fd0195663c
1195
+ .claude/skills/ultracode-service-audit/SKILL.md c7ca76cbda2f8d6b5750b68f524c92927ea375fb47a910ed02332e3a6fa1bca0
1196
+ .claude/skills/user-centered-explanation/SKILL.md eab47a91badce5d6314f63889950c69c43fa5ea4660d544828794ada3684e0b8
1197
+ .claude/skills/verification-loop/SKILL.md 01a9ae310ad4426bb05660dda6cefdeaac9513417585c09c8bb1b94738649a78
1198
+ .claude/skills/verification-loop/SKILL.md 41f481c1146b0b29ecbcf5c633090a6db3749ca4a814499d72b5b8941db694f5
1199
+ .claude/skills/verification-loop/SKILL.md 566fc81da559464d70af80a125dac60991ba5e26464643886c1dee04dd78db95
1200
+ .claude/skills/verification-loop/SKILL.md 1744f867f7868b83b480341c2e8d08bff3848c2408255871d3aba0c2f7eff2f2
1201
+ .claude/skills/verification-loop/agents/openai.yaml 1907fd04fea5c83d15faf14acfc978de90076d4351341cf9259639aa0c3b7bd3
1202
+ .claude/skills/verification-loop/references/tracks.md de11792d447c2e8ea67e8367c6655bd94646b1ba3f29184c4521cae01facc6ec
1203
+ `;
1204
+ var LEGACY_HARNESS_FILES = (() => {
1205
+ const m = /* @__PURE__ */ new Map();
1206
+ for (const [path = "", sha256 = ""] of rows(FILES)) {
1207
+ const s = m.get(path) ?? /* @__PURE__ */ new Set();
1208
+ s.add(sha256);
1209
+ m.set(path, s);
1210
+ }
1211
+ return m;
1212
+ })();
1213
+ function isLegacyHarnessFile(path, sha256) {
1214
+ const key = path.startsWith(".agents/skills/") ? `.claude/skills/${path.slice(".agents/skills/".length)}` : path;
1215
+ return LEGACY_HARNESS_FILES.get(key)?.has(sha256) === true;
1216
+ }
1217
+ var LEGACY_AGENTS_MD_SECTION_KEYS = keySet(`
1218
+ 241678cd4951efaf8ee7bb0059e739c397af6b90b75fea636361501b7ae1cbe7 ## Workflow Gates (26.70.0)
1219
+ 1e19e112dc2c9c85f31d7b8c1b65b5e35e8563db7f31115ba03af8c6ef1d5ea6 ## Command Reference (Antigravity workflows) (26.70.0)
1220
+ fe66384910daab3a0275c7c98d9a944f5f771d58ec2a9addcaf5f16a8d001ef9 ## Protected Files (DO NOT EDIT) (26.70.0)
1221
+ f7fbcaa082ffb260b11f48813a8f97f243663082aadb37e2137d2a99a143f65f ## Scopes (26.70.0)
1222
+ 62225c82dd65fc0c01dba1fd6dbe8e9accb8d46d0f580f4d2a281dead3346997 ## Workflow Gates (26.70.0)
1223
+ 0d509a214b74e5b3966722390279fe84fa20c8337fa7c9853c31fef0b42bf85f ## Session Start (26.70.0)
1224
+ fd29a37cc8231393739123a79728b31c0c4acde371ce502709550ed43837a2d4 ## Protected Files (DO NOT EDIT) (26.70.0)
1225
+ 9c4a901cbad93ba04a5d511952e2e47213130c92ae2122e5f5649a17328d8915 ## Git Policy (26.70.0)
1226
+ c24a96fd321a9286debd618c9d95684c344c061d6a8e0558dce1595aa84e3a9f ## Command Reference (Codex slash) (26.70.0)
1227
+ 23c25f2516a46dec187877d5d85f2e92257752193e287978650b3b112df083dd ## Agents (subagent, multi_agent stable) (26.70.0)
1228
+ dc230c795b307261ea4ee23126e6a209cc73ed474c97857d59e03a134232c4ec ## Hooks \uD604\uD669 (Codex 0.124.0 \uC2E4\uCE21 \uC81C\uC57D) (26.70.0)
1229
+ 462ce33464e58a8ebd95ea5ed0f4cce167153fb2805ea6ba609734174a9027a2 ## Experience Accumulation (26.70.0)
1230
+ dc5629ad55f9800e4898a698650c8dbef5578505e7d5891745f0065f01d650a3 ## Context Management (26.70.0)
1231
+ c7d793aa3bf374b8bd390baf25bfc2c23c2d050377f673e72e53fe14f821c1f4 ## Workflow Gates (26.70.0)
1232
+ cf4cf430b633cb68b4128b03797999ed325f76ed92132fb8adcb60cccbc4e0c2 ## Session Start (26.70.0)
1233
+ ef2c745821688a463d4435affaaa6baf404feaec69f081c68a794d847f72a9e7 ## Protected Files (DO NOT EDIT) (26.70.0)
1234
+ f328397dafd8eaff1eeff91dcda315db3da289e646eca49a6b977725867cea3d ## Command Reference (OpenCode slash) (26.70.0)
1235
+ e1dd38e41e5df06efea65b349376a1ea668ce74a408efaf5c1ce91f08063a666 ## Agents (subagent) (26.70.0)
1236
+ 1ca6e8025be0d099df42fce9248673722fe327be2a77a0d9971bacc18a99a10e ## Hooks (Plugin lifecycle) (26.70.0)
1237
+ ad834e2800b86a486d50efb9526657898a03919ee1b3fbf0cb0aaa89c9a6c095 ## Experience Accumulation (26.70.0)
1238
+ 2cade5a88d6241fa7a50289fe0336b64cccd08d2c81b65e2df72acbdbc436a62 ## Context Management (26.70.0)
1239
+ b2532f7ae8302ee8aa5e0316f7bd9755abe06abeaa9639f7a9a062fc7d89b47f ## Scopes (26.89.0)
1240
+ c144f72dc32d524ae00b6026322439a5a3f2083d4e1781b927f374fe2b20d7c8 ## Session Start (26.89.0)
1241
+ 0c719706bef388d3ac81a62431659bf817b0d4384846a0068d5768c8b3965e36 ## Protected Files (DO NOT EDIT) (26.89.0)
1242
+ 6502c5abcf4cb9148c6dc5227401f7046b7dc8ab97ff7c292824de568b603942 ## Experience Accumulation (26.89.0)
1243
+ 37106505641d9de7ae9e3ac5cc86efc3221abe5c969323325acc11e9b7d7cd04 ## Experience Accumulation (26.115.0)
1244
+ 25baf8cc482b473d7f61e13ff95232484f95cc22063bb2ce9587f43ad242d5dc ## Scopes (26.141.0)
1245
+ d48603cb329fce58fd7ca9eb3b01dde3b223bdbfe79ee583627fbc15e22ba703 ## Session Start (26.141.0)
1246
+ 29cb109e9a2cb4e3037a470d25d7dce4928d0e690c2c7c478d452f2133b65cd5 ## Git Policy (26.141.0)
1247
+ d1affcbe314d8ccd39ca956d467fbd43bcc859b4ffc23bf1d1f8f2f0a3e10f4e ## Context Management (26.141.0)
1248
+ 9203c6d359a7ffc5a968be0645e1b827d6b4940312c27edb1c5fad6a68c9ca7e ## Session Start (26.141.0)
1249
+ 39fdaaed39e0a39c537ebc3dcf5d349fb867740b126822eaa9333833d0de68eb ## Context Management (26.141.0)
1250
+ 6f4bae4fb31bc54074d1fed021f4fd6dc3939844ac701eac8427904404b6daf3 ## Context Management (26.147.0)
1251
+ 0569e0fb18d55a474fc8239dd60bb5684d22245c1ffa6f198cf6af468b5a3794 ## Protected Files (26.151.0)
1252
+ 624b8878a9a17a5d4046b180297c53b27270ea75ed7d892d527939a7580adb19 ## Session Start (26.151.0)
1253
+ 0f6658376e8bba3c31ffca010f24e9acee9f32953c00a41183dca9eaaa4f7913 ## Protected Files (26.151.0)
1254
+ 55412b2ae275e9660f09c7cc286d3e92236e4ae61626cbf68727ae222edcb0e0 ## Protected Files (26.151.0)
1255
+ `);
1256
+ var LEGACY_AGENTS_MD_NAMED_KEYS = keySet(`
1257
+ 92dce1a73d484490c943ec3418f10b2370079ae42aa8d93159596f45d12e699a ## Project Rules (26.70.0)
1258
+ f59bdc7177a12aa86f235ada16b2407c40bd55ae9de8e96a851b77571bdde989 ## Command Reference (Antigravity workflows) (26.70.0)
1259
+ c7f9fa755bd66d80c2df496c6c759e8accd736cd8fef64460feb7ae9cd4c8006 ## Context Management (26.70.0)
1260
+ dc030a35a6e638aba5447b4d4e79ae028fafd1419fbae872b902661fa7787a58 ## Command Reference (Codex slash) (26.70.0)
1261
+ df73823c02e6eee000388444964acfec233ffeec0e20fdc5d31eb018d2ca93c1 ## Context Management (26.77.0)
1262
+ 6c900db77cb104f400091b44a7414e96427003860306a3007651b7a8b91a547c ## Project Rules (26.140.0)
1263
+ d9e3680462e64506ba4ef2df4f12e666855c3f458c1feeeeb623d62de2a5fa17 ## Project Rules (26.145.0)
1264
+ 2da8ca3600045d85a9607ce270f9bc2d77b5ee54fe80cd0765caf7658f51127c ## Harness Rules (26.147.0)
1265
+ bbe5e1d9d368b15221269319b53dde4f87424904b80cd5af46a28de3d8ac923d ## Harness Rules (26.147.0)
1266
+ 41eae7d6a8bb327e71cea2dbaa331d808f879b5ff4074c0bbdbb90bcfe066d9f ## Change Boundaries (rule 26.147.0)
1267
+ bef15b624ea34d08dc5833ceacd710f3c687385050958e5cd103378cf2fcf457 ## Change Boundaries (rule 26.147.0)
1268
+ 9648c5a118c77a23a1a04ddcacd7708be162d65587769d47f51d2405b74c2f72 ## Shell Safety (rule 26.147.0)
1269
+ c2dee88e05c98e1482c99c1c01f59cafc6c6816fda1269d68179707f4ede0b8f ## Shell Safety (rule 26.147.0)
1270
+ a6c3b31f60c80906e8bdb7a5ba699a4c1062b2e2f3e94f9f56b5064f74a722ef ## Documentation Boundaries (rule 26.147.0)
1271
+ b8fbe3bb2d5d790015ddbcff85c68922a122d91705e1cc946a14b30480bfb22b ## Documentation Boundaries (rule 26.147.0)
1272
+ 0a0b44e4c8d10aca52f63a4dba40d9166ea067eb1599886f850dc37ec2bba2f2 ## Git Safety (rule 26.147.0)
1273
+ 05efdb03d3e9d9fbcfd652ddf778d25bb1ab5ce237dd33f17b0be82cad08db5b ## Session Cleanup (rule 26.147.0)
1274
+ 10bdfa993f15639a319e852cf59f7b279b7397d26a94c54e6ca6a94416cc6834 ## Enforcement (rule 26.147.0)
1275
+ b72afd685f3c63e481dc856890c8a9d89c4e36ca3163ab172661e9fd5c3658a5 ## Enforcement (rule 26.147.0)
1276
+ 126a9a57aa42007c9c0bd3cb7f0ce75f2ad6a7497b464e7f6c7f45f3ae5f40d2 ## Delivery (rule 26.147.0)
1277
+ edfa8459a9863e355a080c759419f6f5ffb0ebd5fc418914fd38d79622e73131 ## Delivery (rule 26.147.0)
1278
+ 55295cda2a572e0aab061449248123d9d43543b3045b1b156b95fe2fb6aae509 ## Testing (rule 26.147.0)
1279
+ 6364a5d8727d33db914c7d7a1ac4108cff9ed1dbefffb212bd84c1fcd7584284 ## Testing (rule 26.147.0)
1280
+ 8d407c73c2de630d77d605447f605a6a2511fc4598d500ac7a1ff1374e2e457d ## Delivery (rule 26.148.0)
1281
+ 2c3f8e7c8408f103006e4ef8029dce4da1995bca01bd1e6baf7ca3f4e46e58fa ## Delivery (rule 26.148.0)
1282
+ ae930fa7c8fa6f942d20715a51de43f33461aa5589f469f13a31ab90da1904e7 ## Delivery (rule 26.149.0)
1283
+ 5b97fa550beb24e86c04af7fba2c97d8ff51702fd25abf223d97350db2a19ff1 ## Delivery (rule 26.149.0)
1284
+ e9b5814787b1e1cc066c217da0e344604477edfc0eb17304a5aeca73b0846637 ## Testing (rule 26.149.0)
1285
+ bafced984a2acf13f6fc7a3ca7c79edb99b5cecd4b21e351bd093f260d32fb02 ## Testing (rule 26.149.0)
1286
+ 4972faf000e3433c0c07f7bb36e6b0463453be308dea31cfc177d692e23e3700 ## Project Rules (26.151.0)
1287
+ 381a1d00394f803118575ecde42946585466c2da2ec36239fd6208a3c1b6bab8 ## Change Boundaries (rule 26.151.0)
1288
+ 1a9dda0c66c7d82bdeb29c169f749a44c03b9bc112b3a1146898826b7d77b04e ## Change Boundaries (rule 26.151.0)
1289
+ e0d9ecb6916b563cfd0eaaf3f977106826136c4aaef518e705508c60f17b3cac ## Shell Safety (rule 26.151.0)
1290
+ 053642f8951a2da28bca7d8d985a01c8fc2a6a91223a8cdfcd5e7ba5ef78af62 ## Shell Safety (rule 26.151.0)
1291
+ 6543ff93b6c1f27f6d76f2a2a7599fd7ed0d1004f5419d5082321d1f4729bd1e ## Documentation Boundaries (rule 26.151.0)
1292
+ 1741bf4e931d799c850ae45944ac2a9985800240d011a670ddb9400013b14856 ## Documentation Boundaries (rule 26.151.0)
1293
+ e527b3630786a074e321e1375b44f0870df3f7d4f124d5fdca9bbbd7e66f9315 ## Session Cleanup (rule 26.151.0)
1294
+ 8ec2a06cfe3fa51e8187b218c290cf9ddc7680eac85427e2f6cf2a4a1a03ed4c ## Delivery (rule 26.151.0)
1295
+ d7fad0202a32aedb45717177ef9d3647109a0e77ee13f37b4c4a42f892182d4c ## Delivery (rule 26.151.0)
1296
+ 2332b78bb1eb206ba1b08e28b3114d4919fb1384a9a5378f55dead61fdc3105a ## Testing (rule 26.151.0)
1297
+ d172feb48f54338d5d81e8b390debe3537538f0d2214f51e590272547e113cd2 ## Testing (rule 26.151.0)
1298
+ 99bdd67b5ae37c10588f4ff852525ebe2ab59368723f56bd317818a89161c59a ## Change Boundaries (rule 26.152.0)
1299
+ a07c989310055284328b4ca441e201740fc8158a38572e56ec9968dac44ced13 ## Change Boundaries (rule 26.152.0)
1300
+ e4d2c89e6c2189748bef2dccf8eb506b7f8cf264d5bf8626fbe4446c330e0b63 ## Shell Safety (rule 26.152.0)
1301
+ 028c8514fa466e7f053088e37968ef07ce1bcb08d4c224e76ec807d0f01e4449 ## Shell Safety (rule 26.152.0)
1302
+ 9f0ac9e1c32c486e4f318061e3be3c853217d03b3f837b6c6e425f016c8707e9 ## Documentation Boundaries (rule 26.152.0)
1303
+ 992ca24bd1f15314fb53943af2856af73f0d31ad8c6cf98b25b840ebd017b86a ## Documentation Boundaries (rule 26.152.0)
1304
+ 49ec458da7c57727c16ec8ffa01cb2e2631eb769f6041b3bc07d912ec1a2994b ## Project Rules (26.153.0)
1305
+ 155abf346fea6c63a081d4db1a1e44d537c4a94a479a2affc96345b18928fde3 ## Testing (rule 26.157.0)
1306
+ 675da728d15da072c17fe5e9ba3ca8b21811e99a09f390fed4a53f19dd12c555 ## Testing (rule 26.157.0)
1307
+ `);
1308
+ var LEGACY_AGENTS_MD_PREAMBLE_KEYS = keySet(`
1309
+ 720645dd313be16e6204290bfe0451fb237f77b8a7498a8a8af77dfc44ac0828 > **Generated from**: '.claude/CLAUDE.md' via TS CLI 'src/antigravity/transform.ts' (26.70.0)
1310
+ f95170e7780965de8562db0b5c7846d8e75ac7902a4fab695373c691333c7ff4 > **Generated from**: '.claude/CLAUDE.md' via 'scripts/claude-to-codex.sh' (Phase C) (26.70.0)
1311
+ fe621e2687dd489f3e9fb6ca1b97d480a83af435d99117315c24534d9c4bc169 > **Generated from**: '.claude/CLAUDE.md' via TS CLI 'src/opencode/transform.ts' (Phase C) (26.70.0)
1312
+ 0d05490eb1360e2601d7e63b79c901a10da1dcfd6c9437151e4fb1ce00416bfc > **Generated from**: 'templates/CLAUDE.md' (4-CLI \uB2E8\uC77C \uC6D0\uBCF8) via TS CLI 'src/antigravity/transform.ts' (26.141.0)
1313
+ 1979722e483fba4441ffd4818134b3942cc97f21e39689316d6143e4732c98a7 > **Generated from**: 'templates/CLAUDE.md' (4-CLI \uB2E8\uC77C \uC6D0\uBCF8) via 'scripts/claude-to-codex.sh' (Phase C) (26.141.0)
1314
+ 230413c8211b1a9c3b204e315ff63f6ac3a7d7e5d01c8dd3d4ed294bf3c49f5c > **Generated from**: 'templates/CLAUDE.md' (4-CLI \uB2E8\uC77C \uC6D0\uBCF8) via TS CLI 'src/opencode/transform.ts' (Phase C) (26.141.0)
1315
+ `);
1316
+ var RETIRED_ANCHOR_SECTION_KEYS = keySet(`
1317
+ 522bac15bc17949697e291b837c0d9624f5e0c7666400a3baf94cdef7cfab8b5 ## Rule 1 \u2014 Think Before Coding (26.70.0)
1318
+ ea10b7cd9b84a71949a071fae15256f490b3fe407159d7bddcf3f882310fa835 ## Rule 2 \u2014 Simplicity First (26.70.0)
1319
+ c486465d9554f2de1711cd056437f6a95a5d3243264b82d29a6957f24b5a6de3 ## Rule 3 \u2014 Surgical Changes (26.70.0)
1320
+ 3d080574cc7ae81eda75c4aa019445b38b6f69c5f9eeeda9097e10b6041e7e94 ## Rule 4 \u2014 Goal-Driven Execution (26.70.0)
1321
+ 11e43547f6b1613a5dabb3edaf5131d696a3fd375b3c22558f03555a0f5cf2ef ## Rule 5 \u2014 Use the model only for judgment calls (26.70.0)
1322
+ 60d91718de6ae16ec86b50e7c9a939a6ca5fc0721422b592700cc9972f55aca2 ## Rule 6 \u2014 Token budgets are not advisory (26.70.0)
1323
+ 9d482c7307cbcb02acc6fb35cd57b24baa9fce04528e2bd21e1e877603f8b85b ## Rule 7 \u2014 Surface conflicts, don't average them (26.70.0)
1324
+ abca09f13833ce18bd0ffc0793d59780c35447ca79c2a512afcbc9d7a7116ed8 ## Rule 8 \u2014 Read before you write (26.70.0)
1325
+ 5b4eae6c3dc2d92cfb1772889650882a4a2115f08a36602da9a1d96697059b91 ## Rule 9 \u2014 Tests verify intent, not just behavior (26.70.0)
1326
+ 632670b8897dc373d4a12f611c2436d9a8e86d8cdab917eecabc4bf2a56f8030 ## Rule 10 \u2014 Checkpoint after every significant step (26.70.0)
1327
+ 252e99f25b05a47e5ce884ac9f1e1d34156116b9a76331e2510b1354a6c98cd4 ## Rule 11 \u2014 Match the codebase's conventions, even if you disagree (26.70.0)
1328
+ c28a12b589b6576379793c51fd01dbfaf91d391ac773f84ae0477ddb60a1e3e8 ## Rule 12 \u2014 Fail loud (26.70.0)
1329
+ 72feaf96f998989351f8083edb891c7b0c3bccca65dbea2732fb2864b8f98bd4 ## \uC758\uC0AC\uACB0\uC815 \uBC0F \uCEE8\uD38C \uC694\uCCAD \uC2DC (26.70.0)
1330
+ 95c932ecb4f4fdcdd8d483f9d02166b906f6eb045ef33ee474a16913d0c3e6cd ## Phase/\uC791\uC5C5 \uC644\uB8CC \uC2DC Self-Audit \uC2E4\uD589: (26.70.0)
1331
+ c7f9fa755bd66d80c2df496c6c759e8accd736cd8fef64460feb7ae9cd4c8006 ## Context Management (26.70.0)
1332
+ 6ec0b415a8f86c9940bccd3e6db895ea4a110185e76fef223a348f9553fd897c ## Rule 12 \u2014 Fail loud (26.77.0)
1333
+ a78f0ffa6b51c9b45c964ecb92db951534336f7e558a3d39d11f015ee6c3466c ## Anti-Patterns (Forbidden) (26.77.0)
1334
+ 50d00a511e87571d7ff85f6584b87b9f5c2eef06122d8ac5fdccf3f047643f12 ## When Requesting Decisions or Confirmation (26.77.0)
1335
+ 574519e07f48bcc04f0e3d505c0f9c157ddd426b5eda2baa99656cd4712dad2b ## Run Self-Audit on Phase/Task Completion (26.77.0)
1336
+ df73823c02e6eee000388444964acfec233ffeec0e20fdc5d31eb018d2ca93c1 ## Context Management (26.77.0)
1337
+ 8f49f0a592575a65eadd3e33950c96616223aa8bb116707103affeef71db28c6 ## Delegate the Building, Keep the Deciding (26.139.0)
1338
+ 6115eccc3b2702f436a9db7d6af9803fa7b1fbf7b9ff1110ea658fadd67ec5ea ## 1. Think before coding (26.140.0)
1339
+ 15b120395ec8e757ecbe3e65775371a9120953617fb37eb062e0c176b52f045a ## 2. Prefer the simplest sufficient solution (26.140.0)
1340
+ cc466b4781444ca54aedebd20ba3aa531c3aa84cc438953df84b133bd32a0e1e ## 3. Make surgical changes and preserve existing work (26.140.0)
1341
+ f6d1f6f02cb3c19e61becf329f20335c54e684bccb06b33e4b7f66eb49f9c6b6 ## 4. Define success before editing (26.140.0)
1342
+ 372bf30b282b861c6a89e355c94ffd239bb0202e2ef928f8af99d640579710f0 ## 5. Report evidence, not confidence (26.140.0)
1343
+ 66ca0e3aae98d24c65afbc418645df29d8c570be81918c42192eb1beecd21f23 ## 6. Do not cross high-impact boundaries alone (26.140.0)
1344
+ 9c6c27eb57a9790273fa3fdf0df3628d927b025f870f09933692d1b522d73a25 ## Decisions and explanations (26.140.0)
1345
+ 922d100c2dc6ef8a53989a920c3554afa7efd148255bc144412403c0289439e6 ## Decisions and explanations (26.141.0)
1346
+ 330a67775a28557431aebf36a44018fc5194a4b929bf2cf95184b1f0828a6360 ## 1. Understand First (26.145.0)
1347
+ 3b2f0147dc7bd0f01fd12485790199ef4ee96a6b723e244ffbf3dc96933a1ab8 ## 2. Define Success and Keep It Simple (26.145.0)
1348
+ 8802fb25c05879c98dbf8407001d239c410d25b4fa2521b11d9d7cc108f73b29 ## 3. Preserve Sound Boundaries (26.145.0)
1349
+ 1d0d9bf05d8870dd0dc62e388ceffc98923f1dd2074ef8038f80a50c9b5b9a81 ## 4. Make Surgical Changes (26.145.0)
1350
+ 05e08e2318061141464ae714d6770d35527576affa787740d9c6d9345d3462dd ## 5. Verify and Review (26.145.0)
1351
+ 7b39f1f92a72517d6ae52599becfef29f675e48185a3483dc993d7accd4aee7c ## 6. Protect High-Impact Boundaries (26.145.0)
1352
+ d5d93c55de33e4cdcb38f76c6d6d70a6e0beac7a176c8aa1daa09905ccc5fe39 ## 7. Report Evidence (26.145.0)
1353
+ cefc8bb6194d4f1b6302345e96ffb3a28b8b992032fd40f9f5b4f18997657e7a ## Presenting a decision (26.145.0)
1354
+ 7385ff5df34148278a8f4b164c11ba5f9355626abcc13a822dd1ebb206321c2f ## Skills that apply continuously (26.145.0)
1355
+ ad9fd1ff225c57c9801a7d7472bf4ddf9c952c602f4a93eae86fbcb3bcf468bc ## 7. Report Evidence (26.146.0)
1356
+ 868fe823fc40011d08816c9f1105ef6df7ca7f2479779303ce9583bba1ce6e0d ## Skills that apply continuously (26.146.0)
1357
+ 3f8259ca7c92d79cca1a36bba38f36d4ef5a96fd6cafbd0edb5a79492082f46f ## Presenting a decision (26.147.0)
1358
+ ecfdcd50e97723af77cfe6889bbad784cdeb86dd0c52af3ff98ddf6adf80f445 ## 1. Resolve what matters, then act (26.151.0)
1359
+ 9321cb1312a080bcf560940b8f86d3d59b39c667add4b8f3ad785ddae9bc8b20 ## 2. Choose the simplest sufficient solution (26.151.0)
1360
+ a4c345996a8578cc24b62fde27084e5848a61e4a40d91b0c72a95da46203b43c ## 3. Keep changes focused and preserve existing work (26.151.0)
1361
+ 1adbf1bf88bb8288744e1c1d73518ffdec12a5b668d5a225e2bedd006844466c ## 4. Define success and verify proportionally (26.151.0)
1362
+ 7636e57a877d54039f0c2829fde84202c65378bd36b8c8abb7274a29eaa5f8ac ## 5. Report evidence and stop unproductive loops (26.151.0)
1363
+ ddf2be9e04c04bf53ad9b5476e45639b33a60bf49bd3a83835796632052b17b4 ## 6. Keep authority explicit (26.151.0)
1364
+ 16b0edc0f4886a9f9ec94e6fb97206c385286b2c9d5563b2324b7a2f4a434435 ## 1. Understand what success means (26.153.0)
1365
+ b10ab1eafe25bb7ba3b20b907b1d7eedde03e52fbd49905f24e192e30b4e1b9a ## 2. Choose and adapt the approach (26.153.0)
1366
+ 69bcfb8b37ac184b1a30945a0dea59108ef1242c2f40fb778be118cbd524aea7 ## 3. Keep changes focused and coherent (26.153.0)
1367
+ f22a5a13c5ed8460c9370212d91354d0fea2fefc7f420a1eb3088504ae8da6c0 ## 4. Verify outcomes in proportion to consequences (26.153.0)
1368
+ 7a335cde69e8055ee5e137a9a5c09fd7f7c2e551ab099a2cda87f0c3dcd95a19 ## 5. Let evidence determine readiness (26.153.0)
1369
+ 79797568bb71bd0f7b14393f72e61721a4bfe99ecfb6126ffa38a6c03c53d765 ## 6. Act within clear authority (26.153.0)
1370
+ `);
1371
+ var LEGACY_HOOK_COMMANDS = /* @__PURE__ */ new Set([
1372
+ 'bash "$CLAUDE_PROJECT_DIR/.claude/hooks/agentshield-gate.sh"',
1373
+ 'bash "$CLAUDE_PROJECT_DIR/.claude/hooks/gate-check.sh"',
1374
+ 'bash "$CLAUDE_PROJECT_DIR/.claude/hooks/hito-counter.sh"',
1375
+ 'bash "$CLAUDE_PROJECT_DIR/.claude/hooks/mcp-pre-exec.sh"',
1376
+ 'bash "$CLAUDE_PROJECT_DIR/.claude/hooks/protect-files.sh"',
1377
+ 'bash "$CLAUDE_PROJECT_DIR/.claude/hooks/session-start.sh"',
1378
+ 'bash "$CLAUDE_PROJECT_DIR/.claude/hooks/task-brief-nudge.sh"',
1379
+ 'bash "$CLAUDE_PROJECT_DIR/.claude/skills/strategic-compact/suggest-compact.sh"'
1380
+ ]);
1381
+ var LEGACY_STATUSLINE_VALUES = keySet(`
1382
+ f3de524065fd30f26e2d14b31fad0edc4c6689fb95b8ea6c59b1d48c5a90adc5 statusLine (26.70.0)
1383
+ 94442f9703e367a12f6dc16612ad65ae5f0cd0c73b96dd683e584a18ac91eaea statusLine (26.164.0)
1384
+ `);
1385
+
1386
+ // src/hook-ref.ts
805
1387
  function projectAnchoredRef(command, claudeDir) {
806
1388
  const anchors = [
807
1389
  "$CLAUDE_PROJECT_DIR/.claude/",
@@ -820,12 +1402,21 @@ function projectAnchoredRef(command, claudeDir) {
820
1402
  }
821
1403
  return void 0;
822
1404
  }
1405
+ var LEGACY_HOOK_REFS = [...LEGACY_HOOK_COMMANDS].flatMap(
1406
+ (c3) => projectAnchoredRef(c3) ?? []
1407
+ );
1408
+ function isLegacyHookLine(command, claudeDir) {
1409
+ if (typeof command !== "string") return false;
1410
+ const ref = projectAnchoredRef(command, claudeDir);
1411
+ if (ref === void 0) return false;
1412
+ return !LEGACY_HOOK_REFS.includes(ref) || LEGACY_HOOK_COMMANDS.has(command);
1413
+ }
823
1414
  function keepHookRef(hook, claudeDir, removed) {
824
1415
  const relPath = projectAnchoredRef(hook?.command ?? "", claudeDir);
825
1416
  if (relPath === void 0) return true;
826
- const exists = existsSync(join(claudeDir, relPath));
827
- if (!exists && !removed.includes(relPath)) removed.push(relPath);
828
- return exists;
1417
+ const exists2 = existsSync(join(claudeDir, relPath));
1418
+ if (!exists2 && !removed.includes(relPath)) removed.push(relPath);
1419
+ return exists2;
829
1420
  }
830
1421
  function findStaleHookRefs(settingsPath, claudeDir, spare) {
831
1422
  let settings;
@@ -858,6 +1449,7 @@ function removeRetiredHookRefs(settingsPath, claudeDir, refs, opts = {}) {
858
1449
  const isRetiredDead = (hook) => {
859
1450
  const rel = projectAnchoredRef(hook?.command ?? "", claudeDir);
860
1451
  if (rel === void 0 || !refs.includes(rel)) return false;
1452
+ if (!isLegacyHookLine(hook?.command, claudeDir)) return false;
861
1453
  if (opts.evenIfScriptExists !== true && existsSync(join(claudeDir, rel))) return false;
862
1454
  if (!removed.includes(rel)) removed.push(rel);
863
1455
  return true;
@@ -1438,125 +2030,6 @@ init_esm_shims();
1438
2030
 
1439
2031
  // src/agents-md-merge.ts
1440
2032
  init_esm_shims();
1441
-
1442
- // src/retired-anchor-sections.ts
1443
- init_esm_shims();
1444
- import { createHash } from "crypto";
1445
- function retiredAnchorSectionKey(lines2) {
1446
- const out = lines2.map((l) => l.replace(/\r$/, "").trimEnd());
1447
- while (out.length > 1 && out.at(-1) === "") out.pop();
1448
- return createHash("sha256").update(out.join("\n")).digest("hex");
1449
- }
1450
- var RETIRED_ANCHOR_SECTION_KEYS = /* @__PURE__ */ new Set([
1451
- "522bac15bc17949697e291b837c0d9624f5e0c7666400a3baf94cdef7cfab8b5",
1452
- // ## Rule 1 — Think Before Coding
1453
- "ea10b7cd9b84a71949a071fae15256f490b3fe407159d7bddcf3f882310fa835",
1454
- // ## Rule 2 — Simplicity First
1455
- "c486465d9554f2de1711cd056437f6a95a5d3243264b82d29a6957f24b5a6de3",
1456
- // ## Rule 3 — Surgical Changes
1457
- "3d080574cc7ae81eda75c4aa019445b38b6f69c5f9eeeda9097e10b6041e7e94",
1458
- // ## Rule 4 — Goal-Driven Execution
1459
- "11e43547f6b1613a5dabb3edaf5131d696a3fd375b3c22558f03555a0f5cf2ef",
1460
- // ## Rule 5 — Use the model only for judgment calls
1461
- "60d91718de6ae16ec86b50e7c9a939a6ca5fc0721422b592700cc9972f55aca2",
1462
- // ## Rule 6 — Token budgets are not advisory
1463
- "9d482c7307cbcb02acc6fb35cd57b24baa9fce04528e2bd21e1e877603f8b85b",
1464
- // ## Rule 7 — Surface conflicts, don't average them
1465
- "abca09f13833ce18bd0ffc0793d59780c35447ca79c2a512afcbc9d7a7116ed8",
1466
- // ## Rule 8 — Read before you write
1467
- "5b4eae6c3dc2d92cfb1772889650882a4a2115f08a36602da9a1d96697059b91",
1468
- // ## Rule 9 — Tests verify intent, not just behavior
1469
- "632670b8897dc373d4a12f611c2436d9a8e86d8cdab917eecabc4bf2a56f8030",
1470
- // ## Rule 10 — Checkpoint after every significant step
1471
- "252e99f25b05a47e5ce884ac9f1e1d34156116b9a76331e2510b1354a6c98cd4",
1472
- // ## Rule 11 — Match the codebase's conventions, even if you disagree
1473
- "c28a12b589b6576379793c51fd01dbfaf91d391ac773f84ae0477ddb60a1e3e8",
1474
- // ## Rule 12 — Fail loud
1475
- "72feaf96f998989351f8083edb891c7b0c3bccca65dbea2732fb2864b8f98bd4",
1476
- // ## 의사결정 및 컨펌 요청 시
1477
- "95c932ecb4f4fdcdd8d483f9d02166b906f6eb045ef33ee474a16913d0c3e6cd",
1478
- // ## Phase/작업 완료 시 Self-Audit 실행:
1479
- "c7f9fa755bd66d80c2df496c6c759e8accd736cd8fef64460feb7ae9cd4c8006",
1480
- // ## Context Management
1481
- "6ec0b415a8f86c9940bccd3e6db895ea4a110185e76fef223a348f9553fd897c",
1482
- // ## Rule 12 — Fail loud
1483
- "a78f0ffa6b51c9b45c964ecb92db951534336f7e558a3d39d11f015ee6c3466c",
1484
- // ## Anti-Patterns (Forbidden)
1485
- "50d00a511e87571d7ff85f6584b87b9f5c2eef06122d8ac5fdccf3f047643f12",
1486
- // ## When Requesting Decisions or Confirmation
1487
- "574519e07f48bcc04f0e3d505c0f9c157ddd426b5eda2baa99656cd4712dad2b",
1488
- // ## Run Self-Audit on Phase/Task Completion
1489
- "df73823c02e6eee000388444964acfec233ffeec0e20fdc5d31eb018d2ca93c1",
1490
- // ## Context Management
1491
- "8f49f0a592575a65eadd3e33950c96616223aa8bb116707103affeef71db28c6",
1492
- // ## Delegate the Building, Keep the Deciding
1493
- "6115eccc3b2702f436a9db7d6af9803fa7b1fbf7b9ff1110ea658fadd67ec5ea",
1494
- // ## 1. Think before coding
1495
- "15b120395ec8e757ecbe3e65775371a9120953617fb37eb062e0c176b52f045a",
1496
- // ## 2. Prefer the simplest sufficient solution
1497
- "cc466b4781444ca54aedebd20ba3aa531c3aa84cc438953df84b133bd32a0e1e",
1498
- // ## 3. Make surgical changes and preserve existing work
1499
- "f6d1f6f02cb3c19e61becf329f20335c54e684bccb06b33e4b7f66eb49f9c6b6",
1500
- // ## 4. Define success before editing
1501
- "372bf30b282b861c6a89e355c94ffd239bb0202e2ef928f8af99d640579710f0",
1502
- // ## 5. Report evidence, not confidence
1503
- "66ca0e3aae98d24c65afbc418645df29d8c570be81918c42192eb1beecd21f23",
1504
- // ## 6. Do not cross high-impact boundaries alone
1505
- "9c6c27eb57a9790273fa3fdf0df3628d927b025f870f09933692d1b522d73a25",
1506
- // ## Decisions and explanations
1507
- "922d100c2dc6ef8a53989a920c3554afa7efd148255bc144412403c0289439e6",
1508
- // ## Decisions and explanations
1509
- "330a67775a28557431aebf36a44018fc5194a4b929bf2cf95184b1f0828a6360",
1510
- // ## 1. Understand First
1511
- "3b2f0147dc7bd0f01fd12485790199ef4ee96a6b723e244ffbf3dc96933a1ab8",
1512
- // ## 2. Define Success and Keep It Simple
1513
- "8802fb25c05879c98dbf8407001d239c410d25b4fa2521b11d9d7cc108f73b29",
1514
- // ## 3. Preserve Sound Boundaries
1515
- "1d0d9bf05d8870dd0dc62e388ceffc98923f1dd2074ef8038f80a50c9b5b9a81",
1516
- // ## 4. Make Surgical Changes
1517
- "05e08e2318061141464ae714d6770d35527576affa787740d9c6d9345d3462dd",
1518
- // ## 5. Verify and Review
1519
- "7b39f1f92a72517d6ae52599becfef29f675e48185a3483dc993d7accd4aee7c",
1520
- // ## 6. Protect High-Impact Boundaries
1521
- "d5d93c55de33e4cdcb38f76c6d6d70a6e0beac7a176c8aa1daa09905ccc5fe39",
1522
- // ## 7. Report Evidence
1523
- "cefc8bb6194d4f1b6302345e96ffb3a28b8b992032fd40f9f5b4f18997657e7a",
1524
- // ## Presenting a decision
1525
- "7385ff5df34148278a8f4b164c11ba5f9355626abcc13a822dd1ebb206321c2f",
1526
- // ## Skills that apply continuously
1527
- "ad9fd1ff225c57c9801a7d7472bf4ddf9c952c602f4a93eae86fbcb3bcf468bc",
1528
- // ## 7. Report Evidence
1529
- "868fe823fc40011d08816c9f1105ef6df7ca7f2479779303ce9583bba1ce6e0d",
1530
- // ## Skills that apply continuously
1531
- "3f8259ca7c92d79cca1a36bba38f36d4ef5a96fd6cafbd0edb5a79492082f46f",
1532
- // ## Presenting a decision
1533
- "ecfdcd50e97723af77cfe6889bbad784cdeb86dd0c52af3ff98ddf6adf80f445",
1534
- // ## 1. Resolve what matters, then act
1535
- "9321cb1312a080bcf560940b8f86d3d59b39c667add4b8f3ad785ddae9bc8b20",
1536
- // ## 2. Choose the simplest sufficient solution
1537
- "a4c345996a8578cc24b62fde27084e5848a61e4a40d91b0c72a95da46203b43c",
1538
- // ## 3. Keep changes focused and preserve existing work
1539
- "1adbf1bf88bb8288744e1c1d73518ffdec12a5b668d5a225e2bedd006844466c",
1540
- // ## 4. Define success and verify proportionally
1541
- "7636e57a877d54039f0c2829fde84202c65378bd36b8c8abb7274a29eaa5f8ac",
1542
- // ## 5. Report evidence and stop unproductive loops
1543
- "ddf2be9e04c04bf53ad9b5476e45639b33a60bf49bd3a83835796632052b17b4",
1544
- // ## 6. Keep authority explicit
1545
- "16b0edc0f4886a9f9ec94e6fb97206c385286b2c9d5563b2324b7a2f4a434435",
1546
- // ## 1. Understand what success means
1547
- "b10ab1eafe25bb7ba3b20b907b1d7eedde03e52fbd49905f24e192e30b4e1b9a",
1548
- // ## 2. Choose and adapt the approach
1549
- "69bcfb8b37ac184b1a30945a0dea59108ef1242c2f40fb778be118cbd524aea7",
1550
- // ## 3. Keep changes focused and coherent
1551
- "f22a5a13c5ed8460c9370212d91354d0fea2fefc7f420a1eb3088504ae8da6c0",
1552
- // ## 4. Verify outcomes in proportion to consequences
1553
- "7a335cde69e8055ee5e137a9a5c09fd7f7c2e551ab099a2cda87f0c3dcd95a19",
1554
- // ## 5. Let evidence determine readiness
1555
- "79797568bb71bd0f7b14393f72e61721a4bfe99ecfb6126ffa38a6c03c53d765"
1556
- // ## 6. Act within clear authority
1557
- ]);
1558
-
1559
- // src/agents-md-merge.ts
1560
2033
  var marker = (name) => ({
1561
2034
  start: `<!-- uzys-harness:${name}:start -->`,
1562
2035
  end: `<!-- uzys-harness:${name}:end -->`
@@ -1627,6 +2100,29 @@ function trimTrailingBlanks(lines2) {
1627
2100
  while (out.length > 0 && (out.at(-1) ?? "").trim() === "") out.pop();
1628
2101
  return out;
1629
2102
  }
2103
+ function isLegacyHarnessSection(lines2) {
2104
+ const key = legacySectionKey(lines2);
2105
+ return RETIRED_ANCHOR_SECTION_KEYS.has(key) || LEGACY_AGENTS_MD_SECTION_KEYS.has(key) || LEGACY_AGENTS_MD_NAMED_KEYS.has(key);
2106
+ }
2107
+ function withoutAgentsBlock(text) {
2108
+ const lines2 = text.split("\n");
2109
+ const at5 = blockRange(lines2, AGENTS_BLOCK);
2110
+ if (at5 === null) return text;
2111
+ const head = trimTrailingBlanks(lines2.slice(0, at5[0]));
2112
+ const tail = lines2.slice(at5[1] + 1);
2113
+ while (tail.length > 0 && (tail[0] ?? "").trim() === "") tail.shift();
2114
+ return tail.length > 0 ? [...head, "", ...tail].join("\n") : `${head.join("\n")}
2115
+ `;
2116
+ }
2117
+ function isLegacyHarnessAgentsMd(text) {
2118
+ const body = withoutAgentsBlock(text);
2119
+ const lines2 = body.split("\n");
2120
+ if (blockRange(lines2, ANCHOR_BLOCK) !== null || blockRange(lines2, SKILLS_BLOCK) !== null) {
2121
+ return false;
2122
+ }
2123
+ const key = legacyPreambleKey(body);
2124
+ return key !== null && LEGACY_AGENTS_MD_PREAMBLE_KEYS.has(key);
2125
+ }
1630
2126
  function refreshBlock(existing, rendered, m, legacyHeading) {
1631
2127
  const at5 = blockRange(rendered, m);
1632
2128
  const fresh = at5 === null ? null : rendered.slice(at5[0], at5[1] + 1);
@@ -1679,9 +2175,11 @@ function renderAgentsBlock(params) {
1679
2175
  trimBlankEdges(harness)
1680
2176
  ].filter((part) => part.length > 0).map((part) => part.join("\n")).join("\n\n");
1681
2177
  }
1682
- function mergeAgentsMd(params) {
2178
+ function mergeAgentsMdDetailed(params) {
1683
2179
  const { rendered, existing, template } = params;
1684
- if (existing === null) return rendered;
2180
+ if (existing === null) {
2181
+ return { text: rendered, droppedLegacySections: 0, editedLegacySections: [] };
2182
+ }
1685
2183
  const names = sectionNames(template);
1686
2184
  const bodies = /* @__PURE__ */ new Map();
1687
2185
  const contextNow = sectionBody(existing, names, CONTEXT_SECTION);
@@ -1703,18 +2201,32 @@ function mergeAgentsMd(params) {
1703
2201
  }
1704
2202
  const merged = bodies.size === 0 ? rendered : assemble(rendered, names, bodies);
1705
2203
  const mergedText = merged.replace(/\r/g, "");
1706
- const extras = extraTopLevelSections(
2204
+ const candidates = extraTopLevelSections(
1707
2205
  existing,
1708
2206
  names,
1709
2207
  rendered,
1710
2208
  params.harnessRuleHeadings ?? /* @__PURE__ */ new Set(),
1711
2209
  replacedRulesHeadings
1712
- ).filter((e2) => !mergedText.includes(e2.join("\n").replace(/\r/g, "")));
1713
- if (extras.length === 0) return merged;
1714
- return `${merged.replace(/\n+$/, "\n")}${extras.map((e2) => e2.join("\n")).join("\n")}`.replace(
1715
- /\n+$/,
1716
- "\n"
1717
2210
  );
2211
+ const droppedLegacySections = candidates.legacy;
2212
+ const editedLegacySections = isLegacyHarnessAgentsMd(existing) ? installerSectionsInHarnessArea(
2213
+ existing,
2214
+ names,
2215
+ /* @__PURE__ */ new Set([...params.harnessRuleHeadings ?? [], ...renderedRuleHeadings(rendered, names)]),
2216
+ true
2217
+ ).keptEdited : [];
2218
+ const extras = candidates.sections.filter(
2219
+ (e2) => !mergedText.includes(e2.join("\n").replace(/\r/g, ""))
2220
+ );
2221
+ if (extras.length === 0) return { text: merged, droppedLegacySections, editedLegacySections };
2222
+ return {
2223
+ text: `${merged.replace(/\n+$/, "\n")}${extras.map((e2) => e2.join("\n")).join("\n")}`.replace(
2224
+ /\n+$/,
2225
+ "\n"
2226
+ ),
2227
+ droppedLegacySections,
2228
+ editedLegacySections
2229
+ };
1718
2230
  }
1719
2231
  function headingOwner(bare, ctx) {
1720
2232
  const name = /^## (.+?)\s*$/.exec(bare)?.[1];
@@ -1737,7 +2249,6 @@ function extraTopLevelSections(existing, names, rendered, harnessRuleHeadings, r
1737
2249
  ...renderedRuleHeadings(rendered, names)
1738
2250
  ]);
1739
2251
  const out = [];
1740
- const replacedSections = /* @__PURE__ */ new Set();
1741
2252
  let current = null;
1742
2253
  let region = null;
1743
2254
  for (const line of existing.split("\n")) {
@@ -1749,19 +2260,18 @@ function extraTopLevelSections(existing, names, rendered, harnessRuleHeadings, r
1749
2260
  const owner = headingOwner(bare, { region, names, harnessHeadings });
1750
2261
  const replacedBody = owner === "body" && region === RULES_SECTION && replacedRulesHeadings !== null && !replacedRulesHeadings.has(bare.trim());
1751
2262
  current = owner === "installer" || replacedBody ? [line] : null;
1752
- if (replacedBody && current !== null) replacedSections.add(current);
1753
2263
  continue;
1754
2264
  }
1755
2265
  if (current !== null) current.push(line);
1756
2266
  }
1757
2267
  if (current !== null) out.push(current);
1758
- return out.filter(
1759
- (lines2) => !replacedSections.has(lines2) || !RETIRED_ANCHOR_SECTION_KEYS.has(retiredAnchorSectionKey(lines2))
1760
- ).map((lines2) => {
2268
+ const legacy = out.filter(isLegacyHarnessSection).length;
2269
+ const sections = out.filter((lines2) => !isLegacyHarnessSection(lines2)).map((lines2) => {
1761
2270
  const trimmed = [...lines2];
1762
2271
  while (trimmed.length > 1 && (trimmed.at(-1) ?? "").trim() === "") trimmed.pop();
1763
2272
  return trimmed;
1764
2273
  }).filter((lines2) => lines2.length > 1 || /^## /.test(lines2[0] ?? ""));
2274
+ return { sections, legacy };
1765
2275
  }
1766
2276
  function installerLines(body, m) {
1767
2277
  if (body === null) return [];
@@ -1781,7 +2291,7 @@ function projectContextInstallerLines(params) {
1781
2291
  const body = sectionBody(existing, sectionNames(template), CONTEXT_SECTION);
1782
2292
  return body === null ? null : installerLines(body, SKILLS_BLOCK);
1783
2293
  }
1784
- function installerSectionsInHarnessArea(existing, names, harnessRuleHeadings) {
2294
+ function installerSectionsInHarnessArea(existing, names, harnessRuleHeadings, legacyFile = false) {
1785
2295
  const out = [];
1786
2296
  let current = null;
1787
2297
  let region = null;
@@ -1792,31 +2302,60 @@ function installerSectionsInHarnessArea(existing, names, harnessRuleHeadings) {
1792
2302
  if (current !== null) out.push(current);
1793
2303
  if (names.has(name)) region = name;
1794
2304
  const owner = headingOwner(bare, { region, names, harnessHeadings: harnessRuleHeadings });
1795
- current = owner === "installer" ? [bare] : null;
2305
+ if (!legacyFile) current = owner === "installer" ? { lines: [bare], named: false } : null;
2306
+ else if (region === CONTEXT_SECTION) current = null;
2307
+ else current = { lines: [bare], named: owner === "harness" };
1796
2308
  continue;
1797
2309
  }
1798
- if (current !== null) current.push(bare);
2310
+ if (current !== null) current.lines.push(bare);
1799
2311
  }
1800
2312
  if (current !== null) out.push(current);
1801
- return out.map(trimTrailingBlanks);
2313
+ const sections = [];
2314
+ const keptEdited = [];
2315
+ let legacy = 0;
2316
+ for (const { lines: lines2, named } of out) {
2317
+ if (isLegacyHarnessSection(lines2)) {
2318
+ legacy++;
2319
+ continue;
2320
+ }
2321
+ if (named) {
2322
+ if (lines2.slice(1).every((l) => l.trim() === "")) continue;
2323
+ keptEdited.push((lines2[0] ?? "").replace(/^## /, "").trim());
2324
+ }
2325
+ sections.push(trimTrailingBlanks(lines2));
2326
+ }
2327
+ return { sections, legacy, keptEdited };
1802
2328
  }
1803
- function stripHarnessFromAgentsMd(params) {
2329
+ function stripAgentsMd(params) {
1804
2330
  const { existing, template } = params;
1805
2331
  const lines2 = existing.split("\n");
2332
+ const names = sectionNames(template);
2333
+ const headings = params.harnessRuleHeadings ?? /* @__PURE__ */ new Set();
1806
2334
  if (blockRange(lines2, ANCHOR_BLOCK) === null && blockRange(lines2, SKILLS_BLOCK) === null) {
1807
- return null;
2335
+ if (!isLegacyHarnessAgentsMd(existing)) {
2336
+ return {
2337
+ remainder: null,
2338
+ legacyRemoved: false,
2339
+ legacySections: 0,
2340
+ keptEdited: []
2341
+ };
2342
+ }
2343
+ const body = withoutAgentsBlock(existing);
2344
+ return stripLegacyAgentsMd(body, names, headings);
1808
2345
  }
1809
- const names = sectionNames(template);
1810
2346
  const context = installerLines(sectionBody(existing, names, CONTEXT_SECTION), SKILLS_BLOCK);
1811
2347
  const rules = installerLines(sectionBody(existing, names, RULES_SECTION), ANCHOR_BLOCK);
1812
2348
  const contextFilled = !isUnfilledScaffold(context);
1813
2349
  const rulesFilled = compact(rules).length > 0;
1814
- const extras = installerSectionsInHarnessArea(
1815
- existing,
1816
- names,
1817
- params.harnessRuleHeadings ?? /* @__PURE__ */ new Set()
1818
- );
1819
- if (!contextFilled && !rulesFilled && extras.length === 0) return null;
2350
+ const extras = installerSectionsInHarnessArea(existing, names, headings);
2351
+ const legacy = {
2352
+ legacyRemoved: extras.legacy > 0,
2353
+ legacySections: extras.legacy,
2354
+ keptEdited: []
2355
+ };
2356
+ if (!contextFilled && !rulesFilled && extras.sections.length === 0) {
2357
+ return { remainder: null, ...legacy };
2358
+ }
1820
2359
  const out = [];
1821
2360
  const title = (lines2[0] ?? "").replace(/\r$/, "");
1822
2361
  if (/^# /.test(title)) out.push(title, "");
@@ -1824,8 +2363,26 @@ function stripHarnessFromAgentsMd(params) {
1824
2363
  out.push(`## ${CONTEXT_SECTION}`, "", ...trimBlankEdges(context), "");
1825
2364
  }
1826
2365
  if (rulesFilled) out.push(`## ${RULES_SECTION}`, "", ...trimBlankEdges(rules), "");
1827
- for (const section of extras) out.push(...section, "");
1828
- return out.join("\n");
2366
+ for (const section of extras.sections) out.push(...section, "");
2367
+ return { remainder: out.join("\n"), ...legacy };
2368
+ }
2369
+ function stripLegacyAgentsMd(existing, names, headings) {
2370
+ const contextBody = sectionBody(existing, names, CONTEXT_SECTION);
2371
+ const context = dropHarnessQuoteBlocks(contextBody ?? []);
2372
+ const contextFilled = contextBody !== null && !isUnfilledScaffold(context);
2373
+ const extras = installerSectionsInHarnessArea(existing, names, headings, true);
2374
+ const result = {
2375
+ legacyRemoved: true,
2376
+ legacySections: extras.legacy,
2377
+ keptEdited: extras.keptEdited
2378
+ };
2379
+ if (!contextFilled && extras.sections.length === 0) return { remainder: null, ...result };
2380
+ const out = [];
2381
+ const title = (existing.split("\n")[0] ?? "").replace(/\r$/, "");
2382
+ if (/^# /.test(title)) out.push(title, "");
2383
+ if (contextFilled) out.push(`## ${CONTEXT_SECTION}`, "", ...trimBlankEdges(context), "");
2384
+ for (const section of extras.sections) out.push(...section, "");
2385
+ return { remainder: out.join("\n"), ...result };
1829
2386
  }
1830
2387
 
1831
2388
  // src/adapters/marker-md.ts
@@ -3402,7 +3959,7 @@ function parseRemote(raw) {
3402
3959
  return { type: "http", url, auth: { bearerEnv } };
3403
3960
  }
3404
3961
  function parseTrackMcpMap(raw) {
3405
- const rows = [];
3962
+ const rows2 = [];
3406
3963
  for (const line of raw.split(/\r?\n/)) {
3407
3964
  const trimmed = line.trim();
3408
3965
  if (!trimmed || trimmed.startsWith("#")) {
@@ -3418,7 +3975,7 @@ function parseTrackMcpMap(raw) {
3418
3975
  }
3419
3976
  if (command === "url") {
3420
3977
  const server = parseRemote(argsJson ?? "");
3421
- if (server !== null) rows.push({ name, pattern, server });
3978
+ if (server !== null) rows2.push({ name, pattern, server });
3422
3979
  continue;
3423
3980
  }
3424
3981
  let args;
@@ -3430,9 +3987,9 @@ function parseTrackMcpMap(raw) {
3430
3987
  if (!Array.isArray(args) || !args.every((a) => typeof a === "string")) {
3431
3988
  continue;
3432
3989
  }
3433
- rows.push({ name, pattern, server: { type: "stdio", command, args } });
3990
+ rows2.push({ name, pattern, server: { type: "stdio", command, args } });
3434
3991
  }
3435
- return rows;
3992
+ return rows2;
3436
3993
  }
3437
3994
  function toClaudeServer(cfg) {
3438
3995
  if (cfg.type === "http") {
@@ -3450,12 +4007,12 @@ function toClaudeServer(cfg) {
3450
4007
  if (cfg.env && Object.keys(cfg.env).length > 0) out.env = { ...cfg.env };
3451
4008
  return out;
3452
4009
  }
3453
- function mergeMcpServers(base, rows, tracks, chosen = [], dropped = []) {
4010
+ function mergeMcpServers(base, rows2, tracks, chosen = [], dropped = []) {
3454
4011
  const out = {
3455
4012
  ...base,
3456
4013
  mcpServers: { ...base.mcpServers }
3457
4014
  };
3458
- for (const row of rows) {
4015
+ for (const row of rows2) {
3459
4016
  if (dropped.includes(row.name)) {
3460
4017
  continue;
3461
4018
  }
@@ -3473,27 +4030,27 @@ function mergeMcpServers(base, rows, tracks, chosen = [], dropped = []) {
3473
4030
  function composeMcpJson(opts) {
3474
4031
  const base = JSON.parse(readFileSync3(opts.templateMcpPath, "utf8"));
3475
4032
  const mapRaw = existsSync4(opts.trackMapPath) ? readFileSync3(opts.trackMapPath, "utf8") : "";
3476
- const rows = parseTrackMcpMap(mapRaw);
3477
- return mergeMcpServers(base, rows, opts.tracks, opts.chosen(rows), opts.dropped?.(rows) ?? []);
4033
+ const rows2 = parseTrackMcpMap(mapRaw);
4034
+ return mergeMcpServers(base, rows2, opts.tracks, opts.chosen(rows2), opts.dropped?.(rows2) ?? []);
3478
4035
  }
3479
- function selectableMcpServers(rows) {
3480
- const names = new Set(rows.map((r) => r.name));
4036
+ function selectableMcpServers(rows2) {
4037
+ const names = new Set(rows2.map((r) => r.name));
3481
4038
  const out = /* @__PURE__ */ new Map();
3482
4039
  for (const a of EXTERNAL_ASSETS) {
3483
4040
  if (a.method.kind === "internal" && names.has(a.method.key)) out.set(a.method.key, a.id);
3484
4041
  }
3485
4042
  return out;
3486
4043
  }
3487
- function selectedMcpServers(rows, choice) {
4044
+ function selectedMcpServers(rows2, choice) {
3488
4045
  const recorded2 = new Set(
3489
4046
  (choice.previousLog?.portions ?? []).filter((p2) => p2.path === ".mcp.json").map((p2) => p2.key)
3490
4047
  );
3491
4048
  const legacy = new Set(
3492
- choice.projectDir === void 0 ? [] : legacyMcpServers(choice.projectDir, choice.previousLog, rows)
4049
+ choice.projectDir === void 0 ? [] : legacyMcpServers(choice.projectDir, choice.previousLog, rows2)
3493
4050
  );
3494
- const dropped = new Set(droppedMcpServers(rows, choice.excluded));
4051
+ const dropped = new Set(droppedMcpServers(rows2, choice.excluded));
3495
4052
  const out = [];
3496
- for (const [name, assetId] of selectableMcpServers(rows)) {
4053
+ for (const [name, assetId] of selectableMcpServers(rows2)) {
3497
4054
  if (dropped.has(name)) continue;
3498
4055
  const key = `mcpServers.${name}`;
3499
4056
  if (isAssetSelected(assetId, choice.spec) || recorded2.has(key) || legacy.has(name)) {
@@ -3502,7 +4059,7 @@ function selectedMcpServers(rows, choice) {
3502
4059
  }
3503
4060
  return out;
3504
4061
  }
3505
- function legacyMcpServers(projectDir, previousLog, rows) {
4062
+ function legacyMcpServers(projectDir, previousLog, rows2) {
3506
4063
  if (previousLog === null || previousLog.records === "writer") return [];
3507
4064
  if ((previousLog.portions ?? []).some((p2) => p2.path === ".mcp.json")) return [];
3508
4065
  const created = (previousLog.rootFiles ?? []).some(
@@ -3512,10 +4069,10 @@ function legacyMcpServers(projectDir, previousLog, rows) {
3512
4069
  const servers = readMcpServers(join5(projectDir, ".mcp.json"));
3513
4070
  if (servers === null) return [];
3514
4071
  const out = [];
3515
- for (const name of selectableMcpServers(rows).keys()) {
4072
+ for (const name of selectableMcpServers(rows2).keys()) {
3516
4073
  if (!Object.hasOwn(servers, name)) continue;
3517
4074
  const disk = jsonSha(servers[name]);
3518
- const row = rows.find((r) => r.name === name);
4075
+ const row = rows2.find((r) => r.name === name);
3519
4076
  const known = [...row ? [row.server] : [], ...priorMcpValues(name)];
3520
4077
  if (known.some((v2) => jsonSha(toClaudeServer(v2)) === disk)) out.push(name);
3521
4078
  }
@@ -3533,8 +4090,8 @@ function readMcpServers(path) {
3533
4090
  return null;
3534
4091
  }
3535
4092
  }
3536
- function droppedMcpServers(rows, excluded) {
3537
- return [...selectableMcpServers(rows)].filter(([name, assetId]) => {
4093
+ function droppedMcpServers(rows2, excluded) {
4094
+ return [...selectableMcpServers(rows2)].filter(([name, assetId]) => {
3538
4095
  const id = keyId(".mcp.json", `mcpServers.${name}`);
3539
4096
  return excluded.has(assetId) || id !== null && excluded.has(id);
3540
4097
  }).map(([name]) => name);
@@ -4088,7 +4645,7 @@ function hookScript(handler, claudeDir) {
4088
4645
  const script = ref.slice("hooks/".length);
4089
4646
  return script.includes("/") ? null : script;
4090
4647
  }
4091
- function legacySettingsSeed(text, render, projectDir) {
4648
+ function legacySettingsSeed(text, render, projectDir, opts = {}) {
4092
4649
  const seed = /* @__PURE__ */ new Map();
4093
4650
  let root;
4094
4651
  try {
@@ -4098,6 +4655,7 @@ function legacySettingsSeed(text, render, projectDir) {
4098
4655
  }
4099
4656
  const claudeDir = join7(projectDir, ".claude");
4100
4657
  const candidates = new Set([...render.keys()].filter((k2) => k2.startsWith("hooks.")));
4658
+ const legacyLines = /* @__PURE__ */ new Set();
4101
4659
  const hooks = isObject2(root) && isObject2(root.hooks) ? root.hooks : {};
4102
4660
  for (const [event, groups] of Object.entries(hooks)) {
4103
4661
  if (!Array.isArray(groups)) continue;
@@ -4105,14 +4663,16 @@ function legacySettingsSeed(text, render, projectDir) {
4105
4663
  if (!isObject2(group) || !Array.isArray(group.hooks)) continue;
4106
4664
  for (const handler of group.hooks) {
4107
4665
  const script = hookScript(handler, claudeDir);
4108
- if (script !== null && RETIRED_PATHS.includes(`hooks/${script}`)) {
4109
- candidates.add(`hooks.${event}#${script}`);
4110
- }
4666
+ if (script === null) continue;
4667
+ const key = `hooks.${event}#${script}`;
4668
+ if (RETIRED_PATHS.includes(`hooks/${script}`)) candidates.add(key);
4669
+ if (isObject2(handler) && isLegacyHookLine(handler.command, claudeDir)) legacyLines.add(key);
4111
4670
  }
4112
4671
  }
4113
4672
  }
4114
4673
  const present2 = ADAPTERS["json-keys"].read(text, candidates, projectDir) ?? /* @__PURE__ */ new Map();
4115
4674
  for (const [key, sha] of present2) {
4675
+ if (!legacyLines.has(key) && opts.edited !== true) continue;
4116
4676
  const rendered = render.get(key);
4117
4677
  const handler = isObject2(rendered) && Array.isArray(rendered.hooks) ? rendered.hooks[0] : void 0;
4118
4678
  seed.set(key, handler === void 0 ? sha : jsonSha(handler));
@@ -4209,8 +4769,8 @@ function legacyGitignoreSeed(text, render, previous) {
4209
4769
 
4210
4770
  // src/installer.ts
4211
4771
  init_esm_shims();
4212
- import { chmodSync as chmodSync3, existsSync as existsSync22, readdirSync as readdirSync4, readFileSync as readFileSync22, writeFileSync as writeFileSync9 } from "fs";
4213
- import { basename as basename4, join as join30, relative as relative3, resolve, sep as sep4 } from "path";
4772
+ import { chmodSync as chmodSync3, existsSync as existsSync22, readdirSync as readdirSync5, readFileSync as readFileSync22, writeFileSync as writeFileSync8 } from "fs";
4773
+ import { basename as basename4, join as join31, relative as relative4, resolve, sep as sep5 } from "path";
4214
4774
 
4215
4775
  // src/anchor-seed.ts
4216
4776
  init_esm_shims();
@@ -4513,6 +5073,10 @@ function createOwnedWriter(projectDir, baseline, options = {}) {
4513
5073
  const backupRel = relative2(projectDir, backup).split(sep3).join("/");
4514
5074
  displace({ path: rel, change: "displaced", notes: [backupRel] });
4515
5075
  } else backedUp.push(rel);
5076
+ } else if (opts?.backupFirst === true) {
5077
+ const backup = backupFile(absPath, now);
5078
+ backupPaths.push(backup);
5079
+ journal?.backup(backup);
4516
5080
  }
4517
5081
  writeFileSync4(absPath, content);
4518
5082
  updated++;
@@ -4723,28 +5287,43 @@ function hasMarkerLine(disk, markers) {
4723
5287
  }
4724
5288
  function agentsMdModel(disk, recordedByHarness, recordedBlock = false) {
4725
5289
  if (disk === null) return recordedBlock && !recordedByHarness ? "block" : "sections";
4726
- if (hasMarkerLine(disk, [AGENTS_BLOCK.start, AGENTS_BLOCK.end])) return "block";
5290
+ const legacy = isLegacyHarnessAgentsMd(disk);
5291
+ if (hasMarkerLine(disk, [AGENTS_BLOCK.start, AGENTS_BLOCK.end]) && !legacy) return "block";
4727
5292
  if (recordedByHarness) return "sections";
4728
5293
  if (hasMarkerLine(disk, [ANCHOR_BLOCK.start, SKILLS_BLOCK.start])) return "sections";
5294
+ if (legacy) return "sections";
4729
5295
  return "block";
4730
5296
  }
4731
5297
  function writeAgentsMd(params) {
4732
5298
  const abs = join13(params.projectDir, AGENTS_MD);
4733
5299
  const disk = existsSync11(abs) ? readFileSync8(abs, "utf8") : null;
4734
5300
  const recordedBlock = (params.record.portions ?? []).some((p2) => p2.path === AGENTS_MD);
4735
- if (agentsMdModel(disk, params.baseline.has(AGENTS_MD), recordedBlock) === "sections") {
4736
- params.writer.write(
4737
- abs,
4738
- mergeAgentsMd({
4739
- rendered: params.rendered,
4740
- existing: disk,
4741
- template: params.template,
4742
- ...params.replaceUnfilledContext === true ? { replaceUnfilledContext: true } : {},
4743
- ...params.harnessRuleHeadings === void 0 ? {} : { harnessRuleHeadings: params.harnessRuleHeadings }
4744
- }),
4745
- params.createInRefresh === true ? { createInRefresh: true } : void 0
4746
- );
4747
- return { model: "sections", shared: null };
5301
+ const recordedByHarness = params.baseline.has(AGENTS_MD);
5302
+ if (agentsMdModel(disk, recordedByHarness, recordedBlock) === "sections") {
5303
+ const legacyUnrecorded = disk !== null && !recordedByHarness && isLegacyHarnessAgentsMd(disk);
5304
+ const merged = mergeAgentsMdDetailed({
5305
+ rendered: params.rendered,
5306
+ // N2 — 첫 접촉 블록은 떼고 병합한다(블록 안은 지금 렌더가 다시 쓴다)
5307
+ existing: disk === null ? null : withoutAgentsBlock(disk),
5308
+ template: params.template,
5309
+ ...params.replaceUnfilledContext === true || legacyUnrecorded ? { replaceUnfilledContext: true } : {},
5310
+ ...params.harnessRuleHeadings === void 0 ? {} : { harnessRuleHeadings: params.harnessRuleHeadings }
5311
+ });
5312
+ const dropped = merged.droppedLegacySections;
5313
+ const edited = merged.editedLegacySections;
5314
+ params.writer.write(abs, merged.text, {
5315
+ ...params.createInRefresh === true ? { createInRefresh: true } : {},
5316
+ // ADR-111 — 떨어뜨린 절은 현행 번들에 없는 바이트다 · 고친 이름 절은 설치자 글이다: 기준선 그대로인 파일이라도 1회 백업
5317
+ ...dropped > 0 || edited.length > 0 ? { backupFirst: true } : {}
5318
+ });
5319
+ if (recordedBlock) params.writer.journal?.portions(AGENTS_MD, []);
5320
+ return {
5321
+ model: "sections",
5322
+ shared: null,
5323
+ ...dropped > 0 ? { droppedLegacySections: dropped } : {},
5324
+ ...edited.length > 0 ? { editedLegacySections: edited } : {},
5325
+ ...recordedBlock ? { blockRecordDropped: true } : {}
5326
+ };
4748
5327
  }
4749
5328
  const shared2 = writeShared({
4750
5329
  projectDir: params.projectDir,
@@ -4834,10 +5413,15 @@ function runAgentsMdTransform(params) {
4834
5413
  const { harnessRoot, projectDir, baseline, shared: shared2 = {} } = params;
4835
5414
  const refreshOnly = params.refreshOnly === true;
4836
5415
  const clis = agentsMdClis(params.clis);
5416
+ const agentsMdPath = join14(projectDir, "AGENTS.md");
5417
+ const exists2 = existsSync12(agentsMdPath);
5418
+ const diskBefore = exists2 ? readFileSync9(agentsMdPath, "utf8") : null;
5419
+ const legacyAgentsMd = diskBefore !== null && isLegacyHarnessAgentsMd(diskBefore);
5420
+ const owned = (rel) => params.owned?.(rel) === true || rel === "AGENTS.md" && legacyAgentsMd;
4837
5421
  const writer = createOwnedWriter(projectDir, baseline, {
4838
5422
  refreshOnly,
4839
5423
  ...params.journal === void 0 ? {} : { journal: params.journal },
4840
- ...params.owned === void 0 ? {} : { owned: params.owned }
5424
+ owned
4841
5425
  });
4842
5426
  const claudeMd = readRequired(join14(harnessRoot, "templates/CLAUDE.md"));
4843
5427
  const template = readRequired(join14(harnessRoot, AGENTS_MD_TEMPLATE));
@@ -4847,9 +5431,7 @@ function runAgentsMdTransform(params) {
4847
5431
  refreshOnly,
4848
5432
  writer
4849
5433
  });
4850
- const agentsMdPath = join14(projectDir, "AGENTS.md");
4851
- const exists = existsSync12(agentsMdPath);
4852
- const creates = !exists && (!refreshOnly || params.installedByRecord === true);
5434
+ const creates = !exists2 && (!refreshOnly || params.installedByRecord === true);
4853
5435
  const legacy = params.legacyContext ?? null;
4854
5436
  const fromRoot = creates ? seedAgentsMdProjectContext(projectDir) : null;
4855
5437
  const seed = fromRoot ?? legacy;
@@ -4867,7 +5449,6 @@ function runAgentsMdTransform(params) {
4867
5449
  harnessRules: renderRulesBlock(portRules(harnessRoot, params.rules)),
4868
5450
  clis
4869
5451
  });
4870
- const diskBefore = exists ? readFileSync9(agentsMdPath, "utf8") : null;
4871
5452
  const agentsMd = writeAgentsMd({
4872
5453
  projectDir,
4873
5454
  rendered,
@@ -5564,14 +6145,14 @@ function renderHarnessMcp(harnessRoot, choice) {
5564
6145
  return composeMcpJson({
5565
6146
  ...mcpSources(harnessRoot),
5566
6147
  tracks: choice.spec.tracks,
5567
- chosen: (rows) => selectedMcpServers(rows, choice),
5568
- dropped: (rows) => droppedMcpServers(rows, choice.excluded)
6148
+ chosen: (rows2) => selectedMcpServers(rows2, choice),
6149
+ dropped: (rows2) => droppedMcpServers(rows2, choice.excluded)
5569
6150
  });
5570
6151
  }
5571
6152
  function trackDefaultMcpAssetIds(harnessRoot, tracks) {
5572
- const rows = trackRows(harnessRoot);
5573
- const selectable = selectableMcpServers(rows);
5574
- return rows.flatMap((r) => {
6153
+ const rows2 = trackRows(harnessRoot);
6154
+ const selectable = selectableMcpServers(rows2);
6155
+ return rows2.flatMap((r) => {
5575
6156
  const id = selectable.get(r.name);
5576
6157
  return id !== void 0 && anyTrack(tracks, r.pattern) ? [id] : [];
5577
6158
  });
@@ -5592,13 +6173,13 @@ function renderEverySelectableMcp(harnessRoot, tracks) {
5592
6173
  return composeMcpJson({
5593
6174
  ...mcpSources(harnessRoot),
5594
6175
  tracks,
5595
- chosen: (rows) => [...selectableMcpServers(rows).keys()]
6176
+ chosen: (rows2) => [...selectableMcpServers(rows2).keys()]
5596
6177
  });
5597
6178
  }
5598
6179
  function adapterExcluded(harnessRoot, excluded) {
5599
- const rows = trackRows(harnessRoot);
6180
+ const rows2 = trackRows(harnessRoot);
5600
6181
  const out = new Set(excluded);
5601
- for (const [name, assetId] of selectableMcpServers(rows)) {
6182
+ for (const [name, assetId] of selectableMcpServers(rows2)) {
5602
6183
  const id = keyId(".mcp.json", `mcpServers.${name}`);
5603
6184
  if (excluded.has(assetId) && id !== null) out.add(id);
5604
6185
  }
@@ -5770,15 +6351,62 @@ function runCliTransforms(params) {
5770
6351
  externalOutside,
5771
6352
  sharedFiles,
5772
6353
  portions: sharedFiles.flatMap((r) => r.portions ?? []),
5773
- portionPaths: sharedFiles.filter((r) => r.portions !== null).map((r) => r.path),
6354
+ // #774 (N2) — 블록 모델이던 `AGENTS.md` 를 절 모델로 바꿨으면 그 파일의 몫 기록을 비운다(판정한 경로 · 몫 없음)
6355
+ portionPaths: [
6356
+ ...sharedFiles.filter((r) => r.portions !== null).map((r) => r.path),
6357
+ ...agentsMd?.agentsMd.blockRecordDropped === true ? ["AGENTS.md"] : []
6358
+ ],
5774
6359
  restoredFiles
5775
6360
  };
5776
6361
  }
5777
6362
 
6363
+ // src/displaced.ts
6364
+ init_esm_shims();
6365
+ import { lstatSync as lstatSync3, mkdirSync as mkdirSync5, renameSync } from "fs";
6366
+ import { dirname as dirname5, join as join23 } from "path";
6367
+ function exists(abs) {
6368
+ try {
6369
+ lstatSync3(abs);
6370
+ return true;
6371
+ } catch {
6372
+ return false;
6373
+ }
6374
+ }
6375
+ function restoreDisplaced(log, projectDir, opts) {
6376
+ const out = [];
6377
+ for (const f of log.rootFiles ?? []) {
6378
+ if (f.change !== "displaced" || !opts.has(f.path)) continue;
6379
+ const slot = join23(projectDir, f.path);
6380
+ if (outsideProjectTarget(projectDir, slot) !== null) continue;
6381
+ const backup = f.notes[0] ?? null;
6382
+ const d2 = judgeDisplaced({
6383
+ backup,
6384
+ backupExists: backup !== null && exists(join23(projectDir, backup)),
6385
+ slotEmpty: !exists(slot) || !opts.write && opts.willBeGone?.has(f.path) === true
6386
+ });
6387
+ if (opts.write && d2.verdict === "restore" && backup !== null) {
6388
+ mkdirSync5(dirname5(slot), { recursive: true });
6389
+ renameSync(join23(projectDir, backup), slot);
6390
+ }
6391
+ out.push({
6392
+ path: f.path,
6393
+ backup,
6394
+ verdict: d2.verdict,
6395
+ line: d2.line,
6396
+ forget: d2.record === "forget"
6397
+ });
6398
+ }
6399
+ return out;
6400
+ }
6401
+ function withoutRestored(rootFiles, outcomes) {
6402
+ const settled = new Set(outcomes.filter((d2) => d2.forget).map((d2) => d2.path));
6403
+ return (rootFiles ?? []).filter((f) => !(f.change === "displaced" && settled.has(f.path)));
6404
+ }
6405
+
5778
6406
  // src/excluded-still-there.ts
5779
6407
  init_esm_shims();
5780
6408
  import { existsSync as existsSync18 } from "fs";
5781
- import { join as join23 } from "path";
6409
+ import { join as join24 } from "path";
5782
6410
  function excludedStillThere(projectDir, excluded, baselineOnDisk, previousLog) {
5783
6411
  const out = [];
5784
6412
  const add = (id, catalog) => {
@@ -5791,7 +6419,7 @@ function excludedStillThere(projectDir, excluded, baselineOnDisk, previousLog) {
5791
6419
  for (const id of excluded) {
5792
6420
  if (INTERNAL_BUNDLED_SKILL_IDS.includes(id)) {
5793
6421
  const there = [".claude/skills", ".agents/skills"].some(
5794
- (d2) => existsSync18(join23(projectDir, d2, id))
6422
+ (d2) => existsSync18(join24(projectDir, d2, id))
5795
6423
  );
5796
6424
  if (there) add(id, false);
5797
6425
  } else {
@@ -5805,17 +6433,27 @@ function excludedStillThere(projectDir, excluded, baselineOnDisk, previousLog) {
5805
6433
  function assetStillThere(projectDir, asset) {
5806
6434
  if (asset.method !== "skill" || asset.scope === "global") return true;
5807
6435
  if (asset.files !== void 0)
5808
- return asset.files.some((f) => existsSync18(join23(projectDir, f.path)));
6436
+ return asset.files.some((f) => existsSync18(join24(projectDir, f.path)));
5809
6437
  const dir = asset.detail.skill ?? asset.id;
5810
- return [".claude/skills", ".agents/skills"].some((d2) => existsSync18(join23(projectDir, d2, dir)));
6438
+ return [".claude/skills", ".agents/skills"].some((d2) => existsSync18(join24(projectDir, d2, dir)));
5811
6439
  }
5812
6440
 
5813
6441
  // src/external-installer.ts
5814
6442
  init_esm_shims();
5815
6443
  import { spawnSync } from "child_process";
5816
- import { existsSync as existsSync19, mkdirSync as mkdirSync5, readFileSync as readFileSync17, writeFileSync as writeFileSync7 } from "fs";
6444
+ import {
6445
+ accessSync,
6446
+ existsSync as existsSync19,
6447
+ constants as fsConstants,
6448
+ mkdirSync as mkdirSync6,
6449
+ readdirSync as readdirSync3,
6450
+ readFileSync as readFileSync17,
6451
+ renameSync as renameSync2,
6452
+ rmdirSync,
6453
+ rmSync as rmSync3
6454
+ } from "fs";
5817
6455
  import { homedir as homedir2 } from "os";
5818
- import { dirname as dirname5, join as join24 } from "path";
6456
+ import { dirname as dirname6, join as join25, relative as relative3, sep as sep4 } from "path";
5819
6457
  var SKILL_ROOTS = [".claude/skills", ".agents/skills"];
5820
6458
  function skillRootOf(cli) {
5821
6459
  return cli === "claude" ? ".claude/skills" : ".agents/skills";
@@ -5823,11 +6461,11 @@ function skillRootOf(cli) {
5823
6461
  function snapshotSkillRoots(projectDir) {
5824
6462
  const out = /* @__PURE__ */ new Map();
5825
6463
  for (const root of SKILL_ROOTS) {
5826
- if (outsideProjectTarget(projectDir, join24(projectDir, root)) !== null) continue;
5827
- for (const rel of listFilesRecursive(join24(projectDir, root))) {
6464
+ if (outsideProjectTarget(projectDir, join25(projectDir, root)) !== null) continue;
6465
+ for (const rel of listFilesRecursive(join25(projectDir, root))) {
5828
6466
  const path = `${root}/${rel}`;
5829
6467
  try {
5830
- out.set(path, hashContent(readFileSync17(join24(projectDir, path), "utf8")));
6468
+ out.set(path, hashContent(readFileSync17(join25(projectDir, path), "utf8")));
5831
6469
  } catch {
5832
6470
  }
5833
6471
  }
@@ -5904,7 +6542,7 @@ function installOne(asset, ctx) {
5904
6542
  return runSpawn(asset, ctx.spawn, "npx", buildSkillArgs(method, ctx.cli, ctx.scope), cwd);
5905
6543
  }
5906
6544
  const outside = SKILL_ROOTS.flatMap((root) => {
5907
- const hit = outsideProjectTarget(cwd, join24(cwd, root));
6545
+ const hit = outsideProjectTarget(cwd, join25(cwd, root));
5908
6546
  return hit === null ? [] : [{ root, target: hit.target }];
5909
6547
  });
5910
6548
  const outRoots = new Set(outside.map((o) => o.root));
@@ -5982,32 +6620,46 @@ function refreshExternalSkills(projectDir, deps = {}) {
5982
6620
  return { ...none, notInCatalog, unknown: false };
5983
6621
  }
5984
6622
  const targetIds = new Set(targets.map((a) => a.id));
5985
- const settle = holdSkillSlots(
5986
- projectDir,
5987
- log.assets.filter((a) => targetIds.has(a.id))
5988
- );
5989
- const report = (deps.run ?? runExternalInstall)(
5990
- {
5991
- tracks: log.spec.tracks,
5992
- // `forceInclude` 가 조건 판정을 앞지르므로 옵션 값은 결과에 영향을 주지 않는다.
5993
- options: DEFAULT_OPTIONS,
5994
- // #528 — 대상 CLI 는 **깔린 집합**(`installedClis`)이다. `spec.cli` 는 마지막 install 의
5995
- // 요청이라 `uninstall --cli` 뒤에도 뺀 CLI 를 말하고, 반대로 그걸 비우면 `buildSkillArgs` 가
5996
- // `--agent`·`--copy` 를 못 붙여 Claude 몫이 조용히 빠진다(재리뷰 BLOCKER-3).
5997
- cli: [...installedClis(log)],
5998
- userOverride: { forceInclude: [...installedIds], forceExclude: [] },
5999
- scope: log.scope,
6000
- projectDir
6001
- },
6002
- {
6003
- assets: targets,
6004
- ...deps.spawn ? { spawn: deps.spawn } : {},
6005
- ...deps.log ? { log: deps.log } : {},
6006
- ...deps.warn ? { warn: deps.warn } : {}
6623
+ const clis = [...installedClis(log)];
6624
+ const settle = holdSkillSlots(projectDir, {
6625
+ recorded: log.assets.filter((a) => targetIds.has(a.id)),
6626
+ slots: skillSlotsFor(targets, clis, { log, scope: log.scope }),
6627
+ log,
6628
+ clis,
6629
+ scope: log.scope
6630
+ });
6631
+ const run = deps.run ?? runExternalInstall;
6632
+ let ran;
6633
+ try {
6634
+ ran = run(
6635
+ {
6636
+ tracks: log.spec.tracks,
6637
+ // `forceInclude` 가 조건 판정을 앞지르므로 옵션 값은 결과에 영향을 주지 않는다.
6638
+ options: DEFAULT_OPTIONS,
6639
+ // #528 — 대상 CLI 는 **깔린 집합**(`installedClis`)이다. `spec.cli` 는 마지막 install 의
6640
+ // 요청이라 `uninstall --cli` 뒤에도 뺀 CLI 를 말하고, 반대로 그걸 비우면 `buildSkillArgs` 가
6641
+ // `--agent`·`--copy` 를 못 붙여 Claude 몫이 조용히 빠진다(재리뷰 BLOCKER-3).
6642
+ cli: clis,
6643
+ userOverride: { forceInclude: [...installedIds], forceExclude: [] },
6644
+ scope: log.scope,
6645
+ projectDir
6646
+ },
6647
+ {
6648
+ assets: targets,
6649
+ ...deps.spawn ? { spawn: deps.spawn } : {},
6650
+ ...deps.log ? { log: deps.log } : {},
6651
+ ...deps.warn ? { warn: deps.warn } : {}
6652
+ }
6653
+ );
6654
+ } catch (e2) {
6655
+ try {
6656
+ settle(null);
6657
+ } catch {
6007
6658
  }
6008
- );
6009
- settle();
6010
- recordRefreshedFiles(projectDir, log, report, deps.writeLog ?? writeInstallLog);
6659
+ throw e2;
6660
+ }
6661
+ const { report, displaced } = settle(ran);
6662
+ recordRefreshedFiles(projectDir, log, report, displaced, deps.writeLog ?? writeInstallLog);
6011
6663
  return {
6012
6664
  attempted: report.attempted.length,
6013
6665
  refreshed: report.succeeded,
@@ -6016,53 +6668,160 @@ function refreshExternalSkills(projectDir, deps = {}) {
6016
6668
  unknown: false
6017
6669
  };
6018
6670
  }
6019
- function holdSkillSlots(projectDir, assets) {
6020
- const held = assets.flatMap((a) => holdSlotFiles(projectDir, a.files));
6021
- return () => held.flatMap((h2) => settleHeld(h2) ?? []);
6671
+ function holdSkillSlots(projectDir, hold) {
6672
+ const now = /* @__PURE__ */ new Date();
6673
+ const asides = /* @__PURE__ */ new Map();
6674
+ const moved = [];
6675
+ try {
6676
+ for (const f of slotFilesToKeep(projectDir, hold)) {
6677
+ const root = dirname6(f.slot);
6678
+ let dir = asides.get(root);
6679
+ if (dir === void 0) {
6680
+ dir = claimBackupDir(join25(projectDir, root), now);
6681
+ asides.set(root, dir);
6682
+ }
6683
+ const aside = join25(dir, f.rel.slice(root.length + 1));
6684
+ mkdirSync6(dirname6(aside), { recursive: true });
6685
+ renameSync2(f.abs, aside);
6686
+ moved.push({ ...f, aside });
6687
+ }
6688
+ } catch (e2) {
6689
+ for (const f of moved) renameSync2(f.aside, f.abs);
6690
+ for (const dir of asides.values()) pruneEmptyDirs(dir);
6691
+ throw new Error(
6692
+ `could not move your files aside before the skill tool runs \u2014 nothing was changed: ${e2 instanceof Error ? e2.message : String(e2)}`
6693
+ );
6694
+ }
6695
+ return (report) => {
6696
+ const failedSlots = report === null ? null : skillSlotsFor(
6697
+ report.attempted.filter((r) => !r.ok).map((r) => r.asset),
6698
+ hold.clis,
6699
+ { log: hold.log, scope: hold.scope }
6700
+ );
6701
+ const out = { backups: [], displaced: [] };
6702
+ const back = /* @__PURE__ */ new Set();
6703
+ const failed = [];
6704
+ for (const f of moved) {
6705
+ const restore = failedSlots === null || failedSlots.some((s) => f.rel === s || f.rel.startsWith(`${s}/`));
6706
+ try {
6707
+ const r = settleAside(projectDir, f, restore);
6708
+ if (r === "back") {
6709
+ back.add(f.rel);
6710
+ continue;
6711
+ }
6712
+ out.backups.push(r.backup);
6713
+ if (r.displaced !== null) out.displaced.push(r.displaced);
6714
+ } catch (e2) {
6715
+ failed.push(`${f.rel} (${e2 instanceof Error ? e2.message : String(e2)})`);
6716
+ }
6717
+ }
6718
+ for (const dir of asides.values()) pruneEmptyDirs(dir);
6719
+ if (failed.length > 0) {
6720
+ const at5 = [...asides.values()].map((d2) => `${toProjectRel(projectDir, d2)}/`).join(", ");
6721
+ throw new Error(
6722
+ `could not put back ${failed.length} file(s) moved aside before the skill tool ran \u2014 they stay in ${at5}: ${failed.join(", ")}`
6723
+ );
6724
+ }
6725
+ return { ...out, report: report === null ? null : withoutCreated(report, back) };
6726
+ };
6022
6727
  }
6023
- function holdSlotFiles(projectDir, files) {
6024
- if (files === void 0) return [];
6025
- const sha = new Map(files.map((f) => [f.path, f.sha256]));
6026
- const slots = new Set(files.map((f) => f.path.split("/").slice(0, 3).join("/")));
6728
+ function skillSlotsFor(assets, clis, ctx) {
6729
+ if (resolveScope(ctx.scope) === "global") return [];
6730
+ const roots = clis.length === 0 ? [...SKILL_ROOTS] : [...new Set(clis.map(skillRootOf))];
6731
+ const out = /* @__PURE__ */ new Set();
6732
+ for (const a of assets) {
6733
+ if (a.method.kind !== "skill") continue;
6734
+ const prior = ctx.log?.assets.find((r) => r.id === a.id);
6735
+ if (prior !== void 0 && prior.files === void 0) continue;
6736
+ const skill = a.method.skill;
6737
+ for (const root of roots) out.add(skill === void 0 ? root : `${root}/${skill}`);
6738
+ }
6739
+ return [...out];
6740
+ }
6741
+ function slotFilesToKeep(projectDir, hold) {
6742
+ const mine = hold.recorded.flatMap((a) => a.files ?? []);
6743
+ const sha = new Map(mine.map((f) => [f.path, f.sha256]));
6744
+ const targetIds = new Set(hold.recorded.map((a) => a.id));
6745
+ const others = new Set(
6746
+ (hold.log?.assets ?? []).filter((a) => !targetIds.has(a.id)).flatMap((a) => (a.files ?? []).map((f) => f.path))
6747
+ );
6748
+ const slots = /* @__PURE__ */ new Set([
6749
+ ...mine.map((f) => f.path.split("/").slice(0, 3).join("/")),
6750
+ ...hold.slots
6751
+ ]);
6027
6752
  const out = [];
6753
+ const seen = /* @__PURE__ */ new Set();
6028
6754
  for (const slot of slots) {
6029
- if (outsideProjectTarget(projectDir, join24(projectDir, slot)) !== null) continue;
6030
- for (const rel of listFilesRecursive(join24(projectDir, slot))) {
6755
+ if (outsideProjectTarget(projectDir, join25(projectDir, slot)) !== null) continue;
6756
+ for (const rel of listFilesRecursive(join25(projectDir, slot))) {
6031
6757
  const path = `${slot}/${rel}`;
6032
- const abs = join24(projectDir, path);
6033
- let content;
6758
+ if (seen.has(path)) continue;
6759
+ seen.add(path);
6760
+ const recordedSha = sha.get(path);
6761
+ if (recordedSha === void 0 && (others.has(path) || recorded(hold.log, path).state !== "none"))
6762
+ continue;
6763
+ const abs = join25(projectDir, path);
6034
6764
  try {
6035
- content = readFileSync17(abs);
6765
+ if (recordedSha !== void 0 && hashContent(readFileSync17(abs, "utf8")) === recordedSha)
6766
+ continue;
6767
+ accessSync(abs, fsConstants.R_OK);
6036
6768
  } catch {
6037
6769
  continue;
6038
6770
  }
6039
- const recordedSha = sha.get(path);
6040
- if (recordedSha === void 0) out.push({ abs, content, recorded: false });
6041
- else if (hashContent(content.toString("utf8")) !== recordedSha)
6042
- out.push({ abs, content, recorded: true });
6771
+ out.push({ abs, rel: path, slot, recorded: recordedSha !== void 0 });
6043
6772
  }
6044
6773
  }
6045
6774
  return out;
6046
6775
  }
6047
- function settleHeld(h2) {
6776
+ function settleAside(projectDir, f, restore) {
6048
6777
  let now = null;
6049
6778
  try {
6050
- now = readFileSync17(h2.abs);
6051
- } catch {
6779
+ now = readFileSync17(f.abs);
6780
+ } catch (e2) {
6781
+ const code = e2.code;
6782
+ if (code !== "ENOENT" && code !== "ENOTDIR") throw e2;
6052
6783
  }
6053
- if (now?.equals(h2.content)) return null;
6054
- if (!h2.recorded && now === null) {
6055
- mkdirSync5(dirname5(h2.abs), { recursive: true });
6056
- writeFileSync7(h2.abs, h2.content);
6057
- return null;
6784
+ if (restore || (now === null ? !f.recorded : now.equals(readFileSync17(f.aside)))) {
6785
+ mkdirSync6(dirname6(f.abs), { recursive: true });
6786
+ renameSync2(f.aside, f.abs);
6787
+ return "back";
6788
+ }
6789
+ const backup = backupFromCopy(f.abs, f.aside);
6790
+ rmSync3(f.aside, { force: true });
6791
+ if (f.recorded || now === null) return { backup, displaced: null };
6792
+ return {
6793
+ backup,
6794
+ displaced: { path: f.rel, change: "displaced", notes: [toProjectRel(projectDir, backup)] }
6795
+ };
6796
+ }
6797
+ function withoutCreated(report, paths) {
6798
+ if (paths.size === 0) return report;
6799
+ return {
6800
+ ...report,
6801
+ attempted: report.attempted.map(
6802
+ (r) => r.files === void 0 ? r : {
6803
+ ...r,
6804
+ files: { ...r.files, created: r.files.created.filter((x) => !paths.has(x.path)) }
6805
+ }
6806
+ )
6807
+ };
6808
+ }
6809
+ function pruneEmptyDirs(dir) {
6810
+ try {
6811
+ for (const e2 of readdirSync3(dir, { withFileTypes: true }))
6812
+ if (e2.isDirectory()) pruneEmptyDirs(join25(dir, e2.name));
6813
+ rmdirSync(dir);
6814
+ } catch {
6058
6815
  }
6059
- return backupContent(h2.abs, h2.content);
6060
6816
  }
6061
- function recordRefreshedFiles(projectDir, log, report, writeLog) {
6817
+ function toProjectRel(projectDir, abs) {
6818
+ return relative3(projectDir, abs).split(sep4).join("/");
6819
+ }
6820
+ function recordRefreshedFiles(projectDir, log, report, displaced, writeLog) {
6062
6821
  const next = new Map(
6063
6822
  buildAssetEntries(report, log.scope, log.assets).filter((e2) => e2.files !== void 0).map((e2) => [e2.id, e2.files])
6064
6823
  );
6065
- let changed = false;
6824
+ let changed = displaced.length > 0;
6066
6825
  const assets = log.assets.map((a) => {
6067
6826
  const files = next.get(a.id);
6068
6827
  if (files === void 0 || JSON.stringify(files) === JSON.stringify(a.files)) return a;
@@ -6071,7 +6830,11 @@ function recordRefreshedFiles(projectDir, log, report, writeLog) {
6071
6830
  });
6072
6831
  if (!changed) return;
6073
6832
  try {
6074
- writeLog(projectDir, { ...log, assets });
6833
+ writeLog(projectDir, {
6834
+ ...log,
6835
+ assets,
6836
+ ...displaced.length > 0 ? { rootFiles: mergeRootFiles(log.rootFiles, displaced) } : {}
6837
+ });
6075
6838
  } catch {
6076
6839
  }
6077
6840
  }
@@ -6151,7 +6914,7 @@ function detectVersion(method, spawn, scope, projectDir) {
6151
6914
  case "plugin":
6152
6915
  return detectPluginVersion(method.pluginId, scope, projectDir);
6153
6916
  case "npm": {
6154
- const pkgJson = scope === "global" ? detectGlobalNpmPackageJsonPath(method.pkg, spawn) : join24(projectDir, "node_modules", method.pkg, "package.json");
6917
+ const pkgJson = scope === "global" ? detectGlobalNpmPackageJsonPath(method.pkg, spawn) : join25(projectDir, "node_modules", method.pkg, "package.json");
6155
6918
  if (!pkgJson || !existsSync19(pkgJson)) return void 0;
6156
6919
  const parsed = JSON.parse(readFileSync17(pkgJson, "utf8"));
6157
6920
  return parsed.version;
@@ -6165,7 +6928,7 @@ function detectVersion(method, spawn, scope, projectDir) {
6165
6928
  }
6166
6929
  function detectPluginVersion(pluginId, scope, projectDir) {
6167
6930
  const claudeScope = scope === "global" ? "user" : "project";
6168
- const path = join24(homedir2(), ".claude/plugins/installed_plugins.json");
6931
+ const path = join25(homedir2(), ".claude/plugins/installed_plugins.json");
6169
6932
  if (!existsSync19(path)) return void 0;
6170
6933
  const data = JSON.parse(readFileSync17(path, "utf8"));
6171
6934
  const entries = data.plugins?.[pluginId] ?? [];
@@ -6180,7 +6943,7 @@ function detectPluginVersion(pluginId, scope, projectDir) {
6180
6943
  }
6181
6944
  function detectGlobalNpmPackageJsonPath(pkg, spawn) {
6182
6945
  const npmRoot = getNpmGlobalRoot(spawn);
6183
- return npmRoot ? join24(npmRoot, pkg, "package.json") : void 0;
6946
+ return npmRoot ? join25(npmRoot, pkg, "package.json") : void 0;
6184
6947
  }
6185
6948
  var npmGlobalRootCache;
6186
6949
  function getNpmGlobalRoot(spawn) {
@@ -6200,7 +6963,7 @@ function getNpmGlobalRoot(spawn) {
6200
6963
  // src/key-ids.ts
6201
6964
  init_esm_shims();
6202
6965
  import { readFileSync as readFileSync18 } from "fs";
6203
- import { join as join25 } from "path";
6966
+ import { join as join26 } from "path";
6204
6967
  function renderedKeyIds(harnessRoot, input, clis) {
6205
6968
  const out = /* @__PURE__ */ new Set();
6206
6969
  const add = (path, key) => {
@@ -6223,7 +6986,7 @@ function renderedKeyIds(harnessRoot, input, clis) {
6223
6986
  for (const name of Object.keys(mcp.mcpServers)) add(".mcp.json", `mcpServers.${name}`);
6224
6987
  for (const key of gitignoreRender().keys()) add(".gitignore", key);
6225
6988
  if (clis.includes("claude")) {
6226
- const template = readFileSync18(join25(harnessRoot, "templates/settings.json"), "utf8");
6989
+ const template = readFileSync18(join26(harnessRoot, "templates/settings.json"), "utf8");
6227
6990
  for (const key of renderSettingsPortion(template, () => true).keys()) {
6228
6991
  add(".claude/settings.json", key);
6229
6992
  }
@@ -6264,7 +7027,7 @@ function withoutAccepts(harnessRoot, spec, previous) {
6264
7027
 
6265
7028
  // src/linked-skill-bodies.ts
6266
7029
  init_esm_shims();
6267
- import { join as join26 } from "path";
7030
+ import { join as join27 } from "path";
6268
7031
  function refreshLinkedSkillBodies(params) {
6269
7032
  const { harnessRoot, projectDir, ids, baseline, journal } = params;
6270
7033
  const bodyKey = (id) => `.agents/skills/${id}/SKILL.md`;
@@ -6275,7 +7038,7 @@ function refreshLinkedSkillBodies(params) {
6275
7038
  );
6276
7039
  const result = writer.result();
6277
7040
  return {
6278
- updated: ours.filter((id) => written.has(join26(projectDir, bodyKey(id)))),
7041
+ updated: ours.filter((id) => written.has(join27(projectDir, bodyKey(id)))),
6279
7042
  notOurs: ids.filter((id) => !baseline.has(bodyKey(id))),
6280
7043
  files: result.files,
6281
7044
  backupPaths: result.backupPaths,
@@ -6287,8 +7050,8 @@ function refreshLinkedSkillBodies(params) {
6287
7050
 
6288
7051
  // src/out-of-track.ts
6289
7052
  init_esm_shims();
6290
- import { lstatSync as lstatSync3, readFileSync as readFileSync19, rmSync as rmSync3 } from "fs";
6291
- import { join as join27 } from "path";
7053
+ import { lstatSync as lstatSync4, readFileSync as readFileSync19, rmSync as rmSync4 } from "fs";
7054
+ import { join as join28 } from "path";
6292
7055
  var AGENTS_RULE = /^\.agents\/rules\/([^/]+)\.md$/;
6293
7056
  var ANCHOR_RULE = "uzys-harness";
6294
7057
  function reclaimOutOfTrack(args) {
@@ -6308,9 +7071,9 @@ function reclaimOutOfTrack(args) {
6308
7071
  const name = AGENTS_RULE.exec(f.path)?.[1];
6309
7072
  if (name === void 0 || name === ANCHOR_RULE || rendered.has(name)) continue;
6310
7073
  if (isBaselineExcluded(`.claude/rules/${name}.md`, args.excluded)) continue;
6311
- const abs = join27(projectDir, f.path);
7074
+ const abs = join28(projectDir, f.path);
6312
7075
  if (args.outside.skip(abs)) continue;
6313
- const stat = lstatSync3(abs, { throwIfNoEntry: false });
7076
+ const stat = lstatSync4(abs, { throwIfNoEntry: false });
6314
7077
  if (stat !== void 0 && !stat.isFile()) continue;
6315
7078
  if (stat !== void 0 && claudeCopy.has(`rules/${name}.md`)) {
6316
7079
  out.kept.push(f.path);
@@ -6330,11 +7093,11 @@ function reclaimOutOfTrack(args) {
6330
7093
  out.bringBack[f.path] = tracksBringing(name);
6331
7094
  }
6332
7095
  if (verdict.verdict === "remove") {
6333
- rmSync3(abs);
7096
+ rmSync4(abs);
6334
7097
  out.removed.push(f.path);
6335
7098
  } else if (verdict.verdict === "backup+remove") {
6336
7099
  const backup = backupFile(abs, args.now);
6337
- rmSync3(abs);
7100
+ rmSync4(abs);
6338
7101
  out.backedUp.push({ path: f.path, backup });
6339
7102
  }
6340
7103
  }
@@ -6350,14 +7113,14 @@ function tracksBringing(rule) {
6350
7113
  // src/state.ts
6351
7114
  init_esm_shims();
6352
7115
  import { existsSync as existsSync20, readFileSync as readFileSync20 } from "fs";
6353
- import { join as join28 } from "path";
7116
+ import { join as join29 } from "path";
6354
7117
  var META_FILE = ".claude/.installed-tracks";
6355
7118
  var LEGACY_ANCHOR_FILE = ".claude/CLAUDE.md";
6356
7119
  var TRACE_RULES = ["htmx", "nextjs", "data-analysis", "pyside6", "cli-development"].map(
6357
7120
  (r) => `.claude/rules/${r}.md`
6358
7121
  );
6359
7122
  function detectInstallState(projectDir) {
6360
- const hasClaudeDir = existsSync20(join28(projectDir, ".claude"));
7123
+ const hasClaudeDir = existsSync20(join29(projectDir, ".claude"));
6361
7124
  const read = readInstallLogStatus(projectDir);
6362
7125
  if (read.status === "ok") {
6363
7126
  return {
@@ -6377,7 +7140,7 @@ function tracksFromLog(tracks) {
6377
7140
  return [...new Set(tracks.filter(isTrack))].sort();
6378
7141
  }
6379
7142
  function collectTraces(projectDir) {
6380
- const at5 = (rel) => join28(projectDir, rel);
7143
+ const at5 = (rel) => join29(projectDir, rel);
6381
7144
  const contains = (rel, needle) => existsSync20(at5(rel)) && readFileSync20(at5(rel), "utf8").includes(needle);
6382
7145
  const traces = [];
6383
7146
  if (existsSync20(at5(META_FILE)))
@@ -6437,16 +7200,16 @@ init_esm_shims();
6437
7200
  import {
6438
7201
  copyFileSync,
6439
7202
  existsSync as existsSync21,
6440
- lstatSync as lstatSync4,
6441
- mkdirSync as mkdirSync6,
6442
- readdirSync as readdirSync3,
7203
+ lstatSync as lstatSync5,
7204
+ mkdirSync as mkdirSync7,
7205
+ readdirSync as readdirSync4,
6443
7206
  readFileSync as readFileSync21,
6444
- rmdirSync,
7207
+ rmdirSync as rmdirSync2,
6445
7208
  statSync as statSync4,
6446
7209
  unlinkSync as unlinkSync2,
6447
- writeFileSync as writeFileSync8
7210
+ writeFileSync as writeFileSync7
6448
7211
  } from "fs";
6449
- import { basename as basename3, dirname as dirname6, join as join29 } from "path";
7212
+ import { basename as basename3, dirname as dirname7, join as join30 } from "path";
6450
7213
  var LEGACY_ANCHOR_FILE2 = ".claude/CLAUDE.md";
6451
7214
  function buildUpdateSpec(projectDir, tracks, only) {
6452
7215
  const log = readInstallLog(projectDir);
@@ -6468,7 +7231,7 @@ function parseUpdateOnly(raw) {
6468
7231
  return { ok: true, groups: [...new Set(raw)] };
6469
7232
  }
6470
7233
  function runUpdateMode(projectDir, templatesDir, harnessRoot, deps = {}, only) {
6471
- const claudeDir = join29(projectDir, ".claude");
7234
+ const claudeDir = join30(projectDir, ".claude");
6472
7235
  const startedAt = Date.now();
6473
7236
  const backupsAtStart = new Set(
6474
7237
  collectRunBackups(projectDir, Number.NEGATIVE_INFINITY).map((b2) => b2.backup)
@@ -6514,10 +7277,11 @@ function runUpdateMode(projectDir, templatesDir, harnessRoot, deps = {}, only) {
6514
7277
  const claudeDisplaced = [];
6515
7278
  report.claudeUnrecorded = !claudeManaged && logAtStart !== null && existsSync21(claudeDir) ? recordClaudeCommand(logAtStart, installedTracks(projectDir)) : null;
6516
7279
  const policyBase = policyBaseline(projectDir);
7280
+ const prunedPaths = /* @__PURE__ */ new Set();
6517
7281
  for (const { dir, ext } of POLICY_DIRS) {
6518
7282
  if (!claudeManaged || !wants(dir === "hooks" ? "hooks" : "rules")) continue;
6519
- const target = join29(claudeDir, dir);
6520
- const source = join29(templatesDir, dir);
7283
+ const target = join30(claudeDir, dir);
7284
+ const source = join30(templatesDir, dir);
6521
7285
  const label = `.claude/${dir}`;
6522
7286
  const ctx = {
6523
7287
  prefix: dir,
@@ -6533,6 +7297,7 @@ function runUpdateMode(projectDir, templatesDir, harnessRoot, deps = {}, only) {
6533
7297
  report.policyBackedUp.push(...synced.backedUp);
6534
7298
  claudeDisplaced.push(...synced.displaced);
6535
7299
  report.pruned[label] = pruneOrphans(target, source, ext, ctx);
7300
+ for (const f of report.pruned[label]) prunedPaths.add(`${label}/${f}`);
6536
7301
  }
6537
7302
  const syncedDirs = POLICY_DIRS.filter((d2) => wants(d2.dir === "hooks" ? "hooks" : "rules")).map(
6538
7303
  (d2) => d2.dir
@@ -6545,10 +7310,11 @@ function runUpdateMode(projectDir, templatesDir, harnessRoot, deps = {}, only) {
6545
7310
  outsidePaths(outside, ".claude/"),
6546
7311
  notOursUnder(claudeDisplaced, ".claude/")
6547
7312
  );
7313
+ const prunedRestored = logAtStart === null || prunedPaths.size === 0 ? [] : restoreDisplaced(logAtStart, projectDir, { has: (p2) => prunedPaths.has(p2), write: true });
6548
7314
  const skillTargets = logAtStart === null ? void 0 : recordedSkillIds(projectDir, logAtStart);
6549
7315
  const skillSync = claudeManaged && wants("skills") ? syncSkills(
6550
- join29(claudeDir, "skills"),
6551
- join29(templatesDir, "skills"),
7316
+ join30(claudeDir, "skills"),
7317
+ join30(templatesDir, "skills"),
6552
7318
  skillBaseline(projectDir),
6553
7319
  /* @__PURE__ */ new Date(),
6554
7320
  (relInSkills) => foreignOwnedTarget(projectDir, `.claude/skills/${relInSkills}`),
@@ -6585,7 +7351,8 @@ function runUpdateMode(projectDir, templatesDir, harnessRoot, deps = {}, only) {
6585
7351
  );
6586
7352
  else if (claudeManaged && copiedSkills.length > 0)
6587
7353
  recordNewSkillBaseline(projectDir, templatesDir, copiedSkills);
6588
- if (claudeDisplaced.length > 0) recordDisplaced(projectDir, claudeDisplaced);
7354
+ if (claudeDisplaced.length > 0 || prunedRestored.length > 0)
7355
+ recordDisplaced(projectDir, claudeDisplaced, prunedRestored);
6589
7356
  if (existsSync21(claudeDir) && claudeManaged) {
6590
7357
  if (wants("anchor")) syncHarnessAnchor(projectDir, templatesDir, report, outside);
6591
7358
  }
@@ -6605,7 +7372,7 @@ function runUpdateMode(projectDir, templatesDir, harnessRoot, deps = {}, only) {
6605
7372
  droppedKeys: legacyDroppedKeys(logAtStart),
6606
7373
  harnessMcp
6607
7374
  });
6608
- const settingsPath = join29(claudeDir, "settings.json");
7375
+ const settingsPath = join30(claudeDir, "settings.json");
6609
7376
  if (claudeManaged && wants("hooks") && existsSync21(settingsPath) && !outside.skip(settingsPath)) {
6610
7377
  report.retiredHookRefsRemoved = removeRetiredHookRefs(
6611
7378
  settingsPath,
@@ -6638,18 +7405,31 @@ function runUpdateMode(projectDir, templatesDir, harnessRoot, deps = {}, only) {
6638
7405
  restoredFiles: [],
6639
7406
  legacyRestored: [],
6640
7407
  anchorRetired: null,
7408
+ anchorDisplaced: [],
6641
7409
  agentsMd: null,
7410
+ agentsMdLegacyDropped: 0,
7411
+ agentsMdLegacyEdited: [],
6642
7412
  excludedKeys: [],
6643
7413
  sharedLeft: []
6644
7414
  };
7415
+ const outOfTrackRestored = [];
6645
7416
  if (wants("external")) {
6646
- const outOfTrack = reclaimOutOfTrackRecorded(projectDir, outside);
7417
+ const { reclaim: outOfTrack, displaced } = reclaimOutOfTrackRecorded(projectDir, outside);
6647
7418
  if (outOfTrack.removed.length + outOfTrack.backedUp.length + outOfTrack.kept.length > 0)
6648
7419
  report.outOfTrack = outOfTrack;
7420
+ outOfTrackRestored.push(...displaced);
6649
7421
  }
7422
+ const displacedRestored = [...prunedRestored, ...external.anchorDisplaced, ...outOfTrackRestored];
7423
+ if (displacedRestored.length > 0) report.displacedRestored = displacedRestored;
6650
7424
  report.externalUpdated = external.externalUpdated;
6651
7425
  if (external.anchorRetired !== null) report.anchorRetired = external.anchorRetired;
6652
7426
  if (external.agentsMd !== null) report.agentsMd = external.agentsMd;
7427
+ if (external.agentsMdLegacyDropped > 0) {
7428
+ report.agentsMdLegacyDropped = external.agentsMdLegacyDropped;
7429
+ }
7430
+ if (external.agentsMdLegacyEdited.length > 0) {
7431
+ report.agentsMdLegacyEdited = external.agentsMdLegacyEdited;
7432
+ }
6653
7433
  if (external.sharedLeft.length > 0) report.sharedLeft = external.sharedLeft;
6654
7434
  report.restoredKeys = external.restoredKeys;
6655
7435
  report.restoredFiles = external.restoredFiles;
@@ -6788,18 +7568,21 @@ function reclaimOutOfTrackRecorded(projectDir, outside) {
6788
7568
  excluded: excludedIds(log),
6789
7569
  outside
6790
7570
  });
7571
+ const left = /* @__PURE__ */ new Set([...result.removed, ...result.backedUp.map((b2) => b2.path)]);
7572
+ const displaced = log === null || left.size === 0 ? [] : restoreDisplaced(log, projectDir, { has: (p2) => left.has(p2), write: true });
6791
7573
  if (log !== null && result.forget.length > 0) {
6792
7574
  const forget = new Set(result.forget);
6793
7575
  const next = { ...log };
6794
7576
  const kept = (log.externalFiles ?? []).filter((f) => !forget.has(f.path));
6795
7577
  if (kept.length > 0) next.externalFiles = kept;
6796
7578
  else delete next.externalFiles;
7579
+ if (displaced.some((d2) => d2.forget)) next.rootFiles = withoutRestored(log.rootFiles, displaced);
6797
7580
  try {
6798
7581
  writeInstallLog(projectDir, next);
6799
7582
  } catch {
6800
7583
  }
6801
7584
  }
6802
- return result;
7585
+ return { reclaim: result, displaced };
6803
7586
  }
6804
7587
  function checksumOnRecord(log) {
6805
7588
  if (log === null) return () => false;
@@ -6820,7 +7603,7 @@ function retiredFeaturesPart(projectDir, f) {
6820
7603
  }
6821
7604
  function legacyHookOnDisk(projectDir, rel) {
6822
7605
  try {
6823
- return hasLegacyHarnessHook(readFileSync21(join29(projectDir, rel), "utf8"));
7606
+ return hasLegacyHarnessHook(readFileSync21(join30(projectDir, rel), "utf8"));
6824
7607
  } catch {
6825
7608
  return false;
6826
7609
  }
@@ -6846,7 +7629,7 @@ function writeUpdateSharedFiles(args) {
6846
7629
  excluded: adapterExcluded(harnessRoot, excluded)
6847
7630
  });
6848
7631
  const tracks = installedTracks(projectDir);
6849
- const settingsSource = join29(templatesDir, "settings.json");
7632
+ const settingsSource = join30(templatesDir, "settings.json");
6850
7633
  if (args.claudeManaged && wants("hooks") && existsSync21(settingsSource)) {
6851
7634
  const spec = buildAssetSpec({ tracks, options: DEFAULT_OPTIONS });
6852
7635
  const manifest = buildManifest(spec);
@@ -6857,7 +7640,7 @@ function writeUpdateSharedFiles(args) {
6857
7640
  log,
6858
7641
  (script) => {
6859
7642
  const target = `.claude/hooks/${script}`;
6860
- return manifest.some((e2) => e2.target === target && e2.applies(spec)) && !isBaselineExcluded(target, excluded) && existsSync21(join29(projectDir, target));
7643
+ return manifest.some((e2) => e2.target === target && e2.applies(spec)) && !isBaselineExcluded(target, excluded) && existsSync21(join30(projectDir, target));
6861
7644
  }
6862
7645
  // 기록이 claude 를 깔린 CLI 로 말한다 = install 이 이 파일을 썼다 — 없으면 만든다(훅 배선이 여기 산다)
6863
7646
  );
@@ -6921,30 +7704,30 @@ function catalogRemovedOnRecord(log) {
6921
7704
  }
6922
7705
  function staleSkillDirs(projectDir, claudeDir, clis) {
6923
7706
  const stale = (id) => RENAMED_SKILL_IDS[id] !== void 0 || RETIRED_SKILL_IDS.includes(id);
6924
- const dirs = [join29(claudeDir, "skills")];
6925
- if (clis.some((cli) => cli !== "claude")) dirs.push(join29(projectDir, ".agents", "skills"));
7707
+ const dirs = [join30(claudeDir, "skills")];
7708
+ if (clis.some((cli) => cli !== "claude")) dirs.push(join30(projectDir, ".agents", "skills"));
6926
7709
  const ids = /* @__PURE__ */ new Set();
6927
7710
  for (const dir of dirs) {
6928
7711
  if (!existsSync21(dir)) continue;
6929
- for (const e2 of readdirSync3(dir, { withFileTypes: true })) {
7712
+ for (const e2 of readdirSync4(dir, { withFileTypes: true })) {
6930
7713
  if (e2.isDirectory() && stale(e2.name)) ids.add(e2.name);
6931
7714
  }
6932
7715
  }
6933
7716
  return [...ids];
6934
7717
  }
6935
7718
  function staleAgentFiles(claudeDir) {
6936
- const dir = join29(claudeDir, "agents");
7719
+ const dir = join30(claudeDir, "agents");
6937
7720
  if (!existsSync21(dir)) return [];
6938
- return readdirSync3(dir, { withFileTypes: true }).filter((e2) => e2.isFile() && e2.name.endsWith(".md")).map((e2) => basename3(e2.name, ".md")).filter((id) => RETIRED_AGENT_IDS.includes(id));
7721
+ return readdirSync4(dir, { withFileTypes: true }).filter((e2) => e2.isFile() && e2.name.endsWith(".md")).map((e2) => basename3(e2.name, ".md")).filter((id) => RETIRED_AGENT_IDS.includes(id));
6939
7722
  }
6940
7723
  function demotedAgentFiles(claudeDir, tracks) {
6941
7724
  if (tracks.length === 0) return [];
6942
- const dir = join29(claudeDir, "agents");
7725
+ const dir = join30(claudeDir, "agents");
6943
7726
  if (!existsSync21(dir)) return [];
6944
7727
  const demoted = TRACK_AGENTS.filter(([, pattern]) => !anyTrack(tracks, pattern)).map(
6945
7728
  ([id]) => id
6946
7729
  );
6947
- return readdirSync3(dir, { withFileTypes: true }).filter((e2) => e2.isFile() && e2.name.endsWith(".md")).map((e2) => basename3(e2.name, ".md")).filter((id) => demoted.includes(id));
7730
+ return readdirSync4(dir, { withFileTypes: true }).filter((e2) => e2.isFile() && e2.name.endsWith(".md")).map((e2) => basename3(e2.name, ".md")).filter((id) => demoted.includes(id));
6948
7731
  }
6949
7732
  function installNewAssets(projectDir, templatesDir, wants, outside) {
6950
7733
  const installed = [];
@@ -6962,21 +7745,21 @@ function installNewAssets(projectDir, templatesDir, wants, outside) {
6962
7745
  if (!wants(group)) continue;
6963
7746
  if (entry.target === HARNESS_ANCHOR_FILE) continue;
6964
7747
  if (isBaselineExcluded(entry.target, baselineExcluded)) continue;
6965
- const target = join29(projectDir, entry.target);
7748
+ const target = join30(projectDir, entry.target);
6966
7749
  const foreign = foreignOwnedTarget(projectDir, entry.target);
6967
7750
  if (foreign !== null) {
6968
7751
  if (!foreignOwned.includes(foreign)) foreignOwned.push(foreign);
6969
7752
  continue;
6970
7753
  }
6971
7754
  if (existsSync21(target)) continue;
6972
- const source = join29(templatesDir, entry.source);
7755
+ const source = join30(templatesDir, entry.source);
6973
7756
  if (!existsSync21(source)) continue;
6974
7757
  if (outside.skip(target)) continue;
6975
7758
  if (entry.target.startsWith(".claude/")) {
6976
7759
  if (!claudeSelected) continue;
6977
7760
  if (entry.target === SETTINGS_TARGET) continue;
6978
7761
  }
6979
- mkdirSync6(dirname6(target), { recursive: true });
7762
+ mkdirSync7(dirname7(target), { recursive: true });
6980
7763
  copyFileSync(source, target);
6981
7764
  const recordedAs = entry.target.startsWith(".claude/") ? entry.target.slice(8) : entry.target;
6982
7765
  const wired = entry.target.startsWith(".claude/hooks/") && wiredBefore.has(entry.target.slice(".claude/hooks/".length));
@@ -6996,27 +7779,27 @@ function collectRunBackups(projectDir, startedAt, exclude) {
6996
7779
  const consider = (rel) => {
6997
7780
  if (!BACKUP_SUFFIX.test(rel)) return;
6998
7781
  if (exclude?.has(rel)) return;
6999
- const abs = join29(projectDir, rel);
7782
+ const abs = join30(projectDir, rel);
7000
7783
  if (statSync4(abs).mtimeMs < startedAt - 1e3) return;
7001
7784
  out.push({ path: rel.replace(BACKUP_SUFFIX, ""), backup: rel });
7002
7785
  };
7003
- for (const e2 of readdirSync3(projectDir, { withFileTypes: true }))
7786
+ for (const e2 of readdirSync4(projectDir, { withFileTypes: true }))
7004
7787
  if (e2.isFile()) consider(e2.name);
7005
7788
  for (const dir of BACKUP_SCAN_DIRS) {
7006
- for (const rel of listFilesRecursive(join29(projectDir, dir))) consider(`${dir}/${rel}`);
7789
+ for (const rel of listFilesRecursive(join30(projectDir, dir))) consider(`${dir}/${rel}`);
7007
7790
  }
7008
7791
  return out.sort((a, b2) => a.path.localeCompare(b2.path));
7009
7792
  }
7010
7793
  function writeBackupList(projectDir, backups, noChecksum = /* @__PURE__ */ new Set()) {
7011
- const dir = join29(projectDir, ".uzys-agent-harness");
7012
- const file = join29(dir, "update-backups.json");
7794
+ const dir = join30(projectDir, ".uzys-agent-harness");
7795
+ const file = join30(dir, "update-backups.json");
7013
7796
  try {
7014
7797
  if (backups.length === 0) {
7015
7798
  if (existsSync21(file)) unlinkSync2(file);
7016
7799
  return;
7017
7800
  }
7018
7801
  if (!existsSync21(dir)) return;
7019
- writeFileSync8(
7802
+ writeFileSync7(
7020
7803
  file,
7021
7804
  `${JSON.stringify(
7022
7805
  {
@@ -7047,14 +7830,14 @@ function installNewSkillDirs(projectDir, templatesDir, tracks, outside) {
7047
7830
  if (entry.type !== "dir" || !entry.target.startsWith(".claude/skills/")) continue;
7048
7831
  if (!entry.applies(spec) || isBaselineExcluded(entry.target, excluded)) continue;
7049
7832
  if (skillExcluded.has(entry.target.slice(".claude/skills/".length))) continue;
7050
- const target = join29(projectDir, entry.target);
7833
+ const target = join30(projectDir, entry.target);
7051
7834
  const foreign = foreignOwnedTarget(projectDir, entry.target);
7052
7835
  if (foreign !== null) {
7053
7836
  if (!foreignOwned.includes(foreign)) foreignOwned.push(foreign);
7054
7837
  continue;
7055
7838
  }
7056
7839
  if (existsSync21(target)) continue;
7057
- const source = join29(templatesDir, entry.source);
7840
+ const source = join30(templatesDir, entry.source);
7058
7841
  if (!existsSync21(source)) continue;
7059
7842
  if (outside.skip(target)) continue;
7060
7843
  copyDir(source, target, (rel) => foreignOwnedTarget(projectDir, `${entry.target}/${rel}`));
@@ -7086,12 +7869,12 @@ function trackOnlyFileAssets(tracks) {
7086
7869
  );
7087
7870
  }
7088
7871
  function syncHarnessAnchor(projectDir, templatesDir, report, outside, now = /* @__PURE__ */ new Date()) {
7089
- if (existsSync21(join29(projectDir, LEGACY_ANCHOR_FILE2))) {
7872
+ if (existsSync21(join30(projectDir, LEGACY_ANCHOR_FILE2))) {
7090
7873
  report.legacyAnchor = LEGACY_ANCHOR_FILE2;
7091
7874
  }
7092
- const templateMd = join29(templatesDir, "CLAUDE.md");
7875
+ const templateMd = join30(templatesDir, "CLAUDE.md");
7093
7876
  if (!existsSync21(templateMd)) return;
7094
- const anchor = join29(projectDir, HARNESS_ANCHOR_FILE);
7877
+ const anchor = join30(projectDir, HARNESS_ANCHOR_FILE);
7095
7878
  if (outside.skip(anchor)) return;
7096
7879
  const existed = existsSync21(anchor);
7097
7880
  if (existed) {
@@ -7117,7 +7900,7 @@ function syncHarnessAnchor(projectDir, templatesDir, report, outside, now = /* @
7117
7900
  recordAnchorBaseline(projectDir, anchor);
7118
7901
  }
7119
7902
  function upsertRootImport(projectDir, outside) {
7120
- const target = join29(projectDir, "CLAUDE.md");
7903
+ const target = join30(projectDir, "CLAUDE.md");
7121
7904
  if (outside.skip(target)) return false;
7122
7905
  const existing = existsSync21(target) ? readFileSync21(target, "utf8") : null;
7123
7906
  const next = upsertHarnessImport(existing, {
@@ -7126,12 +7909,12 @@ function upsertRootImport(projectDir, outside) {
7126
7909
  // ADR-085 — update 는 선택 목록을 인자로 받지 않는다. `syncSkills` 와 같은 판정을 쓴다:
7127
7910
  // `.claude/skills/<id>` 가 있으면 그 스킬은 이 설치가 고른 것이다.
7128
7911
  continuousSkills: CONTINUOUS_SKILLS.map((s) => s.id).filter(
7129
- (id) => existsSync21(join29(projectDir, ".claude/skills", id))
7912
+ (id) => existsSync21(join30(projectDir, ".claude/skills", id))
7130
7913
  )
7131
7914
  });
7132
7915
  if (next === existing) return false;
7133
7916
  if (existing !== null) backupIfLossyUtf8(target);
7134
- writeFileSync8(target, next);
7917
+ writeFileSync7(target, next);
7135
7918
  return true;
7136
7919
  }
7137
7920
  function installedTracks(projectDir) {
@@ -7161,7 +7944,7 @@ function excludedBaselineOnDisk(projectDir, log) {
7161
7944
  if (excluded.size === 0) return [];
7162
7945
  const spec = buildAssetSpec({ tracks: installedTracks(projectDir), options: DEFAULT_OPTIONS });
7163
7946
  return buildManifest(spec).filter(
7164
- (e2) => e2.applies(spec) && isBaselineExcluded(e2.target, excluded) && existsSync21(join29(projectDir, e2.target))
7947
+ (e2) => e2.applies(spec) && isBaselineExcluded(e2.target, excluded) && existsSync21(join30(projectDir, e2.target))
7165
7948
  ).map((e2) => e2.target);
7166
7949
  }
7167
7950
  function excludedSkillOf(log) {
@@ -7189,7 +7972,7 @@ function recordedRenderInputs(projectDir, log) {
7189
7972
  function recordedBundledSkills(projectDir, log) {
7190
7973
  if (log === null) {
7191
7974
  return INTERNAL_BUNDLED_SKILL_IDS.filter(
7192
- (id) => existsSync21(join29(projectDir, ".claude/skills", id)) || existsSync21(join29(projectDir, ".agents/skills", id))
7975
+ (id) => existsSync21(join30(projectDir, ".claude/skills", id)) || existsSync21(join30(projectDir, ".agents/skills", id))
7193
7976
  );
7194
7977
  }
7195
7978
  const ids = recordedSkillIds(projectDir, log);
@@ -7236,9 +8019,9 @@ var SHARED_SKILLS_DIR = ".agents/skills";
7236
8019
  var SHARED_SKILL_FILE = /^\.agents\/skills\/([^/]+)\//;
7237
8020
  var SHARED_SKILL_MD = /^\.agents\/skills\/([^/]+)\/SKILL\.md$/;
7238
8021
  function sharedSkillIdsOnDisk(projectDir) {
7239
- const root = join29(projectDir, SHARED_SKILLS_DIR);
8022
+ const root = join30(projectDir, SHARED_SKILLS_DIR);
7240
8023
  if (!existsSync21(root)) return /* @__PURE__ */ new Set();
7241
- return new Set(readdirSync3(root).filter((id) => existsSync21(join29(root, id, "SKILL.md"))));
8024
+ return new Set(readdirSync4(root).filter((id) => existsSync21(join30(root, id, "SKILL.md"))));
7242
8025
  }
7243
8026
  var CREATED_SHARED_HOW = {
7244
8027
  "opencode.json": "created from template (harness part + template defaults)",
@@ -7265,14 +8048,14 @@ function refreshExternalCli(projectDir, harnessRoot, droppedKeys, harnessMcp) {
7265
8048
  const log = readInstallLog(projectDir);
7266
8049
  const presentBefore = sharedSkillIdsOnDisk(projectDir);
7267
8050
  const rulesBefore = /* @__PURE__ */ new Set();
7268
- const rulesDir = join29(projectDir, ".agents", "rules");
8051
+ const rulesDir = join30(projectDir, ".agents", "rules");
7269
8052
  if (existsSync21(rulesDir)) {
7270
8053
  try {
7271
- for (const f of readdirSync3(rulesDir)) rulesBefore.add(f);
8054
+ for (const f of readdirSync4(rulesDir)) rulesBefore.add(f);
7272
8055
  } catch {
7273
8056
  }
7274
8057
  }
7275
- const agentsMdBefore = existsSync21(join29(projectDir, "AGENTS.md"));
8058
+ const agentsMdBefore = existsSync21(join30(projectDir, "AGENTS.md"));
7276
8059
  const result = runCliTransforms({
7277
8060
  harnessRoot,
7278
8061
  projectDir,
@@ -7293,6 +8076,8 @@ function refreshExternalCli(projectDir, harnessRoot, droppedKeys, harnessMcp) {
7293
8076
  // 앞 단계(`refreshNeutralHelpers`)가 헬퍼만 든 `externalFiles` 를 적어도 같은 답이다 — 헬퍼는 외부 자리로 세지 않는다(B-2)
7294
8077
  owned: recordedOwner(log)
7295
8078
  });
8079
+ const anchorPath = result.anchorRetired?.action === "removed" ? result.anchorRetired.path : null;
8080
+ const anchorDisplaced = log === null || anchorPath === null ? [] : restoreDisplaced(log, projectDir, { has: (p2) => p2 === anchorPath, write: true });
7296
8081
  if (log) {
7297
8082
  const retiredPath = result.anchorRetired?.forget === true ? result.anchorRetired.path : null;
7298
8083
  const merged = mergeExternalFiles(log.externalFiles, result.externalFiles).filter(
@@ -7311,6 +8096,8 @@ function refreshExternalCli(projectDir, harnessRoot, droppedKeys, harnessMcp) {
7311
8096
  const created = result.sharedFiles.filter((f) => f.createdAsRoot === true).map((f) => ({ path: f.path, change: "created", notes: ["\uD558\uB124\uC2A4 \uBAAB\uB9CC(\uBE14\uB85D)"] }));
7312
8097
  const roots = [...created, ...withoutLostBackups(log.rootFiles, result.displaced ?? [])];
7313
8098
  if (roots.length > 0) next.rootFiles = mergeRootFiles(log.rootFiles, roots);
8099
+ if (anchorDisplaced.some((d2) => d2.forget))
8100
+ next.rootFiles = withoutRestored(next.rootFiles, anchorDisplaced);
7314
8101
  try {
7315
8102
  writeInstallLog(projectDir, next);
7316
8103
  } catch {
@@ -7390,7 +8177,10 @@ function refreshExternalCli(projectDir, harnessRoot, droppedKeys, harnessMcp) {
7390
8177
  )
7391
8178
  ],
7392
8179
  anchorRetired: result.anchorRetired,
8180
+ anchorDisplaced,
7393
8181
  agentsMd: agentsMdNews(result.agentsMd, agentsMdBefore, priorPaths),
8182
+ agentsMdLegacyDropped: result.agentsMd?.agentsMd.droppedLegacySections ?? 0,
8183
+ agentsMdLegacyEdited: result.agentsMd?.agentsMd.editedLegacySections ?? [],
7394
8184
  // #625 — install 화면(`sharedRow`)이 말하는 "남긴 것" 을 update 도 말한다. 고친 구간과 기록이 없어 모르는 구간은
7395
8185
  // 다른 사실이라 기록(`portions`)으로 가른다 — 어댑터는 기록된 키가 고쳐졌으면 남기고 기록 sha 를 잇는다(계약 ⓑ)
7396
8186
  sharedLeft: result.sharedFiles.filter((f) => f.action === "left" || f.leftAsIs.length + f.kept.length > 0).map((f) => {
@@ -7416,10 +8206,10 @@ function updateDir(target, source, ext, ctx, now = /* @__PURE__ */ new Date()) {
7416
8206
  let updated = 0;
7417
8207
  const backedUp = [];
7418
8208
  const displaced = [];
7419
- for (const file of readdirSync3(target)) {
8209
+ for (const file of readdirSync4(target)) {
7420
8210
  if (!file.endsWith(ext)) continue;
7421
- const targetFile = join29(target, file);
7422
- const sourceFile = join29(source, file);
8211
+ const targetFile = join30(target, file);
8212
+ const sourceFile = join30(source, file);
7423
8213
  if (!existsSync21(sourceFile)) continue;
7424
8214
  if (ctx.outside?.skip(targetFile)) continue;
7425
8215
  const projectRel = `.claude/${ctx.prefix}/${file}`;
@@ -7451,9 +8241,9 @@ function syncSkills(targetDir, sourceDir, baseline, now = /* @__PURE__ */ new Da
7451
8241
  const foreignOwned = [];
7452
8242
  const pruned = [];
7453
8243
  const displaced = [];
7454
- for (const skill of readdirSync3(sourceDir, { withFileTypes: true })) {
8244
+ for (const skill of readdirSync4(sourceDir, { withFileTypes: true })) {
7455
8245
  if (!skill.isDirectory()) continue;
7456
- const targetSkill = join29(targetDir, skill.name);
8246
+ const targetSkill = join30(targetDir, skill.name);
7457
8247
  if (occupiedByNonDirectory(targetSkill)) {
7458
8248
  skippedLinks.push(skill.name);
7459
8249
  continue;
@@ -7461,15 +8251,15 @@ function syncSkills(targetDir, sourceDir, baseline, now = /* @__PURE__ */ new Da
7461
8251
  if (opts.targets !== void 0 && !opts.targets.has(skill.name)) continue;
7462
8252
  if (!existsSync21(targetSkill)) continue;
7463
8253
  if (excludedSkill?.(skill.name)) continue;
7464
- for (const rel of listFilesRecursive(join29(sourceDir, skill.name))) {
7465
- const targetFile = join29(targetSkill, rel);
8254
+ for (const rel of listFilesRecursive(join30(sourceDir, skill.name))) {
8255
+ const targetFile = join30(targetSkill, rel);
7466
8256
  const foreign = foreignOf(`${skill.name}/${rel}`);
7467
8257
  if (foreign !== null) {
7468
8258
  if (!foreignOwned.includes(foreign)) foreignOwned.push(foreign);
7469
8259
  continue;
7470
8260
  }
7471
8261
  if (outside?.skip(targetFile)) continue;
7472
- const next = readFileSync21(join29(sourceDir, skill.name, rel), "utf8");
8262
+ const next = readFileSync21(join30(sourceDir, skill.name, rel), "utf8");
7473
8263
  const projectRel = `.claude/skills/${skill.name}/${rel}`;
7474
8264
  const rec = opts.recordOf?.(projectRel) ?? baselineRecord(baseline, `${skill.name}/${rel}`);
7475
8265
  const w3 = judgedUpdateWrite(targetFile, rec, next, now);
@@ -7478,11 +8268,11 @@ function syncSkills(targetDir, sourceDir, baseline, now = /* @__PURE__ */ new Da
7478
8268
  const d2 = displacedEntry(w3, projectRel, targetFile);
7479
8269
  if (d2 !== null) displaced.push(d2);
7480
8270
  }
7481
- const bundled = new Set(listFilesRecursive(join29(sourceDir, skill.name)));
8271
+ const bundled = new Set(listFilesRecursive(join30(sourceDir, skill.name)));
7482
8272
  for (const rel of listFilesRecursive(targetSkill)) {
7483
8273
  if (bundled.has(rel) || basename3(rel).includes(".backup-")) continue;
7484
8274
  if (foreignOf(`${skill.name}/${rel}`) !== null) continue;
7485
- const targetFile = join29(targetSkill, rel);
8275
+ const targetFile = join30(targetSkill, rel);
7486
8276
  if (outside?.skip(targetFile)) continue;
7487
8277
  const rec = opts.recordOf?.(`.claude/skills/${skill.name}/${rel}`) ?? baselineRecord(baseline, `${skill.name}/${rel}`);
7488
8278
  if (rec.state !== "sha" || hashContent(readFileSync21(targetFile, "utf8")) !== rec.sha256) {
@@ -7491,8 +8281,8 @@ function syncSkills(targetDir, sourceDir, baseline, now = /* @__PURE__ */ new Da
7491
8281
  }
7492
8282
  unlinkSync2(targetFile);
7493
8283
  pruned.push(`${skill.name}/${rel}`);
7494
- for (let d2 = dirname6(targetFile); d2 !== targetSkill && readdirSync3(d2).length === 0; d2 = dirname6(d2))
7495
- rmdirSync(d2);
8284
+ for (let d2 = dirname7(targetFile); d2 !== targetSkill && readdirSync4(d2).length === 0; d2 = dirname7(d2))
8285
+ rmdirSync2(d2);
7496
8286
  }
7497
8287
  }
7498
8288
  return { updated, backedUp, skippedLinks, foreignOwned, pruned, displaced };
@@ -7505,15 +8295,15 @@ function judgedUpdateWrite(abs, rec, next, now) {
7505
8295
  case "leave":
7506
8296
  break;
7507
8297
  case "create":
7508
- mkdirSync6(dirname6(abs), { recursive: true });
7509
- writeFileSync8(abs, next);
8298
+ mkdirSync7(dirname7(abs), { recursive: true });
8299
+ writeFileSync7(abs, next);
7510
8300
  break;
7511
8301
  case "overwrite":
7512
- writeFileSync8(abs, next);
8302
+ writeFileSync7(abs, next);
7513
8303
  break;
7514
8304
  case "backup+overwrite":
7515
8305
  backup = backupFile(abs, now);
7516
- writeFileSync8(abs, next);
8306
+ writeFileSync7(abs, next);
7517
8307
  break;
7518
8308
  default:
7519
8309
  throw new Error(`update: '${j4.verdict}' is not a write verdict (${abs})`);
@@ -7549,13 +8339,15 @@ function withoutLostBackups(prior, add) {
7549
8339
  );
7550
8340
  return add.filter((f) => f.notes.length > 0 || !backedUp.has(f.path));
7551
8341
  }
7552
- function recordDisplaced(projectDir, displaced) {
8342
+ function recordDisplaced(projectDir, displaced, restored = []) {
7553
8343
  const log = readInstallLog(projectDir);
7554
8344
  if (!log) return;
7555
8345
  const add = withoutLostBackups(log.rootFiles, displaced);
7556
- if (add.length === 0) return;
8346
+ const settles = restored.some((d2) => d2.forget);
8347
+ if (add.length === 0 && !settles) return;
8348
+ const merged = add.length === 0 ? [...log.rootFiles ?? []] : mergeRootFiles(log.rootFiles, add);
7557
8349
  try {
7558
- writeInstallLog(projectDir, { ...log, rootFiles: mergeRootFiles(log.rootFiles, add) });
8350
+ writeInstallLog(projectDir, { ...log, rootFiles: withoutRestored(merged, restored) });
7559
8351
  } catch {
7560
8352
  }
7561
8353
  }
@@ -7615,11 +8407,11 @@ function refreshSkillBaseline(projectDir, templatesDir, outside, targets, notOur
7615
8407
  function pruneOrphans(target, source, ext, ctx, now = /* @__PURE__ */ new Date()) {
7616
8408
  if (!existsSync21(target) || !existsSync21(source)) return [];
7617
8409
  const removed = [];
7618
- for (const file of readdirSync3(target)) {
8410
+ for (const file of readdirSync4(target)) {
7619
8411
  if (!file.endsWith(ext)) continue;
7620
- const sourceFile = join29(source, file);
8412
+ const sourceFile = join30(source, file);
7621
8413
  if (!existsSync21(sourceFile)) {
7622
- const targetFile = join29(target, file);
8414
+ const targetFile = join30(target, file);
7623
8415
  const key = `${ctx.prefix}/${file}`;
7624
8416
  if (!ctx.baseline.has(key)) continue;
7625
8417
  if (ctx.outside?.skip(targetFile)) continue;
@@ -7636,7 +8428,7 @@ function pruneOrphans(target, source, ext, ctx, now = /* @__PURE__ */ new Date()
7636
8428
  return removed;
7637
8429
  }
7638
8430
  function retireMcpAllowlist(projectDir, now = /* @__PURE__ */ new Date()) {
7639
- const target = join29(projectDir, ".mcp-allowlist");
8431
+ const target = join30(projectDir, ".mcp-allowlist");
7640
8432
  if (!existsSync21(target)) return null;
7641
8433
  try {
7642
8434
  const backup = backupFile(target, now);
@@ -7652,12 +8444,12 @@ function refreshNeutralHelpers(projectDir, templatesDir, report) {
7652
8444
  for (const entry of buildManifest(spec)) {
7653
8445
  if (entry.type !== "file" || !isCliNeutralTarget(entry.target)) continue;
7654
8446
  if (!entry.applies(spec)) continue;
7655
- const abs = join29(projectDir, entry.target);
7656
- const source = join29(templatesDir, entry.source);
8447
+ const abs = join30(projectDir, entry.target);
8448
+ const source = join30(templatesDir, entry.source);
7657
8449
  if (!existsSync21(source)) continue;
7658
8450
  let st2;
7659
8451
  try {
7660
- st2 = lstatSync4(abs);
8452
+ st2 = lstatSync5(abs);
7661
8453
  } catch {
7662
8454
  continue;
7663
8455
  }
@@ -7676,7 +8468,7 @@ function refreshNeutralHelpers(projectDir, templatesDir, report) {
7676
8468
  continue;
7677
8469
  }
7678
8470
  if (recorded2 === void 0 || recorded2.sha256 !== diskSha) backupFile(abs);
7679
- writeFileSync8(abs, freshContent, "utf8");
8471
+ writeFileSync7(abs, freshContent, "utf8");
7680
8472
  refreshed.set(entry.target, freshSha);
7681
8473
  report.updated[entry.target] = (report.updated[entry.target] ?? 0) + 1;
7682
8474
  }
@@ -7705,11 +8497,11 @@ function recordClaudeCommand(log, tracks) {
7705
8497
  function runInstall(ctx) {
7706
8498
  const { harnessRoot, projectDir } = ctx;
7707
8499
  const mode = ctx.mode ?? "fresh";
7708
- const templatesDir = join30(harnessRoot, "templates");
8500
+ const templatesDir = join31(harnessRoot, "templates");
7709
8501
  if (!existsSync22(templatesDir)) {
7710
8502
  throw new Error(`Templates dir not found: ${templatesDir}`);
7711
8503
  }
7712
- const claudeDir = join30(projectDir, ".claude");
8504
+ const claudeDir = join31(projectDir, ".claude");
7713
8505
  const previousLog = readInstallLog(projectDir);
7714
8506
  const legacyAnchor = mode === "update" ? null : legacyAnchorTrace(projectDir, ctx.spec);
7715
8507
  if (mode === "update" && previousLog === null) {
@@ -7734,13 +8526,13 @@ function runInstall(ctx) {
7734
8526
  const manifestSpec = buildManifestSpec(spec);
7735
8527
  const baselineExcluded = new Set(spec.baselineExclude ?? []);
7736
8528
  if (spec.cli.includes("claude")) {
7737
- const settingsPath = join30(projectDir, ".claude", "settings.json");
8529
+ const settingsPath = join31(projectDir, ".claude", "settings.json");
7738
8530
  if (existsSync22(settingsPath)) {
7739
8531
  try {
7740
8532
  JSON.parse(readFileSync22(settingsPath, "utf8"));
7741
8533
  } catch {
7742
8534
  throw new Error(
7743
- `${relative3(process.cwd(), settingsPath)} is not valid JSON \u2014 left untouched, so no hooks were wired. Fix or delete that file, then run the install again`
8535
+ `${relative4(process.cwd(), settingsPath)} is not valid JSON \u2014 left untouched, so no hooks were wired. Fix or delete that file, then run the install again`
7744
8536
  );
7745
8537
  }
7746
8538
  }
@@ -7874,10 +8666,17 @@ function runInstallStages(ctx, args) {
7874
8666
  ...outOfTrack.forget,
7875
8667
  ...anchorRetired?.forget === true ? [anchorRetired.path] : []
7876
8668
  ]);
8669
+ const left = /* @__PURE__ */ new Set([
8670
+ ...outOfTrack.removed,
8671
+ ...outOfTrack.backedUp.map((b2) => b2.path),
8672
+ ...anchorRetired?.action === "removed" ? [anchorRetired.path] : []
8673
+ ]);
8674
+ const displacedRestored = previousLog === null || left.size === 0 ? [] : restoreDisplaced(previousLog, projectDir, { has: (p2) => left.has(p2), write: true });
7877
8675
  const logBase = previousLog === null || forgotten.size === 0 ? previousLog : {
7878
8676
  ...previousLog,
7879
8677
  spec: { ...previousLog.spec, clis: [...installedClis(previousLog)] },
7880
- externalFiles: (previousLog.externalFiles ?? []).filter((f) => !forgotten.has(f.path))
8678
+ externalFiles: (previousLog.externalFiles ?? []).filter((f) => !forgotten.has(f.path)),
8679
+ ...displacedRestored.some((d2) => d2.forget) ? { rootFiles: withoutRestored(previousLog.rootFiles, displacedRestored) } : {}
7881
8680
  };
7882
8681
  stage.envExampleCreated = writeEnvExample(projectDir, spec.tracks);
7883
8682
  const envFiles = writeEnvironmentFiles(writer, stage.envExampleCreated, previousLog);
@@ -7937,10 +8736,15 @@ function runInstallStages(ctx, args) {
7937
8736
  linked.outside,
7938
8737
  reclaimOutside.list()
7939
8738
  ),
7940
- ...outOfTrack.removed.length + outOfTrack.backedUp.length + outOfTrack.kept.length > 0 ? { outOfTrack } : {}
8739
+ ...outOfTrack.removed.length + outOfTrack.backedUp.length + outOfTrack.kept.length > 0 ? { outOfTrack } : {},
8740
+ ...displacedRestored.length > 0 ? { displacedRestored } : {}
7941
8741
  };
7942
8742
  ctx.onProgress?.({ type: "baseline-complete", baseline });
7943
- const { report: external, backups: externalSkillBackups } = runExternalPhase(ctx, previousLog);
8743
+ const {
8744
+ report: external,
8745
+ backups: externalSkillBackups,
8746
+ displaced: externalSkillDisplaced
8747
+ } = runExternalPhase(ctx, previousLog);
7944
8748
  writeInstallLogSafe(
7945
8749
  ctx,
7946
8750
  // 링크 본문의 기준선도 같은 필드다 — 같은 경로면 뒤(이번에 쓴 값)가 이긴다.
@@ -7956,7 +8760,9 @@ function runInstallStages(ctx, args) {
7956
8760
  ...cliSharedFiles.filter((f) => f.createdAsRoot === true).map((f) => ({ path: f.path, change: "created", notes: ["\uD558\uB124\uC2A4 \uBAAB\uB9CC(\uBE14\uB85D)"] })),
7957
8761
  // #761 — 외부 변환 · 링크 본문이 첫 접촉으로 비켜 둔 설치자 파일. 하네스가 떠날 때 되돌리는 근거다
7958
8762
  ...cliDisplaced,
7959
- ...linked.displaced
8763
+ ...linked.displaced,
8764
+ // #780 — 외부 스킬 도구가 덮은 설치자 파일. 그 자리의 도구 파일은 `buildAssetEntries` 가 이 경로로 자산 몫에 넣는다
8765
+ ...externalSkillDisplaced
7960
8766
  ],
7961
8767
  cliTransforms.codexOptIn
7962
8768
  );
@@ -8018,7 +8824,7 @@ function releasedThisRun(args) {
8018
8824
  }
8019
8825
  if (id.startsWith(BASELINE_PREFIX)) {
8020
8826
  const again2 = manifest.some(
8021
- (e2) => e2.applies(manifestSpec) && classifyBaselineTarget(e2.target)?.id === id && existsSync22(join30(projectDir, e2.target))
8827
+ (e2) => e2.applies(manifestSpec) && classifyBaselineTarget(e2.target)?.id === id && existsSync22(join31(projectDir, e2.target))
8022
8828
  );
8023
8829
  return { id, again: again2, tail: "the harness manages it again" };
8024
8830
  }
@@ -8027,7 +8833,7 @@ function releasedThisRun(args) {
8027
8833
  options: spec.options,
8028
8834
  ...spec.userOverride ? { userOverride: spec.userOverride } : {}
8029
8835
  });
8030
- const recorded2 = (previousLog?.assets.some((a) => a.id === id) ?? false) || [".claude/skills", ".agents/skills"].some((d2) => existsSync22(join30(projectDir, d2, id)));
8836
+ const recorded2 = (previousLog?.assets.some((a) => a.id === id) ?? false) || [".claude/skills", ".agents/skills"].some((d2) => existsSync22(join31(projectDir, d2, id)));
8031
8837
  return {
8032
8838
  id,
8033
8839
  again,
@@ -8039,10 +8845,10 @@ function pendingKeyExcludes(projectDir, keyExclude, touched) {
8039
8845
  const done = new Set(touched);
8040
8846
  return keyExclude.flatMap((id) => {
8041
8847
  const path = sharedPathOfKeyId(id);
8042
- if (path === null || done.has(path) || !existsSync22(join30(projectDir, path))) return [];
8848
+ if (path === null || done.has(path) || !existsSync22(join31(projectDir, path))) return [];
8043
8849
  const name = adapterFor(path);
8044
8850
  const keys = [...excludedKeys(path, [id])];
8045
- const present2 = name === null ? null : ADAPTERS[name].read(readFileSync22(join30(projectDir, path), "utf8"), keys, projectDir);
8851
+ const present2 = name === null ? null : ADAPTERS[name].read(readFileSync22(join31(projectDir, path), "utf8"), keys, projectDir);
8046
8852
  return present2 !== null && present2.size === 0 ? [] : [{ id, path }];
8047
8853
  });
8048
8854
  }
@@ -8086,7 +8892,7 @@ function installCliNeutralAssets(manifestSpec, templatesDir, baselineExcluded, w
8086
8892
  continue;
8087
8893
  }
8088
8894
  if (!isCliNeutralTarget(entry.target)) continue;
8089
- const source = join30(templatesDir, entry.source);
8895
+ const source = join31(templatesDir, entry.source);
8090
8896
  if (!existsSync22(source)) {
8091
8897
  result.skipped += 1;
8092
8898
  continue;
@@ -8107,13 +8913,13 @@ function installClaudeBaseline(manifestSpec, projectDir, templatesDir, baselineE
8107
8913
  if (!entry.applies(manifestSpec)) {
8108
8914
  continue;
8109
8915
  }
8110
- const target = join30(projectDir, entry.target);
8916
+ const target = join31(projectDir, entry.target);
8111
8917
  if (isBaselineExcluded(entry.target, baselineExcluded)) {
8112
8918
  result.excluded.push(entry.target);
8113
8919
  if (existsSync22(target)) result.excludedOnDisk.push(entry.target);
8114
8920
  continue;
8115
8921
  }
8116
- const source = join30(templatesDir, entry.source);
8922
+ const source = join31(templatesDir, entry.source);
8117
8923
  if (!existsSync22(source)) {
8118
8924
  result.skipped += 1;
8119
8925
  continue;
@@ -8144,18 +8950,18 @@ function installClaudeBaseline(manifestSpec, projectDir, templatesDir, baselineE
8144
8950
  if (!result.foreignOwned.includes(slot)) result.foreignOwned.push(slot);
8145
8951
  continue;
8146
8952
  }
8147
- if (writer.skipOutside(join30(projectDir, entry.target, rel))) {
8953
+ if (writer.skipOutside(join31(projectDir, entry.target, rel))) {
8148
8954
  leftOutside += 1;
8149
8955
  continue;
8150
8956
  }
8151
- writer.harness(`${entry.target}/${rel}`, { source: join30(source, rel) });
8957
+ writer.harness(`${entry.target}/${rel}`, { source: join31(source, rel) });
8152
8958
  }
8153
8959
  if (leftOutside > 0) continue;
8154
8960
  result.dirsCopied += 1;
8155
8961
  }
8156
8962
  accumulateCategory(result.categories, entry);
8157
8963
  }
8158
- const hookDir = join30(projectDir, ".claude/hooks");
8964
+ const hookDir = join31(projectDir, ".claude/hooks");
8159
8965
  if (existsSync22(hookDir)) {
8160
8966
  chmodHooksSync(hookDir, projectDir);
8161
8967
  }
@@ -8172,12 +8978,12 @@ function installClaudeBaseline(manifestSpec, projectDir, templatesDir, baselineE
8172
8978
  if (settingsSource !== null) {
8173
8979
  writeSettingsPortion(writer, settingsSource, projectDir, previousLog, (script) => {
8174
8980
  const target = `${HOOKS_PREFIX}${script}`;
8175
- return manifest.some((e2) => e2.target === target && e2.applies(manifestSpec)) && !isBaselineExcluded(target, baselineExcluded) && existsSync22(join30(projectDir, target));
8981
+ return manifest.some((e2) => e2.target === target && e2.applies(manifestSpec)) && !isBaselineExcluded(target, baselineExcluded) && existsSync22(join31(projectDir, target));
8176
8982
  });
8177
8983
  result.keptHookRefs.push(
8178
8984
  ...findStaleHookRefs(
8179
- join30(projectDir, ".claude", "settings.json"),
8180
- join30(projectDir, ".claude")
8985
+ join31(projectDir, ".claude", "settings.json"),
8986
+ join31(projectDir, ".claude")
8181
8987
  )
8182
8988
  );
8183
8989
  }
@@ -8187,7 +8993,7 @@ function installClaudeBaseline(manifestSpec, projectDir, templatesDir, baselineE
8187
8993
  // ADR-085 · update(`upsertRootImport`)와 같은 판정 — 실제로 깔린 스킬만 안내한다. 밖 링크라 쓰지 않은
8188
8994
  // 스킬(ADR-098)을 "installed" 라 적으면 다음 update 가 그 절을 걷어 내 두 동작이 서로 반대로 쓴다.
8189
8995
  (manifestSpec.selectedInternalSkills ?? []).filter(
8190
- (id) => existsSync22(join30(projectDir, ".claude", "skills", id))
8996
+ (id) => existsSync22(join31(projectDir, ".claude", "skills", id))
8191
8997
  ),
8192
8998
  harnessRoot,
8193
8999
  writer
@@ -8228,7 +9034,7 @@ function writeEnvironmentFiles(writer, envExampleCreated, previousLog) {
8228
9034
  }
8229
9035
  function runExternalPhase(ctx, previousLog) {
8230
9036
  if (ctx.runExternal === null) {
8231
- return { report: null, backups: [] };
9037
+ return { report: null, backups: [], displaced: [] };
8232
9038
  }
8233
9039
  const { projectDir, spec } = ctx;
8234
9040
  const runExt = ctx.runExternal ?? runExternalInstall;
@@ -8251,22 +9057,38 @@ function runExternalPhase(ctx, previousLog) {
8251
9057
  };
8252
9058
  const { targets } = selectExternalTargets(EXTERNAL_ASSETS, { ...filterCtx, cli: spec.cli });
8253
9059
  ctx.onProgress?.({ type: "external-start", assetCount: targets.length });
8254
- const skillIds = new Set(targets.filter((a) => a.method.kind === "skill").map((a) => a.id));
8255
- const settle = holdSkillSlots(
8256
- projectDir,
8257
- (previousLog?.assets ?? []).filter((a) => a.method === "skill" && skillIds.has(a.id))
8258
- );
8259
- const external = runExt(
8260
- { ...filterCtx, cli: spec.cli, projectDir, ...spec.scope ? { scope: spec.scope } : {} },
8261
- externalDeps
8262
- );
8263
- const backups = settle();
9060
+ const skills = targets.filter((a) => a.method.kind === "skill");
9061
+ const skillIds = new Set(skills.map((a) => a.id));
9062
+ const settle = holdSkillSlots(projectDir, {
9063
+ recorded: (previousLog?.assets ?? []).filter((a) => a.method === "skill" && skillIds.has(a.id)),
9064
+ slots: skillSlotsFor(skills, spec.cli, { log: previousLog, scope: spec.scope }),
9065
+ log: previousLog,
9066
+ clis: spec.cli,
9067
+ scope: spec.scope
9068
+ });
9069
+ let ran;
9070
+ try {
9071
+ ran = runExt(
9072
+ { ...filterCtx, cli: spec.cli, projectDir, ...spec.scope ? { scope: spec.scope } : {} },
9073
+ externalDeps
9074
+ );
9075
+ } catch (e2) {
9076
+ try {
9077
+ settle(null);
9078
+ } catch {
9079
+ }
9080
+ throw e2;
9081
+ }
9082
+ const { report: external, backups, displaced } = settle(ran);
9083
+ const displacedBackups = new Set(displaced.map((f) => join31(projectDir, f.notes[0] ?? "")));
9084
+ const editBackups = backups.filter((b2) => !displacedBackups.has(b2));
8264
9085
  ctx.onProgress?.({
8265
9086
  type: "external-complete",
8266
9087
  report: external,
8267
- ...backups.length > 0 ? { backups } : {}
9088
+ ...editBackups.length > 0 ? { backups: editBackups } : {},
9089
+ ...displaced.length > 0 ? { displaced: displaced.map((f) => ({ path: f.path, backup: f.notes[0] ?? "" })) } : {}
8268
9090
  });
8269
- return { report: external, backups };
9091
+ return { report: external, backups, displaced };
8270
9092
  }
8271
9093
  var InstallInterruptedError = class extends Error {
8272
9094
  constructor(message, written, record, backups = [], hadInstall = false) {
@@ -8331,7 +9153,7 @@ function recordInterruptedInstall(ctx, error, run) {
8331
9153
  const codexTrust = registeredTrust(journal.codexOptIn, ctx.projectDir);
8332
9154
  const written = writtenSoFar(ledger, cliFiles, rootFiles, stage.rootImportWritten);
8333
9155
  if (codexTrust) written.push(`${codexTrust.configPath} (Codex trust entry for this folder)`);
8334
- const projectRel = (abs) => relative3(ctx.projectDir, abs).split(sep4).join("/");
9156
+ const projectRel = (abs) => relative4(ctx.projectDir, abs).split(sep5).join("/");
8335
9157
  const writtenSet = new Set(written);
8336
9158
  const backups = [...own.backups, ...journal.backups].map((abs) => {
8337
9159
  const original = projectRel(backupOriginal(abs) ?? abs);
@@ -8471,7 +9293,7 @@ function accumulateCategory(cats, entry) {
8471
9293
  }
8472
9294
  }
8473
9295
  function writeRootClaudeMd(projectDir, tracks, continuousSkills, harnessRoot, writer) {
8474
- const target = join30(projectDir, "CLAUDE.md");
9296
+ const target = join31(projectDir, "CLAUDE.md");
8475
9297
  if (writer.skipOutside(target)) return null;
8476
9298
  const existing = existsSync22(target) ? readFileSync22(target, "utf-8") : null;
8477
9299
  const seeded = existing === null ? seedRootClaudeProjectContext(projectDir, harnessRoot) : null;
@@ -8483,7 +9305,7 @@ function writeRootClaudeMd(projectDir, tracks, continuousSkills, harnessRoot, wr
8483
9305
  });
8484
9306
  if (content !== existing) {
8485
9307
  if (existing !== null) backupIfLossyUtf8(target);
8486
- writeFileSync9(target, content);
9308
+ writeFileSync8(target, content);
8487
9309
  }
8488
9310
  return {
8489
9311
  created: existing === null,
@@ -8501,14 +9323,14 @@ function chmodHooksSync(hookDir, projectDir) {
8501
9323
  }
8502
9324
  }
8503
9325
  function listHookFiles(hookDir) {
8504
- return readdirSync4(hookDir, { withFileTypes: true }).filter((e2) => e2.isFile() && e2.name.endsWith(".sh")).map((e2) => resolve(hookDir, e2.name));
9326
+ return readdirSync5(hookDir, { withFileTypes: true }).filter((e2) => e2.isFile() && e2.name.endsWith(".sh")).map((e2) => resolve(hookDir, e2.name));
8505
9327
  }
8506
9328
 
8507
9329
  // src/commands/install-render.ts
8508
9330
  init_esm_shims();
8509
9331
  import { homedir as homedir3 } from "os";
8510
- import { existsSync as existsSync24, readdirSync as readdirSync5, readFileSync as readFileSync24 } from "fs";
8511
- import { join as join32, relative as relative4 } from "path";
9332
+ import { existsSync as existsSync24, readdirSync as readdirSync6, readFileSync as readFileSync24 } from "fs";
9333
+ import { join as join33, relative as relative5 } from "path";
8512
9334
 
8513
9335
  // src/preset-recommend.ts
8514
9336
  init_esm_shims();
@@ -8545,9 +9367,9 @@ function groupAssetsByCategory(assetIds) {
8545
9367
  // src/resident-entries.ts
8546
9368
  init_esm_shims();
8547
9369
  import { existsSync as existsSync23, readFileSync as readFileSync23 } from "fs";
8548
- import { basename as basename5, join as join31 } from "path";
9370
+ import { basename as basename5, join as join32 } from "path";
8549
9371
  function residentEntries(spec) {
8550
- const skillThere = (id) => INTERNAL_BUNDLED_SKILL_IDS.includes(id) && [".claude/skills", ".agents/skills"].some((d2) => existsSync23(join31(spec.projectDir, d2, id)));
9372
+ const skillThere = (id) => INTERNAL_BUNDLED_SKILL_IDS.includes(id) && [".claude/skills", ".agents/skills"].some((d2) => existsSync23(join32(spec.projectDir, d2, id)));
8551
9373
  const forceExclude = (spec.userOverride?.forceExclude ?? []).filter((id) => !skillThere(id));
8552
9374
  const assetSpec = buildManifestSpec(
8553
9375
  spec.userOverride ? { ...spec, userOverride: { ...spec.userOverride, forceExclude } } : spec
@@ -8573,7 +9395,7 @@ function residentEntries(spec) {
8573
9395
  function residentCostFor(spec, entries = residentEntries(spec), contextFiles) {
8574
9396
  if (contextFiles !== void 0) return residentCost(entries, void 0, spec.cli, contextFiles);
8575
9397
  const cost = residentCost(entries, void 0, spec.cli, plannedClaudeContext(spec));
8576
- if (anchorSurface(spec.cli).scaffold === "agents-md" && existsSync23(join31(spec.projectDir, "AGENTS.md"))) {
9398
+ if (anchorSurface(spec.cli).scaffold === "agents-md" && existsSync23(join32(spec.projectDir, "AGENTS.md"))) {
8577
9399
  return makeResidentCost({
8578
9400
  ...cost,
8579
9401
  contextNote: "planned, not counting text already in AGENTS.md"
@@ -8584,7 +9406,7 @@ function residentCostFor(spec, entries = residentEntries(spec), contextFiles) {
8584
9406
  function plannedClaudeContext(spec) {
8585
9407
  if (!spec.cli.includes("claude")) return void 0;
8586
9408
  const root = resolveBundleRoot();
8587
- const rootClaude = join31(spec.projectDir, "CLAUDE.md");
9409
+ const rootClaude = join32(spec.projectDir, "CLAUDE.md");
8588
9410
  const existing = existsSync23(rootClaude) ? readFileSync23(rootClaude, "utf-8") : null;
8589
9411
  const seeded = existing === null ? seedRootClaudeProjectContext(spec.projectDir, root) : null;
8590
9412
  if (existing === null && seeded === null) return void 0;
@@ -8595,14 +9417,14 @@ function plannedClaudeContext(spec) {
8595
9417
  continuousSkills: manifestSpec.selectedInternalSkills ?? [],
8596
9418
  ...seeded === null ? {} : { projectContext: seeded }
8597
9419
  });
8598
- return [join31(root, "templates", "CLAUDE.md"), { text }];
9420
+ return [join32(root, "templates", "CLAUDE.md"), { text }];
8599
9421
  }
8600
9422
  function onDiskTargets(spec, assetSpec) {
8601
9423
  const out = /* @__PURE__ */ new Set();
8602
9424
  for (const e2 of buildManifest(assetSpec)) {
8603
9425
  if (!e2.applies(assetSpec)) continue;
8604
9426
  const t = classifyBaselineTarget(e2.target);
8605
- if (t !== null && existsSync23(join31(spec.projectDir, e2.target))) out.add(t.id);
9427
+ if (t !== null && existsSync23(join32(spec.projectDir, e2.target))) out.add(t.id);
8606
9428
  }
8607
9429
  return out;
8608
9430
  }
@@ -8665,6 +9487,14 @@ function createInstallRenderer(log, spec, verbose) {
8665
9487
  phase2HeaderPrinted = true;
8666
9488
  } else if (event.type === "external-complete") {
8667
9489
  for (const b2 of event.backups ?? []) log(assetRow("success", "backup", shortenPath(b2)));
9490
+ for (const d2 of event.displaced ?? [])
9491
+ log(
9492
+ assetRow(
9493
+ "skip",
9494
+ d2.path,
9495
+ `had a file with this name \u2014 saved as ${d2.backup}, put back on uninstall`
9496
+ )
9497
+ );
8668
9498
  const excluded = event.report.excludedByCli;
8669
9499
  if (excluded.length > 0) {
8670
9500
  if (!phase2HeaderPrinted) {
@@ -8754,23 +9584,23 @@ function residentEntriesOnDisk(spec) {
8754
9584
  const hasClaude = spec.cli.includes("claude");
8755
9585
  const surface = anchorSurface(spec.cli).scaffold;
8756
9586
  const mdFiles = (dir, kind, skip) => {
8757
- const abs = join32(spec.projectDir, dir);
8758
- return existsSync24(abs) ? readdirSync5(abs, { withFileTypes: true }).filter((e2) => e2.isFile() && e2.name.endsWith(".md") && e2.name !== skip).map((e2) => ({
9587
+ const abs = join33(spec.projectDir, dir);
9588
+ return existsSync24(abs) ? readdirSync6(abs, { withFileTypes: true }).filter((e2) => e2.isFile() && e2.name.endsWith(".md") && e2.name !== skip).map((e2) => ({
8759
9589
  source: `${kind}/${e2.name}`,
8760
9590
  // `target` 은 `residentCost` 의 분류 키다 — 실제 자리는 `file` 이 말한다.
8761
9591
  target: `.claude/${kind}/${e2.name}`,
8762
9592
  // 배포판이 아니라 **이 프로젝트의 파일**을 잰다 — 사용자가 고친 본문도,
8763
9593
  // 배포판에 더는 없는 파일도 실제로 상주하는 것은 이쪽이다.
8764
- file: join32(abs, e2.name)
9594
+ file: join33(abs, e2.name)
8765
9595
  })) : [];
8766
9596
  };
8767
- const rules = surface === "claude" ? mdFiles(join32(".claude", "rules"), "rules") : rulesInline(spec.cli) ? planned.filter((e2) => e2.target.startsWith(".claude/rules/")) : mdFiles(join32(".agents", "rules"), "rules", "uzys-harness.md");
8768
- const slot = hasClaude ? join32(".claude", "skills") : join32(".agents", "skills");
9597
+ const rules = surface === "claude" ? mdFiles(join33(".claude", "rules"), "rules") : rulesInline(spec.cli) ? planned.filter((e2) => e2.target.startsWith(".claude/rules/")) : mdFiles(join33(".agents", "rules"), "rules", "uzys-harness.md");
9598
+ const slot = hasClaude ? join33(".claude", "skills") : join33(".agents", "skills");
8769
9599
  const skills = planned.filter((e2) => e2.target.startsWith(".claude/skills/")).map((e2) => ({
8770
9600
  ...e2,
8771
- file: join32(spec.projectDir, slot, e2.target.slice(".claude/skills/".length))
9601
+ file: join33(spec.projectDir, slot, e2.target.slice(".claude/skills/".length))
8772
9602
  })).filter((e2) => existsSync24(e2.file));
8773
- const agents = hasClaude ? mdFiles(join32(".claude", "agents"), "agents") : [];
9603
+ const agents = hasClaude ? mdFiles(join33(".claude", "agents"), "agents") : [];
8774
9604
  return [
8775
9605
  ...planned.filter(
8776
9606
  (e2) => !e2.target.startsWith(".claude/rules/") && !e2.target.startsWith(".claude/agents/") && !e2.target.startsWith(".claude/skills/")
@@ -8782,8 +9612,8 @@ function residentEntriesOnDisk(spec) {
8782
9612
  }
8783
9613
  function contextFilesOnDisk(spec) {
8784
9614
  const surface = anchorSurface(spec.cli).scaffold;
8785
- const files = surface === "claude" ? [HARNESS_ANCHOR_FILE, "CLAUDE.md", join32(".claude", "CLAUDE.md")] : ["AGENTS.md"];
8786
- return files.map((f) => join32(spec.projectDir, f));
9615
+ const files = surface === "claude" ? [HARNESS_ANCHOR_FILE, "CLAUDE.md", join33(".claude", "CLAUDE.md")] : ["AGENTS.md"];
9616
+ return files.map((f) => join33(spec.projectDir, f));
8787
9617
  }
8788
9618
  function rulesInsideAgentsMd(spec, cost) {
8789
9619
  if (anchorSurface(spec.cli).scaffold !== "agents-md" || !rulesInline(spec.cli)) return cost;
@@ -9037,8 +9867,8 @@ function renderFinalSummary(log, spec, report, fromWizard) {
9037
9867
  const codexTrusted = report.codexOptIn?.trustEntry.status === "registered" || report.codexOptIn?.trustEntry.status === "already-present";
9038
9868
  const alreadyTrustedGlobally = (() => {
9039
9869
  try {
9040
- const home = process.env.CODEX_HOME ?? join32(homedir3(), ".codex");
9041
- const configPath = join32(home, "config.toml");
9870
+ const home = process.env.CODEX_HOME ?? join33(homedir3(), ".codex");
9871
+ const configPath = join33(home, "config.toml");
9042
9872
  if (!existsSync24(configPath)) return false;
9043
9873
  return hasTrustEntry(readFileSync24(configPath, "utf8"), spec.projectDir);
9044
9874
  } catch {
@@ -9065,7 +9895,7 @@ function renderFinalSummary(log, spec, report, fromWizard) {
9065
9895
  const remote = (report.shared ?? []).find((f) => f.path === ".mcp.json")?.remote ?? [];
9066
9896
  for (const line of remoteMcpNextLines(remote, spec.cli)) log(`${" ".repeat(16)} ${line}`);
9067
9897
  const scaffoldFiles = scaffoldFilesForCli(spec.cli).filter(
9068
- (f) => f === "CLAUDE.md" && report.rootClaudeMd?.created === true || hasFillPrompt(join32(spec.projectDir, f))
9898
+ (f) => f === "CLAUDE.md" && report.rootClaudeMd?.created === true || hasFillPrompt(join33(spec.projectDir, f))
9069
9899
  );
9070
9900
  if (scaffoldFiles.length > 0) {
9071
9901
  const auditInstalled = buildManifestSpec(spec).selectedInternalSkills?.includes("audit-harness-fit");
@@ -9205,6 +10035,7 @@ function renderPhase1Rows(log, baseline, verbose = false) {
9205
10035
  const retired = anchorRetireRow(baseline.updateMode.anchorRetired ?? null);
9206
10036
  if (retired) log(retired);
9207
10037
  for (const row of outOfTrackRows(baseline.updateMode.outOfTrack)) log(row);
10038
+ for (const row of displacedRows(baseline.updateMode.displacedRestored)) log(row);
9208
10039
  for (const f of baseline.updateMode.sharedWrites ?? []) {
9209
10040
  const row = sharedFileRow(f);
9210
10041
  if (row !== null) log(row);
@@ -9411,6 +10242,26 @@ function renderPhase1Rows(log, baseline, verbose = false) {
9411
10242
  )
9412
10243
  );
9413
10244
  }
10245
+ const legacyDropped = baseline.updateMode.agentsMdLegacyDropped ?? 0;
10246
+ if (legacyDropped > 0) {
10247
+ log(
10248
+ assetRow(
10249
+ "success",
10250
+ "AGENTS.md",
10251
+ `removed ${legacyDropped} section(s) written by an older harness version (saved a copy as AGENTS.md.backup-<time>)`
10252
+ )
10253
+ );
10254
+ }
10255
+ const legacyEdited = baseline.updateMode.agentsMdLegacyEdited ?? [];
10256
+ if (legacyEdited.length > 0) {
10257
+ log(
10258
+ assetRow(
10259
+ "skip",
10260
+ "AGENTS.md",
10261
+ `${legacyEdited.length} harness section(s) you had edited (${legacyEdited.join(" \xB7 ")}) now hold the current version \u2014 your edit is in the copy AGENTS.md.backup-<time>`
10262
+ )
10263
+ );
10264
+ }
9414
10265
  const externalEdited = baseline.updateMode.externalBackedUp.filter((p2) => !noChecksum.has(p2));
9415
10266
  if (externalEdited.length > 0) {
9416
10267
  log(
@@ -9499,6 +10350,7 @@ function renderPhase1Rows(log, baseline, verbose = false) {
9499
10350
  }
9500
10351
  for (const row of outsideLinkRows(baseline.outsideLinks ?? [])) log(row);
9501
10352
  for (const row of outOfTrackRows(baseline.outOfTrack)) log(row);
10353
+ for (const row of displacedRows(baseline.displacedRestored)) log(row);
9502
10354
  if (baseline.backups) {
9503
10355
  for (const b2 of baseline.backups) {
9504
10356
  if (judgedBackups.has(b2)) continue;
@@ -9638,6 +10490,11 @@ function renderPhase1Rows(log, baseline, verbose = false) {
9638
10490
  function judgedRow(j4) {
9639
10491
  return j4.backup !== void 0 ? ` ${c.green(symbol.success)} backed up ${j4.path} \u2014 ${j4.line}` : ` ${c.yellow(symbol.skip)} ${j4.path} \u2014 ${j4.line}`;
9640
10492
  }
10493
+ function displacedRows(outcomes) {
10494
+ return (outcomes ?? []).flatMap(
10495
+ (d2) => d2.verdict === "restore" ? [assetRow("success", d2.path, `yours \u2014 put back (from ${d2.backup})`)] : d2.verdict === "advise" ? [assetRow("skip", d2.path, d2.line)] : []
10496
+ );
10497
+ }
9641
10498
  function outOfTrackRows(r) {
9642
10499
  if (r === void 0) return [];
9643
10500
  const recorded2 = r.recordedTracks.join(", ");
@@ -9674,16 +10531,16 @@ function outOfTrackRows(r) {
9674
10531
  function outsideLinkRows(links) {
9675
10532
  const groups = /* @__PURE__ */ new Map();
9676
10533
  for (const o of links) groups.set(o.link, [...groups.get(o.link) ?? [], o]);
9677
- const rows = [];
10534
+ const rows2 = [];
9678
10535
  for (const [link, group] of groups) {
9679
10536
  const first = group[0];
9680
10537
  if (first === void 0) continue;
9681
10538
  const fileLink = group.length === 1 && first.path === link;
9682
- rows.push(
10539
+ rows2.push(
9683
10540
  fileLink ? ` ${c.yellow(symbol.skip)} ${link} \u2014 left as is: the link points outside the project (${first.linkTarget}). Not written; replace the link with a regular file to get the harness version.` : ` ${c.yellow(symbol.skip)} ${link}/ \u2014 left as is: the link points outside the project (${first.linkTarget}), ${group.length} file(s) not written. Replace the link with a regular folder to get the harness version.`
9684
10541
  );
9685
10542
  }
9686
- return rows;
10543
+ return rows2;
9687
10544
  }
9688
10545
  function sharedFileRow(f) {
9689
10546
  if (f.line === "") return null;
@@ -9872,7 +10729,7 @@ function renderInterruptedInstall(err, e2, cwd = process.cwd()) {
9872
10729
  }
9873
10730
  const { path, error } = e2.record;
9874
10731
  err(
9875
- path !== null ? ` Already in place before it stopped \u2014 recorded in ${relative4(cwd, path) || path}:` : " Already in place before it stopped:"
10732
+ path !== null ? ` Already in place before it stopped \u2014 recorded in ${relative5(cwd, path) || path}:` : " Already in place before it stopped:"
9876
10733
  );
9877
10734
  for (const [key, n] of groups) {
9878
10735
  err(` ${key.endsWith("/") ? `${key} (${n} file${n === 1 ? "" : "s"})` : key}`);
@@ -10196,7 +11053,7 @@ function registerInstallCommand(cli) {
10196
11053
  // src/commands/list.ts
10197
11054
  init_esm_shims();
10198
11055
  import { existsSync as existsSync25, readFileSync as readFileSync25 } from "fs";
10199
- import { join as join33, resolve as resolve3 } from "path";
11056
+ import { join as join34, resolve as resolve3 } from "path";
10200
11057
  function listAction(options = {}, deps = {}) {
10201
11058
  const log = deps.log ?? console.log;
10202
11059
  const err = deps.err ?? console.error;
@@ -10247,33 +11104,33 @@ function listAction(options = {}, deps = {}) {
10247
11104
  }
10248
11105
  var SELECTIONS_SHOWN = 10;
10249
11106
  function formatSelectionRows(log, projectDir) {
10250
- const rows = [];
11107
+ const rows2 = [];
10251
11108
  const excluded = [...excludedIds(log)].sort();
10252
- if (excluded.length === 0) rows.push(c.dim(" excluded: (none)"));
11109
+ if (excluded.length === 0) rows2.push(c.dim(" excluded: (none)"));
10253
11110
  const still = new Set(
10254
11111
  excludedStillThere(projectDir, new Set(excluded), [], log).map((e2) => e2.id)
10255
11112
  );
10256
11113
  for (const id of excluded) {
10257
11114
  const kind = id.startsWith("baseline:") ? "baseline" : isKeyId(id) ? "harness part" : "asset";
10258
- rows.push(` \u2298 ${id} ${c.dim(`(${kind}${still.has(id) ? " \xB7 still on disk" : ""})`)}`);
11115
+ rows2.push(` \u2298 ${id} ${c.dim(`(${kind}${still.has(id) ? " \xB7 still on disk" : ""})`)}`);
10259
11116
  }
10260
11117
  const history = (log.selections ?? []).slice(-SELECTIONS_SHOWN);
10261
- if (history.length > 0) rows.push(c.dim(` history (latest ${history.length}):`));
11118
+ if (history.length > 0) rows2.push(c.dim(` history (latest ${history.length}):`));
10262
11119
  for (const ev of history) {
10263
11120
  const day = ev.at.slice(0, 10);
10264
11121
  const parts = [];
10265
11122
  if (ev.by === "migration") {
10266
11123
  if (ev.released?.length) parts.push(`released ${ev.released.join(", ")}`);
10267
11124
  if (ev.kept?.length) parts.push(`kept ${ev.kept.join(", ")}`);
10268
- rows.push(` ${day} migration (26.162\u201326.163 record): ${parts.join(" \xB7 ")}`);
11125
+ rows2.push(` ${day} migration (26.162\u201326.163 record): ${parts.join(" \xB7 ")}`);
10269
11126
  continue;
10270
11127
  }
10271
11128
  if (ev.without?.length) parts.push(`--without ${ev.without.join(", ")}`);
10272
11129
  if (ev.with?.length) parts.push(`re-added ${ev.with.join(", ")}`);
10273
11130
  const tags = [ev.via === "wizard" ? "wizard" : "", ev.interrupted ? "interrupted" : ""].filter(Boolean).join(", ");
10274
- rows.push(` ${day} install ${parts.join(" \xB7 ")}${tags ? ` (${tags})` : ""}`);
11131
+ rows2.push(` ${day} install ${parts.join(" \xB7 ")}${tags ? ` (${tags})` : ""}`);
10275
11132
  }
10276
- return rows;
11133
+ return rows2;
10277
11134
  }
10278
11135
  function formatAssetRows(assets) {
10279
11136
  const idWidth = Math.max(0, ...assets.map((a) => a.id.length));
@@ -10296,16 +11153,16 @@ function harnessFileTops(log) {
10296
11153
  }
10297
11154
  function formatHarnessFileRows(log, projectDir) {
10298
11155
  const tops = harnessFileTops(log);
10299
- const rows = [` ${c.dim(tops.length > 0 ? tops.join(" ") : "(none recorded)")}`];
11156
+ const rows2 = [` ${c.dim(tops.length > 0 ? tops.join(" ") : "(none recorded)")}`];
10300
11157
  const rootMd = log.templates.rootClaudeMd;
10301
11158
  if (rootMd) {
10302
- const path = join33(projectDir, rootMd.path);
11159
+ const path = join34(projectDir, rootMd.path);
10303
11160
  const modified = existsSync25(path) && hashContent(readFileSync25(path, "utf8")) !== rootMd.sha256;
10304
- rows.push(
11161
+ rows2.push(
10305
11162
  modified ? ` ${c.dim(rootMd.path)} ${c.yellow("(\uC218\uC815\uB428 \u2014 uninstall \uC2DC \uBCF4\uC874)")}` : ` ${c.dim(rootMd.path)}`
10306
11163
  );
10307
11164
  }
10308
- return rows;
11165
+ return rows2;
10309
11166
  }
10310
11167
  var ROOT_FILE_CHANGE = {
10311
11168
  created: "\uC0DD\uC131",
@@ -10314,7 +11171,7 @@ var ROOT_FILE_CHANGE = {
10314
11171
  displaced: "\uBE44\uCF1C \uB460"
10315
11172
  };
10316
11173
  function formatRootFileRows(rootFiles, projectDir) {
10317
- const present2 = rootFiles.filter((f) => existsSync25(join33(projectDir, f.path)));
11174
+ const present2 = rootFiles.filter((f) => existsSync25(join34(projectDir, f.path)));
10318
11175
  const width = Math.max(0, ...present2.map((f) => f.path.length));
10319
11176
  return present2.map(
10320
11177
  (f) => ` ${c.dim(padDisplay(f.path, width))} ${c.dim(ROOT_FILE_CHANGE[f.change])} ${c.dim(f.notes.join(" / "))}`
@@ -10332,22 +11189,20 @@ function registerListCommand(cli) {
10332
11189
  init_esm_shims();
10333
11190
  import { spawnSync as spawnSync2 } from "child_process";
10334
11191
  import {
10335
- accessSync,
11192
+ accessSync as accessSync2,
10336
11193
  existsSync as existsSync26,
10337
- constants as fsConstants,
10338
- lstatSync as lstatSync5,
10339
- mkdirSync as mkdirSync7,
10340
- readdirSync as readdirSync6,
11194
+ constants as fsConstants2,
11195
+ lstatSync as lstatSync6,
11196
+ readdirSync as readdirSync7,
10341
11197
  readFileSync as readFileSync26,
10342
11198
  readlinkSync,
10343
11199
  realpathSync as realpathSync3,
10344
- renameSync,
10345
- rmdirSync as rmdirSync2,
10346
- rmSync as rmSync4,
11200
+ rmdirSync as rmdirSync3,
11201
+ rmSync as rmSync5,
10347
11202
  statSync as statSync5,
10348
- writeFileSync as writeFileSync10
11203
+ writeFileSync as writeFileSync9
10349
11204
  } from "fs";
10350
- import { dirname as dirname7, join as join34, relative as relative5, resolve as resolve4, sep as sep5 } from "path";
11205
+ import { dirname as dirname8, join as join35, relative as relative6, resolve as resolve4, sep as sep6 } from "path";
10351
11206
 
10352
11207
  // src/uninstall-interactive.ts
10353
11208
  init_esm_shims();
@@ -10537,11 +11392,11 @@ var getClosingCode = (openingCode) => {
10537
11392
  };
10538
11393
  var wrapAnsiCode = (code) => `${ESC}${ANSI_CSI}${code}${ANSI_SGR_TERMINATOR}`;
10539
11394
  var wrapAnsiHyperlink = (url) => `${ESC}${ANSI_ESCAPE_LINK}${url}${ANSI_ESCAPE_BELL}`;
10540
- var wrapWord = (rows, word, columns) => {
11395
+ var wrapWord = (rows2, word, columns) => {
10541
11396
  const characters = word[Symbol.iterator]();
10542
11397
  let isInsideEscape = false;
10543
11398
  let isInsideLinkEscape = false;
10544
- let lastRow = rows.at(-1);
11399
+ let lastRow = rows2.at(-1);
10545
11400
  let visible = lastRow === void 0 ? 0 : dist_default2(lastRow);
10546
11401
  let currentCharacter = characters.next();
10547
11402
  let nextCharacter = characters.next();
@@ -10550,9 +11405,9 @@ var wrapWord = (rows, word, columns) => {
10550
11405
  const character = currentCharacter.value;
10551
11406
  const characterLength = dist_default2(character);
10552
11407
  if (visible + characterLength <= columns) {
10553
- rows[rows.length - 1] += character;
11408
+ rows2[rows2.length - 1] += character;
10554
11409
  } else {
10555
- rows.push(character);
11410
+ rows2.push(character);
10556
11411
  visible = 0;
10557
11412
  }
10558
11413
  if (character === ESC || character === CSI) {
@@ -10571,7 +11426,7 @@ var wrapWord = (rows, word, columns) => {
10571
11426
  } else {
10572
11427
  visible += characterLength;
10573
11428
  if (visible === columns && !nextCharacter.done) {
10574
- rows.push("");
11429
+ rows2.push("");
10575
11430
  visible = 0;
10576
11431
  }
10577
11432
  }
@@ -10579,9 +11434,9 @@ var wrapWord = (rows, word, columns) => {
10579
11434
  nextCharacter = characters.next();
10580
11435
  rawCharacterIndex += character.length;
10581
11436
  }
10582
- lastRow = rows.at(-1);
10583
- if (!visible && lastRow !== void 0 && lastRow.length && rows.length > 1) {
10584
- rows[rows.length - 2] += rows.pop();
11437
+ lastRow = rows2.at(-1);
11438
+ if (!visible && lastRow !== void 0 && lastRow.length && rows2.length > 1) {
11439
+ rows2[rows2.length - 2] += rows2.pop();
10585
11440
  }
10586
11441
  };
10587
11442
  var stringVisibleTrimSpacesRight = (string) => {
@@ -10606,25 +11461,25 @@ var exec = (string, columns, options = {}) => {
10606
11461
  let escapeCode;
10607
11462
  let escapeUrl;
10608
11463
  const words = string.split(" ");
10609
- let rows = [""];
11464
+ let rows2 = [""];
10610
11465
  let rowLength = 0;
10611
11466
  for (let index = 0; index < words.length; index++) {
10612
11467
  const word = words[index];
10613
11468
  if (options.trim !== false) {
10614
- const row = rows.at(-1) ?? "";
11469
+ const row = rows2.at(-1) ?? "";
10615
11470
  const trimmed = row.trimStart();
10616
11471
  if (row.length !== trimmed.length) {
10617
- rows[rows.length - 1] = trimmed;
11472
+ rows2[rows2.length - 1] = trimmed;
10618
11473
  rowLength = dist_default2(trimmed);
10619
11474
  }
10620
11475
  }
10621
11476
  if (index !== 0) {
10622
11477
  if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) {
10623
- rows.push("");
11478
+ rows2.push("");
10624
11479
  rowLength = 0;
10625
11480
  }
10626
11481
  if (rowLength || options.trim === false) {
10627
- rows[rows.length - 1] += " ";
11482
+ rows2[rows2.length - 1] += " ";
10628
11483
  rowLength++;
10629
11484
  }
10630
11485
  }
@@ -10634,33 +11489,33 @@ var exec = (string, columns, options = {}) => {
10634
11489
  const breaksStartingThisLine = 1 + Math.floor((wordLength - remainingColumns - 1) / columns);
10635
11490
  const breaksStartingNextLine = Math.floor((wordLength - 1) / columns);
10636
11491
  if (breaksStartingNextLine < breaksStartingThisLine) {
10637
- rows.push("");
11492
+ rows2.push("");
10638
11493
  }
10639
- wrapWord(rows, word, columns);
10640
- rowLength = dist_default2(rows.at(-1) ?? "");
11494
+ wrapWord(rows2, word, columns);
11495
+ rowLength = dist_default2(rows2.at(-1) ?? "");
10641
11496
  continue;
10642
11497
  }
10643
11498
  if (rowLength + wordLength > columns && rowLength && wordLength) {
10644
11499
  if (options.wordWrap === false && rowLength < columns) {
10645
- wrapWord(rows, word, columns);
10646
- rowLength = dist_default2(rows.at(-1) ?? "");
11500
+ wrapWord(rows2, word, columns);
11501
+ rowLength = dist_default2(rows2.at(-1) ?? "");
10647
11502
  continue;
10648
11503
  }
10649
- rows.push("");
11504
+ rows2.push("");
10650
11505
  rowLength = 0;
10651
11506
  }
10652
11507
  if (rowLength + wordLength > columns && options.wordWrap === false) {
10653
- wrapWord(rows, word, columns);
10654
- rowLength = dist_default2(rows.at(-1) ?? "");
11508
+ wrapWord(rows2, word, columns);
11509
+ rowLength = dist_default2(rows2.at(-1) ?? "");
10655
11510
  continue;
10656
11511
  }
10657
- rows[rows.length - 1] += word;
11512
+ rows2[rows2.length - 1] += word;
10658
11513
  rowLength += wordLength;
10659
11514
  }
10660
11515
  if (options.trim !== false) {
10661
- rows = rows.map((row) => stringVisibleTrimSpacesRight(row));
11516
+ rows2 = rows2.map((row) => stringVisibleTrimSpacesRight(row));
10662
11517
  }
10663
- const preString = rows.join("\n");
11518
+ const preString = rows2.join("\n");
10664
11519
  let inSurrogate = false;
10665
11520
  for (let i = 0; i < preString.length; i++) {
10666
11521
  const character = preString[i];
@@ -11544,8 +12399,8 @@ function assertPagesCoverAllCategories(pages) {
11544
12399
  }
11545
12400
  assertPagesCoverAllCategories(INSTALL_TARGET_PAGES);
11546
12401
  function viewportItems(itemCount) {
11547
- const rows = process.stdout.rows ?? 24;
11548
- return Math.max(8, Math.min(itemCount, rows - 10));
12402
+ const rows2 = process.stdout.rows ?? 24;
12403
+ return Math.max(8, Math.min(itemCount, rows2 - 10));
11549
12404
  }
11550
12405
  var defaultPrompts = {
11551
12406
  intro: (msg) => ge(msg),
@@ -11854,11 +12709,11 @@ async function runInteractiveUninstall(projectDir, deps = {}) {
11854
12709
  const log = readLog(projectDir);
11855
12710
  if (!log) return { ok: false, reason: "no-log" };
11856
12711
  if (!deps.embedded) prompts.intro("uzys-agent-harness \xB7 uninstall");
11857
- const rows = buildRemovableRows(log.assets);
12712
+ const rows2 = buildRemovableRows(log.assets);
11858
12713
  const clis = installedClis(log);
11859
12714
  const mode = await prompts.selectMode(
11860
- buildUninstallModeChoices(clis, rows.length),
11861
- `uzys-agent-harness \xB7 uninstall installed: ${clis.join(", ") || "(none)"} \xB7 assets ${rows.length}`
12715
+ buildUninstallModeChoices(clis, rows2.length),
12716
+ `uzys-agent-harness \xB7 uninstall installed: ${clis.join(", ") || "(none)"} \xB7 assets ${rows2.length}`
11862
12717
  );
11863
12718
  if (mode === null) {
11864
12719
  prompts.cancel("Cancelled.");
@@ -11885,7 +12740,7 @@ async function runInteractiveUninstall(projectDir, deps = {}) {
11885
12740
  }
11886
12741
  return { ok: true, options: { projectDir } };
11887
12742
  }
11888
- const picked = await prompts.selectAssets(rows);
12743
+ const picked = await prompts.selectAssets(rows2);
11889
12744
  if (picked === null) {
11890
12745
  prompts.cancel("Cancelled.");
11891
12746
  return { ok: false, reason: "cancelled" };
@@ -11944,18 +12799,18 @@ function defaultUninstallPrompts() {
11944
12799
  });
11945
12800
  return q(r) ? null : r;
11946
12801
  },
11947
- selectCli: async (rows) => {
12802
+ selectCli: async (rows2) => {
11948
12803
  const r = await Ee({
11949
12804
  message: 'Which CLI? (the last remaining CLI cannot be removed this way \u2014 use "Remove everything")',
11950
- options: rows.map((x) => ({ value: x.value, label: x.label, hint: x.hint }))
12805
+ options: rows2.map((x) => ({ value: x.value, label: x.label, hint: x.hint }))
11951
12806
  });
11952
12807
  return q(r) ? null : r;
11953
12808
  },
11954
- selectAssets: async (rows) => {
11955
- if (rows.length === 0) return [];
12809
+ selectAssets: async (rows2) => {
12810
+ if (rows2.length === 0) return [];
11956
12811
  const r = await ve({
11957
12812
  message: "Assets to remove (Space toggle \xB7 Enter confirm \xB7 ESC cancel)",
11958
- options: rows.map((x) => ({ value: x.value, label: x.label, hint: x.hint })),
12813
+ options: rows2.map((x) => ({ value: x.value, label: x.label, hint: x.hint })),
11959
12814
  required: false
11960
12815
  });
11961
12816
  return q(r) ? null : r;
@@ -12087,9 +12942,20 @@ function uninstallAction(options, deps = {}) {
12087
12942
  }
12088
12943
  const logSurvives = selectedIds !== null;
12089
12944
  let reversed;
12945
+ let onlyDisplaced = [];
12090
12946
  try {
12091
12947
  reversed = executeReverse(plan, log, logSurvives, journal);
12092
- if (!assetsOnly) {
12948
+ if (assetsOnly) {
12949
+ const removed = new Set(reversed.removedIds);
12950
+ onlyDisplaced = restoreDisplaced(installLog, projectDir, {
12951
+ has: inAssetSlots(installLog.assets.filter((a) => removed.has(a.id))),
12952
+ write: true
12953
+ });
12954
+ for (const d2 of onlyDisplaced) {
12955
+ if (d2.verdict === "restore") journal.push(`put back ${d2.path}`);
12956
+ }
12957
+ for (const line of displacedLines(onlyDisplaced, false)) log(line);
12958
+ } else {
12093
12959
  const done = removeHarnessFiles(installLog, projectDir, FULL_SCOPE, {
12094
12960
  rm: rmJ,
12095
12961
  write: true,
@@ -12125,7 +12991,7 @@ function uninstallAction(options, deps = {}) {
12125
12991
  }
12126
12992
  const { succeeded, failed, removedIds } = reversed;
12127
12993
  const logWriteFailed = settleLog(
12128
- { installLog, projectDir, selectedIds, removedIds },
12994
+ { installLog, projectDir, selectedIds, removedIds, displaced: onlyDisplaced },
12129
12995
  { log, err, rm, writeLog }
12130
12996
  );
12131
12997
  for (const line of advisoryLines(plan, projectDir, rootFiles, globalTrust)) {
@@ -12154,11 +13020,11 @@ function unwritablePaths(ctx) {
12154
13020
  const project = ctx.targetAssets.filter((a) => a.scope === "project");
12155
13021
  if (project.some((a) => a.method === "npm")) need.add(".");
12156
13022
  const parentOf = (path) => {
12157
- const abs = join34(projectDir, path);
13023
+ const abs = join35(projectDir, path);
12158
13024
  if (!safeExists(abs)) return;
12159
13025
  const real = safeRealpath(abs);
12160
13026
  if (real !== null && isOutsideProject(projectDir, real)) return;
12161
- need.add(dirname7(path));
13027
+ need.add(dirname8(path));
12162
13028
  };
12163
13029
  for (const a of project)
12164
13030
  if (a.method === "skill") for (const f of a.files ?? []) parentOf(f.path);
@@ -12166,16 +13032,17 @@ function unwritablePaths(ctx) {
12166
13032
  const recordedShared = new Set((installLog.portions ?? []).map((p2) => p2.path));
12167
13033
  const made = new Set((installLog.externalFiles ?? []).map((f) => f.path));
12168
13034
  for (const p2 of UNINSTALL_SHARED) {
12169
- if (recordedShared.has(p2) && existsSync26(join34(projectDir, p2))) need.add(p2);
13035
+ if (recordedShared.has(p2) && existsSync26(join35(projectDir, p2))) need.add(p2);
12170
13036
  if (made.has(p2)) parentOf(p2);
12171
13037
  }
12172
13038
  for (const p2 of harnessCandidates(installLog)) parentOf(p2);
13039
+ for (const p2 of legacyFileCandidates()) parentOf(p2);
12173
13040
  for (const f of installLog.rootFiles ?? []) if (f.change === "displaced") parentOf(f.path);
12174
13041
  if (hasRootImport(projectDir)) need.add("CLAUDE.md");
12175
13042
  }
12176
13043
  return [...need].filter((p2) => {
12177
13044
  try {
12178
- accessSync(join34(projectDir, p2), fsConstants.W_OK);
13045
+ accessSync2(join35(projectDir, p2), fsConstants2.W_OK);
12179
13046
  return false;
12180
13047
  } catch (e2) {
12181
13048
  return e2.code !== "ENOENT";
@@ -12184,7 +13051,7 @@ function unwritablePaths(ctx) {
12184
13051
  }
12185
13052
  function safeExists(abs) {
12186
13053
  try {
12187
- lstatSync5(abs);
13054
+ lstatSync6(abs);
12188
13055
  return true;
12189
13056
  } catch {
12190
13057
  return false;
@@ -12249,8 +13116,9 @@ function settleLog(ctx, io) {
12249
13116
  const { installLog, projectDir, selectedIds, removedIds } = ctx;
12250
13117
  if (selectedIds) {
12251
13118
  const remaining = installLog.assets.filter((a) => !removedIds.includes(a.id));
13119
+ const rootFiles = ctx.displaced.some((d2) => d2.forget) ? { rootFiles: withoutRestored(installLog.rootFiles, ctx.displaced) } : {};
12252
13120
  try {
12253
- io.writeLog(projectDir, { ...installLog, assets: remaining });
13121
+ io.writeLog(projectDir, { ...installLog, assets: remaining, ...rootFiles });
12254
13122
  io.log(` ${status.success(`install log updated (${remaining.length} asset(s) remain)`)}`);
12255
13123
  } catch (e2) {
12256
13124
  io.err(status.failure(c.red(`ERROR: install log \uAC31\uC2E0 \uC2E4\uD328 \u2014 ${installLogPath(projectDir)}`)));
@@ -12259,10 +13127,10 @@ function settleLog(ctx, io) {
12259
13127
  return true;
12260
13128
  }
12261
13129
  } else {
12262
- io.rm(join34(projectDir, INSTALL_LOG_DIR));
13130
+ io.rm(join35(projectDir, INSTALL_LOG_DIR));
12263
13131
  if (outsideLinkAt(projectDir, LEGACY_INSTALL_LOG_DIR) === null) {
12264
13132
  io.rm(legacyInstallLogPath(projectDir));
12265
- pruneEmptyDirsUpward(projectDir, join34(projectDir, LEGACY_INSTALL_LOG_DIR));
13133
+ pruneEmptyDirsUpward(projectDir, join35(projectDir, LEGACY_INSTALL_LOG_DIR));
12266
13134
  }
12267
13135
  io.log(` ${status.success("install log removed")}`);
12268
13136
  }
@@ -12286,9 +13154,17 @@ function dryRunLines(plan, installLog, projectDir, assetsOnly, rootFiles, harnes
12286
13154
  rm: () => {
12287
13155
  },
12288
13156
  write: false,
12289
- harnessRoot
13157
+ harnessRoot,
13158
+ assetFilesGone: plannedAssetFiles(plan, installLog)
12290
13159
  });
12291
13160
  lines2.push(...harnessRemovalLines(preview, installLog, projectDir, FULL_SCOPE, true));
13161
+ } else {
13162
+ const preview = restoreDisplaced(installLog, projectDir, {
13163
+ has: inAssetSlots(plannedAssets(plan, installLog)),
13164
+ willBeGone: new Set(plannedAssetFiles(plan, installLog)),
13165
+ write: false
13166
+ });
13167
+ lines2.push(...displacedLines(preview, true));
12292
13168
  }
12293
13169
  lines2.push(...advisoryLines(plan, projectDir, rootFiles, globalTrust), "");
12294
13170
  return lines2;
@@ -12320,7 +13196,7 @@ function advisoryLines(plan, projectDir, rootFiles, globalTrust) {
12320
13196
  }
12321
13197
  function backupArtifactAdvisoryLines(projectDir) {
12322
13198
  const found = [];
12323
- for (const e2 of readdirSync6(projectDir, { withFileTypes: true })) {
13199
+ for (const e2 of readdirSync7(projectDir, { withFileTypes: true })) {
12324
13200
  if (CLI_FOLDERS2.some((d2) => e2.name.startsWith(`${d2}.backup-`))) {
12325
13201
  found.push(e2.name);
12326
13202
  } else if (e2.isFile() && BACKUP_SUFFIX.test(e2.name)) {
@@ -12329,7 +13205,7 @@ function backupArtifactAdvisoryLines(projectDir) {
12329
13205
  }
12330
13206
  for (const dir of BACKUP_SCAN_DIRS) {
12331
13207
  if (dir === INSTALL_LOG_DIR) continue;
12332
- const abs = join34(projectDir, dir);
13208
+ const abs = join35(projectDir, dir);
12333
13209
  if (!existsSync26(abs) || outsideLinkAt(projectDir, dir) !== null) continue;
12334
13210
  for (const rel of listFilesRecursive(abs)) {
12335
13211
  if (BACKUP_SUFFIX.test(rel)) found.push(`${dir}/${rel}`);
@@ -12345,11 +13221,11 @@ function backupArtifactAdvisoryLines(projectDir) {
12345
13221
  }
12346
13222
  function rootFileAdvisoryLines(rootFiles, projectDir) {
12347
13223
  const header = "[ROOT] `.claude/` \uBC16\uC5D0 \uB0A8\uB294 \uAC83 (\uC790\uB3D9\uC73C\uB85C \uC9C0\uC6B0\uC9C0 \uC54A\uB294\uB2E4):";
12348
- const present2 = rootFiles.filter((f) => existsSync26(join34(projectDir, f.path)));
13224
+ const present2 = rootFiles.filter((f) => existsSync26(join35(projectDir, f.path)));
12349
13225
  if (present2.length === 0) return [];
12350
13226
  const outside = /* @__PURE__ */ new Map();
12351
13227
  const inside = present2.filter((f) => {
12352
- const o = outsideProjectTarget(projectDir, join34(projectDir, f.path));
13228
+ const o = outsideProjectTarget(projectDir, join35(projectDir, f.path));
12353
13229
  if (o === null) return true;
12354
13230
  const group = outside.get(o.link) ?? { link: o, files: [] };
12355
13231
  group.files.push(f.path);
@@ -12388,7 +13264,7 @@ function rootFileMeaning(f, projectDir) {
12388
13264
  case "displaced": {
12389
13265
  const backup = f.notes[0];
12390
13266
  if (backup === void 0) return "\uD558\uB124\uC2A4 \uD310\uACFC \uAC19\uC740 \uC124\uCE58\uC790 \uD30C\uC77C\uC774 \uC788\uB358 \uC790\uB9AC (\uADF8\uB300\uB85C \uB450\uC5C8\uB2E4)";
12391
- return existsSync26(join34(projectDir, backup)) ? `\uD558\uB124\uC2A4\uAC00 \uC4F4 \uC790\uB9AC \u2014 \uC6D0\uB798 \uC788\uB358 \uC124\uCE58\uC790 \uD30C\uC77C\uC740 ${backup} \uC5D0 \uC788\uB2E4` : `\uD558\uB124\uC2A4\uAC00 \uC4F4 \uC790\uB9AC \u2014 \uC6D0\uB798 \uC788\uB358 \uC124\uCE58\uC790 \uD30C\uC77C\uC758 \uBC31\uC5C5(${backup})\uC774 \uB354\uB294 \uC5C6\uB2E4`;
13267
+ return existsSync26(join35(projectDir, backup)) ? `\uD558\uB124\uC2A4\uAC00 \uC4F4 \uC790\uB9AC \u2014 \uC6D0\uB798 \uC788\uB358 \uC124\uCE58\uC790 \uD30C\uC77C\uC740 ${backup} \uC5D0 \uC788\uB2E4` : `\uD558\uB124\uC2A4\uAC00 \uC4F4 \uC790\uB9AC \u2014 \uC6D0\uB798 \uC788\uB358 \uC124\uCE58\uC790 \uD30C\uC77C\uC758 \uBC31\uC5C5(${backup})\uC774 \uB354\uB294 \uC5C6\uB2E4`;
12392
13268
  }
12393
13269
  }
12394
13270
  }
@@ -12491,9 +13367,19 @@ function agentsMdRerenderSet(target, remaining, log, projectDir) {
12491
13367
  const set = agentsMdClis(remaining);
12492
13368
  if (set.length === 0) return null;
12493
13369
  const recorded2 = (log.externalFiles ?? []).some((f) => f.path === AGENTS_MD2) || (log.portions ?? []).some((p2) => p2.path === AGENTS_MD2);
12494
- if (!recorded2 || !existsSync26(join34(projectDir, AGENTS_MD2))) return null;
13370
+ if (!existsSync26(join35(projectDir, AGENTS_MD2))) return null;
13371
+ if (!recorded2 && !isLegacyHarnessAgentsMd(readTextOrEmpty(join35(projectDir, AGENTS_MD2)))) {
13372
+ return null;
13373
+ }
12495
13374
  return set;
12496
13375
  }
13376
+ function readTextOrEmpty(abs) {
13377
+ try {
13378
+ return readFileSync26(abs, "utf8");
13379
+ } catch {
13380
+ return "";
13381
+ }
13382
+ }
12497
13383
  function rerenderAgentsMd(ctx, set) {
12498
13384
  const { installLog, projectDir, harnessRoot } = ctx;
12499
13385
  return runAgentsMdTransform({
@@ -12512,10 +13398,11 @@ function withRerender(next, r) {
12512
13398
  const files = mergeExternalFiles(next.externalFiles, r.ownership.files);
12513
13399
  if (files.length > 0) out.externalFiles = files;
12514
13400
  const block = r.agentsMd.shared;
12515
- if (block !== null && block.portions !== null) {
13401
+ const blockPortions = block !== null && block.portions !== null ? block.portions : r.agentsMd.blockRecordDropped === true ? [] : null;
13402
+ if (blockPortions !== null) {
12516
13403
  const portions = [
12517
13404
  ...(next.portions ?? []).filter((p2) => p2.path !== AGENTS_MD2),
12518
- ...block.portions
13405
+ ...blockPortions
12519
13406
  ];
12520
13407
  if (portions.length > 0) out.portions = portions;
12521
13408
  else delete out.portions;
@@ -12555,11 +13442,8 @@ function settleCliLog(ctx, target, remaining, done, anchorRemoved) {
12555
13442
  const survivors = (installLog.externalFiles ?? []).filter((f) => !done.forgotten.has(f.path));
12556
13443
  if (survivors.length > 0) next.externalFiles = survivors;
12557
13444
  else delete next.externalFiles;
12558
- const settled = new Set(done.displaced.filter((d2) => d2.forget).map((d2) => d2.path));
12559
13445
  if (installLog.rootFiles !== void 0) {
12560
- next.rootFiles = installLog.rootFiles.filter(
12561
- (f) => !(f.change === "displaced" && settled.has(f.path))
12562
- );
13446
+ next.rootFiles = withoutRestored(installLog.rootFiles, done.displaced);
12563
13447
  }
12564
13448
  const touched = new Set(done.shared.map((r) => r.path));
12565
13449
  const portions = [
@@ -12621,20 +13505,21 @@ var SKILLS_LOCK = "skills-lock.json";
12621
13505
  function withSkillsLock(rootFiles, assets, projectDir) {
12622
13506
  const out = [...rootFiles];
12623
13507
  const skills = assets.some((a) => a.method === "skill" && a.scope === "project");
12624
- if (skills && !out.some((f) => f.path === SKILLS_LOCK) && existsSync26(join34(projectDir, SKILLS_LOCK))) {
13508
+ if (skills && !out.some((f) => f.path === SKILLS_LOCK) && existsSync26(join35(projectDir, SKILLS_LOCK))) {
12625
13509
  out.push({ path: SKILLS_LOCK, change: "advisory", notes: [] });
12626
13510
  }
12627
13511
  return out;
12628
13512
  }
12629
- function remnantFor(path, log, harnessRoot, projectDir) {
13513
+ function remnantFor(path, log, harnessRoot, projectDir, wiringGone = []) {
12630
13514
  const clis = installedClis(log);
12631
13515
  if (path === SETTINGS_TARGET) {
13516
+ const gone = (k2) => wiringGone.includes(`hooks/${k2.split("#")[1] ?? ""}`);
12632
13517
  return (disk) => {
12633
13518
  try {
12634
- const template = readFileSync26(join34(harnessRoot, "templates", "settings.json"), "utf8");
13519
+ const template = readFileSync26(join35(harnessRoot, "templates", "settings.json"), "utf8");
12635
13520
  const render = renderSettingsPortion(template, () => true);
12636
- return [...legacySettingsSeed(disk, render, projectDir).keys()].filter(
12637
- (k2) => !k2.endsWith("{}")
13521
+ return [...legacySettingsSeed(disk, render, projectDir, { edited: true }).keys()].filter(
13522
+ (k2) => !k2.endsWith("{}") && !gone(k2)
12638
13523
  );
12639
13524
  } catch {
12640
13525
  return [];
@@ -12761,7 +13646,7 @@ function noReverseHints(asset, ctx) {
12761
13646
  }
12762
13647
  if (asset.method !== "skill") return [];
12763
13648
  const name = asset.detail.skill;
12764
- const left = name === void 0 ? [] : [".claude/skills", ".agents/skills"].map((root) => `${root}/${name}/`).filter((p2) => existsSync26(join34(ctx.projectDir, p2)));
13649
+ const left = name === void 0 ? [] : [".claude/skills", ".agents/skills"].map((root) => `${root}/${name}/`).filter((p2) => existsSync26(join35(ctx.projectDir, p2)));
12765
13650
  return [
12766
13651
  left.length > 0 ? `files it put down are not on record (installed by an older version) \u2014 left: ${left.join(" \xB7 ")} (delete by hand if the harness installed it)` : "files it put down are not on record (installed by an older version) \u2014 nothing removed"
12767
13652
  ];
@@ -12861,21 +13746,31 @@ function removeHarnessFiles(log, projectDir, scope, io) {
12861
13746
  forgotten: /* @__PURE__ */ new Set(),
12862
13747
  stripped: [],
12863
13748
  kept: [],
13749
+ legacyAgentsMd: [],
12864
13750
  unjudged: [],
12865
13751
  outside: [],
12866
13752
  displaced: [],
12867
13753
  shared: [],
12868
13754
  retiredWiring: [],
13755
+ legacyWiring: [],
12869
13756
  importStripped: false,
12870
13757
  anchor: { removed: false, lines: [] }
12871
13758
  };
12872
13759
  const pruneFrom = [];
12873
- stripSharedFiles(log, projectDir, scope.shared, io, out, pruneFrom);
12874
13760
  const isTarget = harnessTargets(log);
12875
- for (const path of harnessCandidates(log)) {
13761
+ const candidates = harnessCandidates(log);
13762
+ for (const path of candidates) {
12876
13763
  if (scope.has(path))
12877
13764
  removeRecordedFile(path, { log, projectDir, io, out, isTarget, pruneFrom });
12878
13765
  }
13766
+ const judged = new Set(candidates);
13767
+ for (const path of legacyFileCandidates()) {
13768
+ if (judged.has(path) || !scope.has(path) || !safeExists(join35(projectDir, path))) continue;
13769
+ if (recorded(log, path, { isTarget }).state !== "none") continue;
13770
+ removeRecordedFile(path, { log, projectDir, io, out, isTarget, pruneFrom });
13771
+ }
13772
+ out.legacyWiring = removeLegacyHookWiring(log, projectDir, scope, io, out.removed);
13773
+ stripSharedFiles(log, projectDir, scope.shared, io, out, pruneFrom);
12879
13774
  if (scope.importBlock) {
12880
13775
  out.importStripped = io.write ? stripRootImport(projectDir) : hasRootImport(projectDir);
12881
13776
  }
@@ -12884,11 +13779,19 @@ function removeHarnessFiles(log, projectDir, scope, io) {
12884
13779
  const anchorPath = log.templates?.rootClaudeMd?.path;
12885
13780
  if (out.anchor.removed && anchorPath !== void 0) out.removedAnchor = anchorPath;
12886
13781
  }
12887
- restoreDisplaced(log, projectDir, scope, io, out);
13782
+ out.displaced = restoreDisplaced(log, projectDir, {
13783
+ has: scope.has,
13784
+ willBeGone: /* @__PURE__ */ new Set([
13785
+ ...out.removed,
13786
+ ...out.removedAnchor === void 0 ? [] : [out.removedAnchor],
13787
+ ...io.assetFilesGone ?? []
13788
+ ]),
13789
+ write: io.write
13790
+ });
12888
13791
  if (io.write) {
12889
- for (const p2 of pruneFrom) pruneEmptyDirsUpward(projectDir, dirname7(join34(projectDir, p2)));
13792
+ for (const p2 of pruneFrom) pruneEmptyDirsUpward(projectDir, dirname8(join35(projectDir, p2)));
12890
13793
  for (const d2 of scope.skeleton) {
12891
- const abs = join34(projectDir, d2);
13794
+ const abs = join35(projectDir, d2);
12892
13795
  if (outsideProjectTarget(projectDir, abs) !== null) continue;
12893
13796
  pruneEmptyDirsUpward(projectDir, abs);
12894
13797
  }
@@ -12917,14 +13820,14 @@ function templateNext(harnessRoot, log, path) {
12917
13820
  if (path === INSTALLED_TRACKS) return installedTracksText(log.spec.tracks.filter(isTrack));
12918
13821
  if (!path.startsWith(CLAUDE_DIR3)) return null;
12919
13822
  try {
12920
- return readFileSync26(join34(harnessRoot, "templates", path.slice(CLAUDE_DIR3.length)), "utf8");
13823
+ return readFileSync26(join35(harnessRoot, "templates", path.slice(CLAUDE_DIR3.length)), "utf8");
12921
13824
  } catch {
12922
13825
  return null;
12923
13826
  }
12924
13827
  }
12925
13828
  function removeRecordedFile(path, ctx) {
12926
13829
  const { log, projectDir, io, out } = ctx;
12927
- const abs = join34(projectDir, path);
13830
+ const abs = join35(projectDir, path);
12928
13831
  let foreign;
12929
13832
  try {
12930
13833
  foreign = foreignOwnedTarget(projectDir, path);
@@ -12943,7 +13846,7 @@ function removeRecordedFile(path, ctx) {
12943
13846
  }
12944
13847
  let st2;
12945
13848
  try {
12946
- st2 = lstatSync5(abs, { throwIfNoEntry: false });
13849
+ st2 = lstatSync6(abs, { throwIfNoEntry: false });
12947
13850
  } catch {
12948
13851
  out.unjudged.push(path);
12949
13852
  return;
@@ -12966,17 +13869,20 @@ function removeRecordedFile(path, ctx) {
12966
13869
  out.unjudged.push(path);
12967
13870
  return;
12968
13871
  }
13872
+ const rec = recorded(log, path, { isTarget: ctx.isTarget });
13873
+ const legacy = rec.state !== "sha" && isLegacyHarnessFile(path, hashContent(disk)) && (rec.state === "no-sha" || mayReclaimLegacy(log, path));
13874
+ const inBundle = legacy && ctx.isTarget(bundlePath(path));
12969
13875
  const verdict = judge({
12970
13876
  op: "remove",
12971
13877
  kind: "harness",
12972
- rec: recorded(log, path, { isTarget: ctx.isTarget }),
13878
+ rec: legacy ? { state: "no-sha" } : rec,
12973
13879
  disk,
12974
- next: templateNext(io.harnessRoot, log, path)
13880
+ next: legacy ? inBundle ? disk : null : templateNext(io.harnessRoot, log, path)
12975
13881
  });
12976
13882
  if (verdict.verdict !== "remove" && verdict.verdict !== "backup+remove") return;
12977
13883
  let backup = null;
12978
13884
  if (verdict.verdict === "backup+remove") {
12979
- backup = io.write ? relative5(projectDir, backupFile(effective)).split(sep5).join("/") : `${relative5(projectDir, effective).split(sep5).join("/")}.backup-<time>`;
13885
+ backup = io.write ? relative6(projectDir, backupFile(effective)).split(sep6).join("/") : `${relative6(projectDir, effective).split(sep6).join("/")}.backup-<time>`;
12980
13886
  }
12981
13887
  if (io.write) {
12982
13888
  if (effective !== abs) io.rm(abs);
@@ -12985,7 +13891,34 @@ function removeRecordedFile(path, ctx) {
12985
13891
  out.removed.push(path);
12986
13892
  out.forgotten.add(path);
12987
13893
  ctx.pruneFrom.push(path);
12988
- if (backup !== null) out.backedUp.push({ path, backup, line: verdict.line });
13894
+ if (backup !== null)
13895
+ out.backedUp.push({ path, backup, line: legacy && !inBundle ? LEGACY_SAVED : verdict.line });
13896
+ }
13897
+ var LEGACY_SAVED = "older harness version (byte-identical, not in the current bundle) \u2014 saved a copy, removed from live";
13898
+ function legacyFileCandidates() {
13899
+ return [...LEGACY_HARNESS_FILES.keys()].flatMap(
13900
+ (p2) => p2.startsWith(SKILLS_DIR3) ? [p2, `.agents/skills/${p2.slice(SKILLS_DIR3.length)}`] : [p2]
13901
+ );
13902
+ }
13903
+ function bundlePath(path) {
13904
+ return path.startsWith(".agents/skills/") ? `${SKILLS_DIR3}${path.slice(".agents/skills/".length)}` : path;
13905
+ }
13906
+ function mayReclaimLegacy(log, path) {
13907
+ const clis = installedClis(log);
13908
+ if (!ownersOf(path).some((c3) => clis.includes(c3))) return false;
13909
+ if (isExcludedPath(bundlePath(path), excludedIds(log))) return false;
13910
+ return !(log.rootFiles ?? []).some((f) => f.path === path && f.change === "displaced");
13911
+ }
13912
+ function removeLegacyHookWiring(log, projectDir, scope, io, removed) {
13913
+ if (!scope.has(SETTINGS_TARGET) || !installedClis(log).includes("claude")) return [];
13914
+ if ((log.portions ?? []).some((p2) => p2.path === SETTINGS_TARGET)) return [];
13915
+ const abs = join35(projectDir, SETTINGS_TARGET);
13916
+ if (!safeExists(abs) || outsideProjectTarget(projectDir, abs) !== null) return [];
13917
+ const claudeDir = join35(projectDir, ".claude");
13918
+ const gone = LEGACY_HOOK_REFS.filter(
13919
+ (r) => !RETIRED_HOOK_WIRING_REFS.includes(r) && (removed.includes(`${CLAUDE_DIR3}${r}`) || !safeExists(join35(claudeDir, r)))
13920
+ );
13921
+ return removeRetiredHookRefs(abs, claudeDir, gone, { evenIfScriptExists: true, write: io.write });
12989
13922
  }
12990
13923
  function stripSharedFiles(log, projectDir, paths, io, out, pruneFrom) {
12991
13924
  const made = new Map((log.externalFiles ?? []).map((f) => [f.path, f.sha256]));
@@ -13004,7 +13937,7 @@ function stripSharedFiles(log, projectDir, paths, io, out, pruneFrom) {
13004
13937
  };
13005
13938
  for (const path of paths) {
13006
13939
  if (!relevant(path)) continue;
13007
- const abs = join34(projectDir, path);
13940
+ const abs = join35(projectDir, path);
13008
13941
  if (safeExists(abs)) {
13009
13942
  const o = outsideProjectTarget(projectDir, abs);
13010
13943
  if (o !== null) {
@@ -13015,7 +13948,7 @@ function stripSharedFiles(log, projectDir, paths, io, out, pruneFrom) {
13015
13948
  if (path === SETTINGS_TARGET && safeExists(abs)) {
13016
13949
  out.retiredWiring = removeRetiredHookRefs(
13017
13950
  abs,
13018
- join34(projectDir, ".claude"),
13951
+ join35(projectDir, ".claude"),
13019
13952
  RETIRED_HOOK_WIRING_REFS,
13020
13953
  { evenIfScriptExists: true, write: io.write }
13021
13954
  );
@@ -13024,12 +13957,15 @@ function stripSharedFiles(log, projectDir, paths, io, out, pruneFrom) {
13024
13957
  if (sha !== void 0 && removeHarnessMadeShared(path, sha, projectDir, io, out, pruneFrom)) {
13025
13958
  continue;
13026
13959
  }
13960
+ if (path === AGENTS_MD2 && sha === void 0) {
13961
+ if (removeUnrecordedLegacyAgentsMd(path, projectDir, io, out, pruneFrom)) continue;
13962
+ }
13027
13963
  const r = stripShared({
13028
13964
  projectDir,
13029
13965
  path,
13030
13966
  portions: log.portions ?? [],
13031
13967
  excluded: [...excludedIds(log)],
13032
- remnant: remnantFor(path, log, io.harnessRoot, projectDir),
13968
+ remnant: remnantFor(path, log, io.harnessRoot, projectDir, out.legacyWiring),
13033
13969
  remnantLine: remnantLine(path),
13034
13970
  write: io.write,
13035
13971
  // 하네스가 만든 파일(#569 `created` · #13 `externalFiles`)은 몫을 걷고 남는 것이 없으면 파일째 지운다
@@ -13040,7 +13976,7 @@ function stripSharedFiles(log, projectDir, paths, io, out, pruneFrom) {
13040
13976
  }
13041
13977
  }
13042
13978
  function removeHarnessMadeShared(path, sha, projectDir, io, out, pruneFrom) {
13043
- const abs = join34(projectDir, path);
13979
+ const abs = join35(projectDir, path);
13044
13980
  if (!existsSync26(abs)) {
13045
13981
  out.forgotten.add(path);
13046
13982
  return true;
@@ -13053,7 +13989,7 @@ function removeHarnessMadeShared(path, sha, projectDir, io, out, pruneFrom) {
13053
13989
  out.unjudged.push(path);
13054
13990
  return true;
13055
13991
  }
13056
- if (lstatSync5(abs).isSymbolicLink()) effective = real;
13992
+ if (lstatSync6(abs).isSymbolicLink()) effective = real;
13057
13993
  current = readFileSync26(effective, "utf8");
13058
13994
  } catch {
13059
13995
  out.unjudged.push(path);
@@ -13061,7 +13997,15 @@ function removeHarnessMadeShared(path, sha, projectDir, io, out, pruneFrom) {
13061
13997
  }
13062
13998
  if (hashContent(current) !== sha) {
13063
13999
  if (path === AGENTS_MD2) {
13064
- out.kept.push(path);
14000
+ const verdict = isLegacyHarnessAgentsMd(current) ? agentsMdRemainder(current, io.harnessRoot) : null;
14001
+ if (verdict?.ok === true && verdict.strip.legacyRemoved) {
14002
+ removeLegacyAgentsMd(path, abs, effective, verdict.strip, {
14003
+ projectDir,
14004
+ io,
14005
+ out,
14006
+ pruneFrom
14007
+ });
14008
+ } else out.kept.push(path);
13065
14009
  return true;
13066
14010
  }
13067
14011
  out.forgotten.add(path);
@@ -13073,9 +14017,13 @@ function removeHarnessMadeShared(path, sha, projectDir, io, out, pruneFrom) {
13073
14017
  out.unjudged.push(path);
13074
14018
  return true;
13075
14019
  }
14020
+ if (verdict.strip.legacyRemoved) {
14021
+ removeLegacyAgentsMd(path, abs, effective, verdict.strip, { projectDir, io, out, pruneFrom });
14022
+ return true;
14023
+ }
13076
14024
  if (verdict.remainder !== null) {
13077
14025
  try {
13078
- if (io.write) writeFileSync10(effective, neutralizeScaffoldBanner(verdict.remainder), "utf8");
14026
+ if (io.write) writeFileSync9(effective, neutralizeScaffoldBanner(verdict.remainder), "utf8");
13079
14027
  out.stripped.push(path);
13080
14028
  out.forgotten.add(path);
13081
14029
  } catch {
@@ -13101,38 +14049,44 @@ function removeHarnessMadeShared(path, sha, projectDir, io, out, pruneFrom) {
13101
14049
  pruneFrom.push(path);
13102
14050
  return true;
13103
14051
  }
13104
- function restoreDisplaced(log, projectDir, scope, io, out) {
13105
- const willBeGone = /* @__PURE__ */ new Set([
13106
- ...out.removed,
13107
- ...out.removedAnchor === void 0 ? [] : [out.removedAnchor]
13108
- ]);
13109
- for (const f of log.rootFiles ?? []) {
13110
- if (f.change !== "displaced" || !scope.has(f.path)) continue;
13111
- const slot = join34(projectDir, f.path);
13112
- if (outsideProjectTarget(projectDir, slot) !== null) continue;
13113
- const backup = f.notes[0] ?? null;
13114
- const d2 = judgeDisplaced({
13115
- backup,
13116
- backupExists: backup !== null && safeExists(join34(projectDir, backup)),
13117
- slotEmpty: !safeExists(slot) || !io.write && willBeGone.has(f.path)
13118
- });
13119
- if (io.write && d2.verdict === "restore" && backup !== null) {
13120
- mkdirSync7(dirname7(slot), { recursive: true });
13121
- renameSync(join34(projectDir, backup), slot);
13122
- }
13123
- out.displaced.push({
13124
- path: f.path,
13125
- backup,
13126
- verdict: d2.verdict,
13127
- line: d2.line,
13128
- forget: d2.record === "forget"
13129
- });
13130
- }
13131
- }
13132
14052
  function topOf(path) {
13133
14053
  const i = path.indexOf("/");
13134
14054
  return i < 0 ? path : `${path.slice(0, i)}/`;
13135
14055
  }
14056
+ function displacedLines(displaced, preview) {
14057
+ const lines2 = [];
14058
+ const restore = displaced.filter((d2) => d2.verdict === "restore");
14059
+ if (preview && restore.length > 0) {
14060
+ lines2.push(
14061
+ ` \u25CB put back ${restore.length} file(s) of yours (displaced): ${restore.map((d2) => d2.path).join(" \xB7 ")}`
14062
+ );
14063
+ }
14064
+ for (const d2 of displaced) {
14065
+ if (d2.verdict === "restore" && !preview) {
14066
+ lines2.push(` ${status.success(`put back ${d2.path} (from ${d2.backup})`)}`);
14067
+ } else if (d2.verdict === "advise") {
14068
+ lines2.push(` ${c.yellow("\u2298")} ${d2.path} \u2014 ${d2.line}`);
14069
+ }
14070
+ }
14071
+ return lines2;
14072
+ }
14073
+ function plannedAssets(plan, log) {
14074
+ const ids = new Set(plan.reverseSteps.map((s) => s.assetId));
14075
+ return log.assets.filter((a) => ids.has(a.id));
14076
+ }
14077
+ function plannedAssetFiles(plan, log) {
14078
+ return plannedAssets(plan, log).flatMap(
14079
+ (a) => a.method === "skill" && a.scope === "project" ? (a.files ?? []).map((f) => f.path) : []
14080
+ );
14081
+ }
14082
+ function inAssetSlots(assets) {
14083
+ const slots = new Set(
14084
+ assets.flatMap(
14085
+ (a) => a.method === "skill" && a.scope === "project" ? (a.files ?? []).map((f) => `${f.path.split("/").slice(0, 3).join("/")}/`) : []
14086
+ )
14087
+ );
14088
+ return (path) => [...slots].some((s) => path.startsWith(s));
14089
+ }
13136
14090
  function harnessRemovalLines(r, log, projectDir, scope, preview) {
13137
14091
  const lines2 = [];
13138
14092
  const groups = /* @__PURE__ */ new Map();
@@ -13147,7 +14101,7 @@ function harnessRemovalLines(r, log, projectDir, scope, preview) {
13147
14101
  }
13148
14102
  if (preview) {
13149
14103
  for (const [top, g] of groups) {
13150
- const edited = g.backedUp > 0 ? ` (${g.backedUp} you edited \u2192 saved beside as *.backup-<time>)` : "";
14104
+ const edited = g.backedUp > 0 ? ` (${g.backedUp} with a copy saved beside as *.backup-<time>)` : "";
13151
14105
  lines2.push(` \u25CB remove ${g.removed} harness file(s) under ${top}${edited}`);
13152
14106
  }
13153
14107
  } else if (groups.size > 0) {
@@ -13166,24 +14120,24 @@ function harnessRemovalLines(r, log, projectDir, scope, preview) {
13166
14120
  );
13167
14121
  }
13168
14122
  lines2.push(...r.anchor.lines);
13169
- const restore = r.displaced.filter((d2) => d2.verdict === "restore");
13170
- if (preview && restore.length > 0) {
13171
- lines2.push(
13172
- ` \u25CB put back ${restore.length} file(s) of yours (displaced): ${restore.map((d2) => d2.path).join(" \xB7 ")}`
13173
- );
13174
- }
13175
- for (const d2 of r.displaced) {
13176
- if (d2.verdict === "restore" && !preview) {
13177
- lines2.push(` ${status.success(`put back ${d2.path} (from ${d2.backup})`)}`);
13178
- } else if (d2.verdict === "advise") {
13179
- lines2.push(` ${c.yellow("\u2298")} ${d2.path} \u2014 ${d2.line}`);
13180
- }
13181
- }
14123
+ lines2.push(...displacedLines(r.displaced, preview));
13182
14124
  for (const path of r.stripped) {
13183
14125
  lines2.push(
13184
14126
  preview ? ` \u25CB strip harness sections from ${path} (\uBCF8\uBB38 \uBCF4\uC874)` : ` ${status.success(`${path} \u2014 harness sections removed (\uBCF8\uBB38 \uBCF4\uC874)`)}`
13185
14127
  );
13186
14128
  }
14129
+ for (const l of r.legacyAgentsMd) {
14130
+ const kept = l.keptEdited.length > 0 ? ` \xB7 kept ${l.keptEdited.length} section(s) you edited (${l.keptEdited.join(" \xB7 ")})` : "";
14131
+ if (preview) {
14132
+ lines2.push(
14133
+ l.fileRemoved ? ` \u25CB remove ${l.path} (written by an older harness version \u2014 a copy is saved first)` : ` \u25CB remove the harness sections written by an older version from ${l.path} \u2014 yours stays${kept} (a copy is saved first)`
14134
+ );
14135
+ } else {
14136
+ lines2.push(
14137
+ l.fileRemoved ? ` ${status.success(`removed ${l.path} (written by an older harness version \u2014 saved a copy: ${l.backup})`)}` : ` ${status.success(`${l.path} \u2014 removed the harness sections written by an older version \u2014 yours stays${kept} (saved a copy: ${l.backup})`)}`
14138
+ );
14139
+ }
14140
+ }
13187
14141
  for (const path of r.unjudged) {
13188
14142
  lines2.push(
13189
14143
  path === AGENTS_MD2 ? ` ${c.yellow("\u2298")} ${path} kept \u2014 harness sections could not be separated (a file or template could not be read, or the write failed). Remove manually if intended.` : ` ${c.yellow("\u2298")} ${path} left \u2014 could not read it to judge. Remove manually if intended.`
@@ -13195,6 +14149,12 @@ function harnessRemovalLines(r, log, projectDir, scope, preview) {
13195
14149
  ` ${c.yellow("\u2298")} ${path} kept \u2014 modified since install. Remove manually if intended.`
13196
14150
  );
13197
14151
  }
14152
+ if (r.legacyWiring.length > 0) {
14153
+ const refs = r.legacyWiring.join(" \xB7 ");
14154
+ lines2.push(
14155
+ preview ? ` \u25CB remove harness hook wiring from an older version (script gone) from ${SETTINGS_TARGET}: ${refs}` : ` ${status.success(`${SETTINGS_TARGET} \u2014 removed harness hook wiring from an older version (script gone): ${refs}`)}`
14156
+ );
14157
+ }
13198
14158
  if (r.retiredWiring.length > 0) {
13199
14159
  const refs = r.retiredWiring.join(" \xB7 ");
13200
14160
  lines2.push(
@@ -13245,25 +14205,25 @@ function yoursUnder(projectDir, dir) {
13245
14205
  const walk2 = (abs2, prefix) => {
13246
14206
  let entries;
13247
14207
  try {
13248
- entries = readdirSync6(abs2, { withFileTypes: true });
14208
+ entries = readdirSync7(abs2, { withFileTypes: true });
13249
14209
  } catch {
13250
14210
  return;
13251
14211
  }
13252
14212
  for (const e2 of entries) {
13253
14213
  const name = `${prefix}${e2.name}`;
13254
- if (e2.isDirectory()) walk2(join34(abs2, e2.name), `${name}/`);
14214
+ if (e2.isDirectory()) walk2(join35(abs2, e2.name), `${name}/`);
13255
14215
  else if (BACKUP_SUFFIX.test(e2.name)) continue;
13256
14216
  else if (e2.isSymbolicLink()) {
13257
14217
  let target = "?";
13258
14218
  try {
13259
- target = readlinkSync(join34(abs2, e2.name));
14219
+ target = readlinkSync(join35(abs2, e2.name));
13260
14220
  } catch {
13261
14221
  }
13262
14222
  out.push({ name, shown: `${name} (your link \u2192 ${target})` });
13263
14223
  } else out.push({ name, shown: name });
13264
14224
  }
13265
14225
  };
13266
- const abs = join34(projectDir, dir);
14226
+ const abs = join35(projectDir, dir);
13267
14227
  try {
13268
14228
  if (!statSync5(abs).isDirectory()) return [];
13269
14229
  } catch {
@@ -13275,7 +14235,7 @@ function yoursUnder(projectDir, dir) {
13275
14235
  function assetsLeftLines(log, projectDir, scope) {
13276
14236
  const lines2 = [];
13277
14237
  for (const a of log.assets) {
13278
- const here = (a.files ?? []).map((f) => f.path).filter((p2) => scope.has(p2) && safeExists(join34(projectDir, p2)));
14238
+ const here = (a.files ?? []).map((f) => f.path).filter((p2) => scope.has(p2) && safeExists(join35(projectDir, p2)));
13279
14239
  if (here.length === 0) continue;
13280
14240
  const slots = [...new Set(here.map((p2) => p2.split("/").slice(0, 3).join("/")))].sort();
13281
14241
  lines2.push(
@@ -13287,7 +14247,7 @@ function assetsLeftLines(log, projectDir, scope) {
13287
14247
  function removeAnchor(log, projectDir, io) {
13288
14248
  const rootMd = log.templates?.rootClaudeMd;
13289
14249
  if (!rootMd) return { removed: false, lines: [] };
13290
- const abs = join34(projectDir, rootMd.path);
14250
+ const abs = join35(projectDir, rootMd.path);
13291
14251
  if (!existsSync26(abs)) return { removed: false, lines: [] };
13292
14252
  const outside = outsideProjectTarget(projectDir, abs);
13293
14253
  if (outside !== null) return { removed: false, lines: outsideLines([outside], log) };
@@ -13326,7 +14286,7 @@ function removeAnchor(log, projectDir, io) {
13326
14286
  ]
13327
14287
  };
13328
14288
  }
13329
- const backup = edited ? relative5(projectDir, backupFile(abs)).split(sep5).join("/") : null;
14289
+ const backup = edited ? relative6(projectDir, backupFile(abs)).split(sep6).join("/") : null;
13330
14290
  io.rm(abs);
13331
14291
  return {
13332
14292
  removed: true,
@@ -13338,7 +14298,7 @@ function removeAnchor(log, projectDir, io) {
13338
14298
  var AGENTS_MD2 = "AGENTS.md";
13339
14299
  function readAgentsMdTemplate(harnessRoot) {
13340
14300
  try {
13341
- return readFileSync26(join34(harnessRoot, AGENTS_MD_TEMPLATE), "utf8");
14301
+ return readFileSync26(join35(harnessRoot, AGENTS_MD_TEMPLATE), "utf8");
13342
14302
  } catch {
13343
14303
  return null;
13344
14304
  }
@@ -13356,24 +14316,70 @@ function neutralizeScaffoldBanner(text) {
13356
14316
  function agentsMdRemainder(current, harnessRoot) {
13357
14317
  const template = readAgentsMdTemplate(harnessRoot);
13358
14318
  if (template === null) return { ok: false };
13359
- return {
13360
- ok: true,
13361
- remainder: stripHarnessFromAgentsMd({
13362
- existing: current,
13363
- template,
13364
- harnessRuleHeadings: ruleHeadings(harnessRoot)
13365
- })
13366
- };
14319
+ const strip = stripAgentsMd({
14320
+ existing: current,
14321
+ template,
14322
+ harnessRuleHeadings: ruleHeadings(harnessRoot)
14323
+ });
14324
+ return { ok: true, remainder: strip.remainder, strip };
14325
+ }
14326
+ function removeUnrecordedLegacyAgentsMd(path, projectDir, io, out, pruneFrom) {
14327
+ const abs = join35(projectDir, path);
14328
+ let effective = abs;
14329
+ let current;
14330
+ try {
14331
+ const real = realpathSync3(abs);
14332
+ if (!statSync5(real).isFile()) return false;
14333
+ if (lstatSync6(abs).isSymbolicLink()) effective = real;
14334
+ current = readFileSync26(effective, "utf8");
14335
+ } catch {
14336
+ return false;
14337
+ }
14338
+ if (!isLegacyHarnessAgentsMd(current)) return false;
14339
+ const verdict = agentsMdRemainder(current, io.harnessRoot);
14340
+ if (!verdict.ok) {
14341
+ out.unjudged.push(path);
14342
+ return true;
14343
+ }
14344
+ removeLegacyAgentsMd(path, abs, effective, verdict.strip, { projectDir, io, out, pruneFrom });
14345
+ return true;
14346
+ }
14347
+ function removeLegacyAgentsMd(path, abs, effective, strip, ctx) {
14348
+ const { projectDir, io, out } = ctx;
14349
+ let backup = `${path}.backup-<time>`;
14350
+ try {
14351
+ if (io.write) {
14352
+ backup = relative6(projectDir, backupFile(effective)).split(sep6).join("/");
14353
+ if (strip.remainder !== null) {
14354
+ writeFileSync9(effective, neutralizeScaffoldBanner(strip.remainder), "utf8");
14355
+ } else {
14356
+ if (effective !== abs) io.rm(abs);
14357
+ io.rm(effective);
14358
+ }
14359
+ }
14360
+ } catch {
14361
+ out.unjudged.push(path);
14362
+ return;
14363
+ }
14364
+ if (strip.remainder === null) ctx.pruneFrom.push(path);
14365
+ out.legacyAgentsMd.push({
14366
+ path,
14367
+ backup,
14368
+ fileRemoved: strip.remainder === null,
14369
+ keptEdited: strip.keptEdited
14370
+ });
14371
+ out.forgotten.add(path);
14372
+ out.shared.push({ path, action: "none", line: "", removed: [], kept: [], portions: [] });
13367
14373
  }
13368
14374
  function removeToolFiles(files, projectDir, rm) {
13369
14375
  const notes = [];
13370
14376
  const removed = [];
13371
14377
  let failed = 0;
13372
14378
  for (const { path, sha256 } of files) {
13373
- const abs = join34(projectDir, path);
14379
+ const abs = join35(projectDir, path);
13374
14380
  let isLink;
13375
14381
  try {
13376
- isLink = lstatSync5(abs).isSymbolicLink();
14382
+ isLink = lstatSync6(abs).isSymbolicLink();
13377
14383
  } catch {
13378
14384
  continue;
13379
14385
  }
@@ -13389,7 +14395,7 @@ function removeToolFiles(files, projectDir, rm) {
13389
14395
  try {
13390
14396
  if (hashContent(readFileSync26(abs, "utf8")) !== sha256) {
13391
14397
  const backup = backupFile(abs);
13392
- notes.push(`backed up ${path} \u2192 ${relative5(projectDir, backup)} (changed since install)`);
14398
+ notes.push(`backed up ${path} \u2192 ${relative6(projectDir, backup)} (changed since install)`);
13393
14399
  }
13394
14400
  rm(abs);
13395
14401
  removed.push(path);
@@ -13398,21 +14404,21 @@ function removeToolFiles(files, projectDir, rm) {
13398
14404
  notes.push(`left ${path} \u2014 ${e2 instanceof Error ? e2.message : String(e2)}`);
13399
14405
  }
13400
14406
  }
13401
- for (const path of removed) pruneEmptyDirsUpward(projectDir, dirname7(join34(projectDir, path)));
14407
+ for (const path of removed) pruneEmptyDirsUpward(projectDir, dirname8(join35(projectDir, path)));
13402
14408
  return failed > 0 ? { ok: false, message: `${failed} file(s) could not be removed`, notes } : { ok: true, notes };
13403
14409
  }
13404
14410
  function pruneEmptyDirsUpward(projectDir, startDir) {
13405
14411
  let cursor = startDir;
13406
14412
  while (true) {
13407
- const rel = relative5(projectDir, cursor);
13408
- if (rel === "" || rel.startsWith(`..${sep5}`) || rel === "..") return;
14413
+ const rel = relative6(projectDir, cursor);
14414
+ if (rel === "" || rel.startsWith(`..${sep6}`) || rel === "..") return;
13409
14415
  try {
13410
- if (readdirSync6(cursor).length > 0) return;
13411
- rmdirSync2(cursor);
14416
+ if (readdirSync7(cursor).length > 0) return;
14417
+ rmdirSync3(cursor);
13412
14418
  } catch {
13413
14419
  return;
13414
14420
  }
13415
- cursor = dirname7(cursor);
14421
+ cursor = dirname8(cursor);
13416
14422
  }
13417
14423
  }
13418
14424
  function stripRootImport(projectDir) {
@@ -13420,8 +14426,8 @@ function stripRootImport(projectDir) {
13420
14426
  const stripped = current === null ? null : stripHarnessImport(current);
13421
14427
  if (stripped === null) return false;
13422
14428
  try {
13423
- backupIfLossyUtf8(join34(projectDir, "CLAUDE.md"));
13424
- writeFileSync10(join34(projectDir, "CLAUDE.md"), stripped, "utf8");
14429
+ backupIfLossyUtf8(join35(projectDir, "CLAUDE.md"));
14430
+ writeFileSync9(join35(projectDir, "CLAUDE.md"), stripped, "utf8");
13425
14431
  return true;
13426
14432
  } catch {
13427
14433
  return false;
@@ -13432,7 +14438,7 @@ function hasRootImport(projectDir) {
13432
14438
  return current !== null && stripHarnessImport(current) !== null;
13433
14439
  }
13434
14440
  function readRootClaudeMd(projectDir) {
13435
- const path = join34(projectDir, "CLAUDE.md");
14441
+ const path = join35(projectDir, "CLAUDE.md");
13436
14442
  if (!existsSync26(path)) return null;
13437
14443
  try {
13438
14444
  return readFileSync26(path, "utf8");
@@ -13445,7 +14451,7 @@ function defaultSpawn2(cmd, args) {
13445
14451
  }
13446
14452
  function defaultRm(path) {
13447
14453
  if (existsSync26(path)) {
13448
- rmSync4(path, { recursive: true, force: true });
14454
+ rmSync5(path, { recursive: true, force: true });
13449
14455
  }
13450
14456
  }
13451
14457
  function registerUninstallCommand(cli) {