@ulpi/cli 0.1.5 → 0.1.7
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/README.md +143 -214
- package/dist/{auth-PN7TMQHV-2W4ICG64.js → auth-FWM7MM4Q-VZC3U2XZ.js} +1 -1
- package/dist/{auth-BFFBUJUC.js → auth-HDK7ECJL.js} +2 -1
- package/dist/{chunk-RJIRWQJD.js → chunk-3BCW6ABU.js} +402 -142
- package/dist/{chunk-L3PWNHSA.js → chunk-3WB5CXH4.js} +180 -5
- package/dist/{chunk-K4OVPFY2.js → chunk-4UCJIAOU.js} +2 -2
- package/dist/chunk-4XTHZVDS.js +109 -0
- package/dist/chunk-4ZPOZULQ.js +6522 -0
- package/dist/{chunk-SIAQVRKG.js → chunk-5MI5GIXM.js} +48 -2
- package/dist/{chunk-KLEASXUR.js → chunk-6ZL6NXMV.js} +1 -1
- package/dist/{chunk-AV5RB3N2.js → chunk-76D3BYJD.js} +48 -0
- package/dist/{chunk-DOIKS6C5.js → chunk-AWOSRA5F.js} +1 -1
- package/dist/{chunk-UCMT5OKP.js → chunk-BFEKZZHM.js} +274 -57
- package/dist/chunk-C7CLUQI6.js +1286 -0
- package/dist/{chunk-ELTGWMDE.js → chunk-E3B5NROU.js} +7 -7
- package/dist/chunk-EJ7TW77N.js +1418 -0
- package/dist/{chunk-P2RESJRN.js → chunk-EWLYVXQ4.js} +2 -2
- package/dist/{chunk-6OURRFP7.js → chunk-IV6MWETF.js} +383 -168
- package/dist/chunk-IZPJHSPX.js +1478 -0
- package/dist/chunk-JLHNLM3C.js +228 -0
- package/dist/chunk-PO4NUZUU.js +147 -0
- package/dist/chunk-S6ANCSYO.js +1271 -0
- package/dist/chunk-SEU7WWNQ.js +1251 -0
- package/dist/chunk-SNQ7NAIS.js +453 -0
- package/dist/{ulpi-RMMCUAGP-EWYUE7RU.js → chunk-TSLDGT5O.js} +73 -35
- package/dist/{chunk-EIWYSP3A.js → chunk-UXHCHOWQ.js} +83 -62
- package/dist/chunk-WED4LM5N.js +322 -0
- package/dist/chunk-WVOZE25N.js +6757 -0
- package/dist/{chunk-5SCG7UYM.js → chunk-XKF4DPUM.js} +7 -7
- package/dist/{chunk-74WVVWJ4.js → chunk-YOKL7RB5.js} +184 -15
- package/dist/chunk-Z53CAR7G.js +298 -0
- package/dist/{ci-JQ56YIKC.js → ci-COZRTPGQ.js} +124 -26
- package/dist/cloud-2F3NLVHN.js +274 -0
- package/dist/{codemap-HMYBXJL2.js → codemap-XNGMAF3F.js} +37 -37
- package/dist/codex-MB5YTMRT.js +132 -0
- package/dist/{config-YYWEN7U2.js → config-OOELBYTH.js} +1 -1
- package/dist/dist-2BJYR5EI.js +59 -0
- package/dist/dist-3EIQTZHT.js +1380 -0
- package/dist/{dist-WAMAQVPK.js → dist-4U5L2X2C.js} +2 -2
- package/dist/{dist-4XTJ6HLM.js → dist-54KAMNLO.js} +16 -15
- package/dist/dist-6M4MZWZW.js +58 -0
- package/dist/dist-6X576SU2.js +27 -0
- package/dist/dist-7QOEYLFX.js +103 -0
- package/dist/dist-AYBGHEDY.js +2541 -0
- package/dist/dist-EK45QNEM.js +45 -0
- package/dist/{dist-U7ZIJMZD.js → dist-FKFEJRPX.js} +16 -15
- package/dist/dist-GTEJUBBT.js +66 -0
- package/dist/dist-HA74OKJZ.js +40 -0
- package/dist/{dist-XG2GG5SD.js → dist-HU5RZAON.js} +14 -2
- package/dist/dist-IYE3OBRB.js +374 -0
- package/dist/{dist-7WLLPWWB.js → dist-JLU26AB6.js} +12 -9
- package/dist/{dist-6G7JC2RA.js → dist-KUCI6JFE.js} +49 -9
- package/dist/dist-NUEMFZFL.js +33 -0
- package/dist/{dist-GWGTAHNM.js → dist-NUXMDXZ3.js} +31 -3
- package/dist/{dist-5R4RYNQO.js → dist-YCNWHSLN.js} +15 -5
- package/dist/{dist-6MFVWIFF.js → dist-YFFG2ZD6.js} +9 -16
- package/dist/dist-ZG4OKCSR.js +15 -0
- package/dist/doctor-FKYSIHER.js +345 -0
- package/dist/{export-import-4A5MWLIA.js → export-import-JFQH4KSJ.js} +1 -1
- package/dist/{history-RNUWO4JZ.js → history-UMGQNQQ7.js} +7 -7
- package/dist/{hooks-installer-K2JXEBNN.js → hooks-installer-YEYTYA6Q.js} +2 -2
- package/dist/index.js +398 -622
- package/dist/{init-NQWFZPKO.js → init-TJYW5ROZ.js} +78 -12
- package/dist/job-HIDMAFW2.js +376 -0
- package/dist/jobs.memory-PLMMSFHB-VBECCTHN.js +33 -0
- package/dist/kiro-VMUHDFGK.js +153 -0
- package/dist/{launchd-OYXUAVW6.js → launchd-U3MSWBRH.js} +9 -17
- package/dist/mcp-PDUD7SGP.js +249 -0
- package/dist/mcp-installer-PQU3XOGO.js +259 -0
- package/dist/mcp-setup-OA7IB3H3.js +263 -0
- package/dist/{memory-D6ZFFCI2.js → memory-ZNAEAK3B.js} +17 -17
- package/dist/{ollama-3XCUZMZT-FYKHW4TZ.js → ollama-3XCUZMZT-4JMH6B7P.js} +1 -1
- package/dist/{openai-E7G2YAHU-IG33BFYF.js → openai-E7G2YAHU-T3HMBPH7.js} +2 -2
- package/dist/portal-JYWVHXDU.js +210 -0
- package/dist/prd-Q4J5NVAR.js +408 -0
- package/dist/repos-WWZXNN3P.js +271 -0
- package/dist/review-integration-RQE4KMAV.js +14 -0
- package/dist/{rules-3OFGWHP4.js → rules-Y4VSOY5Y.js} +3 -3
- package/dist/run-VPNXEIBY.js +687 -0
- package/dist/server-COL4AXKU-P7S7NNF6.js +11 -0
- package/dist/server-U7PQ6FTS-MG4MJPTS.js +20 -0
- package/dist/{skills-GY2CTPWN.js → skills-QEYU2N27.js} +4 -2
- package/dist/start-IJKY5RVT.js +303 -0
- package/dist/{status-SE43TIFJ.js → status-BHQYYGAL.js} +2 -2
- package/dist/{templates-O2XDKB5R.js → templates-CBRUJ66V.js} +6 -5
- package/dist/tui-DP7736EX.js +61 -0
- package/dist/ulpi-5EN6JCAS-LFE3WSL4.js +10 -0
- package/dist/{uninstall-KWGSGZTI.js → uninstall-BX6FOV77.js} +3 -3
- package/dist/{update-QYZA4D23.js → update-AQKTHFVQ.js} +3 -3
- package/dist/{version-checker-MVB74DEX.js → version-checker-5L5PUOEX.js} +2 -2
- package/package.json +13 -4
- package/dist/chunk-26LLDX2T.js +0 -553
- package/dist/chunk-DDRLI6JU.js +0 -331
- package/dist/chunk-IFATANHR.js +0 -453
- package/dist/chunk-JWUUVXIV.js +0 -13694
- package/dist/chunk-LD52XG3X.js +0 -4273
- package/dist/chunk-MIAQVCFW.js +0 -39
- package/dist/chunk-YYZOFYS6.js +0 -415
- package/dist/dist-XD4YI27T.js +0 -26
- package/dist/mcp-installer-TOYDP77X.js +0 -124
- package/dist/projects-COUJP4ZC.js +0 -271
- package/dist/review-KMGP2S25.js +0 -152
- package/dist/server-USLHY6GH-F4JSXCWA.js +0 -18
- package/dist/server-X5P6WH2M-ULZF5WHZ.js +0 -11
- package/dist/ui-4SM2SUI6.js +0 -167
- package/dist/ui.html +0 -698
- /package/dist/skills/{ulpi-generate-guardian → ulpi-generate-guards}/SKILL.md +0 -0
- /package/dist/skills/{ulpi-generate-guardian → ulpi-generate-guards}/references/framework-rules.md +0 -0
- /package/dist/skills/{ulpi-generate-guardian → ulpi-generate-guards}/references/language-rules.md +0 -0
|
@@ -2,14 +2,15 @@ import {
|
|
|
2
2
|
ULPI_GLOBAL_DIR,
|
|
3
3
|
projectGuardsFile,
|
|
4
4
|
projectGuardsFileAlt
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-C7CLUQI6.js";
|
|
6
6
|
|
|
7
|
-
// ../../packages/
|
|
7
|
+
// ../../packages/repos-engine/dist/index.js
|
|
8
8
|
import * as fs from "fs";
|
|
9
9
|
import * as path from "path";
|
|
10
10
|
import * as crypto from "crypto";
|
|
11
11
|
var DEFAULT_BASE_DIR = ULPI_GLOBAL_DIR;
|
|
12
|
-
var REGISTRY_FILE = "
|
|
12
|
+
var REGISTRY_FILE = "repos.json";
|
|
13
|
+
var LEGACY_REGISTRY_FILE = "projects.json";
|
|
13
14
|
function registryPath(baseDir) {
|
|
14
15
|
return path.join(baseDir, REGISTRY_FILE);
|
|
15
16
|
}
|
|
@@ -18,7 +19,7 @@ function atomicWrite(filePath, data) {
|
|
|
18
19
|
fs.writeFileSync(tmpPath, data, "utf-8");
|
|
19
20
|
fs.renameSync(tmpPath, filePath);
|
|
20
21
|
}
|
|
21
|
-
function
|
|
22
|
+
function generateRepoId(projectPath) {
|
|
22
23
|
const normalized = path.resolve(projectPath);
|
|
23
24
|
const hash = crypto.createHash("sha256").update(normalized).digest("hex");
|
|
24
25
|
return hash.slice(0, 12);
|
|
@@ -26,11 +27,31 @@ function generateProjectId(projectPath) {
|
|
|
26
27
|
function createEmptyRegistry() {
|
|
27
28
|
return {
|
|
28
29
|
version: 1,
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
repos: {},
|
|
31
|
+
defaultRepo: void 0
|
|
31
32
|
};
|
|
32
33
|
}
|
|
33
|
-
function
|
|
34
|
+
function migrateIfNeeded(baseDir) {
|
|
35
|
+
const newPath = registryPath(baseDir);
|
|
36
|
+
if (fs.existsSync(newPath)) return;
|
|
37
|
+
const legacyPath = path.join(baseDir, LEGACY_REGISTRY_FILE);
|
|
38
|
+
if (!fs.existsSync(legacyPath)) return;
|
|
39
|
+
try {
|
|
40
|
+
const raw = fs.readFileSync(legacyPath, "utf-8");
|
|
41
|
+
const parsed = JSON.parse(raw);
|
|
42
|
+
const migrated = {
|
|
43
|
+
version: 1,
|
|
44
|
+
repos: parsed.projects ?? parsed.repos ?? {},
|
|
45
|
+
defaultRepo: parsed.defaultProject ?? parsed.defaultRepo
|
|
46
|
+
};
|
|
47
|
+
fs.mkdirSync(path.dirname(newPath), { recursive: true });
|
|
48
|
+
atomicWrite(newPath, JSON.stringify(migrated, null, 2));
|
|
49
|
+
fs.unlinkSync(legacyPath);
|
|
50
|
+
} catch {
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function loadRepoRegistry(baseDir = DEFAULT_BASE_DIR) {
|
|
54
|
+
migrateIfNeeded(baseDir);
|
|
34
55
|
const filePath = registryPath(baseDir);
|
|
35
56
|
if (!fs.existsSync(filePath)) {
|
|
36
57
|
return createEmptyRegistry();
|
|
@@ -38,7 +59,7 @@ function loadProjectRegistry(baseDir = DEFAULT_BASE_DIR) {
|
|
|
38
59
|
try {
|
|
39
60
|
const raw = fs.readFileSync(filePath, "utf-8");
|
|
40
61
|
const parsed = JSON.parse(raw);
|
|
41
|
-
if (parsed && typeof parsed === "object" && parsed.version === 1 && typeof parsed.
|
|
62
|
+
if (parsed && typeof parsed === "object" && parsed.version === 1 && typeof parsed.repos === "object") {
|
|
42
63
|
return parsed;
|
|
43
64
|
}
|
|
44
65
|
return createEmptyRegistry();
|
|
@@ -46,17 +67,17 @@ function loadProjectRegistry(baseDir = DEFAULT_BASE_DIR) {
|
|
|
46
67
|
return createEmptyRegistry();
|
|
47
68
|
}
|
|
48
69
|
}
|
|
49
|
-
function
|
|
70
|
+
function saveRepoRegistry(registry, baseDir = DEFAULT_BASE_DIR) {
|
|
50
71
|
const filePath = registryPath(baseDir);
|
|
51
72
|
const dir = path.dirname(filePath);
|
|
52
73
|
fs.mkdirSync(dir, { recursive: true });
|
|
53
74
|
atomicWrite(filePath, JSON.stringify(registry, null, 2));
|
|
54
75
|
}
|
|
55
|
-
function
|
|
76
|
+
function registerRepo(projectDir, options = {}, baseDir = DEFAULT_BASE_DIR) {
|
|
56
77
|
const absPath = path.resolve(projectDir);
|
|
57
|
-
const id =
|
|
58
|
-
const registry =
|
|
59
|
-
const existing = registry.
|
|
78
|
+
const id = generateRepoId(absPath);
|
|
79
|
+
const registry = loadRepoRegistry(baseDir);
|
|
80
|
+
const existing = registry.repos[id];
|
|
60
81
|
let configStatus = "none";
|
|
61
82
|
const rulesPath = projectGuardsFile(absPath);
|
|
62
83
|
const rulesYamlPath = projectGuardsFileAlt(absPath);
|
|
@@ -88,80 +109,80 @@ function registerProject(projectDir, options = {}, baseDir = DEFAULT_BASE_DIR) {
|
|
|
88
109
|
hooksInstalled: options.hooksInstalled ?? hooksInstalled,
|
|
89
110
|
stack: options.stack ?? existing?.stack
|
|
90
111
|
};
|
|
91
|
-
registry.
|
|
92
|
-
|
|
112
|
+
registry.repos[id] = entry;
|
|
113
|
+
saveRepoRegistry(registry, baseDir);
|
|
93
114
|
return entry;
|
|
94
115
|
}
|
|
95
|
-
function
|
|
96
|
-
const registry =
|
|
97
|
-
if (registry.
|
|
98
|
-
delete registry.
|
|
99
|
-
if (registry.
|
|
100
|
-
registry.
|
|
116
|
+
function unregisterRepo(idOrPath, baseDir = DEFAULT_BASE_DIR) {
|
|
117
|
+
const registry = loadRepoRegistry(baseDir);
|
|
118
|
+
if (registry.repos[idOrPath]) {
|
|
119
|
+
delete registry.repos[idOrPath];
|
|
120
|
+
if (registry.defaultRepo === idOrPath) {
|
|
121
|
+
registry.defaultRepo = void 0;
|
|
101
122
|
}
|
|
102
|
-
|
|
123
|
+
saveRepoRegistry(registry, baseDir);
|
|
103
124
|
return true;
|
|
104
125
|
}
|
|
105
126
|
const absPath = path.resolve(idOrPath);
|
|
106
|
-
const id =
|
|
107
|
-
if (registry.
|
|
108
|
-
delete registry.
|
|
109
|
-
if (registry.
|
|
110
|
-
registry.
|
|
127
|
+
const id = generateRepoId(absPath);
|
|
128
|
+
if (registry.repos[id]) {
|
|
129
|
+
delete registry.repos[id];
|
|
130
|
+
if (registry.defaultRepo === id) {
|
|
131
|
+
registry.defaultRepo = void 0;
|
|
111
132
|
}
|
|
112
|
-
|
|
133
|
+
saveRepoRegistry(registry, baseDir);
|
|
113
134
|
return true;
|
|
114
135
|
}
|
|
115
136
|
return false;
|
|
116
137
|
}
|
|
117
|
-
function
|
|
118
|
-
const registry =
|
|
119
|
-
if (registry.
|
|
120
|
-
return registry.
|
|
138
|
+
function getRepo(idOrPath, baseDir = DEFAULT_BASE_DIR) {
|
|
139
|
+
const registry = loadRepoRegistry(baseDir);
|
|
140
|
+
if (registry.repos[idOrPath]) {
|
|
141
|
+
return registry.repos[idOrPath];
|
|
121
142
|
}
|
|
122
143
|
const absPath = path.resolve(idOrPath);
|
|
123
|
-
const id =
|
|
124
|
-
return registry.
|
|
144
|
+
const id = generateRepoId(absPath);
|
|
145
|
+
return registry.repos[id] ?? null;
|
|
125
146
|
}
|
|
126
|
-
function
|
|
127
|
-
const registry =
|
|
128
|
-
return Object.values(registry.
|
|
147
|
+
function listRepos(baseDir = DEFAULT_BASE_DIR) {
|
|
148
|
+
const registry = loadRepoRegistry(baseDir);
|
|
149
|
+
return Object.values(registry.repos).sort((a, b) => {
|
|
129
150
|
return new Date(b.lastAccessed).getTime() - new Date(a.lastAccessed).getTime();
|
|
130
151
|
});
|
|
131
152
|
}
|
|
132
|
-
function
|
|
133
|
-
const registry =
|
|
153
|
+
function setDefaultRepo(idOrPath, baseDir = DEFAULT_BASE_DIR) {
|
|
154
|
+
const registry = loadRepoRegistry(baseDir);
|
|
134
155
|
if (!idOrPath) {
|
|
135
|
-
registry.
|
|
136
|
-
|
|
156
|
+
registry.defaultRepo = void 0;
|
|
157
|
+
saveRepoRegistry(registry, baseDir);
|
|
137
158
|
return true;
|
|
138
159
|
}
|
|
139
160
|
let id = idOrPath;
|
|
140
|
-
if (!registry.
|
|
161
|
+
if (!registry.repos[id]) {
|
|
141
162
|
const absPath = path.resolve(idOrPath);
|
|
142
|
-
id =
|
|
163
|
+
id = generateRepoId(absPath);
|
|
143
164
|
}
|
|
144
|
-
if (!registry.
|
|
165
|
+
if (!registry.repos[id]) {
|
|
145
166
|
return false;
|
|
146
167
|
}
|
|
147
|
-
registry.
|
|
148
|
-
|
|
168
|
+
registry.defaultRepo = id;
|
|
169
|
+
saveRepoRegistry(registry, baseDir);
|
|
149
170
|
return true;
|
|
150
171
|
}
|
|
151
|
-
function
|
|
152
|
-
const registry =
|
|
153
|
-
if (!registry.
|
|
172
|
+
function getDefaultRepo(baseDir = DEFAULT_BASE_DIR) {
|
|
173
|
+
const registry = loadRepoRegistry(baseDir);
|
|
174
|
+
if (!registry.defaultRepo) {
|
|
154
175
|
return null;
|
|
155
176
|
}
|
|
156
|
-
return registry.
|
|
177
|
+
return registry.repos[registry.defaultRepo] ?? null;
|
|
157
178
|
}
|
|
158
|
-
function
|
|
159
|
-
const
|
|
179
|
+
function scanForRepos(rootDir, maxDepth = 3) {
|
|
180
|
+
const repos = [];
|
|
160
181
|
function scan(dir, depth) {
|
|
161
182
|
if (depth > maxDepth) return;
|
|
162
183
|
const ulpiPath = path.join(dir, ".ulpi");
|
|
163
184
|
if (fs.existsSync(path.join(ulpiPath, "guards.yml")) || fs.existsSync(path.join(ulpiPath, "guards.yaml"))) {
|
|
164
|
-
|
|
185
|
+
repos.push(dir);
|
|
165
186
|
return;
|
|
166
187
|
}
|
|
167
188
|
try {
|
|
@@ -182,16 +203,16 @@ function scanForProjects(rootDir, maxDepth = 3) {
|
|
|
182
203
|
}
|
|
183
204
|
}
|
|
184
205
|
scan(path.resolve(rootDir), 0);
|
|
185
|
-
return
|
|
206
|
+
return repos;
|
|
186
207
|
}
|
|
187
208
|
|
|
188
209
|
export {
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
210
|
+
loadRepoRegistry,
|
|
211
|
+
registerRepo,
|
|
212
|
+
unregisterRepo,
|
|
213
|
+
getRepo,
|
|
214
|
+
listRepos,
|
|
215
|
+
setDefaultRepo,
|
|
216
|
+
getDefaultRepo,
|
|
217
|
+
scanForRepos
|
|
197
218
|
};
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import {
|
|
2
|
+
installKiroSkill
|
|
3
|
+
} from "./chunk-IZPJHSPX.js";
|
|
4
|
+
import {
|
|
5
|
+
BUNDLED_SKILLS
|
|
6
|
+
} from "./chunk-4ZPOZULQ.js";
|
|
7
|
+
import {
|
|
8
|
+
getBinaryPath
|
|
9
|
+
} from "./chunk-C7CLUQI6.js";
|
|
10
|
+
|
|
11
|
+
// ../../packages/agent-installer/dist/index.js
|
|
12
|
+
import * as fs from "fs";
|
|
13
|
+
import * as path from "path";
|
|
14
|
+
import * as os from "os";
|
|
15
|
+
import * as fs2 from "fs";
|
|
16
|
+
import * as path2 from "path";
|
|
17
|
+
function buildMcpServers() {
|
|
18
|
+
const binary = getBinaryPath();
|
|
19
|
+
return {
|
|
20
|
+
"ulpi-codemap": {
|
|
21
|
+
command: binary,
|
|
22
|
+
args: ["codemap", "serve"],
|
|
23
|
+
transportType: "stdio"
|
|
24
|
+
},
|
|
25
|
+
"ulpi-memory": {
|
|
26
|
+
command: binary,
|
|
27
|
+
args: ["memory", "serve"],
|
|
28
|
+
transportType: "stdio"
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
function kiroAgentsDir() {
|
|
33
|
+
return path.join(os.homedir(), ".kiro", "agents");
|
|
34
|
+
}
|
|
35
|
+
function kiroAgentPath(name) {
|
|
36
|
+
return path.join(kiroAgentsDir(), `${name}.json`);
|
|
37
|
+
}
|
|
38
|
+
function kiroSkillsDir(projectDir) {
|
|
39
|
+
return path.join(projectDir, ".kiro", "skills");
|
|
40
|
+
}
|
|
41
|
+
function buildHooks() {
|
|
42
|
+
const binary = getBinaryPath();
|
|
43
|
+
return {
|
|
44
|
+
agentSpawn: [{ command: `${binary} session-start` }],
|
|
45
|
+
preToolUse: [{ matcher: "*", command: `${binary} pre-tool` }],
|
|
46
|
+
postToolUse: [{ matcher: "*", command: `${binary} post-tool` }],
|
|
47
|
+
stop: [{ command: `${binary} stop` }]
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function generateAgentConfig() {
|
|
51
|
+
return {
|
|
52
|
+
name: "ulpi-governance",
|
|
53
|
+
description: "ULPI-governed coding agent. Enforces rules from .ulpi/guards.yml, tracks sessions, captures memory, and provides CodeMap semantic search.",
|
|
54
|
+
tools: ["read", "write", "shell"],
|
|
55
|
+
allowedTools: ["read"],
|
|
56
|
+
hooks: buildHooks(),
|
|
57
|
+
resources: [
|
|
58
|
+
"skill://.kiro/skills/*/SKILL.md",
|
|
59
|
+
"file://.ulpi/guards.yml"
|
|
60
|
+
],
|
|
61
|
+
mcpServers: buildMcpServers()
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function installKiroHooks(mode) {
|
|
65
|
+
if (mode === "agent") {
|
|
66
|
+
const agentConfig = generateAgentConfig();
|
|
67
|
+
const agentPath = kiroAgentPath("ulpi-governance");
|
|
68
|
+
const dir2 = path.dirname(agentPath);
|
|
69
|
+
fs.mkdirSync(dir2, { recursive: true });
|
|
70
|
+
fs.writeFileSync(agentPath, JSON.stringify(agentConfig, null, 2) + "\n", "utf-8");
|
|
71
|
+
return { file: agentPath, agent: "ulpi-governance" };
|
|
72
|
+
}
|
|
73
|
+
const defaultPath = kiroAgentPath("kiro_default");
|
|
74
|
+
let config = {};
|
|
75
|
+
if (fs.existsSync(defaultPath)) {
|
|
76
|
+
try {
|
|
77
|
+
config = JSON.parse(fs.readFileSync(defaultPath, "utf-8"));
|
|
78
|
+
} catch {
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
config.hooks = buildHooks();
|
|
82
|
+
config.mcpServers = { ...config.mcpServers ?? {}, ...buildMcpServers() };
|
|
83
|
+
const dir = path.dirname(defaultPath);
|
|
84
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
85
|
+
fs.writeFileSync(defaultPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
86
|
+
return { file: defaultPath, agent: "kiro_default" };
|
|
87
|
+
}
|
|
88
|
+
function installKiroSkills(projectDir) {
|
|
89
|
+
let count = 0;
|
|
90
|
+
for (const skillInfo of BUNDLED_SKILLS) {
|
|
91
|
+
const skill = {
|
|
92
|
+
name: skillInfo.id,
|
|
93
|
+
path: skillInfo.filename,
|
|
94
|
+
source: "bundled",
|
|
95
|
+
description: skillInfo.description
|
|
96
|
+
};
|
|
97
|
+
const dirName = `ulpi-${skillInfo.id}`;
|
|
98
|
+
const skillDir = path.join(kiroSkillsDir(projectDir), dirName);
|
|
99
|
+
const skillPath = path.join(skillDir, "SKILL.md");
|
|
100
|
+
if (fs.existsSync(skillPath)) continue;
|
|
101
|
+
installKiroSkill(skill, projectDir, "repo");
|
|
102
|
+
count++;
|
|
103
|
+
}
|
|
104
|
+
return count;
|
|
105
|
+
}
|
|
106
|
+
function uninstallKiro(projectDir) {
|
|
107
|
+
let agentRemoved = false;
|
|
108
|
+
let skillsRemoved = 0;
|
|
109
|
+
let agentsRemoved = 0;
|
|
110
|
+
const agentPath = kiroAgentPath("ulpi-governance");
|
|
111
|
+
if (fs.existsSync(agentPath)) {
|
|
112
|
+
fs.unlinkSync(agentPath);
|
|
113
|
+
agentRemoved = true;
|
|
114
|
+
}
|
|
115
|
+
const skillsDir = kiroSkillsDir(projectDir);
|
|
116
|
+
if (fs.existsSync(skillsDir)) {
|
|
117
|
+
const entries = fs.readdirSync(skillsDir, { withFileTypes: true });
|
|
118
|
+
for (const entry of entries) {
|
|
119
|
+
if (entry.isDirectory() && entry.name.startsWith("ulpi-")) {
|
|
120
|
+
fs.rmSync(path.join(skillsDir, entry.name), { recursive: true, force: true });
|
|
121
|
+
skillsRemoved++;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const claudeAgentsDir = path.join(projectDir, ".claude", "agents");
|
|
126
|
+
const kiroAgentsBase = path.join(projectDir, ".kiro", "agents");
|
|
127
|
+
if (fs.existsSync(claudeAgentsDir) && fs.existsSync(kiroAgentsBase)) {
|
|
128
|
+
const claudeEntries = fs.readdirSync(claudeAgentsDir);
|
|
129
|
+
for (const file of claudeEntries) {
|
|
130
|
+
if (!file.endsWith(".md")) continue;
|
|
131
|
+
const agentName = file.replace(/\.md$/, "");
|
|
132
|
+
const kiroJson = path.join(kiroAgentsBase, `${agentName}.json`);
|
|
133
|
+
const kiroPromptDir = path.join(kiroAgentsBase, agentName);
|
|
134
|
+
if (fs.existsSync(kiroJson)) {
|
|
135
|
+
fs.unlinkSync(kiroJson);
|
|
136
|
+
agentsRemoved++;
|
|
137
|
+
}
|
|
138
|
+
if (fs.existsSync(kiroPromptDir)) {
|
|
139
|
+
fs.rmSync(kiroPromptDir, { recursive: true, force: true });
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return { agentRemoved, skillsRemoved, agentsRemoved };
|
|
144
|
+
}
|
|
145
|
+
function getKiroStatus(projectDir) {
|
|
146
|
+
const agentPath = kiroAgentPath("ulpi-governance");
|
|
147
|
+
const agentInstalled = fs.existsSync(agentPath);
|
|
148
|
+
let skillCount = 0;
|
|
149
|
+
let convertedSkillCount = 0;
|
|
150
|
+
const skillsDir = kiroSkillsDir(projectDir);
|
|
151
|
+
if (fs.existsSync(skillsDir)) {
|
|
152
|
+
const entries = fs.readdirSync(skillsDir, { withFileTypes: true });
|
|
153
|
+
for (const e of entries) {
|
|
154
|
+
if (!e.isDirectory()) continue;
|
|
155
|
+
if (e.name.startsWith("ulpi-")) {
|
|
156
|
+
skillCount++;
|
|
157
|
+
} else {
|
|
158
|
+
convertedSkillCount++;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
let convertedAgentCount = 0;
|
|
163
|
+
const claudeAgentsDir = path.join(projectDir, ".claude", "agents");
|
|
164
|
+
const kiroAgentsBase = path.join(projectDir, ".kiro", "agents");
|
|
165
|
+
if (fs.existsSync(claudeAgentsDir) && fs.existsSync(kiroAgentsBase)) {
|
|
166
|
+
const claudeEntries = fs.readdirSync(claudeAgentsDir);
|
|
167
|
+
for (const file of claudeEntries) {
|
|
168
|
+
if (!file.endsWith(".md")) continue;
|
|
169
|
+
const agentName = file.replace(/\.md$/, "");
|
|
170
|
+
if (fs.existsSync(path.join(kiroAgentsBase, `${agentName}.json`))) {
|
|
171
|
+
convertedAgentCount++;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
const mcpPath = path.join(projectDir, ".kiro", "settings", "mcp.json");
|
|
176
|
+
let mcpConfigured = false;
|
|
177
|
+
if (fs.existsSync(mcpPath)) {
|
|
178
|
+
try {
|
|
179
|
+
const mcpConfig = JSON.parse(fs.readFileSync(mcpPath, "utf-8"));
|
|
180
|
+
const servers = mcpConfig.mcpServers;
|
|
181
|
+
mcpConfigured = !!(servers?.["ulpi-codemap"] || servers?.["ulpi-memory"]);
|
|
182
|
+
} catch {
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return { agentInstalled, agentPath, skillCount, convertedSkillCount, convertedAgentCount, mcpConfigured };
|
|
186
|
+
}
|
|
187
|
+
function installCodexMcpServers(projectDir) {
|
|
188
|
+
const configPath = path2.join(projectDir, ".codex", "config.toml");
|
|
189
|
+
let content = "";
|
|
190
|
+
if (fs2.existsSync(configPath)) {
|
|
191
|
+
content = fs2.readFileSync(configPath, "utf-8");
|
|
192
|
+
}
|
|
193
|
+
const servers = buildMcpServers();
|
|
194
|
+
let added = 0;
|
|
195
|
+
for (const [name, entry] of Object.entries(servers)) {
|
|
196
|
+
const actualHeader = `[mcp_servers.${name}]`;
|
|
197
|
+
if (content.includes(actualHeader)) continue;
|
|
198
|
+
const argsToml = entry.args.map((a) => `"${a}"`).join(", ");
|
|
199
|
+
content += `
|
|
200
|
+
${actualHeader}
|
|
201
|
+
command = "${entry.command}"
|
|
202
|
+
args = [${argsToml}]
|
|
203
|
+
`;
|
|
204
|
+
added++;
|
|
205
|
+
}
|
|
206
|
+
if (added > 0) {
|
|
207
|
+
const dir = path2.dirname(configPath);
|
|
208
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
209
|
+
fs2.writeFileSync(configPath, content, "utf-8");
|
|
210
|
+
}
|
|
211
|
+
return added;
|
|
212
|
+
}
|
|
213
|
+
function uninstallCodex(projectDir) {
|
|
214
|
+
let agentsRemoved = 0;
|
|
215
|
+
let skillsRemoved = 0;
|
|
216
|
+
let mcpRemoved = false;
|
|
217
|
+
const claudeAgentsDir = path2.join(projectDir, ".claude", "agents");
|
|
218
|
+
const codexAgentsBase = path2.join(projectDir, ".codex", "agents");
|
|
219
|
+
if (fs2.existsSync(claudeAgentsDir) && fs2.existsSync(codexAgentsBase)) {
|
|
220
|
+
const claudeEntries = fs2.readdirSync(claudeAgentsDir);
|
|
221
|
+
for (const file of claudeEntries) {
|
|
222
|
+
if (!file.endsWith(".md")) continue;
|
|
223
|
+
const agentName = file.replace(/\.md$/, "");
|
|
224
|
+
const codexToml = path2.join(codexAgentsBase, `${agentName}.toml`);
|
|
225
|
+
const codexInstructionsDir = path2.join(codexAgentsBase, agentName);
|
|
226
|
+
if (fs2.existsSync(codexToml)) {
|
|
227
|
+
fs2.unlinkSync(codexToml);
|
|
228
|
+
agentsRemoved++;
|
|
229
|
+
}
|
|
230
|
+
if (fs2.existsSync(codexInstructionsDir)) {
|
|
231
|
+
fs2.rmSync(codexInstructionsDir, { recursive: true, force: true });
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
const claudeSkillsDir = path2.join(projectDir, ".claude", "skills");
|
|
236
|
+
const codexSkillsDir = path2.join(projectDir, ".codex", "skills");
|
|
237
|
+
if (fs2.existsSync(claudeSkillsDir) && fs2.existsSync(codexSkillsDir)) {
|
|
238
|
+
const claudeEntries = fs2.readdirSync(claudeSkillsDir, { withFileTypes: true });
|
|
239
|
+
for (const entry of claudeEntries) {
|
|
240
|
+
if (!entry.isDirectory()) continue;
|
|
241
|
+
const codexSkillDir = path2.join(codexSkillsDir, entry.name);
|
|
242
|
+
if (fs2.existsSync(codexSkillDir)) {
|
|
243
|
+
fs2.rmSync(codexSkillDir, { recursive: true, force: true });
|
|
244
|
+
skillsRemoved++;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
const configPath = path2.join(projectDir, ".codex", "config.toml");
|
|
249
|
+
if (fs2.existsSync(configPath)) {
|
|
250
|
+
let content = fs2.readFileSync(configPath, "utf-8");
|
|
251
|
+
const originalLen = content.length;
|
|
252
|
+
for (const name of ["ulpi-codemap", "ulpi-memory"]) {
|
|
253
|
+
const sectionRegex = new RegExp(
|
|
254
|
+
`\\n?\\[mcp_servers\\.${name.replace(/-/g, "\\-")}\\]\\n(?:[^\\[]*?)(?=\\n\\[|$)`,
|
|
255
|
+
"s"
|
|
256
|
+
);
|
|
257
|
+
content = content.replace(sectionRegex, "");
|
|
258
|
+
}
|
|
259
|
+
if (fs2.existsSync(claudeAgentsDir)) {
|
|
260
|
+
const claudeEntries = fs2.readdirSync(claudeAgentsDir);
|
|
261
|
+
for (const file of claudeEntries) {
|
|
262
|
+
if (!file.endsWith(".md")) continue;
|
|
263
|
+
const agentName = file.replace(/\.md$/, "");
|
|
264
|
+
const sectionRegex = new RegExp(
|
|
265
|
+
`\\n?\\[agents\\.${agentName}\\]\\n(?:[^\\[]*?)(?=\\n\\[|$)`,
|
|
266
|
+
"s"
|
|
267
|
+
);
|
|
268
|
+
content = content.replace(sectionRegex, "");
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
if (content.length !== originalLen) {
|
|
272
|
+
mcpRemoved = true;
|
|
273
|
+
fs2.writeFileSync(configPath, content.trim() + "\n", "utf-8");
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return { agentsRemoved, skillsRemoved, mcpRemoved };
|
|
277
|
+
}
|
|
278
|
+
function getCodexStatus(projectDir) {
|
|
279
|
+
let convertedAgentCount = 0;
|
|
280
|
+
let convertedSkillCount = 0;
|
|
281
|
+
const claudeAgentsDir = path2.join(projectDir, ".claude", "agents");
|
|
282
|
+
const codexAgentsBase = path2.join(projectDir, ".codex", "agents");
|
|
283
|
+
if (fs2.existsSync(claudeAgentsDir) && fs2.existsSync(codexAgentsBase)) {
|
|
284
|
+
const claudeEntries = fs2.readdirSync(claudeAgentsDir);
|
|
285
|
+
for (const file of claudeEntries) {
|
|
286
|
+
if (!file.endsWith(".md")) continue;
|
|
287
|
+
const agentName = file.replace(/\.md$/, "");
|
|
288
|
+
if (fs2.existsSync(path2.join(codexAgentsBase, `${agentName}.toml`))) {
|
|
289
|
+
convertedAgentCount++;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
const claudeSkillsDir = path2.join(projectDir, ".claude", "skills");
|
|
294
|
+
const codexSkillsDir = path2.join(projectDir, ".codex", "skills");
|
|
295
|
+
if (fs2.existsSync(claudeSkillsDir) && fs2.existsSync(codexSkillsDir)) {
|
|
296
|
+
const claudeEntries = fs2.readdirSync(claudeSkillsDir, { withFileTypes: true });
|
|
297
|
+
for (const entry of claudeEntries) {
|
|
298
|
+
if (!entry.isDirectory()) continue;
|
|
299
|
+
if (fs2.existsSync(path2.join(codexSkillsDir, entry.name, "SKILL.md"))) {
|
|
300
|
+
convertedSkillCount++;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
const configPath = path2.join(projectDir, ".codex", "config.toml");
|
|
305
|
+
let mcpConfigured = false;
|
|
306
|
+
if (fs2.existsSync(configPath)) {
|
|
307
|
+
const content = fs2.readFileSync(configPath, "utf-8");
|
|
308
|
+
mcpConfigured = content.includes("[mcp_servers.ulpi-codemap]") || content.includes("[mcp_servers.ulpi-memory]");
|
|
309
|
+
}
|
|
310
|
+
return { convertedAgentCount, convertedSkillCount, mcpConfigured };
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export {
|
|
314
|
+
buildMcpServers,
|
|
315
|
+
installKiroHooks,
|
|
316
|
+
installKiroSkills,
|
|
317
|
+
uninstallKiro,
|
|
318
|
+
getKiroStatus,
|
|
319
|
+
installCodexMcpServers,
|
|
320
|
+
uninstallCodex,
|
|
321
|
+
getCodexStatus
|
|
322
|
+
};
|