@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
@@ -6,6 +6,7 @@ import {
6
6
  import { constants as fsConstants } from "node:fs";
7
7
  import path from "node:path";
8
8
  import {
9
+ JSKIT_CLI_SHELL_COMMAND,
9
10
  SESSION_STATE_RELATIVE_PATH
10
11
  } from "./constants.js";
11
12
  import {
@@ -24,6 +25,13 @@ import {
24
25
  import {
25
26
  hasWorktree
26
27
  } from "./worktrees.js";
28
+ import {
29
+ inspectReadyJskitAppRoot
30
+ } from "./appReadiness.js";
31
+
32
+ function jskitCommand(args = "") {
33
+ return `${JSKIT_CLI_SHELL_COMMAND}${args ? ` ${args}` : ""}`;
34
+ }
27
35
 
28
36
  async function assertTargetRootWritable(targetRoot) {
29
37
  try {
@@ -228,7 +236,7 @@ async function assertSessionExists(paths) {
228
236
  error: createError({
229
237
  code: "session_missing",
230
238
  message: `Session does not exist: ${paths.sessionId}`,
231
- repairCommand: "jskit session create"
239
+ repairCommand: jskitCommand("session create")
232
240
  }),
233
241
  precondition: createPrecondition({
234
242
  id: "session_exists",
@@ -238,6 +246,255 @@ async function assertSessionExists(paths) {
238
246
  };
239
247
  }
240
248
 
249
+ async function pathExists(filePath) {
250
+ try {
251
+ await access(filePath, fsConstants.F_OK);
252
+ return true;
253
+ } catch {
254
+ return false;
255
+ }
256
+ }
257
+
258
+ async function assertDependenciesInstalled(paths) {
259
+ if (await pathExists(path.join(paths.sessionRoot, "steps", "dependencies_installed"))) {
260
+ return {
261
+ ok: true,
262
+ precondition: createPrecondition({
263
+ id: "dependencies_installed",
264
+ ok: true,
265
+ message: "Session worktree dependencies have been installed."
266
+ })
267
+ };
268
+ }
269
+ return {
270
+ ok: false,
271
+ error: createError({
272
+ code: "dependencies_not_installed",
273
+ message: "Cannot start issue work until dependencies are installed in the session worktree.",
274
+ repairCommand: jskitCommand(`session ${paths.sessionId} step`)
275
+ }),
276
+ precondition: createPrecondition({
277
+ id: "dependencies_installed",
278
+ ok: false,
279
+ message: "Session worktree dependencies have been installed."
280
+ })
281
+ };
282
+ }
283
+
284
+ async function assertReadyJskitApp(paths) {
285
+ const root = paths.worktree || paths.targetRoot;
286
+ const readiness = await inspectReadyJskitAppRoot(root);
287
+ if (readiness.ok) {
288
+ return {
289
+ ok: true,
290
+ precondition: createPrecondition({
291
+ id: "ready_jskit_app",
292
+ ok: true,
293
+ message: "Session worktree has the required JSKIT app markers."
294
+ })
295
+ };
296
+ }
297
+ return {
298
+ ok: false,
299
+ error: createError({
300
+ code: "app_setup_required",
301
+ message: `Issue sessions require a ready JSKIT app. Missing: ${readiness.missing.join(", ")}.`,
302
+ repairCommand: "Run the app setup flow before starting issue work."
303
+ }),
304
+ precondition: createPrecondition({
305
+ id: "ready_jskit_app",
306
+ ok: false,
307
+ message: "Session worktree has the required JSKIT app markers."
308
+ })
309
+ };
310
+ }
311
+
312
+ async function assertActiveCycleExists(paths) {
313
+ const activeCycle = await readTrimmedFile(path.join(paths.sessionRoot, "active_cycle"));
314
+ if (/^\d+$/u.test(activeCycle)) {
315
+ return {
316
+ ok: true,
317
+ precondition: createPrecondition({
318
+ id: "active_cycle_exists",
319
+ ok: true,
320
+ message: "Active cycle marker exists."
321
+ })
322
+ };
323
+ }
324
+ return {
325
+ ok: false,
326
+ error: createError({
327
+ code: "active_cycle_missing",
328
+ message: "Session active_cycle is missing or invalid."
329
+ }),
330
+ precondition: createPrecondition({
331
+ id: "active_cycle_exists",
332
+ ok: false,
333
+ message: "Active cycle marker exists."
334
+ })
335
+ };
336
+ }
337
+
338
+ async function assertActiveCycleUserCheckPassed(paths) {
339
+ const activeCycle = await readTrimmedFile(path.join(paths.sessionRoot, "active_cycle"));
340
+ const receiptPath = path.join(paths.sessionRoot, "steps", `cycle_${activeCycle}`, "user_check_completed");
341
+ if (await pathExists(receiptPath)) {
342
+ return {
343
+ ok: true,
344
+ precondition: createPrecondition({
345
+ id: "active_cycle_user_check_passed",
346
+ ok: true,
347
+ message: "The active cycle user check has passed."
348
+ })
349
+ };
350
+ }
351
+ return {
352
+ ok: false,
353
+ error: createError({
354
+ code: "user_check_not_passed",
355
+ message: "Finalization cannot continue until the active cycle user check has passed.",
356
+ repairCommand: jskitCommand(`session ${paths.sessionId} step --user-check passed`)
357
+ }),
358
+ precondition: createPrecondition({
359
+ id: "active_cycle_user_check_passed",
360
+ ok: false,
361
+ message: "The active cycle user check has passed."
362
+ })
363
+ };
364
+ }
365
+
366
+ async function assertAcceptedChangesCommitted(paths) {
367
+ const receiptPath = path.join(paths.sessionRoot, "steps", "changes_committed");
368
+ if (await pathExists(receiptPath)) {
369
+ return {
370
+ ok: true,
371
+ precondition: createPrecondition({
372
+ id: "accepted_changes_committed",
373
+ ok: true,
374
+ message: "Accepted changes have been committed."
375
+ })
376
+ };
377
+ }
378
+ return {
379
+ ok: false,
380
+ error: createError({
381
+ code: "accepted_changes_not_committed",
382
+ message: "Accepted changes must be committed before app memory and finalization steps continue.",
383
+ repairCommand: jskitCommand(`session ${paths.sessionId} step`)
384
+ }),
385
+ precondition: createPrecondition({
386
+ id: "accepted_changes_committed",
387
+ ok: false,
388
+ message: "Accepted changes have been committed."
389
+ })
390
+ };
391
+ }
392
+
393
+ async function assertActiveCycleStepReceipt(paths, {
394
+ code,
395
+ id,
396
+ message,
397
+ stepId
398
+ }) {
399
+ const activeCycle = await readTrimmedFile(path.join(paths.sessionRoot, "active_cycle"));
400
+ const receiptPath = path.join(paths.sessionRoot, "steps", `cycle_${activeCycle}`, stepId);
401
+ if (await pathExists(receiptPath)) {
402
+ return {
403
+ ok: true,
404
+ precondition: createPrecondition({
405
+ id,
406
+ ok: true,
407
+ message
408
+ })
409
+ };
410
+ }
411
+ return {
412
+ ok: false,
413
+ error: createError({
414
+ code,
415
+ message,
416
+ repairCommand: jskitCommand(`session ${paths.sessionId} step`)
417
+ }),
418
+ precondition: createPrecondition({
419
+ id,
420
+ ok: false,
421
+ message
422
+ })
423
+ };
424
+ }
425
+
426
+ async function assertAutomatedChecksPassed(paths) {
427
+ return assertActiveCycleStepReceipt(paths, {
428
+ code: "automated_checks_not_passed",
429
+ id: "automated_checks_passed",
430
+ message: "Automated checks have passed.",
431
+ stepId: "automated_checks_run"
432
+ });
433
+ }
434
+
435
+ async function assertDeepUiCheckSatisfied(paths) {
436
+ return assertActiveCycleStepReceipt(paths, {
437
+ code: "deep_ui_check_not_satisfied",
438
+ id: "deep_ui_check_satisfied",
439
+ message: "Deep UI check is satisfied.",
440
+ stepId: "deep_ui_check_run"
441
+ });
442
+ }
443
+
444
+ async function assertIssueMetadataExists(paths) {
445
+ const source = await readTextIfExists(path.join(paths.sessionRoot, "issue_metadata.json"));
446
+ if (!source) {
447
+ return {
448
+ ok: false,
449
+ error: createError({
450
+ code: "issue_metadata_missing",
451
+ message: "Cannot continue before issue_metadata.json records the issue category and UI impact.",
452
+ repairCommand: jskitCommand(`session ${paths.sessionId} step --issue-details -`)
453
+ }),
454
+ precondition: createPrecondition({
455
+ id: "issue_metadata_exists",
456
+ ok: false,
457
+ message: "Issue metadata records issue category and UI impact."
458
+ })
459
+ };
460
+ }
461
+
462
+ let metadata = null;
463
+ try {
464
+ metadata = JSON.parse(source);
465
+ } catch {
466
+ metadata = null;
467
+ }
468
+ const issueCategory = String(metadata?.issueCategory || "").trim().toLowerCase();
469
+ const uiImpact = String(metadata?.uiImpact || "").trim().toLowerCase();
470
+ const validIssueCategories = new Set(["client", "server", "client_server", "tooling", "unknown"]);
471
+ const validUiImpacts = new Set(["none", "possible", "definite", "unknown"]);
472
+ if (validIssueCategories.has(issueCategory) && validUiImpacts.has(uiImpact)) {
473
+ return {
474
+ ok: true,
475
+ precondition: createPrecondition({
476
+ id: "issue_metadata_exists",
477
+ ok: true,
478
+ message: "Issue metadata records issue category and UI impact."
479
+ })
480
+ };
481
+ }
482
+
483
+ return {
484
+ ok: false,
485
+ error: createError({
486
+ code: "issue_metadata_invalid",
487
+ message: "issue_metadata.json must include a valid issueCategory and uiImpact.",
488
+ repairCommand: jskitCommand(`session ${paths.sessionId} step --issue-details -`)
489
+ }),
490
+ precondition: createPrecondition({
491
+ id: "issue_metadata_exists",
492
+ ok: false,
493
+ message: "Issue metadata records issue category and UI impact."
494
+ })
495
+ };
496
+ }
497
+
241
498
  async function assertIssueTextExists(paths) {
242
499
  const issueText = await readTrimmedFile(path.join(paths.sessionRoot, "issue.md"));
243
500
  if (issueText) {
@@ -255,7 +512,7 @@ async function assertIssueTextExists(paths) {
255
512
  error: createError({
256
513
  code: "issue_text_missing",
257
514
  message: "Cannot create a GitHub issue before issue.md exists.",
258
- repairCommand: `jskit session ${paths.sessionId} step --issue -`
515
+ repairCommand: jskitCommand(`session ${paths.sessionId} step --issue -`)
259
516
  }),
260
517
  precondition: createPrecondition({
261
518
  id: "issue_text_exists",
@@ -282,7 +539,7 @@ async function assertIssueUrlExists(paths) {
282
539
  error: createError({
283
540
  code: "issue_url_missing",
284
541
  message: "Cannot create a plan before the GitHub issue exists.",
285
- repairCommand: `jskit session ${paths.sessionId} step`
542
+ repairCommand: jskitCommand(`session ${paths.sessionId} step`)
286
543
  }),
287
544
  precondition: createPrecondition({
288
545
  id: "issue_url_exists",
@@ -292,6 +549,114 @@ async function assertIssueUrlExists(paths) {
292
549
  };
293
550
  }
294
551
 
552
+ async function assertPlanTextExists(paths) {
553
+ const activeCycle = await readTrimmedFile(path.join(paths.sessionRoot, "active_cycle"));
554
+ const planPath = path.join(paths.sessionRoot, "cycles", `cycle_${activeCycle || "001"}`, "plan.md");
555
+ const planText = await readTrimmedFile(planPath);
556
+ if (planText) {
557
+ return {
558
+ ok: true,
559
+ precondition: createPrecondition({
560
+ id: "plan_text_exists",
561
+ ok: true,
562
+ message: "Plan text exists."
563
+ })
564
+ };
565
+ }
566
+ return {
567
+ ok: false,
568
+ error: createError({
569
+ code: "plan_text_missing",
570
+ message: "Cannot execute a plan before the active cycle plan exists.",
571
+ repairCommand: jskitCommand(`session ${paths.sessionId} step --plan -`)
572
+ }),
573
+ precondition: createPrecondition({
574
+ id: "plan_text_exists",
575
+ ok: false,
576
+ message: "Plan text exists."
577
+ })
578
+ };
579
+ }
580
+
581
+ async function assertIssueDetailsExists(paths) {
582
+ const issueDetails = await readTrimmedFile(path.join(paths.sessionRoot, "issue_details.md"));
583
+ if (issueDetails) {
584
+ return {
585
+ ok: true,
586
+ precondition: createPrecondition({
587
+ id: "issue_details_exists",
588
+ ok: true,
589
+ message: "Issue details exist."
590
+ })
591
+ };
592
+ }
593
+ return {
594
+ ok: false,
595
+ error: createError({
596
+ code: "issue_details_missing",
597
+ message: "Cannot create a plan before issue_details.md exists.",
598
+ repairCommand: jskitCommand(`session ${paths.sessionId} step --issue-details -`)
599
+ }),
600
+ precondition: createPrecondition({
601
+ id: "issue_details_exists",
602
+ ok: false,
603
+ message: "Issue details exist."
604
+ })
605
+ };
606
+ }
607
+
608
+ async function assertBlueprintUpdateSatisfied(paths) {
609
+ if (await pathExists(path.join(paths.sessionRoot, "steps", "blueprint_updated"))) {
610
+ return {
611
+ ok: true,
612
+ precondition: createPrecondition({
613
+ id: "blueprint_update_satisfied",
614
+ ok: true,
615
+ message: "Blueprint update step is complete."
616
+ })
617
+ };
618
+ }
619
+ return {
620
+ ok: false,
621
+ error: createError({
622
+ code: "blueprint_update_missing",
623
+ message: "Cannot continue before the blueprint update step is complete.",
624
+ repairCommand: jskitCommand(`session ${paths.sessionId} step`)
625
+ }),
626
+ precondition: createPrecondition({
627
+ id: "blueprint_update_satisfied",
628
+ ok: false,
629
+ message: "Blueprint update step is complete."
630
+ })
631
+ };
632
+ }
633
+
634
+ async function assertFinalReportExists(paths) {
635
+ if (await pathExists(path.join(paths.sessionRoot, "final_report.md"))) {
636
+ return {
637
+ ok: true,
638
+ precondition: createPrecondition({
639
+ id: "final_report_exists",
640
+ ok: true,
641
+ message: "Final report exists."
642
+ })
643
+ };
644
+ }
645
+ return {
646
+ ok: false,
647
+ error: createError({
648
+ code: "final_report_missing",
649
+ message: "Cannot publish the PR before final_report.md exists.",
650
+ repairCommand: jskitCommand(`session ${paths.sessionId} step`)
651
+ }),
652
+ precondition: createPrecondition({
653
+ id: "final_report_exists",
654
+ ok: false,
655
+ message: "Final report exists."
656
+ })
657
+ };
658
+ }
659
+
295
660
  async function assertWorktreeExists(paths) {
296
661
  if (await hasWorktree(paths)) {
297
662
  return {
@@ -308,7 +673,7 @@ async function assertWorktreeExists(paths) {
308
673
  error: createError({
309
674
  code: "worktree_missing",
310
675
  message: "Session worktree does not exist.",
311
- repairCommand: `jskit session ${paths.sessionId} step`
676
+ repairCommand: jskitCommand(`session ${paths.sessionId} step`)
312
677
  }),
313
678
  precondition: createPrecondition({
314
679
  id: "worktree_exists",
@@ -335,7 +700,7 @@ async function assertPrUrlExists(paths) {
335
700
  error: createError({
336
701
  code: "pr_url_missing",
337
702
  message: "Cannot merge before pr_url exists.",
338
- repairCommand: `jskit session ${paths.sessionId} step`
703
+ repairCommand: jskitCommand(`session ${paths.sessionId} step`)
339
704
  }),
340
705
  precondition: createPrecondition({
341
706
  id: "pr_url_exists",
@@ -347,13 +712,25 @@ async function assertPrUrlExists(paths) {
347
712
 
348
713
  export {
349
714
  applyPreconditions,
715
+ assertAcceptedChangesCommitted,
716
+ assertActiveCycleExists,
717
+ assertActiveCycleUserCheckPassed,
718
+ assertBlueprintUpdateSatisfied,
719
+ assertDeepUiCheckSatisfied,
720
+ assertDependenciesInstalled,
721
+ assertFinalReportExists,
350
722
  assertGhAuth,
351
723
  assertGitCurrentBranch,
352
724
  assertGitRepository,
353
725
  assertGithubOrigin,
726
+ assertIssueMetadataExists,
354
727
  assertIssueTextExists,
355
728
  assertIssueUrlExists,
729
+ assertAutomatedChecksPassed,
730
+ assertIssueDetailsExists,
731
+ assertPlanTextExists,
356
732
  assertPrUrlExists,
733
+ assertReadyJskitApp,
357
734
  assertSessionExists,
358
735
  assertTargetRootWritable,
359
736
  assertWorktreeExists,
@@ -1,5 +1,6 @@
1
1
  import path from "node:path";
2
2
  import {
3
+ JSKIT_CLI_SHELL_RULE,
3
4
  PROMPT_DIRECTORY,
4
5
  SESSION_STATE_RELATIVE_PATH
5
6
  } from "./constants.js";
@@ -24,9 +25,20 @@ function renderTemplate(source, values = {}) {
24
25
  });
25
26
  }
26
27
 
28
+ function withShellCommandRule(template) {
29
+ const body = String(template || "").trim();
30
+ if (!body) {
31
+ return JSKIT_CLI_SHELL_RULE;
32
+ }
33
+ if (body.includes("When running JSKIT CLI commands from the shell")) {
34
+ return body;
35
+ }
36
+ return `${JSKIT_CLI_SHELL_RULE}\n\n---\n\n${body}`;
37
+ }
38
+
27
39
  async function renderPrompt(paths, templateName, values = {}) {
28
40
  const template = await readPromptTemplate(paths.targetRoot, templateName);
29
- return renderTemplate(template, {
41
+ return renderTemplate(withShellCommandRule(template), {
30
42
  branch: paths.branch,
31
43
  session_id: paths.sessionId,
32
44
  worktree: paths.worktree,
@@ -37,5 +49,6 @@ async function renderPrompt(paths, templateName, values = {}) {
37
49
  export {
38
50
  readPromptTemplate,
39
51
  renderPrompt,
40
- renderTemplate
52
+ renderTemplate,
53
+ withShellCommandRule
41
54
  };
@@ -0,0 +1,42 @@
1
+ Run automated checks for JSKIT session {{session_id}}.
2
+
3
+ Worktree:
4
+
5
+ {{worktree}}
6
+
7
+ Command:
8
+
9
+ {{check_command}}
10
+
11
+ Run the command in the session worktree. If it fails, diagnose the root cause, fix the worktree, and rerun the command. Keep repeating until the command passes or until a real blocker prevents progress.
12
+
13
+ Rules:
14
+
15
+ - Fix the underlying cause. Do not remove checks, weaken verification, or hide failures to make the command pass.
16
+ - Prefer JSKIT-owned helpers, generators, package seams, and documented commands over local hacks.
17
+ - Use `npx --no-install jskit ...` for JSKIT CLI commands you run directly from the shell.
18
+ - Keep fixes scoped to the current issue, issue details, and active plan.
19
+ - Do not create commits, branches, issues, pull requests, merges, or worktree cleanup. JSKIT session owns those steps.
20
+
21
+ When finished, report:
22
+
23
+ - root cause
24
+ - files changed
25
+ - final check command and result
26
+ - anything still unverified
27
+
28
+ If the repair records a meaningful verification decision, tradeoff, missing coverage, or root-cause explanation future steps should know, include concise entries with reasons in this exact marker block:
29
+
30
+ ```text
31
+ [agent_decisions]
32
+ <verification or repair decisions, or "No new decisions.">
33
+ [/agent_decisions]
34
+ ```
35
+
36
+ At the very end, include this completion block so Studio knows the step is complete:
37
+
38
+ [jskit_step_result]
39
+ status: complete
40
+ step: automated_checks_run
41
+ summary: Short summary of the final check command, result, and any repairs.
42
+ [/jskit_step_result]
@@ -0,0 +1,53 @@
1
+ Deep UI quality check for JSKIT session {{session_id}}.
2
+
3
+ Phase: {{phase}}
4
+ GitHub issue: {{issue_url}}
5
+ Issue number: {{issue_number}}
6
+ Issue title: {{issue_title}}
7
+ Issue body file: {{issue_file}}
8
+ Issue details file (`issue_details.md`): {{issue_details_file}}
9
+ Plan file: {{plan_file}}
10
+ UI impact: {{ui_impact}}
11
+ Worktree: {{worktree}}
12
+
13
+ Changed files since the session base:
14
+
15
+ {{changed_files}}
16
+
17
+ Run a focused UI quality pass for the current worktree. If this is not UI-impacting after inspection, say exactly why and do not edit files. If the issue touches UI, inspect the changed routes, views, components, placements, layouts, and styles.
18
+
19
+ Check:
20
+
21
+ - Material Design quality.
22
+ - Vuetify best practices.
23
+ - visual hierarchy and density.
24
+ - spacing and alignment.
25
+ - responsive behavior on mobile, tablet, and desktop.
26
+ - loading, empty, error, disabled, and success states where relevant.
27
+ - accessibility basics.
28
+ - route and navigation coherence.
29
+ - consistency with the existing app style.
30
+
31
+ When clear scoped UI issues exist, fix them in the worktree. Keep fixes limited to the issue, confirmed issue details, and approved plan.
32
+
33
+ Use Playwright for a meaningful route check when possible. If login is required, use a development-only auth bootstrap path. When possible, record UI verification with:
34
+
35
+ `npx --no-install jskit app verify-ui --command "<playwright command>" --feature "<label>" --auth-mode <mode>`
36
+
37
+ Do not create commits, branches, issues, pull requests, merges, or worktree cleanup. JSKIT session owns those steps.
38
+
39
+ If this pass makes UI fixes, intentionally skips UI work after inspection, changes a design direction, or leaves a meaningful UI verification gap, include concise decision entries with reasons in this exact marker block:
40
+
41
+ ```text
42
+ [agent_decisions]
43
+ <Deep UI decisions or "No new decisions.">
44
+ [/agent_decisions]
45
+ ```
46
+
47
+ At the very end, include this completion block so Studio knows the step is complete:
48
+
49
+ [jskit_step_result]
50
+ status: complete
51
+ step: deep_ui_check_run
52
+ summary: Short summary of UI findings, fixes, verification, or why no UI work applied.
53
+ [/jskit_step_result]
@@ -4,24 +4,35 @@ GitHub issue: {{issue_url}}
4
4
  Issue number: {{issue_number}}
5
5
  Issue title: {{issue_title}}
6
6
  Issue body file: {{issue_file}}
7
+ Issue details file (`issue_details.md`): {{issue_details_file}}
7
8
  Plan file: {{plan_file}}
8
9
  Worktree: {{worktree}}
9
10
 
10
- Implement the plan in the session worktree. Keep the change scoped to the issue and approved plan.
11
+ Confirmed issue details:
12
+
13
+ {{issue_details_text}}
14
+
15
+ Approved plan:
16
+
17
+ {{plan_text}}
18
+
19
+ Implement the plan in the session worktree. Keep the change scoped to the issue, confirmed issue details, and approved plan.
11
20
 
12
21
  Implementation rules:
13
22
 
14
- - Inspect the current app before editing. Do not assume a JSKIT app shape without checking files.
15
- - Prefer existing JSKIT helpers, package runtime seams, generated scaffolds, and documented generators over new local helpers.
16
- - If the plan calls for a generator or package install, use the planned `jskit` command unless inspection proves it does not apply. If you skip a generator, explain the exact gap.
17
- - For non-CRUD route pages, use `jskit generate ui-generator page ...` when it fits instead of hand-writing both route files and placement entries.
23
+ - Inspect the current app before editing. App setup has already passed; if required JSKIT app files are missing, report setup failure rather than inventing recovery work.
24
+ - Follow both `{{issue_details_file}}` and `{{plan_file}}`. If they disagree, ask for clarification before changing files.
25
+ - Read `.jskit/helper-map.md` when it exists before creating helpers, composables, service functions, maps, or package glue.
26
+ - Prefer existing JSKIT helpers, app-local helpers, package runtime seams, generated scaffolds, and documented generators over new local helpers.
27
+ - If the plan calls for a generator or package install, use the planned `npx --no-install jskit` command unless inspection proves it does not apply. If you skip a generator, explain the exact gap.
28
+ - For non-CRUD route pages, use `npx --no-install jskit generate ui-generator page ...` when it fits instead of hand-writing both route files and placement entries.
18
29
  - For CRUD work, scaffold the server side first with `crud-server-generator` before CRUD UI or CRUD route work.
19
30
  - Do not hand-write a separate CRUD migration for a table owned by `crud-server-generator`.
20
31
  - Do not hand-build CRUD endpoints or page trees before the server CRUD package and shared resource file exist.
21
32
  - Keep direct knex exceptional and minimal. Prefer internal json-rest-api seams outside generated CRUD packages and explicit weird-custom feature lanes.
22
33
  - Keep runtime, UI, and data concerns separated.
23
34
  - Avoid accidental scope expansion.
24
- - Do not create old workflow files such as `.jskit/WORKBOARD.md`; the session files and receipts are the workflow record.
35
+ - Do not create `.jskit/WORKBOARD.md`; the session files and receipts are the workflow record.
25
36
  - If user-facing UI changes, bring the screen to Material Design and Vuetify quality before calling it done. Include coherent responsive layout, loading, empty, error, disabled, and success states where relevant.
26
37
  - If verification needs login, use the app's local development auth bootstrap path rather than a live external auth login.
27
38
 
@@ -29,7 +40,22 @@ After making changes:
29
40
 
30
41
  - Review for repeated code, unnecessary helpers, fragmented functions, placeholder work, missing states, broken route wiring, ownership mistakes, and weak JSKIT reuse.
31
42
  - Run the smallest relevant checks you can run safely in the worktree.
32
- - For changed user-facing UI, run or clearly identify the Playwright verification path. When possible, record UI verification with `jskit app verify-ui --command "<playwright command>" --feature "<label>" --auth-mode <mode>`.
43
+ - For changed user-facing UI, run or clearly identify the Playwright verification path. When possible, record UI verification with `npx --no-install jskit app verify-ui --command "<playwright command>" --feature "<label>" --auth-mode <mode>`.
33
44
  - Summarize changed files and checks run.
45
+ - If implementation deviated from the approved plan, generator choices, package ownership, helper reuse, UI verification path, or data ownership, include concise decision entries with reasons in this exact marker block:
46
+
47
+ ```text
48
+ [agent_decisions]
49
+ <implementation decisions or "No new decisions.">
50
+ [/agent_decisions]
51
+ ```
34
52
 
35
53
  Do not create commits, branches, issues, pull requests, merges, or worktree cleanup yourself. JSKIT session will handle those steps.
54
+
55
+ At the very end, include this completion block so Studio knows the step is complete:
56
+
57
+ [jskit_step_result]
58
+ status: complete
59
+ step: plan_executed
60
+ summary: Short summary of what changed and what was checked.
61
+ [/jskit_step_result]
@@ -1,8 +1,10 @@
1
1
  Codex thread id: {{codex_thread_id}}
2
2
  Issue session status: finished
3
3
  PR: {{pr_url}}
4
+ PR outcome: {{pr_outcome}}
5
+ Outcome reason: {{pr_outcome_reason}}
4
6
  Local transcript: {{transcript_log}}
5
7
 
6
8
  Summary:
7
9
 
8
- Session {{session_id}} finished and merged.
10
+ Session {{session_id}} finished with PR outcome `{{pr_outcome}}`.