@ulpi/cli 0.1.5 → 0.1.6
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/LICENSE +21 -0
- 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-6OURRFP7.js → chunk-IV6MWETF.js} +383 -168
- package/dist/chunk-IZPJHSPX.js +1478 -0
- package/dist/chunk-JLHNLM3C.js +228 -0
- package/dist/{chunk-P2RESJRN.js → chunk-KYYI23AQ.js} +2 -2
- 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-V2H5D6Y3.js +146 -0
- package/dist/{chunk-5SCG7UYM.js → chunk-VVEDXI7E.js} +1 -1
- package/dist/chunk-VXH5Y4FO.js +6761 -0
- package/dist/chunk-WED4LM5N.js +322 -0
- package/dist/{chunk-74WVVWJ4.js → chunk-YOKL7RB5.js} +184 -15
- package/dist/chunk-Z53CAR7G.js +298 -0
- package/dist/{ci-JQ56YIKC.js → ci-X3U2W4HC.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-SI4LLLDZ.js +345 -0
- package/dist/{export-import-4A5MWLIA.js → export-import-JFQH4KSJ.js} +1 -1
- package/dist/{history-RNUWO4JZ.js → history-5NE46ZAH.js} +7 -7
- package/dist/{hooks-installer-K2JXEBNN.js → hooks-installer-UN5JZLDQ.js} +2 -2
- package/dist/index.js +394 -618
- package/dist/{init-NQWFZPKO.js → init-5FK3VKRT.js} +76 -10
- 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-6AWT54HR.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-5WHEJU2A.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-KKSETHDV-XSSLEENT.js +20 -0
- package/dist/{skills-GY2CTPWN.js → skills-QEYU2N27.js} +4 -2
- package/dist/start-JYOEL7AJ.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-ICUV6DDV.js} +3 -3
- package/dist/{update-QYZA4D23.js → update-7ZMAYRBH.js} +3 -3
- package/dist/{version-checker-MVB74DEX.js → version-checker-4ZFMZA7Y.js} +2 -2
- package/package.json +39 -31
- 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/skills/ulpi-generate-guardian/SKILL.md +0 -750
- package/dist/skills/ulpi-generate-guardian/references/framework-rules.md +0 -849
- package/dist/skills/ulpi-generate-guardian/references/language-rules.md +0 -591
- package/dist/ui-4SM2SUI6.js +0 -167
- package/dist/ui.html +0 -698
|
@@ -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,146 @@
|
|
|
1
|
+
import {
|
|
2
|
+
REVIEW_FLAGS_DIR,
|
|
3
|
+
loadUlpiSettings
|
|
4
|
+
} from "./chunk-C7CLUQI6.js";
|
|
5
|
+
|
|
6
|
+
// src/hooks/review-integration.ts
|
|
7
|
+
import * as fs from "fs";
|
|
8
|
+
import * as path from "path";
|
|
9
|
+
import { execFileSync } from "child_process";
|
|
10
|
+
function isReviewEnabled(type, rules) {
|
|
11
|
+
const runMode = process.env.ULPI_RUN_MODE;
|
|
12
|
+
if (runMode === "loop" || runMode === "parallel" || runMode === "ci") {
|
|
13
|
+
return false;
|
|
14
|
+
}
|
|
15
|
+
const reviewConfig = rules.review;
|
|
16
|
+
if (reviewConfig) {
|
|
17
|
+
if (reviewConfig.enabled === false) return false;
|
|
18
|
+
if (type === "plan" && reviewConfig.plan_review === false) return false;
|
|
19
|
+
if (type === "code" && reviewConfig.code_review === false) return false;
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
const settings = loadUlpiSettings();
|
|
23
|
+
if (!settings.review.enabled) return false;
|
|
24
|
+
if (type === "plan" && !settings.review.plan_review) return false;
|
|
25
|
+
if (type === "code" && !settings.review.code_review) return false;
|
|
26
|
+
} catch {
|
|
27
|
+
}
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
function extractPlanForReview(input) {
|
|
31
|
+
const toolInput = input.tool_input;
|
|
32
|
+
if (toolInput?.plan && typeof toolInput.plan === "string") {
|
|
33
|
+
return toolInput.plan;
|
|
34
|
+
}
|
|
35
|
+
if (toolInput?.content && typeof toolInput.content === "string") {
|
|
36
|
+
return toolInput.content;
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const plansDir = path.join(input.cwd, ".claude", "plans");
|
|
40
|
+
if (!fs.existsSync(plansDir)) return null;
|
|
41
|
+
const entries = fs.readdirSync(plansDir);
|
|
42
|
+
let newest = null;
|
|
43
|
+
for (const entry of entries) {
|
|
44
|
+
if (!entry.endsWith(".md")) continue;
|
|
45
|
+
const fullPath = path.join(plansDir, entry);
|
|
46
|
+
const stat = fs.statSync(fullPath);
|
|
47
|
+
if (!newest || stat.mtimeMs > newest.mtime) {
|
|
48
|
+
newest = { name: entry, mtime: stat.mtimeMs };
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
if (newest) {
|
|
52
|
+
return fs.readFileSync(path.join(plansDir, newest.name), "utf-8");
|
|
53
|
+
}
|
|
54
|
+
} catch {
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
async function runPlanReviewSession(plan, projectDir, sessionId) {
|
|
59
|
+
try {
|
|
60
|
+
const { discoverUlpiServer, registerWithServer, waitForServerDecision } = await import("./dist-ZG4OKCSR.js");
|
|
61
|
+
const server = await discoverUlpiServer();
|
|
62
|
+
if (!server) return null;
|
|
63
|
+
const settings = loadUlpiSettings();
|
|
64
|
+
const registration = await registerWithServer(
|
|
65
|
+
server.port,
|
|
66
|
+
{ type: "plan", projectPath: projectDir, plan },
|
|
67
|
+
server.secret
|
|
68
|
+
);
|
|
69
|
+
if (!registration?.success) return null;
|
|
70
|
+
const reviewSessionId = registration.sessionId;
|
|
71
|
+
if (settings.review.auto_open_browser) {
|
|
72
|
+
const url = `http://127.0.0.1:${server.port}/review/plan?session=${reviewSessionId}`;
|
|
73
|
+
try {
|
|
74
|
+
execFileSync("open", [url], { timeout: 5e3 });
|
|
75
|
+
} catch {
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const maxWaitMs = settings.review.review_timeout_seconds > 0 ? settings.review.review_timeout_seconds * 1e3 : void 0;
|
|
79
|
+
const decision = await waitForServerDecision(
|
|
80
|
+
server.port,
|
|
81
|
+
reviewSessionId,
|
|
82
|
+
3e4,
|
|
83
|
+
maxWaitMs,
|
|
84
|
+
registration.token,
|
|
85
|
+
server.secret
|
|
86
|
+
);
|
|
87
|
+
if (!decision) {
|
|
88
|
+
if (settings.review.timeout_behavior === "deny") {
|
|
89
|
+
return { behavior: "deny", feedback: "Plan review timed out." };
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
const planDecision = decision;
|
|
94
|
+
const behavior = planDecision.behavior === "deny" ? "deny" : "allow";
|
|
95
|
+
const feedback = planDecision.feedback || planDecision.message || void 0;
|
|
96
|
+
const clearContext = planDecision.clearContext ?? false;
|
|
97
|
+
writeFlagFiles(sessionId, { feedback, clearContext });
|
|
98
|
+
return { behavior, feedback, clearContext };
|
|
99
|
+
} catch {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function writeFlagFiles(sessionId, ctx) {
|
|
104
|
+
try {
|
|
105
|
+
const dir = path.join(REVIEW_FLAGS_DIR, sessionId);
|
|
106
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
107
|
+
if (ctx.feedback) {
|
|
108
|
+
fs.writeFileSync(path.join(dir, "review-feedback.flag"), ctx.feedback, "utf-8");
|
|
109
|
+
}
|
|
110
|
+
if (ctx.clearContext) {
|
|
111
|
+
fs.writeFileSync(path.join(dir, "clear-context.flag"), "1", "utf-8");
|
|
112
|
+
}
|
|
113
|
+
} catch {
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function collectPostReviewContexts(sessionId) {
|
|
117
|
+
const result = {};
|
|
118
|
+
try {
|
|
119
|
+
const dir = path.join(REVIEW_FLAGS_DIR, sessionId);
|
|
120
|
+
if (!fs.existsSync(dir)) return result;
|
|
121
|
+
const feedbackPath = path.join(dir, "review-feedback.flag");
|
|
122
|
+
if (fs.existsSync(feedbackPath)) {
|
|
123
|
+
result.feedback = fs.readFileSync(feedbackPath, "utf-8");
|
|
124
|
+
fs.unlinkSync(feedbackPath);
|
|
125
|
+
}
|
|
126
|
+
const clearPath = path.join(dir, "clear-context.flag");
|
|
127
|
+
if (fs.existsSync(clearPath)) {
|
|
128
|
+
result.clearContext = true;
|
|
129
|
+
fs.unlinkSync(clearPath);
|
|
130
|
+
}
|
|
131
|
+
try {
|
|
132
|
+
const remaining = fs.readdirSync(dir);
|
|
133
|
+
if (remaining.length === 0) fs.rmdirSync(dir);
|
|
134
|
+
} catch {
|
|
135
|
+
}
|
|
136
|
+
} catch {
|
|
137
|
+
}
|
|
138
|
+
return result;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export {
|
|
142
|
+
isReviewEnabled,
|
|
143
|
+
extractPlanForReview,
|
|
144
|
+
runPlanReviewSession,
|
|
145
|
+
collectPostReviewContexts
|
|
146
|
+
};
|