@jskit-ai/jskit-cli 0.2.81 → 0.2.83
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 +127 -3
- package/src/server/commandHandlers/show.js +169 -34
- package/src/server/core/argParser.js +8 -0
- package/src/server/core/commandCatalog.js +60 -2
- 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 +326 -87
- package/src/server/sessionRuntime/preconditions.js +382 -5
- package/src/server/sessionRuntime/promptRenderer.js +15 -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/execute_plan.md +33 -7
- package/src/server/sessionRuntime/prompts/final_comment.md +3 -1
- package/src/server/sessionRuntime/prompts/issue_details.md +46 -0
- package/src/server/sessionRuntime/prompts/new_issue.md +15 -2
- package/src/server/sessionRuntime/prompts/plan_issue.md +40 -9
- package/src/server/sessionRuntime/prompts/resolve_deslop_findings.md +16 -0
- package/src/server/sessionRuntime/prompts/review_changes.md +46 -5
- package/src/server/sessionRuntime/prompts/update_blueprint.md +38 -0
- package/src/server/sessionRuntime/prompts/user_check.md +15 -1
- package/src/server/sessionRuntime/responses.js +860 -62
- package/src/server/sessionRuntime.js +1699 -140
- package/src/server/sessionRuntime/prompts/doctor_failure.md +0 -26
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.83",
|
|
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.82",
|
|
24
|
+
"@jskit-ai/kernel": "0.1.74",
|
|
25
|
+
"@jskit-ai/shell-web": "0.1.73",
|
|
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 };
|
|
@@ -147,6 +147,19 @@ async function resolveStepInputs({
|
|
|
147
147
|
cwd,
|
|
148
148
|
sessionId
|
|
149
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
|
+
|
|
150
163
|
const issueTitle = await resolveTextInput({
|
|
151
164
|
codePrefix: "issue_title",
|
|
152
165
|
fileOption: "issue-title-file",
|
|
@@ -192,20 +205,125 @@ async function resolveStepInputs({
|
|
|
192
205
|
return plan;
|
|
193
206
|
}
|
|
194
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
|
+
|
|
283
|
+
const codexResult = await resolveTextInput({
|
|
284
|
+
codePrefix: "codex_result",
|
|
285
|
+
fileOption: "codex-result-file",
|
|
286
|
+
inlineOptions,
|
|
287
|
+
io,
|
|
288
|
+
repairCommand: `jskit session ${sessionId} step --codex-result -`,
|
|
289
|
+
cwd,
|
|
290
|
+
sessionId,
|
|
291
|
+
stdinOption: "-",
|
|
292
|
+
textOption: "codex-result"
|
|
293
|
+
});
|
|
294
|
+
if (codexResult.ok === false) {
|
|
295
|
+
return codexResult;
|
|
296
|
+
}
|
|
297
|
+
|
|
195
298
|
return {
|
|
299
|
+
agentDecisions: agentDecisions.value,
|
|
300
|
+
closeReason: closeReason.value,
|
|
301
|
+
codexResult: codexResult.value,
|
|
196
302
|
issue: issue.value,
|
|
197
303
|
issueTitle: issueTitle.value,
|
|
198
304
|
ok: true,
|
|
199
|
-
plan: plan.value
|
|
305
|
+
plan: plan.value,
|
|
306
|
+
issueDetails: issueDetails.value,
|
|
307
|
+
reworkNotes: reworkNotes.value,
|
|
308
|
+
skipReason: skipReason.value
|
|
200
309
|
};
|
|
201
310
|
}
|
|
202
311
|
|
|
203
312
|
function normalizeStepOptions(inlineOptions = {}) {
|
|
204
|
-
|
|
313
|
+
const options = {
|
|
205
314
|
...inlineOptions,
|
|
315
|
+
closeWithoutMerge: inlineOptions["close-without-merge"] === "true" || inlineOptions.closeWithoutMerge === true,
|
|
316
|
+
mergePr: inlineOptions["merge-pr"] === "true" || inlineOptions.mergePr === true,
|
|
206
317
|
prompt: inlineOptions.prompt,
|
|
318
|
+
reviewFindings: inlineOptions["review-findings"] || inlineOptions.reviewFindings,
|
|
319
|
+
skipUiCheck: inlineOptions["skip-ui-check"] === "true" || inlineOptions.skipUiCheck === true,
|
|
207
320
|
userCheck: inlineOptions["user-check"] || inlineOptions.userCheck
|
|
208
321
|
};
|
|
322
|
+
if (Object.hasOwn(inlineOptions, "review-findings-remaining") || Object.hasOwn(inlineOptions, "reviewFindingsRemaining")) {
|
|
323
|
+
options.reviewFindingsRemaining = inlineOptions["review-findings-remaining"] === "true" ||
|
|
324
|
+
inlineOptions.reviewFindingsRemaining === true;
|
|
325
|
+
}
|
|
326
|
+
return options;
|
|
209
327
|
}
|
|
210
328
|
|
|
211
329
|
function resolveListArchiveOption(options = {}) {
|
|
@@ -258,7 +376,13 @@ function createSessionCommands() {
|
|
|
258
376
|
...normalizeStepOptions(inlineOptions),
|
|
259
377
|
issue: stepInputs.issue,
|
|
260
378
|
issueTitle: stepInputs.issueTitle,
|
|
261
|
-
plan: stepInputs.plan
|
|
379
|
+
plan: stepInputs.plan,
|
|
380
|
+
issueDetails: stepInputs.issueDetails,
|
|
381
|
+
reworkNotes: stepInputs.reworkNotes,
|
|
382
|
+
skipReason: stepInputs.skipReason,
|
|
383
|
+
agentDecisions: stepInputs.agentDecisions,
|
|
384
|
+
closeReason: stepInputs.closeReason,
|
|
385
|
+
codexResult: stepInputs.codexResult
|
|
262
386
|
}
|
|
263
387
|
});
|
|
264
388
|
} else if (second === "abandon") {
|
|
@@ -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
|
|
|
@@ -137,6 +137,14 @@ function parseArgs(argv, { createCliError } = {}) {
|
|
|
137
137
|
options.inlineOptions.install = "true";
|
|
138
138
|
continue;
|
|
139
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
|
+
}
|
|
140
148
|
|
|
141
149
|
if (token.startsWith("--")) {
|
|
142
150
|
const withoutPrefix = token.slice(2);
|
|
@@ -224,7 +224,17 @@ const COMMAND_DESCRIPTORS = Object.freeze({
|
|
|
224
224
|
"Use --json for the stable machine-readable contract consumed by JSKIT AI Studio.",
|
|
225
225
|
"Use --issue - to read approved issue body from stdin.",
|
|
226
226
|
"Use --issue-title when the approved issue title is separate from the body.",
|
|
227
|
-
"Use --
|
|
227
|
+
"Use --issue-details - to read confirmed issue details from stdin.",
|
|
228
|
+
"Use --plan - to read the approved implementation plan from stdin.",
|
|
229
|
+
"Use --codex-result - after Codex prompt steps to read the final marked Codex result from stdin.",
|
|
230
|
+
"Use --rework-notes - with --user-check failed to start the next plan cycle.",
|
|
231
|
+
"Use --agent-decisions - to append session-local decision log entries from implementation, UI review, verification, or repair phases.",
|
|
232
|
+
"Use --review-findings-remaining true --review-findings \"<findings>\" when an accepted review pass needs another pass.",
|
|
233
|
+
"Use --review-findings-remaining false only when the review/deslop loop is done.",
|
|
234
|
+
"Use --skip-ui-check --skip-reason \"<reason>\" only when uiImpact is possible and the Deep UI Check is intentionally skipped.",
|
|
235
|
+
"Use --merge-pr true at PR finalization to merge the pull request.",
|
|
236
|
+
"Use --close-without-merge --close-reason \"<reason>\" at PR finalization to complete the session without merging.",
|
|
237
|
+
"Run the blueprint step once to render its Codex prompt, then again after Codex updates .jskit/APP_BLUEPRINT.md."
|
|
228
238
|
]),
|
|
229
239
|
examples: Object.freeze([
|
|
230
240
|
Object.freeze({
|
|
@@ -234,13 +244,23 @@ const COMMAND_DESCRIPTORS = Object.freeze({
|
|
|
234
244
|
"jskit session 2026-05-11_21-42-08 step",
|
|
235
245
|
"jskit session 2026-05-11_21-42-08 step --prompt \"Fix the customer filters\"",
|
|
236
246
|
"jskit session 2026-05-11_21-42-08 step --issue-title \"Fix customer filters\" --issue -",
|
|
247
|
+
"jskit session 2026-05-11_21-42-08 step --issue-details -",
|
|
237
248
|
"jskit session 2026-05-11_21-42-08 step --plan -",
|
|
249
|
+
"jskit session 2026-05-11_21-42-08 step --codex-result -",
|
|
250
|
+
"jskit session 2026-05-11_21-42-08 step --agent-decisions -",
|
|
251
|
+
"jskit session 2026-05-11_21-42-08 step --review-findings-remaining true --review-findings \"A helper duplication fix needs another pass\"",
|
|
252
|
+
"jskit session 2026-05-11_21-42-08 step --review-findings-remaining false",
|
|
253
|
+
"jskit session 2026-05-11_21-42-08 step --skip-ui-check --skip-reason \"No user-facing UI changes\"",
|
|
254
|
+
"jskit session 2026-05-11_21-42-08 step",
|
|
255
|
+
"jskit session 2026-05-11_21-42-08 step --merge-pr true",
|
|
256
|
+
"jskit session 2026-05-11_21-42-08 step --close-without-merge --close-reason \"Prototype kept for reference\"",
|
|
257
|
+
"jskit session 2026-05-11_21-42-08 step --user-check failed --rework-notes -",
|
|
238
258
|
"jskit session 2026-05-11_21-42-08 diff --json"
|
|
239
259
|
])
|
|
240
260
|
})
|
|
241
261
|
]),
|
|
242
262
|
fullUse:
|
|
243
|
-
"jskit session [create|<sessionId>] [step|diff|abandon|adopt-codex-thread] [--prompt <text>] [--issue-title <text>|--issue-title-file <path>] [--issue <text>|--issue-file <path>] [--plan <text>|--plan-file <path>] [--user-check <passed|failed>] [--codex-thread-id <id>] [--abandoned|--completed|--all] [--json]",
|
|
263
|
+
"jskit session [create|<sessionId>] [step|diff|abandon|adopt-codex-thread] [--prompt <text>] [--issue-title <text>|--issue-title-file <path>] [--issue <text>|--issue-file <path>] [--issue-details <text>|--issue-details-file <path>] [--plan <text>|--plan-file <path>] [--codex-result <text>|--codex-result-file <path>] [--agent-decisions <text>|--agent-decisions-file <path>] [--review-findings-remaining true --review-findings <text>|--review-findings-remaining false] [--skip-ui-check --skip-reason <text>] [--merge-pr true|--close-without-merge --close-reason <text>] [--user-check <passed|failed>] [--rework-notes <text>|--rework-notes-file <path>] [--codex-thread-id <id>] [--abandoned|--completed|--all] [--json]",
|
|
244
264
|
showHelpOnBareInvocation: false,
|
|
245
265
|
handlerName: "commandSession",
|
|
246
266
|
allowedFlagKeys: Object.freeze(["json", "abandoned", "completed", "all"]),
|
|
@@ -288,6 +308,44 @@ const COMMAND_DESCRIPTORS = Object.freeze({
|
|
|
288
308
|
return subcommand === "prompt" || subcommand === "set";
|
|
289
309
|
}
|
|
290
310
|
}),
|
|
311
|
+
"helper-map": Object.freeze({
|
|
312
|
+
command: "helper-map",
|
|
313
|
+
aliases: Object.freeze([]),
|
|
314
|
+
showInOverview: true,
|
|
315
|
+
summary: "Read or update the generated app helper map.",
|
|
316
|
+
minimalUse: "jskit helper-map update",
|
|
317
|
+
parameters: Object.freeze([
|
|
318
|
+
Object.freeze({
|
|
319
|
+
name: "[update]",
|
|
320
|
+
description: "Without a subcommand, prints the saved helper map. update refreshes .jskit/helper-map files."
|
|
321
|
+
})
|
|
322
|
+
]),
|
|
323
|
+
defaults: Object.freeze([
|
|
324
|
+
"The helper map is generated app state, not a hand-maintained workflow file.",
|
|
325
|
+
"The JSON file lives at .jskit/helper-map.json and the readable map lives at .jskit/helper-map.md.",
|
|
326
|
+
"Use the map before adding helpers, composables, service functions, maps, or package glue.",
|
|
327
|
+
"Use --json for a stable machine-readable response."
|
|
328
|
+
]),
|
|
329
|
+
examples: Object.freeze([
|
|
330
|
+
Object.freeze({
|
|
331
|
+
label: "Refresh helper map",
|
|
332
|
+
lines: Object.freeze([
|
|
333
|
+
"jskit helper-map update",
|
|
334
|
+
"jskit helper-map --json"
|
|
335
|
+
])
|
|
336
|
+
})
|
|
337
|
+
]),
|
|
338
|
+
fullUse: "jskit helper-map [update] [--json]",
|
|
339
|
+
showHelpOnBareInvocation: false,
|
|
340
|
+
handlerName: "commandHelperMap",
|
|
341
|
+
allowedFlagKeys: Object.freeze(["json"]),
|
|
342
|
+
inlineOptionMode: "delegate",
|
|
343
|
+
allowedValueOptionNames: Object.freeze([]),
|
|
344
|
+
canDelegateInlineOptions: (positional = []) => {
|
|
345
|
+
const subcommand = String(Array.isArray(positional) ? positional[0] || "" : "").trim();
|
|
346
|
+
return subcommand === "update";
|
|
347
|
+
}
|
|
348
|
+
}),
|
|
291
349
|
add: Object.freeze({
|
|
292
350
|
command: "add",
|
|
293
351
|
aliases: Object.freeze([]),
|
|
@@ -8,6 +8,7 @@ import { createHealthCommands } from "../commandHandlers/health.js";
|
|
|
8
8
|
import { createCompletionCommands } from "../commandHandlers/completion.js";
|
|
9
9
|
import { createSessionCommands } from "../commandHandlers/session.js";
|
|
10
10
|
import { createBlueprintCommands } from "../commandHandlers/blueprint.js";
|
|
11
|
+
import { createHelperMapCommands } from "../commandHandlers/helperMap.js";
|
|
11
12
|
|
|
12
13
|
function createCommandHandlers(deps = {}) {
|
|
13
14
|
const shared = createCommandHandlerShared(deps);
|
|
@@ -33,6 +34,7 @@ function createCommandHandlers(deps = {}) {
|
|
|
33
34
|
const { commandCompletion } = createCompletionCommands(commandContext);
|
|
34
35
|
const { commandSession } = createSessionCommands(commandContext);
|
|
35
36
|
const { commandBlueprint } = createBlueprintCommands(commandContext);
|
|
37
|
+
const { commandHelperMap } = createHelperMapCommands(commandContext);
|
|
36
38
|
|
|
37
39
|
return {
|
|
38
40
|
commandList,
|
|
@@ -52,7 +54,8 @@ function createCommandHandlers(deps = {}) {
|
|
|
52
54
|
commandDoctor,
|
|
53
55
|
commandLintDescriptors,
|
|
54
56
|
commandSession,
|
|
55
|
-
commandBlueprint
|
|
57
|
+
commandBlueprint,
|
|
58
|
+
commandHelperMap
|
|
56
59
|
};
|
|
57
60
|
}
|
|
58
61
|
|