@uzysjung/agent-harness 26.169.0 → 26.171.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/{chunk-SU2RUN2W.js → chunk-U4X4Z333.js} +13 -56
- package/dist/chunk-U4X4Z333.js.map +1 -0
- package/dist/index.js +1894 -1062
- package/dist/index.js.map +1 -1
- package/dist/trust-tier-drift.js +1 -1
- package/package.json +2 -1
- package/templates/agents/implementer.md +3 -0
- package/templates/agents/reviewer.md +13 -65
- package/dist/chunk-SU2RUN2W.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -37,20 +37,18 @@ 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
|
-
collectPolicyHashes,
|
|
51
|
-
collectSkillHashes,
|
|
52
51
|
continuousNoteEnd,
|
|
53
|
-
copyDir,
|
|
54
52
|
copyFile,
|
|
55
53
|
corruptedInstallLogMessage,
|
|
56
54
|
createOutsideGuard,
|
|
@@ -70,7 +68,6 @@ import {
|
|
|
70
68
|
isAssetSelected,
|
|
71
69
|
isCliBase,
|
|
72
70
|
isCliNeutralTarget,
|
|
73
|
-
isHarnessOwned,
|
|
74
71
|
isInstallScope,
|
|
75
72
|
isKeyId,
|
|
76
73
|
isOutsideProject,
|
|
@@ -104,7 +101,7 @@ import {
|
|
|
104
101
|
targetsInclude,
|
|
105
102
|
upsertHarnessImport,
|
|
106
103
|
writeInstallLog
|
|
107
|
-
} from "./chunk-
|
|
104
|
+
} from "./chunk-U4X4Z333.js";
|
|
108
105
|
|
|
109
106
|
// node_modules/sisteransi/src/index.js
|
|
110
107
|
var require_src = __commonJS({
|
|
@@ -802,6 +799,594 @@ import { join as join2 } from "path";
|
|
|
802
799
|
init_esm_shims();
|
|
803
800
|
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
804
801
|
import { join } from "path";
|
|
802
|
+
|
|
803
|
+
// src/legacy-fingerprints.ts
|
|
804
|
+
init_esm_shims();
|
|
805
|
+
import { createHash } from "crypto";
|
|
806
|
+
function legacySectionKey(lines2) {
|
|
807
|
+
const out = lines2.map((l) => l.replace(/\r$/, "").trimEnd());
|
|
808
|
+
while (out.length > 1 && out.at(-1) === "") out.pop();
|
|
809
|
+
return createHash("sha256").update(out.join("\n")).digest("hex");
|
|
810
|
+
}
|
|
811
|
+
function legacyPreambleKey(text) {
|
|
812
|
+
const pre = [];
|
|
813
|
+
for (const line of text.split("\n")) {
|
|
814
|
+
if (/^## /.test(line)) break;
|
|
815
|
+
pre.push(line);
|
|
816
|
+
}
|
|
817
|
+
const head = pre.filter((l) => !/^# /.test(l));
|
|
818
|
+
return head.some((l) => l.trim() !== "") ? legacySectionKey(head) : null;
|
|
819
|
+
}
|
|
820
|
+
function rows(text) {
|
|
821
|
+
return text.split("\n").filter((l) => l !== "").map((l) => l.split(" "));
|
|
822
|
+
}
|
|
823
|
+
function keySet(text) {
|
|
824
|
+
return new Set(rows(text).map((r) => r[0] ?? ""));
|
|
825
|
+
}
|
|
826
|
+
var FILES = `
|
|
827
|
+
.claude/CLAUDE.md c8a0f19e0c84faec6fc0a999efbf205d72270a1f8bcb8d28894d564431405b52
|
|
828
|
+
.claude/CLAUDE.md c833b9a2b3e762563bdf8984520257579408de387ce3021ac2c606551f39aa75
|
|
829
|
+
.claude/CLAUDE.md 5a167acf64d246b278f878228f07cf76fe2a808e201d3d82c1c0274f50d736de
|
|
830
|
+
.claude/CLAUDE.md 7fbfe6999a82a880a3a0d34bdaf8e263cfd9c927ef5fb33873059182094d3f7f
|
|
831
|
+
.claude/CLAUDE.md 1dc65a4d8c0f2c47d541852f767d85dca41637d7b4009db6dbf41a0beb20ff68
|
|
832
|
+
.claude/CLAUDE.md db2c8bc13b4d9882c71ab1977e5fc5aa66fb031d5943faba587ce9eba100a0b8
|
|
833
|
+
.claude/CLAUDE.md dca32656dfd75c8676504836501607b7c821115a6dd14cba7baafb5c631cb1ff
|
|
834
|
+
.claude/CLAUDE.md 3aeeea1767e0f910adff08340895a524df829240df93d298bb3d0e327d0711e0
|
|
835
|
+
.claude/CLAUDE.md 16347e86e7c1699db212586685a640135891ec5787ba486e0a12562d85bc9b60
|
|
836
|
+
.claude/CLAUDE.md 71db56ff054601a03f8e287a965c1eb1be64d9db1fccc3b03c1f499c2f23119a
|
|
837
|
+
.claude/CLAUDE.md d92c6bbc4c2c1c7a2547e697f7f128b7918d4e2062c9af958b729e7cb0c58308
|
|
838
|
+
.claude/CLAUDE.md 7f94cca4a8ca2f257164ba9b44360d10f99030d3b636c667f65fd0a1771e123c
|
|
839
|
+
.claude/agents/build-error-resolver.md 28597d1e97a68701999704b789a97a20a28b121b7c27ee6a6e80ab43bcd514b8
|
|
840
|
+
.claude/agents/build-error-resolver.md a050a74ed31acba06b36e8c34bc35bc0e684b6b7ab01c891dfc2d13ba94f9824
|
|
841
|
+
.claude/agents/build-error-resolver.md 59f9eb1ae55c6a943d43610cc4e74d05018d681758ac19cb31d874c51605914e
|
|
842
|
+
.claude/agents/code-reviewer.md e112e5e0bbc501788e8a3bfd2771d34e31a8564bbd87391bff7401af1509782c
|
|
843
|
+
.claude/agents/data-analyst.md 1d75c07c51b8a000e536cd8a1c23e0609d93ea51b02cd48f9877610082cb2475
|
|
844
|
+
.claude/agents/implementer.md ba0ee71bf5ae6f8aeb461b0d6161fe0869a7c45820d49145b2abf27264af7dd2
|
|
845
|
+
.claude/agents/implementer.md a12f9132a55526208837e4960c96705df595c0e1cc2870eba1e56f2a87632de1
|
|
846
|
+
.claude/agents/plan-checker.md 405be32ad0d95d8d4cbc8cddb94e7b2be74981a4dadc160aa9200156b56d40df
|
|
847
|
+
.claude/agents/plan-checker.md 467ddec15189cc4273adacd08f97e7eabe1cc164901882f2dd5bba81fbf72327
|
|
848
|
+
.claude/agents/plan-checker.md f605005ba6ebf1e3494e47e257d68a2d34317d15a47b5c8b52317d9cf914b004
|
|
849
|
+
.claude/agents/plan-checker.md 86ad22297e6f1d75d42146685d759af10698cf763feb1c9484d1f0437262e833
|
|
850
|
+
.claude/agents/plan-checker.md 451181ce44f67f747f7190aa53932565df1ce6c934da4584f03f339502fb9265
|
|
851
|
+
.claude/agents/reviewer.md 4036905c0b8deff6555c9f6cbe962609c243d063c417196cca57fc6f87139cd6
|
|
852
|
+
.claude/agents/reviewer.md 1a0153a7fcc8a170f3f08f2a4e392ca72117d413d690441b930028ce923a6094
|
|
853
|
+
.claude/agents/reviewer.md 98c63bfe35afafb28b2543e5b3c662a5df58b66b877b753efc54b9af32208298
|
|
854
|
+
.claude/agents/security-reviewer.md eacaa50c2b2fdee398ba2e3c896c018ea8887d34701e5b841278ea2c1472cc19
|
|
855
|
+
.claude/agents/silent-failure-hunter.md 004ce0389356e0666d80c89cef39ad895ab326b3f7d19d34d23c70ab249a795d
|
|
856
|
+
.claude/agents/strategist.md b217c7bd273e672de44d4df123201cc5c10203fa9bafad84a370d4b7d32b7fc6
|
|
857
|
+
.claude/agents/strategist.md b8d0b387748b5403ee6a489c7e9969f864ebad9544d3d34ee9ff1b4d40f4662f
|
|
858
|
+
.claude/commands/ecc/checkpoint.md 7462e42241b4e38ca4826750567002420f014089b81406279248e22e5879f608
|
|
859
|
+
.claude/commands/ecc/e2e.md fdc040d9d32ca1c4bcc53ccca32042983f9132240fcaca5144de51e4385b9479
|
|
860
|
+
.claude/commands/ecc/eval.md 586ffc66cf889428ff46a86c0d8067f925d58899758eea5f129c9fa62ca55f5f
|
|
861
|
+
.claude/commands/ecc/evolve.md b4a635e1fc9e70f5f53c8bb36a1e8a385e249b5802afaffcc54e17cbacc1c8ca
|
|
862
|
+
.claude/commands/ecc/harness-audit.md ba76cdd30f6fdcf9b6286de753881eebe0e15306829bc3cf53af1591e4126771
|
|
863
|
+
.claude/commands/ecc/instinct-status.md 642b16d6b155f635b76800d78618f4525fc7db9fa298e947e7651e5b3d5fe85c
|
|
864
|
+
.claude/commands/ecc/promote.md b8e6e79dd43053a183b426e88e31631dfe6c812efd37241e26798b88b3febdab
|
|
865
|
+
.claude/commands/ecc/security-scan.md 440cb02294593a8cc86bb1e707fe43a28506f2833de6e20ec811cab12a543db3
|
|
866
|
+
.claude/commands/uzys/auto.md 39e06b3164527fc59bd1cdbf156cdf1f953aab188c68603bce7a396f51921b40
|
|
867
|
+
.claude/commands/uzys/build.md 3eed86d0f9bd8b60724d829a95578e7febab0043a6bdd6353993b2a55021a908
|
|
868
|
+
.claude/commands/uzys/plan.md e1c11ecaa804b6a333f669a8a375b06fc8ba245d9683aed0f172c3fdadf8b4b7
|
|
869
|
+
.claude/commands/uzys/review.md af4e3a4af894bc161f966c64fda60cdc83d815c174f3ad1f9c0a0d40d76a07b6
|
|
870
|
+
.claude/commands/uzys/ship.md 572a644f37c41e1844b95701fe116b2b6e71f22d0ef8593725ab2de24d61207d
|
|
871
|
+
.claude/commands/uzys/spec.md 91ec49031ec683dcd9c5a2befa9b8aca3c95ffb415928b95a2fefa113e102554
|
|
872
|
+
.claude/commands/uzys/test.md 63e58f69bb431a3995b9baae6f6c55f958ae0c46a3d89740ec551fab4b3bb920
|
|
873
|
+
.claude/hooks/agentshield-gate.sh 9493cb98409a5b7b4368307ecf535f39c32d933f8f012f79c9c2b6c2fa788012
|
|
874
|
+
.claude/hooks/checkpoint-snapshot.sh 8ef77c09baa3e24740b19a7d119b83e58559cafcd8e6ab4edfaacc4e42caffef
|
|
875
|
+
.claude/hooks/checkpoint-snapshot.sh f86e7f445cad48569353b9cbce6e162074fdb5224f4b0781734f5a200b94868c
|
|
876
|
+
.claude/hooks/gate-check.sh f04831db7fbce538cc9c9cbcada62a7917e621e6275365686c4849e39da14583
|
|
877
|
+
.claude/hooks/hito-counter.sh eb79ca20fcbaa070c621d5c985422e68e5dbe6b9f4c25f7bf81ae82fe77f6d49
|
|
878
|
+
.claude/hooks/karpathy-gate.sh e72ea3c24cbb953ea7786504362a45f8ec07473a89aeb2006bde2fe0fb6b51c7
|
|
879
|
+
.claude/hooks/mcp-pre-exec.sh 3a7b64149a45dca9e1c15a793e1e84cc28d1f7675d7b519c38cf4b4b27ef5219
|
|
880
|
+
.claude/hooks/mcp-pre-exec.sh ad7f79a13eae3b59e530f00c5ca37b05b01df6629d2c09034bb4f3ac55429120
|
|
881
|
+
.claude/hooks/protect-files.sh f18aef8b355be30afc14e097e8f152a0f00351342e9c1505859f400b445af242
|
|
882
|
+
.claude/hooks/protect-files.sh 0190071614b9466bd4f29189b99f839eceecb08b480f397e5937f8087e6aac08
|
|
883
|
+
.claude/hooks/protect-files.sh 416780a048c3bf674e4348e8982906ae768ca81480b46b56c0fad800d9f21d55
|
|
884
|
+
.claude/hooks/protect-files.sh 5408a423eaade935d984d187f6f93387869cba9423b4644120f30025df4a7b5d
|
|
885
|
+
.claude/hooks/session-start.sh 1c2ffddd804bc82bd456b6cf6e1566084f6c5b43d3596b418e982d073bdfdfb1
|
|
886
|
+
.claude/hooks/session-start.sh b82d19dda66419967708a9937746d03bdd099886f9e7ed9103254209017f1147
|
|
887
|
+
.claude/hooks/session-start.sh 894ebdc240b80b37da93b4124994471c1cb0a26d8592d7a621d8fa3a748e8c79
|
|
888
|
+
.claude/hooks/session-start.sh dfad4b1add755a7efa89cacd370ba418c629f64911d1e0da1bcb19502bbc5948
|
|
889
|
+
.claude/hooks/session-start.sh dcea99eab4c03341b2c571185e8433379e3c5bcfa5bed35d8f1979eee3a45c1a
|
|
890
|
+
.claude/hooks/session-start.sh 490b1d99f6d901d63e48a8122d67225f5c48cc835db0f410fed91c364666ba2e
|
|
891
|
+
.claude/hooks/session-start.sh 613156711d285ae2dc3ac6b1c26d72b7f92f90c80639c6aed1c5fe982bc68114
|
|
892
|
+
.claude/hooks/session-start.sh 238e4a9565b2cde0809fed3b49059fa5b3189ad1c2e86d4963fcbf5e73de7152
|
|
893
|
+
.claude/hooks/spec-drift-check.sh 48e2c5ed391086c842a9a647dcafe50d757513b993561c3137c9cf4ecf96f7b8
|
|
894
|
+
.claude/hooks/spec-drift-check.sh d5bbbfbc3da3bc3eb2d3ac06cc10dc02426ec9472f4fba68300b895c3ffb24ec
|
|
895
|
+
.claude/hooks/spec-drift-check.sh 43f01059a5cc1d779c9e80eb4207fb4e263d853f5a367dbfd45b0b77685d0e28
|
|
896
|
+
.claude/hooks/spec-drift-check.sh d979fffa4f45c4ac03940a70abfa63860bf2a22fbdac9469a43f64565a6abdd2
|
|
897
|
+
.claude/hooks/spec-drift-check.sh 1c7c81e4009866b204e03fd7c4eac87a1b66d7b467a747393dca2bab6793eee2
|
|
898
|
+
.claude/hooks/task-brief-nudge.sh a5bca92a610efab0d770c96e12d3f6996cb184ae0175005724635a9a920fefac
|
|
899
|
+
.claude/rules/api-contract.md ae12cbcacd6380d41d13ca87d0e6f5d589df9f8561f408618cb365e144afced3
|
|
900
|
+
.claude/rules/benchmark-parity.md 595149aec4ed190e7ea96c11c271fa6b743f7ad8c38910dffd2cc180d9a51e8f
|
|
901
|
+
.claude/rules/benchmark-parity.md ee33155ed0ac2c267d0ebacb5f89335cca7dd679c5b2d54ffec81c4738bd9be3
|
|
902
|
+
.claude/rules/benchmark-parity.md b602bc9fc5627ec1e964915240f15748bd13e5bd99737346dbd8d3d2e7c633a8
|
|
903
|
+
.claude/rules/benchmark-parity.md f98f9429c3250ba860b1d39ca304854de0c9e905cdd12fd068d57025e40350e3
|
|
904
|
+
.claude/rules/change-management.md d21082487eeef59664899f85df6098bd46e3c74dbba3f2ebf9e49cf5bab64c34
|
|
905
|
+
.claude/rules/change-management.md 62b7932f691664459d2d7b0971c6aaee22cfeb5f9103ca1145cc55631a072077
|
|
906
|
+
.claude/rules/change-management.md 264b79b82de252cfc933d63708ac8bdf9f18c74f388063d62960456dfa764e2f
|
|
907
|
+
.claude/rules/change-management.md 611bb3a89d47d5b43ac22de8be59edbdf9b700959901d1fa878dc0f89d9ec40e
|
|
908
|
+
.claude/rules/change-management.md d2977a144259dc744835d9bb6c3cfa8d1b390f5393c34d883ba0f67a6bc4dc3e
|
|
909
|
+
.claude/rules/change-management.md 20c548a1380f1e5e9aad5821e0bce0ae999a2dbcfc1f564a990bb30f3590d418
|
|
910
|
+
.claude/rules/change-management.md 0c46f2fe8a9045c14a93895a1614b068d04a4b0e96c183d46ab688e57885c6a6
|
|
911
|
+
.claude/rules/cli-development.md a0bfd2fe69336e8b3bf329a2029d926c96192bc24e784f22f7b99861358829b7
|
|
912
|
+
.claude/rules/cli-development.md b116324d53c7ed3b36d51474f17bd61eede610dff7abea4d3533656dd5cf9a34
|
|
913
|
+
.claude/rules/cli-development.md d5a267f7e22c9d292693857577c2e5819811147b561a38c15b450740d4dce98b
|
|
914
|
+
.claude/rules/cli-development.md 158b76f589d0588f07453b4c47bf9368117467843cda37ddc8bec7197cd671b3
|
|
915
|
+
.claude/rules/cli-development.md cc0545a04706c18304eb92c365d691986d511f02436f405894306e829b4f5b8e
|
|
916
|
+
.claude/rules/cli-development.md 27f7696b1ed13ae15f9e0bfb4bdf2206325f42d87cca6e1a6efcc76f6c9d32bf
|
|
917
|
+
.claude/rules/cli-development.md 73813a5f6f0111507430c1f83c9a099b870bc2a03c16a391817dc74444597eaa
|
|
918
|
+
.claude/rules/code-style.md 2e67fc49d4c8eacaa6dac9064cf566d7f3039509a5b6c5f03b5b2126b0043def
|
|
919
|
+
.claude/rules/data-analysis.md 81b87e41919f7a7a4b06ff459a127b1c44ff6804876856eac0b17da8b0568695
|
|
920
|
+
.claude/rules/database.md a421fe0ffea76ec480cd9cc90ef753ceef7bff3ad4f49ee7837786960b634ba5
|
|
921
|
+
.claude/rules/design-workflow.md 5b6a40c9004355420de2f647c782728e47eb6b01722d7453acf570b6aa002dc7
|
|
922
|
+
.claude/rules/design-workflow.md 49fc2c7efedac467d52031b3bedd7d33fec9c73dff45d20071a5456b82015cd3
|
|
923
|
+
.claude/rules/doc-governance.md 0618fa6f93d245cb46d42862b881fa840e54b196e759d748937d7098c60eed71
|
|
924
|
+
.claude/rules/doc-governance.md e3b2197e19609724e6301ff6035ec9d34e5a60b5385bb4f48a2b633c3c3ca2d5
|
|
925
|
+
.claude/rules/doc-governance.md 5569bb742cc2c0666b2431e3eb662d5fdeb99f8f7224506e0379ce618c4bdf61
|
|
926
|
+
.claude/rules/doc-governance.md d83292a77146ae96e7adcb2dd796811ad8af979526e8d81b1a33bce8cebe6b7b
|
|
927
|
+
.claude/rules/doc-governance.md 54157849bbf9897969745f1d162181b93f4dd9260ae18d4a890b6ad014232797
|
|
928
|
+
.claude/rules/doc-governance.md 8d508bf15bbc1e87b8d0820a6e54a6d5de4b243ae8859ee98b6657d60dfbc7c7
|
|
929
|
+
.claude/rules/doc-governance.md c6f2bb6210ae076acf15e6928a8bb20adbd9d40727433c462d5e1b5eb73803de
|
|
930
|
+
.claude/rules/doc-governance.md 5257f74d94188b18977670a4299658673e00d7b227c54ebb19e00ab019d9adfb
|
|
931
|
+
.claude/rules/doc-governance.md 364c147096985e1fad1a03457ac864a6e4839d8d9487a5c7f20fbaafeeb43eaa
|
|
932
|
+
.claude/rules/doc-governance.md 589e70962b426503098c5d1a60da4b11f9a0c97a654d3ccac900d58f02b7fb52
|
|
933
|
+
.claude/rules/doc-governance.md 7a79bba801a1fb3695566bc19c9bd2f89456219560d76ac4f2bcf405c238b6a1
|
|
934
|
+
.claude/rules/doc-governance.md 3360574fb55f332cf3de18ea32506326fb2880651a593c0bec0246337633fe80
|
|
935
|
+
.claude/rules/doc-governance.md c14e70d6fc5b0ca8e9385d293cccdc39512ec6e73fac6f34ed723572acbebd97
|
|
936
|
+
.claude/rules/error-handling.md 5ea6a188e3a925d5f1f38c1defb766bf71af7a408b58ecce208c7fd3059aa843
|
|
937
|
+
.claude/rules/gates-taxonomy.md 2276e03e41463f946d5b4867c953579aab91445bb781a4d24ecd9337d2f67e3d
|
|
938
|
+
.claude/rules/gates-taxonomy.md 8a5162bd03f20c92230e2bd84a879de5f5d24a5746e6489f3dc895891055f4a2
|
|
939
|
+
.claude/rules/git-policy.md 932e24935cdd20f088b4a3a75a493cb454e065c75e294283fd01a7a768bf9059
|
|
940
|
+
.claude/rules/git-policy.md 3c0cf97e7ec6d921cb8b066d6d34a9f70f57fbdb0c78e9ab11cb919a4251da0d
|
|
941
|
+
.claude/rules/git-policy.md 0d8d01c7b471b4623be31221e773b7298bf230aa102394e0384859db5393b0c6
|
|
942
|
+
.claude/rules/git-policy.md 1c83e7e9acd5967d31406fec70a231cd8de09d5931eb7ca8ebed68f428c3d081
|
|
943
|
+
.claude/rules/git-policy.md 421e837c323bed48fd7e51d02e3c27dd479037d67ecce9dbcc0da3b8c1e764b3
|
|
944
|
+
.claude/rules/git-policy.md 02e127647bee532d0ffc5b994eb2f554f42e96b10529618f953e9b27a3ec0ab2
|
|
945
|
+
.claude/rules/git-policy.md c4f5c1f4b33f3f91aebe673b736b3dc76db785a225d0214f29ab6ceccec26550
|
|
946
|
+
.claude/rules/git-policy.md e1ebe8b7abf6e61015bef44c6f848f13ae8cafe16384b765b35905efecf0a21b
|
|
947
|
+
.claude/rules/git-policy.md 469077325ea8c4a67dfe827014370bc099494998f55aa76f864f6411b40b07d8
|
|
948
|
+
.claude/rules/htmx.md 4faf811dcf5b2b85f899507b249db4853b328c73b2d45760106c1b2132b53c83
|
|
949
|
+
.claude/rules/nextjs.md 855eb2f49b830a89ebd9b92f29a05ea3348d6dda032d2a267c15a5c762371ea5
|
|
950
|
+
.claude/rules/no-false-ship.md 964853f056a2ed898b09648faaf5302d471d3e723dc8e15d387e32aba82eee14
|
|
951
|
+
.claude/rules/no-false-ship.md 2d760fd1f3387233703c04127bc595874a835ea46a50055d7c506cdbc7ece5cf
|
|
952
|
+
.claude/rules/no-false-ship.md 9098f58fe799367cb6cfc02779715b02c4f0a2e5c24539fb2d65f5eb36332762
|
|
953
|
+
.claude/rules/playwright-launch.md 770232379a9205f0466804b83edb4f53e1ccef2fcbc5e82b8e0c5b0a96fac783
|
|
954
|
+
.claude/rules/playwright-launch.md 1bf90d35a050a1f0d712f406329d687bf9bc7661ed0a183e83613bfaef895820
|
|
955
|
+
.claude/rules/playwright-launch.md 783be44da36bf9eaef56d0117d6cd19b7c0c1ef9242745b3f3f87721e84f2664
|
|
956
|
+
.claude/rules/pyside6.md 19c092d5fd7691818e9a759bb23173c9aa1f511c4766a67a9e7fa918b7062852
|
|
957
|
+
.claude/rules/shadcn.md af1fc4624cdede22a35d087b8a7fb4ef042302e2c998373c73f018736e68e5a4
|
|
958
|
+
.claude/rules/ship-checklist.md 14319e7639aa4827690099efd5ad228c997e56a9002eeba6c90e7f274c44bb12
|
|
959
|
+
.claude/rules/ship-checklist.md d371f417f9af32a72afa99e38378d5a95a085ea5c8ad106328cf41a5f61cf117
|
|
960
|
+
.claude/rules/ship-checklist.md 27d3885cc3944a1a4d92dbd8e0d51ac943d7971d2284db77244deafe007c2906
|
|
961
|
+
.claude/rules/ship-checklist.md 286fe3b971c1aa72bb41f610c576ef6d23a9778ed4ab4cbbb493d1f241494a44
|
|
962
|
+
.claude/rules/ship-checklist.md e5d1dc357c54026f473ffba52b6ae3746ef49173b8270fea6faf16fbc2ec7b10
|
|
963
|
+
.claude/rules/ship-checklist.md 6825d1ce40a817f9fa004256b17b0685eb1ccb69ea27641c97e53dd5e323e755
|
|
964
|
+
.claude/rules/ship-checklist.md e713a2738dad8a03d16f0cb1b24a7b207bb4a1445766f883391a0b4a8ad6a766
|
|
965
|
+
.claude/rules/ship-checklist.md 0d9988b3d6b387dd13738c5f1667a8f07e72929f5515168e2ef6e94ad4c0da88
|
|
966
|
+
.claude/rules/ship-checklist.md 1b42169da6e29bfee8ea695831154f672d7cabd8816d1993678c4955a43ed1e4
|
|
967
|
+
.claude/rules/ship-checklist.md 9423f862188ea0ddcb5ec9594e457988c23dc80a0bdba7ed6cc7630f8cc4623e
|
|
968
|
+
.claude/rules/ship-checklist.md be7e93da56b688c9b90d5392dc29b16197d5d4857152f073eb39d1c737952a02
|
|
969
|
+
.claude/rules/tauri.md dd429a144c71f1205384abb5c305b373908e8f6c2c4ae7d6b4dfa9fa707e972d
|
|
970
|
+
.claude/rules/test-policy.md d775453a9b0c3fd7f65eba039e512ec6fc92eda448a2218738da6bb1c85a3023
|
|
971
|
+
.claude/rules/test-policy.md a106e6952520eaa2cebedb9a20a47ee12a8bd0069639077f324cc1d93e3d5501
|
|
972
|
+
.claude/rules/test-policy.md 1b6f0c2fab4842c974c11dd53b22320fb5593870390e0c375625ec584196e580
|
|
973
|
+
.claude/rules/test-policy.md cc73a7e656c237c4313bfa814a9eadab5a44542ff8dbf250fceaf97d6ae1f05b
|
|
974
|
+
.claude/rules/test-policy.md 87660a29cbf43f49e24fd7f53124f0383c94c8333138d1cc1ab9dc233b5e8a4a
|
|
975
|
+
.claude/rules/test-policy.md 54426764c08cadc8c1b31bdaa5817f5c4aefc359d263bd13051949aec7858c0b
|
|
976
|
+
.claude/rules/test-policy.md 9f1e71e12db41a3b20653854c66adcb224c47e86d6a5815d3b7002418cae458b
|
|
977
|
+
.claude/rules/test-policy.md 95b9c6af6a63e4cc85488e109f42440b7f7d1892c73d5b96b7ab387354303cf4
|
|
978
|
+
.claude/rules/test-policy.md 3460db5bbfaea281e417c55b5a76236b10c64c38cf38fe16b934f6799c1268b5
|
|
979
|
+
.claude/rules/ui-components.md 836b66be19c773b3cfa2ee92ed29bd802d8883a55da21cf0be9b73e25a2c8ebe
|
|
980
|
+
.claude/skills/agent-introspection-debugging/SKILL.md aff0d52785d3013d9f98de95ca778bfcab7c566db20352ead42852a1659292d2
|
|
981
|
+
.claude/skills/agent-introspection-debugging/SKILL.md f03dc3838ba8b81ad6a87959a2d666f8d5915d3516cea60d12a65ce74685c54e
|
|
982
|
+
.claude/skills/asis-tobe-decision/SKILL.md 8880ea604b8458acd30b8dc515efc54a6a1640590c572d5f4be7034cbd2d7242
|
|
983
|
+
.claude/skills/audit-harness-fit/README.md 885c756b8fbe51d23747667d3d96ba8c76e1c0e5fb48030cd394b0dad4c304f5
|
|
984
|
+
.claude/skills/audit-harness-fit/README.md e1295cd42a0671d373d7d071374918abdc37aa294052ed6bde8511ac07e80039
|
|
985
|
+
.claude/skills/audit-harness-fit/README.md 2aa6eb69e9991d0156b140f5c4ca36dd87b32ad006aa8dc176f173e7a864ecb9
|
|
986
|
+
.claude/skills/audit-harness-fit/SKILL.md 6919e5c6fce93b4262392ddd9e0476b700e921e39a91ab646bf48f05f4fbe39a
|
|
987
|
+
.claude/skills/audit-harness-fit/SKILL.md ccf5817e3ebcc7575e409b4a1c397f2ef23d690e355490487b2bd829736d1ab5
|
|
988
|
+
.claude/skills/audit-harness-fit/SKILL.md 85c489aec23eb0b9f907c3b10395dabbe03add8300f6d365e886e02f833fd769
|
|
989
|
+
.claude/skills/audit-harness-fit/SKILL.md 5f20eaac20e77c3207978857e2424bcb86d5681362528eed7cc3a09afdffb845
|
|
990
|
+
.claude/skills/audit-harness-fit/SKILL.md 3c348fe635f8b389a349db3f686ebca4f49e1ef7058aa3b4c6e0211e51c12562
|
|
991
|
+
.claude/skills/audit-harness-fit/SKILL.md 9dfd4565013a630c0aa66c9396b4d4073fe70f8601bff89989ebe162da7beb76
|
|
992
|
+
.claude/skills/audit-harness-fit/SKILL.md a23c98c78fd9c5f4660dd73058d58eaf78aa49c107bbc0e3c60de73231f5c163
|
|
993
|
+
.claude/skills/audit-harness-fit/evals/scenarios.yaml 016257464f98f62433e2aba5a064405f41128b54eba05e3702cf44ce93d97ae6
|
|
994
|
+
.claude/skills/audit-harness-fit/evals/scenarios.yaml ac6355013fb7be658196e135ac449bfa5afdc564adb1d5d1ed10d65a64d16e04
|
|
995
|
+
.claude/skills/audit-harness-fit/evals/scenarios.yaml 714fe2ef457dd38fc9b3b354b7f2d616c5d7121770ef1dd889d008eaec661159
|
|
996
|
+
.claude/skills/audit-harness-fit/references/apply.md e4803a5d6d6c0d32c9808172a03f0f555320ef29fdf73277dd4fc535c4474d77
|
|
997
|
+
.claude/skills/audit-harness-fit/references/apply.md 97886bd748ef2e2d9a979dd0cf65c5acf81a90c2a19d08851ce87c66df933f92
|
|
998
|
+
.claude/skills/audit-harness-fit/references/apply.md 6f38cb6673546bfe6609ff6ae18436e5487f93386ac1bfb4625f9c85997c36e6
|
|
999
|
+
.claude/skills/audit-harness-fit/references/audit.md 39d077f20624e69582ac0e2df28d192c08e8246f8c7dfb8e471e7c461f1cc5f0
|
|
1000
|
+
.claude/skills/audit-harness-fit/references/audit.md 973605514d4eb560b79ff267058e6dbd47bd61b53752f3f91e7f49a4904eac4f
|
|
1001
|
+
.claude/skills/audit-harness-fit/references/audit.md 328d620140846005bf326998387e9305371bf95b5e95cb3a9e7272377e26277a
|
|
1002
|
+
.claude/skills/audit-harness-fit/references/audit.md 4b4eef5a9060ad0a7fb264b261c69802c1c3f0e7c61787ccca18be898c84c091
|
|
1003
|
+
.claude/skills/audit-harness-fit/references/audit.md b93eba13d00481e391fc05e70d894164661ae689f28b08d47514e2c35ebfc790
|
|
1004
|
+
.claude/skills/audit-harness-fit/references/official-criteria.md b80c77f12fdf1752f671eb1c0f8edb6f4f34c3777d6753b9af713f91cff77222
|
|
1005
|
+
.claude/skills/audit-harness-fit/references/populate.md 48227ddac79899f725769050f6105aff0b352d47f72b01341e836362db943ad3
|
|
1006
|
+
.claude/skills/audit-harness-fit/references/populate.md eabe235e5e097ad44a42588201ed89dca359e9fd1a301e29be02deb0338d38cf
|
|
1007
|
+
.claude/skills/audit-harness-fit/references/verification.md deff70dc0f419a760e8b280a2ae57b43a0ae859c17fb6627ea749741b855ff62
|
|
1008
|
+
.claude/skills/audit-harness-fit/references/verification.md aa367e0655a98ce575919e5c30687713187346a7976b97fc1081a99bbbef6ce3
|
|
1009
|
+
.claude/skills/audit-harness-fit/references/verification.md 18bd5f577b85cb043229ca9df160ec9c0f3fb70d01c3db5abb5ccbba7ae6dab1
|
|
1010
|
+
.claude/skills/audit-harness-fit/references/verification.md 695c1f08c6bee5de28d0edfec796df12ca5fbff8cdb473bafbda6fb7f3cff79a
|
|
1011
|
+
.claude/skills/audit-service-gaps/SKILL.md aefd2a47a0b9c2b6bd1846151e60cef0147d0bfbb4b1933da2431f980a0f2922
|
|
1012
|
+
.claude/skills/audit-service-gaps/SKILL.md ba9ac6df2315538935aff945f25a7596b3a9e478c4cdcb3a218ff404f4b612d7
|
|
1013
|
+
.claude/skills/audit-service-gaps/SKILL.md 81323cc7d4bda9f3739e8a72f566699d209f888aa216f77f106e77db975f231d
|
|
1014
|
+
.claude/skills/audit-service-gaps/SKILL.md bbc7782ea688ae74f12934145c1041f58a029eb07d9979c316849cb9fb88f56e
|
|
1015
|
+
.claude/skills/audit-service-gaps/references/modes-and-evidence.md fa73b3edf2c55f5caf47f1f2d930d8c2ccd737af0a2def5f40a1db942029275d
|
|
1016
|
+
.claude/skills/audit-service-gaps/references/worked-example.md e5f31f498e864dcaabe2a0d6a05fe1d64cd8be6a1b79a18de78bcbb42e06d658
|
|
1017
|
+
.claude/skills/chatgpt-delegate/SKILL.md 0e614e643bb8bad52db3663ff9394f77ef6c89a6c72c529796deeed824eca0f0
|
|
1018
|
+
.claude/skills/clear-korean-communication/SKILL.md a8afb5e0114332fd7831de12a12cd981e95726458df61f1a3fdb6160086aedc5
|
|
1019
|
+
.claude/skills/clear-korean-communication/SKILL.md fe480eb8357a79abcc1f6c5954c61f0a8b3e7479b9835b7fbdead18a9dac4b46
|
|
1020
|
+
.claude/skills/clear-korean-communication/SKILL.md a8a41bd88b2b04c931047f08614f8c431eb8e401fe366d110291201a9fb571e8
|
|
1021
|
+
.claude/skills/clear-korean-communication/references/pre-send-checklist.md 65f93177e9a442332c2c90f4e905c4d558b6349e47d5c86eee7705b76b71a1b9
|
|
1022
|
+
.claude/skills/clear-korean-communication/references/why-it-works.md d4439db6a1765fab5fa6875d0528fe715366c270ea35853ad8bb1404388200cb
|
|
1023
|
+
.claude/skills/clear-korean-communication/references/worked-examples.md d53369cf02c62147510bae3a0cfa878ce89013bed11a30c32cc675dd0a0df825
|
|
1024
|
+
.claude/skills/codex-consult/SKILL.md 0af4f6cd00739e62d73f7adc9c8ea85b0db3ee53432bc5605fbf6bf788a0cd13
|
|
1025
|
+
.claude/skills/codex-consult/SKILL.md 288d6d5f4135b8f3e1d8b06b42b68c238e63c9257f973ecdc4f86445d5619be1
|
|
1026
|
+
.claude/skills/codex-consult/SKILL.md 767b0d65ff96f0a10c2cd81335a5ded2a85394b8e8ab3aa1c7737c6296f22582
|
|
1027
|
+
.claude/skills/codex-consult/scripts/codex-ask.sh 64835a9e11094bc24d9e8f9044a98a699ca45155d516dba926ffb8c145cbf1f6
|
|
1028
|
+
.claude/skills/compaction-handoff/SKILL.md 1b19203ae45869dd43b7ca4b28c63bb5c4267aefc9a62abb17d29bdceee316a9
|
|
1029
|
+
.claude/skills/compaction-handoff/SKILL.md b484a4408f25f4b78bf2e7cd88b1b3fec7b969d6c4a03de8a3b8e072719fc74f
|
|
1030
|
+
.claude/skills/compaction-handoff/SKILL.md 42d8300cddc4bbe78b353c8ff846b5fd8ed2b4a68f1998982900fd31596c1755
|
|
1031
|
+
.claude/skills/compaction-handoff/SKILL.md 59191dc216233b74e5f5a72ed1041d8c236504a386e8b5df81dbf52062dbaad9
|
|
1032
|
+
.claude/skills/compaction-handoff/SKILL.md fe70142b0bbf21b5a7b6e9e5af8f0011e6b8e654746f97f4391384d5143c9701
|
|
1033
|
+
.claude/skills/continuous-learning-v2/SKILL.md 7629ed1a18ce078b57f22f407115a41a7f404aee73de17667ec5571b0001a8e4
|
|
1034
|
+
.claude/skills/continuous-learning-v2/SKILL.md 75485ddb37e2d1d6f056b404d9939bf46a2b409b1286aec209a510112e5b64b1
|
|
1035
|
+
.claude/skills/continuous-learning-v2/agents/observer-loop.sh 25ceefcc260c3599b6d12148d1a573110ace3091c723bdee3a3cf10692e5d4e2
|
|
1036
|
+
.claude/skills/continuous-learning-v2/agents/observer.md 320d50ff2965efeabd6f07c2be134e11da160293e958c1bc27c309d613839ad2
|
|
1037
|
+
.claude/skills/continuous-learning-v2/agents/session-guardian.sh ee6e4c0990f8d538cae1c85aa194e01e9ca2336e5d993ef68eb608b96cb0d82c
|
|
1038
|
+
.claude/skills/continuous-learning-v2/agents/start-observer.sh 6b1966e38eb0c96d61de5d204b87097592884364be59e5bea6007289e8068936
|
|
1039
|
+
.claude/skills/continuous-learning-v2/config.json 6f17e7a99aafe252ecd0b9212fb5f606be50b8ce1685f5a6435e46e87ffeb970
|
|
1040
|
+
.claude/skills/continuous-learning-v2/hooks/observe.sh 285c673af5a5f5fcc0839e924ccdb4b7326c593f9198f690c635b2fa7091feb6
|
|
1041
|
+
.claude/skills/continuous-learning-v2/hooks/observe.sh e632c2f486248b8b141059c23586d5ca0187df8c34f53d7597cd845713e06948
|
|
1042
|
+
.claude/skills/continuous-learning-v2/scripts/detect-project.sh 527917b87d8b35b38baf01ca96c6fc4cbeb91ed9a24c6f9c09e4f4d290555295
|
|
1043
|
+
.claude/skills/continuous-learning-v2/scripts/detect-project.sh a39677edd0ce1deb7628ed31610baafc16090a710233963d2b6a55db64167cf9
|
|
1044
|
+
.claude/skills/continuous-learning-v2/scripts/instinct-cli.py 777193745515c8dce35676b1696c90a85e2610705157205a0b54e8e453b69942
|
|
1045
|
+
.claude/skills/continuous-learning-v2/scripts/instinct-cli.py 0b060a762f0fc4ad56e45cbaa14c14fb9ab3f468763f6a32a17bb864fbd3fc30
|
|
1046
|
+
.claude/skills/continuous-learning-v2/scripts/lib/homunculus-dir.sh 99dfa99ae0f7c6e2e15ed5b5bf3c46e91a5f089f4060ba93d5da5e85e04fd308
|
|
1047
|
+
.claude/skills/continuous-learning-v2/scripts/migrate-homunculus.sh 34f121c143a676d330f06209618aae8cb08f8155298cb5fa70c893314bf9b303
|
|
1048
|
+
.claude/skills/continuous-learning-v2/scripts/test_parse_instinct.py acf556e8a8023347b35988bb490927a4e9f65f2579b03f26cad610687656605b
|
|
1049
|
+
.claude/skills/deep-research/SKILL.md 2d631427fc9aba27a318735f930bdb49f5c6ce416506340025eac01648f1df09
|
|
1050
|
+
.claude/skills/deep-research/SKILL.md 69be70af34e27112f192cbe201210c4cf541c24952670487213de715aa297b40
|
|
1051
|
+
.claude/skills/deep-research/SKILL.md b852bebb31908f352c5397bde6de06ee7ca3c0e1c866fae4dedbd5c4fbb27323
|
|
1052
|
+
.claude/skills/deep-research/agents/openai.yaml cb877e559cfe405d0e12bfc9bcaef657ab05a30ef698e6f3e486e39c5e0a6d2d
|
|
1053
|
+
.claude/skills/e2e-testing/SKILL.md f84ae93c159bf6ecef5a60c9735dc82d96bc5f977ef52eb71678b66722acf684
|
|
1054
|
+
.claude/skills/e2e-testing/agents/openai.yaml 5f50508a300616d77f39dc50a51de10cabd05ef7ae770e7948ef6c28f340cdf2
|
|
1055
|
+
.claude/skills/eval-harness/SKILL.md 03fc47842b35861231efdd1d15de291942915c372b8ffcc05a22e942d1233ced
|
|
1056
|
+
.claude/skills/eval-harness/SKILL.md 98f10c6cfc7fd041a358093f5c700b489d431879b90db778db7623a3c1c5404f
|
|
1057
|
+
.claude/skills/eval-harness/SKILL.md 12399b9de9e044273fd4dd6a8177bc4f17db008a33df83557ef56770b1466a56
|
|
1058
|
+
.claude/skills/eval-harness/agents/openai.yaml 6f2c19eb59062ca776286c2f6a6a7f1b552b4f927a2b48de888a7dbb2eeec6bd
|
|
1059
|
+
.claude/skills/explain-plainly/SKILL.md 7838e4f78b7d4d46d31a7c932f069fc66ec4bcd873e49fb57f37923be188fd0d
|
|
1060
|
+
.claude/skills/external-model-consult/SKILL.md b1d7db909a459708ed721f5a7eeeeebe48fb3d57448f763e7e0000df5426a241
|
|
1061
|
+
.claude/skills/external-model-consult/SKILL.md c33d6d2e02aa9631fcb4e91aae83b56834307b0290a984af55378d2f0011d7dd
|
|
1062
|
+
.claude/skills/external-model-consult/SKILL.md 24cafc7b50fde21eb874fc2178d3ebd7eca3b1c54e9278d60a088f9079b7b534
|
|
1063
|
+
.claude/skills/external-model-consult/SKILL.md 2d115e29ad53d778ac4d4f942ec2039b441ecc571d612d27cc725695641f4db1
|
|
1064
|
+
.claude/skills/external-model-consult/SKILL.md a4d429bcd4737fbb2a90de6b9beb9cdf0488fe385eb0f6fb395f0e76322dbb0e
|
|
1065
|
+
.claude/skills/external-model-consult/references/direct-calls.md 6bf094fe54bcb09285ba552371eabf1d743545eccdb118157a8aea987b7c8147
|
|
1066
|
+
.claude/skills/external-model-consult/references/direct-calls.md 966db9c1f80c367ffc81842b83326a67190cc97287e7d624c0c16ee65fd4b16e
|
|
1067
|
+
.claude/skills/external-model-consult/references/model-evidence.md 27dfc0eaac4bbf97dbe4430852e947d99a7bd895aeaa7f1d565915c2a2fdef1d
|
|
1068
|
+
.claude/skills/external-model-consult/references/prompt-templates.md 2277839d5eb9ecbf8535f51a1f1ca97d55816e47b6ea578f34e9637280b1b5ea
|
|
1069
|
+
.claude/skills/external-model-consult/scripts/codex-ask.sh 64835a9e11094bc24d9e8f9044a98a699ca45155d516dba926ffb8c145cbf1f6
|
|
1070
|
+
.claude/skills/external-model-consult/scripts/codex-ask.sh 75f24da435dff5ea7ed7636d8b121456d1e91806e9a114ea993862e173d84d72
|
|
1071
|
+
.claude/skills/external-model-consult/scripts/codex-ask.sh c644272c25f3d0d42ab63bc8c4acf81c1ae90ce1af5f7780977dd63f464fda7b
|
|
1072
|
+
.claude/skills/external-model-consult/scripts/gemini-ask.sh 6736c394de1d059908ebed770221b298f37d09e01aa3eb58991265c2d45915cc
|
|
1073
|
+
.claude/skills/external-model-consult/scripts/gemini-ask.sh a598276b4e2d9e4a54b704229822d8da49a6c54497c8f2471af5420b4c3017c3
|
|
1074
|
+
.claude/skills/external-model-consult/scripts/gemini-ask.sh 9c5eb72c61d140228dff796ff599f88982b76763abbf52aaa31486ddeb03e9e8
|
|
1075
|
+
.claude/skills/gap-analysis-e2e/SKILL.md ef28d245d354c07de60244778469fcc344385a584eddba33c67e9b096654ba4f
|
|
1076
|
+
.claude/skills/gap-analysis-e2e/SKILL.md 739e9a181eac99c749b585fc4f2b64a30dcd4783083422afde64ea85a9a2b062
|
|
1077
|
+
.claude/skills/gemini-consult/SKILL.md f096ad4e6a16e4e6d33ff7d817382e3f8c07311fd7c1f809ae91a951a9f58856
|
|
1078
|
+
.claude/skills/gemini-consult/SKILL.md 24c7f1a8855f5f44447015990991c47c80dc14fd9e373dd818084f8870ff8004
|
|
1079
|
+
.claude/skills/gemini-consult/SKILL.md 9ec900de7b699b73addd0e6259b4a2fc8bbf559d22662842424a1402cb581793
|
|
1080
|
+
.claude/skills/gemini-consult/SKILL.md 81cf4563f9fc790a64796a24e6f85f3b33bffc7e31989dbaebedcc2452984805
|
|
1081
|
+
.claude/skills/gemini-consult/scripts/gemini-ask.sh d9f4cc371e3e3b1919dd773d41b351484c9a3612487bee1ba314378a8486a39c
|
|
1082
|
+
.claude/skills/gemini-consult/scripts/gemini-ask.sh 87b065bec8c13b28dcc451235dcf9679d97af4f68ec678153e23ee14f7c94d0a
|
|
1083
|
+
.claude/skills/gemini-consult/scripts/gemini-ask.sh 6736c394de1d059908ebed770221b298f37d09e01aa3eb58991265c2d45915cc
|
|
1084
|
+
.claude/skills/gemini-delegate/SKILL.md e3d569add39fecf8c412d76c287e88054710f70b87ac38d88c20ad7b00b301fa
|
|
1085
|
+
.claude/skills/genspark-delegate/SKILL.md 3f495d55f1968730c9ce66009745530c16adee5110267e7b735f6a0333e2bcf2
|
|
1086
|
+
.claude/skills/gh-issue-workflow/ISSUE.template.md e004bcbf6199486d527feea43aa68be108bfc8fd3b13800bc543baa778291dc0
|
|
1087
|
+
.claude/skills/gh-issue-workflow/ISSUE.template.md c30fbe41d1d6ca15a82c031441c8b20a6db20cabd3d52c9c2c7ec70ca97d60fa
|
|
1088
|
+
.claude/skills/gh-issue-workflow/ISSUE.template.md 6c897058f7cfbc7b3eb5a3688f21a106fda39b7ded0f05570cff349214aca427
|
|
1089
|
+
.claude/skills/gh-issue-workflow/SKILL.md f2b906076945adce0cfd80dd9331420eea0bd1c1758b76e1f300c82811b06f50
|
|
1090
|
+
.claude/skills/gh-issue-workflow/SKILL.md 99736619cdb450870fb8b51e9ef3375fdd4c625b5d23e37c75078e40b1f1dd32
|
|
1091
|
+
.claude/skills/gh-issue-workflow/SKILL.md 00dc33d939b034dac6c653a07a64da5b362e350bd9133def2f11420c94353008
|
|
1092
|
+
.claude/skills/gh-issue-workflow/SKILL.md ea1012246121662e0604e296913b63e7ce5a02b902182c86102dabe5e13563fd
|
|
1093
|
+
.claude/skills/gh-issue-workflow/SKILL.md 0b1ce6a696c1388e928240ec787b449dd0b0a92749789fe28f8627fbb9aee880
|
|
1094
|
+
.claude/skills/gh-issue-workflow/SKILL.md 578c25a3687c7c6557c2bd115489f44a49d5668e2cb97e114a009d7066db7a72
|
|
1095
|
+
.claude/skills/gh-issue-workflow/SKILL.md 7128c3faddf72ce6285b3a0e7179da01d6a434659ccef6f9b51851b3f5f50d17
|
|
1096
|
+
.claude/skills/gh-issue-workflow/references/hierarchy.md 0e16e38d5919e5eed0aa044899895fb13c3846a333f3470d8001bda09ba959c4
|
|
1097
|
+
.claude/skills/gh-issue-workflow/references/operating-model.md c6feec997887d05d3385441258c464609e52c4bbebb7c0b7390a5d6016ad9a0a
|
|
1098
|
+
.claude/skills/gh-issue-workflow/references/readiness.md 08df321b014d96f8d5b5e0c7af7f36d09d719fb098bdaec7928af4a77c1866cb
|
|
1099
|
+
.claude/skills/harness-health-audit/SKILL.md 12932ba2e5b77a7efab0ae2d0fca334bf249503a583de5a3933105fba89c94ef
|
|
1100
|
+
.claude/skills/harness-health-audit/SKILL.md 6a843a002f9a7ca9c04816214509caccc1cc3f3661595939cc4096366847f09e
|
|
1101
|
+
.claude/skills/harness-health-audit/SKILL.md 16501e7db181780684612f4f38db80861e775cc1204f444169efdbc5d9165bb3
|
|
1102
|
+
.claude/skills/harness-health-audit/SKILL.md b481d7844303896a24a3a95269a035ee57690d8c15c5ad5e85f16227fa5f7f27
|
|
1103
|
+
.claude/skills/harness-health-audit/scripts/observation-digest.mjs cfedf96b819819142f2d69bdd6663bcbdd56301c429545b4f31cc2f358249cb8
|
|
1104
|
+
.claude/skills/harness-health-audit/scripts/observation-digest.mjs 7c9c42fed4c3ab1a0df6363386c34e03776a53f6b32aa1bef3c6899dcd77aa5f
|
|
1105
|
+
.claude/skills/humanize-korean/SKILL.md 7d0d77c25f5990f203480abc6a02772d534a40ebfff4ab4086cf5da3ed1b7afd
|
|
1106
|
+
.claude/skills/investor-materials/SKILL.md 0541ac8ede8d39c59a646834481d0de86312e598331b86dc7027ece0def3c193
|
|
1107
|
+
.claude/skills/investor-outreach/SKILL.md ab71ee37a1ff5f9b7f27908d33fc47f03e7897e6c87be3f8d7c0e4a8d73fefdd
|
|
1108
|
+
.claude/skills/market-research/SKILL.md 7ef3fa13d6272fd295eeb2aca9f6a2f09f6a8270cf33b0675fc5a0018cf6e406
|
|
1109
|
+
.claude/skills/market-research/agents/openai.yaml 42e1b1bf676506bc50027131cd8226b151f48a57551197308102dd01fd080943
|
|
1110
|
+
.claude/skills/model-orchestration/SKILL.md da6b448d0119e7dfd441f47c9afa267c227ac9301561ddf07c3fdc81bf494ff6
|
|
1111
|
+
.claude/skills/model-orchestration/SKILL.md d4ec28fa8e7bcf48607a17dc84a9fb873dd9f58f6ffef38ae5324f94477160a1
|
|
1112
|
+
.claude/skills/model-orchestration/SKILL.md 2282ac0ca6c06006d36616295dbbb78bb593b93e06712baf8be6b6466426c540
|
|
1113
|
+
.claude/skills/model-orchestration/SKILL.md 7a60184798f2c7ab28d81af37bf61d4785b0831836f0be1e933d279c1b552161
|
|
1114
|
+
.claude/skills/model-orchestration/SKILL.md 2210704bbb4ae972e74f1062512accd53882a405fb91adb0461ad9a2325774a6
|
|
1115
|
+
.claude/skills/model-orchestration/SKILL.md a4447594e45e598028c5f614cc46d1555c6cbf20e0edce1c9d8a30ca17798268
|
|
1116
|
+
.claude/skills/model-orchestration/SKILL.md d8d1982fbc76d572b2f6a3ffd07cba944d3e734987fc5bc66002de5f86accd3b
|
|
1117
|
+
.claude/skills/model-orchestration/SKILL.md a67b5948e8072a87669621feda866198ffadd7c76979fdc3a0b1d8cf2a4ac8bd
|
|
1118
|
+
.claude/skills/model-orchestration/SKILL.md 34add0d50a3ed2687b4ac092a4146928b841f5f6a8bbbfd09a42e2b59f4ef2cf
|
|
1119
|
+
.claude/skills/model-orchestration/SKILL.md 6320632e46180275ee36a9e0897fd616ceb1b8ce7ffdf0647c871b293ae5c846
|
|
1120
|
+
.claude/skills/model-orchestration/SKILL.md a22190744eccc76d1f2d8995a1d66395e4ee173935b2114a334eff95239c234b
|
|
1121
|
+
.claude/skills/model-orchestration/SKILL.md 19d64858ca267987eb9be129a588b7e76ed86b7f788accf019e3f2c2db493117
|
|
1122
|
+
.claude/skills/model-orchestration/SKILL.md 65f0e657979e6b6c0fdacdd5b2cc73f73bb0cdb866c7c8ae1f099c54747c46fc
|
|
1123
|
+
.claude/skills/model-orchestration/SKILL.md 78cb2ac0f153afc4deb3ccc88b40abc7bab1f2b9ab8138d2fd3998082f380178
|
|
1124
|
+
.claude/skills/multi-model-debate/SKILL.md b6e4e4855ca36bcc2a720d926be68008259e0604c8c9dcc8b00cdd65c2bc48ec
|
|
1125
|
+
.claude/skills/multi-model-debate/agents/openai.yaml 64eb836095ff28669ebfd41d133a63e29faec0542dfc90862e10ed7fd275071e
|
|
1126
|
+
.claude/skills/multi-model-debate/references/adapters.md 06d54103576b4de93b9856c26f773842cfbb81b9491fe95c55354bd324fe4c51
|
|
1127
|
+
.claude/skills/multi-model-debate/references/evaluation.md 34f14eeecf6912c8afe5eefa1431744351b7911525d0f6eb612120d31170b290
|
|
1128
|
+
.claude/skills/multi-model-debate/references/prompts.md 45b348552563a499e221edd6fd75fb1d8e77b389aa25a9cc56688547e68434dc
|
|
1129
|
+
.claude/skills/multi-model-debate/references/research.md d99201f4774c7b3648e5bb3953c2e2979af752c1ccd8fe5013c8b6bea155e949
|
|
1130
|
+
.claude/skills/multi-persona-review/SKILL.md 8fa6a0d476b50e1c6b14fc62c31b03c8ea983711d24cc21351589ebc8f1dcd57
|
|
1131
|
+
.claude/skills/multi-persona-review/SKILL.md f0ac01160ebf176617cbe9d606a2b258eef8741c05b4a972f813ac90dd6e9dba
|
|
1132
|
+
.claude/skills/multi-persona-review/SKILL.md 4f221fec547e838d4698c4e2eaf82d6ebabbc52004be8933131e84add66fb397
|
|
1133
|
+
.claude/skills/multi-persona-review/SKILL.md 5339755ba6c7d61b82a1e06f1dde8ef46f5ee263092a7cc5cc6d300ae9bc79b0
|
|
1134
|
+
.claude/skills/multi-persona-review/SKILL.md b23879e303b7d0c95d30a9369f20b1928f93c24114b891a29f8bb17816cfac20
|
|
1135
|
+
.claude/skills/multi-persona-review/SKILL.md 29b1022bf403005764c95670b6d29ea3695ca935261afbf248c452058b2e2d56
|
|
1136
|
+
.claude/skills/multi-persona-review/SKILL.md 17f9f1a0c224168fb4c773f87f8ad84a4d7db9082088e096262aa71e1916f0f6
|
|
1137
|
+
.claude/skills/multi-persona-review/SKILL.md 6da7f5ccfae30d3d7e4ee77f90a06d7de30a532b590482a01d779addd912864e
|
|
1138
|
+
.claude/skills/multi-persona-review/references/reviewer-design.md 327b70bdedff29868b6b3b88d2279db572a811eb19defe8ec0c724e3a007cb45
|
|
1139
|
+
.claude/skills/multi-persona-review/references/reviewer-design.md 4afc9d327f91139b4d272a54e1b1992766b7e0482b4479c76ca9b5284e28d7c8
|
|
1140
|
+
.claude/skills/multi-persona-review/references/worked-example.md 95b48adac8ae5a91cb60fb9d5c32c90365734225775f0f85f26fb72404345943
|
|
1141
|
+
.claude/skills/natural-korean/SKILL.md 0057cef32a4accff3efa155a4916ac65fc283ee766abb2951227da91fa8bdee0
|
|
1142
|
+
.claude/skills/nextjs-turbopack/SKILL.md f65da15aabeb9dca7ae08525739e72ab16e79a78ff4004f7cab6ad2de1c2a79b
|
|
1143
|
+
.claude/skills/north-star/NORTH_STAR.template.md f778da89c561cf92b987bc1d46e5eb8c979f2422882714b0a0602ccce62a7b5d
|
|
1144
|
+
.claude/skills/north-star/NORTH_STAR.template.md 401ac922beb41b5b3c6d19313d5a46184cc90808aa330e0e288108355b5f8aff
|
|
1145
|
+
.claude/skills/north-star/NORTH_STAR.template.md 23a071af1893e3be7860111d448d02a55f965519811bdadafdba4231607d66c3
|
|
1146
|
+
.claude/skills/north-star/NORTH_STAR.template.md 741efd7d4c477f95ecd1fca85656d4582a694b3753ece77378ddab8ba0f0b69e
|
|
1147
|
+
.claude/skills/north-star/SKILL.md f73b7ce6a73bb3666ff3c18557ba37248a844107d54ffbaf5bb3d562fc2e7f61
|
|
1148
|
+
.claude/skills/north-star/SKILL.md e335733ad2c6dab82d104f868c5ce3d3de99ee1f139330eba9ff497529bd9485
|
|
1149
|
+
.claude/skills/north-star/SKILL.md 5b1f8176bb264e5a426594704e640eb69605d6482d6ba93f53329e9fe08dadcb
|
|
1150
|
+
.claude/skills/north-star/SKILL.md e37ed854c29f26f64a96ccd4847e71723f5bab9a56d3c8f53a4f9815120085fe
|
|
1151
|
+
.claude/skills/north-star/SKILL.md b11245dfa084bcd8b1fa4f7eb186e7a6ed97b30905a1507992c35448af45cc62
|
|
1152
|
+
.claude/skills/north-star/SKILL.md fa4427fb57243aed96d639362d97c69202170dfa949bfb0818f4600b1cd8432f
|
|
1153
|
+
.claude/skills/north-star/SKILL.md 0616424076bb18c4388d9e48ac4e4bacb51106b0b8bdcf6be223e413e0c43bf9
|
|
1154
|
+
.claude/skills/north-star/references/roadmap-method.md 78b6d7e05e014c5c7ecd5680767ed2469c6a147faf053b09f448f63cebda9da7
|
|
1155
|
+
.claude/skills/north-star/references/roadmap-method.md fd58a20159eb0b14b69781ea2536be1fdebd78c9eb83658c2b76de78efd21bab
|
|
1156
|
+
.claude/skills/north-star/references/roadmap-method.md 32e812eac7356e15704d0eff162f3fe3d93f1de880c7107017c1d802463190b6
|
|
1157
|
+
.claude/skills/northstar-roadmap/SKILL.md 489e7a70f81d80c296dd9160debe7ef69381506f9ac00874cfb48e2b61e58736
|
|
1158
|
+
.claude/skills/northstar-roadmap/SKILL.md 9a632a49e6bbf877fee61d448046444d57127b75b4f76f9b8ddf8946c8b7990b
|
|
1159
|
+
.claude/skills/objective-brief/SKILL.md 4df0bbd72dd7ea698d7d9d3b10476c4c4ff3e6bc3d9a1d29531e083c9e9bf59a
|
|
1160
|
+
.claude/skills/objective-brief/SKILL.md 51fa706442849b5f74e71c23fab8952526dd3a60ab1d78a3fe53d2631f24e47d
|
|
1161
|
+
.claude/skills/objective-brief/SKILL.md 531c8f0f09492e4a1643a5de38dbc293be9981a5c81ebc7f783620d5380a5806
|
|
1162
|
+
.claude/skills/python-patterns/SKILL.md df0c0abbbd0e6a01811d1b1d10d8fa7a8a19ce73afdc9432d24843f62649cdd2
|
|
1163
|
+
.claude/skills/python-testing/SKILL.md b304a8c503af32644f97a889c5545ee4f90e91980462ad4ce33fee3dea6f414f
|
|
1164
|
+
.claude/skills/recurrence-prevention/SKILL.md ab537b5f35be053ffa930f99c5b3d972b80fd621d18eda8390506d01503f6d78
|
|
1165
|
+
.claude/skills/recurrence-prevention/SKILL.md 905324644b719f2cfc2744be0bb21922c9e4e6534a83c6b8cad980d6327b92be
|
|
1166
|
+
.claude/skills/recurrence-prevention/SKILL.md 40b8e5a14136cecf12a63cc2f709de2d80290e352aee88aa9a482200a3fd7295
|
|
1167
|
+
.claude/skills/recurrence-prevention/SKILL.md 8a26b9d530305497fe11b39e31eb7806d835953c2585fc15fcf51488d7fe6279
|
|
1168
|
+
.claude/skills/recurrence-prevention/SKILL.md 62fe94e2cd34d9c3c40871766619d5c37c957e89247c5d281e62c85de51326de
|
|
1169
|
+
.claude/skills/recurrence-prevention/SKILL.md a626f5760ffb7446695a578104baef9ba9259b3b41115b00d699c43d260c0295
|
|
1170
|
+
.claude/skills/recurrence-prevention/SKILL.md 9e44542d54006e02ae1d906346a90c0ad0e26c1797496e791c83f7bb0e867cc6
|
|
1171
|
+
.claude/skills/recurrence-prevention/SKILL.md c7c163aceb457535adb3c3052fe41355048716db2cbb0b4cc768ca6fd4533f26
|
|
1172
|
+
.claude/skills/recurrence-prevention/SKILL.md 46614922e61e79235493c80664da2f9e7d95d034c58c9a646b948a7c2a1f70b2
|
|
1173
|
+
.claude/skills/recurrence-prevention/references/failure-analysis.md 1dd840db9a2bc662ec9688833988d93e80d0be245e7edd727c2d065a9d7d9eca
|
|
1174
|
+
.claude/skills/recurrence-prevention/references/failure-analysis.md 5fc80d28b3f52e92843e9ef431a9dab74d8b43cb3cfd7ed5d2aa359ad00586bc
|
|
1175
|
+
.claude/skills/self-hosted-github-runner/SKILL.md 4e5b86b9c7c8527599cfd8be61f4ed3ab67d439bb791f4068d85e52c9327e5df
|
|
1176
|
+
.claude/skills/self-hosted-github-runner/SKILL.md a1394fde762c88fddc88db1502b15aabe88bdfc1c565e77bd3cdbb0512352d10
|
|
1177
|
+
.claude/skills/spec-scaling/SKILL.md fd28afb5558e2ba4168b0b16bc19b1c4d2fb732741649010a1601f751f9eafc5
|
|
1178
|
+
.claude/skills/spec-scaling/SKILL.md 93fe3ed443754bd368a45e71145434c1fd7efd349e25b0179bbb63774ac4ca0e
|
|
1179
|
+
.claude/skills/strategic-compact/SKILL.md c8e861a39fb84968aefa82783c1b25e61d1b625c29c0f5b2bb301f4652c93e9d
|
|
1180
|
+
.claude/skills/strategic-compact/SKILL.md 6bfc63c380eb89886335ad033f759a4ff3f1b1ae2c5a143598bb628e38c6e769
|
|
1181
|
+
.claude/skills/strategic-compact/suggest-compact.sh 62af1630b000713842e363447675ad5a94f72cddf47241df68fc9883de686689
|
|
1182
|
+
.claude/skills/task-brief/SKILL.md 69125822c0c7da8daa6e67117f0845e3388284b0d4b7cc2b69f440c9b865b454
|
|
1183
|
+
.claude/skills/task-brief/SKILL.md 0859fc0b6cf760edb83b4c41cb8156cc90b7c62f1d5b5dd364acd4c5f7935cc2
|
|
1184
|
+
.claude/skills/ui-visual-review/SKILL.md 4016297b69844f05a51c4669e62083b8d27a734f0daa24b3a03039979d6a28c7
|
|
1185
|
+
.claude/skills/ui-visual-review/SKILL.md 4c92c01e4d437150fe115406044d2ea9b8c942c2026f9e0d8d446667c4db7912
|
|
1186
|
+
.claude/skills/ui-visual-review/SKILL.md e9689dadb419979e2b62a3f1c84069f90b91ae95dd0a061dc759b3a60598aa32
|
|
1187
|
+
.claude/skills/ui-visual-review/SKILL.md 39371f46b46b7d8f51da0b9a28ca710156de634b6e066217e9618b1ecbe3f5ee
|
|
1188
|
+
.claude/skills/ui-visual-review/SKILL.md 2e23c9ba4e40a13db152ee750a33cadb6e32169daf51417c9a0a97b0ed021e45
|
|
1189
|
+
.claude/skills/ui-visual-review/SKILL.md 8d5c23460b4ba78c9b8077d9e6de59af5a38ea3035ca65f5cf645140ba523741
|
|
1190
|
+
.claude/skills/ultracode-service-audit/SKILL.md bdb3d151ca74e6129e547339b17192ba415701b46d889e0a1bf9f7fd0195663c
|
|
1191
|
+
.claude/skills/ultracode-service-audit/SKILL.md c7ca76cbda2f8d6b5750b68f524c92927ea375fb47a910ed02332e3a6fa1bca0
|
|
1192
|
+
.claude/skills/user-centered-explanation/SKILL.md eab47a91badce5d6314f63889950c69c43fa5ea4660d544828794ada3684e0b8
|
|
1193
|
+
.claude/skills/verification-loop/SKILL.md 01a9ae310ad4426bb05660dda6cefdeaac9513417585c09c8bb1b94738649a78
|
|
1194
|
+
.claude/skills/verification-loop/SKILL.md 41f481c1146b0b29ecbcf5c633090a6db3749ca4a814499d72b5b8941db694f5
|
|
1195
|
+
.claude/skills/verification-loop/SKILL.md 566fc81da559464d70af80a125dac60991ba5e26464643886c1dee04dd78db95
|
|
1196
|
+
.claude/skills/verification-loop/SKILL.md 1744f867f7868b83b480341c2e8d08bff3848c2408255871d3aba0c2f7eff2f2
|
|
1197
|
+
.claude/skills/verification-loop/agents/openai.yaml 1907fd04fea5c83d15faf14acfc978de90076d4351341cf9259639aa0c3b7bd3
|
|
1198
|
+
.claude/skills/verification-loop/references/tracks.md de11792d447c2e8ea67e8367c6655bd94646b1ba3f29184c4521cae01facc6ec
|
|
1199
|
+
.uzys-agent-harness/check-absence.sh b9bbc7bbdc69d51eac2a4e4748ee7c137dd585b4f3ca1d9bd2404eab9694c9b4
|
|
1200
|
+
.uzys-agent-harness/check-absence.sh c08d3a1df4188e5f37ddf7f7b53901184d87bdbed63c5c99afbddd0ef6a0442d
|
|
1201
|
+
.uzys-agent-harness/check-absence.sh 3655faf030e319e26a6386b316df004f4e2fee963fe0ebacb661030e85cda92e
|
|
1202
|
+
.uzys-agent-harness/protect-branch.sh 3356c4941ef1d5c174b10fd8858887f00b3b06c851788064e0e3cc6a6c8c56fd
|
|
1203
|
+
.uzys-agent-harness/protect-branch.sh ecd46450beae58c085a0d407c34441ae470092d9963bd4a37f09416a22cfad35
|
|
1204
|
+
.uzys-agent-harness/spec-drift-check.sh f35a64dd9954a776c3eabf356c0cda017db30e129d08022341a07c5a9d2b6f9a
|
|
1205
|
+
.uzys-agent-harness/spec-drift-check.sh 3c6925b03775454ec3a81e63dda400511824a9ac6e3f8f30b302ce1edf39d062
|
|
1206
|
+
`;
|
|
1207
|
+
var LEGACY_HARNESS_FILES = (() => {
|
|
1208
|
+
const m = /* @__PURE__ */ new Map();
|
|
1209
|
+
for (const [path = "", sha256 = ""] of rows(FILES)) {
|
|
1210
|
+
const s = m.get(path) ?? /* @__PURE__ */ new Set();
|
|
1211
|
+
s.add(sha256);
|
|
1212
|
+
m.set(path, s);
|
|
1213
|
+
}
|
|
1214
|
+
return m;
|
|
1215
|
+
})();
|
|
1216
|
+
function isLegacyHarnessFile(path, sha256) {
|
|
1217
|
+
const key = path.startsWith(".agents/skills/") ? `.claude/skills/${path.slice(".agents/skills/".length)}` : path;
|
|
1218
|
+
return LEGACY_HARNESS_FILES.get(key)?.has(sha256) === true;
|
|
1219
|
+
}
|
|
1220
|
+
var LEGACY_AGENTS_MD_SECTION_KEYS = keySet(`
|
|
1221
|
+
241678cd4951efaf8ee7bb0059e739c397af6b90b75fea636361501b7ae1cbe7 ## Workflow Gates (26.70.0)
|
|
1222
|
+
1e19e112dc2c9c85f31d7b8c1b65b5e35e8563db7f31115ba03af8c6ef1d5ea6 ## Command Reference (Antigravity workflows) (26.70.0)
|
|
1223
|
+
fe66384910daab3a0275c7c98d9a944f5f771d58ec2a9addcaf5f16a8d001ef9 ## Protected Files (DO NOT EDIT) (26.70.0)
|
|
1224
|
+
f7fbcaa082ffb260b11f48813a8f97f243663082aadb37e2137d2a99a143f65f ## Scopes (26.70.0)
|
|
1225
|
+
62225c82dd65fc0c01dba1fd6dbe8e9accb8d46d0f580f4d2a281dead3346997 ## Workflow Gates (26.70.0)
|
|
1226
|
+
0d509a214b74e5b3966722390279fe84fa20c8337fa7c9853c31fef0b42bf85f ## Session Start (26.70.0)
|
|
1227
|
+
fd29a37cc8231393739123a79728b31c0c4acde371ce502709550ed43837a2d4 ## Protected Files (DO NOT EDIT) (26.70.0)
|
|
1228
|
+
9c4a901cbad93ba04a5d511952e2e47213130c92ae2122e5f5649a17328d8915 ## Git Policy (26.70.0)
|
|
1229
|
+
c24a96fd321a9286debd618c9d95684c344c061d6a8e0558dce1595aa84e3a9f ## Command Reference (Codex slash) (26.70.0)
|
|
1230
|
+
23c25f2516a46dec187877d5d85f2e92257752193e287978650b3b112df083dd ## Agents (subagent, multi_agent stable) (26.70.0)
|
|
1231
|
+
dc230c795b307261ea4ee23126e6a209cc73ed474c97857d59e03a134232c4ec ## Hooks \uD604\uD669 (Codex 0.124.0 \uC2E4\uCE21 \uC81C\uC57D) (26.70.0)
|
|
1232
|
+
462ce33464e58a8ebd95ea5ed0f4cce167153fb2805ea6ba609734174a9027a2 ## Experience Accumulation (26.70.0)
|
|
1233
|
+
dc5629ad55f9800e4898a698650c8dbef5578505e7d5891745f0065f01d650a3 ## Context Management (26.70.0)
|
|
1234
|
+
c7d793aa3bf374b8bd390baf25bfc2c23c2d050377f673e72e53fe14f821c1f4 ## Workflow Gates (26.70.0)
|
|
1235
|
+
cf4cf430b633cb68b4128b03797999ed325f76ed92132fb8adcb60cccbc4e0c2 ## Session Start (26.70.0)
|
|
1236
|
+
ef2c745821688a463d4435affaaa6baf404feaec69f081c68a794d847f72a9e7 ## Protected Files (DO NOT EDIT) (26.70.0)
|
|
1237
|
+
f328397dafd8eaff1eeff91dcda315db3da289e646eca49a6b977725867cea3d ## Command Reference (OpenCode slash) (26.70.0)
|
|
1238
|
+
e1dd38e41e5df06efea65b349376a1ea668ce74a408efaf5c1ce91f08063a666 ## Agents (subagent) (26.70.0)
|
|
1239
|
+
1ca6e8025be0d099df42fce9248673722fe327be2a77a0d9971bacc18a99a10e ## Hooks (Plugin lifecycle) (26.70.0)
|
|
1240
|
+
ad834e2800b86a486d50efb9526657898a03919ee1b3fbf0cb0aaa89c9a6c095 ## Experience Accumulation (26.70.0)
|
|
1241
|
+
2cade5a88d6241fa7a50289fe0336b64cccd08d2c81b65e2df72acbdbc436a62 ## Context Management (26.70.0)
|
|
1242
|
+
b2532f7ae8302ee8aa5e0316f7bd9755abe06abeaa9639f7a9a062fc7d89b47f ## Scopes (26.89.0)
|
|
1243
|
+
c144f72dc32d524ae00b6026322439a5a3f2083d4e1781b927f374fe2b20d7c8 ## Session Start (26.89.0)
|
|
1244
|
+
0c719706bef388d3ac81a62431659bf817b0d4384846a0068d5768c8b3965e36 ## Protected Files (DO NOT EDIT) (26.89.0)
|
|
1245
|
+
6502c5abcf4cb9148c6dc5227401f7046b7dc8ab97ff7c292824de568b603942 ## Experience Accumulation (26.89.0)
|
|
1246
|
+
37106505641d9de7ae9e3ac5cc86efc3221abe5c969323325acc11e9b7d7cd04 ## Experience Accumulation (26.115.0)
|
|
1247
|
+
25baf8cc482b473d7f61e13ff95232484f95cc22063bb2ce9587f43ad242d5dc ## Scopes (26.141.0)
|
|
1248
|
+
d48603cb329fce58fd7ca9eb3b01dde3b223bdbfe79ee583627fbc15e22ba703 ## Session Start (26.141.0)
|
|
1249
|
+
29cb109e9a2cb4e3037a470d25d7dce4928d0e690c2c7c478d452f2133b65cd5 ## Git Policy (26.141.0)
|
|
1250
|
+
d1affcbe314d8ccd39ca956d467fbd43bcc859b4ffc23bf1d1f8f2f0a3e10f4e ## Context Management (26.141.0)
|
|
1251
|
+
9203c6d359a7ffc5a968be0645e1b827d6b4940312c27edb1c5fad6a68c9ca7e ## Session Start (26.141.0)
|
|
1252
|
+
39fdaaed39e0a39c537ebc3dcf5d349fb867740b126822eaa9333833d0de68eb ## Context Management (26.141.0)
|
|
1253
|
+
6f4bae4fb31bc54074d1fed021f4fd6dc3939844ac701eac8427904404b6daf3 ## Context Management (26.147.0)
|
|
1254
|
+
0569e0fb18d55a474fc8239dd60bb5684d22245c1ffa6f198cf6af468b5a3794 ## Protected Files (26.151.0)
|
|
1255
|
+
624b8878a9a17a5d4046b180297c53b27270ea75ed7d892d527939a7580adb19 ## Session Start (26.151.0)
|
|
1256
|
+
0f6658376e8bba3c31ffca010f24e9acee9f32953c00a41183dca9eaaa4f7913 ## Protected Files (26.151.0)
|
|
1257
|
+
55412b2ae275e9660f09c7cc286d3e92236e4ae61626cbf68727ae222edcb0e0 ## Protected Files (26.151.0)
|
|
1258
|
+
`);
|
|
1259
|
+
var LEGACY_AGENTS_MD_NAMED_KEYS = keySet(`
|
|
1260
|
+
92dce1a73d484490c943ec3418f10b2370079ae42aa8d93159596f45d12e699a ## Project Rules (26.70.0)
|
|
1261
|
+
f59bdc7177a12aa86f235ada16b2407c40bd55ae9de8e96a851b77571bdde989 ## Command Reference (Antigravity workflows) (26.70.0)
|
|
1262
|
+
c7f9fa755bd66d80c2df496c6c759e8accd736cd8fef64460feb7ae9cd4c8006 ## Context Management (26.70.0)
|
|
1263
|
+
dc030a35a6e638aba5447b4d4e79ae028fafd1419fbae872b902661fa7787a58 ## Command Reference (Codex slash) (26.70.0)
|
|
1264
|
+
df73823c02e6eee000388444964acfec233ffeec0e20fdc5d31eb018d2ca93c1 ## Context Management (26.77.0)
|
|
1265
|
+
6c900db77cb104f400091b44a7414e96427003860306a3007651b7a8b91a547c ## Project Rules (26.140.0)
|
|
1266
|
+
d9e3680462e64506ba4ef2df4f12e666855c3f458c1feeeeb623d62de2a5fa17 ## Project Rules (26.145.0)
|
|
1267
|
+
2da8ca3600045d85a9607ce270f9bc2d77b5ee54fe80cd0765caf7658f51127c ## Harness Rules (26.147.0)
|
|
1268
|
+
bbe5e1d9d368b15221269319b53dde4f87424904b80cd5af46a28de3d8ac923d ## Harness Rules (26.147.0)
|
|
1269
|
+
41eae7d6a8bb327e71cea2dbaa331d808f879b5ff4074c0bbdbb90bcfe066d9f ## Change Boundaries (rule 26.147.0)
|
|
1270
|
+
bef15b624ea34d08dc5833ceacd710f3c687385050958e5cd103378cf2fcf457 ## Change Boundaries (rule 26.147.0)
|
|
1271
|
+
9648c5a118c77a23a1a04ddcacd7708be162d65587769d47f51d2405b74c2f72 ## Shell Safety (rule 26.147.0)
|
|
1272
|
+
c2dee88e05c98e1482c99c1c01f59cafc6c6816fda1269d68179707f4ede0b8f ## Shell Safety (rule 26.147.0)
|
|
1273
|
+
a6c3b31f60c80906e8bdb7a5ba699a4c1062b2e2f3e94f9f56b5064f74a722ef ## Documentation Boundaries (rule 26.147.0)
|
|
1274
|
+
b8fbe3bb2d5d790015ddbcff85c68922a122d91705e1cc946a14b30480bfb22b ## Documentation Boundaries (rule 26.147.0)
|
|
1275
|
+
0a0b44e4c8d10aca52f63a4dba40d9166ea067eb1599886f850dc37ec2bba2f2 ## Git Safety (rule 26.147.0)
|
|
1276
|
+
05efdb03d3e9d9fbcfd652ddf778d25bb1ab5ce237dd33f17b0be82cad08db5b ## Session Cleanup (rule 26.147.0)
|
|
1277
|
+
10bdfa993f15639a319e852cf59f7b279b7397d26a94c54e6ca6a94416cc6834 ## Enforcement (rule 26.147.0)
|
|
1278
|
+
b72afd685f3c63e481dc856890c8a9d89c4e36ca3163ab172661e9fd5c3658a5 ## Enforcement (rule 26.147.0)
|
|
1279
|
+
126a9a57aa42007c9c0bd3cb7f0ce75f2ad6a7497b464e7f6c7f45f3ae5f40d2 ## Delivery (rule 26.147.0)
|
|
1280
|
+
edfa8459a9863e355a080c759419f6f5ffb0ebd5fc418914fd38d79622e73131 ## Delivery (rule 26.147.0)
|
|
1281
|
+
55295cda2a572e0aab061449248123d9d43543b3045b1b156b95fe2fb6aae509 ## Testing (rule 26.147.0)
|
|
1282
|
+
6364a5d8727d33db914c7d7a1ac4108cff9ed1dbefffb212bd84c1fcd7584284 ## Testing (rule 26.147.0)
|
|
1283
|
+
8d407c73c2de630d77d605447f605a6a2511fc4598d500ac7a1ff1374e2e457d ## Delivery (rule 26.148.0)
|
|
1284
|
+
2c3f8e7c8408f103006e4ef8029dce4da1995bca01bd1e6baf7ca3f4e46e58fa ## Delivery (rule 26.148.0)
|
|
1285
|
+
ae930fa7c8fa6f942d20715a51de43f33461aa5589f469f13a31ab90da1904e7 ## Delivery (rule 26.149.0)
|
|
1286
|
+
5b97fa550beb24e86c04af7fba2c97d8ff51702fd25abf223d97350db2a19ff1 ## Delivery (rule 26.149.0)
|
|
1287
|
+
e9b5814787b1e1cc066c217da0e344604477edfc0eb17304a5aeca73b0846637 ## Testing (rule 26.149.0)
|
|
1288
|
+
bafced984a2acf13f6fc7a3ca7c79edb99b5cecd4b21e351bd093f260d32fb02 ## Testing (rule 26.149.0)
|
|
1289
|
+
4972faf000e3433c0c07f7bb36e6b0463453be308dea31cfc177d692e23e3700 ## Project Rules (26.151.0)
|
|
1290
|
+
381a1d00394f803118575ecde42946585466c2da2ec36239fd6208a3c1b6bab8 ## Change Boundaries (rule 26.151.0)
|
|
1291
|
+
1a9dda0c66c7d82bdeb29c169f749a44c03b9bc112b3a1146898826b7d77b04e ## Change Boundaries (rule 26.151.0)
|
|
1292
|
+
e0d9ecb6916b563cfd0eaaf3f977106826136c4aaef518e705508c60f17b3cac ## Shell Safety (rule 26.151.0)
|
|
1293
|
+
053642f8951a2da28bca7d8d985a01c8fc2a6a91223a8cdfcd5e7ba5ef78af62 ## Shell Safety (rule 26.151.0)
|
|
1294
|
+
6543ff93b6c1f27f6d76f2a2a7599fd7ed0d1004f5419d5082321d1f4729bd1e ## Documentation Boundaries (rule 26.151.0)
|
|
1295
|
+
1741bf4e931d799c850ae45944ac2a9985800240d011a670ddb9400013b14856 ## Documentation Boundaries (rule 26.151.0)
|
|
1296
|
+
e527b3630786a074e321e1375b44f0870df3f7d4f124d5fdca9bbbd7e66f9315 ## Session Cleanup (rule 26.151.0)
|
|
1297
|
+
8ec2a06cfe3fa51e8187b218c290cf9ddc7680eac85427e2f6cf2a4a1a03ed4c ## Delivery (rule 26.151.0)
|
|
1298
|
+
d7fad0202a32aedb45717177ef9d3647109a0e77ee13f37b4c4a42f892182d4c ## Delivery (rule 26.151.0)
|
|
1299
|
+
2332b78bb1eb206ba1b08e28b3114d4919fb1384a9a5378f55dead61fdc3105a ## Testing (rule 26.151.0)
|
|
1300
|
+
d172feb48f54338d5d81e8b390debe3537538f0d2214f51e590272547e113cd2 ## Testing (rule 26.151.0)
|
|
1301
|
+
99bdd67b5ae37c10588f4ff852525ebe2ab59368723f56bd317818a89161c59a ## Change Boundaries (rule 26.152.0)
|
|
1302
|
+
a07c989310055284328b4ca441e201740fc8158a38572e56ec9968dac44ced13 ## Change Boundaries (rule 26.152.0)
|
|
1303
|
+
e4d2c89e6c2189748bef2dccf8eb506b7f8cf264d5bf8626fbe4446c330e0b63 ## Shell Safety (rule 26.152.0)
|
|
1304
|
+
028c8514fa466e7f053088e37968ef07ce1bcb08d4c224e76ec807d0f01e4449 ## Shell Safety (rule 26.152.0)
|
|
1305
|
+
9f0ac9e1c32c486e4f318061e3be3c853217d03b3f837b6c6e425f016c8707e9 ## Documentation Boundaries (rule 26.152.0)
|
|
1306
|
+
992ca24bd1f15314fb53943af2856af73f0d31ad8c6cf98b25b840ebd017b86a ## Documentation Boundaries (rule 26.152.0)
|
|
1307
|
+
49ec458da7c57727c16ec8ffa01cb2e2631eb769f6041b3bc07d912ec1a2994b ## Project Rules (26.153.0)
|
|
1308
|
+
155abf346fea6c63a081d4db1a1e44d537c4a94a479a2affc96345b18928fde3 ## Testing (rule 26.157.0)
|
|
1309
|
+
675da728d15da072c17fe5e9ba3ca8b21811e99a09f390fed4a53f19dd12c555 ## Testing (rule 26.157.0)
|
|
1310
|
+
`);
|
|
1311
|
+
var LEGACY_AGENTS_MD_PREAMBLE_KEYS = keySet(`
|
|
1312
|
+
720645dd313be16e6204290bfe0451fb237f77b8a7498a8a8af77dfc44ac0828 > **Generated from**: '.claude/CLAUDE.md' via TS CLI 'src/antigravity/transform.ts' (26.70.0)
|
|
1313
|
+
f95170e7780965de8562db0b5c7846d8e75ac7902a4fab695373c691333c7ff4 > **Generated from**: '.claude/CLAUDE.md' via 'scripts/claude-to-codex.sh' (Phase C) (26.70.0)
|
|
1314
|
+
fe621e2687dd489f3e9fb6ca1b97d480a83af435d99117315c24534d9c4bc169 > **Generated from**: '.claude/CLAUDE.md' via TS CLI 'src/opencode/transform.ts' (Phase C) (26.70.0)
|
|
1315
|
+
0d05490eb1360e2601d7e63b79c901a10da1dcfd6c9437151e4fb1ce00416bfc > **Generated from**: 'templates/CLAUDE.md' (4-CLI \uB2E8\uC77C \uC6D0\uBCF8) via TS CLI 'src/antigravity/transform.ts' (26.141.0)
|
|
1316
|
+
1979722e483fba4441ffd4818134b3942cc97f21e39689316d6143e4732c98a7 > **Generated from**: 'templates/CLAUDE.md' (4-CLI \uB2E8\uC77C \uC6D0\uBCF8) via 'scripts/claude-to-codex.sh' (Phase C) (26.141.0)
|
|
1317
|
+
230413c8211b1a9c3b204e315ff63f6ac3a7d7e5d01c8dd3d4ed294bf3c49f5c > **Generated from**: 'templates/CLAUDE.md' (4-CLI \uB2E8\uC77C \uC6D0\uBCF8) via TS CLI 'src/opencode/transform.ts' (Phase C) (26.141.0)
|
|
1318
|
+
`);
|
|
1319
|
+
var RETIRED_ANCHOR_SECTION_KEYS = keySet(`
|
|
1320
|
+
522bac15bc17949697e291b837c0d9624f5e0c7666400a3baf94cdef7cfab8b5 ## Rule 1 \u2014 Think Before Coding (26.70.0)
|
|
1321
|
+
ea10b7cd9b84a71949a071fae15256f490b3fe407159d7bddcf3f882310fa835 ## Rule 2 \u2014 Simplicity First (26.70.0)
|
|
1322
|
+
c486465d9554f2de1711cd056437f6a95a5d3243264b82d29a6957f24b5a6de3 ## Rule 3 \u2014 Surgical Changes (26.70.0)
|
|
1323
|
+
3d080574cc7ae81eda75c4aa019445b38b6f69c5f9eeeda9097e10b6041e7e94 ## Rule 4 \u2014 Goal-Driven Execution (26.70.0)
|
|
1324
|
+
11e43547f6b1613a5dabb3edaf5131d696a3fd375b3c22558f03555a0f5cf2ef ## Rule 5 \u2014 Use the model only for judgment calls (26.70.0)
|
|
1325
|
+
60d91718de6ae16ec86b50e7c9a939a6ca5fc0721422b592700cc9972f55aca2 ## Rule 6 \u2014 Token budgets are not advisory (26.70.0)
|
|
1326
|
+
9d482c7307cbcb02acc6fb35cd57b24baa9fce04528e2bd21e1e877603f8b85b ## Rule 7 \u2014 Surface conflicts, don't average them (26.70.0)
|
|
1327
|
+
abca09f13833ce18bd0ffc0793d59780c35447ca79c2a512afcbc9d7a7116ed8 ## Rule 8 \u2014 Read before you write (26.70.0)
|
|
1328
|
+
5b4eae6c3dc2d92cfb1772889650882a4a2115f08a36602da9a1d96697059b91 ## Rule 9 \u2014 Tests verify intent, not just behavior (26.70.0)
|
|
1329
|
+
632670b8897dc373d4a12f611c2436d9a8e86d8cdab917eecabc4bf2a56f8030 ## Rule 10 \u2014 Checkpoint after every significant step (26.70.0)
|
|
1330
|
+
252e99f25b05a47e5ce884ac9f1e1d34156116b9a76331e2510b1354a6c98cd4 ## Rule 11 \u2014 Match the codebase's conventions, even if you disagree (26.70.0)
|
|
1331
|
+
c28a12b589b6576379793c51fd01dbfaf91d391ac773f84ae0477ddb60a1e3e8 ## Rule 12 \u2014 Fail loud (26.70.0)
|
|
1332
|
+
72feaf96f998989351f8083edb891c7b0c3bccca65dbea2732fb2864b8f98bd4 ## \uC758\uC0AC\uACB0\uC815 \uBC0F \uCEE8\uD38C \uC694\uCCAD \uC2DC (26.70.0)
|
|
1333
|
+
95c932ecb4f4fdcdd8d483f9d02166b906f6eb045ef33ee474a16913d0c3e6cd ## Phase/\uC791\uC5C5 \uC644\uB8CC \uC2DC Self-Audit \uC2E4\uD589: (26.70.0)
|
|
1334
|
+
c7f9fa755bd66d80c2df496c6c759e8accd736cd8fef64460feb7ae9cd4c8006 ## Context Management (26.70.0)
|
|
1335
|
+
6ec0b415a8f86c9940bccd3e6db895ea4a110185e76fef223a348f9553fd897c ## Rule 12 \u2014 Fail loud (26.77.0)
|
|
1336
|
+
a78f0ffa6b51c9b45c964ecb92db951534336f7e558a3d39d11f015ee6c3466c ## Anti-Patterns (Forbidden) (26.77.0)
|
|
1337
|
+
50d00a511e87571d7ff85f6584b87b9f5c2eef06122d8ac5fdccf3f047643f12 ## When Requesting Decisions or Confirmation (26.77.0)
|
|
1338
|
+
574519e07f48bcc04f0e3d505c0f9c157ddd426b5eda2baa99656cd4712dad2b ## Run Self-Audit on Phase/Task Completion (26.77.0)
|
|
1339
|
+
df73823c02e6eee000388444964acfec233ffeec0e20fdc5d31eb018d2ca93c1 ## Context Management (26.77.0)
|
|
1340
|
+
8f49f0a592575a65eadd3e33950c96616223aa8bb116707103affeef71db28c6 ## Delegate the Building, Keep the Deciding (26.139.0)
|
|
1341
|
+
6115eccc3b2702f436a9db7d6af9803fa7b1fbf7b9ff1110ea658fadd67ec5ea ## 1. Think before coding (26.140.0)
|
|
1342
|
+
15b120395ec8e757ecbe3e65775371a9120953617fb37eb062e0c176b52f045a ## 2. Prefer the simplest sufficient solution (26.140.0)
|
|
1343
|
+
cc466b4781444ca54aedebd20ba3aa531c3aa84cc438953df84b133bd32a0e1e ## 3. Make surgical changes and preserve existing work (26.140.0)
|
|
1344
|
+
f6d1f6f02cb3c19e61becf329f20335c54e684bccb06b33e4b7f66eb49f9c6b6 ## 4. Define success before editing (26.140.0)
|
|
1345
|
+
372bf30b282b861c6a89e355c94ffd239bb0202e2ef928f8af99d640579710f0 ## 5. Report evidence, not confidence (26.140.0)
|
|
1346
|
+
66ca0e3aae98d24c65afbc418645df29d8c570be81918c42192eb1beecd21f23 ## 6. Do not cross high-impact boundaries alone (26.140.0)
|
|
1347
|
+
9c6c27eb57a9790273fa3fdf0df3628d927b025f870f09933692d1b522d73a25 ## Decisions and explanations (26.140.0)
|
|
1348
|
+
922d100c2dc6ef8a53989a920c3554afa7efd148255bc144412403c0289439e6 ## Decisions and explanations (26.141.0)
|
|
1349
|
+
330a67775a28557431aebf36a44018fc5194a4b929bf2cf95184b1f0828a6360 ## 1. Understand First (26.145.0)
|
|
1350
|
+
3b2f0147dc7bd0f01fd12485790199ef4ee96a6b723e244ffbf3dc96933a1ab8 ## 2. Define Success and Keep It Simple (26.145.0)
|
|
1351
|
+
8802fb25c05879c98dbf8407001d239c410d25b4fa2521b11d9d7cc108f73b29 ## 3. Preserve Sound Boundaries (26.145.0)
|
|
1352
|
+
1d0d9bf05d8870dd0dc62e388ceffc98923f1dd2074ef8038f80a50c9b5b9a81 ## 4. Make Surgical Changes (26.145.0)
|
|
1353
|
+
05e08e2318061141464ae714d6770d35527576affa787740d9c6d9345d3462dd ## 5. Verify and Review (26.145.0)
|
|
1354
|
+
7b39f1f92a72517d6ae52599becfef29f675e48185a3483dc993d7accd4aee7c ## 6. Protect High-Impact Boundaries (26.145.0)
|
|
1355
|
+
d5d93c55de33e4cdcb38f76c6d6d70a6e0beac7a176c8aa1daa09905ccc5fe39 ## 7. Report Evidence (26.145.0)
|
|
1356
|
+
cefc8bb6194d4f1b6302345e96ffb3a28b8b992032fd40f9f5b4f18997657e7a ## Presenting a decision (26.145.0)
|
|
1357
|
+
7385ff5df34148278a8f4b164c11ba5f9355626abcc13a822dd1ebb206321c2f ## Skills that apply continuously (26.145.0)
|
|
1358
|
+
ad9fd1ff225c57c9801a7d7472bf4ddf9c952c602f4a93eae86fbcb3bcf468bc ## 7. Report Evidence (26.146.0)
|
|
1359
|
+
868fe823fc40011d08816c9f1105ef6df7ca7f2479779303ce9583bba1ce6e0d ## Skills that apply continuously (26.146.0)
|
|
1360
|
+
3f8259ca7c92d79cca1a36bba38f36d4ef5a96fd6cafbd0edb5a79492082f46f ## Presenting a decision (26.147.0)
|
|
1361
|
+
ecfdcd50e97723af77cfe6889bbad784cdeb86dd0c52af3ff98ddf6adf80f445 ## 1. Resolve what matters, then act (26.151.0)
|
|
1362
|
+
9321cb1312a080bcf560940b8f86d3d59b39c667add4b8f3ad785ddae9bc8b20 ## 2. Choose the simplest sufficient solution (26.151.0)
|
|
1363
|
+
a4c345996a8578cc24b62fde27084e5848a61e4a40d91b0c72a95da46203b43c ## 3. Keep changes focused and preserve existing work (26.151.0)
|
|
1364
|
+
1adbf1bf88bb8288744e1c1d73518ffdec12a5b668d5a225e2bedd006844466c ## 4. Define success and verify proportionally (26.151.0)
|
|
1365
|
+
7636e57a877d54039f0c2829fde84202c65378bd36b8c8abb7274a29eaa5f8ac ## 5. Report evidence and stop unproductive loops (26.151.0)
|
|
1366
|
+
ddf2be9e04c04bf53ad9b5476e45639b33a60bf49bd3a83835796632052b17b4 ## 6. Keep authority explicit (26.151.0)
|
|
1367
|
+
16b0edc0f4886a9f9ec94e6fb97206c385286b2c9d5563b2324b7a2f4a434435 ## 1. Understand what success means (26.153.0)
|
|
1368
|
+
b10ab1eafe25bb7ba3b20b907b1d7eedde03e52fbd49905f24e192e30b4e1b9a ## 2. Choose and adapt the approach (26.153.0)
|
|
1369
|
+
69bcfb8b37ac184b1a30945a0dea59108ef1242c2f40fb778be118cbd524aea7 ## 3. Keep changes focused and coherent (26.153.0)
|
|
1370
|
+
f22a5a13c5ed8460c9370212d91354d0fea2fefc7f420a1eb3088504ae8da6c0 ## 4. Verify outcomes in proportion to consequences (26.153.0)
|
|
1371
|
+
7a335cde69e8055ee5e137a9a5c09fd7f7c2e551ab099a2cda87f0c3dcd95a19 ## 5. Let evidence determine readiness (26.153.0)
|
|
1372
|
+
79797568bb71bd0f7b14393f72e61721a4bfe99ecfb6126ffa38a6c03c53d765 ## 6. Act within clear authority (26.153.0)
|
|
1373
|
+
`);
|
|
1374
|
+
var LEGACY_HOOK_COMMANDS = /* @__PURE__ */ new Set([
|
|
1375
|
+
'bash "$CLAUDE_PROJECT_DIR/.claude/hooks/agentshield-gate.sh"',
|
|
1376
|
+
'bash "$CLAUDE_PROJECT_DIR/.claude/hooks/gate-check.sh"',
|
|
1377
|
+
'bash "$CLAUDE_PROJECT_DIR/.claude/hooks/hito-counter.sh"',
|
|
1378
|
+
'bash "$CLAUDE_PROJECT_DIR/.claude/hooks/mcp-pre-exec.sh"',
|
|
1379
|
+
'bash "$CLAUDE_PROJECT_DIR/.claude/hooks/protect-files.sh"',
|
|
1380
|
+
'bash "$CLAUDE_PROJECT_DIR/.claude/hooks/session-start.sh"',
|
|
1381
|
+
'bash "$CLAUDE_PROJECT_DIR/.claude/hooks/task-brief-nudge.sh"',
|
|
1382
|
+
'bash "$CLAUDE_PROJECT_DIR/.claude/skills/strategic-compact/suggest-compact.sh"'
|
|
1383
|
+
]);
|
|
1384
|
+
var LEGACY_STATUSLINE_VALUES = keySet(`
|
|
1385
|
+
f3de524065fd30f26e2d14b31fad0edc4c6689fb95b8ea6c59b1d48c5a90adc5 statusLine (26.70.0)
|
|
1386
|
+
94442f9703e367a12f6dc16612ad65ae5f0cd0c73b96dd683e584a18ac91eaea statusLine (26.164.0)
|
|
1387
|
+
`);
|
|
1388
|
+
|
|
1389
|
+
// src/hook-ref.ts
|
|
805
1390
|
function projectAnchoredRef(command, claudeDir) {
|
|
806
1391
|
const anchors = [
|
|
807
1392
|
"$CLAUDE_PROJECT_DIR/.claude/",
|
|
@@ -820,12 +1405,21 @@ function projectAnchoredRef(command, claudeDir) {
|
|
|
820
1405
|
}
|
|
821
1406
|
return void 0;
|
|
822
1407
|
}
|
|
1408
|
+
var LEGACY_HOOK_REFS = [...LEGACY_HOOK_COMMANDS].flatMap(
|
|
1409
|
+
(c3) => projectAnchoredRef(c3) ?? []
|
|
1410
|
+
);
|
|
1411
|
+
function isLegacyHookLine(command, claudeDir) {
|
|
1412
|
+
if (typeof command !== "string") return false;
|
|
1413
|
+
const ref = projectAnchoredRef(command, claudeDir);
|
|
1414
|
+
if (ref === void 0) return false;
|
|
1415
|
+
return !LEGACY_HOOK_REFS.includes(ref) || LEGACY_HOOK_COMMANDS.has(command);
|
|
1416
|
+
}
|
|
823
1417
|
function keepHookRef(hook, claudeDir, removed) {
|
|
824
1418
|
const relPath = projectAnchoredRef(hook?.command ?? "", claudeDir);
|
|
825
1419
|
if (relPath === void 0) return true;
|
|
826
|
-
const
|
|
827
|
-
if (!
|
|
828
|
-
return
|
|
1420
|
+
const exists2 = existsSync(join(claudeDir, relPath));
|
|
1421
|
+
if (!exists2 && !removed.includes(relPath)) removed.push(relPath);
|
|
1422
|
+
return exists2;
|
|
829
1423
|
}
|
|
830
1424
|
function findStaleHookRefs(settingsPath, claudeDir, spare) {
|
|
831
1425
|
let settings;
|
|
@@ -858,6 +1452,7 @@ function removeRetiredHookRefs(settingsPath, claudeDir, refs, opts = {}) {
|
|
|
858
1452
|
const isRetiredDead = (hook) => {
|
|
859
1453
|
const rel = projectAnchoredRef(hook?.command ?? "", claudeDir);
|
|
860
1454
|
if (rel === void 0 || !refs.includes(rel)) return false;
|
|
1455
|
+
if (!isLegacyHookLine(hook?.command, claudeDir)) return false;
|
|
861
1456
|
if (opts.evenIfScriptExists !== true && existsSync(join(claudeDir, rel))) return false;
|
|
862
1457
|
if (!removed.includes(rel)) removed.push(rel);
|
|
863
1458
|
return true;
|
|
@@ -943,13 +1538,14 @@ function planUpsert(args) {
|
|
|
943
1538
|
}
|
|
944
1539
|
function planStrip(args) {
|
|
945
1540
|
const alwaysStrip2 = args.alwaysStrip ?? (() => false);
|
|
946
|
-
const plan = { remove: [], kept: [], portions: /* @__PURE__ */ new Map() };
|
|
1541
|
+
const plan = { remove: [], removedEdited: [], kept: [], portions: /* @__PURE__ */ new Map() };
|
|
947
1542
|
for (const [key, sha] of args.recorded) {
|
|
948
1543
|
if (args.excluded.has(key)) continue;
|
|
949
1544
|
const now = args.present.get(key);
|
|
950
1545
|
if (now === void 0) continue;
|
|
951
1546
|
if (now === sha || alwaysStrip2(key)) {
|
|
952
1547
|
plan.remove.push(key);
|
|
1548
|
+
if (now !== sha) plan.removedEdited.push(key);
|
|
953
1549
|
} else {
|
|
954
1550
|
plan.kept.push(key);
|
|
955
1551
|
plan.portions.set(key, sha);
|
|
@@ -1235,6 +1831,7 @@ var jsonKeys = {
|
|
|
1235
1831
|
text: changed ? serialize(root) : existing,
|
|
1236
1832
|
changed,
|
|
1237
1833
|
removed: plan.remove,
|
|
1834
|
+
removedEdited: plan.removedEdited,
|
|
1238
1835
|
kept: plan.kept,
|
|
1239
1836
|
portions: plan.portions,
|
|
1240
1837
|
empty: Object.keys(root).length === 0
|
|
@@ -1426,6 +2023,7 @@ var lines = {
|
|
|
1426
2023
|
text,
|
|
1427
2024
|
changed: text !== existing,
|
|
1428
2025
|
removed: plan.remove,
|
|
2026
|
+
removedEdited: plan.removedEdited,
|
|
1429
2027
|
kept: plan.kept,
|
|
1430
2028
|
portions: plan.portions,
|
|
1431
2029
|
empty: text.trim() === ""
|
|
@@ -1438,125 +2036,6 @@ init_esm_shims();
|
|
|
1438
2036
|
|
|
1439
2037
|
// src/agents-md-merge.ts
|
|
1440
2038
|
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
2039
|
var marker = (name) => ({
|
|
1561
2040
|
start: `<!-- uzys-harness:${name}:start -->`,
|
|
1562
2041
|
end: `<!-- uzys-harness:${name}:end -->`
|
|
@@ -1627,6 +2106,29 @@ function trimTrailingBlanks(lines2) {
|
|
|
1627
2106
|
while (out.length > 0 && (out.at(-1) ?? "").trim() === "") out.pop();
|
|
1628
2107
|
return out;
|
|
1629
2108
|
}
|
|
2109
|
+
function isLegacyHarnessSection(lines2) {
|
|
2110
|
+
const key = legacySectionKey(lines2);
|
|
2111
|
+
return RETIRED_ANCHOR_SECTION_KEYS.has(key) || LEGACY_AGENTS_MD_SECTION_KEYS.has(key) || LEGACY_AGENTS_MD_NAMED_KEYS.has(key);
|
|
2112
|
+
}
|
|
2113
|
+
function withoutAgentsBlock(text) {
|
|
2114
|
+
const lines2 = text.split("\n");
|
|
2115
|
+
const at5 = blockRange(lines2, AGENTS_BLOCK);
|
|
2116
|
+
if (at5 === null) return text;
|
|
2117
|
+
const head = trimTrailingBlanks(lines2.slice(0, at5[0]));
|
|
2118
|
+
const tail = lines2.slice(at5[1] + 1);
|
|
2119
|
+
while (tail.length > 0 && (tail[0] ?? "").trim() === "") tail.shift();
|
|
2120
|
+
return tail.length > 0 ? [...head, "", ...tail].join("\n") : `${head.join("\n")}
|
|
2121
|
+
`;
|
|
2122
|
+
}
|
|
2123
|
+
function isLegacyHarnessAgentsMd(text) {
|
|
2124
|
+
const body = withoutAgentsBlock(text);
|
|
2125
|
+
const lines2 = body.split("\n");
|
|
2126
|
+
if (blockRange(lines2, ANCHOR_BLOCK) !== null || blockRange(lines2, SKILLS_BLOCK) !== null) {
|
|
2127
|
+
return false;
|
|
2128
|
+
}
|
|
2129
|
+
const key = legacyPreambleKey(body);
|
|
2130
|
+
return key !== null && LEGACY_AGENTS_MD_PREAMBLE_KEYS.has(key);
|
|
2131
|
+
}
|
|
1630
2132
|
function refreshBlock(existing, rendered, m, legacyHeading) {
|
|
1631
2133
|
const at5 = blockRange(rendered, m);
|
|
1632
2134
|
const fresh = at5 === null ? null : rendered.slice(at5[0], at5[1] + 1);
|
|
@@ -1679,9 +2181,11 @@ function renderAgentsBlock(params) {
|
|
|
1679
2181
|
trimBlankEdges(harness)
|
|
1680
2182
|
].filter((part) => part.length > 0).map((part) => part.join("\n")).join("\n\n");
|
|
1681
2183
|
}
|
|
1682
|
-
function
|
|
2184
|
+
function mergeAgentsMdDetailed(params) {
|
|
1683
2185
|
const { rendered, existing, template } = params;
|
|
1684
|
-
if (existing === null)
|
|
2186
|
+
if (existing === null) {
|
|
2187
|
+
return { text: rendered, droppedLegacySections: 0, editedLegacySections: [] };
|
|
2188
|
+
}
|
|
1685
2189
|
const names = sectionNames(template);
|
|
1686
2190
|
const bodies = /* @__PURE__ */ new Map();
|
|
1687
2191
|
const contextNow = sectionBody(existing, names, CONTEXT_SECTION);
|
|
@@ -1703,18 +2207,32 @@ function mergeAgentsMd(params) {
|
|
|
1703
2207
|
}
|
|
1704
2208
|
const merged = bodies.size === 0 ? rendered : assemble(rendered, names, bodies);
|
|
1705
2209
|
const mergedText = merged.replace(/\r/g, "");
|
|
1706
|
-
const
|
|
2210
|
+
const candidates = extraTopLevelSections(
|
|
1707
2211
|
existing,
|
|
1708
2212
|
names,
|
|
1709
2213
|
rendered,
|
|
1710
2214
|
params.harnessRuleHeadings ?? /* @__PURE__ */ new Set(),
|
|
1711
2215
|
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
2216
|
);
|
|
2217
|
+
const droppedLegacySections = candidates.legacy;
|
|
2218
|
+
const editedLegacySections = isLegacyHarnessAgentsMd(existing) ? installerSectionsInHarnessArea(
|
|
2219
|
+
existing,
|
|
2220
|
+
names,
|
|
2221
|
+
/* @__PURE__ */ new Set([...params.harnessRuleHeadings ?? [], ...renderedRuleHeadings(rendered, names)]),
|
|
2222
|
+
true
|
|
2223
|
+
).keptEdited : [];
|
|
2224
|
+
const extras = candidates.sections.filter(
|
|
2225
|
+
(e2) => !mergedText.includes(e2.join("\n").replace(/\r/g, ""))
|
|
2226
|
+
);
|
|
2227
|
+
if (extras.length === 0) return { text: merged, droppedLegacySections, editedLegacySections };
|
|
2228
|
+
return {
|
|
2229
|
+
text: `${merged.replace(/\n+$/, "\n")}${extras.map((e2) => e2.join("\n")).join("\n")}`.replace(
|
|
2230
|
+
/\n+$/,
|
|
2231
|
+
"\n"
|
|
2232
|
+
),
|
|
2233
|
+
droppedLegacySections,
|
|
2234
|
+
editedLegacySections
|
|
2235
|
+
};
|
|
1718
2236
|
}
|
|
1719
2237
|
function headingOwner(bare, ctx) {
|
|
1720
2238
|
const name = /^## (.+?)\s*$/.exec(bare)?.[1];
|
|
@@ -1737,7 +2255,6 @@ function extraTopLevelSections(existing, names, rendered, harnessRuleHeadings, r
|
|
|
1737
2255
|
...renderedRuleHeadings(rendered, names)
|
|
1738
2256
|
]);
|
|
1739
2257
|
const out = [];
|
|
1740
|
-
const replacedSections = /* @__PURE__ */ new Set();
|
|
1741
2258
|
let current = null;
|
|
1742
2259
|
let region = null;
|
|
1743
2260
|
for (const line of existing.split("\n")) {
|
|
@@ -1749,19 +2266,18 @@ function extraTopLevelSections(existing, names, rendered, harnessRuleHeadings, r
|
|
|
1749
2266
|
const owner = headingOwner(bare, { region, names, harnessHeadings });
|
|
1750
2267
|
const replacedBody = owner === "body" && region === RULES_SECTION && replacedRulesHeadings !== null && !replacedRulesHeadings.has(bare.trim());
|
|
1751
2268
|
current = owner === "installer" || replacedBody ? [line] : null;
|
|
1752
|
-
if (replacedBody && current !== null) replacedSections.add(current);
|
|
1753
2269
|
continue;
|
|
1754
2270
|
}
|
|
1755
2271
|
if (current !== null) current.push(line);
|
|
1756
2272
|
}
|
|
1757
2273
|
if (current !== null) out.push(current);
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
).map((lines2) => {
|
|
2274
|
+
const legacy = out.filter(isLegacyHarnessSection).length;
|
|
2275
|
+
const sections = out.filter((lines2) => !isLegacyHarnessSection(lines2)).map((lines2) => {
|
|
1761
2276
|
const trimmed = [...lines2];
|
|
1762
2277
|
while (trimmed.length > 1 && (trimmed.at(-1) ?? "").trim() === "") trimmed.pop();
|
|
1763
2278
|
return trimmed;
|
|
1764
2279
|
}).filter((lines2) => lines2.length > 1 || /^## /.test(lines2[0] ?? ""));
|
|
2280
|
+
return { sections, legacy };
|
|
1765
2281
|
}
|
|
1766
2282
|
function installerLines(body, m) {
|
|
1767
2283
|
if (body === null) return [];
|
|
@@ -1781,7 +2297,7 @@ function projectContextInstallerLines(params) {
|
|
|
1781
2297
|
const body = sectionBody(existing, sectionNames(template), CONTEXT_SECTION);
|
|
1782
2298
|
return body === null ? null : installerLines(body, SKILLS_BLOCK);
|
|
1783
2299
|
}
|
|
1784
|
-
function installerSectionsInHarnessArea(existing, names, harnessRuleHeadings) {
|
|
2300
|
+
function installerSectionsInHarnessArea(existing, names, harnessRuleHeadings, legacyFile = false) {
|
|
1785
2301
|
const out = [];
|
|
1786
2302
|
let current = null;
|
|
1787
2303
|
let region = null;
|
|
@@ -1792,31 +2308,60 @@ function installerSectionsInHarnessArea(existing, names, harnessRuleHeadings) {
|
|
|
1792
2308
|
if (current !== null) out.push(current);
|
|
1793
2309
|
if (names.has(name)) region = name;
|
|
1794
2310
|
const owner = headingOwner(bare, { region, names, harnessHeadings: harnessRuleHeadings });
|
|
1795
|
-
current = owner === "installer" ? [bare] : null;
|
|
2311
|
+
if (!legacyFile) current = owner === "installer" ? { lines: [bare], named: false } : null;
|
|
2312
|
+
else if (region === CONTEXT_SECTION) current = null;
|
|
2313
|
+
else current = { lines: [bare], named: owner === "harness" };
|
|
1796
2314
|
continue;
|
|
1797
2315
|
}
|
|
1798
|
-
if (current !== null) current.push(bare);
|
|
2316
|
+
if (current !== null) current.lines.push(bare);
|
|
1799
2317
|
}
|
|
1800
2318
|
if (current !== null) out.push(current);
|
|
1801
|
-
|
|
2319
|
+
const sections = [];
|
|
2320
|
+
const keptEdited = [];
|
|
2321
|
+
let legacy = 0;
|
|
2322
|
+
for (const { lines: lines2, named } of out) {
|
|
2323
|
+
if (isLegacyHarnessSection(lines2)) {
|
|
2324
|
+
legacy++;
|
|
2325
|
+
continue;
|
|
2326
|
+
}
|
|
2327
|
+
if (named) {
|
|
2328
|
+
if (lines2.slice(1).every((l) => l.trim() === "")) continue;
|
|
2329
|
+
keptEdited.push((lines2[0] ?? "").replace(/^## /, "").trim());
|
|
2330
|
+
}
|
|
2331
|
+
sections.push(trimTrailingBlanks(lines2));
|
|
2332
|
+
}
|
|
2333
|
+
return { sections, legacy, keptEdited };
|
|
1802
2334
|
}
|
|
1803
|
-
function
|
|
2335
|
+
function stripAgentsMd(params) {
|
|
1804
2336
|
const { existing, template } = params;
|
|
1805
2337
|
const lines2 = existing.split("\n");
|
|
2338
|
+
const names = sectionNames(template);
|
|
2339
|
+
const headings = params.harnessRuleHeadings ?? /* @__PURE__ */ new Set();
|
|
1806
2340
|
if (blockRange(lines2, ANCHOR_BLOCK) === null && blockRange(lines2, SKILLS_BLOCK) === null) {
|
|
1807
|
-
|
|
2341
|
+
if (!isLegacyHarnessAgentsMd(existing)) {
|
|
2342
|
+
return {
|
|
2343
|
+
remainder: null,
|
|
2344
|
+
legacyRemoved: false,
|
|
2345
|
+
legacySections: 0,
|
|
2346
|
+
keptEdited: []
|
|
2347
|
+
};
|
|
2348
|
+
}
|
|
2349
|
+
const body = withoutAgentsBlock(existing);
|
|
2350
|
+
return stripLegacyAgentsMd(body, names, headings);
|
|
1808
2351
|
}
|
|
1809
|
-
const names = sectionNames(template);
|
|
1810
2352
|
const context = installerLines(sectionBody(existing, names, CONTEXT_SECTION), SKILLS_BLOCK);
|
|
1811
2353
|
const rules = installerLines(sectionBody(existing, names, RULES_SECTION), ANCHOR_BLOCK);
|
|
1812
2354
|
const contextFilled = !isUnfilledScaffold(context);
|
|
1813
2355
|
const rulesFilled = compact(rules).length > 0;
|
|
1814
|
-
const extras = installerSectionsInHarnessArea(
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
2356
|
+
const extras = installerSectionsInHarnessArea(existing, names, headings);
|
|
2357
|
+
const legacy = {
|
|
2358
|
+
legacyRemoved: extras.legacy > 0,
|
|
2359
|
+
legacySections: extras.legacy,
|
|
2360
|
+
keptEdited: []
|
|
2361
|
+
};
|
|
2362
|
+
if (!contextFilled && !rulesFilled && extras.sections.length === 0) {
|
|
2363
|
+
return { remainder: null, ...legacy };
|
|
2364
|
+
}
|
|
1820
2365
|
const out = [];
|
|
1821
2366
|
const title = (lines2[0] ?? "").replace(/\r$/, "");
|
|
1822
2367
|
if (/^# /.test(title)) out.push(title, "");
|
|
@@ -1824,8 +2369,26 @@ function stripHarnessFromAgentsMd(params) {
|
|
|
1824
2369
|
out.push(`## ${CONTEXT_SECTION}`, "", ...trimBlankEdges(context), "");
|
|
1825
2370
|
}
|
|
1826
2371
|
if (rulesFilled) out.push(`## ${RULES_SECTION}`, "", ...trimBlankEdges(rules), "");
|
|
1827
|
-
for (const section of extras) out.push(...section, "");
|
|
1828
|
-
return out.join("\n");
|
|
2372
|
+
for (const section of extras.sections) out.push(...section, "");
|
|
2373
|
+
return { remainder: out.join("\n"), ...legacy };
|
|
2374
|
+
}
|
|
2375
|
+
function stripLegacyAgentsMd(existing, names, headings) {
|
|
2376
|
+
const contextBody = sectionBody(existing, names, CONTEXT_SECTION);
|
|
2377
|
+
const context = dropHarnessQuoteBlocks(contextBody ?? []);
|
|
2378
|
+
const contextFilled = contextBody !== null && !isUnfilledScaffold(context);
|
|
2379
|
+
const extras = installerSectionsInHarnessArea(existing, names, headings, true);
|
|
2380
|
+
const result = {
|
|
2381
|
+
legacyRemoved: true,
|
|
2382
|
+
legacySections: extras.legacy,
|
|
2383
|
+
keptEdited: extras.keptEdited
|
|
2384
|
+
};
|
|
2385
|
+
if (!contextFilled && extras.sections.length === 0) return { remainder: null, ...result };
|
|
2386
|
+
const out = [];
|
|
2387
|
+
const title = (existing.split("\n")[0] ?? "").replace(/\r$/, "");
|
|
2388
|
+
if (/^# /.test(title)) out.push(title, "");
|
|
2389
|
+
if (contextFilled) out.push(`## ${CONTEXT_SECTION}`, "", ...trimBlankEdges(context), "");
|
|
2390
|
+
for (const section of extras.sections) out.push(...section, "");
|
|
2391
|
+
return { remainder: out.join("\n"), ...result };
|
|
1829
2392
|
}
|
|
1830
2393
|
|
|
1831
2394
|
// src/adapters/marker-md.ts
|
|
@@ -1915,6 +2478,7 @@ var markerMd = {
|
|
|
1915
2478
|
text,
|
|
1916
2479
|
changed: text !== existing,
|
|
1917
2480
|
removed: plan.remove,
|
|
2481
|
+
removedEdited: plan.removedEdited,
|
|
1918
2482
|
kept: plan.kept,
|
|
1919
2483
|
portions: plan.portions,
|
|
1920
2484
|
empty: text.trim() === ""
|
|
@@ -2951,6 +3515,7 @@ var tomlRegion = {
|
|
|
2951
3515
|
text,
|
|
2952
3516
|
changed: text !== existing,
|
|
2953
3517
|
removed: plan.remove,
|
|
3518
|
+
removedEdited: plan.removedEdited,
|
|
2954
3519
|
kept: plan.kept,
|
|
2955
3520
|
portions: plan.portions,
|
|
2956
3521
|
empty: text.trim() === ""
|
|
@@ -3283,7 +3848,7 @@ function harnessWrite(input) {
|
|
|
3283
3848
|
const update = input.run === "update";
|
|
3284
3849
|
if (input.excluded) return j("leave", "", "keep");
|
|
3285
3850
|
if (disk === null) {
|
|
3286
|
-
if (rec.state
|
|
3851
|
+
if (rec.state !== "sha") return j("create", update ? LINES.newInRelease : LINES.wrote, "sha");
|
|
3287
3852
|
return j("create", update ? LINES.restored : LINES.wrote, "sha");
|
|
3288
3853
|
}
|
|
3289
3854
|
if (rec.state === "none") {
|
|
@@ -3402,7 +3967,7 @@ function parseRemote(raw) {
|
|
|
3402
3967
|
return { type: "http", url, auth: { bearerEnv } };
|
|
3403
3968
|
}
|
|
3404
3969
|
function parseTrackMcpMap(raw) {
|
|
3405
|
-
const
|
|
3970
|
+
const rows2 = [];
|
|
3406
3971
|
for (const line of raw.split(/\r?\n/)) {
|
|
3407
3972
|
const trimmed = line.trim();
|
|
3408
3973
|
if (!trimmed || trimmed.startsWith("#")) {
|
|
@@ -3418,7 +3983,7 @@ function parseTrackMcpMap(raw) {
|
|
|
3418
3983
|
}
|
|
3419
3984
|
if (command === "url") {
|
|
3420
3985
|
const server = parseRemote(argsJson ?? "");
|
|
3421
|
-
if (server !== null)
|
|
3986
|
+
if (server !== null) rows2.push({ name, pattern, server });
|
|
3422
3987
|
continue;
|
|
3423
3988
|
}
|
|
3424
3989
|
let args;
|
|
@@ -3430,9 +3995,9 @@ function parseTrackMcpMap(raw) {
|
|
|
3430
3995
|
if (!Array.isArray(args) || !args.every((a) => typeof a === "string")) {
|
|
3431
3996
|
continue;
|
|
3432
3997
|
}
|
|
3433
|
-
|
|
3998
|
+
rows2.push({ name, pattern, server: { type: "stdio", command, args } });
|
|
3434
3999
|
}
|
|
3435
|
-
return
|
|
4000
|
+
return rows2;
|
|
3436
4001
|
}
|
|
3437
4002
|
function toClaudeServer(cfg) {
|
|
3438
4003
|
if (cfg.type === "http") {
|
|
@@ -3450,12 +4015,12 @@ function toClaudeServer(cfg) {
|
|
|
3450
4015
|
if (cfg.env && Object.keys(cfg.env).length > 0) out.env = { ...cfg.env };
|
|
3451
4016
|
return out;
|
|
3452
4017
|
}
|
|
3453
|
-
function mergeMcpServers(base,
|
|
4018
|
+
function mergeMcpServers(base, rows2, tracks, chosen = [], dropped = []) {
|
|
3454
4019
|
const out = {
|
|
3455
4020
|
...base,
|
|
3456
4021
|
mcpServers: { ...base.mcpServers }
|
|
3457
4022
|
};
|
|
3458
|
-
for (const row of
|
|
4023
|
+
for (const row of rows2) {
|
|
3459
4024
|
if (dropped.includes(row.name)) {
|
|
3460
4025
|
continue;
|
|
3461
4026
|
}
|
|
@@ -3473,27 +4038,27 @@ function mergeMcpServers(base, rows, tracks, chosen = [], dropped = []) {
|
|
|
3473
4038
|
function composeMcpJson(opts) {
|
|
3474
4039
|
const base = JSON.parse(readFileSync3(opts.templateMcpPath, "utf8"));
|
|
3475
4040
|
const mapRaw = existsSync4(opts.trackMapPath) ? readFileSync3(opts.trackMapPath, "utf8") : "";
|
|
3476
|
-
const
|
|
3477
|
-
return mergeMcpServers(base,
|
|
4041
|
+
const rows2 = parseTrackMcpMap(mapRaw);
|
|
4042
|
+
return mergeMcpServers(base, rows2, opts.tracks, opts.chosen(rows2), opts.dropped?.(rows2) ?? []);
|
|
3478
4043
|
}
|
|
3479
|
-
function selectableMcpServers(
|
|
3480
|
-
const names = new Set(
|
|
4044
|
+
function selectableMcpServers(rows2) {
|
|
4045
|
+
const names = new Set(rows2.map((r) => r.name));
|
|
3481
4046
|
const out = /* @__PURE__ */ new Map();
|
|
3482
4047
|
for (const a of EXTERNAL_ASSETS) {
|
|
3483
4048
|
if (a.method.kind === "internal" && names.has(a.method.key)) out.set(a.method.key, a.id);
|
|
3484
4049
|
}
|
|
3485
4050
|
return out;
|
|
3486
4051
|
}
|
|
3487
|
-
function selectedMcpServers(
|
|
4052
|
+
function selectedMcpServers(rows2, choice) {
|
|
3488
4053
|
const recorded2 = new Set(
|
|
3489
4054
|
(choice.previousLog?.portions ?? []).filter((p2) => p2.path === ".mcp.json").map((p2) => p2.key)
|
|
3490
4055
|
);
|
|
3491
4056
|
const legacy = new Set(
|
|
3492
|
-
choice.projectDir === void 0 ? [] : legacyMcpServers(choice.projectDir, choice.previousLog,
|
|
4057
|
+
choice.projectDir === void 0 ? [] : legacyMcpServers(choice.projectDir, choice.previousLog, rows2)
|
|
3493
4058
|
);
|
|
3494
|
-
const dropped = new Set(droppedMcpServers(
|
|
4059
|
+
const dropped = new Set(droppedMcpServers(rows2, choice.excluded));
|
|
3495
4060
|
const out = [];
|
|
3496
|
-
for (const [name, assetId] of selectableMcpServers(
|
|
4061
|
+
for (const [name, assetId] of selectableMcpServers(rows2)) {
|
|
3497
4062
|
if (dropped.has(name)) continue;
|
|
3498
4063
|
const key = `mcpServers.${name}`;
|
|
3499
4064
|
if (isAssetSelected(assetId, choice.spec) || recorded2.has(key) || legacy.has(name)) {
|
|
@@ -3502,7 +4067,7 @@ function selectedMcpServers(rows, choice) {
|
|
|
3502
4067
|
}
|
|
3503
4068
|
return out;
|
|
3504
4069
|
}
|
|
3505
|
-
function legacyMcpServers(projectDir, previousLog,
|
|
4070
|
+
function legacyMcpServers(projectDir, previousLog, rows2) {
|
|
3506
4071
|
if (previousLog === null || previousLog.records === "writer") return [];
|
|
3507
4072
|
if ((previousLog.portions ?? []).some((p2) => p2.path === ".mcp.json")) return [];
|
|
3508
4073
|
const created = (previousLog.rootFiles ?? []).some(
|
|
@@ -3512,10 +4077,10 @@ function legacyMcpServers(projectDir, previousLog, rows) {
|
|
|
3512
4077
|
const servers = readMcpServers(join5(projectDir, ".mcp.json"));
|
|
3513
4078
|
if (servers === null) return [];
|
|
3514
4079
|
const out = [];
|
|
3515
|
-
for (const name of selectableMcpServers(
|
|
4080
|
+
for (const name of selectableMcpServers(rows2).keys()) {
|
|
3516
4081
|
if (!Object.hasOwn(servers, name)) continue;
|
|
3517
4082
|
const disk = jsonSha(servers[name]);
|
|
3518
|
-
const row =
|
|
4083
|
+
const row = rows2.find((r) => r.name === name);
|
|
3519
4084
|
const known = [...row ? [row.server] : [], ...priorMcpValues(name)];
|
|
3520
4085
|
if (known.some((v2) => jsonSha(toClaudeServer(v2)) === disk)) out.push(name);
|
|
3521
4086
|
}
|
|
@@ -3533,8 +4098,8 @@ function readMcpServers(path) {
|
|
|
3533
4098
|
return null;
|
|
3534
4099
|
}
|
|
3535
4100
|
}
|
|
3536
|
-
function droppedMcpServers(
|
|
3537
|
-
return [...selectableMcpServers(
|
|
4101
|
+
function droppedMcpServers(rows2, excluded) {
|
|
4102
|
+
return [...selectableMcpServers(rows2)].filter(([name, assetId]) => {
|
|
3538
4103
|
const id = keyId(".mcp.json", `mcpServers.${name}`);
|
|
3539
4104
|
return excluded.has(assetId) || id !== null && excluded.has(id);
|
|
3540
4105
|
}).map(([name]) => name);
|
|
@@ -3703,7 +4268,11 @@ function scanFieldOf(log, path) {
|
|
|
3703
4268
|
({ dir, ext }) => path.startsWith(`${CLAUDE_DIR}${dir}/`) && path.endsWith(ext)
|
|
3704
4269
|
);
|
|
3705
4270
|
if (policy === void 0) return "outside";
|
|
3706
|
-
return present2(
|
|
4271
|
+
return present2(
|
|
4272
|
+
(log.policyFiles ?? []).some(
|
|
4273
|
+
(f) => f.path.startsWith(`${policy.dir}/`) && !RETIRED_PATHS.includes(f.path)
|
|
4274
|
+
)
|
|
4275
|
+
);
|
|
3707
4276
|
}
|
|
3708
4277
|
function isExternalOnly(path) {
|
|
3709
4278
|
const owners = ownersOf(path);
|
|
@@ -3739,6 +4308,7 @@ function createInstallWriter(args) {
|
|
|
3739
4308
|
const portionPaths = [];
|
|
3740
4309
|
const backups = [];
|
|
3741
4310
|
const judged = [];
|
|
4311
|
+
const writes = [];
|
|
3742
4312
|
const shared2 = [];
|
|
3743
4313
|
const outside = createOutsideGuard(projectDir);
|
|
3744
4314
|
const rel = (abs) => relative(projectDir, abs).split(sep).join("/");
|
|
@@ -3753,12 +4323,15 @@ function createInstallWriter(args) {
|
|
|
3753
4323
|
if (outside.skip(abs)) return null;
|
|
3754
4324
|
const next = "source" in from ? readFileSync4(from.source, "utf8") : from.content;
|
|
3755
4325
|
const disk = existsSync6(abs) ? readFileSync4(abs, "utf8") : null;
|
|
4326
|
+
const rec = recorded(previousLog, path, opts);
|
|
4327
|
+
const diskSha = rec.state === "no-sha" && disk !== null ? hashContent(disk) : null;
|
|
3756
4328
|
const j4 = judge({
|
|
3757
4329
|
op: "write",
|
|
3758
4330
|
kind: "harness",
|
|
3759
|
-
rec:
|
|
4331
|
+
rec: diskSha !== null && isLegacyHarnessFile(path, diskSha) ? { state: "sha", sha256: diskSha } : rec,
|
|
3760
4332
|
disk,
|
|
3761
|
-
next
|
|
4333
|
+
next,
|
|
4334
|
+
...args.run === void 0 ? {} : { run: args.run }
|
|
3762
4335
|
});
|
|
3763
4336
|
let backupAbs;
|
|
3764
4337
|
const write = () => {
|
|
@@ -3800,13 +4373,11 @@ function createInstallWriter(args) {
|
|
|
3800
4373
|
default:
|
|
3801
4374
|
throw new Error(`install: '${j4.record}' is not a write record (${path})`);
|
|
3802
4375
|
}
|
|
4376
|
+
const line = backup === void 0 ? j4.line : j4.line.replace(BACKUP_PLACEHOLDER, backup);
|
|
4377
|
+
const backupPair = backup === void 0 || backupAbs === void 0 ? {} : { backup, backupAbs };
|
|
4378
|
+
writes.push({ path, verdict: j4.verdict, record: j4.record, line, ...backupPair });
|
|
3803
4379
|
if (j4.line === "" || j4.verdict === "create" || j4.verdict === "overwrite") return null;
|
|
3804
|
-
const out = {
|
|
3805
|
-
path,
|
|
3806
|
-
verdict: j4.verdict,
|
|
3807
|
-
line: backup === void 0 ? j4.line : j4.line.replace(BACKUP_PLACEHOLDER, backup),
|
|
3808
|
-
...backup === void 0 || backupAbs === void 0 ? {} : { backup, backupAbs }
|
|
3809
|
-
};
|
|
4380
|
+
const out = { path, verdict: j4.verdict, line, ...backupPair };
|
|
3810
4381
|
judged.push(out);
|
|
3811
4382
|
return out;
|
|
3812
4383
|
}
|
|
@@ -3867,7 +4438,12 @@ function createInstallWriter(args) {
|
|
|
3867
4438
|
if (disk === null && ![...res.portions.keys()].some((k2) => !isContainerKey(k2))) {
|
|
3868
4439
|
return result("leave", "");
|
|
3869
4440
|
}
|
|
4441
|
+
let backupAbs;
|
|
3870
4442
|
if (res.changed) {
|
|
4443
|
+
if (disk !== null && res.removedEdited.length > 0) {
|
|
4444
|
+
backupAbs = backupFile(abs, now);
|
|
4445
|
+
backups.push(backupAbs);
|
|
4446
|
+
}
|
|
3871
4447
|
mkdirSync(dirname(abs), { recursive: true });
|
|
3872
4448
|
writeFileSync3(abs, res.text);
|
|
3873
4449
|
}
|
|
@@ -3889,7 +4465,7 @@ function createInstallWriter(args) {
|
|
|
3889
4465
|
const ids = (keys) => [...keys].flatMap((k2) => keyId(path, k2) ?? []);
|
|
3890
4466
|
const out = excludedKeys(path, excluded);
|
|
3891
4467
|
const removedOut = res.removed.filter((k2) => out.has(k2));
|
|
3892
|
-
const removedEdited = res.removedEdited
|
|
4468
|
+
const removedEdited = res.removedEdited;
|
|
3893
4469
|
const keptOut = res.kept.filter((k2) => out.has(k2));
|
|
3894
4470
|
const onlyRemoved = disk !== null && res.removed.length > 0 && res.replaced.length === 0 && addedKeys.length === 0 && restoredKeys.size === 0;
|
|
3895
4471
|
const wrote = onlyRemoved ? "removed the harness part" : j4.line;
|
|
@@ -3897,6 +4473,7 @@ function createInstallWriter(args) {
|
|
|
3897
4473
|
const retired = names(res.removed.filter((k2) => !out.has(k2) && !render.has(k2)));
|
|
3898
4474
|
const replaced = names(res.replaced);
|
|
3899
4475
|
return result(j4.verdict, line, {
|
|
4476
|
+
...backupAbs === void 0 ? {} : { backup: rel(backupAbs), backupAbs },
|
|
3900
4477
|
...retired.length > 0 ? { retired } : {},
|
|
3901
4478
|
...replaced.length > 0 ? { replaced } : {},
|
|
3902
4479
|
changed: res.changed,
|
|
@@ -3924,6 +4501,7 @@ function createInstallWriter(args) {
|
|
|
3924
4501
|
portionPaths: [...portionPaths],
|
|
3925
4502
|
backups: [...backups],
|
|
3926
4503
|
judged: [...judged],
|
|
4504
|
+
writes: [...writes],
|
|
3927
4505
|
shared: [...shared2],
|
|
3928
4506
|
outside: outside.list()
|
|
3929
4507
|
})
|
|
@@ -4088,7 +4666,7 @@ function hookScript(handler, claudeDir) {
|
|
|
4088
4666
|
const script = ref.slice("hooks/".length);
|
|
4089
4667
|
return script.includes("/") ? null : script;
|
|
4090
4668
|
}
|
|
4091
|
-
function legacySettingsSeed(text, render, projectDir) {
|
|
4669
|
+
function legacySettingsSeed(text, render, projectDir, opts = {}) {
|
|
4092
4670
|
const seed = /* @__PURE__ */ new Map();
|
|
4093
4671
|
let root;
|
|
4094
4672
|
try {
|
|
@@ -4098,6 +4676,7 @@ function legacySettingsSeed(text, render, projectDir) {
|
|
|
4098
4676
|
}
|
|
4099
4677
|
const claudeDir = join7(projectDir, ".claude");
|
|
4100
4678
|
const candidates = new Set([...render.keys()].filter((k2) => k2.startsWith("hooks.")));
|
|
4679
|
+
const legacyLines = /* @__PURE__ */ new Set();
|
|
4101
4680
|
const hooks = isObject2(root) && isObject2(root.hooks) ? root.hooks : {};
|
|
4102
4681
|
for (const [event, groups] of Object.entries(hooks)) {
|
|
4103
4682
|
if (!Array.isArray(groups)) continue;
|
|
@@ -4105,14 +4684,16 @@ function legacySettingsSeed(text, render, projectDir) {
|
|
|
4105
4684
|
if (!isObject2(group) || !Array.isArray(group.hooks)) continue;
|
|
4106
4685
|
for (const handler of group.hooks) {
|
|
4107
4686
|
const script = hookScript(handler, claudeDir);
|
|
4108
|
-
if (script
|
|
4109
|
-
|
|
4110
|
-
}
|
|
4687
|
+
if (script === null) continue;
|
|
4688
|
+
const key = `hooks.${event}#${script}`;
|
|
4689
|
+
if (RETIRED_PATHS.includes(`hooks/${script}`)) candidates.add(key);
|
|
4690
|
+
if (isObject2(handler) && isLegacyHookLine(handler.command, claudeDir)) legacyLines.add(key);
|
|
4111
4691
|
}
|
|
4112
4692
|
}
|
|
4113
4693
|
}
|
|
4114
4694
|
const present2 = ADAPTERS["json-keys"].read(text, candidates, projectDir) ?? /* @__PURE__ */ new Map();
|
|
4115
4695
|
for (const [key, sha] of present2) {
|
|
4696
|
+
if (!legacyLines.has(key) && opts.edited !== true) continue;
|
|
4116
4697
|
const rendered = render.get(key);
|
|
4117
4698
|
const handler = isObject2(rendered) && Array.isArray(rendered.hooks) ? rendered.hooks[0] : void 0;
|
|
4118
4699
|
seed.set(key, handler === void 0 ? sha : jsonSha(handler));
|
|
@@ -4209,8 +4790,8 @@ function legacyGitignoreSeed(text, render, previous) {
|
|
|
4209
4790
|
|
|
4210
4791
|
// src/installer.ts
|
|
4211
4792
|
init_esm_shims();
|
|
4212
|
-
import { chmodSync as chmodSync3, existsSync as existsSync22, readdirSync as
|
|
4213
|
-
import { basename as basename4, join as
|
|
4793
|
+
import { chmodSync as chmodSync3, existsSync as existsSync22, readdirSync as readdirSync5, readFileSync as readFileSync22, writeFileSync as writeFileSync8 } from "fs";
|
|
4794
|
+
import { basename as basename4, join as join31, relative as relative5, resolve, sep as sep6 } from "path";
|
|
4214
4795
|
|
|
4215
4796
|
// src/anchor-seed.ts
|
|
4216
4797
|
init_esm_shims();
|
|
@@ -4489,37 +5070,34 @@ function createOwnedWriter(projectDir, baseline, options = {}) {
|
|
|
4489
5070
|
return false;
|
|
4490
5071
|
}
|
|
4491
5072
|
if (outside.skip(absPath)) return false;
|
|
4492
|
-
const
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
5073
|
+
const recordedSha = baseline.get(rel);
|
|
5074
|
+
const rec = recordedSha !== void 0 ? { state: "sha", sha256: recordedSha } : { state: owned(rel) ? "no-sha" : "none" };
|
|
5075
|
+
const disk = existsSync9(absPath) ? readFileSync6(absPath, "utf8") : null;
|
|
5076
|
+
if (disk === null && refreshOnly && !opts?.createInRefresh && rec.state !== "sha")
|
|
5077
|
+
return false;
|
|
5078
|
+
const { verdict, record } = judge({ op: "write", kind: "harness", rec, disk, next: content });
|
|
5079
|
+
let backupRel = null;
|
|
5080
|
+
if (verdict === "backup+overwrite" || verdict === "overwrite" && opts?.backupFirst === true) {
|
|
5081
|
+
const backup = backupFile(absPath, now);
|
|
5082
|
+
backupPaths.push(backup);
|
|
5083
|
+
journal?.backup(backup);
|
|
5084
|
+
backupRel = relative2(projectDir, backup).split(sep3).join("/");
|
|
5085
|
+
if (verdict === "backup+overwrite" && rec.state !== "none") backedUp.push(rel);
|
|
5086
|
+
}
|
|
5087
|
+
if (record === "displaced" || record === "displaced+sha") {
|
|
5088
|
+
displace({ path: rel, change: "displaced", notes: backupRel === null ? [] : [backupRel] });
|
|
5089
|
+
}
|
|
5090
|
+
if (verdict !== "leave") {
|
|
4496
5091
|
mkdirSync2(dirname2(absPath), { recursive: true });
|
|
4497
5092
|
writeFileSync4(absPath, content);
|
|
4498
5093
|
updated++;
|
|
4499
|
-
if (refreshOnly &&
|
|
4500
|
-
}
|
|
4501
|
-
|
|
4502
|
-
const
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
return true;
|
|
4506
|
-
}
|
|
4507
|
-
if (current !== content) {
|
|
4508
|
-
if (!isHarnessOwned(baseline, rel, current)) {
|
|
4509
|
-
const backup = backupFile(absPath, now);
|
|
4510
|
-
backupPaths.push(backup);
|
|
4511
|
-
journal?.backup(backup);
|
|
4512
|
-
if (firstContact) {
|
|
4513
|
-
const backupRel = relative2(projectDir, backup).split(sep3).join("/");
|
|
4514
|
-
displace({ path: rel, change: "displaced", notes: [backupRel] });
|
|
4515
|
-
} else backedUp.push(rel);
|
|
4516
|
-
}
|
|
4517
|
-
writeFileSync4(absPath, content);
|
|
4518
|
-
updated++;
|
|
4519
|
-
}
|
|
5094
|
+
if (refreshOnly && verdict === "create" && rec.state === "sha") restored.push(rel);
|
|
5095
|
+
}
|
|
5096
|
+
if (record === "sha" || record === "displaced+sha") {
|
|
5097
|
+
const digest = hashContent(content);
|
|
5098
|
+
written.set(rel, digest);
|
|
5099
|
+
journal?.file({ path: rel, sha256: digest });
|
|
4520
5100
|
}
|
|
4521
|
-
written.set(rel, digest);
|
|
4522
|
-
journal?.file({ path: rel, sha256: digest });
|
|
4523
5101
|
return true;
|
|
4524
5102
|
},
|
|
4525
5103
|
...journal === void 0 ? {} : { journal },
|
|
@@ -4594,7 +5172,7 @@ function renderRulesBlock(rules) {
|
|
|
4594
5172
|
// src/shared-write.ts
|
|
4595
5173
|
init_esm_shims();
|
|
4596
5174
|
import { existsSync as existsSync11, mkdirSync as mkdirSync3, readFileSync as readFileSync8, rmSync, statSync as statSync3, writeFileSync as writeFileSync5 } from "fs";
|
|
4597
|
-
import { dirname as dirname3, join as join13 } from "path";
|
|
5175
|
+
import { dirname as dirname3, join as join13, relative as relative3, sep as sep4 } from "path";
|
|
4598
5176
|
function toPortions(path, portions) {
|
|
4599
5177
|
const adapter = adapterFor(path);
|
|
4600
5178
|
if (adapter === null) throw new Error(`shared-write: ${path} is not a shared file`);
|
|
@@ -4723,28 +5301,43 @@ function hasMarkerLine(disk, markers) {
|
|
|
4723
5301
|
}
|
|
4724
5302
|
function agentsMdModel(disk, recordedByHarness, recordedBlock = false) {
|
|
4725
5303
|
if (disk === null) return recordedBlock && !recordedByHarness ? "block" : "sections";
|
|
4726
|
-
|
|
5304
|
+
const legacy = isLegacyHarnessAgentsMd(disk);
|
|
5305
|
+
if (hasMarkerLine(disk, [AGENTS_BLOCK.start, AGENTS_BLOCK.end]) && !legacy) return "block";
|
|
4727
5306
|
if (recordedByHarness) return "sections";
|
|
4728
5307
|
if (hasMarkerLine(disk, [ANCHOR_BLOCK.start, SKILLS_BLOCK.start])) return "sections";
|
|
5308
|
+
if (legacy) return "sections";
|
|
4729
5309
|
return "block";
|
|
4730
5310
|
}
|
|
4731
5311
|
function writeAgentsMd(params) {
|
|
4732
5312
|
const abs = join13(params.projectDir, AGENTS_MD);
|
|
4733
5313
|
const disk = existsSync11(abs) ? readFileSync8(abs, "utf8") : null;
|
|
4734
5314
|
const recordedBlock = (params.record.portions ?? []).some((p2) => p2.path === AGENTS_MD);
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
}
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
5315
|
+
const recordedByHarness = params.baseline.has(AGENTS_MD);
|
|
5316
|
+
if (agentsMdModel(disk, recordedByHarness, recordedBlock) === "sections") {
|
|
5317
|
+
const legacyUnrecorded = disk !== null && !recordedByHarness && isLegacyHarnessAgentsMd(disk);
|
|
5318
|
+
const merged = mergeAgentsMdDetailed({
|
|
5319
|
+
rendered: params.rendered,
|
|
5320
|
+
// N2 — 첫 접촉 블록은 떼고 병합한다(블록 안은 지금 렌더가 다시 쓴다)
|
|
5321
|
+
existing: disk === null ? null : withoutAgentsBlock(disk),
|
|
5322
|
+
template: params.template,
|
|
5323
|
+
...params.replaceUnfilledContext === true || legacyUnrecorded ? { replaceUnfilledContext: true } : {},
|
|
5324
|
+
...params.harnessRuleHeadings === void 0 ? {} : { harnessRuleHeadings: params.harnessRuleHeadings }
|
|
5325
|
+
});
|
|
5326
|
+
const dropped = merged.droppedLegacySections;
|
|
5327
|
+
const edited = merged.editedLegacySections;
|
|
5328
|
+
params.writer.write(abs, merged.text, {
|
|
5329
|
+
...params.createInRefresh === true ? { createInRefresh: true } : {},
|
|
5330
|
+
// ADR-111 — 떨어뜨린 절은 현행 번들에 없는 바이트다 · 고친 이름 절은 설치자 글이다: 기준선 그대로인 파일이라도 1회 백업
|
|
5331
|
+
...dropped > 0 || edited.length > 0 ? { backupFirst: true } : {}
|
|
5332
|
+
});
|
|
5333
|
+
if (recordedBlock) params.writer.journal?.portions(AGENTS_MD, []);
|
|
5334
|
+
return {
|
|
5335
|
+
model: "sections",
|
|
5336
|
+
shared: null,
|
|
5337
|
+
...dropped > 0 ? { droppedLegacySections: dropped } : {},
|
|
5338
|
+
...edited.length > 0 ? { editedLegacySections: edited } : {},
|
|
5339
|
+
...recordedBlock ? { blockRecordDropped: true } : {}
|
|
5340
|
+
};
|
|
4748
5341
|
}
|
|
4749
5342
|
const shared2 = writeShared({
|
|
4750
5343
|
projectDir: params.projectDir,
|
|
@@ -4817,6 +5410,10 @@ function stripShared(params) {
|
|
|
4817
5410
|
});
|
|
4818
5411
|
}
|
|
4819
5412
|
const fileRemoved = params.removeIfEmpty === true && res.removed.length > 0 && res.empty;
|
|
5413
|
+
const edited = res.removedEdited.length === 0 ? void 0 : {
|
|
5414
|
+
keys: res.removedEdited,
|
|
5415
|
+
backup: params.write ? relative3(projectDir, backupFile(abs)).split(sep4).join("/") : `${path}.backup-<time>`
|
|
5416
|
+
};
|
|
4820
5417
|
if (params.write && fileRemoved) rmSync(abs);
|
|
4821
5418
|
else if (params.write && res.changed) writeFileSync5(abs, res.text);
|
|
4822
5419
|
const action = res.removed.length > 0 ? "removed" : res.kept.length > 0 ? "left" : "none";
|
|
@@ -4824,6 +5421,7 @@ function stripShared(params) {
|
|
|
4824
5421
|
removed: res.removed,
|
|
4825
5422
|
kept: res.kept,
|
|
4826
5423
|
portions: toPortions(path, res.portions),
|
|
5424
|
+
...edited === void 0 ? {} : { edited },
|
|
4827
5425
|
...fileRemoved ? { fileRemoved } : {}
|
|
4828
5426
|
});
|
|
4829
5427
|
}
|
|
@@ -4834,10 +5432,15 @@ function runAgentsMdTransform(params) {
|
|
|
4834
5432
|
const { harnessRoot, projectDir, baseline, shared: shared2 = {} } = params;
|
|
4835
5433
|
const refreshOnly = params.refreshOnly === true;
|
|
4836
5434
|
const clis = agentsMdClis(params.clis);
|
|
5435
|
+
const agentsMdPath = join14(projectDir, "AGENTS.md");
|
|
5436
|
+
const exists2 = existsSync12(agentsMdPath);
|
|
5437
|
+
const diskBefore = exists2 ? readFileSync9(agentsMdPath, "utf8") : null;
|
|
5438
|
+
const legacyAgentsMd = diskBefore !== null && isLegacyHarnessAgentsMd(diskBefore);
|
|
5439
|
+
const owned = (rel) => params.owned?.(rel) === true || rel === "AGENTS.md" && legacyAgentsMd;
|
|
4837
5440
|
const writer = createOwnedWriter(projectDir, baseline, {
|
|
4838
5441
|
refreshOnly,
|
|
4839
5442
|
...params.journal === void 0 ? {} : { journal: params.journal },
|
|
4840
|
-
|
|
5443
|
+
owned
|
|
4841
5444
|
});
|
|
4842
5445
|
const claudeMd = readRequired(join14(harnessRoot, "templates/CLAUDE.md"));
|
|
4843
5446
|
const template = readRequired(join14(harnessRoot, AGENTS_MD_TEMPLATE));
|
|
@@ -4847,9 +5450,7 @@ function runAgentsMdTransform(params) {
|
|
|
4847
5450
|
refreshOnly,
|
|
4848
5451
|
writer
|
|
4849
5452
|
});
|
|
4850
|
-
const
|
|
4851
|
-
const exists = existsSync12(agentsMdPath);
|
|
4852
|
-
const creates = !exists && (!refreshOnly || params.installedByRecord === true);
|
|
5453
|
+
const creates = !exists2 && (!refreshOnly || params.installedByRecord === true);
|
|
4853
5454
|
const legacy = params.legacyContext ?? null;
|
|
4854
5455
|
const fromRoot = creates ? seedAgentsMdProjectContext(projectDir) : null;
|
|
4855
5456
|
const seed = fromRoot ?? legacy;
|
|
@@ -4867,7 +5468,6 @@ function runAgentsMdTransform(params) {
|
|
|
4867
5468
|
harnessRules: renderRulesBlock(portRules(harnessRoot, params.rules)),
|
|
4868
5469
|
clis
|
|
4869
5470
|
});
|
|
4870
|
-
const diskBefore = exists ? readFileSync9(agentsMdPath, "utf8") : null;
|
|
4871
5471
|
const agentsMd = writeAgentsMd({
|
|
4872
5472
|
projectDir,
|
|
4873
5473
|
rendered,
|
|
@@ -5564,14 +6164,14 @@ function renderHarnessMcp(harnessRoot, choice) {
|
|
|
5564
6164
|
return composeMcpJson({
|
|
5565
6165
|
...mcpSources(harnessRoot),
|
|
5566
6166
|
tracks: choice.spec.tracks,
|
|
5567
|
-
chosen: (
|
|
5568
|
-
dropped: (
|
|
6167
|
+
chosen: (rows2) => selectedMcpServers(rows2, choice),
|
|
6168
|
+
dropped: (rows2) => droppedMcpServers(rows2, choice.excluded)
|
|
5569
6169
|
});
|
|
5570
6170
|
}
|
|
5571
6171
|
function trackDefaultMcpAssetIds(harnessRoot, tracks) {
|
|
5572
|
-
const
|
|
5573
|
-
const selectable = selectableMcpServers(
|
|
5574
|
-
return
|
|
6172
|
+
const rows2 = trackRows(harnessRoot);
|
|
6173
|
+
const selectable = selectableMcpServers(rows2);
|
|
6174
|
+
return rows2.flatMap((r) => {
|
|
5575
6175
|
const id = selectable.get(r.name);
|
|
5576
6176
|
return id !== void 0 && anyTrack(tracks, r.pattern) ? [id] : [];
|
|
5577
6177
|
});
|
|
@@ -5592,13 +6192,13 @@ function renderEverySelectableMcp(harnessRoot, tracks) {
|
|
|
5592
6192
|
return composeMcpJson({
|
|
5593
6193
|
...mcpSources(harnessRoot),
|
|
5594
6194
|
tracks,
|
|
5595
|
-
chosen: (
|
|
6195
|
+
chosen: (rows2) => [...selectableMcpServers(rows2).keys()]
|
|
5596
6196
|
});
|
|
5597
6197
|
}
|
|
5598
6198
|
function adapterExcluded(harnessRoot, excluded) {
|
|
5599
|
-
const
|
|
6199
|
+
const rows2 = trackRows(harnessRoot);
|
|
5600
6200
|
const out = new Set(excluded);
|
|
5601
|
-
for (const [name, assetId] of selectableMcpServers(
|
|
6201
|
+
for (const [name, assetId] of selectableMcpServers(rows2)) {
|
|
5602
6202
|
const id = keyId(".mcp.json", `mcpServers.${name}`);
|
|
5603
6203
|
if (excluded.has(assetId) && id !== null) out.add(id);
|
|
5604
6204
|
}
|
|
@@ -5770,15 +6370,62 @@ function runCliTransforms(params) {
|
|
|
5770
6370
|
externalOutside,
|
|
5771
6371
|
sharedFiles,
|
|
5772
6372
|
portions: sharedFiles.flatMap((r) => r.portions ?? []),
|
|
5773
|
-
|
|
6373
|
+
// #774 (N2) — 블록 모델이던 `AGENTS.md` 를 절 모델로 바꿨으면 그 파일의 몫 기록을 비운다(판정한 경로 · 몫 없음)
|
|
6374
|
+
portionPaths: [
|
|
6375
|
+
...sharedFiles.filter((r) => r.portions !== null).map((r) => r.path),
|
|
6376
|
+
...agentsMd?.agentsMd.blockRecordDropped === true ? ["AGENTS.md"] : []
|
|
6377
|
+
],
|
|
5774
6378
|
restoredFiles
|
|
5775
6379
|
};
|
|
5776
6380
|
}
|
|
5777
6381
|
|
|
6382
|
+
// src/displaced.ts
|
|
6383
|
+
init_esm_shims();
|
|
6384
|
+
import { lstatSync as lstatSync3, mkdirSync as mkdirSync5, renameSync } from "fs";
|
|
6385
|
+
import { dirname as dirname5, join as join23 } from "path";
|
|
6386
|
+
function exists(abs) {
|
|
6387
|
+
try {
|
|
6388
|
+
lstatSync3(abs);
|
|
6389
|
+
return true;
|
|
6390
|
+
} catch {
|
|
6391
|
+
return false;
|
|
6392
|
+
}
|
|
6393
|
+
}
|
|
6394
|
+
function restoreDisplaced(log, projectDir, opts) {
|
|
6395
|
+
const out = [];
|
|
6396
|
+
for (const f of log.rootFiles ?? []) {
|
|
6397
|
+
if (f.change !== "displaced" || !opts.has(f.path)) continue;
|
|
6398
|
+
const slot = join23(projectDir, f.path);
|
|
6399
|
+
if (outsideProjectTarget(projectDir, slot) !== null) continue;
|
|
6400
|
+
const backup = f.notes[0] ?? null;
|
|
6401
|
+
const d2 = judgeDisplaced({
|
|
6402
|
+
backup,
|
|
6403
|
+
backupExists: backup !== null && exists(join23(projectDir, backup)),
|
|
6404
|
+
slotEmpty: !exists(slot) || !opts.write && opts.willBeGone?.has(f.path) === true
|
|
6405
|
+
});
|
|
6406
|
+
if (opts.write && d2.verdict === "restore" && backup !== null) {
|
|
6407
|
+
mkdirSync5(dirname5(slot), { recursive: true });
|
|
6408
|
+
renameSync(join23(projectDir, backup), slot);
|
|
6409
|
+
}
|
|
6410
|
+
out.push({
|
|
6411
|
+
path: f.path,
|
|
6412
|
+
backup,
|
|
6413
|
+
verdict: d2.verdict,
|
|
6414
|
+
line: d2.line,
|
|
6415
|
+
forget: d2.record === "forget"
|
|
6416
|
+
});
|
|
6417
|
+
}
|
|
6418
|
+
return out;
|
|
6419
|
+
}
|
|
6420
|
+
function withoutRestored(rootFiles, outcomes) {
|
|
6421
|
+
const settled = new Set(outcomes.filter((d2) => d2.forget).map((d2) => d2.path));
|
|
6422
|
+
return (rootFiles ?? []).filter((f) => !(f.change === "displaced" && settled.has(f.path)));
|
|
6423
|
+
}
|
|
6424
|
+
|
|
5778
6425
|
// src/excluded-still-there.ts
|
|
5779
6426
|
init_esm_shims();
|
|
5780
6427
|
import { existsSync as existsSync18 } from "fs";
|
|
5781
|
-
import { join as
|
|
6428
|
+
import { join as join24 } from "path";
|
|
5782
6429
|
function excludedStillThere(projectDir, excluded, baselineOnDisk, previousLog) {
|
|
5783
6430
|
const out = [];
|
|
5784
6431
|
const add = (id, catalog) => {
|
|
@@ -5791,7 +6438,7 @@ function excludedStillThere(projectDir, excluded, baselineOnDisk, previousLog) {
|
|
|
5791
6438
|
for (const id of excluded) {
|
|
5792
6439
|
if (INTERNAL_BUNDLED_SKILL_IDS.includes(id)) {
|
|
5793
6440
|
const there = [".claude/skills", ".agents/skills"].some(
|
|
5794
|
-
(d2) => existsSync18(
|
|
6441
|
+
(d2) => existsSync18(join24(projectDir, d2, id))
|
|
5795
6442
|
);
|
|
5796
6443
|
if (there) add(id, false);
|
|
5797
6444
|
} else {
|
|
@@ -5805,17 +6452,27 @@ function excludedStillThere(projectDir, excluded, baselineOnDisk, previousLog) {
|
|
|
5805
6452
|
function assetStillThere(projectDir, asset) {
|
|
5806
6453
|
if (asset.method !== "skill" || asset.scope === "global") return true;
|
|
5807
6454
|
if (asset.files !== void 0)
|
|
5808
|
-
return asset.files.some((f) => existsSync18(
|
|
6455
|
+
return asset.files.some((f) => existsSync18(join24(projectDir, f.path)));
|
|
5809
6456
|
const dir = asset.detail.skill ?? asset.id;
|
|
5810
|
-
return [".claude/skills", ".agents/skills"].some((d2) => existsSync18(
|
|
6457
|
+
return [".claude/skills", ".agents/skills"].some((d2) => existsSync18(join24(projectDir, d2, dir)));
|
|
5811
6458
|
}
|
|
5812
6459
|
|
|
5813
6460
|
// src/external-installer.ts
|
|
5814
6461
|
init_esm_shims();
|
|
5815
6462
|
import { spawnSync } from "child_process";
|
|
5816
|
-
import {
|
|
6463
|
+
import {
|
|
6464
|
+
accessSync,
|
|
6465
|
+
existsSync as existsSync19,
|
|
6466
|
+
constants as fsConstants,
|
|
6467
|
+
mkdirSync as mkdirSync6,
|
|
6468
|
+
readdirSync as readdirSync3,
|
|
6469
|
+
readFileSync as readFileSync17,
|
|
6470
|
+
renameSync as renameSync2,
|
|
6471
|
+
rmdirSync,
|
|
6472
|
+
rmSync as rmSync3
|
|
6473
|
+
} from "fs";
|
|
5817
6474
|
import { homedir as homedir2 } from "os";
|
|
5818
|
-
import { dirname as
|
|
6475
|
+
import { dirname as dirname6, join as join25, relative as relative4, sep as sep5 } from "path";
|
|
5819
6476
|
var SKILL_ROOTS = [".claude/skills", ".agents/skills"];
|
|
5820
6477
|
function skillRootOf(cli) {
|
|
5821
6478
|
return cli === "claude" ? ".claude/skills" : ".agents/skills";
|
|
@@ -5823,11 +6480,11 @@ function skillRootOf(cli) {
|
|
|
5823
6480
|
function snapshotSkillRoots(projectDir) {
|
|
5824
6481
|
const out = /* @__PURE__ */ new Map();
|
|
5825
6482
|
for (const root of SKILL_ROOTS) {
|
|
5826
|
-
if (outsideProjectTarget(projectDir,
|
|
5827
|
-
for (const rel of listFilesRecursive(
|
|
6483
|
+
if (outsideProjectTarget(projectDir, join25(projectDir, root)) !== null) continue;
|
|
6484
|
+
for (const rel of listFilesRecursive(join25(projectDir, root))) {
|
|
5828
6485
|
const path = `${root}/${rel}`;
|
|
5829
6486
|
try {
|
|
5830
|
-
out.set(path, hashContent(readFileSync17(
|
|
6487
|
+
out.set(path, hashContent(readFileSync17(join25(projectDir, path), "utf8")));
|
|
5831
6488
|
} catch {
|
|
5832
6489
|
}
|
|
5833
6490
|
}
|
|
@@ -5904,7 +6561,7 @@ function installOne(asset, ctx) {
|
|
|
5904
6561
|
return runSpawn(asset, ctx.spawn, "npx", buildSkillArgs(method, ctx.cli, ctx.scope), cwd);
|
|
5905
6562
|
}
|
|
5906
6563
|
const outside = SKILL_ROOTS.flatMap((root) => {
|
|
5907
|
-
const hit = outsideProjectTarget(cwd,
|
|
6564
|
+
const hit = outsideProjectTarget(cwd, join25(cwd, root));
|
|
5908
6565
|
return hit === null ? [] : [{ root, target: hit.target }];
|
|
5909
6566
|
});
|
|
5910
6567
|
const outRoots = new Set(outside.map((o) => o.root));
|
|
@@ -5982,32 +6639,46 @@ function refreshExternalSkills(projectDir, deps = {}) {
|
|
|
5982
6639
|
return { ...none, notInCatalog, unknown: false };
|
|
5983
6640
|
}
|
|
5984
6641
|
const targetIds = new Set(targets.map((a) => a.id));
|
|
5985
|
-
const
|
|
5986
|
-
|
|
5987
|
-
log.assets.filter((a) => targetIds.has(a.id))
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
|
|
5992
|
-
|
|
5993
|
-
|
|
5994
|
-
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
5998
|
-
|
|
5999
|
-
|
|
6000
|
-
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
|
|
6004
|
-
|
|
6005
|
-
|
|
6006
|
-
|
|
6642
|
+
const clis = [...installedClis(log)];
|
|
6643
|
+
const settle = holdSkillSlots(projectDir, {
|
|
6644
|
+
recorded: log.assets.filter((a) => targetIds.has(a.id)),
|
|
6645
|
+
slots: skillSlotsFor(targets, clis, { log, scope: log.scope }),
|
|
6646
|
+
log,
|
|
6647
|
+
clis,
|
|
6648
|
+
scope: log.scope
|
|
6649
|
+
});
|
|
6650
|
+
const run = deps.run ?? runExternalInstall;
|
|
6651
|
+
let ran;
|
|
6652
|
+
try {
|
|
6653
|
+
ran = run(
|
|
6654
|
+
{
|
|
6655
|
+
tracks: log.spec.tracks,
|
|
6656
|
+
// `forceInclude` 가 조건 판정을 앞지르므로 옵션 값은 결과에 영향을 주지 않는다.
|
|
6657
|
+
options: DEFAULT_OPTIONS,
|
|
6658
|
+
// #528 — 대상 CLI 는 **깔린 집합**(`installedClis`)이다. `spec.cli` 는 마지막 install 의
|
|
6659
|
+
// 요청이라 `uninstall --cli` 뒤에도 뺀 CLI 를 말하고, 반대로 그걸 비우면 `buildSkillArgs` 가
|
|
6660
|
+
// `--agent`·`--copy` 를 못 붙여 Claude 몫이 조용히 빠진다(재리뷰 BLOCKER-3).
|
|
6661
|
+
cli: clis,
|
|
6662
|
+
userOverride: { forceInclude: [...installedIds], forceExclude: [] },
|
|
6663
|
+
scope: log.scope,
|
|
6664
|
+
projectDir
|
|
6665
|
+
},
|
|
6666
|
+
{
|
|
6667
|
+
assets: targets,
|
|
6668
|
+
...deps.spawn ? { spawn: deps.spawn } : {},
|
|
6669
|
+
...deps.log ? { log: deps.log } : {},
|
|
6670
|
+
...deps.warn ? { warn: deps.warn } : {}
|
|
6671
|
+
}
|
|
6672
|
+
);
|
|
6673
|
+
} catch (e2) {
|
|
6674
|
+
try {
|
|
6675
|
+
settle(null);
|
|
6676
|
+
} catch {
|
|
6007
6677
|
}
|
|
6008
|
-
|
|
6009
|
-
|
|
6010
|
-
|
|
6678
|
+
throw e2;
|
|
6679
|
+
}
|
|
6680
|
+
const { report, displaced } = settle(ran);
|
|
6681
|
+
recordRefreshedFiles(projectDir, log, report, displaced, deps.writeLog ?? writeInstallLog);
|
|
6011
6682
|
return {
|
|
6012
6683
|
attempted: report.attempted.length,
|
|
6013
6684
|
refreshed: report.succeeded,
|
|
@@ -6016,53 +6687,160 @@ function refreshExternalSkills(projectDir, deps = {}) {
|
|
|
6016
6687
|
unknown: false
|
|
6017
6688
|
};
|
|
6018
6689
|
}
|
|
6019
|
-
function holdSkillSlots(projectDir,
|
|
6020
|
-
const
|
|
6021
|
-
|
|
6690
|
+
function holdSkillSlots(projectDir, hold) {
|
|
6691
|
+
const now = /* @__PURE__ */ new Date();
|
|
6692
|
+
const asides = /* @__PURE__ */ new Map();
|
|
6693
|
+
const moved = [];
|
|
6694
|
+
try {
|
|
6695
|
+
for (const f of slotFilesToKeep(projectDir, hold)) {
|
|
6696
|
+
const root = dirname6(f.slot);
|
|
6697
|
+
let dir = asides.get(root);
|
|
6698
|
+
if (dir === void 0) {
|
|
6699
|
+
dir = claimBackupDir(join25(projectDir, root), now);
|
|
6700
|
+
asides.set(root, dir);
|
|
6701
|
+
}
|
|
6702
|
+
const aside = join25(dir, f.rel.slice(root.length + 1));
|
|
6703
|
+
mkdirSync6(dirname6(aside), { recursive: true });
|
|
6704
|
+
renameSync2(f.abs, aside);
|
|
6705
|
+
moved.push({ ...f, aside });
|
|
6706
|
+
}
|
|
6707
|
+
} catch (e2) {
|
|
6708
|
+
for (const f of moved) renameSync2(f.aside, f.abs);
|
|
6709
|
+
for (const dir of asides.values()) pruneEmptyDirs(dir);
|
|
6710
|
+
throw new Error(
|
|
6711
|
+
`could not move your files aside before the skill tool runs \u2014 nothing was changed: ${e2 instanceof Error ? e2.message : String(e2)}`
|
|
6712
|
+
);
|
|
6713
|
+
}
|
|
6714
|
+
return (report) => {
|
|
6715
|
+
const failedSlots = report === null ? null : skillSlotsFor(
|
|
6716
|
+
report.attempted.filter((r) => !r.ok).map((r) => r.asset),
|
|
6717
|
+
hold.clis,
|
|
6718
|
+
{ log: hold.log, scope: hold.scope }
|
|
6719
|
+
);
|
|
6720
|
+
const out = { backups: [], displaced: [] };
|
|
6721
|
+
const back = /* @__PURE__ */ new Set();
|
|
6722
|
+
const failed = [];
|
|
6723
|
+
for (const f of moved) {
|
|
6724
|
+
const restore = failedSlots === null || failedSlots.some((s) => f.rel === s || f.rel.startsWith(`${s}/`));
|
|
6725
|
+
try {
|
|
6726
|
+
const r = settleAside(projectDir, f, restore);
|
|
6727
|
+
if (r === "back") {
|
|
6728
|
+
back.add(f.rel);
|
|
6729
|
+
continue;
|
|
6730
|
+
}
|
|
6731
|
+
out.backups.push(r.backup);
|
|
6732
|
+
if (r.displaced !== null) out.displaced.push(r.displaced);
|
|
6733
|
+
} catch (e2) {
|
|
6734
|
+
failed.push(`${f.rel} (${e2 instanceof Error ? e2.message : String(e2)})`);
|
|
6735
|
+
}
|
|
6736
|
+
}
|
|
6737
|
+
for (const dir of asides.values()) pruneEmptyDirs(dir);
|
|
6738
|
+
if (failed.length > 0) {
|
|
6739
|
+
const at5 = [...asides.values()].map((d2) => `${toProjectRel(projectDir, d2)}/`).join(", ");
|
|
6740
|
+
throw new Error(
|
|
6741
|
+
`could not put back ${failed.length} file(s) moved aside before the skill tool ran \u2014 they stay in ${at5}: ${failed.join(", ")}`
|
|
6742
|
+
);
|
|
6743
|
+
}
|
|
6744
|
+
return { ...out, report: report === null ? null : withoutCreated(report, back) };
|
|
6745
|
+
};
|
|
6022
6746
|
}
|
|
6023
|
-
function
|
|
6024
|
-
if (
|
|
6025
|
-
const
|
|
6026
|
-
const
|
|
6747
|
+
function skillSlotsFor(assets, clis, ctx) {
|
|
6748
|
+
if (resolveScope(ctx.scope) === "global") return [];
|
|
6749
|
+
const roots = clis.length === 0 ? [...SKILL_ROOTS] : [...new Set(clis.map(skillRootOf))];
|
|
6750
|
+
const out = /* @__PURE__ */ new Set();
|
|
6751
|
+
for (const a of assets) {
|
|
6752
|
+
if (a.method.kind !== "skill") continue;
|
|
6753
|
+
const prior = ctx.log?.assets.find((r) => r.id === a.id);
|
|
6754
|
+
if (prior !== void 0 && prior.files === void 0) continue;
|
|
6755
|
+
const skill = a.method.skill;
|
|
6756
|
+
for (const root of roots) out.add(skill === void 0 ? root : `${root}/${skill}`);
|
|
6757
|
+
}
|
|
6758
|
+
return [...out];
|
|
6759
|
+
}
|
|
6760
|
+
function slotFilesToKeep(projectDir, hold) {
|
|
6761
|
+
const mine = hold.recorded.flatMap((a) => a.files ?? []);
|
|
6762
|
+
const sha = new Map(mine.map((f) => [f.path, f.sha256]));
|
|
6763
|
+
const targetIds = new Set(hold.recorded.map((a) => a.id));
|
|
6764
|
+
const others = new Set(
|
|
6765
|
+
(hold.log?.assets ?? []).filter((a) => !targetIds.has(a.id)).flatMap((a) => (a.files ?? []).map((f) => f.path))
|
|
6766
|
+
);
|
|
6767
|
+
const slots = /* @__PURE__ */ new Set([
|
|
6768
|
+
...mine.map((f) => f.path.split("/").slice(0, 3).join("/")),
|
|
6769
|
+
...hold.slots
|
|
6770
|
+
]);
|
|
6027
6771
|
const out = [];
|
|
6772
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6028
6773
|
for (const slot of slots) {
|
|
6029
|
-
if (outsideProjectTarget(projectDir,
|
|
6030
|
-
for (const rel of listFilesRecursive(
|
|
6774
|
+
if (outsideProjectTarget(projectDir, join25(projectDir, slot)) !== null) continue;
|
|
6775
|
+
for (const rel of listFilesRecursive(join25(projectDir, slot))) {
|
|
6031
6776
|
const path = `${slot}/${rel}`;
|
|
6032
|
-
|
|
6033
|
-
|
|
6777
|
+
if (seen.has(path)) continue;
|
|
6778
|
+
seen.add(path);
|
|
6779
|
+
const recordedSha = sha.get(path);
|
|
6780
|
+
if (recordedSha === void 0 && (others.has(path) || recorded(hold.log, path).state !== "none"))
|
|
6781
|
+
continue;
|
|
6782
|
+
const abs = join25(projectDir, path);
|
|
6034
6783
|
try {
|
|
6035
|
-
|
|
6784
|
+
if (recordedSha !== void 0 && hashContent(readFileSync17(abs, "utf8")) === recordedSha)
|
|
6785
|
+
continue;
|
|
6786
|
+
accessSync(abs, fsConstants.R_OK);
|
|
6036
6787
|
} catch {
|
|
6037
6788
|
continue;
|
|
6038
6789
|
}
|
|
6039
|
-
|
|
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 });
|
|
6790
|
+
out.push({ abs, rel: path, slot, recorded: recordedSha !== void 0 });
|
|
6043
6791
|
}
|
|
6044
6792
|
}
|
|
6045
6793
|
return out;
|
|
6046
6794
|
}
|
|
6047
|
-
function
|
|
6795
|
+
function settleAside(projectDir, f, restore) {
|
|
6048
6796
|
let now = null;
|
|
6049
6797
|
try {
|
|
6050
|
-
now = readFileSync17(
|
|
6051
|
-
} catch {
|
|
6798
|
+
now = readFileSync17(f.abs);
|
|
6799
|
+
} catch (e2) {
|
|
6800
|
+
const code = e2.code;
|
|
6801
|
+
if (code !== "ENOENT" && code !== "ENOTDIR") throw e2;
|
|
6052
6802
|
}
|
|
6053
|
-
if (now
|
|
6054
|
-
|
|
6055
|
-
|
|
6056
|
-
|
|
6057
|
-
|
|
6803
|
+
if (restore || (now === null ? !f.recorded : now.equals(readFileSync17(f.aside)))) {
|
|
6804
|
+
mkdirSync6(dirname6(f.abs), { recursive: true });
|
|
6805
|
+
renameSync2(f.aside, f.abs);
|
|
6806
|
+
return "back";
|
|
6807
|
+
}
|
|
6808
|
+
const backup = backupFromCopy(f.abs, f.aside);
|
|
6809
|
+
rmSync3(f.aside, { force: true });
|
|
6810
|
+
if (f.recorded || now === null) return { backup, displaced: null };
|
|
6811
|
+
return {
|
|
6812
|
+
backup,
|
|
6813
|
+
displaced: { path: f.rel, change: "displaced", notes: [toProjectRel(projectDir, backup)] }
|
|
6814
|
+
};
|
|
6815
|
+
}
|
|
6816
|
+
function withoutCreated(report, paths) {
|
|
6817
|
+
if (paths.size === 0) return report;
|
|
6818
|
+
return {
|
|
6819
|
+
...report,
|
|
6820
|
+
attempted: report.attempted.map(
|
|
6821
|
+
(r) => r.files === void 0 ? r : {
|
|
6822
|
+
...r,
|
|
6823
|
+
files: { ...r.files, created: r.files.created.filter((x) => !paths.has(x.path)) }
|
|
6824
|
+
}
|
|
6825
|
+
)
|
|
6826
|
+
};
|
|
6827
|
+
}
|
|
6828
|
+
function pruneEmptyDirs(dir) {
|
|
6829
|
+
try {
|
|
6830
|
+
for (const e2 of readdirSync3(dir, { withFileTypes: true }))
|
|
6831
|
+
if (e2.isDirectory()) pruneEmptyDirs(join25(dir, e2.name));
|
|
6832
|
+
rmdirSync(dir);
|
|
6833
|
+
} catch {
|
|
6058
6834
|
}
|
|
6059
|
-
return backupContent(h2.abs, h2.content);
|
|
6060
6835
|
}
|
|
6061
|
-
function
|
|
6836
|
+
function toProjectRel(projectDir, abs) {
|
|
6837
|
+
return relative4(projectDir, abs).split(sep5).join("/");
|
|
6838
|
+
}
|
|
6839
|
+
function recordRefreshedFiles(projectDir, log, report, displaced, writeLog) {
|
|
6062
6840
|
const next = new Map(
|
|
6063
6841
|
buildAssetEntries(report, log.scope, log.assets).filter((e2) => e2.files !== void 0).map((e2) => [e2.id, e2.files])
|
|
6064
6842
|
);
|
|
6065
|
-
let changed =
|
|
6843
|
+
let changed = displaced.length > 0;
|
|
6066
6844
|
const assets = log.assets.map((a) => {
|
|
6067
6845
|
const files = next.get(a.id);
|
|
6068
6846
|
if (files === void 0 || JSON.stringify(files) === JSON.stringify(a.files)) return a;
|
|
@@ -6071,7 +6849,11 @@ function recordRefreshedFiles(projectDir, log, report, writeLog) {
|
|
|
6071
6849
|
});
|
|
6072
6850
|
if (!changed) return;
|
|
6073
6851
|
try {
|
|
6074
|
-
writeLog(projectDir, {
|
|
6852
|
+
writeLog(projectDir, {
|
|
6853
|
+
...log,
|
|
6854
|
+
assets,
|
|
6855
|
+
...displaced.length > 0 ? { rootFiles: mergeRootFiles(log.rootFiles, displaced) } : {}
|
|
6856
|
+
});
|
|
6075
6857
|
} catch {
|
|
6076
6858
|
}
|
|
6077
6859
|
}
|
|
@@ -6151,7 +6933,7 @@ function detectVersion(method, spawn, scope, projectDir) {
|
|
|
6151
6933
|
case "plugin":
|
|
6152
6934
|
return detectPluginVersion(method.pluginId, scope, projectDir);
|
|
6153
6935
|
case "npm": {
|
|
6154
|
-
const pkgJson = scope === "global" ? detectGlobalNpmPackageJsonPath(method.pkg, spawn) :
|
|
6936
|
+
const pkgJson = scope === "global" ? detectGlobalNpmPackageJsonPath(method.pkg, spawn) : join25(projectDir, "node_modules", method.pkg, "package.json");
|
|
6155
6937
|
if (!pkgJson || !existsSync19(pkgJson)) return void 0;
|
|
6156
6938
|
const parsed = JSON.parse(readFileSync17(pkgJson, "utf8"));
|
|
6157
6939
|
return parsed.version;
|
|
@@ -6165,7 +6947,7 @@ function detectVersion(method, spawn, scope, projectDir) {
|
|
|
6165
6947
|
}
|
|
6166
6948
|
function detectPluginVersion(pluginId, scope, projectDir) {
|
|
6167
6949
|
const claudeScope = scope === "global" ? "user" : "project";
|
|
6168
|
-
const path =
|
|
6950
|
+
const path = join25(homedir2(), ".claude/plugins/installed_plugins.json");
|
|
6169
6951
|
if (!existsSync19(path)) return void 0;
|
|
6170
6952
|
const data = JSON.parse(readFileSync17(path, "utf8"));
|
|
6171
6953
|
const entries = data.plugins?.[pluginId] ?? [];
|
|
@@ -6180,7 +6962,7 @@ function detectPluginVersion(pluginId, scope, projectDir) {
|
|
|
6180
6962
|
}
|
|
6181
6963
|
function detectGlobalNpmPackageJsonPath(pkg, spawn) {
|
|
6182
6964
|
const npmRoot = getNpmGlobalRoot(spawn);
|
|
6183
|
-
return npmRoot ?
|
|
6965
|
+
return npmRoot ? join25(npmRoot, pkg, "package.json") : void 0;
|
|
6184
6966
|
}
|
|
6185
6967
|
var npmGlobalRootCache;
|
|
6186
6968
|
function getNpmGlobalRoot(spawn) {
|
|
@@ -6200,7 +6982,7 @@ function getNpmGlobalRoot(spawn) {
|
|
|
6200
6982
|
// src/key-ids.ts
|
|
6201
6983
|
init_esm_shims();
|
|
6202
6984
|
import { readFileSync as readFileSync18 } from "fs";
|
|
6203
|
-
import { join as
|
|
6985
|
+
import { join as join26 } from "path";
|
|
6204
6986
|
function renderedKeyIds(harnessRoot, input, clis) {
|
|
6205
6987
|
const out = /* @__PURE__ */ new Set();
|
|
6206
6988
|
const add = (path, key) => {
|
|
@@ -6223,7 +7005,7 @@ function renderedKeyIds(harnessRoot, input, clis) {
|
|
|
6223
7005
|
for (const name of Object.keys(mcp.mcpServers)) add(".mcp.json", `mcpServers.${name}`);
|
|
6224
7006
|
for (const key of gitignoreRender().keys()) add(".gitignore", key);
|
|
6225
7007
|
if (clis.includes("claude")) {
|
|
6226
|
-
const template = readFileSync18(
|
|
7008
|
+
const template = readFileSync18(join26(harnessRoot, "templates/settings.json"), "utf8");
|
|
6227
7009
|
for (const key of renderSettingsPortion(template, () => true).keys()) {
|
|
6228
7010
|
add(".claude/settings.json", key);
|
|
6229
7011
|
}
|
|
@@ -6264,7 +7046,7 @@ function withoutAccepts(harnessRoot, spec, previous) {
|
|
|
6264
7046
|
|
|
6265
7047
|
// src/linked-skill-bodies.ts
|
|
6266
7048
|
init_esm_shims();
|
|
6267
|
-
import { join as
|
|
7049
|
+
import { join as join27 } from "path";
|
|
6268
7050
|
function refreshLinkedSkillBodies(params) {
|
|
6269
7051
|
const { harnessRoot, projectDir, ids, baseline, journal } = params;
|
|
6270
7052
|
const bodyKey = (id) => `.agents/skills/${id}/SKILL.md`;
|
|
@@ -6275,7 +7057,7 @@ function refreshLinkedSkillBodies(params) {
|
|
|
6275
7057
|
);
|
|
6276
7058
|
const result = writer.result();
|
|
6277
7059
|
return {
|
|
6278
|
-
updated: ours.filter((id) => written.has(
|
|
7060
|
+
updated: ours.filter((id) => written.has(join27(projectDir, bodyKey(id)))),
|
|
6279
7061
|
notOurs: ids.filter((id) => !baseline.has(bodyKey(id))),
|
|
6280
7062
|
files: result.files,
|
|
6281
7063
|
backupPaths: result.backupPaths,
|
|
@@ -6287,8 +7069,8 @@ function refreshLinkedSkillBodies(params) {
|
|
|
6287
7069
|
|
|
6288
7070
|
// src/out-of-track.ts
|
|
6289
7071
|
init_esm_shims();
|
|
6290
|
-
import { lstatSync as
|
|
6291
|
-
import { join as
|
|
7072
|
+
import { lstatSync as lstatSync4, readFileSync as readFileSync19, rmSync as rmSync4 } from "fs";
|
|
7073
|
+
import { join as join28 } from "path";
|
|
6292
7074
|
var AGENTS_RULE = /^\.agents\/rules\/([^/]+)\.md$/;
|
|
6293
7075
|
var ANCHOR_RULE = "uzys-harness";
|
|
6294
7076
|
function reclaimOutOfTrack(args) {
|
|
@@ -6308,9 +7090,9 @@ function reclaimOutOfTrack(args) {
|
|
|
6308
7090
|
const name = AGENTS_RULE.exec(f.path)?.[1];
|
|
6309
7091
|
if (name === void 0 || name === ANCHOR_RULE || rendered.has(name)) continue;
|
|
6310
7092
|
if (isBaselineExcluded(`.claude/rules/${name}.md`, args.excluded)) continue;
|
|
6311
|
-
const abs =
|
|
7093
|
+
const abs = join28(projectDir, f.path);
|
|
6312
7094
|
if (args.outside.skip(abs)) continue;
|
|
6313
|
-
const stat =
|
|
7095
|
+
const stat = lstatSync4(abs, { throwIfNoEntry: false });
|
|
6314
7096
|
if (stat !== void 0 && !stat.isFile()) continue;
|
|
6315
7097
|
if (stat !== void 0 && claudeCopy.has(`rules/${name}.md`)) {
|
|
6316
7098
|
out.kept.push(f.path);
|
|
@@ -6330,11 +7112,11 @@ function reclaimOutOfTrack(args) {
|
|
|
6330
7112
|
out.bringBack[f.path] = tracksBringing(name);
|
|
6331
7113
|
}
|
|
6332
7114
|
if (verdict.verdict === "remove") {
|
|
6333
|
-
|
|
7115
|
+
rmSync4(abs);
|
|
6334
7116
|
out.removed.push(f.path);
|
|
6335
7117
|
} else if (verdict.verdict === "backup+remove") {
|
|
6336
7118
|
const backup = backupFile(abs, args.now);
|
|
6337
|
-
|
|
7119
|
+
rmSync4(abs);
|
|
6338
7120
|
out.backedUp.push({ path: f.path, backup });
|
|
6339
7121
|
}
|
|
6340
7122
|
}
|
|
@@ -6350,14 +7132,14 @@ function tracksBringing(rule) {
|
|
|
6350
7132
|
// src/state.ts
|
|
6351
7133
|
init_esm_shims();
|
|
6352
7134
|
import { existsSync as existsSync20, readFileSync as readFileSync20 } from "fs";
|
|
6353
|
-
import { join as
|
|
7135
|
+
import { join as join29 } from "path";
|
|
6354
7136
|
var META_FILE = ".claude/.installed-tracks";
|
|
6355
7137
|
var LEGACY_ANCHOR_FILE = ".claude/CLAUDE.md";
|
|
6356
7138
|
var TRACE_RULES = ["htmx", "nextjs", "data-analysis", "pyside6", "cli-development"].map(
|
|
6357
7139
|
(r) => `.claude/rules/${r}.md`
|
|
6358
7140
|
);
|
|
6359
7141
|
function detectInstallState(projectDir) {
|
|
6360
|
-
const hasClaudeDir = existsSync20(
|
|
7142
|
+
const hasClaudeDir = existsSync20(join29(projectDir, ".claude"));
|
|
6361
7143
|
const read = readInstallLogStatus(projectDir);
|
|
6362
7144
|
if (read.status === "ok") {
|
|
6363
7145
|
return {
|
|
@@ -6377,7 +7159,7 @@ function tracksFromLog(tracks) {
|
|
|
6377
7159
|
return [...new Set(tracks.filter(isTrack))].sort();
|
|
6378
7160
|
}
|
|
6379
7161
|
function collectTraces(projectDir) {
|
|
6380
|
-
const at5 = (rel) =>
|
|
7162
|
+
const at5 = (rel) => join29(projectDir, rel);
|
|
6381
7163
|
const contains = (rel, needle) => existsSync20(at5(rel)) && readFileSync20(at5(rel), "utf8").includes(needle);
|
|
6382
7164
|
const traces = [];
|
|
6383
7165
|
if (existsSync20(at5(META_FILE)))
|
|
@@ -6437,16 +7219,14 @@ init_esm_shims();
|
|
|
6437
7219
|
import {
|
|
6438
7220
|
copyFileSync,
|
|
6439
7221
|
existsSync as existsSync21,
|
|
6440
|
-
|
|
6441
|
-
mkdirSync as mkdirSync6,
|
|
6442
|
-
readdirSync as readdirSync3,
|
|
7222
|
+
readdirSync as readdirSync4,
|
|
6443
7223
|
readFileSync as readFileSync21,
|
|
6444
|
-
rmdirSync,
|
|
7224
|
+
rmdirSync as rmdirSync2,
|
|
6445
7225
|
statSync as statSync4,
|
|
6446
7226
|
unlinkSync as unlinkSync2,
|
|
6447
|
-
writeFileSync as
|
|
7227
|
+
writeFileSync as writeFileSync7
|
|
6448
7228
|
} from "fs";
|
|
6449
|
-
import { basename as basename3, dirname as
|
|
7229
|
+
import { basename as basename3, dirname as dirname7, join as join30 } from "path";
|
|
6450
7230
|
var LEGACY_ANCHOR_FILE2 = ".claude/CLAUDE.md";
|
|
6451
7231
|
function buildUpdateSpec(projectDir, tracks, only) {
|
|
6452
7232
|
const log = readInstallLog(projectDir);
|
|
@@ -6468,7 +7248,7 @@ function parseUpdateOnly(raw) {
|
|
|
6468
7248
|
return { ok: true, groups: [...new Set(raw)] };
|
|
6469
7249
|
}
|
|
6470
7250
|
function runUpdateMode(projectDir, templatesDir, harnessRoot, deps = {}, only) {
|
|
6471
|
-
const claudeDir =
|
|
7251
|
+
const claudeDir = join30(projectDir, ".claude");
|
|
6472
7252
|
const startedAt = Date.now();
|
|
6473
7253
|
const backupsAtStart = new Set(
|
|
6474
7254
|
collectRunBackups(projectDir, Number.NEGATIVE_INFINITY).map((b2) => b2.backup)
|
|
@@ -6505,87 +7285,12 @@ function runUpdateMode(projectDir, templatesDir, harnessRoot, deps = {}, only) {
|
|
|
6505
7285
|
demotedAgents: [],
|
|
6506
7286
|
mcpAllowlistRetired: null
|
|
6507
7287
|
};
|
|
6508
|
-
const fresh = installNewAssets(projectDir, templatesDir, wants, outside);
|
|
6509
|
-
report.installedNew = fresh.installed;
|
|
6510
|
-
report.restored = fresh.restored;
|
|
6511
7288
|
const logAtStart = readInstallLog(projectDir);
|
|
6512
7289
|
const claudeManaged = logAtStart === null || installedClis(logAtStart).includes("claude");
|
|
6513
|
-
const recordOf = recordedStateOf(logAtStart);
|
|
6514
|
-
const claudeDisplaced = [];
|
|
6515
7290
|
report.claudeUnrecorded = !claudeManaged && logAtStart !== null && existsSync21(claudeDir) ? recordClaudeCommand(logAtStart, installedTracks(projectDir)) : null;
|
|
6516
|
-
const
|
|
6517
|
-
|
|
6518
|
-
|
|
6519
|
-
const target = join29(claudeDir, dir);
|
|
6520
|
-
const source = join29(templatesDir, dir);
|
|
6521
|
-
const label = `.claude/${dir}`;
|
|
6522
|
-
const ctx = {
|
|
6523
|
-
prefix: dir,
|
|
6524
|
-
baseline: policyBase,
|
|
6525
|
-
outside,
|
|
6526
|
-
excluded: excludedIds(logAtStart),
|
|
6527
|
-
// 0단계가 방금 깐 파일은 기록 전이지만 하네스 것이다 — 첫 접촉으로 읽지 않는다
|
|
6528
|
-
justWritten: new Set(fresh.installed),
|
|
6529
|
-
...recordOf === void 0 ? {} : { recordOf }
|
|
6530
|
-
};
|
|
6531
|
-
const synced = updateDir(target, source, ext, ctx);
|
|
6532
|
-
report.updated[label] = synced.updated;
|
|
6533
|
-
report.policyBackedUp.push(...synced.backedUp);
|
|
6534
|
-
claudeDisplaced.push(...synced.displaced);
|
|
6535
|
-
report.pruned[label] = pruneOrphans(target, source, ext, ctx);
|
|
6536
|
-
}
|
|
6537
|
-
const syncedDirs = POLICY_DIRS.filter((d2) => wants(d2.dir === "hooks" ? "hooks" : "rules")).map(
|
|
6538
|
-
(d2) => d2.dir
|
|
6539
|
-
);
|
|
6540
|
-
if (claudeManaged && syncedDirs.length > 0)
|
|
6541
|
-
refreshPolicyBaseline(
|
|
6542
|
-
projectDir,
|
|
6543
|
-
templatesDir,
|
|
6544
|
-
syncedDirs,
|
|
6545
|
-
outsidePaths(outside, ".claude/"),
|
|
6546
|
-
notOursUnder(claudeDisplaced, ".claude/")
|
|
6547
|
-
);
|
|
6548
|
-
const skillTargets = logAtStart === null ? void 0 : recordedSkillIds(projectDir, logAtStart);
|
|
6549
|
-
const skillSync = claudeManaged && wants("skills") ? syncSkills(
|
|
6550
|
-
join29(claudeDir, "skills"),
|
|
6551
|
-
join29(templatesDir, "skills"),
|
|
6552
|
-
skillBaseline(projectDir),
|
|
6553
|
-
/* @__PURE__ */ new Date(),
|
|
6554
|
-
(relInSkills) => foreignOwnedTarget(projectDir, `.claude/skills/${relInSkills}`),
|
|
6555
|
-
outside,
|
|
6556
|
-
excludedSkillOf(logAtStart),
|
|
6557
|
-
{
|
|
6558
|
-
...recordOf === void 0 ? {} : { recordOf },
|
|
6559
|
-
...skillTargets === void 0 ? {} : { targets: skillTargets }
|
|
6560
|
-
}
|
|
6561
|
-
) : {
|
|
6562
|
-
updated: 0,
|
|
6563
|
-
backedUp: [],
|
|
6564
|
-
skippedLinks: [],
|
|
6565
|
-
foreignOwned: [],
|
|
6566
|
-
pruned: [],
|
|
6567
|
-
displaced: []
|
|
6568
|
-
};
|
|
6569
|
-
claudeDisplaced.push(...skillSync.displaced);
|
|
6570
|
-
if (wants("skills")) report.updated[".claude/skills"] = skillSync.updated;
|
|
6571
|
-
report.skillsBackedUp = skillSync.backedUp;
|
|
6572
|
-
report.skillsSkippedLinks = skillSync.skippedLinks;
|
|
6573
|
-
report.skillsPruned = skillSync.pruned;
|
|
6574
|
-
const newSkills = claudeManaged && wants("new-skills") ? installNewSkillDirs(projectDir, templatesDir, installedTracks(projectDir), outside) : { installed: [], restored: [], foreignOwned: [] };
|
|
6575
|
-
report.installedNew.push(...newSkills.installed);
|
|
6576
|
-
report.restored.push(...newSkills.restored);
|
|
6577
|
-
const copiedSkills = [...newSkills.installed, ...newSkills.restored];
|
|
6578
|
-
if (claudeManaged && wants("skills"))
|
|
6579
|
-
refreshSkillBaseline(
|
|
6580
|
-
projectDir,
|
|
6581
|
-
templatesDir,
|
|
6582
|
-
outsidePaths(outside, ".claude/skills/"),
|
|
6583
|
-
skillTargets,
|
|
6584
|
-
notOursUnder(claudeDisplaced, ".claude/skills/")
|
|
6585
|
-
);
|
|
6586
|
-
else if (claudeManaged && copiedSkills.length > 0)
|
|
6587
|
-
recordNewSkillBaseline(projectDir, templatesDir, copiedSkills);
|
|
6588
|
-
if (claudeDisplaced.length > 0) recordDisplaced(projectDir, claudeDisplaced);
|
|
7291
|
+
const harness = logAtStart === null ? { displaced: [], restored: [], foreignOwned: [], outside: [] } : updateHarnessFiles({ projectDir, templatesDir, log: logAtStart, wants, outside, report });
|
|
7292
|
+
const claudeDisplaced = harness.displaced;
|
|
7293
|
+
const prunedRestored = harness.restored;
|
|
6589
7294
|
if (existsSync21(claudeDir) && claudeManaged) {
|
|
6590
7295
|
if (wants("anchor")) syncHarnessAnchor(projectDir, templatesDir, report, outside);
|
|
6591
7296
|
}
|
|
@@ -6605,7 +7310,7 @@ function runUpdateMode(projectDir, templatesDir, harnessRoot, deps = {}, only) {
|
|
|
6605
7310
|
droppedKeys: legacyDroppedKeys(logAtStart),
|
|
6606
7311
|
harnessMcp
|
|
6607
7312
|
});
|
|
6608
|
-
const settingsPath =
|
|
7313
|
+
const settingsPath = join30(claudeDir, "settings.json");
|
|
6609
7314
|
if (claudeManaged && wants("hooks") && existsSync21(settingsPath) && !outside.skip(settingsPath)) {
|
|
6610
7315
|
report.retiredHookRefsRemoved = removeRetiredHookRefs(
|
|
6611
7316
|
settingsPath,
|
|
@@ -6621,8 +7326,6 @@ function runUpdateMode(projectDir, templatesDir, harnessRoot, deps = {}, only) {
|
|
|
6621
7326
|
if (wants("hooks")) report.mcpAllowlistRetired = retireMcpAllowlist(projectDir);
|
|
6622
7327
|
report.retiredAgents = staleAgentFiles(claudeDir);
|
|
6623
7328
|
report.demotedAgents = demotedAgentFiles(claudeDir, installedTracks(projectDir));
|
|
6624
|
-
if (logAtStart !== null && wants("rules"))
|
|
6625
|
-
refreshNeutralHelpers(projectDir, templatesDir, report);
|
|
6626
7329
|
const external = wants("external") ? refreshExternalCli(projectDir, harnessRoot, legacyDroppedKeys(logAtStart), harnessMcp) : {
|
|
6627
7330
|
externalUpdated: 0,
|
|
6628
7331
|
externalBackedUp: [],
|
|
@@ -6638,18 +7341,31 @@ function runUpdateMode(projectDir, templatesDir, harnessRoot, deps = {}, only) {
|
|
|
6638
7341
|
restoredFiles: [],
|
|
6639
7342
|
legacyRestored: [],
|
|
6640
7343
|
anchorRetired: null,
|
|
7344
|
+
anchorDisplaced: [],
|
|
6641
7345
|
agentsMd: null,
|
|
7346
|
+
agentsMdLegacyDropped: 0,
|
|
7347
|
+
agentsMdLegacyEdited: [],
|
|
6642
7348
|
excludedKeys: [],
|
|
6643
7349
|
sharedLeft: []
|
|
6644
7350
|
};
|
|
7351
|
+
const outOfTrackRestored = [];
|
|
6645
7352
|
if (wants("external")) {
|
|
6646
|
-
const outOfTrack = reclaimOutOfTrackRecorded(projectDir, outside);
|
|
7353
|
+
const { reclaim: outOfTrack, displaced } = reclaimOutOfTrackRecorded(projectDir, outside);
|
|
6647
7354
|
if (outOfTrack.removed.length + outOfTrack.backedUp.length + outOfTrack.kept.length > 0)
|
|
6648
7355
|
report.outOfTrack = outOfTrack;
|
|
7356
|
+
outOfTrackRestored.push(...displaced);
|
|
6649
7357
|
}
|
|
7358
|
+
const displacedRestored = [...prunedRestored, ...external.anchorDisplaced, ...outOfTrackRestored];
|
|
7359
|
+
if (displacedRestored.length > 0) report.displacedRestored = displacedRestored;
|
|
6650
7360
|
report.externalUpdated = external.externalUpdated;
|
|
6651
7361
|
if (external.anchorRetired !== null) report.anchorRetired = external.anchorRetired;
|
|
6652
7362
|
if (external.agentsMd !== null) report.agentsMd = external.agentsMd;
|
|
7363
|
+
if (external.agentsMdLegacyDropped > 0) {
|
|
7364
|
+
report.agentsMdLegacyDropped = external.agentsMdLegacyDropped;
|
|
7365
|
+
}
|
|
7366
|
+
if (external.agentsMdLegacyEdited.length > 0) {
|
|
7367
|
+
report.agentsMdLegacyEdited = external.agentsMdLegacyEdited;
|
|
7368
|
+
}
|
|
6653
7369
|
if (external.sharedLeft.length > 0) report.sharedLeft = external.sharedLeft;
|
|
6654
7370
|
report.restoredKeys = external.restoredKeys;
|
|
6655
7371
|
report.restoredFiles = external.restoredFiles;
|
|
@@ -6681,12 +7397,7 @@ function runUpdateMode(projectDir, templatesDir, harnessRoot, deps = {}, only) {
|
|
|
6681
7397
|
report.restoredWithout = restoredWithoutArgs(report.restored, installedTracks(projectDir));
|
|
6682
7398
|
const saidBySlotRow = new Set(report.skillsSkippedLinks.map((id) => `.claude/skills/${id}`));
|
|
6683
7399
|
const merged = [];
|
|
6684
|
-
for (const f of [
|
|
6685
|
-
...skillSync.foreignOwned,
|
|
6686
|
-
...fresh.foreignOwned,
|
|
6687
|
-
...newSkills.foreignOwned,
|
|
6688
|
-
...external.externalForeignOwned
|
|
6689
|
-
]) {
|
|
7400
|
+
for (const f of [...harness.foreignOwned, ...external.externalForeignOwned]) {
|
|
6690
7401
|
if (!saidBySlotRow.has(f) && !merged.includes(f)) merged.push(f);
|
|
6691
7402
|
}
|
|
6692
7403
|
report.foreignOwned = merged;
|
|
@@ -6716,7 +7427,12 @@ function runUpdateMode(projectDir, templatesDir, harnessRoot, deps = {}, only) {
|
|
|
6716
7427
|
).filter((id) => !skillRefresh.notInCatalog.includes(id))
|
|
6717
7428
|
].filter((id) => !saidAsRemoved.has(id));
|
|
6718
7429
|
report.externalSkillsUnknown = skillRefresh.unknown;
|
|
6719
|
-
const outsideLinks = mergeOutside(
|
|
7430
|
+
const outsideLinks = mergeOutside(
|
|
7431
|
+
harness.outside,
|
|
7432
|
+
outside.list(),
|
|
7433
|
+
sharedWrites.outside,
|
|
7434
|
+
external.externalOutside
|
|
7435
|
+
);
|
|
6720
7436
|
if (outsideLinks.length > 0) report.outsideLinks = outsideLinks;
|
|
6721
7437
|
const displacedAll = [...claudeDisplaced, ...external.displaced];
|
|
6722
7438
|
const displacedMoved = displacedAll.filter((f) => f.notes.length > 0).map((f) => f.path);
|
|
@@ -6788,18 +7504,21 @@ function reclaimOutOfTrackRecorded(projectDir, outside) {
|
|
|
6788
7504
|
excluded: excludedIds(log),
|
|
6789
7505
|
outside
|
|
6790
7506
|
});
|
|
7507
|
+
const left = /* @__PURE__ */ new Set([...result.removed, ...result.backedUp.map((b2) => b2.path)]);
|
|
7508
|
+
const displaced = log === null || left.size === 0 ? [] : restoreDisplaced(log, projectDir, { has: (p2) => left.has(p2), write: true });
|
|
6791
7509
|
if (log !== null && result.forget.length > 0) {
|
|
6792
7510
|
const forget = new Set(result.forget);
|
|
6793
7511
|
const next = { ...log };
|
|
6794
7512
|
const kept = (log.externalFiles ?? []).filter((f) => !forget.has(f.path));
|
|
6795
7513
|
if (kept.length > 0) next.externalFiles = kept;
|
|
6796
7514
|
else delete next.externalFiles;
|
|
7515
|
+
if (displaced.some((d2) => d2.forget)) next.rootFiles = withoutRestored(log.rootFiles, displaced);
|
|
6797
7516
|
try {
|
|
6798
7517
|
writeInstallLog(projectDir, next);
|
|
6799
7518
|
} catch {
|
|
6800
7519
|
}
|
|
6801
7520
|
}
|
|
6802
|
-
return result;
|
|
7521
|
+
return { reclaim: result, displaced };
|
|
6803
7522
|
}
|
|
6804
7523
|
function checksumOnRecord(log) {
|
|
6805
7524
|
if (log === null) return () => false;
|
|
@@ -6807,7 +7526,9 @@ function checksumOnRecord(log) {
|
|
|
6807
7526
|
...(log.policyFiles ?? []).map((f) => `.claude/${f.path}`),
|
|
6808
7527
|
...(log.skillFiles ?? []).map((f) => `.claude/skills/${f.path}`),
|
|
6809
7528
|
...(log.externalFiles ?? []).map((f) => f.path),
|
|
6810
|
-
...log.assets.flatMap((a) => a.files ?? []).map((f) => f.path)
|
|
7529
|
+
...log.assets.flatMap((a) => a.files ?? []).map((f) => f.path),
|
|
7530
|
+
// #800 — 함께 쓰는 파일은 몫마다 sha 가 있다 — 그 백업은 설치자 편집이 확실하다
|
|
7531
|
+
...(log.portions ?? []).map((p2) => p2.path)
|
|
6811
7532
|
]);
|
|
6812
7533
|
const anchor = log.templates.rootClaudeMd;
|
|
6813
7534
|
if (anchor !== void 0) paths.add(anchor.path);
|
|
@@ -6820,7 +7541,7 @@ function retiredFeaturesPart(projectDir, f) {
|
|
|
6820
7541
|
}
|
|
6821
7542
|
function legacyHookOnDisk(projectDir, rel) {
|
|
6822
7543
|
try {
|
|
6823
|
-
return hasLegacyHarnessHook(readFileSync21(
|
|
7544
|
+
return hasLegacyHarnessHook(readFileSync21(join30(projectDir, rel), "utf8"));
|
|
6824
7545
|
} catch {
|
|
6825
7546
|
return false;
|
|
6826
7547
|
}
|
|
@@ -6846,7 +7567,7 @@ function writeUpdateSharedFiles(args) {
|
|
|
6846
7567
|
excluded: adapterExcluded(harnessRoot, excluded)
|
|
6847
7568
|
});
|
|
6848
7569
|
const tracks = installedTracks(projectDir);
|
|
6849
|
-
const settingsSource =
|
|
7570
|
+
const settingsSource = join30(templatesDir, "settings.json");
|
|
6850
7571
|
if (args.claudeManaged && wants("hooks") && existsSync21(settingsSource)) {
|
|
6851
7572
|
const spec = buildAssetSpec({ tracks, options: DEFAULT_OPTIONS });
|
|
6852
7573
|
const manifest = buildManifest(spec);
|
|
@@ -6857,7 +7578,7 @@ function writeUpdateSharedFiles(args) {
|
|
|
6857
7578
|
log,
|
|
6858
7579
|
(script) => {
|
|
6859
7580
|
const target = `.claude/hooks/${script}`;
|
|
6860
|
-
return manifest.some((e2) => e2.target === target && e2.applies(spec)) && !isBaselineExcluded(target, excluded) && existsSync21(
|
|
7581
|
+
return manifest.some((e2) => e2.target === target && e2.applies(spec)) && !isBaselineExcluded(target, excluded) && existsSync21(join30(projectDir, target));
|
|
6861
7582
|
}
|
|
6862
7583
|
// 기록이 claude 를 깔린 CLI 로 말한다 = install 이 이 파일을 썼다 — 없으면 만든다(훅 배선이 여기 산다)
|
|
6863
7584
|
);
|
|
@@ -6921,102 +7642,255 @@ function catalogRemovedOnRecord(log) {
|
|
|
6921
7642
|
}
|
|
6922
7643
|
function staleSkillDirs(projectDir, claudeDir, clis) {
|
|
6923
7644
|
const stale = (id) => RENAMED_SKILL_IDS[id] !== void 0 || RETIRED_SKILL_IDS.includes(id);
|
|
6924
|
-
const dirs = [
|
|
6925
|
-
if (clis.some((cli) => cli !== "claude")) dirs.push(
|
|
7645
|
+
const dirs = [join30(claudeDir, "skills")];
|
|
7646
|
+
if (clis.some((cli) => cli !== "claude")) dirs.push(join30(projectDir, ".agents", "skills"));
|
|
6926
7647
|
const ids = /* @__PURE__ */ new Set();
|
|
6927
7648
|
for (const dir of dirs) {
|
|
6928
7649
|
if (!existsSync21(dir)) continue;
|
|
6929
|
-
for (const e2 of
|
|
7650
|
+
for (const e2 of readdirSync4(dir, { withFileTypes: true })) {
|
|
6930
7651
|
if (e2.isDirectory() && stale(e2.name)) ids.add(e2.name);
|
|
6931
7652
|
}
|
|
6932
7653
|
}
|
|
6933
7654
|
return [...ids];
|
|
6934
7655
|
}
|
|
6935
7656
|
function staleAgentFiles(claudeDir) {
|
|
6936
|
-
const dir =
|
|
7657
|
+
const dir = join30(claudeDir, "agents");
|
|
6937
7658
|
if (!existsSync21(dir)) return [];
|
|
6938
|
-
return
|
|
7659
|
+
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
7660
|
}
|
|
6940
7661
|
function demotedAgentFiles(claudeDir, tracks) {
|
|
6941
7662
|
if (tracks.length === 0) return [];
|
|
6942
|
-
const dir =
|
|
7663
|
+
const dir = join30(claudeDir, "agents");
|
|
6943
7664
|
if (!existsSync21(dir)) return [];
|
|
6944
7665
|
const demoted = TRACK_AGENTS.filter(([, pattern]) => !anyTrack(tracks, pattern)).map(
|
|
6945
7666
|
([id]) => id
|
|
6946
7667
|
);
|
|
6947
|
-
return
|
|
7668
|
+
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
7669
|
}
|
|
6949
|
-
function
|
|
6950
|
-
const
|
|
6951
|
-
const
|
|
6952
|
-
const
|
|
6953
|
-
const
|
|
6954
|
-
|
|
6955
|
-
|
|
6956
|
-
|
|
6957
|
-
|
|
6958
|
-
|
|
6959
|
-
|
|
6960
|
-
|
|
6961
|
-
|
|
6962
|
-
|
|
6963
|
-
|
|
6964
|
-
|
|
6965
|
-
|
|
6966
|
-
|
|
6967
|
-
|
|
6968
|
-
|
|
7670
|
+
function updateHarnessTargets(projectDir, templatesDir, log, wants, report, foreignOwned) {
|
|
7671
|
+
const files = [];
|
|
7672
|
+
const claude = installedClis(log).includes("claude");
|
|
7673
|
+
const excluded = excludedIds(log);
|
|
7674
|
+
for (const e2 of trackOnlyFileAssets(installedTracks(projectDir))) {
|
|
7675
|
+
if (e2.target === HARNESS_ANCHOR_FILE || e2.target === SETTINGS_TARGET) continue;
|
|
7676
|
+
if (!wants(e2.target.startsWith(".claude/hooks/") ? "hooks" : "rules")) continue;
|
|
7677
|
+
if (e2.target.startsWith(".claude/") && !claude) continue;
|
|
7678
|
+
if (isBaselineExcluded(e2.target, excluded)) continue;
|
|
7679
|
+
const source = join30(templatesDir, e2.source);
|
|
7680
|
+
if (!existsSync21(source)) continue;
|
|
7681
|
+
const policy = POLICY_DIRS.find((d2) => e2.target.startsWith(`.claude/${d2.dir}/`));
|
|
7682
|
+
files.push({
|
|
7683
|
+
path: e2.target,
|
|
7684
|
+
source,
|
|
7685
|
+
unit: e2.target,
|
|
7686
|
+
unitExisted: existsSync21(join30(projectDir, e2.target)),
|
|
7687
|
+
label: policy === void 0 ? e2.target : `.claude/${policy.dir}`
|
|
7688
|
+
});
|
|
7689
|
+
}
|
|
7690
|
+
const refreshedSkills = [];
|
|
7691
|
+
const skillsSource = join30(templatesDir, "skills");
|
|
7692
|
+
if (!claude || !(wants("skills") || wants("new-skills")) || !existsSync21(skillsSource)) {
|
|
7693
|
+
return { files, refreshedSkills };
|
|
7694
|
+
}
|
|
7695
|
+
const ids = recordedSkillIds(projectDir, log);
|
|
7696
|
+
const creatable = claudeSkillIds(projectDir, log);
|
|
7697
|
+
const excludedSkill = excludedSkillOf(log);
|
|
7698
|
+
for (const d2 of readdirSync4(skillsSource, { withFileTypes: true })) {
|
|
7699
|
+
if (!d2.isDirectory()) continue;
|
|
7700
|
+
const unit = `.claude/skills/${d2.name}`;
|
|
7701
|
+
if (occupiedByNonDirectory(join30(projectDir, unit))) {
|
|
7702
|
+
report.skillsSkippedLinks.push(d2.name);
|
|
6969
7703
|
continue;
|
|
6970
7704
|
}
|
|
6971
|
-
if (
|
|
6972
|
-
const
|
|
6973
|
-
if (!
|
|
6974
|
-
|
|
6975
|
-
|
|
6976
|
-
if (
|
|
6977
|
-
|
|
7705
|
+
if (!ids.has(d2.name) || excludedSkill(d2.name)) continue;
|
|
7706
|
+
const existed = existsSync21(join30(projectDir, unit));
|
|
7707
|
+
if (existed ? !wants("skills") : !wants("new-skills") || !creatable.has(d2.name)) continue;
|
|
7708
|
+
for (const rel of listFilesRecursive(join30(skillsSource, d2.name))) {
|
|
7709
|
+
const foreign = foreignOwnedTarget(projectDir, `${unit}/${rel}`);
|
|
7710
|
+
if (foreign !== null) {
|
|
7711
|
+
if (!foreignOwned.includes(foreign)) foreignOwned.push(foreign);
|
|
7712
|
+
continue;
|
|
7713
|
+
}
|
|
7714
|
+
const source = join30(skillsSource, d2.name, rel);
|
|
7715
|
+
files.push({
|
|
7716
|
+
path: `${unit}/${rel}`,
|
|
7717
|
+
source,
|
|
7718
|
+
unit,
|
|
7719
|
+
unitExisted: existed,
|
|
7720
|
+
label: ".claude/skills"
|
|
7721
|
+
});
|
|
6978
7722
|
}
|
|
6979
|
-
|
|
6980
|
-
copyFileSync(source, target);
|
|
6981
|
-
const recordedAs = entry.target.startsWith(".claude/") ? entry.target.slice(8) : entry.target;
|
|
6982
|
-
const wired = entry.target.startsWith(".claude/hooks/") && wiredBefore.has(entry.target.slice(".claude/hooks/".length));
|
|
6983
|
-
if (priorBaseline.has(recordedAs) || wired) restored.push(entry.target);
|
|
6984
|
-
else installed.push(entry.target);
|
|
7723
|
+
if (existed) refreshedSkills.push(d2.name);
|
|
6985
7724
|
}
|
|
6986
|
-
return {
|
|
7725
|
+
return { files, refreshedSkills };
|
|
6987
7726
|
}
|
|
6988
|
-
|
|
6989
|
-
|
|
6990
|
-
|
|
6991
|
-
|
|
6992
|
-
)
|
|
6993
|
-
|
|
6994
|
-
|
|
6995
|
-
const
|
|
6996
|
-
|
|
6997
|
-
|
|
7727
|
+
function updateHarnessFiles(args) {
|
|
7728
|
+
const { projectDir, templatesDir, log, wants, outside, report } = args;
|
|
7729
|
+
const now = /* @__PURE__ */ new Date();
|
|
7730
|
+
const claude = installedClis(log).includes("claude");
|
|
7731
|
+
const claims = retiredClaims(log, projectDir, log.policyFiles ?? []);
|
|
7732
|
+
const isTarget = recordedTrackTargets(log);
|
|
7733
|
+
const recordOf = (path) => recorded(log, path, { isTarget });
|
|
7734
|
+
const writer = createInstallWriter({
|
|
7735
|
+
projectDir,
|
|
7736
|
+
previousLog: log,
|
|
7737
|
+
excluded: excludedIds(log),
|
|
7738
|
+
now,
|
|
7739
|
+
run: "update"
|
|
7740
|
+
});
|
|
7741
|
+
const foreignOwned = [];
|
|
7742
|
+
const targets = updateHarnessTargets(projectDir, templatesDir, log, wants, report, foreignOwned);
|
|
7743
|
+
for (const t of targets.files) writer.harness(t.path, { source: t.source }, { isTarget });
|
|
7744
|
+
const prunedPolicy = /* @__PURE__ */ new Set();
|
|
7745
|
+
for (const { dir, ext } of POLICY_DIRS) {
|
|
7746
|
+
if (!claude || !wants(dir === "hooks" ? "hooks" : "rules")) continue;
|
|
7747
|
+
const label = `.claude/${dir}`;
|
|
7748
|
+
report.updated[label] = 0;
|
|
7749
|
+
const ctx = { prefix: dir, outside, recordOf };
|
|
7750
|
+
report.pruned[label] = pruneOrphans(
|
|
7751
|
+
join30(projectDir, label),
|
|
7752
|
+
join30(templatesDir, dir),
|
|
7753
|
+
ext,
|
|
7754
|
+
ctx,
|
|
7755
|
+
now
|
|
7756
|
+
);
|
|
7757
|
+
for (const f of report.pruned[label]) prunedPolicy.add(`${dir}/${f}`);
|
|
7758
|
+
}
|
|
7759
|
+
if (claude && wants("skills")) report.updated[".claude/skills"] = 0;
|
|
7760
|
+
const skillPrune = pruneSkillExtras(
|
|
7761
|
+
projectDir,
|
|
7762
|
+
templatesDir,
|
|
7763
|
+
targets.refreshedSkills,
|
|
7764
|
+
outside,
|
|
7765
|
+
recordOf,
|
|
7766
|
+
now
|
|
7767
|
+
);
|
|
7768
|
+
report.skillsPruned = skillPrune.pruned;
|
|
7769
|
+
report.skillsBackedUp.push(...skillPrune.backedUp);
|
|
7770
|
+
const restored = prunedPolicy.size === 0 ? [] : restoreDisplaced(log, projectDir, {
|
|
7771
|
+
has: (p2) => p2.startsWith(".claude/") && prunedPolicy.has(p2.slice(".claude/".length)),
|
|
7772
|
+
write: true
|
|
7773
|
+
});
|
|
7774
|
+
const ledger = writer.ledger();
|
|
7775
|
+
recordHarnessWrites(projectDir, ledger, {
|
|
7776
|
+
claims,
|
|
7777
|
+
prunedPolicy,
|
|
7778
|
+
prunedSkill: new Set(skillPrune.pruned),
|
|
7779
|
+
restored,
|
|
7780
|
+
walkedSkills: wants("skills")
|
|
7781
|
+
});
|
|
7782
|
+
const byPath = new Map(targets.files.map((t) => [t.path, t]));
|
|
7783
|
+
const created = /* @__PURE__ */ new Map();
|
|
7784
|
+
for (const w3 of ledger.writes) {
|
|
7785
|
+
const t = byPath.get(w3.path);
|
|
7786
|
+
if (t === void 0) continue;
|
|
7787
|
+
if (!t.unitExisted) {
|
|
7788
|
+
if (w3.verdict === "create")
|
|
7789
|
+
created.set(t.unit, created.get(t.unit) === true || w3.line === LINES.restored);
|
|
7790
|
+
continue;
|
|
7791
|
+
}
|
|
7792
|
+
if (w3.verdict !== "leave") report.updated[t.label] = (report.updated[t.label] ?? 0) + 1;
|
|
7793
|
+
if (w3.verdict !== "backup+overwrite" || w3.record !== "sha") continue;
|
|
7794
|
+
if (w3.path.startsWith(".claude/skills/"))
|
|
7795
|
+
report.skillsBackedUp.push(w3.path.slice(".claude/skills/".length));
|
|
7796
|
+
else if (w3.path.startsWith(".claude/"))
|
|
7797
|
+
report.policyBackedUp.push(w3.path.slice(".claude/".length));
|
|
7798
|
+
}
|
|
7799
|
+
for (const [unit, wasRestored] of created)
|
|
7800
|
+
(wasRestored ? report.restored : report.installedNew).push(unit);
|
|
7801
|
+
return {
|
|
7802
|
+
displaced: ledger.rootFiles.filter((f) => f.change === "displaced"),
|
|
7803
|
+
restored,
|
|
7804
|
+
foreignOwned,
|
|
7805
|
+
outside: ledger.outside
|
|
7806
|
+
};
|
|
7807
|
+
}
|
|
7808
|
+
function pruneSkillExtras(projectDir, templatesDir, ids, outside, recordOf, now) {
|
|
7809
|
+
const pruned = [];
|
|
7810
|
+
const backedUp = [];
|
|
7811
|
+
for (const id of ids) {
|
|
7812
|
+
const targetSkill = join30(projectDir, ".claude/skills", id);
|
|
7813
|
+
const bundled = new Set(listFilesRecursive(join30(templatesDir, "skills", id)));
|
|
7814
|
+
for (const rel of listFilesRecursive(targetSkill)) {
|
|
7815
|
+
if (bundled.has(rel) || basename3(rel).includes(".backup-")) continue;
|
|
7816
|
+
if (foreignOwnedTarget(projectDir, `.claude/skills/${id}/${rel}`) !== null) continue;
|
|
7817
|
+
const targetFile = join30(targetSkill, rel);
|
|
7818
|
+
if (outside.skip(targetFile)) continue;
|
|
7819
|
+
const rec = recordOf(`.claude/skills/${id}/${rel}`);
|
|
7820
|
+
if (rec.state !== "sha" || hashContent(readFileSync21(targetFile, "utf8")) !== rec.sha256) {
|
|
7821
|
+
backupFile(targetFile, now);
|
|
7822
|
+
backedUp.push(`${id}/${rel}`);
|
|
7823
|
+
}
|
|
7824
|
+
unlinkSync2(targetFile);
|
|
7825
|
+
pruned.push(`${id}/${rel}`);
|
|
7826
|
+
for (let d2 = dirname7(targetFile); d2 !== targetSkill && readdirSync4(d2).length === 0; d2 = dirname7(d2))
|
|
7827
|
+
rmdirSync2(d2);
|
|
7828
|
+
}
|
|
7829
|
+
}
|
|
7830
|
+
return { pruned, backedUp };
|
|
7831
|
+
}
|
|
7832
|
+
function recordHarnessWrites(projectDir, ledger, x) {
|
|
7833
|
+
const log = readInstallLog(projectDir);
|
|
7834
|
+
if (!log) return;
|
|
7835
|
+
const skillLedger = log.skillFiles === void 0 && !x.walkedSkills ? [] : ledger.skillFiles;
|
|
7836
|
+
const policy = mergeExternalFiles(log.policyFiles, ledger.policyFiles).filter(
|
|
7837
|
+
(f) => !x.prunedPolicy.has(f.path)
|
|
7838
|
+
);
|
|
7839
|
+
const have = new Set(policy.map((f) => f.path));
|
|
7840
|
+
const next = {
|
|
7841
|
+
...log,
|
|
7842
|
+
policyFiles: [
|
|
7843
|
+
...policy,
|
|
7844
|
+
...x.claims.filter((c3) => !x.prunedPolicy.has(c3.path) && !have.has(c3.path))
|
|
7845
|
+
],
|
|
7846
|
+
skillFiles: mergeExternalFiles(log.skillFiles, skillLedger).filter(
|
|
7847
|
+
(f) => !x.prunedSkill.has(f.path)
|
|
7848
|
+
),
|
|
7849
|
+
externalFiles: mergeExternalFiles(log.externalFiles, ledger.externalFiles),
|
|
7850
|
+
rootFiles: withoutRestored(
|
|
7851
|
+
mergeRootFiles(log.rootFiles, withoutLostBackups(log.rootFiles, ledger.rootFiles)),
|
|
7852
|
+
x.restored
|
|
7853
|
+
)
|
|
7854
|
+
};
|
|
7855
|
+
for (const key of ["policyFiles", "skillFiles", "externalFiles", "rootFiles"])
|
|
7856
|
+
if (next[key]?.length === 0) delete next[key];
|
|
7857
|
+
try {
|
|
7858
|
+
writeInstallLog(projectDir, next);
|
|
7859
|
+
} catch {
|
|
7860
|
+
}
|
|
7861
|
+
}
|
|
7862
|
+
var BACKUP_SUFFIX = /\.backup-\d{8}T\d{6}(-\d+)?$/;
|
|
7863
|
+
var BACKUP_SCAN_DIRS = [
|
|
7864
|
+
...new Set(
|
|
7865
|
+
Object.values(CLI_OWNERSHIP).flat().map((owned) => owned.path).filter((path) => path.includes("/")).map((path) => path.slice(0, path.indexOf("/")))
|
|
7866
|
+
)
|
|
7867
|
+
];
|
|
7868
|
+
function collectRunBackups(projectDir, startedAt, exclude) {
|
|
7869
|
+
const out = [];
|
|
7870
|
+
const consider = (rel) => {
|
|
7871
|
+
if (!BACKUP_SUFFIX.test(rel)) return;
|
|
6998
7872
|
if (exclude?.has(rel)) return;
|
|
6999
|
-
const abs =
|
|
7873
|
+
const abs = join30(projectDir, rel);
|
|
7000
7874
|
if (statSync4(abs).mtimeMs < startedAt - 1e3) return;
|
|
7001
7875
|
out.push({ path: rel.replace(BACKUP_SUFFIX, ""), backup: rel });
|
|
7002
7876
|
};
|
|
7003
|
-
for (const e2 of
|
|
7877
|
+
for (const e2 of readdirSync4(projectDir, { withFileTypes: true }))
|
|
7004
7878
|
if (e2.isFile()) consider(e2.name);
|
|
7005
7879
|
for (const dir of BACKUP_SCAN_DIRS) {
|
|
7006
|
-
for (const rel of listFilesRecursive(
|
|
7880
|
+
for (const rel of listFilesRecursive(join30(projectDir, dir))) consider(`${dir}/${rel}`);
|
|
7007
7881
|
}
|
|
7008
7882
|
return out.sort((a, b2) => a.path.localeCompare(b2.path));
|
|
7009
7883
|
}
|
|
7010
7884
|
function writeBackupList(projectDir, backups, noChecksum = /* @__PURE__ */ new Set()) {
|
|
7011
|
-
const dir =
|
|
7012
|
-
const file =
|
|
7885
|
+
const dir = join30(projectDir, ".uzys-agent-harness");
|
|
7886
|
+
const file = join30(dir, "update-backups.json");
|
|
7013
7887
|
try {
|
|
7014
7888
|
if (backups.length === 0) {
|
|
7015
7889
|
if (existsSync21(file)) unlinkSync2(file);
|
|
7016
7890
|
return;
|
|
7017
7891
|
}
|
|
7018
7892
|
if (!existsSync21(dir)) return;
|
|
7019
|
-
|
|
7893
|
+
writeFileSync7(
|
|
7020
7894
|
file,
|
|
7021
7895
|
`${JSON.stringify(
|
|
7022
7896
|
{
|
|
@@ -7032,51 +7906,6 @@ function writeBackupList(projectDir, backups, noChecksum = /* @__PURE__ */ new S
|
|
|
7032
7906
|
} catch {
|
|
7033
7907
|
}
|
|
7034
7908
|
}
|
|
7035
|
-
function installNewSkillDirs(projectDir, templatesDir, tracks, outside) {
|
|
7036
|
-
const installed = [];
|
|
7037
|
-
const restored = [];
|
|
7038
|
-
const foreignOwned = [];
|
|
7039
|
-
const log = readInstallLog(projectDir);
|
|
7040
|
-
const priorIds = new Set((log?.skillFiles ?? []).map((f) => f.path.split("/")[0] ?? ""));
|
|
7041
|
-
const excluded = excludedIds(log);
|
|
7042
|
-
const skillExcluded = excluded;
|
|
7043
|
-
if (log !== null && !installedClis(log).includes("claude"))
|
|
7044
|
-
return { installed, restored, foreignOwned };
|
|
7045
|
-
const spec = buildAssetSpec({ tracks, options: DEFAULT_OPTIONS });
|
|
7046
|
-
for (const entry of buildManifest(spec)) {
|
|
7047
|
-
if (entry.type !== "dir" || !entry.target.startsWith(".claude/skills/")) continue;
|
|
7048
|
-
if (!entry.applies(spec) || isBaselineExcluded(entry.target, excluded)) continue;
|
|
7049
|
-
if (skillExcluded.has(entry.target.slice(".claude/skills/".length))) continue;
|
|
7050
|
-
const target = join29(projectDir, entry.target);
|
|
7051
|
-
const foreign = foreignOwnedTarget(projectDir, entry.target);
|
|
7052
|
-
if (foreign !== null) {
|
|
7053
|
-
if (!foreignOwned.includes(foreign)) foreignOwned.push(foreign);
|
|
7054
|
-
continue;
|
|
7055
|
-
}
|
|
7056
|
-
if (existsSync21(target)) continue;
|
|
7057
|
-
const source = join29(templatesDir, entry.source);
|
|
7058
|
-
if (!existsSync21(source)) continue;
|
|
7059
|
-
if (outside.skip(target)) continue;
|
|
7060
|
-
copyDir(source, target, (rel) => foreignOwnedTarget(projectDir, `${entry.target}/${rel}`));
|
|
7061
|
-
if (priorIds.has(entry.target.slice(".claude/skills/".length))) restored.push(entry.target);
|
|
7062
|
-
else installed.push(entry.target);
|
|
7063
|
-
}
|
|
7064
|
-
return { installed, restored, foreignOwned };
|
|
7065
|
-
}
|
|
7066
|
-
function recordNewSkillBaseline(projectDir, templatesDir, targets) {
|
|
7067
|
-
const log = readInstallLog(projectDir);
|
|
7068
|
-
if (!log) return;
|
|
7069
|
-
if (log.skillFiles === void 0) return;
|
|
7070
|
-
const ids = new Set(targets.map((t) => t.slice(".claude/skills/".length)));
|
|
7071
|
-
const added = collectSkillHashes(projectDir, templatesDir).filter(
|
|
7072
|
-
(f) => ids.has(f.path.split("/")[0] ?? "")
|
|
7073
|
-
);
|
|
7074
|
-
const kept = (log.skillFiles ?? []).filter((f) => !ids.has(f.path.split("/")[0] ?? ""));
|
|
7075
|
-
try {
|
|
7076
|
-
writeInstallLog(projectDir, { ...log, skillFiles: [...kept, ...added] });
|
|
7077
|
-
} catch {
|
|
7078
|
-
}
|
|
7079
|
-
}
|
|
7080
7909
|
function trackOnlyFileAssets(tracks) {
|
|
7081
7910
|
const base = { tracks, selectedInternalSkills: [] };
|
|
7082
7911
|
const optedOut = { ...base, withTauri: false };
|
|
@@ -7086,12 +7915,12 @@ function trackOnlyFileAssets(tracks) {
|
|
|
7086
7915
|
);
|
|
7087
7916
|
}
|
|
7088
7917
|
function syncHarnessAnchor(projectDir, templatesDir, report, outside, now = /* @__PURE__ */ new Date()) {
|
|
7089
|
-
if (existsSync21(
|
|
7918
|
+
if (existsSync21(join30(projectDir, LEGACY_ANCHOR_FILE2))) {
|
|
7090
7919
|
report.legacyAnchor = LEGACY_ANCHOR_FILE2;
|
|
7091
7920
|
}
|
|
7092
|
-
const templateMd =
|
|
7921
|
+
const templateMd = join30(templatesDir, "CLAUDE.md");
|
|
7093
7922
|
if (!existsSync21(templateMd)) return;
|
|
7094
|
-
const anchor =
|
|
7923
|
+
const anchor = join30(projectDir, HARNESS_ANCHOR_FILE);
|
|
7095
7924
|
if (outside.skip(anchor)) return;
|
|
7096
7925
|
const existed = existsSync21(anchor);
|
|
7097
7926
|
if (existed) {
|
|
@@ -7117,21 +7946,21 @@ function syncHarnessAnchor(projectDir, templatesDir, report, outside, now = /* @
|
|
|
7117
7946
|
recordAnchorBaseline(projectDir, anchor);
|
|
7118
7947
|
}
|
|
7119
7948
|
function upsertRootImport(projectDir, outside) {
|
|
7120
|
-
const target =
|
|
7949
|
+
const target = join30(projectDir, "CLAUDE.md");
|
|
7121
7950
|
if (outside.skip(target)) return false;
|
|
7122
7951
|
const existing = existsSync21(target) ? readFileSync21(target, "utf8") : null;
|
|
7123
7952
|
const next = upsertHarnessImport(existing, {
|
|
7124
7953
|
projectName: basename3(projectDir),
|
|
7125
7954
|
tracks: installedTracks(projectDir),
|
|
7126
|
-
// ADR-085 — update 는 선택 목록을 인자로 받지 않는다.
|
|
7955
|
+
// ADR-085 — update 는 선택 목록을 인자로 받지 않는다. 앞 단계(하네스 파일 쓰기)가 지나간 디스크로 판정한다:
|
|
7127
7956
|
// `.claude/skills/<id>` 가 있으면 그 스킬은 이 설치가 고른 것이다.
|
|
7128
7957
|
continuousSkills: CONTINUOUS_SKILLS.map((s) => s.id).filter(
|
|
7129
|
-
(id) => existsSync21(
|
|
7958
|
+
(id) => existsSync21(join30(projectDir, ".claude/skills", id))
|
|
7130
7959
|
)
|
|
7131
7960
|
});
|
|
7132
7961
|
if (next === existing) return false;
|
|
7133
7962
|
if (existing !== null) backupIfLossyUtf8(target);
|
|
7134
|
-
|
|
7963
|
+
writeFileSync7(target, next);
|
|
7135
7964
|
return true;
|
|
7136
7965
|
}
|
|
7137
7966
|
function installedTracks(projectDir) {
|
|
@@ -7161,7 +7990,7 @@ function excludedBaselineOnDisk(projectDir, log) {
|
|
|
7161
7990
|
if (excluded.size === 0) return [];
|
|
7162
7991
|
const spec = buildAssetSpec({ tracks: installedTracks(projectDir), options: DEFAULT_OPTIONS });
|
|
7163
7992
|
return buildManifest(spec).filter(
|
|
7164
|
-
(e2) => e2.applies(spec) && isBaselineExcluded(e2.target, excluded) && existsSync21(
|
|
7993
|
+
(e2) => e2.applies(spec) && isBaselineExcluded(e2.target, excluded) && existsSync21(join30(projectDir, e2.target))
|
|
7165
7994
|
).map((e2) => e2.target);
|
|
7166
7995
|
}
|
|
7167
7996
|
function excludedSkillOf(log) {
|
|
@@ -7189,23 +8018,27 @@ function recordedRenderInputs(projectDir, log) {
|
|
|
7189
8018
|
function recordedBundledSkills(projectDir, log) {
|
|
7190
8019
|
if (log === null) {
|
|
7191
8020
|
return INTERNAL_BUNDLED_SKILL_IDS.filter(
|
|
7192
|
-
(id) => existsSync21(
|
|
8021
|
+
(id) => existsSync21(join30(projectDir, ".claude/skills", id)) || existsSync21(join30(projectDir, ".agents/skills", id))
|
|
7193
8022
|
);
|
|
7194
8023
|
}
|
|
7195
8024
|
const ids = recordedSkillIds(projectDir, log);
|
|
7196
8025
|
return INTERNAL_BUNDLED_SKILL_IDS.filter((id) => ids.has(id));
|
|
7197
8026
|
}
|
|
7198
8027
|
function recordedSkillIds(projectDir, log) {
|
|
8028
|
+
const ids = claudeSkillIds(projectDir, log);
|
|
8029
|
+
for (const f of log.externalFiles ?? []) {
|
|
8030
|
+
const id = SHARED_SKILL_ID.exec(f.path)?.[1];
|
|
8031
|
+
if (id !== void 0) ids.add(id);
|
|
8032
|
+
}
|
|
8033
|
+
return ids;
|
|
8034
|
+
}
|
|
8035
|
+
function claudeSkillIds(projectDir, log) {
|
|
7199
8036
|
const isTarget = recordedTrackTargets(log);
|
|
7200
8037
|
const ids = new Set(bundledSkillTargets(projectDir, log));
|
|
7201
8038
|
for (const f of log.skillFiles ?? []) {
|
|
7202
8039
|
const id = f.path.split("/")[0] ?? "";
|
|
7203
8040
|
if (recorded(log, `.claude/skills/${f.path}`, { isTarget }).state !== "none") ids.add(id);
|
|
7204
8041
|
}
|
|
7205
|
-
for (const f of log.externalFiles ?? []) {
|
|
7206
|
-
const id = SHARED_SKILL_ID.exec(f.path)?.[1];
|
|
7207
|
-
if (id !== void 0) ids.add(id);
|
|
7208
|
-
}
|
|
7209
8042
|
return ids;
|
|
7210
8043
|
}
|
|
7211
8044
|
var SHARED_SKILL_ID = /^\.agents\/skills\/([^/]+)\//;
|
|
@@ -7236,9 +8069,9 @@ var SHARED_SKILLS_DIR = ".agents/skills";
|
|
|
7236
8069
|
var SHARED_SKILL_FILE = /^\.agents\/skills\/([^/]+)\//;
|
|
7237
8070
|
var SHARED_SKILL_MD = /^\.agents\/skills\/([^/]+)\/SKILL\.md$/;
|
|
7238
8071
|
function sharedSkillIdsOnDisk(projectDir) {
|
|
7239
|
-
const root =
|
|
8072
|
+
const root = join30(projectDir, SHARED_SKILLS_DIR);
|
|
7240
8073
|
if (!existsSync21(root)) return /* @__PURE__ */ new Set();
|
|
7241
|
-
return new Set(
|
|
8074
|
+
return new Set(readdirSync4(root).filter((id) => existsSync21(join30(root, id, "SKILL.md"))));
|
|
7242
8075
|
}
|
|
7243
8076
|
var CREATED_SHARED_HOW = {
|
|
7244
8077
|
"opencode.json": "created from template (harness part + template defaults)",
|
|
@@ -7265,14 +8098,14 @@ function refreshExternalCli(projectDir, harnessRoot, droppedKeys, harnessMcp) {
|
|
|
7265
8098
|
const log = readInstallLog(projectDir);
|
|
7266
8099
|
const presentBefore = sharedSkillIdsOnDisk(projectDir);
|
|
7267
8100
|
const rulesBefore = /* @__PURE__ */ new Set();
|
|
7268
|
-
const rulesDir =
|
|
8101
|
+
const rulesDir = join30(projectDir, ".agents", "rules");
|
|
7269
8102
|
if (existsSync21(rulesDir)) {
|
|
7270
8103
|
try {
|
|
7271
|
-
for (const f of
|
|
8104
|
+
for (const f of readdirSync4(rulesDir)) rulesBefore.add(f);
|
|
7272
8105
|
} catch {
|
|
7273
8106
|
}
|
|
7274
8107
|
}
|
|
7275
|
-
const agentsMdBefore = existsSync21(
|
|
8108
|
+
const agentsMdBefore = existsSync21(join30(projectDir, "AGENTS.md"));
|
|
7276
8109
|
const result = runCliTransforms({
|
|
7277
8110
|
harnessRoot,
|
|
7278
8111
|
projectDir,
|
|
@@ -7290,9 +8123,11 @@ function refreshExternalCli(projectDir, harnessRoot, droppedKeys, harnessMcp) {
|
|
|
7290
8123
|
// 기록 없음: CLI 경로로는 도달 불가 — 진입 판정(#699)이 먼저 거절. 엔진 단위 방어(빈 집합).
|
|
7291
8124
|
recordedClis: log === null ? [] : installedClis(log),
|
|
7292
8125
|
// #761 B-1 — 외부 기록이 아예 없던 옛 판의 산출물은 첫 접촉이 아니라 체크섬 없는 하네스 파일이다(install 과 같은 판정).
|
|
7293
|
-
// 앞 단계(
|
|
8126
|
+
// 앞 단계(하네스 파일 쓰기)가 헬퍼만 든 `externalFiles` 를 적어도 같은 답이다 — 헬퍼는 외부 자리로 세지 않는다(B-2)
|
|
7294
8127
|
owned: recordedOwner(log)
|
|
7295
8128
|
});
|
|
8129
|
+
const anchorPath = result.anchorRetired?.action === "removed" ? result.anchorRetired.path : null;
|
|
8130
|
+
const anchorDisplaced = log === null || anchorPath === null ? [] : restoreDisplaced(log, projectDir, { has: (p2) => p2 === anchorPath, write: true });
|
|
7296
8131
|
if (log) {
|
|
7297
8132
|
const retiredPath = result.anchorRetired?.forget === true ? result.anchorRetired.path : null;
|
|
7298
8133
|
const merged = mergeExternalFiles(log.externalFiles, result.externalFiles).filter(
|
|
@@ -7311,6 +8146,8 @@ function refreshExternalCli(projectDir, harnessRoot, droppedKeys, harnessMcp) {
|
|
|
7311
8146
|
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
8147
|
const roots = [...created, ...withoutLostBackups(log.rootFiles, result.displaced ?? [])];
|
|
7313
8148
|
if (roots.length > 0) next.rootFiles = mergeRootFiles(log.rootFiles, roots);
|
|
8149
|
+
if (anchorDisplaced.some((d2) => d2.forget))
|
|
8150
|
+
next.rootFiles = withoutRestored(next.rootFiles, anchorDisplaced);
|
|
7314
8151
|
try {
|
|
7315
8152
|
writeInstallLog(projectDir, next);
|
|
7316
8153
|
} catch {
|
|
@@ -7390,7 +8227,10 @@ function refreshExternalCli(projectDir, harnessRoot, droppedKeys, harnessMcp) {
|
|
|
7390
8227
|
)
|
|
7391
8228
|
],
|
|
7392
8229
|
anchorRetired: result.anchorRetired,
|
|
8230
|
+
anchorDisplaced,
|
|
7393
8231
|
agentsMd: agentsMdNews(result.agentsMd, agentsMdBefore, priorPaths),
|
|
8232
|
+
agentsMdLegacyDropped: result.agentsMd?.agentsMd.droppedLegacySections ?? 0,
|
|
8233
|
+
agentsMdLegacyEdited: result.agentsMd?.agentsMd.editedLegacySections ?? [],
|
|
7394
8234
|
// #625 — install 화면(`sharedRow`)이 말하는 "남긴 것" 을 update 도 말한다. 고친 구간과 기록이 없어 모르는 구간은
|
|
7395
8235
|
// 다른 사실이라 기록(`portions`)으로 가른다 — 어댑터는 기록된 키가 고쳐졌으면 남기고 기록 sha 를 잇는다(계약 ⓑ)
|
|
7396
8236
|
sharedLeft: result.sharedFiles.filter((f) => f.action === "left" || f.leftAsIs.length + f.kept.length > 0).map((f) => {
|
|
@@ -7410,233 +8250,33 @@ function refreshExternalCli(projectDir, harnessRoot, droppedKeys, harnessMcp) {
|
|
|
7410
8250
|
})
|
|
7411
8251
|
};
|
|
7412
8252
|
}
|
|
7413
|
-
function updateDir(target, source, ext, ctx, now = /* @__PURE__ */ new Date()) {
|
|
7414
|
-
if (!existsSync21(target) || !existsSync21(source))
|
|
7415
|
-
return { updated: 0, backedUp: [], displaced: [] };
|
|
7416
|
-
let updated = 0;
|
|
7417
|
-
const backedUp = [];
|
|
7418
|
-
const displaced = [];
|
|
7419
|
-
for (const file of readdirSync3(target)) {
|
|
7420
|
-
if (!file.endsWith(ext)) continue;
|
|
7421
|
-
const targetFile = join29(target, file);
|
|
7422
|
-
const sourceFile = join29(source, file);
|
|
7423
|
-
if (!existsSync21(sourceFile)) continue;
|
|
7424
|
-
if (ctx.outside?.skip(targetFile)) continue;
|
|
7425
|
-
const projectRel = `.claude/${ctx.prefix}/${file}`;
|
|
7426
|
-
if (ctx.excluded && isBaselineExcluded(projectRel, ctx.excluded)) continue;
|
|
7427
|
-
if (ctx.justWritten?.has(projectRel)) continue;
|
|
7428
|
-
const next = readFileSync21(sourceFile, "utf8");
|
|
7429
|
-
const rec = ctx.recordOf?.(projectRel) ?? baselineRecord(ctx.baseline, `${ctx.prefix}/${file}`);
|
|
7430
|
-
const w3 = judgedUpdateWrite(targetFile, rec, next, now);
|
|
7431
|
-
if (w3.changed) updated++;
|
|
7432
|
-
if (w3.kind === "edited") backedUp.push(`${ctx.prefix}/${file}`);
|
|
7433
|
-
const d2 = displacedEntry(w3, projectRel, targetFile);
|
|
7434
|
-
if (d2 !== null) displaced.push(d2);
|
|
7435
|
-
}
|
|
7436
|
-
return { updated, backedUp, displaced };
|
|
7437
|
-
}
|
|
7438
|
-
function syncSkills(targetDir, sourceDir, baseline, now = /* @__PURE__ */ new Date(), foreignOf, outside, excludedSkill, opts = {}) {
|
|
7439
|
-
if (!existsSync21(targetDir) || !existsSync21(sourceDir))
|
|
7440
|
-
return {
|
|
7441
|
-
updated: 0,
|
|
7442
|
-
backedUp: [],
|
|
7443
|
-
skippedLinks: [],
|
|
7444
|
-
foreignOwned: [],
|
|
7445
|
-
pruned: [],
|
|
7446
|
-
displaced: []
|
|
7447
|
-
};
|
|
7448
|
-
let updated = 0;
|
|
7449
|
-
const backedUp = [];
|
|
7450
|
-
const skippedLinks = [];
|
|
7451
|
-
const foreignOwned = [];
|
|
7452
|
-
const pruned = [];
|
|
7453
|
-
const displaced = [];
|
|
7454
|
-
for (const skill of readdirSync3(sourceDir, { withFileTypes: true })) {
|
|
7455
|
-
if (!skill.isDirectory()) continue;
|
|
7456
|
-
const targetSkill = join29(targetDir, skill.name);
|
|
7457
|
-
if (occupiedByNonDirectory(targetSkill)) {
|
|
7458
|
-
skippedLinks.push(skill.name);
|
|
7459
|
-
continue;
|
|
7460
|
-
}
|
|
7461
|
-
if (opts.targets !== void 0 && !opts.targets.has(skill.name)) continue;
|
|
7462
|
-
if (!existsSync21(targetSkill)) continue;
|
|
7463
|
-
if (excludedSkill?.(skill.name)) continue;
|
|
7464
|
-
for (const rel of listFilesRecursive(join29(sourceDir, skill.name))) {
|
|
7465
|
-
const targetFile = join29(targetSkill, rel);
|
|
7466
|
-
const foreign = foreignOf(`${skill.name}/${rel}`);
|
|
7467
|
-
if (foreign !== null) {
|
|
7468
|
-
if (!foreignOwned.includes(foreign)) foreignOwned.push(foreign);
|
|
7469
|
-
continue;
|
|
7470
|
-
}
|
|
7471
|
-
if (outside?.skip(targetFile)) continue;
|
|
7472
|
-
const next = readFileSync21(join29(sourceDir, skill.name, rel), "utf8");
|
|
7473
|
-
const projectRel = `.claude/skills/${skill.name}/${rel}`;
|
|
7474
|
-
const rec = opts.recordOf?.(projectRel) ?? baselineRecord(baseline, `${skill.name}/${rel}`);
|
|
7475
|
-
const w3 = judgedUpdateWrite(targetFile, rec, next, now);
|
|
7476
|
-
if (w3.changed) updated++;
|
|
7477
|
-
if (w3.kind === "edited") backedUp.push(`${skill.name}/${rel}`);
|
|
7478
|
-
const d2 = displacedEntry(w3, projectRel, targetFile);
|
|
7479
|
-
if (d2 !== null) displaced.push(d2);
|
|
7480
|
-
}
|
|
7481
|
-
const bundled = new Set(listFilesRecursive(join29(sourceDir, skill.name)));
|
|
7482
|
-
for (const rel of listFilesRecursive(targetSkill)) {
|
|
7483
|
-
if (bundled.has(rel) || basename3(rel).includes(".backup-")) continue;
|
|
7484
|
-
if (foreignOf(`${skill.name}/${rel}`) !== null) continue;
|
|
7485
|
-
const targetFile = join29(targetSkill, rel);
|
|
7486
|
-
if (outside?.skip(targetFile)) continue;
|
|
7487
|
-
const rec = opts.recordOf?.(`.claude/skills/${skill.name}/${rel}`) ?? baselineRecord(baseline, `${skill.name}/${rel}`);
|
|
7488
|
-
if (rec.state !== "sha" || hashContent(readFileSync21(targetFile, "utf8")) !== rec.sha256) {
|
|
7489
|
-
backupFile(targetFile, now);
|
|
7490
|
-
backedUp.push(`${skill.name}/${rel}`);
|
|
7491
|
-
}
|
|
7492
|
-
unlinkSync2(targetFile);
|
|
7493
|
-
pruned.push(`${skill.name}/${rel}`);
|
|
7494
|
-
for (let d2 = dirname6(targetFile); d2 !== targetSkill && readdirSync3(d2).length === 0; d2 = dirname6(d2))
|
|
7495
|
-
rmdirSync(d2);
|
|
7496
|
-
}
|
|
7497
|
-
}
|
|
7498
|
-
return { updated, backedUp, skippedLinks, foreignOwned, pruned, displaced };
|
|
7499
|
-
}
|
|
7500
|
-
function judgedUpdateWrite(abs, rec, next, now) {
|
|
7501
|
-
const disk = existsSync21(abs) ? readFileSync21(abs, "utf8") : null;
|
|
7502
|
-
const j4 = judge({ op: "write", kind: "harness", rec, disk, next, run: "update" });
|
|
7503
|
-
let backup;
|
|
7504
|
-
switch (j4.verdict) {
|
|
7505
|
-
case "leave":
|
|
7506
|
-
break;
|
|
7507
|
-
case "create":
|
|
7508
|
-
mkdirSync6(dirname6(abs), { recursive: true });
|
|
7509
|
-
writeFileSync8(abs, next);
|
|
7510
|
-
break;
|
|
7511
|
-
case "overwrite":
|
|
7512
|
-
writeFileSync8(abs, next);
|
|
7513
|
-
break;
|
|
7514
|
-
case "backup+overwrite":
|
|
7515
|
-
backup = backupFile(abs, now);
|
|
7516
|
-
writeFileSync8(abs, next);
|
|
7517
|
-
break;
|
|
7518
|
-
default:
|
|
7519
|
-
throw new Error(`update: '${j4.verdict}' is not a write verdict (${abs})`);
|
|
7520
|
-
}
|
|
7521
|
-
const changed = j4.verdict !== "leave";
|
|
7522
|
-
if (j4.record === "displaced") return { kind: "displacedSame", changed };
|
|
7523
|
-
if (backup === void 0) return { kind: changed ? "written" : "same", changed };
|
|
7524
|
-
return { kind: j4.record === "displaced+sha" ? "displaced" : "edited", changed, backup };
|
|
7525
|
-
}
|
|
7526
|
-
function displacedEntry(w3, projectRel, abs) {
|
|
7527
|
-
if (w3.kind === "displacedSame") return { path: projectRel, change: "displaced", notes: [] };
|
|
7528
|
-
if (w3.kind !== "displaced" || w3.backup === void 0) return null;
|
|
7529
|
-
const backupRel = `${projectRel}${w3.backup.slice(abs.length)}`;
|
|
7530
|
-
return { path: projectRel, change: "displaced", notes: [backupRel] };
|
|
7531
|
-
}
|
|
7532
|
-
function baselineRecord(baseline, key) {
|
|
7533
|
-
const sha256 = baseline.get(key);
|
|
7534
|
-
return sha256 === void 0 ? { state: "no-sha" } : { state: "sha", sha256 };
|
|
7535
|
-
}
|
|
7536
|
-
function recordedStateOf(log) {
|
|
7537
|
-
if (log === null) return void 0;
|
|
7538
|
-
const isTarget = recordedTrackTargets(log);
|
|
7539
|
-
return (projectRel) => recorded(log, projectRel, { isTarget });
|
|
7540
|
-
}
|
|
7541
|
-
function notOursUnder(displaced, prefix) {
|
|
7542
|
-
return new Set(
|
|
7543
|
-
displaced.filter((f) => f.notes.length === 0 && f.path.startsWith(prefix)).map((f) => f.path.slice(prefix.length))
|
|
7544
|
-
);
|
|
7545
|
-
}
|
|
7546
8253
|
function withoutLostBackups(prior, add) {
|
|
7547
8254
|
const backedUp = new Set(
|
|
7548
8255
|
(prior ?? []).filter((f) => f.change === "displaced" && f.notes.length > 0).map((f) => f.path)
|
|
7549
8256
|
);
|
|
7550
8257
|
return add.filter((f) => f.notes.length > 0 || !backedUp.has(f.path));
|
|
7551
8258
|
}
|
|
7552
|
-
function
|
|
7553
|
-
const log = readInstallLog(projectDir);
|
|
7554
|
-
if (!log) return;
|
|
7555
|
-
const add = withoutLostBackups(log.rootFiles, displaced);
|
|
7556
|
-
if (add.length === 0) return;
|
|
7557
|
-
try {
|
|
7558
|
-
writeInstallLog(projectDir, { ...log, rootFiles: mergeRootFiles(log.rootFiles, add) });
|
|
7559
|
-
} catch {
|
|
7560
|
-
}
|
|
7561
|
-
}
|
|
7562
|
-
function skillBaseline(projectDir) {
|
|
7563
|
-
const log = readInstallLog(projectDir);
|
|
7564
|
-
return new Map((log?.skillFiles ?? []).map((f) => [f.path, f.sha256]));
|
|
7565
|
-
}
|
|
7566
|
-
function policyBaseline(projectDir) {
|
|
7567
|
-
const log = readInstallLog(projectDir);
|
|
7568
|
-
return new Map((log?.policyFiles ?? []).map((f) => [f.path, f.sha256]));
|
|
7569
|
-
}
|
|
7570
|
-
function refreshPolicyBaseline(projectDir, templatesDir, dirs, outside, notOurs = /* @__PURE__ */ new Set()) {
|
|
7571
|
-
const log = readInstallLog(projectDir);
|
|
7572
|
-
if (!log) return;
|
|
7573
|
-
const excluded = excludedIds(log);
|
|
7574
|
-
const inDirs = (path) => (dirs === void 0 || dirs.some((d2) => path.startsWith(`${d2}/`))) && !outside.has(path) && !isBaselineExcluded(`.claude/${path}`, excluded);
|
|
7575
|
-
const rewritten = [
|
|
7576
|
-
...(log.policyFiles ?? []).filter((f) => !inDirs(f.path)),
|
|
7577
|
-
...collectPolicyHashes(projectDir, templatesDir).filter(
|
|
7578
|
-
(f) => inDirs(f.path) && !notOurs.has(f.path)
|
|
7579
|
-
)
|
|
7580
|
-
];
|
|
7581
|
-
const policyFiles = [...rewritten, ...retiredClaims(log, projectDir, rewritten)];
|
|
7582
|
-
const next = { ...log };
|
|
7583
|
-
if (policyFiles.length > 0) next.policyFiles = policyFiles;
|
|
7584
|
-
else delete next.policyFiles;
|
|
7585
|
-
try {
|
|
7586
|
-
writeInstallLog(projectDir, next);
|
|
7587
|
-
} catch {
|
|
7588
|
-
}
|
|
7589
|
-
}
|
|
7590
|
-
function outsidePaths(outside, prefix) {
|
|
7591
|
-
return new Set(
|
|
7592
|
-
outside.list().filter((o) => o.path.startsWith(prefix)).map((o) => o.path.slice(prefix.length))
|
|
7593
|
-
);
|
|
7594
|
-
}
|
|
7595
|
-
function refreshSkillBaseline(projectDir, templatesDir, outside, targets, notOurs = /* @__PURE__ */ new Set()) {
|
|
7596
|
-
const log = readInstallLog(projectDir);
|
|
7597
|
-
if (!log) return;
|
|
7598
|
-
const excludedSkill = excludedSkillOf(log);
|
|
7599
|
-
const keepPrior = (path) => outside.has(path) || excludedSkill(path.split("/")[0] ?? "");
|
|
7600
|
-
const ours = (path) => (targets === void 0 || targets.has(path.split("/")[0] ?? "")) && !notOurs.has(path);
|
|
7601
|
-
const skillFiles = [
|
|
7602
|
-
...collectSkillHashes(projectDir, templatesDir).filter(
|
|
7603
|
-
(f) => !keepPrior(f.path) && ours(f.path)
|
|
7604
|
-
),
|
|
7605
|
-
...(log.skillFiles ?? []).filter((f) => keepPrior(f.path))
|
|
7606
|
-
];
|
|
7607
|
-
const next = { ...log };
|
|
7608
|
-
if (skillFiles.length > 0) next.skillFiles = skillFiles;
|
|
7609
|
-
else delete next.skillFiles;
|
|
7610
|
-
try {
|
|
7611
|
-
writeInstallLog(projectDir, next);
|
|
7612
|
-
} catch {
|
|
7613
|
-
}
|
|
7614
|
-
}
|
|
7615
|
-
function pruneOrphans(target, source, ext, ctx, now = /* @__PURE__ */ new Date()) {
|
|
8259
|
+
function pruneOrphans(target, source, ext, ctx, now) {
|
|
7616
8260
|
if (!existsSync21(target) || !existsSync21(source)) return [];
|
|
7617
8261
|
const removed = [];
|
|
7618
|
-
for (const file of
|
|
7619
|
-
if (!file.endsWith(ext)) continue;
|
|
7620
|
-
const
|
|
7621
|
-
|
|
7622
|
-
|
|
7623
|
-
const
|
|
7624
|
-
|
|
7625
|
-
if (ctx.outside
|
|
7626
|
-
|
|
7627
|
-
|
|
7628
|
-
|
|
7629
|
-
|
|
7630
|
-
unlinkSync2(targetFile);
|
|
7631
|
-
removed.push(file);
|
|
7632
|
-
} catch {
|
|
7633
|
-
}
|
|
8262
|
+
for (const file of readdirSync4(target)) {
|
|
8263
|
+
if (!file.endsWith(ext) || existsSync21(join30(source, file))) continue;
|
|
8264
|
+
const targetFile = join30(target, file);
|
|
8265
|
+
const rec = ctx.recordOf(`.claude/${ctx.prefix}/${file}`);
|
|
8266
|
+
try {
|
|
8267
|
+
const disk = readFileSync21(targetFile, "utf8");
|
|
8268
|
+
const { verdict } = judge({ op: "remove", kind: "harness", rec, disk, next: null });
|
|
8269
|
+
if (verdict === "leave" || ctx.outside.skip(targetFile)) continue;
|
|
8270
|
+
if (verdict === "backup+remove") backupFile(targetFile, now);
|
|
8271
|
+
unlinkSync2(targetFile);
|
|
8272
|
+
removed.push(file);
|
|
8273
|
+
} catch {
|
|
7634
8274
|
}
|
|
7635
8275
|
}
|
|
7636
8276
|
return removed;
|
|
7637
8277
|
}
|
|
7638
8278
|
function retireMcpAllowlist(projectDir, now = /* @__PURE__ */ new Date()) {
|
|
7639
|
-
const target =
|
|
8279
|
+
const target = join30(projectDir, ".mcp-allowlist");
|
|
7640
8280
|
if (!existsSync21(target)) return null;
|
|
7641
8281
|
try {
|
|
7642
8282
|
const backup = backupFile(target, now);
|
|
@@ -7646,53 +8286,6 @@ function retireMcpAllowlist(projectDir, now = /* @__PURE__ */ new Date()) {
|
|
|
7646
8286
|
return null;
|
|
7647
8287
|
}
|
|
7648
8288
|
}
|
|
7649
|
-
function refreshNeutralHelpers(projectDir, templatesDir, report) {
|
|
7650
|
-
const spec = buildAssetSpec({ tracks: installedTracks(projectDir), options: DEFAULT_OPTIONS });
|
|
7651
|
-
const refreshed = /* @__PURE__ */ new Map();
|
|
7652
|
-
for (const entry of buildManifest(spec)) {
|
|
7653
|
-
if (entry.type !== "file" || !isCliNeutralTarget(entry.target)) continue;
|
|
7654
|
-
if (!entry.applies(spec)) continue;
|
|
7655
|
-
const abs = join29(projectDir, entry.target);
|
|
7656
|
-
const source = join29(templatesDir, entry.source);
|
|
7657
|
-
if (!existsSync21(source)) continue;
|
|
7658
|
-
let st2;
|
|
7659
|
-
try {
|
|
7660
|
-
st2 = lstatSync4(abs);
|
|
7661
|
-
} catch {
|
|
7662
|
-
continue;
|
|
7663
|
-
}
|
|
7664
|
-
if (st2.isSymbolicLink()) {
|
|
7665
|
-
report.helpersKept = [...report.helpersKept ?? [], entry.target];
|
|
7666
|
-
continue;
|
|
7667
|
-
}
|
|
7668
|
-
if (!st2.isFile()) continue;
|
|
7669
|
-
const log2 = readInstallLog(projectDir);
|
|
7670
|
-
const recorded2 = (log2?.externalFiles ?? []).find((f) => f.path === entry.target);
|
|
7671
|
-
const diskSha = hashContent(readFileSync21(abs, "utf8"));
|
|
7672
|
-
const freshContent = readFileSync21(source, "utf8");
|
|
7673
|
-
const freshSha = hashContent(freshContent);
|
|
7674
|
-
if (diskSha === freshSha) {
|
|
7675
|
-
if (recorded2?.sha256 !== freshSha) refreshed.set(entry.target, freshSha);
|
|
7676
|
-
continue;
|
|
7677
|
-
}
|
|
7678
|
-
if (recorded2 === void 0 || recorded2.sha256 !== diskSha) backupFile(abs);
|
|
7679
|
-
writeFileSync8(abs, freshContent, "utf8");
|
|
7680
|
-
refreshed.set(entry.target, freshSha);
|
|
7681
|
-
report.updated[entry.target] = (report.updated[entry.target] ?? 0) + 1;
|
|
7682
|
-
}
|
|
7683
|
-
if (refreshed.size === 0) return;
|
|
7684
|
-
const log = readInstallLog(projectDir);
|
|
7685
|
-
if (log === null) return;
|
|
7686
|
-
const next = (log.externalFiles ?? []).map(
|
|
7687
|
-
(f) => refreshed.has(f.path) ? { ...f, sha256: refreshed.get(f.path) } : f
|
|
7688
|
-
);
|
|
7689
|
-
for (const [path, sha256] of refreshed)
|
|
7690
|
-
if (!next.some((f) => f.path === path)) next.push({ path, sha256 });
|
|
7691
|
-
try {
|
|
7692
|
-
writeInstallLog(projectDir, { ...log, externalFiles: next });
|
|
7693
|
-
} catch {
|
|
7694
|
-
}
|
|
7695
|
-
}
|
|
7696
8289
|
function recordClaudeCommand(log, tracks) {
|
|
7697
8290
|
const trackArgs = (tracks.length > 0 ? tracks : log.spec.tracks).map((t) => `--track ${t}`);
|
|
7698
8291
|
return `agent-harness install ${trackArgs.join(" ")} --cli claude --scope ${log.scope}`.replace(
|
|
@@ -7705,11 +8298,11 @@ function recordClaudeCommand(log, tracks) {
|
|
|
7705
8298
|
function runInstall(ctx) {
|
|
7706
8299
|
const { harnessRoot, projectDir } = ctx;
|
|
7707
8300
|
const mode = ctx.mode ?? "fresh";
|
|
7708
|
-
const templatesDir =
|
|
8301
|
+
const templatesDir = join31(harnessRoot, "templates");
|
|
7709
8302
|
if (!existsSync22(templatesDir)) {
|
|
7710
8303
|
throw new Error(`Templates dir not found: ${templatesDir}`);
|
|
7711
8304
|
}
|
|
7712
|
-
const claudeDir =
|
|
8305
|
+
const claudeDir = join31(projectDir, ".claude");
|
|
7713
8306
|
const previousLog = readInstallLog(projectDir);
|
|
7714
8307
|
const legacyAnchor = mode === "update" ? null : legacyAnchorTrace(projectDir, ctx.spec);
|
|
7715
8308
|
if (mode === "update" && previousLog === null) {
|
|
@@ -7734,13 +8327,13 @@ function runInstall(ctx) {
|
|
|
7734
8327
|
const manifestSpec = buildManifestSpec(spec);
|
|
7735
8328
|
const baselineExcluded = new Set(spec.baselineExclude ?? []);
|
|
7736
8329
|
if (spec.cli.includes("claude")) {
|
|
7737
|
-
const settingsPath =
|
|
8330
|
+
const settingsPath = join31(projectDir, ".claude", "settings.json");
|
|
7738
8331
|
if (existsSync22(settingsPath)) {
|
|
7739
8332
|
try {
|
|
7740
8333
|
JSON.parse(readFileSync22(settingsPath, "utf8"));
|
|
7741
8334
|
} catch {
|
|
7742
8335
|
throw new Error(
|
|
7743
|
-
`${
|
|
8336
|
+
`${relative5(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
8337
|
);
|
|
7745
8338
|
}
|
|
7746
8339
|
}
|
|
@@ -7874,10 +8467,17 @@ function runInstallStages(ctx, args) {
|
|
|
7874
8467
|
...outOfTrack.forget,
|
|
7875
8468
|
...anchorRetired?.forget === true ? [anchorRetired.path] : []
|
|
7876
8469
|
]);
|
|
8470
|
+
const left = /* @__PURE__ */ new Set([
|
|
8471
|
+
...outOfTrack.removed,
|
|
8472
|
+
...outOfTrack.backedUp.map((b2) => b2.path),
|
|
8473
|
+
...anchorRetired?.action === "removed" ? [anchorRetired.path] : []
|
|
8474
|
+
]);
|
|
8475
|
+
const displacedRestored = previousLog === null || left.size === 0 ? [] : restoreDisplaced(previousLog, projectDir, { has: (p2) => left.has(p2), write: true });
|
|
7877
8476
|
const logBase = previousLog === null || forgotten.size === 0 ? previousLog : {
|
|
7878
8477
|
...previousLog,
|
|
7879
8478
|
spec: { ...previousLog.spec, clis: [...installedClis(previousLog)] },
|
|
7880
|
-
externalFiles: (previousLog.externalFiles ?? []).filter((f) => !forgotten.has(f.path))
|
|
8479
|
+
externalFiles: (previousLog.externalFiles ?? []).filter((f) => !forgotten.has(f.path)),
|
|
8480
|
+
...displacedRestored.some((d2) => d2.forget) ? { rootFiles: withoutRestored(previousLog.rootFiles, displacedRestored) } : {}
|
|
7881
8481
|
};
|
|
7882
8482
|
stage.envExampleCreated = writeEnvExample(projectDir, spec.tracks);
|
|
7883
8483
|
const envFiles = writeEnvironmentFiles(writer, stage.envExampleCreated, previousLog);
|
|
@@ -7937,10 +8537,15 @@ function runInstallStages(ctx, args) {
|
|
|
7937
8537
|
linked.outside,
|
|
7938
8538
|
reclaimOutside.list()
|
|
7939
8539
|
),
|
|
7940
|
-
...outOfTrack.removed.length + outOfTrack.backedUp.length + outOfTrack.kept.length > 0 ? { outOfTrack } : {}
|
|
8540
|
+
...outOfTrack.removed.length + outOfTrack.backedUp.length + outOfTrack.kept.length > 0 ? { outOfTrack } : {},
|
|
8541
|
+
...displacedRestored.length > 0 ? { displacedRestored } : {}
|
|
7941
8542
|
};
|
|
7942
8543
|
ctx.onProgress?.({ type: "baseline-complete", baseline });
|
|
7943
|
-
const {
|
|
8544
|
+
const {
|
|
8545
|
+
report: external,
|
|
8546
|
+
backups: externalSkillBackups,
|
|
8547
|
+
displaced: externalSkillDisplaced
|
|
8548
|
+
} = runExternalPhase(ctx, previousLog);
|
|
7944
8549
|
writeInstallLogSafe(
|
|
7945
8550
|
ctx,
|
|
7946
8551
|
// 링크 본문의 기준선도 같은 필드다 — 같은 경로면 뒤(이번에 쓴 값)가 이긴다.
|
|
@@ -7956,7 +8561,9 @@ function runInstallStages(ctx, args) {
|
|
|
7956
8561
|
...cliSharedFiles.filter((f) => f.createdAsRoot === true).map((f) => ({ path: f.path, change: "created", notes: ["\uD558\uB124\uC2A4 \uBAAB\uB9CC(\uBE14\uB85D)"] })),
|
|
7957
8562
|
// #761 — 외부 변환 · 링크 본문이 첫 접촉으로 비켜 둔 설치자 파일. 하네스가 떠날 때 되돌리는 근거다
|
|
7958
8563
|
...cliDisplaced,
|
|
7959
|
-
...linked.displaced
|
|
8564
|
+
...linked.displaced,
|
|
8565
|
+
// #780 — 외부 스킬 도구가 덮은 설치자 파일. 그 자리의 도구 파일은 `buildAssetEntries` 가 이 경로로 자산 몫에 넣는다
|
|
8566
|
+
...externalSkillDisplaced
|
|
7960
8567
|
],
|
|
7961
8568
|
cliTransforms.codexOptIn
|
|
7962
8569
|
);
|
|
@@ -8018,7 +8625,7 @@ function releasedThisRun(args) {
|
|
|
8018
8625
|
}
|
|
8019
8626
|
if (id.startsWith(BASELINE_PREFIX)) {
|
|
8020
8627
|
const again2 = manifest.some(
|
|
8021
|
-
(e2) => e2.applies(manifestSpec) && classifyBaselineTarget(e2.target)?.id === id && existsSync22(
|
|
8628
|
+
(e2) => e2.applies(manifestSpec) && classifyBaselineTarget(e2.target)?.id === id && existsSync22(join31(projectDir, e2.target))
|
|
8022
8629
|
);
|
|
8023
8630
|
return { id, again: again2, tail: "the harness manages it again" };
|
|
8024
8631
|
}
|
|
@@ -8027,7 +8634,7 @@ function releasedThisRun(args) {
|
|
|
8027
8634
|
options: spec.options,
|
|
8028
8635
|
...spec.userOverride ? { userOverride: spec.userOverride } : {}
|
|
8029
8636
|
});
|
|
8030
|
-
const recorded2 = (previousLog?.assets.some((a) => a.id === id) ?? false) || [".claude/skills", ".agents/skills"].some((d2) => existsSync22(
|
|
8637
|
+
const recorded2 = (previousLog?.assets.some((a) => a.id === id) ?? false) || [".claude/skills", ".agents/skills"].some((d2) => existsSync22(join31(projectDir, d2, id)));
|
|
8031
8638
|
return {
|
|
8032
8639
|
id,
|
|
8033
8640
|
again,
|
|
@@ -8039,10 +8646,10 @@ function pendingKeyExcludes(projectDir, keyExclude, touched) {
|
|
|
8039
8646
|
const done = new Set(touched);
|
|
8040
8647
|
return keyExclude.flatMap((id) => {
|
|
8041
8648
|
const path = sharedPathOfKeyId(id);
|
|
8042
|
-
if (path === null || done.has(path) || !existsSync22(
|
|
8649
|
+
if (path === null || done.has(path) || !existsSync22(join31(projectDir, path))) return [];
|
|
8043
8650
|
const name = adapterFor(path);
|
|
8044
8651
|
const keys = [...excludedKeys(path, [id])];
|
|
8045
|
-
const present2 = name === null ? null : ADAPTERS[name].read(readFileSync22(
|
|
8652
|
+
const present2 = name === null ? null : ADAPTERS[name].read(readFileSync22(join31(projectDir, path), "utf8"), keys, projectDir);
|
|
8046
8653
|
return present2 !== null && present2.size === 0 ? [] : [{ id, path }];
|
|
8047
8654
|
});
|
|
8048
8655
|
}
|
|
@@ -8086,7 +8693,7 @@ function installCliNeutralAssets(manifestSpec, templatesDir, baselineExcluded, w
|
|
|
8086
8693
|
continue;
|
|
8087
8694
|
}
|
|
8088
8695
|
if (!isCliNeutralTarget(entry.target)) continue;
|
|
8089
|
-
const source =
|
|
8696
|
+
const source = join31(templatesDir, entry.source);
|
|
8090
8697
|
if (!existsSync22(source)) {
|
|
8091
8698
|
result.skipped += 1;
|
|
8092
8699
|
continue;
|
|
@@ -8107,13 +8714,13 @@ function installClaudeBaseline(manifestSpec, projectDir, templatesDir, baselineE
|
|
|
8107
8714
|
if (!entry.applies(manifestSpec)) {
|
|
8108
8715
|
continue;
|
|
8109
8716
|
}
|
|
8110
|
-
const target =
|
|
8717
|
+
const target = join31(projectDir, entry.target);
|
|
8111
8718
|
if (isBaselineExcluded(entry.target, baselineExcluded)) {
|
|
8112
8719
|
result.excluded.push(entry.target);
|
|
8113
8720
|
if (existsSync22(target)) result.excludedOnDisk.push(entry.target);
|
|
8114
8721
|
continue;
|
|
8115
8722
|
}
|
|
8116
|
-
const source =
|
|
8723
|
+
const source = join31(templatesDir, entry.source);
|
|
8117
8724
|
if (!existsSync22(source)) {
|
|
8118
8725
|
result.skipped += 1;
|
|
8119
8726
|
continue;
|
|
@@ -8144,18 +8751,18 @@ function installClaudeBaseline(manifestSpec, projectDir, templatesDir, baselineE
|
|
|
8144
8751
|
if (!result.foreignOwned.includes(slot)) result.foreignOwned.push(slot);
|
|
8145
8752
|
continue;
|
|
8146
8753
|
}
|
|
8147
|
-
if (writer.skipOutside(
|
|
8754
|
+
if (writer.skipOutside(join31(projectDir, entry.target, rel))) {
|
|
8148
8755
|
leftOutside += 1;
|
|
8149
8756
|
continue;
|
|
8150
8757
|
}
|
|
8151
|
-
writer.harness(`${entry.target}/${rel}`, { source:
|
|
8758
|
+
writer.harness(`${entry.target}/${rel}`, { source: join31(source, rel) });
|
|
8152
8759
|
}
|
|
8153
8760
|
if (leftOutside > 0) continue;
|
|
8154
8761
|
result.dirsCopied += 1;
|
|
8155
8762
|
}
|
|
8156
8763
|
accumulateCategory(result.categories, entry);
|
|
8157
8764
|
}
|
|
8158
|
-
const hookDir =
|
|
8765
|
+
const hookDir = join31(projectDir, ".claude/hooks");
|
|
8159
8766
|
if (existsSync22(hookDir)) {
|
|
8160
8767
|
chmodHooksSync(hookDir, projectDir);
|
|
8161
8768
|
}
|
|
@@ -8172,12 +8779,12 @@ function installClaudeBaseline(manifestSpec, projectDir, templatesDir, baselineE
|
|
|
8172
8779
|
if (settingsSource !== null) {
|
|
8173
8780
|
writeSettingsPortion(writer, settingsSource, projectDir, previousLog, (script) => {
|
|
8174
8781
|
const target = `${HOOKS_PREFIX}${script}`;
|
|
8175
|
-
return manifest.some((e2) => e2.target === target && e2.applies(manifestSpec)) && !isBaselineExcluded(target, baselineExcluded) && existsSync22(
|
|
8782
|
+
return manifest.some((e2) => e2.target === target && e2.applies(manifestSpec)) && !isBaselineExcluded(target, baselineExcluded) && existsSync22(join31(projectDir, target));
|
|
8176
8783
|
});
|
|
8177
8784
|
result.keptHookRefs.push(
|
|
8178
8785
|
...findStaleHookRefs(
|
|
8179
|
-
|
|
8180
|
-
|
|
8786
|
+
join31(projectDir, ".claude", "settings.json"),
|
|
8787
|
+
join31(projectDir, ".claude")
|
|
8181
8788
|
)
|
|
8182
8789
|
);
|
|
8183
8790
|
}
|
|
@@ -8187,7 +8794,7 @@ function installClaudeBaseline(manifestSpec, projectDir, templatesDir, baselineE
|
|
|
8187
8794
|
// ADR-085 · update(`upsertRootImport`)와 같은 판정 — 실제로 깔린 스킬만 안내한다. 밖 링크라 쓰지 않은
|
|
8188
8795
|
// 스킬(ADR-098)을 "installed" 라 적으면 다음 update 가 그 절을 걷어 내 두 동작이 서로 반대로 쓴다.
|
|
8189
8796
|
(manifestSpec.selectedInternalSkills ?? []).filter(
|
|
8190
|
-
(id) => existsSync22(
|
|
8797
|
+
(id) => existsSync22(join31(projectDir, ".claude", "skills", id))
|
|
8191
8798
|
),
|
|
8192
8799
|
harnessRoot,
|
|
8193
8800
|
writer
|
|
@@ -8228,7 +8835,7 @@ function writeEnvironmentFiles(writer, envExampleCreated, previousLog) {
|
|
|
8228
8835
|
}
|
|
8229
8836
|
function runExternalPhase(ctx, previousLog) {
|
|
8230
8837
|
if (ctx.runExternal === null) {
|
|
8231
|
-
return { report: null, backups: [] };
|
|
8838
|
+
return { report: null, backups: [], displaced: [] };
|
|
8232
8839
|
}
|
|
8233
8840
|
const { projectDir, spec } = ctx;
|
|
8234
8841
|
const runExt = ctx.runExternal ?? runExternalInstall;
|
|
@@ -8251,22 +8858,38 @@ function runExternalPhase(ctx, previousLog) {
|
|
|
8251
8858
|
};
|
|
8252
8859
|
const { targets } = selectExternalTargets(EXTERNAL_ASSETS, { ...filterCtx, cli: spec.cli });
|
|
8253
8860
|
ctx.onProgress?.({ type: "external-start", assetCount: targets.length });
|
|
8254
|
-
const
|
|
8255
|
-
const
|
|
8256
|
-
|
|
8257
|
-
(previousLog?.assets ?? []).filter((a) => a.method === "skill" && skillIds.has(a.id))
|
|
8258
|
-
|
|
8259
|
-
|
|
8260
|
-
|
|
8261
|
-
|
|
8262
|
-
);
|
|
8263
|
-
|
|
8861
|
+
const skills = targets.filter((a) => a.method.kind === "skill");
|
|
8862
|
+
const skillIds = new Set(skills.map((a) => a.id));
|
|
8863
|
+
const settle = holdSkillSlots(projectDir, {
|
|
8864
|
+
recorded: (previousLog?.assets ?? []).filter((a) => a.method === "skill" && skillIds.has(a.id)),
|
|
8865
|
+
slots: skillSlotsFor(skills, spec.cli, { log: previousLog, scope: spec.scope }),
|
|
8866
|
+
log: previousLog,
|
|
8867
|
+
clis: spec.cli,
|
|
8868
|
+
scope: spec.scope
|
|
8869
|
+
});
|
|
8870
|
+
let ran;
|
|
8871
|
+
try {
|
|
8872
|
+
ran = runExt(
|
|
8873
|
+
{ ...filterCtx, cli: spec.cli, projectDir, ...spec.scope ? { scope: spec.scope } : {} },
|
|
8874
|
+
externalDeps
|
|
8875
|
+
);
|
|
8876
|
+
} catch (e2) {
|
|
8877
|
+
try {
|
|
8878
|
+
settle(null);
|
|
8879
|
+
} catch {
|
|
8880
|
+
}
|
|
8881
|
+
throw e2;
|
|
8882
|
+
}
|
|
8883
|
+
const { report: external, backups, displaced } = settle(ran);
|
|
8884
|
+
const displacedBackups = new Set(displaced.map((f) => join31(projectDir, f.notes[0] ?? "")));
|
|
8885
|
+
const editBackups = backups.filter((b2) => !displacedBackups.has(b2));
|
|
8264
8886
|
ctx.onProgress?.({
|
|
8265
8887
|
type: "external-complete",
|
|
8266
8888
|
report: external,
|
|
8267
|
-
...
|
|
8889
|
+
...editBackups.length > 0 ? { backups: editBackups } : {},
|
|
8890
|
+
...displaced.length > 0 ? { displaced: displaced.map((f) => ({ path: f.path, backup: f.notes[0] ?? "" })) } : {}
|
|
8268
8891
|
});
|
|
8269
|
-
return { report: external, backups };
|
|
8892
|
+
return { report: external, backups, displaced };
|
|
8270
8893
|
}
|
|
8271
8894
|
var InstallInterruptedError = class extends Error {
|
|
8272
8895
|
constructor(message, written, record, backups = [], hadInstall = false) {
|
|
@@ -8331,7 +8954,7 @@ function recordInterruptedInstall(ctx, error, run) {
|
|
|
8331
8954
|
const codexTrust = registeredTrust(journal.codexOptIn, ctx.projectDir);
|
|
8332
8955
|
const written = writtenSoFar(ledger, cliFiles, rootFiles, stage.rootImportWritten);
|
|
8333
8956
|
if (codexTrust) written.push(`${codexTrust.configPath} (Codex trust entry for this folder)`);
|
|
8334
|
-
const projectRel = (abs) =>
|
|
8957
|
+
const projectRel = (abs) => relative5(ctx.projectDir, abs).split(sep6).join("/");
|
|
8335
8958
|
const writtenSet = new Set(written);
|
|
8336
8959
|
const backups = [...own.backups, ...journal.backups].map((abs) => {
|
|
8337
8960
|
const original = projectRel(backupOriginal(abs) ?? abs);
|
|
@@ -8471,7 +9094,7 @@ function accumulateCategory(cats, entry) {
|
|
|
8471
9094
|
}
|
|
8472
9095
|
}
|
|
8473
9096
|
function writeRootClaudeMd(projectDir, tracks, continuousSkills, harnessRoot, writer) {
|
|
8474
|
-
const target =
|
|
9097
|
+
const target = join31(projectDir, "CLAUDE.md");
|
|
8475
9098
|
if (writer.skipOutside(target)) return null;
|
|
8476
9099
|
const existing = existsSync22(target) ? readFileSync22(target, "utf-8") : null;
|
|
8477
9100
|
const seeded = existing === null ? seedRootClaudeProjectContext(projectDir, harnessRoot) : null;
|
|
@@ -8483,7 +9106,7 @@ function writeRootClaudeMd(projectDir, tracks, continuousSkills, harnessRoot, wr
|
|
|
8483
9106
|
});
|
|
8484
9107
|
if (content !== existing) {
|
|
8485
9108
|
if (existing !== null) backupIfLossyUtf8(target);
|
|
8486
|
-
|
|
9109
|
+
writeFileSync8(target, content);
|
|
8487
9110
|
}
|
|
8488
9111
|
return {
|
|
8489
9112
|
created: existing === null,
|
|
@@ -8501,14 +9124,14 @@ function chmodHooksSync(hookDir, projectDir) {
|
|
|
8501
9124
|
}
|
|
8502
9125
|
}
|
|
8503
9126
|
function listHookFiles(hookDir) {
|
|
8504
|
-
return
|
|
9127
|
+
return readdirSync5(hookDir, { withFileTypes: true }).filter((e2) => e2.isFile() && e2.name.endsWith(".sh")).map((e2) => resolve(hookDir, e2.name));
|
|
8505
9128
|
}
|
|
8506
9129
|
|
|
8507
9130
|
// src/commands/install-render.ts
|
|
8508
9131
|
init_esm_shims();
|
|
8509
9132
|
import { homedir as homedir3 } from "os";
|
|
8510
|
-
import { existsSync as existsSync24, readdirSync as
|
|
8511
|
-
import { join as
|
|
9133
|
+
import { existsSync as existsSync24, readdirSync as readdirSync6, readFileSync as readFileSync24 } from "fs";
|
|
9134
|
+
import { join as join33, relative as relative6 } from "path";
|
|
8512
9135
|
|
|
8513
9136
|
// src/preset-recommend.ts
|
|
8514
9137
|
init_esm_shims();
|
|
@@ -8545,9 +9168,9 @@ function groupAssetsByCategory(assetIds) {
|
|
|
8545
9168
|
// src/resident-entries.ts
|
|
8546
9169
|
init_esm_shims();
|
|
8547
9170
|
import { existsSync as existsSync23, readFileSync as readFileSync23 } from "fs";
|
|
8548
|
-
import { basename as basename5, join as
|
|
9171
|
+
import { basename as basename5, join as join32 } from "path";
|
|
8549
9172
|
function residentEntries(spec) {
|
|
8550
|
-
const skillThere = (id) => INTERNAL_BUNDLED_SKILL_IDS.includes(id) && [".claude/skills", ".agents/skills"].some((d2) => existsSync23(
|
|
9173
|
+
const skillThere = (id) => INTERNAL_BUNDLED_SKILL_IDS.includes(id) && [".claude/skills", ".agents/skills"].some((d2) => existsSync23(join32(spec.projectDir, d2, id)));
|
|
8551
9174
|
const forceExclude = (spec.userOverride?.forceExclude ?? []).filter((id) => !skillThere(id));
|
|
8552
9175
|
const assetSpec = buildManifestSpec(
|
|
8553
9176
|
spec.userOverride ? { ...spec, userOverride: { ...spec.userOverride, forceExclude } } : spec
|
|
@@ -8573,7 +9196,7 @@ function residentEntries(spec) {
|
|
|
8573
9196
|
function residentCostFor(spec, entries = residentEntries(spec), contextFiles) {
|
|
8574
9197
|
if (contextFiles !== void 0) return residentCost(entries, void 0, spec.cli, contextFiles);
|
|
8575
9198
|
const cost = residentCost(entries, void 0, spec.cli, plannedClaudeContext(spec));
|
|
8576
|
-
if (anchorSurface(spec.cli).scaffold === "agents-md" && existsSync23(
|
|
9199
|
+
if (anchorSurface(spec.cli).scaffold === "agents-md" && existsSync23(join32(spec.projectDir, "AGENTS.md"))) {
|
|
8577
9200
|
return makeResidentCost({
|
|
8578
9201
|
...cost,
|
|
8579
9202
|
contextNote: "planned, not counting text already in AGENTS.md"
|
|
@@ -8584,7 +9207,7 @@ function residentCostFor(spec, entries = residentEntries(spec), contextFiles) {
|
|
|
8584
9207
|
function plannedClaudeContext(spec) {
|
|
8585
9208
|
if (!spec.cli.includes("claude")) return void 0;
|
|
8586
9209
|
const root = resolveBundleRoot();
|
|
8587
|
-
const rootClaude =
|
|
9210
|
+
const rootClaude = join32(spec.projectDir, "CLAUDE.md");
|
|
8588
9211
|
const existing = existsSync23(rootClaude) ? readFileSync23(rootClaude, "utf-8") : null;
|
|
8589
9212
|
const seeded = existing === null ? seedRootClaudeProjectContext(spec.projectDir, root) : null;
|
|
8590
9213
|
if (existing === null && seeded === null) return void 0;
|
|
@@ -8595,14 +9218,14 @@ function plannedClaudeContext(spec) {
|
|
|
8595
9218
|
continuousSkills: manifestSpec.selectedInternalSkills ?? [],
|
|
8596
9219
|
...seeded === null ? {} : { projectContext: seeded }
|
|
8597
9220
|
});
|
|
8598
|
-
return [
|
|
9221
|
+
return [join32(root, "templates", "CLAUDE.md"), { text }];
|
|
8599
9222
|
}
|
|
8600
9223
|
function onDiskTargets(spec, assetSpec) {
|
|
8601
9224
|
const out = /* @__PURE__ */ new Set();
|
|
8602
9225
|
for (const e2 of buildManifest(assetSpec)) {
|
|
8603
9226
|
if (!e2.applies(assetSpec)) continue;
|
|
8604
9227
|
const t = classifyBaselineTarget(e2.target);
|
|
8605
|
-
if (t !== null && existsSync23(
|
|
9228
|
+
if (t !== null && existsSync23(join32(spec.projectDir, e2.target))) out.add(t.id);
|
|
8606
9229
|
}
|
|
8607
9230
|
return out;
|
|
8608
9231
|
}
|
|
@@ -8665,6 +9288,14 @@ function createInstallRenderer(log, spec, verbose) {
|
|
|
8665
9288
|
phase2HeaderPrinted = true;
|
|
8666
9289
|
} else if (event.type === "external-complete") {
|
|
8667
9290
|
for (const b2 of event.backups ?? []) log(assetRow("success", "backup", shortenPath(b2)));
|
|
9291
|
+
for (const d2 of event.displaced ?? [])
|
|
9292
|
+
log(
|
|
9293
|
+
assetRow(
|
|
9294
|
+
"skip",
|
|
9295
|
+
d2.path,
|
|
9296
|
+
`had a file with this name \u2014 saved as ${d2.backup}, put back on uninstall`
|
|
9297
|
+
)
|
|
9298
|
+
);
|
|
8668
9299
|
const excluded = event.report.excludedByCli;
|
|
8669
9300
|
if (excluded.length > 0) {
|
|
8670
9301
|
if (!phase2HeaderPrinted) {
|
|
@@ -8754,23 +9385,23 @@ function residentEntriesOnDisk(spec) {
|
|
|
8754
9385
|
const hasClaude = spec.cli.includes("claude");
|
|
8755
9386
|
const surface = anchorSurface(spec.cli).scaffold;
|
|
8756
9387
|
const mdFiles = (dir, kind, skip) => {
|
|
8757
|
-
const abs =
|
|
8758
|
-
return existsSync24(abs) ?
|
|
9388
|
+
const abs = join33(spec.projectDir, dir);
|
|
9389
|
+
return existsSync24(abs) ? readdirSync6(abs, { withFileTypes: true }).filter((e2) => e2.isFile() && e2.name.endsWith(".md") && e2.name !== skip).map((e2) => ({
|
|
8759
9390
|
source: `${kind}/${e2.name}`,
|
|
8760
9391
|
// `target` 은 `residentCost` 의 분류 키다 — 실제 자리는 `file` 이 말한다.
|
|
8761
9392
|
target: `.claude/${kind}/${e2.name}`,
|
|
8762
9393
|
// 배포판이 아니라 **이 프로젝트의 파일**을 잰다 — 사용자가 고친 본문도,
|
|
8763
9394
|
// 배포판에 더는 없는 파일도 실제로 상주하는 것은 이쪽이다.
|
|
8764
|
-
file:
|
|
9395
|
+
file: join33(abs, e2.name)
|
|
8765
9396
|
})) : [];
|
|
8766
9397
|
};
|
|
8767
|
-
const rules = surface === "claude" ? mdFiles(
|
|
8768
|
-
const slot = hasClaude ?
|
|
9398
|
+
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");
|
|
9399
|
+
const slot = hasClaude ? join33(".claude", "skills") : join33(".agents", "skills");
|
|
8769
9400
|
const skills = planned.filter((e2) => e2.target.startsWith(".claude/skills/")).map((e2) => ({
|
|
8770
9401
|
...e2,
|
|
8771
|
-
file:
|
|
9402
|
+
file: join33(spec.projectDir, slot, e2.target.slice(".claude/skills/".length))
|
|
8772
9403
|
})).filter((e2) => existsSync24(e2.file));
|
|
8773
|
-
const agents = hasClaude ? mdFiles(
|
|
9404
|
+
const agents = hasClaude ? mdFiles(join33(".claude", "agents"), "agents") : [];
|
|
8774
9405
|
return [
|
|
8775
9406
|
...planned.filter(
|
|
8776
9407
|
(e2) => !e2.target.startsWith(".claude/rules/") && !e2.target.startsWith(".claude/agents/") && !e2.target.startsWith(".claude/skills/")
|
|
@@ -8782,8 +9413,8 @@ function residentEntriesOnDisk(spec) {
|
|
|
8782
9413
|
}
|
|
8783
9414
|
function contextFilesOnDisk(spec) {
|
|
8784
9415
|
const surface = anchorSurface(spec.cli).scaffold;
|
|
8785
|
-
const files = surface === "claude" ? [HARNESS_ANCHOR_FILE, "CLAUDE.md",
|
|
8786
|
-
return files.map((f) =>
|
|
9416
|
+
const files = surface === "claude" ? [HARNESS_ANCHOR_FILE, "CLAUDE.md", join33(".claude", "CLAUDE.md")] : ["AGENTS.md"];
|
|
9417
|
+
return files.map((f) => join33(spec.projectDir, f));
|
|
8787
9418
|
}
|
|
8788
9419
|
function rulesInsideAgentsMd(spec, cost) {
|
|
8789
9420
|
if (anchorSurface(spec.cli).scaffold !== "agents-md" || !rulesInline(spec.cli)) return cost;
|
|
@@ -9037,8 +9668,8 @@ function renderFinalSummary(log, spec, report, fromWizard) {
|
|
|
9037
9668
|
const codexTrusted = report.codexOptIn?.trustEntry.status === "registered" || report.codexOptIn?.trustEntry.status === "already-present";
|
|
9038
9669
|
const alreadyTrustedGlobally = (() => {
|
|
9039
9670
|
try {
|
|
9040
|
-
const home = process.env.CODEX_HOME ??
|
|
9041
|
-
const configPath =
|
|
9671
|
+
const home = process.env.CODEX_HOME ?? join33(homedir3(), ".codex");
|
|
9672
|
+
const configPath = join33(home, "config.toml");
|
|
9042
9673
|
if (!existsSync24(configPath)) return false;
|
|
9043
9674
|
return hasTrustEntry(readFileSync24(configPath, "utf8"), spec.projectDir);
|
|
9044
9675
|
} catch {
|
|
@@ -9065,7 +9696,7 @@ function renderFinalSummary(log, spec, report, fromWizard) {
|
|
|
9065
9696
|
const remote = (report.shared ?? []).find((f) => f.path === ".mcp.json")?.remote ?? [];
|
|
9066
9697
|
for (const line of remoteMcpNextLines(remote, spec.cli)) log(`${" ".repeat(16)} ${line}`);
|
|
9067
9698
|
const scaffoldFiles = scaffoldFilesForCli(spec.cli).filter(
|
|
9068
|
-
(f) => f === "CLAUDE.md" && report.rootClaudeMd?.created === true || hasFillPrompt(
|
|
9699
|
+
(f) => f === "CLAUDE.md" && report.rootClaudeMd?.created === true || hasFillPrompt(join33(spec.projectDir, f))
|
|
9069
9700
|
);
|
|
9070
9701
|
if (scaffoldFiles.length > 0) {
|
|
9071
9702
|
const auditInstalled = buildManifestSpec(spec).selectedInternalSkills?.includes("audit-harness-fit");
|
|
@@ -9205,6 +9836,7 @@ function renderPhase1Rows(log, baseline, verbose = false) {
|
|
|
9205
9836
|
const retired = anchorRetireRow(baseline.updateMode.anchorRetired ?? null);
|
|
9206
9837
|
if (retired) log(retired);
|
|
9207
9838
|
for (const row of outOfTrackRows(baseline.updateMode.outOfTrack)) log(row);
|
|
9839
|
+
for (const row of displacedRows(baseline.updateMode.displacedRestored)) log(row);
|
|
9208
9840
|
for (const f of baseline.updateMode.sharedWrites ?? []) {
|
|
9209
9841
|
const row = sharedFileRow(f);
|
|
9210
9842
|
if (row !== null) log(row);
|
|
@@ -9311,15 +9943,6 @@ function renderPhase1Rows(log, baseline, verbose = false) {
|
|
|
9311
9943
|
)
|
|
9312
9944
|
);
|
|
9313
9945
|
}
|
|
9314
|
-
if (baseline.updateMode.helpersKept?.length) {
|
|
9315
|
-
log(
|
|
9316
|
-
assetRow(
|
|
9317
|
-
"skip",
|
|
9318
|
-
"helper is a link",
|
|
9319
|
-
`${baseline.updateMode.helpersKept.join(", ")} \xB7 \uB9C1\uD06C\uB77C \uAC31\uC2E0\uD558\uC9C0 \uC54A\uACE0 \uB0A8\uACBC\uB2E4`
|
|
9320
|
-
)
|
|
9321
|
-
);
|
|
9322
|
-
}
|
|
9323
9946
|
for (const row of outsideLinkRows(baseline.updateMode.outsideLinks ?? [])) log(row);
|
|
9324
9947
|
if (baseline.updateMode.foreignOwned.length > 0) {
|
|
9325
9948
|
log(
|
|
@@ -9411,6 +10034,26 @@ function renderPhase1Rows(log, baseline, verbose = false) {
|
|
|
9411
10034
|
)
|
|
9412
10035
|
);
|
|
9413
10036
|
}
|
|
10037
|
+
const legacyDropped = baseline.updateMode.agentsMdLegacyDropped ?? 0;
|
|
10038
|
+
if (legacyDropped > 0) {
|
|
10039
|
+
log(
|
|
10040
|
+
assetRow(
|
|
10041
|
+
"success",
|
|
10042
|
+
"AGENTS.md",
|
|
10043
|
+
`removed ${legacyDropped} section(s) written by an older harness version (saved a copy as AGENTS.md.backup-<time>)`
|
|
10044
|
+
)
|
|
10045
|
+
);
|
|
10046
|
+
}
|
|
10047
|
+
const legacyEdited = baseline.updateMode.agentsMdLegacyEdited ?? [];
|
|
10048
|
+
if (legacyEdited.length > 0) {
|
|
10049
|
+
log(
|
|
10050
|
+
assetRow(
|
|
10051
|
+
"skip",
|
|
10052
|
+
"AGENTS.md",
|
|
10053
|
+
`${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>`
|
|
10054
|
+
)
|
|
10055
|
+
);
|
|
10056
|
+
}
|
|
9414
10057
|
const externalEdited = baseline.updateMode.externalBackedUp.filter((p2) => !noChecksum.has(p2));
|
|
9415
10058
|
if (externalEdited.length > 0) {
|
|
9416
10059
|
log(
|
|
@@ -9497,8 +10140,12 @@ function renderPhase1Rows(log, baseline, verbose = false) {
|
|
|
9497
10140
|
if (j4.backupAbs !== void 0) judgedBackups.add(j4.backupAbs);
|
|
9498
10141
|
log(judgedRow(j4));
|
|
9499
10142
|
}
|
|
10143
|
+
for (const f of baseline.shared ?? []) {
|
|
10144
|
+
if (f.backupAbs !== void 0 && f.removedEdited.length > 0) judgedBackups.add(f.backupAbs);
|
|
10145
|
+
}
|
|
9500
10146
|
for (const row of outsideLinkRows(baseline.outsideLinks ?? [])) log(row);
|
|
9501
10147
|
for (const row of outOfTrackRows(baseline.outOfTrack)) log(row);
|
|
10148
|
+
for (const row of displacedRows(baseline.displacedRestored)) log(row);
|
|
9502
10149
|
if (baseline.backups) {
|
|
9503
10150
|
for (const b2 of baseline.backups) {
|
|
9504
10151
|
if (judgedBackups.has(b2)) continue;
|
|
@@ -9638,6 +10285,11 @@ function renderPhase1Rows(log, baseline, verbose = false) {
|
|
|
9638
10285
|
function judgedRow(j4) {
|
|
9639
10286
|
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
10287
|
}
|
|
10288
|
+
function displacedRows(outcomes) {
|
|
10289
|
+
return (outcomes ?? []).flatMap(
|
|
10290
|
+
(d2) => d2.verdict === "restore" ? [assetRow("success", d2.path, `yours \u2014 put back (from ${d2.backup})`)] : d2.verdict === "advise" ? [assetRow("skip", d2.path, d2.line)] : []
|
|
10291
|
+
);
|
|
10292
|
+
}
|
|
9641
10293
|
function outOfTrackRows(r) {
|
|
9642
10294
|
if (r === void 0) return [];
|
|
9643
10295
|
const recorded2 = r.recordedTracks.join(", ");
|
|
@@ -9674,16 +10326,16 @@ function outOfTrackRows(r) {
|
|
|
9674
10326
|
function outsideLinkRows(links) {
|
|
9675
10327
|
const groups = /* @__PURE__ */ new Map();
|
|
9676
10328
|
for (const o of links) groups.set(o.link, [...groups.get(o.link) ?? [], o]);
|
|
9677
|
-
const
|
|
10329
|
+
const rows2 = [];
|
|
9678
10330
|
for (const [link, group] of groups) {
|
|
9679
10331
|
const first = group[0];
|
|
9680
10332
|
if (first === void 0) continue;
|
|
9681
10333
|
const fileLink = group.length === 1 && first.path === link;
|
|
9682
|
-
|
|
10334
|
+
rows2.push(
|
|
9683
10335
|
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
10336
|
);
|
|
9685
10337
|
}
|
|
9686
|
-
return
|
|
10338
|
+
return rows2;
|
|
9687
10339
|
}
|
|
9688
10340
|
function sharedFileRow(f) {
|
|
9689
10341
|
if (f.line === "") return null;
|
|
@@ -9751,8 +10403,9 @@ function excludedKeyParts(f) {
|
|
|
9751
10403
|
parts.push(`removed the harness part: ${f.removedOut.join(", ")} (you asked: ${asked})`);
|
|
9752
10404
|
}
|
|
9753
10405
|
if (f.removedEdited.length > 0) {
|
|
10406
|
+
const where = f.backup === void 0 ? "went with it" : `are in the copy: ${f.backup}`;
|
|
9754
10407
|
parts.push(
|
|
9755
|
-
`your edits to ${f.removedEdited.join(", ")}
|
|
10408
|
+
`your edits to ${f.removedEdited.join(", ")} ${where} (a hook entry calls a harness script \u2014 left alone it would call a script that is no longer wired)`
|
|
9756
10409
|
);
|
|
9757
10410
|
}
|
|
9758
10411
|
if (f.keptOut.length > 0) {
|
|
@@ -9872,7 +10525,7 @@ function renderInterruptedInstall(err, e2, cwd = process.cwd()) {
|
|
|
9872
10525
|
}
|
|
9873
10526
|
const { path, error } = e2.record;
|
|
9874
10527
|
err(
|
|
9875
|
-
path !== null ? ` Already in place before it stopped \u2014 recorded in ${
|
|
10528
|
+
path !== null ? ` Already in place before it stopped \u2014 recorded in ${relative6(cwd, path) || path}:` : " Already in place before it stopped:"
|
|
9876
10529
|
);
|
|
9877
10530
|
for (const [key, n] of groups) {
|
|
9878
10531
|
err(` ${key.endsWith("/") ? `${key} (${n} file${n === 1 ? "" : "s"})` : key}`);
|
|
@@ -10196,7 +10849,7 @@ function registerInstallCommand(cli) {
|
|
|
10196
10849
|
// src/commands/list.ts
|
|
10197
10850
|
init_esm_shims();
|
|
10198
10851
|
import { existsSync as existsSync25, readFileSync as readFileSync25 } from "fs";
|
|
10199
|
-
import { join as
|
|
10852
|
+
import { join as join34, resolve as resolve3 } from "path";
|
|
10200
10853
|
function listAction(options = {}, deps = {}) {
|
|
10201
10854
|
const log = deps.log ?? console.log;
|
|
10202
10855
|
const err = deps.err ?? console.error;
|
|
@@ -10247,33 +10900,33 @@ function listAction(options = {}, deps = {}) {
|
|
|
10247
10900
|
}
|
|
10248
10901
|
var SELECTIONS_SHOWN = 10;
|
|
10249
10902
|
function formatSelectionRows(log, projectDir) {
|
|
10250
|
-
const
|
|
10903
|
+
const rows2 = [];
|
|
10251
10904
|
const excluded = [...excludedIds(log)].sort();
|
|
10252
|
-
if (excluded.length === 0)
|
|
10905
|
+
if (excluded.length === 0) rows2.push(c.dim(" excluded: (none)"));
|
|
10253
10906
|
const still = new Set(
|
|
10254
10907
|
excludedStillThere(projectDir, new Set(excluded), [], log).map((e2) => e2.id)
|
|
10255
10908
|
);
|
|
10256
10909
|
for (const id of excluded) {
|
|
10257
10910
|
const kind = id.startsWith("baseline:") ? "baseline" : isKeyId(id) ? "harness part" : "asset";
|
|
10258
|
-
|
|
10911
|
+
rows2.push(` \u2298 ${id} ${c.dim(`(${kind}${still.has(id) ? " \xB7 still on disk" : ""})`)}`);
|
|
10259
10912
|
}
|
|
10260
10913
|
const history = (log.selections ?? []).slice(-SELECTIONS_SHOWN);
|
|
10261
|
-
if (history.length > 0)
|
|
10914
|
+
if (history.length > 0) rows2.push(c.dim(` history (latest ${history.length}):`));
|
|
10262
10915
|
for (const ev of history) {
|
|
10263
10916
|
const day = ev.at.slice(0, 10);
|
|
10264
10917
|
const parts = [];
|
|
10265
10918
|
if (ev.by === "migration") {
|
|
10266
10919
|
if (ev.released?.length) parts.push(`released ${ev.released.join(", ")}`);
|
|
10267
10920
|
if (ev.kept?.length) parts.push(`kept ${ev.kept.join(", ")}`);
|
|
10268
|
-
|
|
10921
|
+
rows2.push(` ${day} migration (26.162\u201326.163 record): ${parts.join(" \xB7 ")}`);
|
|
10269
10922
|
continue;
|
|
10270
10923
|
}
|
|
10271
10924
|
if (ev.without?.length) parts.push(`--without ${ev.without.join(", ")}`);
|
|
10272
10925
|
if (ev.with?.length) parts.push(`re-added ${ev.with.join(", ")}`);
|
|
10273
10926
|
const tags = [ev.via === "wizard" ? "wizard" : "", ev.interrupted ? "interrupted" : ""].filter(Boolean).join(", ");
|
|
10274
|
-
|
|
10927
|
+
rows2.push(` ${day} install ${parts.join(" \xB7 ")}${tags ? ` (${tags})` : ""}`);
|
|
10275
10928
|
}
|
|
10276
|
-
return
|
|
10929
|
+
return rows2;
|
|
10277
10930
|
}
|
|
10278
10931
|
function formatAssetRows(assets) {
|
|
10279
10932
|
const idWidth = Math.max(0, ...assets.map((a) => a.id.length));
|
|
@@ -10296,16 +10949,16 @@ function harnessFileTops(log) {
|
|
|
10296
10949
|
}
|
|
10297
10950
|
function formatHarnessFileRows(log, projectDir) {
|
|
10298
10951
|
const tops = harnessFileTops(log);
|
|
10299
|
-
const
|
|
10952
|
+
const rows2 = [` ${c.dim(tops.length > 0 ? tops.join(" ") : "(none recorded)")}`];
|
|
10300
10953
|
const rootMd = log.templates.rootClaudeMd;
|
|
10301
10954
|
if (rootMd) {
|
|
10302
|
-
const path =
|
|
10955
|
+
const path = join34(projectDir, rootMd.path);
|
|
10303
10956
|
const modified = existsSync25(path) && hashContent(readFileSync25(path, "utf8")) !== rootMd.sha256;
|
|
10304
|
-
|
|
10957
|
+
rows2.push(
|
|
10305
10958
|
modified ? ` ${c.dim(rootMd.path)} ${c.yellow("(\uC218\uC815\uB428 \u2014 uninstall \uC2DC \uBCF4\uC874)")}` : ` ${c.dim(rootMd.path)}`
|
|
10306
10959
|
);
|
|
10307
10960
|
}
|
|
10308
|
-
return
|
|
10961
|
+
return rows2;
|
|
10309
10962
|
}
|
|
10310
10963
|
var ROOT_FILE_CHANGE = {
|
|
10311
10964
|
created: "\uC0DD\uC131",
|
|
@@ -10314,7 +10967,7 @@ var ROOT_FILE_CHANGE = {
|
|
|
10314
10967
|
displaced: "\uBE44\uCF1C \uB460"
|
|
10315
10968
|
};
|
|
10316
10969
|
function formatRootFileRows(rootFiles, projectDir) {
|
|
10317
|
-
const present2 = rootFiles.filter((f) => existsSync25(
|
|
10970
|
+
const present2 = rootFiles.filter((f) => existsSync25(join34(projectDir, f.path)));
|
|
10318
10971
|
const width = Math.max(0, ...present2.map((f) => f.path.length));
|
|
10319
10972
|
return present2.map(
|
|
10320
10973
|
(f) => ` ${c.dim(padDisplay(f.path, width))} ${c.dim(ROOT_FILE_CHANGE[f.change])} ${c.dim(f.notes.join(" / "))}`
|
|
@@ -10332,22 +10985,20 @@ function registerListCommand(cli) {
|
|
|
10332
10985
|
init_esm_shims();
|
|
10333
10986
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
10334
10987
|
import {
|
|
10335
|
-
accessSync,
|
|
10988
|
+
accessSync as accessSync2,
|
|
10336
10989
|
existsSync as existsSync26,
|
|
10337
|
-
constants as
|
|
10990
|
+
constants as fsConstants2,
|
|
10338
10991
|
lstatSync as lstatSync5,
|
|
10339
|
-
|
|
10340
|
-
readdirSync as readdirSync6,
|
|
10992
|
+
readdirSync as readdirSync7,
|
|
10341
10993
|
readFileSync as readFileSync26,
|
|
10342
10994
|
readlinkSync,
|
|
10343
10995
|
realpathSync as realpathSync3,
|
|
10344
|
-
|
|
10345
|
-
|
|
10346
|
-
rmSync as rmSync4,
|
|
10996
|
+
rmdirSync as rmdirSync3,
|
|
10997
|
+
rmSync as rmSync5,
|
|
10347
10998
|
statSync as statSync5,
|
|
10348
|
-
writeFileSync as
|
|
10999
|
+
writeFileSync as writeFileSync9
|
|
10349
11000
|
} from "fs";
|
|
10350
|
-
import { dirname as
|
|
11001
|
+
import { dirname as dirname8, join as join35, relative as relative7, resolve as resolve4, sep as sep7 } from "path";
|
|
10351
11002
|
|
|
10352
11003
|
// src/uninstall-interactive.ts
|
|
10353
11004
|
init_esm_shims();
|
|
@@ -10537,11 +11188,11 @@ var getClosingCode = (openingCode) => {
|
|
|
10537
11188
|
};
|
|
10538
11189
|
var wrapAnsiCode = (code) => `${ESC}${ANSI_CSI}${code}${ANSI_SGR_TERMINATOR}`;
|
|
10539
11190
|
var wrapAnsiHyperlink = (url) => `${ESC}${ANSI_ESCAPE_LINK}${url}${ANSI_ESCAPE_BELL}`;
|
|
10540
|
-
var wrapWord = (
|
|
11191
|
+
var wrapWord = (rows2, word, columns) => {
|
|
10541
11192
|
const characters = word[Symbol.iterator]();
|
|
10542
11193
|
let isInsideEscape = false;
|
|
10543
11194
|
let isInsideLinkEscape = false;
|
|
10544
|
-
let lastRow =
|
|
11195
|
+
let lastRow = rows2.at(-1);
|
|
10545
11196
|
let visible = lastRow === void 0 ? 0 : dist_default2(lastRow);
|
|
10546
11197
|
let currentCharacter = characters.next();
|
|
10547
11198
|
let nextCharacter = characters.next();
|
|
@@ -10550,9 +11201,9 @@ var wrapWord = (rows, word, columns) => {
|
|
|
10550
11201
|
const character = currentCharacter.value;
|
|
10551
11202
|
const characterLength = dist_default2(character);
|
|
10552
11203
|
if (visible + characterLength <= columns) {
|
|
10553
|
-
|
|
11204
|
+
rows2[rows2.length - 1] += character;
|
|
10554
11205
|
} else {
|
|
10555
|
-
|
|
11206
|
+
rows2.push(character);
|
|
10556
11207
|
visible = 0;
|
|
10557
11208
|
}
|
|
10558
11209
|
if (character === ESC || character === CSI) {
|
|
@@ -10571,7 +11222,7 @@ var wrapWord = (rows, word, columns) => {
|
|
|
10571
11222
|
} else {
|
|
10572
11223
|
visible += characterLength;
|
|
10573
11224
|
if (visible === columns && !nextCharacter.done) {
|
|
10574
|
-
|
|
11225
|
+
rows2.push("");
|
|
10575
11226
|
visible = 0;
|
|
10576
11227
|
}
|
|
10577
11228
|
}
|
|
@@ -10579,9 +11230,9 @@ var wrapWord = (rows, word, columns) => {
|
|
|
10579
11230
|
nextCharacter = characters.next();
|
|
10580
11231
|
rawCharacterIndex += character.length;
|
|
10581
11232
|
}
|
|
10582
|
-
lastRow =
|
|
10583
|
-
if (!visible && lastRow !== void 0 && lastRow.length &&
|
|
10584
|
-
|
|
11233
|
+
lastRow = rows2.at(-1);
|
|
11234
|
+
if (!visible && lastRow !== void 0 && lastRow.length && rows2.length > 1) {
|
|
11235
|
+
rows2[rows2.length - 2] += rows2.pop();
|
|
10585
11236
|
}
|
|
10586
11237
|
};
|
|
10587
11238
|
var stringVisibleTrimSpacesRight = (string) => {
|
|
@@ -10606,25 +11257,25 @@ var exec = (string, columns, options = {}) => {
|
|
|
10606
11257
|
let escapeCode;
|
|
10607
11258
|
let escapeUrl;
|
|
10608
11259
|
const words = string.split(" ");
|
|
10609
|
-
let
|
|
11260
|
+
let rows2 = [""];
|
|
10610
11261
|
let rowLength = 0;
|
|
10611
11262
|
for (let index = 0; index < words.length; index++) {
|
|
10612
11263
|
const word = words[index];
|
|
10613
11264
|
if (options.trim !== false) {
|
|
10614
|
-
const row =
|
|
11265
|
+
const row = rows2.at(-1) ?? "";
|
|
10615
11266
|
const trimmed = row.trimStart();
|
|
10616
11267
|
if (row.length !== trimmed.length) {
|
|
10617
|
-
|
|
11268
|
+
rows2[rows2.length - 1] = trimmed;
|
|
10618
11269
|
rowLength = dist_default2(trimmed);
|
|
10619
11270
|
}
|
|
10620
11271
|
}
|
|
10621
11272
|
if (index !== 0) {
|
|
10622
11273
|
if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) {
|
|
10623
|
-
|
|
11274
|
+
rows2.push("");
|
|
10624
11275
|
rowLength = 0;
|
|
10625
11276
|
}
|
|
10626
11277
|
if (rowLength || options.trim === false) {
|
|
10627
|
-
|
|
11278
|
+
rows2[rows2.length - 1] += " ";
|
|
10628
11279
|
rowLength++;
|
|
10629
11280
|
}
|
|
10630
11281
|
}
|
|
@@ -10634,33 +11285,33 @@ var exec = (string, columns, options = {}) => {
|
|
|
10634
11285
|
const breaksStartingThisLine = 1 + Math.floor((wordLength - remainingColumns - 1) / columns);
|
|
10635
11286
|
const breaksStartingNextLine = Math.floor((wordLength - 1) / columns);
|
|
10636
11287
|
if (breaksStartingNextLine < breaksStartingThisLine) {
|
|
10637
|
-
|
|
11288
|
+
rows2.push("");
|
|
10638
11289
|
}
|
|
10639
|
-
wrapWord(
|
|
10640
|
-
rowLength = dist_default2(
|
|
11290
|
+
wrapWord(rows2, word, columns);
|
|
11291
|
+
rowLength = dist_default2(rows2.at(-1) ?? "");
|
|
10641
11292
|
continue;
|
|
10642
11293
|
}
|
|
10643
11294
|
if (rowLength + wordLength > columns && rowLength && wordLength) {
|
|
10644
11295
|
if (options.wordWrap === false && rowLength < columns) {
|
|
10645
|
-
wrapWord(
|
|
10646
|
-
rowLength = dist_default2(
|
|
11296
|
+
wrapWord(rows2, word, columns);
|
|
11297
|
+
rowLength = dist_default2(rows2.at(-1) ?? "");
|
|
10647
11298
|
continue;
|
|
10648
11299
|
}
|
|
10649
|
-
|
|
11300
|
+
rows2.push("");
|
|
10650
11301
|
rowLength = 0;
|
|
10651
11302
|
}
|
|
10652
11303
|
if (rowLength + wordLength > columns && options.wordWrap === false) {
|
|
10653
|
-
wrapWord(
|
|
10654
|
-
rowLength = dist_default2(
|
|
11304
|
+
wrapWord(rows2, word, columns);
|
|
11305
|
+
rowLength = dist_default2(rows2.at(-1) ?? "");
|
|
10655
11306
|
continue;
|
|
10656
11307
|
}
|
|
10657
|
-
|
|
11308
|
+
rows2[rows2.length - 1] += word;
|
|
10658
11309
|
rowLength += wordLength;
|
|
10659
11310
|
}
|
|
10660
11311
|
if (options.trim !== false) {
|
|
10661
|
-
|
|
11312
|
+
rows2 = rows2.map((row) => stringVisibleTrimSpacesRight(row));
|
|
10662
11313
|
}
|
|
10663
|
-
const preString =
|
|
11314
|
+
const preString = rows2.join("\n");
|
|
10664
11315
|
let inSurrogate = false;
|
|
10665
11316
|
for (let i = 0; i < preString.length; i++) {
|
|
10666
11317
|
const character = preString[i];
|
|
@@ -11544,8 +12195,8 @@ function assertPagesCoverAllCategories(pages) {
|
|
|
11544
12195
|
}
|
|
11545
12196
|
assertPagesCoverAllCategories(INSTALL_TARGET_PAGES);
|
|
11546
12197
|
function viewportItems(itemCount) {
|
|
11547
|
-
const
|
|
11548
|
-
return Math.max(8, Math.min(itemCount,
|
|
12198
|
+
const rows2 = process.stdout.rows ?? 24;
|
|
12199
|
+
return Math.max(8, Math.min(itemCount, rows2 - 10));
|
|
11549
12200
|
}
|
|
11550
12201
|
var defaultPrompts = {
|
|
11551
12202
|
intro: (msg) => ge(msg),
|
|
@@ -11854,11 +12505,11 @@ async function runInteractiveUninstall(projectDir, deps = {}) {
|
|
|
11854
12505
|
const log = readLog(projectDir);
|
|
11855
12506
|
if (!log) return { ok: false, reason: "no-log" };
|
|
11856
12507
|
if (!deps.embedded) prompts.intro("uzys-agent-harness \xB7 uninstall");
|
|
11857
|
-
const
|
|
12508
|
+
const rows2 = buildRemovableRows(log.assets);
|
|
11858
12509
|
const clis = installedClis(log);
|
|
11859
12510
|
const mode = await prompts.selectMode(
|
|
11860
|
-
buildUninstallModeChoices(clis,
|
|
11861
|
-
`uzys-agent-harness \xB7 uninstall installed: ${clis.join(", ") || "(none)"} \xB7 assets ${
|
|
12511
|
+
buildUninstallModeChoices(clis, rows2.length),
|
|
12512
|
+
`uzys-agent-harness \xB7 uninstall installed: ${clis.join(", ") || "(none)"} \xB7 assets ${rows2.length}`
|
|
11862
12513
|
);
|
|
11863
12514
|
if (mode === null) {
|
|
11864
12515
|
prompts.cancel("Cancelled.");
|
|
@@ -11885,7 +12536,7 @@ async function runInteractiveUninstall(projectDir, deps = {}) {
|
|
|
11885
12536
|
}
|
|
11886
12537
|
return { ok: true, options: { projectDir } };
|
|
11887
12538
|
}
|
|
11888
|
-
const picked = await prompts.selectAssets(
|
|
12539
|
+
const picked = await prompts.selectAssets(rows2);
|
|
11889
12540
|
if (picked === null) {
|
|
11890
12541
|
prompts.cancel("Cancelled.");
|
|
11891
12542
|
return { ok: false, reason: "cancelled" };
|
|
@@ -11944,18 +12595,18 @@ function defaultUninstallPrompts() {
|
|
|
11944
12595
|
});
|
|
11945
12596
|
return q(r) ? null : r;
|
|
11946
12597
|
},
|
|
11947
|
-
selectCli: async (
|
|
12598
|
+
selectCli: async (rows2) => {
|
|
11948
12599
|
const r = await Ee({
|
|
11949
12600
|
message: 'Which CLI? (the last remaining CLI cannot be removed this way \u2014 use "Remove everything")',
|
|
11950
|
-
options:
|
|
12601
|
+
options: rows2.map((x) => ({ value: x.value, label: x.label, hint: x.hint }))
|
|
11951
12602
|
});
|
|
11952
12603
|
return q(r) ? null : r;
|
|
11953
12604
|
},
|
|
11954
|
-
selectAssets: async (
|
|
11955
|
-
if (
|
|
12605
|
+
selectAssets: async (rows2) => {
|
|
12606
|
+
if (rows2.length === 0) return [];
|
|
11956
12607
|
const r = await ve({
|
|
11957
12608
|
message: "Assets to remove (Space toggle \xB7 Enter confirm \xB7 ESC cancel)",
|
|
11958
|
-
options:
|
|
12609
|
+
options: rows2.map((x) => ({ value: x.value, label: x.label, hint: x.hint })),
|
|
11959
12610
|
required: false
|
|
11960
12611
|
});
|
|
11961
12612
|
return q(r) ? null : r;
|
|
@@ -12087,9 +12738,20 @@ function uninstallAction(options, deps = {}) {
|
|
|
12087
12738
|
}
|
|
12088
12739
|
const logSurvives = selectedIds !== null;
|
|
12089
12740
|
let reversed;
|
|
12741
|
+
let onlyDisplaced = [];
|
|
12090
12742
|
try {
|
|
12091
12743
|
reversed = executeReverse(plan, log, logSurvives, journal);
|
|
12092
|
-
if (
|
|
12744
|
+
if (assetsOnly) {
|
|
12745
|
+
const removed = new Set(reversed.removedIds);
|
|
12746
|
+
onlyDisplaced = restoreDisplaced(installLog, projectDir, {
|
|
12747
|
+
has: inAssetSlots(installLog.assets.filter((a) => removed.has(a.id))),
|
|
12748
|
+
write: true
|
|
12749
|
+
});
|
|
12750
|
+
for (const d2 of onlyDisplaced) {
|
|
12751
|
+
if (d2.verdict === "restore") journal.push(`put back ${d2.path}`);
|
|
12752
|
+
}
|
|
12753
|
+
for (const line of displacedLines(onlyDisplaced, false)) log(line);
|
|
12754
|
+
} else {
|
|
12093
12755
|
const done = removeHarnessFiles(installLog, projectDir, FULL_SCOPE, {
|
|
12094
12756
|
rm: rmJ,
|
|
12095
12757
|
write: true,
|
|
@@ -12125,7 +12787,7 @@ function uninstallAction(options, deps = {}) {
|
|
|
12125
12787
|
}
|
|
12126
12788
|
const { succeeded, failed, removedIds } = reversed;
|
|
12127
12789
|
const logWriteFailed = settleLog(
|
|
12128
|
-
{ installLog, projectDir, selectedIds, removedIds },
|
|
12790
|
+
{ installLog, projectDir, selectedIds, removedIds, displaced: onlyDisplaced },
|
|
12129
12791
|
{ log, err, rm, writeLog }
|
|
12130
12792
|
);
|
|
12131
12793
|
for (const line of advisoryLines(plan, projectDir, rootFiles, globalTrust)) {
|
|
@@ -12154,11 +12816,11 @@ function unwritablePaths(ctx) {
|
|
|
12154
12816
|
const project = ctx.targetAssets.filter((a) => a.scope === "project");
|
|
12155
12817
|
if (project.some((a) => a.method === "npm")) need.add(".");
|
|
12156
12818
|
const parentOf = (path) => {
|
|
12157
|
-
const abs =
|
|
12819
|
+
const abs = join35(projectDir, path);
|
|
12158
12820
|
if (!safeExists(abs)) return;
|
|
12159
12821
|
const real = safeRealpath(abs);
|
|
12160
12822
|
if (real !== null && isOutsideProject(projectDir, real)) return;
|
|
12161
|
-
need.add(
|
|
12823
|
+
need.add(dirname8(path));
|
|
12162
12824
|
};
|
|
12163
12825
|
for (const a of project)
|
|
12164
12826
|
if (a.method === "skill") for (const f of a.files ?? []) parentOf(f.path);
|
|
@@ -12166,16 +12828,17 @@ function unwritablePaths(ctx) {
|
|
|
12166
12828
|
const recordedShared = new Set((installLog.portions ?? []).map((p2) => p2.path));
|
|
12167
12829
|
const made = new Set((installLog.externalFiles ?? []).map((f) => f.path));
|
|
12168
12830
|
for (const p2 of UNINSTALL_SHARED) {
|
|
12169
|
-
if (recordedShared.has(p2) && existsSync26(
|
|
12831
|
+
if (recordedShared.has(p2) && existsSync26(join35(projectDir, p2))) need.add(p2);
|
|
12170
12832
|
if (made.has(p2)) parentOf(p2);
|
|
12171
12833
|
}
|
|
12172
12834
|
for (const p2 of harnessCandidates(installLog)) parentOf(p2);
|
|
12835
|
+
for (const p2 of legacyFileCandidates()) parentOf(p2);
|
|
12173
12836
|
for (const f of installLog.rootFiles ?? []) if (f.change === "displaced") parentOf(f.path);
|
|
12174
12837
|
if (hasRootImport(projectDir)) need.add("CLAUDE.md");
|
|
12175
12838
|
}
|
|
12176
12839
|
return [...need].filter((p2) => {
|
|
12177
12840
|
try {
|
|
12178
|
-
|
|
12841
|
+
accessSync2(join35(projectDir, p2), fsConstants2.W_OK);
|
|
12179
12842
|
return false;
|
|
12180
12843
|
} catch (e2) {
|
|
12181
12844
|
return e2.code !== "ENOENT";
|
|
@@ -12249,8 +12912,9 @@ function settleLog(ctx, io) {
|
|
|
12249
12912
|
const { installLog, projectDir, selectedIds, removedIds } = ctx;
|
|
12250
12913
|
if (selectedIds) {
|
|
12251
12914
|
const remaining = installLog.assets.filter((a) => !removedIds.includes(a.id));
|
|
12915
|
+
const rootFiles = ctx.displaced.some((d2) => d2.forget) ? { rootFiles: withoutRestored(installLog.rootFiles, ctx.displaced) } : {};
|
|
12252
12916
|
try {
|
|
12253
|
-
io.writeLog(projectDir, { ...installLog, assets: remaining });
|
|
12917
|
+
io.writeLog(projectDir, { ...installLog, assets: remaining, ...rootFiles });
|
|
12254
12918
|
io.log(` ${status.success(`install log updated (${remaining.length} asset(s) remain)`)}`);
|
|
12255
12919
|
} catch (e2) {
|
|
12256
12920
|
io.err(status.failure(c.red(`ERROR: install log \uAC31\uC2E0 \uC2E4\uD328 \u2014 ${installLogPath(projectDir)}`)));
|
|
@@ -12259,10 +12923,20 @@ function settleLog(ctx, io) {
|
|
|
12259
12923
|
return true;
|
|
12260
12924
|
}
|
|
12261
12925
|
} else {
|
|
12262
|
-
|
|
12926
|
+
const recordDir = join35(projectDir, INSTALL_LOG_DIR);
|
|
12927
|
+
if (outsideLinkAt(projectDir, INSTALL_LOG_DIR) !== null) io.rm(recordDir);
|
|
12928
|
+
else {
|
|
12929
|
+
for (const rel of [
|
|
12930
|
+
`${INSTALL_LOG_DIR}/${INSTALL_LOG_FILENAME}`,
|
|
12931
|
+
...HARNESS_RUNTIME_IGNORES
|
|
12932
|
+
]) {
|
|
12933
|
+
io.rm(join35(projectDir, rel));
|
|
12934
|
+
}
|
|
12935
|
+
pruneEmptyDirsUpward(projectDir, recordDir);
|
|
12936
|
+
}
|
|
12263
12937
|
if (outsideLinkAt(projectDir, LEGACY_INSTALL_LOG_DIR) === null) {
|
|
12264
12938
|
io.rm(legacyInstallLogPath(projectDir));
|
|
12265
|
-
pruneEmptyDirsUpward(projectDir,
|
|
12939
|
+
pruneEmptyDirsUpward(projectDir, join35(projectDir, LEGACY_INSTALL_LOG_DIR));
|
|
12266
12940
|
}
|
|
12267
12941
|
io.log(` ${status.success("install log removed")}`);
|
|
12268
12942
|
}
|
|
@@ -12274,7 +12948,9 @@ function dryRunLines(plan, installLog, projectDir, assetsOnly, rootFiles, harnes
|
|
|
12274
12948
|
lines2.push(c.dim(" (no project-scope assets to reverse)"));
|
|
12275
12949
|
}
|
|
12276
12950
|
lines2.push(...plan.reverseSteps.map((s) => ` \u25CB ${s.label}`));
|
|
12277
|
-
lines2.push(
|
|
12951
|
+
lines2.push(
|
|
12952
|
+
" \u25CB remove install record (.uzys-agent-harness/ \u2014 \uC124\uCE58 \uAE30\uB85D\xB7\uCC28\uB2E8 \uB85C\uADF8\xB7update \uBC31\uC5C5 \uBAA9\uB85D)"
|
|
12953
|
+
);
|
|
12278
12954
|
lines2.push(
|
|
12279
12955
|
...plan.noReversePath.flatMap((a) => [
|
|
12280
12956
|
c.dim(` \u2298 ${a.id} (${a.method}) \u2014 \uC790\uB3D9 \uB418\uB3CC\uB9AC\uAE30 \uACBD\uB85C \uC5C6\uC74C, \uAE30\uB85D \uC720\uC9C0`),
|
|
@@ -12286,9 +12962,17 @@ function dryRunLines(plan, installLog, projectDir, assetsOnly, rootFiles, harnes
|
|
|
12286
12962
|
rm: () => {
|
|
12287
12963
|
},
|
|
12288
12964
|
write: false,
|
|
12289
|
-
harnessRoot
|
|
12965
|
+
harnessRoot,
|
|
12966
|
+
assetFilesGone: plannedAssetFiles(plan, installLog)
|
|
12290
12967
|
});
|
|
12291
12968
|
lines2.push(...harnessRemovalLines(preview, installLog, projectDir, FULL_SCOPE, true));
|
|
12969
|
+
} else {
|
|
12970
|
+
const preview = restoreDisplaced(installLog, projectDir, {
|
|
12971
|
+
has: inAssetSlots(plannedAssets(plan, installLog)),
|
|
12972
|
+
willBeGone: new Set(plannedAssetFiles(plan, installLog)),
|
|
12973
|
+
write: false
|
|
12974
|
+
});
|
|
12975
|
+
lines2.push(...displacedLines(preview, true));
|
|
12292
12976
|
}
|
|
12293
12977
|
lines2.push(...advisoryLines(plan, projectDir, rootFiles, globalTrust), "");
|
|
12294
12978
|
return lines2;
|
|
@@ -12320,7 +13004,7 @@ function advisoryLines(plan, projectDir, rootFiles, globalTrust) {
|
|
|
12320
13004
|
}
|
|
12321
13005
|
function backupArtifactAdvisoryLines(projectDir) {
|
|
12322
13006
|
const found = [];
|
|
12323
|
-
for (const e2 of
|
|
13007
|
+
for (const e2 of readdirSync7(projectDir, { withFileTypes: true })) {
|
|
12324
13008
|
if (CLI_FOLDERS2.some((d2) => e2.name.startsWith(`${d2}.backup-`))) {
|
|
12325
13009
|
found.push(e2.name);
|
|
12326
13010
|
} else if (e2.isFile() && BACKUP_SUFFIX.test(e2.name)) {
|
|
@@ -12328,8 +13012,7 @@ function backupArtifactAdvisoryLines(projectDir) {
|
|
|
12328
13012
|
}
|
|
12329
13013
|
}
|
|
12330
13014
|
for (const dir of BACKUP_SCAN_DIRS) {
|
|
12331
|
-
|
|
12332
|
-
const abs = join34(projectDir, dir);
|
|
13015
|
+
const abs = join35(projectDir, dir);
|
|
12333
13016
|
if (!existsSync26(abs) || outsideLinkAt(projectDir, dir) !== null) continue;
|
|
12334
13017
|
for (const rel of listFilesRecursive(abs)) {
|
|
12335
13018
|
if (BACKUP_SUFFIX.test(rel)) found.push(`${dir}/${rel}`);
|
|
@@ -12345,11 +13028,11 @@ function backupArtifactAdvisoryLines(projectDir) {
|
|
|
12345
13028
|
}
|
|
12346
13029
|
function rootFileAdvisoryLines(rootFiles, projectDir) {
|
|
12347
13030
|
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(
|
|
13031
|
+
const present2 = rootFiles.filter((f) => existsSync26(join35(projectDir, f.path)));
|
|
12349
13032
|
if (present2.length === 0) return [];
|
|
12350
13033
|
const outside = /* @__PURE__ */ new Map();
|
|
12351
13034
|
const inside = present2.filter((f) => {
|
|
12352
|
-
const o = outsideProjectTarget(projectDir,
|
|
13035
|
+
const o = outsideProjectTarget(projectDir, join35(projectDir, f.path));
|
|
12353
13036
|
if (o === null) return true;
|
|
12354
13037
|
const group = outside.get(o.link) ?? { link: o, files: [] };
|
|
12355
13038
|
group.files.push(f.path);
|
|
@@ -12388,7 +13071,7 @@ function rootFileMeaning(f, projectDir) {
|
|
|
12388
13071
|
case "displaced": {
|
|
12389
13072
|
const backup = f.notes[0];
|
|
12390
13073
|
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(
|
|
13074
|
+
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
13075
|
}
|
|
12393
13076
|
}
|
|
12394
13077
|
}
|
|
@@ -12491,9 +13174,19 @@ function agentsMdRerenderSet(target, remaining, log, projectDir) {
|
|
|
12491
13174
|
const set = agentsMdClis(remaining);
|
|
12492
13175
|
if (set.length === 0) return null;
|
|
12493
13176
|
const recorded2 = (log.externalFiles ?? []).some((f) => f.path === AGENTS_MD2) || (log.portions ?? []).some((p2) => p2.path === AGENTS_MD2);
|
|
12494
|
-
if (!
|
|
13177
|
+
if (!existsSync26(join35(projectDir, AGENTS_MD2))) return null;
|
|
13178
|
+
if (!recorded2 && !isLegacyHarnessAgentsMd(readTextOrEmpty(join35(projectDir, AGENTS_MD2)))) {
|
|
13179
|
+
return null;
|
|
13180
|
+
}
|
|
12495
13181
|
return set;
|
|
12496
13182
|
}
|
|
13183
|
+
function readTextOrEmpty(abs) {
|
|
13184
|
+
try {
|
|
13185
|
+
return readFileSync26(abs, "utf8");
|
|
13186
|
+
} catch {
|
|
13187
|
+
return "";
|
|
13188
|
+
}
|
|
13189
|
+
}
|
|
12497
13190
|
function rerenderAgentsMd(ctx, set) {
|
|
12498
13191
|
const { installLog, projectDir, harnessRoot } = ctx;
|
|
12499
13192
|
return runAgentsMdTransform({
|
|
@@ -12512,10 +13205,11 @@ function withRerender(next, r) {
|
|
|
12512
13205
|
const files = mergeExternalFiles(next.externalFiles, r.ownership.files);
|
|
12513
13206
|
if (files.length > 0) out.externalFiles = files;
|
|
12514
13207
|
const block = r.agentsMd.shared;
|
|
12515
|
-
|
|
13208
|
+
const blockPortions = block !== null && block.portions !== null ? block.portions : r.agentsMd.blockRecordDropped === true ? [] : null;
|
|
13209
|
+
if (blockPortions !== null) {
|
|
12516
13210
|
const portions = [
|
|
12517
13211
|
...(next.portions ?? []).filter((p2) => p2.path !== AGENTS_MD2),
|
|
12518
|
-
...
|
|
13212
|
+
...blockPortions
|
|
12519
13213
|
];
|
|
12520
13214
|
if (portions.length > 0) out.portions = portions;
|
|
12521
13215
|
else delete out.portions;
|
|
@@ -12555,11 +13249,8 @@ function settleCliLog(ctx, target, remaining, done, anchorRemoved) {
|
|
|
12555
13249
|
const survivors = (installLog.externalFiles ?? []).filter((f) => !done.forgotten.has(f.path));
|
|
12556
13250
|
if (survivors.length > 0) next.externalFiles = survivors;
|
|
12557
13251
|
else delete next.externalFiles;
|
|
12558
|
-
const settled = new Set(done.displaced.filter((d2) => d2.forget).map((d2) => d2.path));
|
|
12559
13252
|
if (installLog.rootFiles !== void 0) {
|
|
12560
|
-
next.rootFiles = installLog.rootFiles.
|
|
12561
|
-
(f) => !(f.change === "displaced" && settled.has(f.path))
|
|
12562
|
-
);
|
|
13253
|
+
next.rootFiles = withoutRestored(installLog.rootFiles, done.displaced);
|
|
12563
13254
|
}
|
|
12564
13255
|
const touched = new Set(done.shared.map((r) => r.path));
|
|
12565
13256
|
const portions = [
|
|
@@ -12621,20 +13312,21 @@ var SKILLS_LOCK = "skills-lock.json";
|
|
|
12621
13312
|
function withSkillsLock(rootFiles, assets, projectDir) {
|
|
12622
13313
|
const out = [...rootFiles];
|
|
12623
13314
|
const skills = assets.some((a) => a.method === "skill" && a.scope === "project");
|
|
12624
|
-
if (skills && !out.some((f) => f.path === SKILLS_LOCK) && existsSync26(
|
|
13315
|
+
if (skills && !out.some((f) => f.path === SKILLS_LOCK) && existsSync26(join35(projectDir, SKILLS_LOCK))) {
|
|
12625
13316
|
out.push({ path: SKILLS_LOCK, change: "advisory", notes: [] });
|
|
12626
13317
|
}
|
|
12627
13318
|
return out;
|
|
12628
13319
|
}
|
|
12629
|
-
function remnantFor(path, log, harnessRoot, projectDir) {
|
|
13320
|
+
function remnantFor(path, log, harnessRoot, projectDir, wiringGone = []) {
|
|
12630
13321
|
const clis = installedClis(log);
|
|
12631
13322
|
if (path === SETTINGS_TARGET) {
|
|
13323
|
+
const gone = (k2) => wiringGone.includes(`hooks/${k2.split("#")[1] ?? ""}`);
|
|
12632
13324
|
return (disk) => {
|
|
12633
13325
|
try {
|
|
12634
|
-
const template = readFileSync26(
|
|
13326
|
+
const template = readFileSync26(join35(harnessRoot, "templates", "settings.json"), "utf8");
|
|
12635
13327
|
const render = renderSettingsPortion(template, () => true);
|
|
12636
|
-
return [...legacySettingsSeed(disk, render, projectDir).keys()].filter(
|
|
12637
|
-
(k2) => !k2.endsWith("{}")
|
|
13328
|
+
return [...legacySettingsSeed(disk, render, projectDir, { edited: true }).keys()].filter(
|
|
13329
|
+
(k2) => !k2.endsWith("{}") && !gone(k2)
|
|
12638
13330
|
);
|
|
12639
13331
|
} catch {
|
|
12640
13332
|
return [];
|
|
@@ -12716,15 +13408,24 @@ function sharedStripLines(results, preview) {
|
|
|
12716
13408
|
return id === null ? [] : [id.slice(id.indexOf(":") + 1)];
|
|
12717
13409
|
};
|
|
12718
13410
|
const names = (keys) => keys.flatMap(display).join(" \xB7 ");
|
|
13411
|
+
const stays = r.edited === void 0 ? " (yours stays)" : "";
|
|
12719
13412
|
if (r.fileRemoved) {
|
|
13413
|
+
const only = (verb) => r.edited === void 0 ? ` and only its part ${verb} in it` : "";
|
|
12720
13414
|
lines2.push(
|
|
12721
|
-
preview ? ` \u25CB remove ${r.path} (the harness created it
|
|
13415
|
+
preview ? ` \u25CB remove ${r.path} (the harness created it${only("is")})` : ` ${status.success(`${r.path} \u2014 removed (the harness created it${only("was")})`)}`
|
|
12722
13416
|
);
|
|
12723
13417
|
} else if (r.removed.length > 0) {
|
|
12724
13418
|
const which = r.path === AGENTS_MD2 ? "" : `: ${names(r.removed)}`;
|
|
12725
13419
|
const what = r.path === AGENTS_MD2 ? "the harness block" : "the harness part";
|
|
12726
13420
|
lines2.push(
|
|
12727
|
-
preview ? ` \u25CB remove ${what} from ${r.path}${which}
|
|
13421
|
+
preview ? ` \u25CB remove ${what} from ${r.path}${which}${stays}` : ` ${status.success(`${r.path} \u2014 removed ${what}${which}${stays}`)}`
|
|
13422
|
+
);
|
|
13423
|
+
}
|
|
13424
|
+
if (r.edited !== void 0) {
|
|
13425
|
+
const n = r.edited.keys.length;
|
|
13426
|
+
const edited = `you had edited ${n} harness hook line${n === 1 ? "" : "s"} (${names(r.edited.keys)})`;
|
|
13427
|
+
lines2.push(
|
|
13428
|
+
preview ? ` \u25CB ${r.path} \u2014 ${edited} \u2014 a copy is saved first as ${r.edited.backup}` : ` ${c.yellow("\u2298")} ${r.path} \u2014 ${edited} \u2014 your edit is in the copy: ${r.edited.backup}`
|
|
12728
13429
|
);
|
|
12729
13430
|
}
|
|
12730
13431
|
if (r.kept.length > 0) {
|
|
@@ -12761,7 +13462,7 @@ function noReverseHints(asset, ctx) {
|
|
|
12761
13462
|
}
|
|
12762
13463
|
if (asset.method !== "skill") return [];
|
|
12763
13464
|
const name = asset.detail.skill;
|
|
12764
|
-
const left = name === void 0 ? [] : [".claude/skills", ".agents/skills"].map((root) => `${root}/${name}/`).filter((p2) => existsSync26(
|
|
13465
|
+
const left = name === void 0 ? [] : [".claude/skills", ".agents/skills"].map((root) => `${root}/${name}/`).filter((p2) => existsSync26(join35(ctx.projectDir, p2)));
|
|
12765
13466
|
return [
|
|
12766
13467
|
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
13468
|
];
|
|
@@ -12861,21 +13562,31 @@ function removeHarnessFiles(log, projectDir, scope, io) {
|
|
|
12861
13562
|
forgotten: /* @__PURE__ */ new Set(),
|
|
12862
13563
|
stripped: [],
|
|
12863
13564
|
kept: [],
|
|
13565
|
+
legacyAgentsMd: [],
|
|
12864
13566
|
unjudged: [],
|
|
12865
13567
|
outside: [],
|
|
12866
13568
|
displaced: [],
|
|
12867
13569
|
shared: [],
|
|
12868
13570
|
retiredWiring: [],
|
|
13571
|
+
legacyWiring: [],
|
|
12869
13572
|
importStripped: false,
|
|
12870
13573
|
anchor: { removed: false, lines: [] }
|
|
12871
13574
|
};
|
|
12872
13575
|
const pruneFrom = [];
|
|
12873
|
-
stripSharedFiles(log, projectDir, scope.shared, io, out, pruneFrom);
|
|
12874
13576
|
const isTarget = harnessTargets(log);
|
|
12875
|
-
|
|
13577
|
+
const candidates = harnessCandidates(log);
|
|
13578
|
+
for (const path of candidates) {
|
|
12876
13579
|
if (scope.has(path))
|
|
12877
13580
|
removeRecordedFile(path, { log, projectDir, io, out, isTarget, pruneFrom });
|
|
12878
13581
|
}
|
|
13582
|
+
const judged = new Set(candidates);
|
|
13583
|
+
for (const path of legacyFileCandidates()) {
|
|
13584
|
+
if (judged.has(path) || !scope.has(path) || !safeExists(join35(projectDir, path))) continue;
|
|
13585
|
+
if (recorded(log, path, { isTarget }).state !== "none") continue;
|
|
13586
|
+
removeRecordedFile(path, { log, projectDir, io, out, isTarget, pruneFrom });
|
|
13587
|
+
}
|
|
13588
|
+
out.legacyWiring = removeLegacyHookWiring(log, projectDir, scope, io, out.removed);
|
|
13589
|
+
stripSharedFiles(log, projectDir, scope.shared, io, out, pruneFrom);
|
|
12879
13590
|
if (scope.importBlock) {
|
|
12880
13591
|
out.importStripped = io.write ? stripRootImport(projectDir) : hasRootImport(projectDir);
|
|
12881
13592
|
}
|
|
@@ -12884,11 +13595,19 @@ function removeHarnessFiles(log, projectDir, scope, io) {
|
|
|
12884
13595
|
const anchorPath = log.templates?.rootClaudeMd?.path;
|
|
12885
13596
|
if (out.anchor.removed && anchorPath !== void 0) out.removedAnchor = anchorPath;
|
|
12886
13597
|
}
|
|
12887
|
-
restoreDisplaced(log, projectDir,
|
|
13598
|
+
out.displaced = restoreDisplaced(log, projectDir, {
|
|
13599
|
+
has: scope.has,
|
|
13600
|
+
willBeGone: /* @__PURE__ */ new Set([
|
|
13601
|
+
...out.removed,
|
|
13602
|
+
...out.removedAnchor === void 0 ? [] : [out.removedAnchor],
|
|
13603
|
+
...io.assetFilesGone ?? []
|
|
13604
|
+
]),
|
|
13605
|
+
write: io.write
|
|
13606
|
+
});
|
|
12888
13607
|
if (io.write) {
|
|
12889
|
-
for (const p2 of pruneFrom) pruneEmptyDirsUpward(projectDir,
|
|
13608
|
+
for (const p2 of pruneFrom) pruneEmptyDirsUpward(projectDir, dirname8(join35(projectDir, p2)));
|
|
12890
13609
|
for (const d2 of scope.skeleton) {
|
|
12891
|
-
const abs =
|
|
13610
|
+
const abs = join35(projectDir, d2);
|
|
12892
13611
|
if (outsideProjectTarget(projectDir, abs) !== null) continue;
|
|
12893
13612
|
pruneEmptyDirsUpward(projectDir, abs);
|
|
12894
13613
|
}
|
|
@@ -12899,7 +13618,10 @@ function harnessCandidates(log) {
|
|
|
12899
13618
|
const paths = [
|
|
12900
13619
|
...(log.policyFiles ?? []).map((f) => `${CLAUDE_DIR3}${f.path}`),
|
|
12901
13620
|
...(log.skillFiles ?? []).map((f) => `${SKILLS_DIR3}${f.path}`),
|
|
12902
|
-
...(log.externalFiles ?? []).map((f) => f.path)
|
|
13621
|
+
...(log.externalFiles ?? []).map((f) => f.path),
|
|
13622
|
+
// 헬퍼 — writer 기록은 `externalFiles` 에 sha 로 적지만 옛 기록(≤v26.161.0)엔 항목이 없다. `recorded()` 가 가른다
|
|
13623
|
+
// (writer 기록에 없으면 `none` = 설치자 파일 · 옛 기록이면 `no-sha` = 번들 판과 같을 때만 백업 없이)
|
|
13624
|
+
...helperSources().keys(),
|
|
12903
13625
|
// 어느 필드에도 적힌 적 없는 옛 판의 하네스 파일 — `isTarget` 이 알려 준다(A8 · install 과 같은 방식)
|
|
12904
13626
|
INSTALLED_TRACKS,
|
|
12905
13627
|
// 스캔 필드가 아예 없는 옛 로그(v26.125.0 이하)는 필드가 하네스 파일을 열거하지 못한다 — manifest 의 하네스 자리 ·
|
|
@@ -12913,18 +13635,25 @@ function harnessTargets(log) {
|
|
|
12913
13635
|
const tracked = recordedTrackTargets(log);
|
|
12914
13636
|
return (p2) => p2 === INSTALLED_TRACKS || tracked(p2);
|
|
12915
13637
|
}
|
|
13638
|
+
function helperSources() {
|
|
13639
|
+
return new Map(
|
|
13640
|
+
buildManifest({ tracks: [] }).filter((e2) => isCliNeutralTarget(e2.target)).map((e2) => [e2.target, e2.source])
|
|
13641
|
+
);
|
|
13642
|
+
}
|
|
12916
13643
|
function templateNext(harnessRoot, log, path) {
|
|
12917
13644
|
if (path === INSTALLED_TRACKS) return installedTracksText(log.spec.tracks.filter(isTrack));
|
|
12918
|
-
|
|
13645
|
+
const helper = helperSources().get(path);
|
|
13646
|
+
if (helper === void 0 && !path.startsWith(CLAUDE_DIR3)) return null;
|
|
12919
13647
|
try {
|
|
12920
|
-
|
|
13648
|
+
const source = helper ?? path.slice(CLAUDE_DIR3.length);
|
|
13649
|
+
return readFileSync26(join35(harnessRoot, "templates", source), "utf8");
|
|
12921
13650
|
} catch {
|
|
12922
13651
|
return null;
|
|
12923
13652
|
}
|
|
12924
13653
|
}
|
|
12925
13654
|
function removeRecordedFile(path, ctx) {
|
|
12926
13655
|
const { log, projectDir, io, out } = ctx;
|
|
12927
|
-
const abs =
|
|
13656
|
+
const abs = join35(projectDir, path);
|
|
12928
13657
|
let foreign;
|
|
12929
13658
|
try {
|
|
12930
13659
|
foreign = foreignOwnedTarget(projectDir, path);
|
|
@@ -12966,17 +13695,20 @@ function removeRecordedFile(path, ctx) {
|
|
|
12966
13695
|
out.unjudged.push(path);
|
|
12967
13696
|
return;
|
|
12968
13697
|
}
|
|
13698
|
+
const rec = recorded(log, path, { isTarget: ctx.isTarget });
|
|
13699
|
+
const legacy = rec.state !== "sha" && isLegacyHarnessFile(path, hashContent(disk)) && (rec.state === "no-sha" || mayReclaimLegacy(log, path));
|
|
13700
|
+
const inBundle = legacy && ctx.isTarget(bundlePath(path));
|
|
12969
13701
|
const verdict = judge({
|
|
12970
13702
|
op: "remove",
|
|
12971
13703
|
kind: "harness",
|
|
12972
|
-
rec:
|
|
13704
|
+
rec: legacy ? { state: "no-sha" } : rec,
|
|
12973
13705
|
disk,
|
|
12974
|
-
next: templateNext(io.harnessRoot, log, path)
|
|
13706
|
+
next: legacy ? inBundle ? disk : null : templateNext(io.harnessRoot, log, path)
|
|
12975
13707
|
});
|
|
12976
13708
|
if (verdict.verdict !== "remove" && verdict.verdict !== "backup+remove") return;
|
|
12977
13709
|
let backup = null;
|
|
12978
13710
|
if (verdict.verdict === "backup+remove") {
|
|
12979
|
-
backup = io.write ?
|
|
13711
|
+
backup = io.write ? relative7(projectDir, backupFile(effective)).split(sep7).join("/") : `${relative7(projectDir, effective).split(sep7).join("/")}.backup-<time>`;
|
|
12980
13712
|
}
|
|
12981
13713
|
if (io.write) {
|
|
12982
13714
|
if (effective !== abs) io.rm(abs);
|
|
@@ -12985,7 +13717,34 @@ function removeRecordedFile(path, ctx) {
|
|
|
12985
13717
|
out.removed.push(path);
|
|
12986
13718
|
out.forgotten.add(path);
|
|
12987
13719
|
ctx.pruneFrom.push(path);
|
|
12988
|
-
if (backup !== null)
|
|
13720
|
+
if (backup !== null)
|
|
13721
|
+
out.backedUp.push({ path, backup, line: legacy && !inBundle ? LEGACY_SAVED : verdict.line });
|
|
13722
|
+
}
|
|
13723
|
+
var LEGACY_SAVED = "older harness version (byte-identical, not in the current bundle) \u2014 saved a copy, removed from live";
|
|
13724
|
+
function legacyFileCandidates() {
|
|
13725
|
+
return [...LEGACY_HARNESS_FILES.keys()].flatMap(
|
|
13726
|
+
(p2) => p2.startsWith(SKILLS_DIR3) ? [p2, `.agents/skills/${p2.slice(SKILLS_DIR3.length)}`] : [p2]
|
|
13727
|
+
);
|
|
13728
|
+
}
|
|
13729
|
+
function bundlePath(path) {
|
|
13730
|
+
return path.startsWith(".agents/skills/") ? `${SKILLS_DIR3}${path.slice(".agents/skills/".length)}` : path;
|
|
13731
|
+
}
|
|
13732
|
+
function mayReclaimLegacy(log, path) {
|
|
13733
|
+
const clis = installedClis(log);
|
|
13734
|
+
if (!ownersOf(path).some((c3) => clis.includes(c3))) return false;
|
|
13735
|
+
if (isExcludedPath(bundlePath(path), excludedIds(log))) return false;
|
|
13736
|
+
return !(log.rootFiles ?? []).some((f) => f.path === path && f.change === "displaced");
|
|
13737
|
+
}
|
|
13738
|
+
function removeLegacyHookWiring(log, projectDir, scope, io, removed) {
|
|
13739
|
+
if (!scope.has(SETTINGS_TARGET) || !installedClis(log).includes("claude")) return [];
|
|
13740
|
+
if ((log.portions ?? []).some((p2) => p2.path === SETTINGS_TARGET)) return [];
|
|
13741
|
+
const abs = join35(projectDir, SETTINGS_TARGET);
|
|
13742
|
+
if (!safeExists(abs) || outsideProjectTarget(projectDir, abs) !== null) return [];
|
|
13743
|
+
const claudeDir = join35(projectDir, ".claude");
|
|
13744
|
+
const gone = LEGACY_HOOK_REFS.filter(
|
|
13745
|
+
(r) => !RETIRED_HOOK_WIRING_REFS.includes(r) && (removed.includes(`${CLAUDE_DIR3}${r}`) || !safeExists(join35(claudeDir, r)))
|
|
13746
|
+
);
|
|
13747
|
+
return removeRetiredHookRefs(abs, claudeDir, gone, { evenIfScriptExists: true, write: io.write });
|
|
12989
13748
|
}
|
|
12990
13749
|
function stripSharedFiles(log, projectDir, paths, io, out, pruneFrom) {
|
|
12991
13750
|
const made = new Map((log.externalFiles ?? []).map((f) => [f.path, f.sha256]));
|
|
@@ -13004,7 +13763,7 @@ function stripSharedFiles(log, projectDir, paths, io, out, pruneFrom) {
|
|
|
13004
13763
|
};
|
|
13005
13764
|
for (const path of paths) {
|
|
13006
13765
|
if (!relevant(path)) continue;
|
|
13007
|
-
const abs =
|
|
13766
|
+
const abs = join35(projectDir, path);
|
|
13008
13767
|
if (safeExists(abs)) {
|
|
13009
13768
|
const o = outsideProjectTarget(projectDir, abs);
|
|
13010
13769
|
if (o !== null) {
|
|
@@ -13015,7 +13774,7 @@ function stripSharedFiles(log, projectDir, paths, io, out, pruneFrom) {
|
|
|
13015
13774
|
if (path === SETTINGS_TARGET && safeExists(abs)) {
|
|
13016
13775
|
out.retiredWiring = removeRetiredHookRefs(
|
|
13017
13776
|
abs,
|
|
13018
|
-
|
|
13777
|
+
join35(projectDir, ".claude"),
|
|
13019
13778
|
RETIRED_HOOK_WIRING_REFS,
|
|
13020
13779
|
{ evenIfScriptExists: true, write: io.write }
|
|
13021
13780
|
);
|
|
@@ -13024,12 +13783,15 @@ function stripSharedFiles(log, projectDir, paths, io, out, pruneFrom) {
|
|
|
13024
13783
|
if (sha !== void 0 && removeHarnessMadeShared(path, sha, projectDir, io, out, pruneFrom)) {
|
|
13025
13784
|
continue;
|
|
13026
13785
|
}
|
|
13786
|
+
if (path === AGENTS_MD2 && sha === void 0) {
|
|
13787
|
+
if (removeUnrecordedLegacyAgentsMd(path, projectDir, io, out, pruneFrom)) continue;
|
|
13788
|
+
}
|
|
13027
13789
|
const r = stripShared({
|
|
13028
13790
|
projectDir,
|
|
13029
13791
|
path,
|
|
13030
13792
|
portions: log.portions ?? [],
|
|
13031
13793
|
excluded: [...excludedIds(log)],
|
|
13032
|
-
remnant: remnantFor(path, log, io.harnessRoot, projectDir),
|
|
13794
|
+
remnant: remnantFor(path, log, io.harnessRoot, projectDir, out.legacyWiring),
|
|
13033
13795
|
remnantLine: remnantLine(path),
|
|
13034
13796
|
write: io.write,
|
|
13035
13797
|
// 하네스가 만든 파일(#569 `created` · #13 `externalFiles`)은 몫을 걷고 남는 것이 없으면 파일째 지운다
|
|
@@ -13040,7 +13802,7 @@ function stripSharedFiles(log, projectDir, paths, io, out, pruneFrom) {
|
|
|
13040
13802
|
}
|
|
13041
13803
|
}
|
|
13042
13804
|
function removeHarnessMadeShared(path, sha, projectDir, io, out, pruneFrom) {
|
|
13043
|
-
const abs =
|
|
13805
|
+
const abs = join35(projectDir, path);
|
|
13044
13806
|
if (!existsSync26(abs)) {
|
|
13045
13807
|
out.forgotten.add(path);
|
|
13046
13808
|
return true;
|
|
@@ -13061,7 +13823,15 @@ function removeHarnessMadeShared(path, sha, projectDir, io, out, pruneFrom) {
|
|
|
13061
13823
|
}
|
|
13062
13824
|
if (hashContent(current) !== sha) {
|
|
13063
13825
|
if (path === AGENTS_MD2) {
|
|
13064
|
-
|
|
13826
|
+
const verdict = isLegacyHarnessAgentsMd(current) ? agentsMdRemainder(current, io.harnessRoot) : null;
|
|
13827
|
+
if (verdict?.ok === true && verdict.strip.legacyRemoved) {
|
|
13828
|
+
removeLegacyAgentsMd(path, abs, effective, verdict.strip, {
|
|
13829
|
+
projectDir,
|
|
13830
|
+
io,
|
|
13831
|
+
out,
|
|
13832
|
+
pruneFrom
|
|
13833
|
+
});
|
|
13834
|
+
} else out.kept.push(path);
|
|
13065
13835
|
return true;
|
|
13066
13836
|
}
|
|
13067
13837
|
out.forgotten.add(path);
|
|
@@ -13073,9 +13843,13 @@ function removeHarnessMadeShared(path, sha, projectDir, io, out, pruneFrom) {
|
|
|
13073
13843
|
out.unjudged.push(path);
|
|
13074
13844
|
return true;
|
|
13075
13845
|
}
|
|
13846
|
+
if (verdict.strip.legacyRemoved) {
|
|
13847
|
+
removeLegacyAgentsMd(path, abs, effective, verdict.strip, { projectDir, io, out, pruneFrom });
|
|
13848
|
+
return true;
|
|
13849
|
+
}
|
|
13076
13850
|
if (verdict.remainder !== null) {
|
|
13077
13851
|
try {
|
|
13078
|
-
if (io.write)
|
|
13852
|
+
if (io.write) writeFileSync9(effective, neutralizeScaffoldBanner(verdict.remainder), "utf8");
|
|
13079
13853
|
out.stripped.push(path);
|
|
13080
13854
|
out.forgotten.add(path);
|
|
13081
13855
|
} catch {
|
|
@@ -13101,38 +13875,44 @@ function removeHarnessMadeShared(path, sha, projectDir, io, out, pruneFrom) {
|
|
|
13101
13875
|
pruneFrom.push(path);
|
|
13102
13876
|
return true;
|
|
13103
13877
|
}
|
|
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
13878
|
function topOf(path) {
|
|
13133
13879
|
const i = path.indexOf("/");
|
|
13134
13880
|
return i < 0 ? path : `${path.slice(0, i)}/`;
|
|
13135
13881
|
}
|
|
13882
|
+
function displacedLines(displaced, preview) {
|
|
13883
|
+
const lines2 = [];
|
|
13884
|
+
const restore = displaced.filter((d2) => d2.verdict === "restore");
|
|
13885
|
+
if (preview && restore.length > 0) {
|
|
13886
|
+
lines2.push(
|
|
13887
|
+
` \u25CB put back ${restore.length} file(s) of yours (displaced): ${restore.map((d2) => d2.path).join(" \xB7 ")}`
|
|
13888
|
+
);
|
|
13889
|
+
}
|
|
13890
|
+
for (const d2 of displaced) {
|
|
13891
|
+
if (d2.verdict === "restore" && !preview) {
|
|
13892
|
+
lines2.push(` ${status.success(`put back ${d2.path} (from ${d2.backup})`)}`);
|
|
13893
|
+
} else if (d2.verdict === "advise") {
|
|
13894
|
+
lines2.push(` ${c.yellow("\u2298")} ${d2.path} \u2014 ${d2.line}`);
|
|
13895
|
+
}
|
|
13896
|
+
}
|
|
13897
|
+
return lines2;
|
|
13898
|
+
}
|
|
13899
|
+
function plannedAssets(plan, log) {
|
|
13900
|
+
const ids = new Set(plan.reverseSteps.map((s) => s.assetId));
|
|
13901
|
+
return log.assets.filter((a) => ids.has(a.id));
|
|
13902
|
+
}
|
|
13903
|
+
function plannedAssetFiles(plan, log) {
|
|
13904
|
+
return plannedAssets(plan, log).flatMap(
|
|
13905
|
+
(a) => a.method === "skill" && a.scope === "project" ? (a.files ?? []).map((f) => f.path) : []
|
|
13906
|
+
);
|
|
13907
|
+
}
|
|
13908
|
+
function inAssetSlots(assets) {
|
|
13909
|
+
const slots = new Set(
|
|
13910
|
+
assets.flatMap(
|
|
13911
|
+
(a) => a.method === "skill" && a.scope === "project" ? (a.files ?? []).map((f) => `${f.path.split("/").slice(0, 3).join("/")}/`) : []
|
|
13912
|
+
)
|
|
13913
|
+
);
|
|
13914
|
+
return (path) => [...slots].some((s) => path.startsWith(s));
|
|
13915
|
+
}
|
|
13136
13916
|
function harnessRemovalLines(r, log, projectDir, scope, preview) {
|
|
13137
13917
|
const lines2 = [];
|
|
13138
13918
|
const groups = /* @__PURE__ */ new Map();
|
|
@@ -13147,7 +13927,7 @@ function harnessRemovalLines(r, log, projectDir, scope, preview) {
|
|
|
13147
13927
|
}
|
|
13148
13928
|
if (preview) {
|
|
13149
13929
|
for (const [top, g] of groups) {
|
|
13150
|
-
const edited = g.backedUp > 0 ? ` (${g.backedUp}
|
|
13930
|
+
const edited = g.backedUp > 0 ? ` (${g.backedUp} with a copy saved beside as *.backup-<time>)` : "";
|
|
13151
13931
|
lines2.push(` \u25CB remove ${g.removed} harness file(s) under ${top}${edited}`);
|
|
13152
13932
|
}
|
|
13153
13933
|
} else if (groups.size > 0) {
|
|
@@ -13166,24 +13946,24 @@ function harnessRemovalLines(r, log, projectDir, scope, preview) {
|
|
|
13166
13946
|
);
|
|
13167
13947
|
}
|
|
13168
13948
|
lines2.push(...r.anchor.lines);
|
|
13169
|
-
|
|
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
|
-
}
|
|
13949
|
+
lines2.push(...displacedLines(r.displaced, preview));
|
|
13182
13950
|
for (const path of r.stripped) {
|
|
13183
13951
|
lines2.push(
|
|
13184
13952
|
preview ? ` \u25CB strip harness sections from ${path} (\uBCF8\uBB38 \uBCF4\uC874)` : ` ${status.success(`${path} \u2014 harness sections removed (\uBCF8\uBB38 \uBCF4\uC874)`)}`
|
|
13185
13953
|
);
|
|
13186
13954
|
}
|
|
13955
|
+
for (const l of r.legacyAgentsMd) {
|
|
13956
|
+
const kept = l.keptEdited.length > 0 ? ` \xB7 kept ${l.keptEdited.length} section(s) you edited (${l.keptEdited.join(" \xB7 ")})` : "";
|
|
13957
|
+
if (preview) {
|
|
13958
|
+
lines2.push(
|
|
13959
|
+
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)`
|
|
13960
|
+
);
|
|
13961
|
+
} else {
|
|
13962
|
+
lines2.push(
|
|
13963
|
+
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})`)}`
|
|
13964
|
+
);
|
|
13965
|
+
}
|
|
13966
|
+
}
|
|
13187
13967
|
for (const path of r.unjudged) {
|
|
13188
13968
|
lines2.push(
|
|
13189
13969
|
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 +13975,12 @@ function harnessRemovalLines(r, log, projectDir, scope, preview) {
|
|
|
13195
13975
|
` ${c.yellow("\u2298")} ${path} kept \u2014 modified since install. Remove manually if intended.`
|
|
13196
13976
|
);
|
|
13197
13977
|
}
|
|
13978
|
+
if (r.legacyWiring.length > 0) {
|
|
13979
|
+
const refs = r.legacyWiring.join(" \xB7 ");
|
|
13980
|
+
lines2.push(
|
|
13981
|
+
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}`)}`
|
|
13982
|
+
);
|
|
13983
|
+
}
|
|
13198
13984
|
if (r.retiredWiring.length > 0) {
|
|
13199
13985
|
const refs = r.retiredWiring.join(" \xB7 ");
|
|
13200
13986
|
lines2.push(
|
|
@@ -13245,25 +14031,25 @@ function yoursUnder(projectDir, dir) {
|
|
|
13245
14031
|
const walk2 = (abs2, prefix) => {
|
|
13246
14032
|
let entries;
|
|
13247
14033
|
try {
|
|
13248
|
-
entries =
|
|
14034
|
+
entries = readdirSync7(abs2, { withFileTypes: true });
|
|
13249
14035
|
} catch {
|
|
13250
14036
|
return;
|
|
13251
14037
|
}
|
|
13252
14038
|
for (const e2 of entries) {
|
|
13253
14039
|
const name = `${prefix}${e2.name}`;
|
|
13254
|
-
if (e2.isDirectory()) walk2(
|
|
14040
|
+
if (e2.isDirectory()) walk2(join35(abs2, e2.name), `${name}/`);
|
|
13255
14041
|
else if (BACKUP_SUFFIX.test(e2.name)) continue;
|
|
13256
14042
|
else if (e2.isSymbolicLink()) {
|
|
13257
14043
|
let target = "?";
|
|
13258
14044
|
try {
|
|
13259
|
-
target = readlinkSync(
|
|
14045
|
+
target = readlinkSync(join35(abs2, e2.name));
|
|
13260
14046
|
} catch {
|
|
13261
14047
|
}
|
|
13262
14048
|
out.push({ name, shown: `${name} (your link \u2192 ${target})` });
|
|
13263
14049
|
} else out.push({ name, shown: name });
|
|
13264
14050
|
}
|
|
13265
14051
|
};
|
|
13266
|
-
const abs =
|
|
14052
|
+
const abs = join35(projectDir, dir);
|
|
13267
14053
|
try {
|
|
13268
14054
|
if (!statSync5(abs).isDirectory()) return [];
|
|
13269
14055
|
} catch {
|
|
@@ -13275,7 +14061,7 @@ function yoursUnder(projectDir, dir) {
|
|
|
13275
14061
|
function assetsLeftLines(log, projectDir, scope) {
|
|
13276
14062
|
const lines2 = [];
|
|
13277
14063
|
for (const a of log.assets) {
|
|
13278
|
-
const here = (a.files ?? []).map((f) => f.path).filter((p2) => scope.has(p2) && safeExists(
|
|
14064
|
+
const here = (a.files ?? []).map((f) => f.path).filter((p2) => scope.has(p2) && safeExists(join35(projectDir, p2)));
|
|
13279
14065
|
if (here.length === 0) continue;
|
|
13280
14066
|
const slots = [...new Set(here.map((p2) => p2.split("/").slice(0, 3).join("/")))].sort();
|
|
13281
14067
|
lines2.push(
|
|
@@ -13287,7 +14073,7 @@ function assetsLeftLines(log, projectDir, scope) {
|
|
|
13287
14073
|
function removeAnchor(log, projectDir, io) {
|
|
13288
14074
|
const rootMd = log.templates?.rootClaudeMd;
|
|
13289
14075
|
if (!rootMd) return { removed: false, lines: [] };
|
|
13290
|
-
const abs =
|
|
14076
|
+
const abs = join35(projectDir, rootMd.path);
|
|
13291
14077
|
if (!existsSync26(abs)) return { removed: false, lines: [] };
|
|
13292
14078
|
const outside = outsideProjectTarget(projectDir, abs);
|
|
13293
14079
|
if (outside !== null) return { removed: false, lines: outsideLines([outside], log) };
|
|
@@ -13326,7 +14112,7 @@ function removeAnchor(log, projectDir, io) {
|
|
|
13326
14112
|
]
|
|
13327
14113
|
};
|
|
13328
14114
|
}
|
|
13329
|
-
const backup = edited ?
|
|
14115
|
+
const backup = edited ? relative7(projectDir, backupFile(abs)).split(sep7).join("/") : null;
|
|
13330
14116
|
io.rm(abs);
|
|
13331
14117
|
return {
|
|
13332
14118
|
removed: true,
|
|
@@ -13338,7 +14124,7 @@ function removeAnchor(log, projectDir, io) {
|
|
|
13338
14124
|
var AGENTS_MD2 = "AGENTS.md";
|
|
13339
14125
|
function readAgentsMdTemplate(harnessRoot) {
|
|
13340
14126
|
try {
|
|
13341
|
-
return readFileSync26(
|
|
14127
|
+
return readFileSync26(join35(harnessRoot, AGENTS_MD_TEMPLATE), "utf8");
|
|
13342
14128
|
} catch {
|
|
13343
14129
|
return null;
|
|
13344
14130
|
}
|
|
@@ -13356,21 +14142,67 @@ function neutralizeScaffoldBanner(text) {
|
|
|
13356
14142
|
function agentsMdRemainder(current, harnessRoot) {
|
|
13357
14143
|
const template = readAgentsMdTemplate(harnessRoot);
|
|
13358
14144
|
if (template === null) return { ok: false };
|
|
13359
|
-
|
|
13360
|
-
|
|
13361
|
-
|
|
13362
|
-
|
|
13363
|
-
|
|
13364
|
-
|
|
13365
|
-
|
|
13366
|
-
|
|
14145
|
+
const strip = stripAgentsMd({
|
|
14146
|
+
existing: current,
|
|
14147
|
+
template,
|
|
14148
|
+
harnessRuleHeadings: ruleHeadings(harnessRoot)
|
|
14149
|
+
});
|
|
14150
|
+
return { ok: true, remainder: strip.remainder, strip };
|
|
14151
|
+
}
|
|
14152
|
+
function removeUnrecordedLegacyAgentsMd(path, projectDir, io, out, pruneFrom) {
|
|
14153
|
+
const abs = join35(projectDir, path);
|
|
14154
|
+
let effective = abs;
|
|
14155
|
+
let current;
|
|
14156
|
+
try {
|
|
14157
|
+
const real = realpathSync3(abs);
|
|
14158
|
+
if (!statSync5(real).isFile()) return false;
|
|
14159
|
+
if (lstatSync5(abs).isSymbolicLink()) effective = real;
|
|
14160
|
+
current = readFileSync26(effective, "utf8");
|
|
14161
|
+
} catch {
|
|
14162
|
+
return false;
|
|
14163
|
+
}
|
|
14164
|
+
if (!isLegacyHarnessAgentsMd(current)) return false;
|
|
14165
|
+
const verdict = agentsMdRemainder(current, io.harnessRoot);
|
|
14166
|
+
if (!verdict.ok) {
|
|
14167
|
+
out.unjudged.push(path);
|
|
14168
|
+
return true;
|
|
14169
|
+
}
|
|
14170
|
+
removeLegacyAgentsMd(path, abs, effective, verdict.strip, { projectDir, io, out, pruneFrom });
|
|
14171
|
+
return true;
|
|
14172
|
+
}
|
|
14173
|
+
function removeLegacyAgentsMd(path, abs, effective, strip, ctx) {
|
|
14174
|
+
const { projectDir, io, out } = ctx;
|
|
14175
|
+
let backup = `${path}.backup-<time>`;
|
|
14176
|
+
try {
|
|
14177
|
+
if (io.write) {
|
|
14178
|
+
backup = relative7(projectDir, backupFile(effective)).split(sep7).join("/");
|
|
14179
|
+
if (strip.remainder !== null) {
|
|
14180
|
+
writeFileSync9(effective, neutralizeScaffoldBanner(strip.remainder), "utf8");
|
|
14181
|
+
} else {
|
|
14182
|
+
if (effective !== abs) io.rm(abs);
|
|
14183
|
+
io.rm(effective);
|
|
14184
|
+
}
|
|
14185
|
+
}
|
|
14186
|
+
} catch {
|
|
14187
|
+
out.unjudged.push(path);
|
|
14188
|
+
return;
|
|
14189
|
+
}
|
|
14190
|
+
if (strip.remainder === null) ctx.pruneFrom.push(path);
|
|
14191
|
+
out.legacyAgentsMd.push({
|
|
14192
|
+
path,
|
|
14193
|
+
backup,
|
|
14194
|
+
fileRemoved: strip.remainder === null,
|
|
14195
|
+
keptEdited: strip.keptEdited
|
|
14196
|
+
});
|
|
14197
|
+
out.forgotten.add(path);
|
|
14198
|
+
out.shared.push({ path, action: "none", line: "", removed: [], kept: [], portions: [] });
|
|
13367
14199
|
}
|
|
13368
14200
|
function removeToolFiles(files, projectDir, rm) {
|
|
13369
14201
|
const notes = [];
|
|
13370
14202
|
const removed = [];
|
|
13371
14203
|
let failed = 0;
|
|
13372
14204
|
for (const { path, sha256 } of files) {
|
|
13373
|
-
const abs =
|
|
14205
|
+
const abs = join35(projectDir, path);
|
|
13374
14206
|
let isLink;
|
|
13375
14207
|
try {
|
|
13376
14208
|
isLink = lstatSync5(abs).isSymbolicLink();
|
|
@@ -13389,7 +14221,7 @@ function removeToolFiles(files, projectDir, rm) {
|
|
|
13389
14221
|
try {
|
|
13390
14222
|
if (hashContent(readFileSync26(abs, "utf8")) !== sha256) {
|
|
13391
14223
|
const backup = backupFile(abs);
|
|
13392
|
-
notes.push(`backed up ${path} \u2192 ${
|
|
14224
|
+
notes.push(`backed up ${path} \u2192 ${relative7(projectDir, backup)} (changed since install)`);
|
|
13393
14225
|
}
|
|
13394
14226
|
rm(abs);
|
|
13395
14227
|
removed.push(path);
|
|
@@ -13398,21 +14230,21 @@ function removeToolFiles(files, projectDir, rm) {
|
|
|
13398
14230
|
notes.push(`left ${path} \u2014 ${e2 instanceof Error ? e2.message : String(e2)}`);
|
|
13399
14231
|
}
|
|
13400
14232
|
}
|
|
13401
|
-
for (const path of removed) pruneEmptyDirsUpward(projectDir,
|
|
14233
|
+
for (const path of removed) pruneEmptyDirsUpward(projectDir, dirname8(join35(projectDir, path)));
|
|
13402
14234
|
return failed > 0 ? { ok: false, message: `${failed} file(s) could not be removed`, notes } : { ok: true, notes };
|
|
13403
14235
|
}
|
|
13404
14236
|
function pruneEmptyDirsUpward(projectDir, startDir) {
|
|
13405
14237
|
let cursor = startDir;
|
|
13406
14238
|
while (true) {
|
|
13407
|
-
const rel =
|
|
13408
|
-
if (rel === "" || rel.startsWith(`..${
|
|
14239
|
+
const rel = relative7(projectDir, cursor);
|
|
14240
|
+
if (rel === "" || rel.startsWith(`..${sep7}`) || rel === "..") return;
|
|
13409
14241
|
try {
|
|
13410
|
-
if (
|
|
13411
|
-
|
|
14242
|
+
if (readdirSync7(cursor).length > 0) return;
|
|
14243
|
+
rmdirSync3(cursor);
|
|
13412
14244
|
} catch {
|
|
13413
14245
|
return;
|
|
13414
14246
|
}
|
|
13415
|
-
cursor =
|
|
14247
|
+
cursor = dirname8(cursor);
|
|
13416
14248
|
}
|
|
13417
14249
|
}
|
|
13418
14250
|
function stripRootImport(projectDir) {
|
|
@@ -13420,8 +14252,8 @@ function stripRootImport(projectDir) {
|
|
|
13420
14252
|
const stripped = current === null ? null : stripHarnessImport(current);
|
|
13421
14253
|
if (stripped === null) return false;
|
|
13422
14254
|
try {
|
|
13423
|
-
backupIfLossyUtf8(
|
|
13424
|
-
|
|
14255
|
+
backupIfLossyUtf8(join35(projectDir, "CLAUDE.md"));
|
|
14256
|
+
writeFileSync9(join35(projectDir, "CLAUDE.md"), stripped, "utf8");
|
|
13425
14257
|
return true;
|
|
13426
14258
|
} catch {
|
|
13427
14259
|
return false;
|
|
@@ -13432,7 +14264,7 @@ function hasRootImport(projectDir) {
|
|
|
13432
14264
|
return current !== null && stripHarnessImport(current) !== null;
|
|
13433
14265
|
}
|
|
13434
14266
|
function readRootClaudeMd(projectDir) {
|
|
13435
|
-
const path =
|
|
14267
|
+
const path = join35(projectDir, "CLAUDE.md");
|
|
13436
14268
|
if (!existsSync26(path)) return null;
|
|
13437
14269
|
try {
|
|
13438
14270
|
return readFileSync26(path, "utf8");
|
|
@@ -13445,7 +14277,7 @@ function defaultSpawn2(cmd, args) {
|
|
|
13445
14277
|
}
|
|
13446
14278
|
function defaultRm(path) {
|
|
13447
14279
|
if (existsSync26(path)) {
|
|
13448
|
-
|
|
14280
|
+
rmSync5(path, { recursive: true, force: true });
|
|
13449
14281
|
}
|
|
13450
14282
|
}
|
|
13451
14283
|
function registerUninstallCommand(cli) {
|