@ikie-dev/cli 9.8.7 → 9.9.1
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/ferment/index.ts +2 -0
- package/src/extensions/ferment/tools/escalate.ts +70 -0
- package/src/extensions/orchestration/continuation-nudge.test.ts +9 -0
- package/src/extensions/orchestration/continuation-nudge.ts +8 -0
- package/src/extensions/orchestration/model-roles.test.ts +6 -1
- package/src/extensions/orchestration/model-roles.ts +6 -0
- package/src/extensions/prompt-construction/prompt-enrichment.test.ts +49 -3
- 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/src/shared/planning/tool-catalog.test.ts +15 -8
- package/src/shared/planning/tool-catalog.ts +4 -3
- 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
|
@@ -3,6 +3,7 @@ import { arch, version as osVersion, platform, release, tmpdir } from "node:os"
|
|
|
3
3
|
import { join } from "node:path"
|
|
4
4
|
import type { AssistantMessage, ToolResultMessage } from "@earendil-works/pi-ai"
|
|
5
5
|
import type { ExtensionAPI, ToolInfo } from "@earendil-works/pi-coding-agent"
|
|
6
|
+
import { loadSkillsFromDir } from "@earendil-works/pi-coding-agent"
|
|
6
7
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"
|
|
7
8
|
import * as config from "../../config.js"
|
|
8
9
|
import type { ModelMetadata } from "../../models.js"
|
|
@@ -11,6 +12,7 @@ import * as startupContext from "../../startup-context.js"
|
|
|
11
12
|
import * as agentWorkerContext from "../agent-worker-context.js"
|
|
12
13
|
import { CLAUDE_CODE_SKILLS_RESOURCE_ID } from "../claude-code-skills/definition.js"
|
|
13
14
|
import type { OrchestratorMessages } from "../orchestration/continuation-nudge.js"
|
|
15
|
+
import * as modelRoles from "../orchestration/model-roles.js"
|
|
14
16
|
import promptEnrichmentExtension, {
|
|
15
17
|
stripEmptyToolCalls,
|
|
16
18
|
_resetDeprecatedNotificationTracking,
|
|
@@ -509,6 +511,46 @@ describe("prompt enrichment Claude Code skills", () => {
|
|
|
509
511
|
|
|
510
512
|
expect(result.systemPrompt).not.toContain("<name>typescript-safety</name>")
|
|
511
513
|
})
|
|
514
|
+
|
|
515
|
+
it("sanitizes project skill names and emits no name-validation diagnostics", async () => {
|
|
516
|
+
const cwd = join(dir, "project")
|
|
517
|
+
const skillDir = join(cwd, ".ikie", "skills", "ckm-slides")
|
|
518
|
+
writeRawSkill(
|
|
519
|
+
join(skillDir, "SKILL.md"),
|
|
520
|
+
`---
|
|
521
|
+
name: ckm:slides
|
|
522
|
+
description: Ikie project slides skill.
|
|
523
|
+
---
|
|
524
|
+
|
|
525
|
+
# Slides
|
|
526
|
+
|
|
527
|
+
Slides skill body.
|
|
528
|
+
`,
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
const { createSkillSanitizer } = await import("../skills-manager/skill-sanitizer.js")
|
|
532
|
+
const sanitizer = createSkillSanitizer()
|
|
533
|
+
const sanitizedDir = sanitizer.sanitizePath(skillDir)
|
|
534
|
+
const directLoad = loadSkillsFromDir({ dir: sanitizedDir, source: "project" })
|
|
535
|
+
const nameDiagnostics = directLoad.diagnostics.filter(
|
|
536
|
+
(d) => d.type === "warning" && typeof d.message === "string" && d.message.toLowerCase().includes("name"),
|
|
537
|
+
)
|
|
538
|
+
expect(nameDiagnostics).toEqual([])
|
|
539
|
+
expect(directLoad.skills.map((s) => s.name)).toContain("ckm-slides")
|
|
540
|
+
sanitizer.cleanup()
|
|
541
|
+
|
|
542
|
+
const { beforeAgentStart } = buildPromptExtensionWithHandlers([])
|
|
543
|
+
if (!beforeAgentStart) throw new Error("before_agent_start handler was not registered")
|
|
544
|
+
|
|
545
|
+
const result = (await beforeAgentStart(
|
|
546
|
+
{},
|
|
547
|
+
{ cwd, model: undefined, hasUI: false, sessionManager: { getSessionId: () => "session-1" } },
|
|
548
|
+
)) as { systemPrompt: string }
|
|
549
|
+
|
|
550
|
+
expect(result.systemPrompt).toContain("<available_skills>")
|
|
551
|
+
expect(result.systemPrompt).toContain("<name>ckm-slides</name>")
|
|
552
|
+
expect(result.systemPrompt).toContain("Ikie project slides skill.")
|
|
553
|
+
})
|
|
512
554
|
})
|
|
513
555
|
|
|
514
556
|
describe("append system prompt", () => {
|
|
@@ -646,9 +688,13 @@ describe("model role startup warnings", () => {
|
|
|
646
688
|
expect(warn).not.toHaveBeenCalledWith(expect.stringContaining("[model-roles] Warning:"))
|
|
647
689
|
})
|
|
648
690
|
|
|
649
|
-
it("keeps unavailable role warnings when Ikie auth is already configured", () => {
|
|
691
|
+
it("keeps unavailable role warnings for explicit user role overrides when Ikie auth is already configured", () => {
|
|
650
692
|
vi.spyOn(config, "loadConfig").mockReturnValue({ apiKey: "test-key" } as ReturnType<typeof config.loadConfig>)
|
|
651
693
|
vi.spyOn(startupContext, "getAvailableModels").mockReturnValue([modelMetadata("different-model")])
|
|
694
|
+
vi.spyOn(modelRoles, "getModelRoles").mockReturnValue({
|
|
695
|
+
...modelRoles.DEFAULT_MODEL_ROLES,
|
|
696
|
+
builder: "anthropic/claude-sonnet-4-5",
|
|
697
|
+
})
|
|
652
698
|
const warn = vi.spyOn(console, "warn").mockImplementation(() => {})
|
|
653
699
|
const pi = {
|
|
654
700
|
registerFlag: () => {},
|
|
@@ -661,7 +707,7 @@ describe("model role startup warnings", () => {
|
|
|
661
707
|
|
|
662
708
|
promptEnrichmentExtension([])(pi)
|
|
663
709
|
|
|
664
|
-
expect(warn).toHaveBeenCalledWith(expect.stringContaining("[model-roles] Warning:
|
|
710
|
+
expect(warn).toHaveBeenCalledWith(expect.stringContaining("[model-roles] Warning: builder"))
|
|
665
711
|
})
|
|
666
712
|
})
|
|
667
713
|
|
|
@@ -1054,7 +1100,7 @@ describe("continuation nudge turn_end handler", () => {
|
|
|
1054
1100
|
// The handler should allow a second nudge since the model did not
|
|
1055
1101
|
// intentionally stop.
|
|
1056
1102
|
await fire("turn_end", {
|
|
1057
|
-
message: makeAssistantWithStop([{ type: "text", text: "I was going to
|
|
1103
|
+
message: makeAssistantWithStop([{ type: "text", text: "I was going to call the Agent tool." }], "length"),
|
|
1058
1104
|
})
|
|
1059
1105
|
expect(sendMessageCalls.length).toBe(2)
|
|
1060
1106
|
})
|
|
@@ -63,6 +63,7 @@ import {
|
|
|
63
63
|
splitModelRef,
|
|
64
64
|
validateModelRoles,
|
|
65
65
|
} from "../orchestration/model-roles.js"
|
|
66
|
+
import { createSkillSanitizer } from "../skills-manager/skill-sanitizer.js"
|
|
66
67
|
import { getCurrentPhase } from "../tags.js"
|
|
67
68
|
import { type ContextFile, loadGlobalContextFiles, loadProjectContextFiles } from "./context-files.js"
|
|
68
69
|
import {
|
|
@@ -476,6 +477,8 @@ export default function (skillPaths: string[]) {
|
|
|
476
477
|
const cachedUsername = safeUsername()
|
|
477
478
|
const cachedHomeDir = homedir()
|
|
478
479
|
|
|
480
|
+
const skillSanitizer = createSkillSanitizer()
|
|
481
|
+
|
|
479
482
|
let cachedContextFiles: ContextFile[] | undefined
|
|
480
483
|
let cachedSkills: Skill[] | undefined
|
|
481
484
|
let cachedGitRemote: string | undefined | null = null
|
|
@@ -505,7 +508,7 @@ export default function (skillPaths: string[]) {
|
|
|
505
508
|
cachedSkills = loadSkills({
|
|
506
509
|
cwd: ctx.cwd,
|
|
507
510
|
agentDir: getAgentDir(),
|
|
508
|
-
skillPaths: allSkillPaths,
|
|
511
|
+
skillPaths: allSkillPaths.map((p) => skillSanitizer.sanitizePath(p)),
|
|
509
512
|
includeDefaults: false,
|
|
510
513
|
}).skills
|
|
511
514
|
}
|
|
@@ -15,36 +15,53 @@ import {
|
|
|
15
15
|
|
|
16
16
|
describe("validateName", () => {
|
|
17
17
|
const valid = (name: string) => expect(validateName(name)).toBeNull()
|
|
18
|
-
const invalid = (name: string
|
|
19
|
-
|
|
20
|
-
expect(result).not.toBeNull()
|
|
21
|
-
expect(result?.toLowerCase()).toContain(contains)
|
|
18
|
+
const invalid = (name: string) => {
|
|
19
|
+
expect(validateName(name)).not.toBeNull()
|
|
22
20
|
}
|
|
23
21
|
|
|
24
22
|
it("accepts valid names", () => {
|
|
23
|
+
valid("ckm-slides")
|
|
24
|
+
valid("ui-ux-pro-max")
|
|
25
25
|
valid("systematic-debugging")
|
|
26
|
-
valid("debug_v2")
|
|
27
|
-
valid("foo.bar")
|
|
28
26
|
valid("abc123")
|
|
29
27
|
})
|
|
30
28
|
|
|
31
|
-
it("rejects names
|
|
32
|
-
invalid("
|
|
33
|
-
|
|
29
|
+
it("rejects names with colons", () => {
|
|
30
|
+
invalid("ckm:slides")
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it("rejects names with underscores", () => {
|
|
34
|
+
invalid("foo_bar")
|
|
35
|
+
invalid("debug_v2")
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
it("rejects names with dots", () => {
|
|
39
|
+
invalid("foo.bar")
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
it("rejects names with a leading hyphen", () => {
|
|
43
|
+
invalid("-bad")
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
it("rejects names with consecutive hyphens", () => {
|
|
47
|
+
invalid("bad--bad")
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it("rejects names starting with an underscore", () => {
|
|
51
|
+
invalid("_bar")
|
|
34
52
|
})
|
|
35
53
|
|
|
36
54
|
it("rejects uppercase letters", () => {
|
|
37
|
-
invalid("Foo"
|
|
38
|
-
invalid("SYSTEM"
|
|
55
|
+
invalid("Foo")
|
|
56
|
+
invalid("SYSTEM")
|
|
39
57
|
})
|
|
40
58
|
|
|
41
59
|
it("rejects names longer than 64 chars", () => {
|
|
42
|
-
invalid("a".repeat(65)
|
|
60
|
+
invalid("a".repeat(65))
|
|
43
61
|
})
|
|
44
62
|
|
|
45
63
|
it("rejects names with spaces", () => {
|
|
46
|
-
|
|
47
|
-
expect(result).not.toBeNull()
|
|
64
|
+
invalid("foo bar")
|
|
48
65
|
})
|
|
49
66
|
})
|
|
50
67
|
|
|
@@ -44,23 +44,32 @@ export interface SkillManageResult {
|
|
|
44
44
|
path?: string
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
// Agent Skills spec: only lowercase a-z, 0-9, hyphens; no leading/trailing
|
|
48
|
+
// hyphens; no consecutive hyphens; max 64 characters.
|
|
49
|
+
const SKILL_NAME_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/
|
|
50
|
+
// Category directory names are filesystem-side only, so they allow a broader
|
|
51
|
+
// set of characters (dots, underscores) but still reject spaces and must
|
|
52
|
+
// start with a lowercase letter or digit.
|
|
53
|
+
const CATEGORY_RE = /^[a-z0-9][a-z0-9._-]*$/
|
|
48
54
|
const MAX_NAME_LEN = 64
|
|
49
55
|
const ALLOWED_SUBDIRS = new Set(["references", "templates", "scripts", "assets"])
|
|
50
56
|
|
|
51
57
|
export function validateName(name: string): string | null {
|
|
52
58
|
if (name.length === 0) return "Name cannot be empty."
|
|
53
59
|
if (name.length > MAX_NAME_LEN) return `Name must be at most ${MAX_NAME_LEN} characters.`
|
|
54
|
-
if (!
|
|
55
|
-
|
|
56
|
-
return "Name must contain only lowercase letters, digits, dots, underscores, or hyphens."
|
|
60
|
+
if (!SKILL_NAME_RE.test(name)) {
|
|
61
|
+
return "Name must contain only lowercase letters, digits, and hyphens, with no leading or trailing hyphens or consecutive hyphens."
|
|
57
62
|
}
|
|
58
63
|
return null
|
|
59
64
|
}
|
|
60
65
|
|
|
61
66
|
export function validateCategory(category?: string): string | null {
|
|
62
67
|
if (!category) return null
|
|
63
|
-
|
|
68
|
+
if (category.length > MAX_NAME_LEN) return `Category must be at most ${MAX_NAME_LEN} characters.`
|
|
69
|
+
if (!CATEGORY_RE.test(category)) {
|
|
70
|
+
return "Category must start with a lowercase letter or digit and contain only lowercase letters, digits, dots, underscores, or hyphens."
|
|
71
|
+
}
|
|
72
|
+
return null
|
|
64
73
|
}
|
|
65
74
|
|
|
66
75
|
/**
|
|
@@ -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
|
+
})
|