@ikie-dev/cli 9.8.7 → 9.9.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/.ikie/ferments/019f2b5d-426e-741a-a176-6031399e42cd/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-4289-71d5-9c92-949495910599/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-42a0-74f5-b804-1dd55616035a/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-42c5-7381-83e5-548f04ddbc55/runtime.json +12 -0
- package/.ikie/ferments/019f2b5d-42fd-702c-baef-81f5354cc24e/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-432e-7322-9af5-5333b4686468/runtime.json +15 -0
- package/.ikie/ferments/019f2b5d-434d-7429-b25f-0b58109fa362/runtime.json +15 -0
- package/.ikie/ferments/019f2b5d-436e-7389-b2ad-6a02cda4f9bb/runtime.json +15 -0
- package/.ikie/ferments/019f2b5d-439d-74dd-9786-13df51571d6b/runtime.json +13 -0
- package/.ikie/ferments/019f2b5d-43ce-71c9-81e0-16aa00ff9e28/runtime.json +15 -0
- package/.ikie/ferments/019f2b5d-440e-72cc-8509-b6b3fd2b6c6c/runtime.json +15 -0
- package/.ikie/ferments/019f2b5d-444f-73c1-8172-dbad1e42640a/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-4469-71c1-97ff-23e2bb7ccc3b/runtime.json +15 -0
- package/.ikie/ferments/019f2b5d-448d-714d-b181-338e8a5dc8e1/runtime.json +15 -0
- package/.ikie/ferments/019f2b5d-44ad-71fb-b0a9-a1f949f9129a/runtime.json +15 -0
- package/.ikie/ferments/019f2b5d-44ca-730d-993c-9a827d415ffd/runtime.json +15 -0
- package/.ikie/ferments/019f2b5d-44ec-71c8-8523-031284e26b4b/runtime.json +15 -0
- package/.ikie/ferments/019f2b5d-450e-7013-93c5-3dd9b900ebd3/runtime.json +15 -0
- package/.ikie/ferments/019f2b5d-452a-714d-aff8-fdaca0988792/runtime.json +15 -0
- package/.ikie/ferments/019f2b5d-4550-749d-8807-3e9493ba614b/runtime.json +15 -0
- package/.ikie/ferments/019f2b5d-4570-7713-8d0f-5d13e8446bfb/runtime.json +15 -0
- package/.ikie/ferments/019f2b5d-459a-778a-a7f7-3317ecd6837f/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-45c1-718d-9ba5-b55dd0160a78/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-45f9-7381-9394-4647f47a2132/reviews/phase-phase-1-1.json +63 -0
- package/.ikie/ferments/019f2b5d-45f9-7381-9394-4647f47a2132/runtime.json +17 -0
- package/.ikie/ferments/019f2b5d-4782-71d4-89de-9c3e734707c8/reviews/phase-phase-1-1.json +63 -0
- package/.ikie/ferments/019f2b5d-4782-71d4-89de-9c3e734707c8/runtime.json +17 -0
- package/.ikie/ferments/019f2b5d-4950-728c-bf46-542c8ec21a6c/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-4de5-75df-8d7d-a1cd2588a596/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-4e07-70d4-9152-0925c5f81057/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-4e28-7770-8b24-587c856e4b9b/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-4e48-7159-9cb7-6401c6930ed4/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-4e6e-73a9-8bfd-639e394f48a4/pending-proposal.json +45 -0
- package/.ikie/ferments/019f2b5d-4e85-73c4-b099-4f6dc69c5268/pending-proposal.json +45 -0
- package/.ikie/ferments/019f2b5d-4fd0-7019-a28a-49af2a0266ed/pending-proposal.json +45 -0
- package/.ikie/ferments/019f2b5d-5045-70cc-b084-9ccd595944b3/pending-proposal.json +45 -0
- package/.ikie/ferments/019f2b5d-5056-759a-ae60-d4e8d2f7554f/pending-proposal.json +45 -0
- package/.ikie/ferments/019f2b5d-883b-759c-8453-2a7e8200e481/runtime.json +13 -0
- package/.ikie/ferments/019f2b5d-8873-723e-9b60-75d7ece374f9/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-8898-70a3-8c9d-ef7f569c3e72/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-88b4-710c-ba72-ef0fc3dbf0ae/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-88d2-73cf-8983-953907020e62/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-88f3-73df-9ffa-dd262c3d4163/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-8912-74db-b14a-95e882507c3e/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-892b-76c2-b9b3-42dbf26fa1c5/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-8956-74d1-883d-b974060e341f/runtime.json +9 -0
- package/.ikie/ferments/019f2b5d-8979-741b-9ecc-2fe299103e8e/runtime.json +13 -0
- package/.ikie/ferments/019f2b5d-89a1-74ed-83f8-f19dd9f63c9d/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-89c9-71d8-88b2-8ded0c6a473e/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-8a28-7309-a773-95dde5282ddf/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-8a3c-7088-85cd-9e45836799c8/runtime.json +9 -0
- package/.ikie/ferments/019f2b5d-8a58-727b-8607-94e087e8b56f/runtime.json +9 -0
- package/.ikie/ferments/019f2b5d-8a6d-7465-bd8e-ab8c1cdbeef8/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-8b30-75d0-9526-93a548435f3a/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-8b4b-7352-a7a2-899427c50e5d/runtime.json +12 -0
- package/.ikie/ferments/019f2b5d-8b6f-723b-83fa-556273e78c4e/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-8b95-74b2-b003-5ecf17ff2936/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-8ba6-71f3-90eb-37751e5bab04/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-8bbe-7251-b4f0-5d52ca8bbd0f/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-8bd6-779d-b55d-3df6cfd3d4ba/runtime.json +13 -0
- package/.ikie/ferments/019f2b5d-8bee-75b5-acf7-95f68fd37837/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-9b8e-7307-a95c-7e184eed7946/reviews/phase-phase-1-1.json +41 -0
- package/.ikie/ferments/019f2b5d-9b8e-7307-a95c-7e184eed7946/runtime.json +11 -0
- package/.ikie/ferments/019f2b5d-9bd7-7418-a977-3d39b5027fcc/reviews/phase-phase-1-1.json +47 -0
- package/.ikie/ferments/019f2b5d-9bd7-7418-a977-3d39b5027fcc/runtime.json +13 -0
- package/.ikie/ferments/019f2b5d-9c36-738b-9800-c32b17ab0a08/reviews/phase-phase-1-1.json +40 -0
- package/.ikie/ferments/019f2b5d-9c36-738b-9800-c32b17ab0a08/runtime.json +9 -0
- package/.ikie/ferments/019f2b5d-9c67-76b8-9a49-00bf505ca1b8/reviews/phase-phase-1-1.json +40 -0
- package/.ikie/ferments/019f2b5d-9c67-76b8-9a49-00bf505ca1b8/runtime.json +9 -0
- package/.ikie/ferments/019f2b5d-9c80-73ba-98ca-fa4595c45658/reviews/phase-phase-1-1.json +40 -0
- package/.ikie/ferments/019f2b5d-9c80-73ba-98ca-fa4595c45658/runtime.json +9 -0
- package/.ikie/ferments/019f2b5d-9c9e-71a5-bd87-e317142e21fd/reviews/phase-phase-1-1.json +40 -0
- package/.ikie/ferments/019f2b5d-9c9e-71a5-bd87-e317142e21fd/runtime.json +9 -0
- package/.ikie/ferments/019f2b5d-9cc1-73bf-98ae-cdd3759fdbd4/reviews/phase-phase-1-1.json +40 -0
- package/.ikie/ferments/019f2b5d-9cc1-73bf-98ae-cdd3759fdbd4/runtime.json +9 -0
- package/.ikie/ferments/019f2b5d-9cd9-7478-aa4d-68ff15ec302e/reviews/phase-phase-1-1.json +62 -0
- package/.ikie/ferments/019f2b5d-9cd9-7478-aa4d-68ff15ec302e/runtime.json +9 -0
- package/.ikie/ferments/019f2b6e-10f5-71fd-b0ac-906640800f2a/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-111f-75fe-af2b-0a9cf1727058/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-113b-73de-9df2-3dc2058b0037/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-115e-772e-91f2-45da602cc046/runtime.json +12 -0
- package/.ikie/ferments/019f2b6e-1174-70a1-a06e-4c9a676e7a44/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-1199-70d9-ae9a-01e965e953f1/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-11d1-74af-ab47-8e94823af880/runtime.json +15 -0
- package/.ikie/ferments/019f2b6e-11f3-7087-a610-3673d9a730c8/runtime.json +15 -0
- package/.ikie/ferments/019f2b6e-1214-7778-974a-3773b4f88517/runtime.json +15 -0
- package/.ikie/ferments/019f2b6e-123b-762d-8600-80a4da430695/runtime.json +13 -0
- package/.ikie/ferments/019f2b6e-1271-76b7-8c79-2c86e0e70e8c/runtime.json +15 -0
- package/.ikie/ferments/019f2b6e-129a-731e-93aa-a4f113bfeda8/runtime.json +15 -0
- package/.ikie/ferments/019f2b6e-12db-728a-bea2-d97e3310b918/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-12f5-72a8-8ea9-e83e907bb297/runtime.json +15 -0
- package/.ikie/ferments/019f2b6e-131a-714e-8d20-eb7a6aaeed29/runtime.json +15 -0
- package/.ikie/ferments/019f2b6e-1349-72aa-a518-6fac705a8a5f/runtime.json +15 -0
- package/.ikie/ferments/019f2b6e-1374-740e-8b66-ccc849baf168/runtime.json +15 -0
- package/.ikie/ferments/019f2b6e-13a6-75fd-a594-0e6dec52929b/runtime.json +15 -0
- package/.ikie/ferments/019f2b6e-13d3-775b-a8ad-e8efc6332d52/runtime.json +15 -0
- package/.ikie/ferments/019f2b6e-13ff-753a-aac4-207bd4d84720/runtime.json +15 -0
- package/.ikie/ferments/019f2b6e-1423-71ba-9cb9-8d5dc4ba44af/runtime.json +15 -0
- package/.ikie/ferments/019f2b6e-1449-77b9-95f8-c8b9a5cdbe1b/runtime.json +15 -0
- package/.ikie/ferments/019f2b6e-1475-771f-95b7-41248e78e547/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-1498-76c2-a4c3-4a9d6ea8727d/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-14bd-77ad-89ea-7706d62850c0/reviews/phase-phase-1-1.json +63 -0
- package/.ikie/ferments/019f2b6e-14bd-77ad-89ea-7706d62850c0/runtime.json +17 -0
- package/.ikie/ferments/019f2b6e-1627-755e-943c-164dc672353c/reviews/phase-phase-1-1.json +63 -0
- package/.ikie/ferments/019f2b6e-1627-755e-943c-164dc672353c/runtime.json +17 -0
- package/.ikie/ferments/019f2b6e-17a9-74b2-921b-1d9ec0a01d5f/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-1bb3-71ad-8be1-e8e3cd1a78b8/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-1bde-778e-9fd2-dc5291b667d4/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-1bfd-717c-8ab8-6d6b97e73a76/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-1c1e-724b-80f7-e8084123ea42/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-1c3c-70a8-ab5c-8858a41b1111/pending-proposal.json +45 -0
- package/.ikie/ferments/019f2b6e-1c52-71af-975e-f514de2d2a9f/pending-proposal.json +45 -0
- package/.ikie/ferments/019f2b6e-1d84-726a-9382-0f49ac269f40/pending-proposal.json +45 -0
- package/.ikie/ferments/019f2b6e-1dcb-760e-b2cd-c06ba8d57f7c/pending-proposal.json +45 -0
- package/.ikie/ferments/019f2b6e-1de3-74a8-8567-7960dca0da46/pending-proposal.json +45 -0
- package/.ikie/ferments/019f2b6e-50b5-77dc-a145-de2797f954ba/runtime.json +13 -0
- package/.ikie/ferments/019f2b6e-513b-7019-9404-f46db9a8b3ec/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-5159-7711-9957-3393d05b23a3/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-5175-771d-8391-8f6b9f807ea8/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-519c-730d-bfed-592ef56a2720/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-51cd-709b-b3b5-352e20717ad9/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-51f0-728a-9edf-7e48bd6c69a7/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-521b-763a-9fe9-c7197b8209cd/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-5242-702d-a4aa-feb8569b86ad/runtime.json +9 -0
- package/.ikie/ferments/019f2b6e-5269-725a-be96-7135e5857c5f/runtime.json +13 -0
- package/.ikie/ferments/019f2b6e-52a5-74c9-b708-335a2e9bf42b/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-52e4-7506-89cb-182398a88f40/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-5389-736c-b328-dd8fa27082f9/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-53be-774f-9a27-291c66f2747a/runtime.json +9 -0
- package/.ikie/ferments/019f2b6e-53f4-73ae-bbca-2124c710812b/runtime.json +9 -0
- package/.ikie/ferments/019f2b6e-542e-71ee-87b1-37bbc5f40ccd/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-55b4-7238-89f5-a2a50dcaff05/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-55ec-72ba-a3b7-3b7739efe858/runtime.json +12 -0
- package/.ikie/ferments/019f2b6e-563d-721b-8ba0-f3286b33f62f/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-565b-7453-9046-2a7e60c63c62/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-5684-7125-a1ef-41494eb8be74/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-56a7-7512-b7e5-3c709a24a5e9/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-56ea-702a-9a97-7911f5f2caad/runtime.json +13 -0
- package/.ikie/ferments/019f2b6e-5730-75fb-bad2-18d701837e37/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-645f-7522-a80c-ddcd6935f5dc/reviews/phase-phase-1-1.json +41 -0
- package/.ikie/ferments/019f2b6e-645f-7522-a80c-ddcd6935f5dc/runtime.json +11 -0
- package/.ikie/ferments/019f2b6e-64aa-7328-ae9b-04f663f377b8/reviews/phase-phase-1-1.json +47 -0
- package/.ikie/ferments/019f2b6e-64aa-7328-ae9b-04f663f377b8/runtime.json +13 -0
- package/.ikie/ferments/019f2b6e-64fe-723a-99a2-0fab54b29f4a/reviews/phase-phase-1-1.json +40 -0
- package/.ikie/ferments/019f2b6e-64fe-723a-99a2-0fab54b29f4a/runtime.json +9 -0
- package/.ikie/ferments/019f2b6e-651b-7018-91c0-baa3cf77c217/reviews/phase-phase-1-1.json +40 -0
- package/.ikie/ferments/019f2b6e-651b-7018-91c0-baa3cf77c217/runtime.json +9 -0
- package/.ikie/ferments/019f2b6e-6533-70ee-a6de-6b3bc5ca17ef/reviews/phase-phase-1-1.json +40 -0
- package/.ikie/ferments/019f2b6e-6533-70ee-a6de-6b3bc5ca17ef/runtime.json +9 -0
- package/.ikie/ferments/019f2b6e-654d-7760-942f-6ea45bebb394/reviews/phase-phase-1-1.json +40 -0
- package/.ikie/ferments/019f2b6e-654d-7760-942f-6ea45bebb394/runtime.json +9 -0
- package/.ikie/ferments/019f2b6e-6563-74c5-bfd2-d8075d4005db/reviews/phase-phase-1-1.json +40 -0
- package/.ikie/ferments/019f2b6e-6563-74c5-bfd2-d8075d4005db/runtime.json +9 -0
- package/.ikie/ferments/019f2b6e-6586-748a-83ac-05ea7a9e24f3/reviews/phase-phase-1-1.json +62 -0
- package/.ikie/ferments/019f2b6e-6586-748a-83ac-05ea7a9e24f3/runtime.json +9 -0
- package/.ikie/ferments/019f2b8e-485a-722f-ab3e-0b23bdf37851/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-4876-7247-ba41-e38f1dc709af/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-488d-732e-9b99-75f4ad2f9983/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-48ad-70b7-b262-ecb600a8be1a/runtime.json +12 -0
- package/.ikie/ferments/019f2b8e-48d9-73af-92cb-aa861441eef8/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-4906-7494-9168-5e15c0e984ed/runtime.json +15 -0
- package/.ikie/ferments/019f2b8e-4929-71db-a7b5-b8686b433b49/runtime.json +15 -0
- package/.ikie/ferments/019f2b8e-494a-774c-8e7e-e881204e3b2b/runtime.json +15 -0
- package/.ikie/ferments/019f2b8e-4972-70ab-8b70-9f8ac3ad9f33/runtime.json +13 -0
- package/.ikie/ferments/019f2b8e-49a7-7058-95e7-ea362f0554ba/runtime.json +15 -0
- package/.ikie/ferments/019f2b8e-49d5-750e-a1e0-7e7cf027c6c7/runtime.json +15 -0
- package/.ikie/ferments/019f2b8e-4a12-7181-a65a-c6bbb6e750f3/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-4a2a-7741-a5d7-8109a9bf4c22/runtime.json +15 -0
- package/.ikie/ferments/019f2b8e-4a4e-712f-9830-598e984f59b5/runtime.json +15 -0
- package/.ikie/ferments/019f2b8e-4a72-71da-97bf-f2970d34ae8d/runtime.json +15 -0
- package/.ikie/ferments/019f2b8e-4a93-76bc-8a04-28cdbb24a987/runtime.json +15 -0
- package/.ikie/ferments/019f2b8e-4ab9-770e-b160-59b011c69b81/runtime.json +15 -0
- package/.ikie/ferments/019f2b8e-4ae2-7619-8055-ddefbc9f4698/runtime.json +15 -0
- package/.ikie/ferments/019f2b8e-4b0c-722e-9afe-6fab90611474/runtime.json +15 -0
- package/.ikie/ferments/019f2b8e-4b3f-7143-b577-91721e39f89d/runtime.json +15 -0
- package/.ikie/ferments/019f2b8e-4b72-720d-a104-19ce38a362e2/runtime.json +15 -0
- package/.ikie/ferments/019f2b8e-4bab-70e9-ac26-136c55e9e4c0/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-4bca-714d-80d0-317ca4733687/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-4bf1-7029-a93f-c509e847ec71/reviews/phase-phase-1-1.json +63 -0
- package/.ikie/ferments/019f2b8e-4bf1-7029-a93f-c509e847ec71/runtime.json +17 -0
- package/.ikie/ferments/019f2b8e-4d51-75ff-951e-652cf6a5e901/reviews/phase-phase-1-1.json +63 -0
- package/.ikie/ferments/019f2b8e-4d51-75ff-951e-652cf6a5e901/runtime.json +17 -0
- package/.ikie/ferments/019f2b8e-4ece-70cf-a9bb-9ba0327f74f1/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-52f5-71dc-86d6-d08c3dba9c10/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-5313-747f-b0b7-9ec09f80674a/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-5333-759e-9a2e-2198d28d8a31/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-535d-7501-86c4-2d120359fda5/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-537e-7528-b236-a550ec6f9b9b/pending-proposal.json +45 -0
- package/.ikie/ferments/019f2b8e-5393-74aa-86a6-31db0e99c73c/pending-proposal.json +45 -0
- package/.ikie/ferments/019f2b8e-54cd-7573-bb52-14899e431b6a/pending-proposal.json +45 -0
- package/.ikie/ferments/019f2b8e-551d-755d-9aa9-52bb0c7ce63e/pending-proposal.json +45 -0
- package/.ikie/ferments/019f2b8e-5549-708c-8b89-1a6cc53a4ec5/pending-proposal.json +45 -0
- package/.ikie/ferments/019f2b8e-8874-7469-a3ca-1f19416a5413/runtime.json +13 -0
- package/.ikie/ferments/019f2b8e-88a4-737d-82ba-59fb52017a81/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-88c7-7448-a22d-bc9dcd6e06a2/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-88dc-72a8-813b-c9f1c91a6dd2/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-88ee-7600-a227-18ca80b3d525/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-88ff-7027-9bb9-e583b435e8b0/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-8919-737a-9f89-b74eeb851e5c/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-8936-71cc-9056-bca6ef3cbb91/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-8966-77f5-b367-a9262cc45f25/runtime.json +9 -0
- package/.ikie/ferments/019f2b8e-8990-747d-b585-59cd82d765c6/runtime.json +13 -0
- package/.ikie/ferments/019f2b8e-89c9-71ed-a2e6-016626cbe5aa/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-89de-741f-ba71-489cca892cc4/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-8a1e-727d-b14a-daf7374500ea/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-8a35-7463-803e-de399c8d3158/runtime.json +9 -0
- package/.ikie/ferments/019f2b8e-8a51-72ad-b6d1-966e350960b7/runtime.json +9 -0
- package/.ikie/ferments/019f2b8e-8a6c-73e1-a3ab-f1e554db6b03/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-8b16-7688-a299-84f3acc74338/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-8b2f-71bf-8c76-21f5ce28b4fd/runtime.json +12 -0
- package/.ikie/ferments/019f2b8e-8b54-711e-b25c-8e06b22d52a3/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-8b66-7039-97d2-00e7b31d85fe/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-8b7a-76c8-8456-727db5f07f3f/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-8b8e-7451-a3d6-7fbcc67a28c9/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-8ba1-73e8-bff2-bfbc47873b3b/runtime.json +13 -0
- package/.ikie/ferments/019f2b8e-8bb9-721b-aad5-fab25fa9b1d1/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-982a-74b9-b1b2-ad6c1b598e0a/reviews/phase-phase-1-1.json +41 -0
- package/.ikie/ferments/019f2b8e-982a-74b9-b1b2-ad6c1b598e0a/runtime.json +11 -0
- package/.ikie/ferments/019f2b8e-986d-7469-949a-be76ce3780d3/reviews/phase-phase-1-1.json +47 -0
- package/.ikie/ferments/019f2b8e-986d-7469-949a-be76ce3780d3/runtime.json +13 -0
- package/.ikie/ferments/019f2b8e-98ba-749a-839a-f5b64fbca3bc/reviews/phase-phase-1-1.json +40 -0
- package/.ikie/ferments/019f2b8e-98ba-749a-839a-f5b64fbca3bc/runtime.json +9 -0
- package/.ikie/ferments/019f2b8e-98f7-7482-b89d-ca40d860d72b/reviews/phase-phase-1-1.json +40 -0
- package/.ikie/ferments/019f2b8e-98f7-7482-b89d-ca40d860d72b/runtime.json +9 -0
- package/.ikie/ferments/019f2b8e-991a-729a-83c8-0da93e3f26ff/reviews/phase-phase-1-1.json +40 -0
- package/.ikie/ferments/019f2b8e-991a-729a-83c8-0da93e3f26ff/runtime.json +9 -0
- package/.ikie/ferments/019f2b8e-9931-713f-845d-211cb77d0482/reviews/phase-phase-1-1.json +40 -0
- package/.ikie/ferments/019f2b8e-9931-713f-845d-211cb77d0482/runtime.json +9 -0
- package/.ikie/ferments/019f2b8e-9952-734c-a3b4-8877348a7856/reviews/phase-phase-1-1.json +40 -0
- package/.ikie/ferments/019f2b8e-9952-734c-a3b4-8877348a7856/runtime.json +9 -0
- package/.ikie/ferments/019f2b8e-9974-700e-b045-cc2244e4d691/reviews/phase-phase-1-1.json +62 -0
- package/.ikie/ferments/019f2b8e-9974-700e-b045-cc2244e4d691/runtime.json +9 -0
- package/benchmark/audit-session/audit-session.sh +0 -0
- package/benchmark/manual/check-session.py +0 -0
- package/benchmark/manual/new-session-claude.sh +0 -0
- package/benchmark/manual/new-session.sh +0 -0
- package/benchmark/manual/run-evaluation.sh +0 -0
- package/benchmark/manual/start-self-improvement.sh +0 -0
- package/benchmark/terminal-bench-2/scripts/analyze-ferment-bench.py +0 -0
- package/benchmark/terminal-bench-2/scripts/run-claude-code-ikie.sh +0 -0
- package/benchmark/terminal-bench-2/scripts/run-gsd-ikie.sh +0 -0
- package/benchmark/terminal-bench-2/scripts/run-local.sh +0 -0
- package/benchmark/terminal-bench-2/scripts/run-opencode-ikie.sh +0 -0
- package/benchmark/terminal-bench-2/scripts/run-release.sh +0 -0
- package/package.json +103 -125
- package/scripts/dev-overlay.sh +0 -0
- package/scripts/dev-startup.sh +0 -0
- package/scripts/install.sh +0 -0
- package/scripts/prepublish-npm.js +1 -1
- package/scripts/verify-acp-load.mjs +0 -0
- package/src/cli-auth/index.test.ts +14 -10
- package/src/extensions/agents/prompt/skill-loader.test.ts +18 -0
- package/src/extensions/agents/prompt/skill-loader.ts +4 -1
- package/src/extensions/prompt-construction/prompt-enrichment.test.ts +41 -0
- package/src/extensions/prompt-construction/prompt-enrichment.ts +4 -1
- package/src/extensions/skills-manager/skill-manager.test.ts +31 -14
- package/src/extensions/skills-manager/skill-manager.ts +14 -5
- package/src/extensions/skills-manager/skill-sanitizer.test.ts +287 -0
- package/src/extensions/skills-manager/skill-sanitizer.ts +269 -0
- package/src/models.test.ts +3 -1
- package/vendor/superpowers/hooks/run-hook.cmd +0 -0
- package/vendor/superpowers/hooks/session-start +0 -0
- package/vendor/superpowers/scripts/bump-version.sh +0 -0
- package/vendor/superpowers/scripts/sync-to-codex-plugin.sh +0 -0
- package/vendor/superpowers/skills/brainstorming/scripts/start-server.sh +0 -0
- package/vendor/superpowers/skills/brainstorming/scripts/stop-server.sh +0 -0
- package/vendor/superpowers/skills/systematic-debugging/find-polluter.sh +0 -0
- package/vendor/superpowers/skills/writing-skills/render-graphs.js +0 -0
- package/vendor/superpowers/tests/brainstorm-server/windows-lifecycle.test.sh +0 -0
- package/vendor/superpowers/tests/claude-code/analyze-token-usage.py +0 -0
- package/vendor/superpowers/tests/claude-code/run-skill-tests.sh +0 -0
- package/vendor/superpowers/tests/claude-code/test-document-review-system.sh +0 -0
- package/vendor/superpowers/tests/claude-code/test-helpers.sh +0 -0
- package/vendor/superpowers/tests/claude-code/test-requesting-code-review.sh +0 -0
- package/vendor/superpowers/tests/claude-code/test-subagent-driven-development-integration.sh +0 -0
- package/vendor/superpowers/tests/claude-code/test-subagent-driven-development.sh +0 -0
- package/vendor/superpowers/tests/claude-code/test-worktree-native-preference.sh +0 -0
- package/vendor/superpowers/tests/codex-plugin-sync/test-sync-to-codex-plugin.sh +0 -0
- package/vendor/superpowers/tests/explicit-skill-requests/run-all.sh +0 -0
- package/vendor/superpowers/tests/explicit-skill-requests/run-claude-describes-sdd.sh +0 -0
- package/vendor/superpowers/tests/explicit-skill-requests/run-extended-multiturn-test.sh +0 -0
- package/vendor/superpowers/tests/explicit-skill-requests/run-haiku-test.sh +0 -0
- package/vendor/superpowers/tests/explicit-skill-requests/run-multiturn-test.sh +0 -0
- package/vendor/superpowers/tests/explicit-skill-requests/run-test.sh +0 -0
- package/vendor/superpowers/tests/opencode/run-tests.sh +0 -0
- package/vendor/superpowers/tests/opencode/setup.sh +0 -0
- package/vendor/superpowers/tests/opencode/test-bootstrap-caching.sh +0 -0
- package/vendor/superpowers/tests/opencode/test-plugin-loading.sh +0 -0
- package/vendor/superpowers/tests/opencode/test-priority.sh +0 -0
- package/vendor/superpowers/tests/opencode/test-tools.sh +0 -0
- package/vendor/superpowers/tests/skill-triggering/run-all.sh +0 -0
- package/vendor/superpowers/tests/skill-triggering/run-test.sh +0 -0
- package/vendor/superpowers/tests/subagent-driven-dev/go-fractals/scaffold.sh +0 -0
- package/vendor/superpowers/tests/subagent-driven-dev/run-test.sh +0 -0
- package/vendor/superpowers/tests/subagent-driven-dev/svelte-todo/scaffold.sh +0 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"
|
|
2
|
+
import { tmpdir } from "node:os"
|
|
3
|
+
import { join } from "node:path"
|
|
4
|
+
import { loadSkillsFromDir } from "@earendil-works/pi-coding-agent"
|
|
5
|
+
import { afterEach, describe, expect, it } from "vitest"
|
|
6
|
+
import { createSkillSanitizer, isValidSkillName, normalizeSkillName, sanitizeSkillMarkdown } from "./skill-sanitizer.js"
|
|
7
|
+
|
|
8
|
+
describe("normalizeSkillName", () => {
|
|
9
|
+
it("lowercases input", () => {
|
|
10
|
+
expect(normalizeSkillName("FooBar")).toBe("foobar")
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
it("replaces runs of invalid chars with a single hyphen", () => {
|
|
14
|
+
expect(normalizeSkillName("ckm:slides")).toBe("ckm-slides")
|
|
15
|
+
expect(normalizeSkillName("foo_bar")).toBe("foo-bar")
|
|
16
|
+
expect(normalizeSkillName("a b")).toBe("a-b")
|
|
17
|
+
expect(normalizeSkillName("a___b")).toBe("a-b")
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it("trims leading and trailing hyphens", () => {
|
|
21
|
+
expect(normalizeSkillName("-foo-")).toBe("foo")
|
|
22
|
+
expect(normalizeSkillName("---bar---")).toBe("bar")
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it("truncates to 64 characters", () => {
|
|
26
|
+
const long = "a".repeat(100)
|
|
27
|
+
expect(normalizeSkillName(long)).toHaveLength(64)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it("falls back to 'skill' when empty after normalization", () => {
|
|
31
|
+
expect(normalizeSkillName("")).toBe("skill")
|
|
32
|
+
expect(normalizeSkillName("___")).toBe("skill")
|
|
33
|
+
expect(normalizeSkillName("---")).toBe("skill")
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
it("collapses consecutive hyphens", () => {
|
|
37
|
+
expect(normalizeSkillName("foo--bar")).toBe("foo-bar")
|
|
38
|
+
})
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
describe("isValidSkillName", () => {
|
|
42
|
+
it("accepts valid names", () => {
|
|
43
|
+
expect(isValidSkillName("ckm-slides")).toBe(true)
|
|
44
|
+
expect(isValidSkillName("ui-ux-pro-max")).toBe(true)
|
|
45
|
+
expect(isValidSkillName("abc")).toBe(true)
|
|
46
|
+
expect(isValidSkillName("a1b2")).toBe(true)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it("rejects empty or too long", () => {
|
|
50
|
+
expect(isValidSkillName("")).toBe(false)
|
|
51
|
+
expect(isValidSkillName("a".repeat(65))).toBe(false)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it("rejects invalid characters", () => {
|
|
55
|
+
expect(isValidSkillName("ckm:slides")).toBe(false)
|
|
56
|
+
expect(isValidSkillName("Foo_Bar")).toBe(false)
|
|
57
|
+
expect(isValidSkillName("foo.bar")).toBe(false)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it("rejects leading/trailing hyphens", () => {
|
|
61
|
+
expect(isValidSkillName("-bad")).toBe(false)
|
|
62
|
+
expect(isValidSkillName("bad-")).toBe(false)
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it("rejects consecutive hyphens", () => {
|
|
66
|
+
expect(isValidSkillName("bad--bad")).toBe(false)
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
describe("sanitizeSkillMarkdown", () => {
|
|
71
|
+
it("leaves valid skill content unchanged", () => {
|
|
72
|
+
const input = `---
|
|
73
|
+
name: ckm-slides
|
|
74
|
+
description: My slides skill
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
# Body
|
|
78
|
+
|
|
79
|
+
Some content.`
|
|
80
|
+
expect(sanitizeSkillMarkdown(input)).toBe(input)
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it("rewrites name: ckm:slides to quoted normalized form", () => {
|
|
84
|
+
const input = `---
|
|
85
|
+
name: ckm:slides
|
|
86
|
+
description: slides
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
Body content`
|
|
90
|
+
const out = sanitizeSkillMarkdown(input)
|
|
91
|
+
expect(out).toContain('name: "ckm-slides"')
|
|
92
|
+
expect(out).not.toContain("ckm:slides")
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
it("rewrites name: Foo_Bar to quoted normalized form", () => {
|
|
96
|
+
const input = `---
|
|
97
|
+
name: Foo_Bar
|
|
98
|
+
description: foo bar
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
Body`
|
|
102
|
+
const out = sanitizeSkillMarkdown(input)
|
|
103
|
+
expect(out).toContain('name: "foo-bar"')
|
|
104
|
+
expect(out).not.toContain("Foo_Bar")
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it("preserves body content", () => {
|
|
108
|
+
const input = `---
|
|
109
|
+
name: ckm:slides
|
|
110
|
+
description: slides
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
# Heading
|
|
114
|
+
|
|
115
|
+
Important body content with code:
|
|
116
|
+
|
|
117
|
+
\`\`\`bash
|
|
118
|
+
echo hi
|
|
119
|
+
\`\`\`
|
|
120
|
+
`
|
|
121
|
+
const out = sanitizeSkillMarkdown(input)
|
|
122
|
+
expect(out).toContain("# Heading")
|
|
123
|
+
expect(out).toContain("Important body content")
|
|
124
|
+
expect(out).toContain("echo hi")
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
it("preserves non-name frontmatter keys", () => {
|
|
128
|
+
const input = `---
|
|
129
|
+
name: ckm:slides
|
|
130
|
+
description: slides
|
|
131
|
+
allowed-tools: Read, Write
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
Body`
|
|
135
|
+
const out = sanitizeSkillMarkdown(input)
|
|
136
|
+
expect(out).toContain('name: "ckm-slides"')
|
|
137
|
+
expect(out).toContain("allowed-tools: Read, Write")
|
|
138
|
+
expect(out).toContain("description: slides")
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
it("returns content unchanged when name is missing", () => {
|
|
142
|
+
const input = `---
|
|
143
|
+
description: only description
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
Body`
|
|
147
|
+
expect(sanitizeSkillMarkdown(input)).toBe(input)
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
it("returns content unchanged when there is no frontmatter", () => {
|
|
151
|
+
const input = "Just a body with no frontmatter."
|
|
152
|
+
expect(sanitizeSkillMarkdown(input)).toBe(input)
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
it("returns content unchanged on frontmatter parse failure", () => {
|
|
156
|
+
const input = `---
|
|
157
|
+
name: ckm:slides
|
|
158
|
+
description: [unterminated
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
Body`
|
|
162
|
+
expect(sanitizeSkillMarkdown(input)).toBe(input)
|
|
163
|
+
})
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
describe("createSkillSanitizer / sanitizeDir", () => {
|
|
167
|
+
let createdTempDirs: string[] = []
|
|
168
|
+
|
|
169
|
+
afterEach(() => {
|
|
170
|
+
for (const d of createdTempDirs) {
|
|
171
|
+
try {
|
|
172
|
+
rmSync(d, { recursive: true, force: true })
|
|
173
|
+
} catch {
|
|
174
|
+
// ignore
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
createdTempDirs = []
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
function makeSourceDir(files: Record<string, string>): string {
|
|
181
|
+
const dir = mkdtempSync(join(tmpdir(), "ikie-sanitizer-test-src-"))
|
|
182
|
+
createdTempDirs.push(dir)
|
|
183
|
+
for (const [relPath, content] of Object.entries(files)) {
|
|
184
|
+
const full = join(dir, relPath)
|
|
185
|
+
mkdirSync(join(full, ".."), { recursive: true })
|
|
186
|
+
writeFileSync(full, content, "utf-8")
|
|
187
|
+
}
|
|
188
|
+
return dir
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
it("produces a directory that loads cleanly via upstream loadSkillsFromDir", () => {
|
|
192
|
+
const source = makeSourceDir({
|
|
193
|
+
"ckm:slides/SKILL.md": `---
|
|
194
|
+
name: ckm:slides
|
|
195
|
+
description: slides skill
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
body`,
|
|
199
|
+
})
|
|
200
|
+
|
|
201
|
+
const sanitizer = createSkillSanitizer()
|
|
202
|
+
const sanitizedDir = sanitizer.sanitizeDir(source)
|
|
203
|
+
createdTempDirs.push(sanitizedDir)
|
|
204
|
+
expect(existsSync(join(sanitizedDir, "ckm:slides", "SKILL.md"))).toBe(true)
|
|
205
|
+
|
|
206
|
+
const result = loadSkillsFromDir({ dir: sanitizedDir, source: "user" })
|
|
207
|
+
const nameDiagnostics = result.diagnostics.filter(
|
|
208
|
+
(d) => typeof d.message === "string" && d.message.toLowerCase().includes("name"),
|
|
209
|
+
)
|
|
210
|
+
expect(nameDiagnostics).toEqual([])
|
|
211
|
+
expect(result.skills.length).toBe(1)
|
|
212
|
+
expect(result.skills[0].name).toBe("ckm-slides")
|
|
213
|
+
|
|
214
|
+
const sanitizedContent = readFileSync(join(sanitizedDir, "ckm:slides", "SKILL.md"), "utf-8")
|
|
215
|
+
expect(sanitizedContent).toContain('name: "ckm-slides"')
|
|
216
|
+
|
|
217
|
+
sanitizer.cleanup()
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
it("sanitizePath handles a directory via sanitizeDir", () => {
|
|
221
|
+
const source = makeSourceDir({
|
|
222
|
+
"ckm:slides/SKILL.md": `---
|
|
223
|
+
name: ckm:slides
|
|
224
|
+
description: slides skill
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
body`,
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
const sanitizer = createSkillSanitizer()
|
|
231
|
+
const sanitizedDir = sanitizer.sanitizePath(source)
|
|
232
|
+
createdTempDirs.push(sanitizedDir)
|
|
233
|
+
expect(existsSync(join(sanitizedDir, "ckm:slides", "SKILL.md"))).toBe(true)
|
|
234
|
+
|
|
235
|
+
const result = loadSkillsFromDir({ dir: sanitizedDir, source: "user" })
|
|
236
|
+
const nameDiagnostics = result.diagnostics.filter(
|
|
237
|
+
(d) => typeof d.message === "string" && d.message.toLowerCase().includes("name"),
|
|
238
|
+
)
|
|
239
|
+
expect(nameDiagnostics).toEqual([])
|
|
240
|
+
expect(result.skills.length).toBe(1)
|
|
241
|
+
expect(result.skills[0].name).toBe("ckm-slides")
|
|
242
|
+
|
|
243
|
+
sanitizer.cleanup()
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
it("sanitizePath handles a single .md file by copying it into a cached skill directory", () => {
|
|
247
|
+
const sourceDir = mkdtempSync(join(tmpdir(), "ikie-sanitizer-test-src-"))
|
|
248
|
+
createdTempDirs.push(sourceDir)
|
|
249
|
+
const sourceFile = join(sourceDir, "ckm:slides.md")
|
|
250
|
+
writeFileSync(
|
|
251
|
+
sourceFile,
|
|
252
|
+
`---
|
|
253
|
+
name: ckm:slides
|
|
254
|
+
description: slides skill
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
body content`,
|
|
258
|
+
"utf-8",
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
const sanitizer = createSkillSanitizer()
|
|
262
|
+
const sanitizedDir = sanitizer.sanitizePath(sourceFile)
|
|
263
|
+
createdTempDirs.push(sanitizedDir)
|
|
264
|
+
expect(existsSync(join(sanitizedDir, "SKILL.md"))).toBe(true)
|
|
265
|
+
|
|
266
|
+
const result = loadSkillsFromDir({ dir: sanitizedDir, source: "user" })
|
|
267
|
+
const nameDiagnostics = result.diagnostics.filter(
|
|
268
|
+
(d) => typeof d.message === "string" && d.message.toLowerCase().includes("name"),
|
|
269
|
+
)
|
|
270
|
+
expect(nameDiagnostics).toEqual([])
|
|
271
|
+
expect(result.skills.length).toBe(1)
|
|
272
|
+
expect(result.skills[0].name).toBe("ckm-slides")
|
|
273
|
+
|
|
274
|
+
const sanitizedContent = readFileSync(join(sanitizedDir, "SKILL.md"), "utf-8")
|
|
275
|
+
expect(sanitizedContent).toContain('name: "ckm-slides"')
|
|
276
|
+
expect(sanitizedContent).toContain("body content")
|
|
277
|
+
|
|
278
|
+
sanitizer.cleanup()
|
|
279
|
+
})
|
|
280
|
+
|
|
281
|
+
it("sanitizePath returns the original path for non-existent paths", () => {
|
|
282
|
+
const sanitizer = createSkillSanitizer()
|
|
283
|
+
const missing = join(tmpdir(), "ikie-sanitizer-missing-", Date.now().toString())
|
|
284
|
+
expect(sanitizer.sanitizePath(missing)).toBe(missing)
|
|
285
|
+
sanitizer.cleanup()
|
|
286
|
+
})
|
|
287
|
+
})
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { createHash } from "node:crypto"
|
|
2
|
+
import {
|
|
3
|
+
cpSync,
|
|
4
|
+
existsSync,
|
|
5
|
+
mkdirSync,
|
|
6
|
+
mkdtempSync,
|
|
7
|
+
readFileSync,
|
|
8
|
+
readdirSync,
|
|
9
|
+
rmSync,
|
|
10
|
+
statSync,
|
|
11
|
+
writeFileSync,
|
|
12
|
+
} from "node:fs"
|
|
13
|
+
import { tmpdir } from "node:os"
|
|
14
|
+
import { basename, extname, join } from "node:path"
|
|
15
|
+
import { parse as parseYaml } from "yaml"
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Shared skill-name sanitizer for ikie.
|
|
19
|
+
*
|
|
20
|
+
* Mirrors the Agent Skills spec used by `@earendil-works/pi-coding-agent`:
|
|
21
|
+
* - lowercase a-z, digits, hyphens only
|
|
22
|
+
* - no leading/trailing hyphens
|
|
23
|
+
* - no consecutive hyphens
|
|
24
|
+
* - max 64 characters
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
const MAX_NAME_LENGTH = 64
|
|
28
|
+
const VALID_NAME_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/
|
|
29
|
+
const FRONTMATTER_REGEX = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Normalize a raw skill name to a valid Agent Skills name.
|
|
33
|
+
* - lower-case
|
|
34
|
+
* - replace runs of invalid characters with a single hyphen
|
|
35
|
+
* - trim leading/trailing hyphens
|
|
36
|
+
* - truncate to 64 characters
|
|
37
|
+
* - fall back to `"skill"` if the result would be empty
|
|
38
|
+
*/
|
|
39
|
+
export function normalizeSkillName(raw: string): string {
|
|
40
|
+
const normalized = raw
|
|
41
|
+
.toLowerCase()
|
|
42
|
+
.replace(/[^a-z0-9-]+/g, "-")
|
|
43
|
+
.replace(/-+/g, "-")
|
|
44
|
+
.replace(/^-+|-+$/g, "")
|
|
45
|
+
.slice(0, MAX_NAME_LENGTH)
|
|
46
|
+
.replace(/^-+|-+$/g, "")
|
|
47
|
+
|
|
48
|
+
return normalized.length > 0 ? normalized : "skill"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* True iff `name` is a valid Agent Skills name (matches the upstream regex and length limit).
|
|
53
|
+
*/
|
|
54
|
+
export function isValidSkillName(name: string): boolean {
|
|
55
|
+
if (typeof name !== "string") return false
|
|
56
|
+
if (name.length === 0 || name.length > MAX_NAME_LENGTH) return false
|
|
57
|
+
return VALID_NAME_RE.test(name)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Sanitize the frontmatter `name` field of a skill markdown file in-place.
|
|
62
|
+
*
|
|
63
|
+
* - If the content does not start with `---` frontmatter, return as-is.
|
|
64
|
+
* - Parse the frontmatter YAML and read the `name` field.
|
|
65
|
+
* - If `name` is missing or already valid, return the original content unchanged.
|
|
66
|
+
* - If `name` is invalid, rewrite the first top-level `name:` line to
|
|
67
|
+
* `name: <normalized>` (the normalized value is JSON-quoted).
|
|
68
|
+
* - If frontmatter parsing fails, return the original content unchanged.
|
|
69
|
+
*/
|
|
70
|
+
export function sanitizeSkillMarkdown(content: string): string {
|
|
71
|
+
const match = FRONTMATTER_REGEX.exec(content)
|
|
72
|
+
if (!match) return content
|
|
73
|
+
|
|
74
|
+
const frontmatter = match[1]
|
|
75
|
+
const fmStart = match.index ?? 0
|
|
76
|
+
const fmEnd = fmStart + match[0].length
|
|
77
|
+
|
|
78
|
+
let parsed: unknown
|
|
79
|
+
try {
|
|
80
|
+
parsed = parseYaml(frontmatter)
|
|
81
|
+
} catch {
|
|
82
|
+
return content
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
86
|
+
return content
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const record = parsed as Record<string, unknown>
|
|
90
|
+
const rawName = record.name
|
|
91
|
+
if (typeof rawName !== "string" || rawName.length === 0) {
|
|
92
|
+
return content
|
|
93
|
+
}
|
|
94
|
+
if (isValidSkillName(rawName)) {
|
|
95
|
+
return content
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const normalized = normalizeSkillName(rawName)
|
|
99
|
+
const replacement = `name: ${JSON.stringify(normalized)}`
|
|
100
|
+
|
|
101
|
+
// match[1] is the inner frontmatter text between the two `---` markers.
|
|
102
|
+
// Its offset within `content` is right after the opening `---` line.
|
|
103
|
+
const openingPrefix = content.slice(fmStart, fmStart + 4) // "---\n" or "---\r\n"
|
|
104
|
+
const innerStart = fmStart + openingPrefix.length
|
|
105
|
+
const innerEnd = innerStart + match[1].length
|
|
106
|
+
|
|
107
|
+
const inner = content.slice(innerStart, innerEnd)
|
|
108
|
+
const lines = inner.split("\n")
|
|
109
|
+
let replaced = false
|
|
110
|
+
const newLines = lines.map((line) => {
|
|
111
|
+
if (replaced) return line
|
|
112
|
+
// Match top-level "name:" key (no leading whitespace).
|
|
113
|
+
if (/^name:\s*/.test(line)) {
|
|
114
|
+
replaced = true
|
|
115
|
+
return replacement
|
|
116
|
+
}
|
|
117
|
+
return line
|
|
118
|
+
})
|
|
119
|
+
|
|
120
|
+
if (!replaced) {
|
|
121
|
+
// No top-level `name:` line was found; insert one at the top of the frontmatter.
|
|
122
|
+
newLines.unshift(replacement)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const newInner = newLines.join("\n")
|
|
126
|
+
return content.slice(0, innerStart) + newInner + content.slice(innerEnd)
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
interface SkillSanitizer {
|
|
130
|
+
sanitizeDir(dir: string): string
|
|
131
|
+
sanitizePath(path: string): string
|
|
132
|
+
cleanup(): void
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
let cachedRoot: string | undefined
|
|
136
|
+
let cleanupRegistered = false
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Create a process-lifetime skill sanitizer. It maintains a single temp
|
|
140
|
+
* directory and caches per-input sanitized copies so callers can re-use
|
|
141
|
+
* the result across invocations.
|
|
142
|
+
*
|
|
143
|
+
* The returned `sanitizeDir(dir)` copies `dir` (recursively) into the cache
|
|
144
|
+
* and rewrites every `SKILL.md` in place with `sanitizeSkillMarkdown`.
|
|
145
|
+
* The cached path is returned.
|
|
146
|
+
*
|
|
147
|
+
* `cleanup()` removes the temp directory; it is also registered as a
|
|
148
|
+
* process-exit handler on first invocation.
|
|
149
|
+
*/
|
|
150
|
+
export function createSkillSanitizer(): SkillSanitizer {
|
|
151
|
+
function getRoot(): string {
|
|
152
|
+
if (cachedRoot === undefined) {
|
|
153
|
+
cachedRoot = mkdtempSync(join(tmpdir(), "ikie-sanitized-skills-"))
|
|
154
|
+
if (!cleanupRegistered) {
|
|
155
|
+
cleanupRegistered = true
|
|
156
|
+
process.once("exit", () => {
|
|
157
|
+
if (cachedRoot) {
|
|
158
|
+
try {
|
|
159
|
+
rmSync(cachedRoot, { recursive: true, force: true })
|
|
160
|
+
} catch {
|
|
161
|
+
// best-effort cleanup
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return cachedRoot
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function sanitizeDir(dir: string): string {
|
|
171
|
+
const root = getRoot()
|
|
172
|
+
const key = createHash("sha256").update(dir).digest("hex").slice(0, 12)
|
|
173
|
+
const target = join(root, key)
|
|
174
|
+
rmSync(target, { recursive: true, force: true })
|
|
175
|
+
mkdirSync(target, { recursive: true })
|
|
176
|
+
cpSync(dir, target, { recursive: true, force: true })
|
|
177
|
+
|
|
178
|
+
rewriteSkillFiles(target)
|
|
179
|
+
|
|
180
|
+
return target
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function sanitizePath(path: string): string {
|
|
184
|
+
if (!existsSync(path)) {
|
|
185
|
+
return path
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
try {
|
|
189
|
+
const stats = statSync(path)
|
|
190
|
+
if (stats.isDirectory()) {
|
|
191
|
+
return sanitizeDir(path)
|
|
192
|
+
}
|
|
193
|
+
if (stats.isFile() && extname(path).toLowerCase() === ".md") {
|
|
194
|
+
const root = getRoot()
|
|
195
|
+
const key = createHash("sha256").update(path).digest("hex").slice(0, 12)
|
|
196
|
+
const targetDir = join(root, key)
|
|
197
|
+
rmSync(targetDir, { recursive: true, force: true })
|
|
198
|
+
mkdirSync(targetDir, { recursive: true })
|
|
199
|
+
|
|
200
|
+
const stem = basename(path, ".md")
|
|
201
|
+
const skillDir = join(targetDir, stem)
|
|
202
|
+
mkdirSync(skillDir, { recursive: true })
|
|
203
|
+
|
|
204
|
+
const targetFile = join(skillDir, "SKILL.md")
|
|
205
|
+
const original = readFileSync(path, "utf-8")
|
|
206
|
+
const updated = sanitizeSkillMarkdown(original)
|
|
207
|
+
writeFileSync(targetFile, updated, "utf-8")
|
|
208
|
+
|
|
209
|
+
return skillDir
|
|
210
|
+
}
|
|
211
|
+
} catch {
|
|
212
|
+
// fall through to returning the original path
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return path
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function cleanup(): void {
|
|
219
|
+
if (cachedRoot !== undefined) {
|
|
220
|
+
try {
|
|
221
|
+
rmSync(cachedRoot, { recursive: true, force: true })
|
|
222
|
+
} catch {
|
|
223
|
+
// best-effort cleanup
|
|
224
|
+
}
|
|
225
|
+
cachedRoot = undefined
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return { sanitizeDir, sanitizePath, cleanup }
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function rewriteSkillFiles(dir: string): void {
|
|
233
|
+
let entries: import("node:fs").Dirent[]
|
|
234
|
+
try {
|
|
235
|
+
entries = readdirSync(dir, { withFileTypes: true })
|
|
236
|
+
} catch {
|
|
237
|
+
return
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
for (const entry of entries) {
|
|
241
|
+
const fullPath = join(dir, entry.name.toString())
|
|
242
|
+
if (entry.isDirectory()) {
|
|
243
|
+
rewriteSkillFiles(fullPath)
|
|
244
|
+
continue
|
|
245
|
+
}
|
|
246
|
+
const name = entry.name.toString()
|
|
247
|
+
if (entry.isFile() && name === "SKILL.md") {
|
|
248
|
+
try {
|
|
249
|
+
const original = readFileSync(fullPath, "utf-8")
|
|
250
|
+
const updated = sanitizeSkillMarkdown(original)
|
|
251
|
+
if (updated !== original) {
|
|
252
|
+
writeFileSync(fullPath, updated, "utf-8")
|
|
253
|
+
}
|
|
254
|
+
} catch {
|
|
255
|
+
// skip files we can't read/write
|
|
256
|
+
}
|
|
257
|
+
} else if (entry.isSymbolicLink() && name === "SKILL.md" && existsSync(fullPath)) {
|
|
258
|
+
try {
|
|
259
|
+
const original = readFileSync(fullPath, "utf-8")
|
|
260
|
+
const updated = sanitizeSkillMarkdown(original)
|
|
261
|
+
if (updated !== original) {
|
|
262
|
+
writeFileSync(fullPath, updated, "utf-8")
|
|
263
|
+
}
|
|
264
|
+
} catch {
|
|
265
|
+
// skip
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
package/src/models.test.ts
CHANGED
|
@@ -190,7 +190,9 @@ describe("updateModelsConfig", () => {
|
|
|
190
190
|
json: async () => ({ models: [KIMI] }),
|
|
191
191
|
} as Response)
|
|
192
192
|
|
|
193
|
-
await updateModelsConfig(modelsJsonPath, "test-key", {
|
|
193
|
+
await updateModelsConfig(modelsJsonPath, "test-key", {
|
|
194
|
+
endpoint: "https://custom.ikie.example/v1/chat/completions",
|
|
195
|
+
})
|
|
194
196
|
|
|
195
197
|
expect(fetch).toHaveBeenCalledWith(
|
|
196
198
|
"https://custom.ikie.example/models",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/vendor/superpowers/tests/claude-code/test-subagent-driven-development-integration.sh
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|