@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.
Files changed (28) hide show
  1. package/package.json +6 -4
  2. package/src/server/appBlueprint.js +1 -1
  3. package/src/server/commandHandlers/helperMap.js +104 -0
  4. package/src/server/commandHandlers/session.js +127 -3
  5. package/src/server/commandHandlers/show.js +169 -34
  6. package/src/server/core/argParser.js +8 -0
  7. package/src/server/core/commandCatalog.js +60 -2
  8. package/src/server/core/createCommandHandlers.js +4 -1
  9. package/src/server/helperMap.js +463 -0
  10. package/src/server/helperMapPaths.js +7 -0
  11. package/src/server/sessionRuntime/appReadiness.js +55 -0
  12. package/src/server/sessionRuntime/constants.js +326 -87
  13. package/src/server/sessionRuntime/preconditions.js +382 -5
  14. package/src/server/sessionRuntime/promptRenderer.js +15 -2
  15. package/src/server/sessionRuntime/prompts/automated_checks.md +42 -0
  16. package/src/server/sessionRuntime/prompts/deep_ui_check.md +53 -0
  17. package/src/server/sessionRuntime/prompts/execute_plan.md +33 -7
  18. package/src/server/sessionRuntime/prompts/final_comment.md +3 -1
  19. package/src/server/sessionRuntime/prompts/issue_details.md +46 -0
  20. package/src/server/sessionRuntime/prompts/new_issue.md +15 -2
  21. package/src/server/sessionRuntime/prompts/plan_issue.md +40 -9
  22. package/src/server/sessionRuntime/prompts/resolve_deslop_findings.md +16 -0
  23. package/src/server/sessionRuntime/prompts/review_changes.md +46 -5
  24. package/src/server/sessionRuntime/prompts/update_blueprint.md +38 -0
  25. package/src/server/sessionRuntime/prompts/user_check.md +15 -1
  26. package/src/server/sessionRuntime/responses.js +860 -62
  27. package/src/server/sessionRuntime.js +1699 -140
  28. package/src/server/sessionRuntime/prompts/doctor_failure.md +0 -26
@@ -13,7 +13,19 @@ const SESSION_STATUS = Object.freeze({
13
13
 
14
14
  const SESSION_ID_PATTERN = /^\d{4}-\d{2}-\d{2}_\d{2}-\d{2}-\d{2}(?:-[a-z0-9]{4})?$/u;
15
15
  const SESSION_STATE_RELATIVE_PATH = ".jskit/sessions";
16
+ const SESSION_WORKFLOW_VERSION = "6";
17
+ const REVIEW_PASS_LIMIT = 0;
16
18
  const PROMPT_DIRECTORY = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "prompts");
19
+ const JSKIT_CLI_SHELL_COMMAND = "npx --no-install jskit";
20
+ const JSKIT_CLI_SHELL_RULE = [
21
+ "Shell command rule:",
22
+ "",
23
+ `- When running JSKIT CLI commands from the shell, use \`${JSKIT_CLI_SHELL_COMMAND} ...\`.`,
24
+ "- Do not run bare `jskit ...` unless you are inside an npm script where `node_modules/.bin` is on PATH.",
25
+ "- Do not run `npx jskit ...` without `--no-install`; it may fetch packages instead of using this app's installed CLI.",
26
+ "- If `npx --no-install jskit ...` is unavailable, continue with filesystem inspection when possible and report that the local JSKIT CLI is missing."
27
+ ].join("\n");
28
+ const DEFAULT_NEXT_COMMAND_TEMPLATE = `${JSKIT_CLI_SHELL_COMMAND} session {{session_id}} step`;
17
29
 
18
30
  const INPUT_NONE = Object.freeze({ type: "none" });
19
31
  const ISSUE_TITLE_INPUT = Object.freeze({
@@ -72,6 +84,50 @@ const PLAN_OUTPUT = Object.freeze({
72
84
  multiline: true,
73
85
  required: true
74
86
  });
87
+ const ISSUE_DETAILS_INPUT = Object.freeze({
88
+ extract: "issue_details",
89
+ formatHint: "markdown",
90
+ label: "Confirmed issue details",
91
+ multiline: true,
92
+ name: "issueDetails",
93
+ required: true,
94
+ type: "text"
95
+ });
96
+ const ISSUE_DETAILS_OUTPUT = Object.freeze({
97
+ extract: "issue_details",
98
+ field: "issueDetails",
99
+ formatHint: "markdown",
100
+ label: "Issue details",
101
+ multiline: true,
102
+ required: true
103
+ });
104
+ const ISSUE_CATEGORY_OUTPUT = Object.freeze({
105
+ extract: "issue_category",
106
+ field: "issueCategory",
107
+ formatHint: "text",
108
+ label: "Issue category",
109
+ options: Object.freeze([
110
+ Object.freeze({ label: "Client", value: "client" }),
111
+ Object.freeze({ label: "Server", value: "server" }),
112
+ Object.freeze({ label: "Client and server", value: "client_server" }),
113
+ Object.freeze({ label: "Tooling", value: "tooling" }),
114
+ Object.freeze({ label: "Unknown", value: "unknown" })
115
+ ]),
116
+ required: true
117
+ });
118
+ const UI_IMPACT_OUTPUT = Object.freeze({
119
+ extract: "ui_impact",
120
+ field: "uiImpact",
121
+ formatHint: "text",
122
+ label: "UI impact",
123
+ options: Object.freeze([
124
+ Object.freeze({ label: "No UI impact", value: "none" }),
125
+ Object.freeze({ label: "Possible UI impact", value: "possible" }),
126
+ Object.freeze({ label: "Definite UI impact", value: "definite" }),
127
+ Object.freeze({ label: "Unknown", value: "unknown" })
128
+ ]),
129
+ required: true
130
+ });
75
131
  const USER_CHECK_INPUT = Object.freeze({
76
132
  label: "User check result",
77
133
  name: "userCheck",
@@ -82,28 +138,130 @@ const USER_CHECK_INPUT = Object.freeze({
82
138
  required: true,
83
139
  type: "choice"
84
140
  });
85
- function codexHandoff(expectedOutput, {
141
+
142
+ const JSKIT_STEP_RESULT_CONTRACT = Object.freeze({
143
+ completionBehavior: "auto_advance",
144
+ kind: "completion_marker",
145
+ marker: "jskit_step_result",
146
+ missingMarkerBehavior: "resend",
147
+ required: true,
148
+ stepField: "step"
149
+ });
150
+ const DESLOP_RESULT_CONTRACT = Object.freeze({
151
+ autoResolvePriorities: Object.freeze(["high", "medium"]),
152
+ completionBehavior: "deslop_loop",
153
+ kind: "deslop_result",
154
+ marker: "deslop_result",
155
+ missingMarkerBehavior: "resend",
156
+ required: true,
157
+ resolvePrompt: Object.freeze({
158
+ findingsPlaceholder: "{{findings}}",
159
+ marker: "resolve_deslop_findings",
160
+ templateFile: "resolve_deslop_findings.md"
161
+ })
162
+ });
163
+
164
+ function fieldResponseContract(outputDefinitions) {
165
+ const fields = outputDefinitions
166
+ .filter((output) => output?.field && output?.extract)
167
+ .map((output) => Object.freeze({
168
+ extract: output.extract,
169
+ field: output.field,
170
+ formatHint: output.formatHint || "",
171
+ label: output.label || output.field,
172
+ manualEntry: true,
173
+ ...(output.multiline === true ? { multiline: true } : {}),
174
+ ...(Array.isArray(output.options) ? { options: Object.freeze(output.options.map((option) => Object.freeze({ ...option }))) } : {}),
175
+ required: output.required !== false
176
+ }));
177
+ return Object.freeze({
178
+ fields: Object.freeze(fields),
179
+ kind: "fields",
180
+ missingMarkerBehavior: "manual_or_resend",
181
+ required: fields.some((field) => field.required)
182
+ });
183
+ }
184
+
185
+ function codexHandoff(outputDefinition, {
86
186
  autoInject = false,
87
- promptActionLabel = ""
187
+ promptActionLabel = "",
188
+ promptIntroText = "",
189
+ promptWaitingText = "",
190
+ responseContract = undefined
88
191
  } = {}) {
89
- const expectedOutputs = Object.freeze(Array.isArray(expectedOutput) ? [...expectedOutput] : [expectedOutput]);
192
+ const outputDefinitions = Object.freeze(Array.isArray(outputDefinition) ? [...outputDefinition] : [outputDefinition]);
193
+ const resolvedResponseContract = responseContract === undefined
194
+ ? fieldResponseContract(outputDefinitions)
195
+ : responseContract;
90
196
  return Object.freeze({
91
197
  ...(autoInject ? { autoInject: true } : {}),
92
- expectedOutput: expectedOutputs[expectedOutputs.length - 1] || null,
93
- expectedOutputs,
94
198
  mode: "inject_prompt",
95
199
  promptField: "prompt",
96
- ...(promptActionLabel ? { promptActionLabel } : {})
200
+ ...(promptActionLabel ? { promptActionLabel } : {}),
201
+ ...(promptIntroText ? { promptIntroText } : {}),
202
+ ...(promptWaitingText ? { promptWaitingText } : {}),
203
+ ...(resolvedResponseContract ? { responseContract: resolvedResponseContract } : {})
97
204
  });
98
205
  }
99
206
 
207
+ function stepAutomationFor({
208
+ codex = undefined,
209
+ id,
210
+ kind,
211
+ requiresExplicitRun = false
212
+ }) {
213
+ if (requiresExplicitRun) {
214
+ return Object.freeze({ mode: "manual" });
215
+ }
216
+ if (id === "dependencies_installed") {
217
+ return Object.freeze({ mode: "terminal" });
218
+ }
219
+ if (kind === "automatic") {
220
+ return Object.freeze({ mode: "immediate" });
221
+ }
222
+ if (kind === "codex_prompt" && codex?.autoInject === true) {
223
+ return Object.freeze({ mode: "codex_prompt" });
224
+ }
225
+ if (kind === "codex_output" && codex?.autoInject === true) {
226
+ return Object.freeze({ mode: "codex_output_prompt" });
227
+ }
228
+ return Object.freeze({ mode: "manual" });
229
+ }
230
+
100
231
  const PLAN_EXECUTION_CODEX_HANDOFF = codexHandoff([], {
101
232
  autoInject: true,
102
- promptActionLabel: "Execute plan"
233
+ promptActionLabel: "Get Codex to execute plan",
234
+ responseContract: JSKIT_STEP_RESULT_CONTRACT
235
+ });
236
+ const ISSUE_DETAILS_CODEX_HANDOFF = codexHandoff([
237
+ ISSUE_CATEGORY_OUTPUT,
238
+ UI_IMPACT_OUTPUT,
239
+ ISSUE_DETAILS_OUTPUT
240
+ ], {
241
+ autoInject: true,
242
+ promptActionLabel: "Start details conversation",
243
+ promptIntroText: "Codex will gather issue details and classify the issue.",
244
+ promptWaitingText: "Please respond and finalise things with Codex"
103
245
  });
104
246
  const REVIEW_EXECUTION_CODEX_HANDOFF = codexHandoff([], {
105
247
  autoInject: true,
106
- promptActionLabel: "Start review"
248
+ promptActionLabel: "Run deslop",
249
+ responseContract: DESLOP_RESULT_CONTRACT
250
+ });
251
+ const DEEP_UI_CHECK_CODEX_HANDOFF = codexHandoff([], {
252
+ autoInject: true,
253
+ promptActionLabel: "Run Deep UI check",
254
+ responseContract: JSKIT_STEP_RESULT_CONTRACT
255
+ });
256
+ const AUTOMATED_CHECK_REPAIR_CODEX_HANDOFF = codexHandoff([], {
257
+ autoInject: true,
258
+ promptActionLabel: "Run automated checks",
259
+ responseContract: JSKIT_STEP_RESULT_CONTRACT
260
+ });
261
+ const BLUEPRINT_CODEX_HANDOFF = codexHandoff([], {
262
+ autoInject: true,
263
+ promptActionLabel: "Update blueprint",
264
+ responseContract: JSKIT_STEP_RESULT_CONTRACT
107
265
  });
108
266
 
109
267
  function defineStep({
@@ -114,20 +272,36 @@ function defineStep({
114
272
  input = INPUT_NONE,
115
273
  kind = "automatic",
116
274
  label,
117
- nextCommandTemplate = "jskit session {{session_id}} step",
275
+ nextCommandTemplate = DEFAULT_NEXT_COMMAND_TEMPLATE,
118
276
  preconditions = [],
119
- utilityActions = []
277
+ requiresExplicitRun = false,
278
+ submitOptions = {},
279
+ automation = undefined,
280
+ utilityActions = [],
281
+ displayGroupId = "",
282
+ displayGroupLabel = ""
120
283
  }) {
284
+ const resolvedAutomation = automation || stepAutomationFor({
285
+ codex,
286
+ id,
287
+ kind,
288
+ requiresExplicitRun
289
+ });
121
290
  return Object.freeze({
291
+ automation: Object.freeze({ ...resolvedAutomation }),
122
292
  buttonLabel,
123
293
  codex,
124
294
  description,
295
+ displayGroupId,
296
+ displayGroupLabel,
125
297
  id,
126
298
  input,
127
299
  kind,
128
300
  label,
129
301
  nextCommandTemplate,
130
302
  preconditions: Object.freeze([...preconditions]),
303
+ requiresExplicitRun,
304
+ submitOptions: Object.freeze({ ...submitOptions }),
131
305
  utilityActions: Object.freeze([...utilityActions])
132
306
  });
133
307
  }
@@ -135,27 +309,27 @@ function defineStep({
135
309
  const STEP_DEFINITIONS = Object.freeze([
136
310
  defineStep({
137
311
  buttonLabel: "Create session",
138
- description: "Create the filesystem-backed session record.",
312
+ description: "JSKIT creates the filesystem-backed session record and initial receipt.",
139
313
  id: "session_created",
140
314
  label: "Session created"
141
315
  }),
142
316
  defineStep({
143
317
  buttonLabel: "Create worktree",
144
- description: "Create the isolated branch and worktree for this session.",
318
+ description: "JSKIT creates the isolated Git branch and session worktree where Codex will work.",
145
319
  id: "worktree_created",
146
320
  label: "Worktree created",
147
321
  preconditions: ["session_exists", "git_repository", "git_current_branch"]
148
322
  }),
149
323
  defineStep({
150
324
  buttonLabel: "Install dependencies",
151
- description: "Install Node dependencies inside the session worktree before Codex starts.",
325
+ description: "JSKIT installs Node dependencies inside the session worktree before Codex starts.",
152
326
  id: "dependencies_installed",
153
327
  label: "Dependencies installed",
154
328
  preconditions: ["session_exists", "worktree_exists"]
155
329
  }),
156
330
  defineStep({
157
- buttonLabel: "Submit prompt to Codex",
158
- description: "Capture the initial change request and send it to Codex to draft a GitHub issue.",
331
+ buttonLabel: "Set initial prompt",
332
+ description: "User describes the requested change; JSKIT records it and prepares the Codex issue-drafting prompt.",
159
333
  id: "issue_prompt_rendered",
160
334
  input: Object.freeze({
161
335
  label: "What should change?",
@@ -167,129 +341,176 @@ const STEP_DEFINITIONS = Object.freeze([
167
341
  }),
168
342
  kind: "human_input",
169
343
  label: "Initial issue prompt",
170
- nextCommandTemplate: "jskit session {{session_id}} step --prompt \"<what should change>\"",
171
- preconditions: ["session_exists"]
344
+ nextCommandTemplate: `${JSKIT_CLI_SHELL_COMMAND} session {{session_id}} step --prompt "<what should change>"`,
345
+ preconditions: ["session_exists", "worktree_exists", "dependencies_installed", "ready_jskit_app"]
172
346
  }),
173
347
  defineStep({
174
- buttonLabel: "Save issue draft",
348
+ buttonLabel: "Finalise issue",
175
349
  codex: codexHandoff([
176
350
  ISSUE_TITLE_OUTPUT,
177
351
  ISSUE_TEXT_OUTPUT
178
- ]),
179
- description: "Save the approved issue title and body drafted by Codex.",
352
+ ], {
353
+ autoInject: true,
354
+ promptActionLabel: "Get Codex to create issue text",
355
+ promptIntroText: "Codex will create a comprehensive issue."
356
+ }),
357
+ description: "Codex drafts the issue title and body; user reviews or edits them; JSKIT saves the approved draft.",
180
358
  id: "issue_drafted",
181
359
  input: ISSUE_DRAFT_INPUT,
182
360
  kind: "codex_output",
183
361
  label: "Issue drafted",
184
- nextCommandTemplate: "jskit session {{session_id}} step --issue -",
185
- preconditions: ["session_exists"]
362
+ nextCommandTemplate: `${JSKIT_CLI_SHELL_COMMAND} session {{session_id}} step --issue -`,
363
+ preconditions: ["session_exists", "worktree_exists", "dependencies_installed", "ready_jskit_app"]
186
364
  }),
187
365
  defineStep({
188
- buttonLabel: "Create GitHub issue",
189
- description: "Create the GitHub issue from the approved draft.",
366
+ buttonLabel: "Create issue",
367
+ description: "JSKIT creates the GitHub issue from the approved draft and records the issue URL.",
190
368
  id: "issue_created",
191
369
  label: "Issue created",
192
- preconditions: ["session_exists", "issue_text_exists", "github_auth", "github_origin"]
370
+ preconditions: ["session_exists", "worktree_exists", "dependencies_installed", "ready_jskit_app", "issue_text_exists", "github_auth", "github_origin"],
371
+ requiresExplicitRun: false
372
+ }),
373
+ defineStep({
374
+ buttonLabel: "Save issue details",
375
+ codex: ISSUE_DETAILS_CODEX_HANDOFF,
376
+ description: "Codex finalises with user issue details and classification; user reviews or edits final outcome; JSKIT saves the confirmed details.",
377
+ displayGroupId: "issue_details",
378
+ displayGroupLabel: "Get issue details",
379
+ id: "issue_details_gathered",
380
+ input: ISSUE_DETAILS_INPUT,
381
+ kind: "codex_output",
382
+ label: "Issue details gathered",
383
+ nextCommandTemplate: `${JSKIT_CLI_SHELL_COMMAND} session {{session_id}} step --issue-details -`,
384
+ preconditions: ["session_exists", "worktree_exists", "dependencies_installed", "ready_jskit_app", "issue_text_exists", "issue_url_exists"]
193
385
  }),
194
386
  defineStep({
195
- buttonLabel: "Execute plan",
196
- codex: codexHandoff(PLAN_OUTPUT),
197
- description: "Save the approved implementation plan, comment it on the GitHub issue, and submit it to Codex.",
387
+ buttonLabel: "Save plan",
388
+ codex: codexHandoff(PLAN_OUTPUT, {
389
+ autoInject: true,
390
+ promptActionLabel: "Get Codex to create plan",
391
+ promptIntroText: "Codex will create an implementation plan based on the issue."
392
+ }),
393
+ description: "Codex writes an implementation plan for the active cycle; cycle 001 plans from the issue, later cycles plan from user rework notes.",
198
394
  id: "plan_made",
199
395
  input: PLAN_INPUT,
200
396
  kind: "codex_output",
201
- label: "Plan execution",
202
- nextCommandTemplate: "jskit session {{session_id}} step --plan -",
203
- preconditions: ["session_exists", "issue_text_exists", "issue_url_exists", "worktree_exists"]
397
+ label: "Plan made",
398
+ nextCommandTemplate: `${JSKIT_CLI_SHELL_COMMAND} session {{session_id}} step --plan -`,
399
+ preconditions: ["session_exists", "worktree_exists", "dependencies_installed", "ready_jskit_app", "issue_text_exists", "issue_url_exists", "issue_details_exists", "issue_metadata_exists", "active_cycle_exists"]
204
400
  }),
205
401
  defineStep({
206
- buttonLabel: "Accept changes",
207
- description: "Review the worktree diff and accept the changes as ready to commit.",
208
- id: "implementation_changes_accepted",
209
- kind: "user_check",
210
- label: "Changes accepted",
211
- preconditions: ["session_exists", "worktree_exists"],
212
- utilityActions: Object.freeze([
213
- Object.freeze({
214
- id: "session_diff",
215
- kind: "diff",
216
- label: "Review changes",
217
- nextCommandTemplate: "jskit session {{session_id}} diff"
218
- })
219
- ])
402
+ buttonLabel: "Get Codex to execute plan",
403
+ codex: PLAN_EXECUTION_CODEX_HANDOFF,
404
+ description: "JSKIT sends the active cycle plan to Codex; Codex implements it; Studio advances when Codex finishes.",
405
+ id: "plan_executed",
406
+ kind: "codex_prompt",
407
+ label: "Plan executed",
408
+ preconditions: ["session_exists", "worktree_exists", "dependencies_installed", "ready_jskit_app", "issue_text_exists", "issue_url_exists", "issue_details_exists", "issue_metadata_exists", "active_cycle_exists", "plan_text_exists"]
220
409
  }),
221
410
  defineStep({
222
- buttonLabel: "Commit implementation",
223
- description: "Commit the accepted implementation changes in the session worktree.",
224
- id: "implementation_changes_committed",
225
- label: "Changes committed",
226
- preconditions: ["session_exists", "worktree_exists"]
411
+ buttonLabel: "Run Deep UI check",
412
+ codex: DEEP_UI_CHECK_CODEX_HANDOFF,
413
+ description: "JSKIT asks Codex for a focused UI quality pass when the issue affects UI, or records a skip receipt when it does not.",
414
+ id: "deep_ui_check_run",
415
+ kind: "codex_prompt",
416
+ label: "Deep UI check run",
417
+ preconditions: ["session_exists", "worktree_exists", "dependencies_installed", "ready_jskit_app", "issue_metadata_exists", "active_cycle_exists"]
227
418
  }),
228
419
  defineStep({
229
- buttonLabel: "Start review",
230
- description: "Submit the code review prompt to Codex for the committed changes.",
420
+ buttonLabel: "Run deslop",
421
+ codex: REVIEW_EXECUTION_CODEX_HANDOFF,
422
+ description: "JSKIT sends the current implementation to Codex for a review/deslop pass; Codex reports findings and applies the selected cleanup.",
423
+ displayGroupId: "review_deslop",
424
+ displayGroupLabel: "Review/deslop",
231
425
  id: "review_prompt_rendered",
232
426
  kind: "codex_prompt",
233
- label: "Review execution",
234
- preconditions: ["session_exists", "worktree_exists"]
427
+ label: "Review/deslop",
428
+ preconditions: ["session_exists", "worktree_exists", "dependencies_installed", "ready_jskit_app", "issue_metadata_exists", "active_cycle_exists", "deep_ui_check_satisfied"]
235
429
  }),
236
430
  defineStep({
237
- buttonLabel: "Accept review changes",
238
- description: "Review the post-review worktree diff and accept it as ready to commit.",
431
+ buttonLabel: "I am done",
432
+ description: "User confirms the review/deslop loop is done; JSKIT records the loop result without committing yet.",
433
+ displayGroupId: "review_deslop",
434
+ displayGroupLabel: "Review/deslop",
239
435
  id: "review_changes_accepted",
240
436
  kind: "user_check",
241
- label: "Review changes accepted",
242
- preconditions: ["session_exists", "worktree_exists"],
243
- utilityActions: Object.freeze([
244
- Object.freeze({
245
- id: "session_diff",
246
- kind: "diff",
247
- label: "Review changes",
248
- nextCommandTemplate: "jskit session {{session_id}} diff"
249
- })
250
- ])
437
+ label: "Review/deslop",
438
+ nextCommandTemplate: `${JSKIT_CLI_SHELL_COMMAND} session {{session_id}} step --review-findings-remaining false`,
439
+ preconditions: ["session_exists", "worktree_exists", "dependencies_installed", "ready_jskit_app", "issue_metadata_exists", "active_cycle_exists", "deep_ui_check_satisfied"],
440
+ submitOptions: Object.freeze({
441
+ reviewFindingsRemaining: false
442
+ })
251
443
  }),
252
444
  defineStep({
253
- buttonLabel: "Commit review changes",
254
- description: "Commit accepted review changes, or record that no review changes were needed.",
255
- id: "review_changes_committed",
256
- label: "Review changes committed",
257
- preconditions: ["session_exists", "worktree_exists"]
445
+ buttonLabel: "Run automated checks",
446
+ codex: AUTOMATED_CHECK_REPAIR_CODEX_HANDOFF,
447
+ description: "JSKIT asks Codex to run the official verification command in the worktree, fix failures, and report the final passing result.",
448
+ id: "automated_checks_run",
449
+ kind: "codex_prompt",
450
+ label: "Automated checks",
451
+ preconditions: ["session_exists", "worktree_exists", "dependencies_installed", "ready_jskit_app", "issue_metadata_exists", "active_cycle_exists", "deep_ui_check_satisfied"]
258
452
  }),
259
453
  defineStep({
260
454
  buttonLabel: "Save user check",
261
- description: "Record whether the user’s manual check passed.",
455
+ description: "User manually checks the result; JSKIT records pass or collects rework notes for another plan cycle.",
262
456
  id: "user_check_completed",
263
457
  input: USER_CHECK_INPUT,
264
458
  kind: "user_check",
265
459
  label: "User check",
266
- nextCommandTemplate: "jskit session {{session_id}} step --user-check passed",
267
- preconditions: ["session_exists"]
460
+ nextCommandTemplate: `${JSKIT_CLI_SHELL_COMMAND} session {{session_id}} step --user-check passed`,
461
+ preconditions: ["session_exists", "worktree_exists", "dependencies_installed", "ready_jskit_app", "issue_metadata_exists", "active_cycle_exists", "automated_checks_passed", "deep_ui_check_satisfied"],
462
+ utilityActions: Object.freeze([
463
+ Object.freeze({
464
+ id: "session_app_test",
465
+ kind: "app_test",
466
+ label: "Test app"
467
+ })
468
+ ])
268
469
  }),
269
470
  defineStep({
270
- buttonLabel: "Run verification",
271
- description: "Run the project verification command in the session worktree.",
272
- id: "doctor_run",
273
- label: "Verification run",
274
- preconditions: ["session_exists", "worktree_exists"]
471
+ buttonLabel: "Commit accepted changes",
472
+ description: "JSKIT commits the user-accepted session changes in the session worktree.",
473
+ id: "changes_committed",
474
+ label: "Changes committed",
475
+ preconditions: ["session_exists", "worktree_exists", "dependencies_installed", "ready_jskit_app", "issue_metadata_exists", "issue_url_exists", "github_auth", "active_cycle_exists", "automated_checks_passed", "deep_ui_check_satisfied", "active_cycle_user_check_passed"]
476
+ }),
477
+ defineStep({
478
+ buttonLabel: "Update blueprint",
479
+ codex: BLUEPRINT_CODEX_HANDOFF,
480
+ description: "JSKIT asks Codex to update durable app memory from the accepted work; Codex edits .jskit/APP_BLUEPRINT.md; JSKIT records and commits the update.",
481
+ id: "blueprint_updated",
482
+ kind: "codex_prompt",
483
+ label: "Blueprint updated",
484
+ preconditions: ["session_exists", "worktree_exists", "dependencies_installed", "ready_jskit_app", "issue_metadata_exists", "active_cycle_exists", "automated_checks_passed", "deep_ui_check_satisfied", "active_cycle_user_check_passed", "accepted_changes_committed"]
485
+ }),
486
+ defineStep({
487
+ buttonLabel: "Create final report",
488
+ description: "JSKIT creates the deterministic final session report and comments it on the GitHub issue.",
489
+ id: "final_report_created",
490
+ label: "Final report created",
491
+ preconditions: ["session_exists", "worktree_exists", "dependencies_installed", "ready_jskit_app", "issue_metadata_exists", "active_cycle_exists", "automated_checks_passed", "deep_ui_check_satisfied", "active_cycle_user_check_passed", "accepted_changes_committed", "blueprint_update_satisfied"]
275
492
  }),
276
493
  defineStep({
277
494
  buttonLabel: "Push branch and create PR",
278
- description: "Push the session branch to origin and create a GitHub pull request.",
495
+ description: "JSKIT pushes the session branch to origin, creates or reuses the GitHub pull request, and records the PR URL.",
279
496
  id: "pr_created",
280
497
  label: "Branch pushed, PR created",
281
- preconditions: ["session_exists", "worktree_exists"]
498
+ preconditions: ["session_exists", "worktree_exists", "dependencies_installed", "ready_jskit_app", "issue_metadata_exists", "active_cycle_exists", "automated_checks_passed", "deep_ui_check_satisfied", "active_cycle_user_check_passed", "accepted_changes_committed", "blueprint_update_satisfied", "final_report_exists"]
282
499
  }),
283
500
  defineStep({
284
- buttonLabel: "Merge PR and remove worktree",
285
- description: "Merge the pull request, close the GitHub issue, and remove the session worktree.",
286
- id: "pr_merged",
287
- label: "PR merged, worktree removed",
288
- preconditions: ["session_exists", "pr_url_exists", "worktree_exists"]
501
+ buttonLabel: "Merge PR",
502
+ description: "User chooses whether JSKIT merges the pull request or finishes without merge; JSKIT then removes the session worktree.",
503
+ id: "pr_finalized",
504
+ label: "PR finalized, worktree removed",
505
+ preconditions: ["session_exists", "pr_url_exists", "worktree_exists"],
506
+ requiresExplicitRun: true,
507
+ submitOptions: Object.freeze({
508
+ mergePr: true
509
+ })
289
510
  }),
290
511
  defineStep({
291
512
  buttonLabel: "Finish session",
292
- description: "Write the final receipt and archive the completed session.",
513
+ description: "JSKIT writes the final receipt and archives the completed session.",
293
514
  id: "session_finished",
294
515
  label: "Session finished",
295
516
  preconditions: ["session_exists"]
@@ -299,6 +520,15 @@ const STEP_DEFINITIONS = Object.freeze([
299
520
  const STEP_IDS = Object.freeze(STEP_DEFINITIONS.map((step) => step.id));
300
521
  const STEP_LABEL_BY_ID = Object.freeze(Object.fromEntries(STEP_DEFINITIONS.map((step) => [step.id, step.label])));
301
522
  const STEP_DEFINITION_BY_ID = Object.freeze(Object.fromEntries(STEP_DEFINITIONS.map((step) => [step.id, step])));
523
+ const CYCLE_STEP_IDS = Object.freeze([
524
+ "plan_made",
525
+ "plan_executed",
526
+ "deep_ui_check_run",
527
+ "review_prompt_rendered",
528
+ "review_changes_accepted",
529
+ "automated_checks_run",
530
+ "user_check_completed"
531
+ ]);
302
532
  const STEP_PRECONDITION_NAMES = Object.freeze(Object.fromEntries(
303
533
  STEP_DEFINITIONS
304
534
  .filter((step) => step.id !== "session_created")
@@ -309,12 +539,21 @@ export {
309
539
  PROMPT_DIRECTORY,
310
540
  SESSION_ID_PATTERN,
311
541
  SESSION_STATUS,
542
+ SESSION_WORKFLOW_VERSION,
543
+ REVIEW_PASS_LIMIT,
544
+ CYCLE_STEP_IDS,
312
545
  STEP_DEFINITION_BY_ID,
313
546
  STEP_DEFINITIONS,
314
547
  STEP_IDS,
315
548
  STEP_LABEL_BY_ID,
316
549
  STEP_PRECONDITION_NAMES,
550
+ ISSUE_DETAILS_CODEX_HANDOFF,
317
551
  PLAN_EXECUTION_CODEX_HANDOFF,
318
552
  REVIEW_EXECUTION_CODEX_HANDOFF,
553
+ DEEP_UI_CHECK_CODEX_HANDOFF,
554
+ AUTOMATED_CHECK_REPAIR_CODEX_HANDOFF,
555
+ BLUEPRINT_CODEX_HANDOFF,
556
+ JSKIT_CLI_SHELL_COMMAND,
557
+ JSKIT_CLI_SHELL_RULE,
319
558
  SESSION_STATE_RELATIVE_PATH
320
559
  };