@jskit-ai/jskit-cli 0.2.80 → 0.2.82
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/package.json +6 -4
- package/src/server/appBlueprint.js +1 -1
- package/src/server/commandHandlers/helperMap.js +104 -0
- package/src/server/commandHandlers/session.js +179 -4
- package/src/server/commandHandlers/show.js +169 -34
- package/src/server/core/argParser.js +20 -0
- package/src/server/core/commandCatalog.js +70 -7
- package/src/server/core/createCommandHandlers.js +4 -1
- package/src/server/helperMap.js +463 -0
- package/src/server/helperMapPaths.js +7 -0
- package/src/server/sessionRuntime/appReadiness.js +55 -0
- package/src/server/sessionRuntime/constants.js +298 -135
- package/src/server/sessionRuntime/paths.js +2 -4
- package/src/server/sessionRuntime/preconditions.js +393 -26
- package/src/server/sessionRuntime/promptRenderer.js +15 -2
- package/src/server/sessionRuntime/prompts/app_blueprint.md +26 -2
- package/src/server/sessionRuntime/prompts/automated_checks.md +42 -0
- package/src/server/sessionRuntime/prompts/deep_ui_check.md +53 -0
- package/src/server/sessionRuntime/prompts/doctor_failure.md +21 -1
- package/src/server/sessionRuntime/prompts/execute_plan.md +61 -0
- package/src/server/sessionRuntime/prompts/final_comment.md +3 -1
- package/src/server/sessionRuntime/prompts/issue_details.md +52 -0
- package/src/server/sessionRuntime/prompts/new_issue.md +34 -3
- package/src/server/sessionRuntime/prompts/plan_issue.md +81 -0
- package/src/server/sessionRuntime/prompts/pr_failure.md +14 -1
- package/src/server/sessionRuntime/prompts/review_changes.md +77 -15
- package/src/server/sessionRuntime/prompts/update_blueprint.md +36 -0
- package/src/server/sessionRuntime/prompts/user_check.md +22 -4
- package/src/server/sessionRuntime/responses.js +877 -30
- package/src/server/sessionRuntime/worktrees.js +31 -0
- package/src/server/sessionRuntime.js +2070 -244
- package/src/server/sessionRuntime/prompts/implement_issue.md +0 -25
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jskit-ai/jskit-cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.82",
|
|
4
4
|
"description": "Bundle and package orchestration CLI for JSKIT apps.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -20,9 +20,11 @@
|
|
|
20
20
|
"test": "node --test"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@jskit-ai/jskit-catalog": "0.1.
|
|
24
|
-
"@jskit-ai/kernel": "0.1.
|
|
25
|
-
"@jskit-ai/shell-web": "0.1.
|
|
23
|
+
"@jskit-ai/jskit-catalog": "0.1.81",
|
|
24
|
+
"@jskit-ai/kernel": "0.1.73",
|
|
25
|
+
"@jskit-ai/shell-web": "0.1.72",
|
|
26
|
+
"@vue/compiler-sfc": "^3.5.29",
|
|
27
|
+
"ts-morph": "^28.0.0"
|
|
26
28
|
},
|
|
27
29
|
"engines": {
|
|
28
30
|
"node": ">=20 <23"
|
|
@@ -28,7 +28,7 @@ function resolveAppBlueprintPaths(targetRoot = process.cwd()) {
|
|
|
28
28
|
function extractAppBlueprintText(value = "") {
|
|
29
29
|
const text = normalizeText(value);
|
|
30
30
|
const match = /\[app_blueprint\]([\s\S]*?)\[\/app_blueprint\]/u.exec(text);
|
|
31
|
-
return normalizeText(match ? match[1] :
|
|
31
|
+
return normalizeText(match ? match[1] : "");
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
async function readAppPromptTemplate(paths, templateName) {
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
function writeJson(stdout, payload) {
|
|
2
|
+
stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function writeErrors(stdout, payload) {
|
|
6
|
+
for (const error of payload.errors || []) {
|
|
7
|
+
stdout.write(`[${error.code}] ${error.message}\n`);
|
|
8
|
+
if (error.repairCommand) {
|
|
9
|
+
stdout.write(`Repair: ${error.repairCommand}\n`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function writeHelperMapText(stdout, payload) {
|
|
15
|
+
if (Object.hasOwn(payload, "changed")) {
|
|
16
|
+
stdout.write(
|
|
17
|
+
payload.changed
|
|
18
|
+
? `Updated helper map at ${payload.helperMapMarkdownPath}.\n`
|
|
19
|
+
: `Helper map is up to date at ${payload.helperMapMarkdownPath}.\n`
|
|
20
|
+
);
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (payload.exists === false) {
|
|
24
|
+
stdout.write(`No helper map set at ${payload.helperMapMarkdownPath}. Run jskit helper-map update.\n`);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (payload.markdown) {
|
|
28
|
+
stdout.write(payload.markdown);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
stdout.write(`Helper map is up to date at ${payload.helperMapMarkdownPath}.\n`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function createHelperMapCommands(ctx = {}) {
|
|
35
|
+
const { resolveAppRootFromCwd } = ctx;
|
|
36
|
+
|
|
37
|
+
async function commandHelperMap({
|
|
38
|
+
positional = [],
|
|
39
|
+
options = {},
|
|
40
|
+
cwd,
|
|
41
|
+
stdout
|
|
42
|
+
} = {}) {
|
|
43
|
+
const subcommand = String(positional[0] || "").trim();
|
|
44
|
+
let payload;
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const appRoot = await resolveAppRootFromCwd(cwd);
|
|
48
|
+
if (positional.length > 1) {
|
|
49
|
+
payload = {
|
|
50
|
+
ok: false,
|
|
51
|
+
errors: [
|
|
52
|
+
{
|
|
53
|
+
code: "unexpected_helper_map_argument",
|
|
54
|
+
message: `Unexpected helper-map argument: ${positional.slice(1).join(" ")}`,
|
|
55
|
+
repairCommand: "jskit helper-map"
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
};
|
|
59
|
+
} else if (!subcommand) {
|
|
60
|
+
const { readHelperMap } = await import("../helperMap.js");
|
|
61
|
+
payload = await readHelperMap({ targetRoot: appRoot });
|
|
62
|
+
} else if (subcommand === "update") {
|
|
63
|
+
const { updateHelperMap } = await import("../helperMap.js");
|
|
64
|
+
payload = await updateHelperMap({ targetRoot: appRoot });
|
|
65
|
+
} else {
|
|
66
|
+
payload = {
|
|
67
|
+
ok: false,
|
|
68
|
+
errors: [
|
|
69
|
+
{
|
|
70
|
+
code: "unknown_helper_map_subcommand",
|
|
71
|
+
message: `Unknown helper-map subcommand: ${subcommand}`,
|
|
72
|
+
repairCommand: "jskit helper-map update"
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
} catch (error) {
|
|
78
|
+
payload = {
|
|
79
|
+
ok: false,
|
|
80
|
+
errors: [
|
|
81
|
+
{
|
|
82
|
+
code: "helper_map_failed",
|
|
83
|
+
message: String(error?.message || error),
|
|
84
|
+
repairCommand: "jskit helper-map update"
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (options.json) {
|
|
91
|
+
writeJson(stdout, payload);
|
|
92
|
+
} else if (payload.ok === false) {
|
|
93
|
+
writeErrors(stdout, payload);
|
|
94
|
+
} else {
|
|
95
|
+
writeHelperMapText(stdout, payload);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return payload.ok === false ? 1 : 0;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return { commandHelperMap };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export { createHelperMapCommands };
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
adoptCodexThreadId,
|
|
5
5
|
buildSessionErrorResponse,
|
|
6
6
|
createSession,
|
|
7
|
+
inspectSessionDiff,
|
|
7
8
|
inspectSessionDetails,
|
|
8
9
|
listSessions,
|
|
9
10
|
runSessionStep
|
|
@@ -52,6 +53,17 @@ function writeSessionText(stdout, payload) {
|
|
|
52
53
|
stdout.write(payload.prompt);
|
|
53
54
|
stdout.write("\n");
|
|
54
55
|
}
|
|
56
|
+
if (payload.gitStatus !== undefined && payload.unstagedDiff !== undefined) {
|
|
57
|
+
stdout.write("\nGit status:\n");
|
|
58
|
+
stdout.write(payload.gitStatus || "No changes.");
|
|
59
|
+
stdout.write("\n");
|
|
60
|
+
const diff = [payload.stagedDiff, payload.unstagedDiff, payload.untrackedDiff].filter(Boolean).join("\n");
|
|
61
|
+
if (diff) {
|
|
62
|
+
stdout.write("\nDiff:\n");
|
|
63
|
+
stdout.write(diff);
|
|
64
|
+
stdout.write("\n");
|
|
65
|
+
}
|
|
66
|
+
}
|
|
55
67
|
if (payload.errors?.length) {
|
|
56
68
|
stdout.write("Errors:\n");
|
|
57
69
|
for (const error of payload.errors) {
|
|
@@ -135,6 +147,34 @@ async function resolveStepInputs({
|
|
|
135
147
|
cwd,
|
|
136
148
|
sessionId
|
|
137
149
|
}) {
|
|
150
|
+
if (Object.hasOwn(inlineOptions, "blueprint") || Object.hasOwn(inlineOptions, "blueprint-file")) {
|
|
151
|
+
return {
|
|
152
|
+
ok: false,
|
|
153
|
+
payload: buildSessionErrorResponse({
|
|
154
|
+
targetRoot: cwd,
|
|
155
|
+
sessionId,
|
|
156
|
+
code: "session_blueprint_input_removed",
|
|
157
|
+
message: "The session blueprint step no longer accepts --blueprint input. Run the step to get the Codex prompt, let Codex edit .jskit/APP_BLUEPRINT.md, then run the step again.",
|
|
158
|
+
repairCommand: `jskit session ${sessionId} step`
|
|
159
|
+
})
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const issueTitle = await resolveTextInput({
|
|
164
|
+
codePrefix: "issue_title",
|
|
165
|
+
fileOption: "issue-title-file",
|
|
166
|
+
inlineOptions,
|
|
167
|
+
io,
|
|
168
|
+
repairCommand: `jskit session ${sessionId} step --issue-title "<title>" --issue -`,
|
|
169
|
+
cwd,
|
|
170
|
+
sessionId,
|
|
171
|
+
stdinOption: "-",
|
|
172
|
+
textOption: "issue-title"
|
|
173
|
+
});
|
|
174
|
+
if (issueTitle.ok === false) {
|
|
175
|
+
return issueTitle;
|
|
176
|
+
}
|
|
177
|
+
|
|
138
178
|
const issue = await resolveTextInput({
|
|
139
179
|
codePrefix: "issue",
|
|
140
180
|
fileOption: "issue-file",
|
|
@@ -150,18 +190,138 @@ async function resolveStepInputs({
|
|
|
150
190
|
return issue;
|
|
151
191
|
}
|
|
152
192
|
|
|
193
|
+
const plan = await resolveTextInput({
|
|
194
|
+
codePrefix: "plan",
|
|
195
|
+
fileOption: "plan-file",
|
|
196
|
+
inlineOptions,
|
|
197
|
+
io,
|
|
198
|
+
repairCommand: `jskit session ${sessionId} step --plan -`,
|
|
199
|
+
cwd,
|
|
200
|
+
sessionId,
|
|
201
|
+
stdinOption: "-",
|
|
202
|
+
textOption: "plan"
|
|
203
|
+
});
|
|
204
|
+
if (plan.ok === false) {
|
|
205
|
+
return plan;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const issueDetails = await resolveTextInput({
|
|
209
|
+
codePrefix: "issue_details",
|
|
210
|
+
fileOption: "issue-details-file",
|
|
211
|
+
inlineOptions,
|
|
212
|
+
io,
|
|
213
|
+
repairCommand: `jskit session ${sessionId} step --issue-details -`,
|
|
214
|
+
cwd,
|
|
215
|
+
sessionId,
|
|
216
|
+
stdinOption: "-",
|
|
217
|
+
textOption: "issue-details"
|
|
218
|
+
});
|
|
219
|
+
if (issueDetails.ok === false) {
|
|
220
|
+
return issueDetails;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const reworkNotes = await resolveTextInput({
|
|
224
|
+
codePrefix: "rework_notes",
|
|
225
|
+
fileOption: "rework-notes-file",
|
|
226
|
+
inlineOptions,
|
|
227
|
+
io,
|
|
228
|
+
repairCommand: `jskit session ${sessionId} step --user-check failed --rework-notes -`,
|
|
229
|
+
cwd,
|
|
230
|
+
sessionId,
|
|
231
|
+
stdinOption: "-",
|
|
232
|
+
textOption: "rework-notes"
|
|
233
|
+
});
|
|
234
|
+
if (reworkNotes.ok === false) {
|
|
235
|
+
return reworkNotes;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const skipReason = await resolveTextInput({
|
|
239
|
+
codePrefix: "skip_reason",
|
|
240
|
+
fileOption: "skip-reason-file",
|
|
241
|
+
inlineOptions,
|
|
242
|
+
io,
|
|
243
|
+
repairCommand: `jskit session ${sessionId} step --skip-ui-check --skip-reason "<reason>"`,
|
|
244
|
+
cwd,
|
|
245
|
+
sessionId,
|
|
246
|
+
stdinOption: "-",
|
|
247
|
+
textOption: "skip-reason"
|
|
248
|
+
});
|
|
249
|
+
if (skipReason.ok === false) {
|
|
250
|
+
return skipReason;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const agentDecisions = await resolveTextInput({
|
|
254
|
+
codePrefix: "agent_decisions",
|
|
255
|
+
fileOption: "agent-decisions-file",
|
|
256
|
+
inlineOptions,
|
|
257
|
+
io,
|
|
258
|
+
repairCommand: `jskit session ${sessionId} step --agent-decisions -`,
|
|
259
|
+
cwd,
|
|
260
|
+
sessionId,
|
|
261
|
+
stdinOption: "-",
|
|
262
|
+
textOption: "agent-decisions"
|
|
263
|
+
});
|
|
264
|
+
if (agentDecisions.ok === false) {
|
|
265
|
+
return agentDecisions;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const closeReason = await resolveTextInput({
|
|
269
|
+
codePrefix: "close_reason",
|
|
270
|
+
fileOption: "close-reason-file",
|
|
271
|
+
inlineOptions,
|
|
272
|
+
io,
|
|
273
|
+
repairCommand: `jskit session ${sessionId} step --close-without-merge --close-reason "<reason>"`,
|
|
274
|
+
cwd,
|
|
275
|
+
sessionId,
|
|
276
|
+
stdinOption: "-",
|
|
277
|
+
textOption: "close-reason"
|
|
278
|
+
});
|
|
279
|
+
if (closeReason.ok === false) {
|
|
280
|
+
return closeReason;
|
|
281
|
+
}
|
|
282
|
+
|
|
153
283
|
return {
|
|
284
|
+
agentDecisions: agentDecisions.value,
|
|
285
|
+
closeReason: closeReason.value,
|
|
154
286
|
issue: issue.value,
|
|
155
|
-
|
|
287
|
+
issueTitle: issueTitle.value,
|
|
288
|
+
ok: true,
|
|
289
|
+
plan: plan.value,
|
|
290
|
+
issueDetails: issueDetails.value,
|
|
291
|
+
reworkNotes: reworkNotes.value,
|
|
292
|
+
skipReason: skipReason.value
|
|
156
293
|
};
|
|
157
294
|
}
|
|
158
295
|
|
|
159
296
|
function normalizeStepOptions(inlineOptions = {}) {
|
|
160
|
-
|
|
297
|
+
const options = {
|
|
161
298
|
...inlineOptions,
|
|
299
|
+
closeWithoutMerge: inlineOptions["close-without-merge"] === "true" || inlineOptions.closeWithoutMerge === true,
|
|
300
|
+
mergePr: inlineOptions["merge-pr"] === "true" || inlineOptions.mergePr === true,
|
|
162
301
|
prompt: inlineOptions.prompt,
|
|
302
|
+
reviewFindings: inlineOptions["review-findings"] || inlineOptions.reviewFindings,
|
|
303
|
+
skipUiCheck: inlineOptions["skip-ui-check"] === "true" || inlineOptions.skipUiCheck === true,
|
|
163
304
|
userCheck: inlineOptions["user-check"] || inlineOptions.userCheck
|
|
164
305
|
};
|
|
306
|
+
if (Object.hasOwn(inlineOptions, "review-findings-remaining") || Object.hasOwn(inlineOptions, "reviewFindingsRemaining")) {
|
|
307
|
+
options.reviewFindingsRemaining = inlineOptions["review-findings-remaining"] === "true" ||
|
|
308
|
+
inlineOptions.reviewFindingsRemaining === true;
|
|
309
|
+
}
|
|
310
|
+
return options;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function resolveListArchiveOption(options = {}) {
|
|
314
|
+
const archives = [];
|
|
315
|
+
if (options.abandoned) {
|
|
316
|
+
archives.push("abandoned");
|
|
317
|
+
}
|
|
318
|
+
if (options.completed) {
|
|
319
|
+
archives.push("completed");
|
|
320
|
+
}
|
|
321
|
+
if (options.all) {
|
|
322
|
+
archives.push("all");
|
|
323
|
+
}
|
|
324
|
+
return archives.length > 0 ? archives : "active";
|
|
165
325
|
}
|
|
166
326
|
|
|
167
327
|
function createSessionCommands() {
|
|
@@ -178,7 +338,10 @@ function createSessionCommands() {
|
|
|
178
338
|
let payload;
|
|
179
339
|
|
|
180
340
|
if (!first) {
|
|
181
|
-
payload = await listSessions({
|
|
341
|
+
payload = await listSessions({
|
|
342
|
+
targetRoot: cwd,
|
|
343
|
+
archive: resolveListArchiveOption(options)
|
|
344
|
+
});
|
|
182
345
|
} else if (first === "create") {
|
|
183
346
|
payload = await createSession({ targetRoot: cwd });
|
|
184
347
|
} else if (second === "step") {
|
|
@@ -195,7 +358,14 @@ function createSessionCommands() {
|
|
|
195
358
|
sessionId: first,
|
|
196
359
|
options: {
|
|
197
360
|
...normalizeStepOptions(inlineOptions),
|
|
198
|
-
issue: stepInputs.issue
|
|
361
|
+
issue: stepInputs.issue,
|
|
362
|
+
issueTitle: stepInputs.issueTitle,
|
|
363
|
+
plan: stepInputs.plan,
|
|
364
|
+
issueDetails: stepInputs.issueDetails,
|
|
365
|
+
reworkNotes: stepInputs.reworkNotes,
|
|
366
|
+
skipReason: stepInputs.skipReason,
|
|
367
|
+
agentDecisions: stepInputs.agentDecisions,
|
|
368
|
+
closeReason: stepInputs.closeReason
|
|
199
369
|
}
|
|
200
370
|
});
|
|
201
371
|
} else if (second === "abandon") {
|
|
@@ -203,6 +373,11 @@ function createSessionCommands() {
|
|
|
203
373
|
targetRoot: cwd,
|
|
204
374
|
sessionId: first
|
|
205
375
|
});
|
|
376
|
+
} else if (second === "diff") {
|
|
377
|
+
payload = await inspectSessionDiff({
|
|
378
|
+
targetRoot: cwd,
|
|
379
|
+
sessionId: first
|
|
380
|
+
});
|
|
206
381
|
} else if (second === "adopt-codex-thread") {
|
|
207
382
|
payload = await adoptCodexThreadId({
|
|
208
383
|
targetRoot: cwd,
|
|
@@ -12,10 +12,17 @@ function createShowCommand(ctx = {}) {
|
|
|
12
12
|
createColorFormatter,
|
|
13
13
|
resolveWrapWidth,
|
|
14
14
|
writeWrappedItems,
|
|
15
|
+
normalizeRelativePath,
|
|
15
16
|
normalizeRelativePosixPath,
|
|
17
|
+
resolveAppRootFromCwd,
|
|
16
18
|
resolvePackageIdInput,
|
|
17
19
|
loadPackageRegistry,
|
|
18
20
|
loadBundleRegistry,
|
|
21
|
+
loadAppLocalPackageRegistry,
|
|
22
|
+
loadLockFile,
|
|
23
|
+
mergePackageRegistries,
|
|
24
|
+
path,
|
|
25
|
+
fileExists,
|
|
19
26
|
inspectPackageOfferings,
|
|
20
27
|
buildFileWriteGroups,
|
|
21
28
|
listDeclaredCapabilities,
|
|
@@ -28,7 +35,149 @@ function createShowCommand(ctx = {}) {
|
|
|
28
35
|
deriveProviderDisplayName
|
|
29
36
|
} = ctx;
|
|
30
37
|
|
|
31
|
-
async function
|
|
38
|
+
async function renderPackageEntry({
|
|
39
|
+
packageRegistry,
|
|
40
|
+
packageEntry,
|
|
41
|
+
options,
|
|
42
|
+
stdout,
|
|
43
|
+
color
|
|
44
|
+
}) {
|
|
45
|
+
const {
|
|
46
|
+
payload,
|
|
47
|
+
provides,
|
|
48
|
+
requires,
|
|
49
|
+
capabilityDetails
|
|
50
|
+
} = await buildPackageShowPayload({
|
|
51
|
+
packageRegistry,
|
|
52
|
+
packageEntry,
|
|
53
|
+
options,
|
|
54
|
+
inspectPackageOfferings,
|
|
55
|
+
buildFileWriteGroups,
|
|
56
|
+
listDeclaredCapabilities,
|
|
57
|
+
buildCapabilityDetailsForPackage
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
if (options.json) {
|
|
61
|
+
stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
62
|
+
} else {
|
|
63
|
+
renderPackagePayloadText({
|
|
64
|
+
payload,
|
|
65
|
+
provides,
|
|
66
|
+
requires,
|
|
67
|
+
capabilityDetails,
|
|
68
|
+
options,
|
|
69
|
+
stdout,
|
|
70
|
+
color,
|
|
71
|
+
resolveWrapWidth,
|
|
72
|
+
writeWrappedItems,
|
|
73
|
+
normalizeRelativePosixPath,
|
|
74
|
+
formatPackageSubpathImport,
|
|
75
|
+
normalizePlacementOutlets,
|
|
76
|
+
normalizePlacementContributions,
|
|
77
|
+
shouldShowPackageExportTarget,
|
|
78
|
+
classifyExportedSymbols,
|
|
79
|
+
deriveProviderDisplayName
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function isLocalPackageLockEntry(lockEntry = {}) {
|
|
85
|
+
const sourceType = String(lockEntry?.source?.type || "").trim();
|
|
86
|
+
return sourceType === "local-package" || sourceType === "app-local-package";
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function resolveInstalledLocalPackageEntry(lock = {}, id = "") {
|
|
90
|
+
const normalizedId = String(id || "").trim();
|
|
91
|
+
if (!normalizedId) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const installedPackages = lock?.installedPackages || {};
|
|
96
|
+
const directEntry = installedPackages[normalizedId];
|
|
97
|
+
if (directEntry && isLocalPackageLockEntry(directEntry)) {
|
|
98
|
+
return {
|
|
99
|
+
packageId: normalizedId,
|
|
100
|
+
lockEntry: directEntry
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
for (const [packageId, lockEntry] of Object.entries(installedPackages)) {
|
|
105
|
+
if (!isLocalPackageLockEntry(lockEntry)) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
const recordedPackageId = String(lockEntry?.packageId || "").trim();
|
|
109
|
+
if (recordedPackageId === normalizedId) {
|
|
110
|
+
return {
|
|
111
|
+
packageId,
|
|
112
|
+
lockEntry
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async function assertInstalledLocalPackageIsDiscoverable({ appRoot, id }) {
|
|
121
|
+
const { lock } = await loadLockFile(appRoot);
|
|
122
|
+
const installedLocalPackage = resolveInstalledLocalPackageEntry(lock, id);
|
|
123
|
+
if (!installedLocalPackage) {
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const { packageId, lockEntry } = installedLocalPackage;
|
|
128
|
+
const source = lockEntry?.source || {};
|
|
129
|
+
const descriptorPath = String(source.descriptorPath || "").trim();
|
|
130
|
+
if (!descriptorPath) {
|
|
131
|
+
throw createCliError(
|
|
132
|
+
`Local package ${packageId} is recorded in .jskit/lock.json but has no descriptorPath.`
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
const absoluteDescriptorPath = path.resolve(appRoot, descriptorPath);
|
|
137
|
+
if (!(await fileExists(absoluteDescriptorPath))) {
|
|
138
|
+
throw createCliError(
|
|
139
|
+
`Local package ${packageId} is recorded in .jskit/lock.json but descriptor is missing at ${descriptorPath}.`
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const packagePath = String(source.packagePath || "").trim();
|
|
144
|
+
if (packagePath) {
|
|
145
|
+
const packageJsonPath = path.join(appRoot, packagePath, "package.json");
|
|
146
|
+
if (!(await fileExists(packageJsonPath))) {
|
|
147
|
+
throw createCliError(
|
|
148
|
+
`Local package ${packageId} is recorded in .jskit/lock.json but package.json is missing at ${packagePath}/package.json.`
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const descriptorLabel = normalizeRelativePath(appRoot, absoluteDescriptorPath);
|
|
154
|
+
throw createCliError(
|
|
155
|
+
`Local package ${packageId} is recorded in .jskit/lock.json but was not discoverable from ${descriptorLabel}. Ensure its package.json name matches the descriptor packageId.`
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
async function resolveAppLocalShowTarget({ id, cwd, catalogPackageRegistry }) {
|
|
160
|
+
let appRoot = "";
|
|
161
|
+
try {
|
|
162
|
+
appRoot = await resolveAppRootFromCwd(cwd);
|
|
163
|
+
} catch {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const appLocalRegistry = await loadAppLocalPackageRegistry(appRoot);
|
|
168
|
+
const resolvedPackageId = resolvePackageIdInput(id, appLocalRegistry);
|
|
169
|
+
if (resolvedPackageId) {
|
|
170
|
+
return {
|
|
171
|
+
packageRegistry: mergePackageRegistries(catalogPackageRegistry, appLocalRegistry),
|
|
172
|
+
packageEntry: appLocalRegistry.get(resolvedPackageId)
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
await assertInstalledLocalPackageIsDiscoverable({ appRoot, id });
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async function commandShow({ positional, options, cwd, stdout }) {
|
|
32
181
|
const id = String(positional[0] || "").trim();
|
|
33
182
|
if (!id) {
|
|
34
183
|
throw createCliError("show requires an id.", { showUsage: true });
|
|
@@ -41,43 +190,13 @@ function createShowCommand(ctx = {}) {
|
|
|
41
190
|
|
|
42
191
|
if (resolvedPackageId) {
|
|
43
192
|
const packageEntry = packageRegistry.get(resolvedPackageId);
|
|
44
|
-
|
|
45
|
-
payload,
|
|
46
|
-
provides,
|
|
47
|
-
requires,
|
|
48
|
-
capabilityDetails
|
|
49
|
-
} = await buildPackageShowPayload({
|
|
193
|
+
await renderPackageEntry({
|
|
50
194
|
packageRegistry,
|
|
51
195
|
packageEntry,
|
|
52
196
|
options,
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
listDeclaredCapabilities,
|
|
56
|
-
buildCapabilityDetailsForPackage
|
|
197
|
+
stdout,
|
|
198
|
+
color
|
|
57
199
|
});
|
|
58
|
-
|
|
59
|
-
if (options.json) {
|
|
60
|
-
stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
61
|
-
} else {
|
|
62
|
-
renderPackagePayloadText({
|
|
63
|
-
payload,
|
|
64
|
-
provides,
|
|
65
|
-
requires,
|
|
66
|
-
capabilityDetails,
|
|
67
|
-
options,
|
|
68
|
-
stdout,
|
|
69
|
-
color,
|
|
70
|
-
resolveWrapWidth,
|
|
71
|
-
writeWrappedItems,
|
|
72
|
-
normalizeRelativePosixPath,
|
|
73
|
-
formatPackageSubpathImport,
|
|
74
|
-
normalizePlacementOutlets,
|
|
75
|
-
normalizePlacementContributions,
|
|
76
|
-
shouldShowPackageExportTarget,
|
|
77
|
-
classifyExportedSymbols,
|
|
78
|
-
deriveProviderDisplayName
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
200
|
return 0;
|
|
82
201
|
}
|
|
83
202
|
|
|
@@ -103,6 +222,22 @@ function createShowCommand(ctx = {}) {
|
|
|
103
222
|
return 0;
|
|
104
223
|
}
|
|
105
224
|
|
|
225
|
+
const appLocalTarget = await resolveAppLocalShowTarget({
|
|
226
|
+
id,
|
|
227
|
+
cwd,
|
|
228
|
+
catalogPackageRegistry: packageRegistry
|
|
229
|
+
});
|
|
230
|
+
if (appLocalTarget) {
|
|
231
|
+
await renderPackageEntry({
|
|
232
|
+
packageRegistry: appLocalTarget.packageRegistry,
|
|
233
|
+
packageEntry: appLocalTarget.packageEntry,
|
|
234
|
+
options,
|
|
235
|
+
stdout,
|
|
236
|
+
color
|
|
237
|
+
});
|
|
238
|
+
return 0;
|
|
239
|
+
}
|
|
240
|
+
|
|
106
241
|
throw createCliError(`Unknown package or bundle: ${id}`);
|
|
107
242
|
}
|
|
108
243
|
|
|
@@ -23,6 +23,8 @@ function parseArgs(argv, { createCliError } = {}) {
|
|
|
23
23
|
verbose: false,
|
|
24
24
|
json: false,
|
|
25
25
|
all: false,
|
|
26
|
+
abandoned: false,
|
|
27
|
+
completed: false,
|
|
26
28
|
concrete: false,
|
|
27
29
|
help: true,
|
|
28
30
|
inlineOptions: {}
|
|
@@ -50,6 +52,8 @@ function parseArgs(argv, { createCliError } = {}) {
|
|
|
50
52
|
verbose: false,
|
|
51
53
|
json: false,
|
|
52
54
|
all: false,
|
|
55
|
+
abandoned: false,
|
|
56
|
+
completed: false,
|
|
53
57
|
concrete: false,
|
|
54
58
|
help: false,
|
|
55
59
|
inlineOptions: {}
|
|
@@ -109,6 +113,14 @@ function parseArgs(argv, { createCliError } = {}) {
|
|
|
109
113
|
options.all = true;
|
|
110
114
|
continue;
|
|
111
115
|
}
|
|
116
|
+
if (token === "--abandoned") {
|
|
117
|
+
options.abandoned = true;
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if (token === "--completed") {
|
|
121
|
+
options.completed = true;
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
112
124
|
if (token === "--concrete") {
|
|
113
125
|
options.concrete = true;
|
|
114
126
|
continue;
|
|
@@ -125,6 +137,14 @@ function parseArgs(argv, { createCliError } = {}) {
|
|
|
125
137
|
options.inlineOptions.install = "true";
|
|
126
138
|
continue;
|
|
127
139
|
}
|
|
140
|
+
if (token === "--skip-ui-check") {
|
|
141
|
+
options.inlineOptions["skip-ui-check"] = "true";
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (token === "--close-without-merge") {
|
|
145
|
+
options.inlineOptions["close-without-merge"] = "true";
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
128
148
|
|
|
129
149
|
if (token.startsWith("--")) {
|
|
130
150
|
const withoutPrefix = token.slice(2);
|