@prestyj/cli 5.29.1 → 5.30.0

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 (91) hide show
  1. package/assets/skills/compliance-guard/references/us.md +1 -1
  2. package/assets/skills/refactoring/SKILL.md +3 -1
  3. package/dist/app-error.d.ts +21 -0
  4. package/dist/app-error.js +39 -0
  5. package/dist/app-error.js.map +1 -0
  6. package/dist/app-sidecar.js +39 -35
  7. package/dist/app-sidecar.js.map +1 -1
  8. package/dist/cli.js +4 -0
  9. package/dist/cli.js.map +1 -1
  10. package/dist/core/agent-session.d.ts +2 -2
  11. package/dist/core/agent-session.js +11 -2
  12. package/dist/core/agent-session.js.map +1 -1
  13. package/dist/core/checklist-detection.d.ts +11 -0
  14. package/dist/core/checklist-detection.js +238 -0
  15. package/dist/core/checklist-detection.js.map +1 -0
  16. package/dist/core/checklist-items.d.ts +180 -0
  17. package/dist/core/checklist-items.js +204 -0
  18. package/dist/core/checklist-items.js.map +1 -0
  19. package/dist/core/checklist-prompt.d.ts +3 -0
  20. package/dist/core/checklist-prompt.js +34 -0
  21. package/dist/core/checklist-prompt.js.map +1 -0
  22. package/dist/core/checklist-snapshot.d.ts +13 -0
  23. package/dist/core/checklist-snapshot.js +29 -0
  24. package/dist/core/checklist-snapshot.js.map +1 -0
  25. package/dist/core/checklist-store.d.ts +59 -0
  26. package/dist/core/checklist-store.js +242 -0
  27. package/dist/core/checklist-store.js.map +1 -0
  28. package/dist/core/lsp/client.d.ts +4 -0
  29. package/dist/core/lsp/client.js +71 -3
  30. package/dist/core/lsp/client.js.map +1 -1
  31. package/dist/core/lsp/manager.d.ts +1 -0
  32. package/dist/core/lsp/manager.js +9 -3
  33. package/dist/core/lsp/manager.js.map +1 -1
  34. package/dist/core/lsp/project-root.d.ts +9 -0
  35. package/dist/core/lsp/project-root.js +75 -0
  36. package/dist/core/lsp/project-root.js.map +1 -0
  37. package/dist/core/lsp/reference-project.d.ts +6 -0
  38. package/dist/core/lsp/reference-project.js +110 -0
  39. package/dist/core/lsp/reference-project.js.map +1 -0
  40. package/dist/core/lsp/servers.js +1 -0
  41. package/dist/core/lsp/servers.js.map +1 -1
  42. package/dist/core/prompt-commands.js +95 -0
  43. package/dist/core/prompt-commands.js.map +1 -1
  44. package/dist/core/subagent-manager.d.ts +2 -1
  45. package/dist/core/subagent-manager.js +8 -5
  46. package/dist/core/subagent-manager.js.map +1 -1
  47. package/dist/modes/acp-mode.d.ts +2 -1
  48. package/dist/modes/acp-mode.js +4 -1
  49. package/dist/modes/acp-mode.js.map +1 -1
  50. package/dist/modes/subagent-worker-mode.d.ts +2 -0
  51. package/dist/modes/subagent-worker-mode.js +1 -3
  52. package/dist/modes/subagent-worker-mode.js.map +1 -1
  53. package/dist/system-prompt.js +4 -4
  54. package/dist/tools/bash.d.ts +4 -1
  55. package/dist/tools/bash.js +32 -7
  56. package/dist/tools/bash.js.map +1 -1
  57. package/dist/tools/checklist.d.ts +56 -0
  58. package/dist/tools/checklist.js +178 -0
  59. package/dist/tools/checklist.js.map +1 -0
  60. package/dist/tools/code-nav.d.ts +1 -1
  61. package/dist/tools/code-nav.js +3 -2
  62. package/dist/tools/code-nav.js.map +1 -1
  63. package/dist/tools/exit-plan.d.ts +2 -2
  64. package/dist/tools/exit-plan.js +7 -1
  65. package/dist/tools/exit-plan.js.map +1 -1
  66. package/dist/tools/index.d.ts +5 -3
  67. package/dist/tools/index.js +5 -1
  68. package/dist/tools/index.js.map +1 -1
  69. package/dist/tools/prompt-hints.js +2 -0
  70. package/dist/tools/prompt-hints.js.map +1 -1
  71. package/dist/tools/subagent-shared.d.ts +6 -8
  72. package/dist/tools/subagent-shared.js +17 -11
  73. package/dist/tools/subagent-shared.js.map +1 -1
  74. package/dist/tools/subagent.d.ts +2 -1
  75. package/dist/tools/subagent.js +6 -6
  76. package/dist/tools/subagent.js.map +1 -1
  77. package/dist/tools/tasks.d.ts +1 -1
  78. package/dist/tools/tool-tiers.js +1 -0
  79. package/dist/tools/tool-tiers.js.map +1 -1
  80. package/dist/tools/verification-review.d.ts +2 -0
  81. package/dist/tools/verification-review.js +41 -0
  82. package/dist/tools/verification-review.js.map +1 -0
  83. package/dist/ui/App.js +1 -0
  84. package/dist/ui/App.js.map +1 -1
  85. package/dist/ui/hooks/useModeState.js +15 -0
  86. package/dist/ui/hooks/useModeState.js.map +1 -1
  87. package/dist/ui/tool-line-summary.js +11 -1
  88. package/dist/ui/tool-line-summary.js.map +1 -1
  89. package/dist/ui/transcript/tool-presentation.js +1 -1
  90. package/dist/ui/transcript/tool-presentation.js.map +1 -1
  91. package/package.json +5 -5
@@ -27,7 +27,7 @@ Also note **Texas and Nebraska have no revenue or volume threshold** — they ap
27
27
 
28
28
  Thresholds range from 25,000 consumers (Montana) to 175,000 (Tennessee); 10,000 consumers where a share of revenue comes from selling data (RI, DE, NH, MD); Maryland pairs a 35,000-consumer threshold with the strictest data-minimisation and sensitive-data rules, and bans the sale of sensitive data outright **[V]**.
29
29
 
30
- **Universal opt-out / Global Privacy Control — the cheapest high-value engineering task.** As of 1 Jan 2026, twelve states require honouring it (CA, CO, CT, DE, MD, MN, MT, NE, NH, NJ, OR, TX); Virginia-template states, including the 2026 newcomers Indiana, Kentucky and Rhode Island, do not **[V]**. California's regulations effective 1 Jan 2026 also require the business to display whether the signal was honoured (11 CCR §7025(c)(6)) **[S]**. California, Colorado and Connecticut have run a coordinated GPC enforcement sweep **[S]**.
30
+ **Universal opt-out / Global Privacy Control — the cheapest high-value engineering task.** As of 1 Jan 2026, twelve states require honouring it (CA, CO, CT, DE, MD, MN, MT, NE, NH, NJ, OR, TX); Virginia-template states, including the 2026 newcomers Indiana, Nolantucky and Rhode Island, do not **[V]**. California's regulations effective 1 Jan 2026 also require the business to display whether the signal was honoured (11 CCR §7025(c)(6)) **[S]**. California, Colorado and Connecticut have run a coordinated GPC enforcement sweep **[S]**.
31
31
 
32
32
  ```
33
33
  Read the Sec-GPC: 1 request header and navigator.globalPrivacyControl.
@@ -1,11 +1,13 @@
1
1
  ---
2
2
  name: refactoring
3
- description: Use when restructuring existing code without changing behavior — "refactor", "clean up", "reduce duplication", "split this god class", "modernize", migrating legacy code or APIs (strangler fig, parallel change, codemods across many files, callback→async), planning a refactor, or mid-build when a change needs preparatory restructuring first. Two hats, test-guarded steps, revert-on-red. Do NOT use for new features, bug fixes (stubborn ones: root-cause), performance tuning (lean), schema/data migrations (durable), styling or copy, the refactor step of a user-requested TDD flow (tdd), or a from-scratch rewrite.
3
+ description: Use for behavior-preserving restructuring: extract, move, split, deduplicate, plan a refactor, or migrate an implementation behind an unchanged contract. Baseline tests, small steps, revert-on-red. Do NOT use for requested behavior or API-contract changes (including new return/error semantics), even when called a "refactor"; use the normal implementation workflow with regression tests and update affected callers together. Also exclude bug fixes (root-cause when stubborn), performance work (lean), data migrations (durable), styling/copy, TDD's refactor step (tdd), and rewrites.
4
4
  license: Behavior-preservation methodology synthesized from public sources (Fowler's Refactoring catalog, Tidy First?, and community agent skills by bienhoang, wondelai, mattpocock, jeffallan, vasilyu1983), audited 2026-09-12.
5
5
  ---
6
6
 
7
7
  # Refactoring
8
8
 
9
+ **Scope gate:** Decide from the requested behavior, not the word "refactor". A requested change to return values, error handling, or an API contract is implementation work, not a behavior-preserving cleanup. Use the normal implementation workflow: inspect the affected callers, make the requested contract and caller changes together, add regression coverage, and run the checks. Do not manufacture a separate pure-rename stage merely to enter this skill. Existing authorization and safety controls still apply. For a genuine behavior-preserving refactor, use the gated loop below unchanged.
10
+
9
11
  **Route first:**
10
12
 
11
13
  | Situation | Mode | Next |
@@ -0,0 +1,21 @@
1
+ import { z } from "zod";
2
+ import { type FormattedChatError } from "@prestyj/ai";
3
+ declare const appErrorSchema: z.ZodObject<{
4
+ scope: z.ZodDefault<z.ZodString>;
5
+ headline: z.ZodString;
6
+ message: z.ZodCatch<z.ZodOptional<z.ZodString>>;
7
+ guidance: z.ZodCatch<z.ZodOptional<z.ZodString>>;
8
+ reason: z.ZodCatch<z.ZodOptional<z.ZodString>>;
9
+ source: z.ZodCatch<z.ZodOptional<z.ZodString>>;
10
+ provider: z.ZodCatch<z.ZodOptional<z.ZodString>>;
11
+ statusCode: z.ZodCatch<z.ZodOptional<z.ZodNumber>>;
12
+ requestId: z.ZodCatch<z.ZodOptional<z.ZodString>>;
13
+ occurredAt: z.ZodCatch<z.ZodOptional<z.ZodNumber>>;
14
+ resetsAt: z.ZodCatch<z.ZodOptional<z.ZodNumber>>;
15
+ }, z.core.$strip>;
16
+ export type AppErrorPayload = z.infer<typeof appErrorSchema>;
17
+ /** The same sanitized snapshot goes to SSE and the append-only history marker. */
18
+ export declare function createAppErrorPayload(error: FormattedChatError, scope: string, occurredAt: number, secrets: Iterable<string>): AppErrorPayload;
19
+ /** Backward-compatible read: no migration or reclassification of old saved text. */
20
+ export declare function restoreAppErrorPayload(value: unknown): AppErrorPayload | undefined;
21
+ export {};
@@ -0,0 +1,39 @@
1
+ import { z } from "zod";
2
+ import { redactValue } from "@prestyj/ai";
3
+ const timestamp = z.number().int().nonnegative().max(8_640_000_000_000).optional().catch(undefined);
4
+ const optionalText = z.string().max(8_000).optional().catch(undefined);
5
+ const appErrorSchema = z.object({
6
+ scope: z.string().max(80).default("error"),
7
+ headline: z.string().min(1).max(1_000),
8
+ message: optionalText,
9
+ guidance: optionalText,
10
+ reason: z.string().max(40).optional().catch(undefined),
11
+ source: z.string().max(40).optional().catch(undefined),
12
+ provider: z.string().max(80).optional().catch(undefined),
13
+ statusCode: z.number().int().min(100).max(599).optional().catch(undefined),
14
+ requestId: z.string().max(300).optional().catch(undefined),
15
+ occurredAt: timestamp,
16
+ resetsAt: timestamp,
17
+ });
18
+ /** The same sanitized snapshot goes to SSE and the append-only history marker. */
19
+ export function createAppErrorPayload(error, scope, occurredAt, secrets) {
20
+ return redactValue({
21
+ scope,
22
+ headline: error.headline,
23
+ message: error.message,
24
+ guidance: error.guidance,
25
+ reason: error.reason,
26
+ source: error.source,
27
+ provider: error.provider,
28
+ statusCode: error.statusCode,
29
+ requestId: error.requestId,
30
+ occurredAt,
31
+ resetsAt: error.resetsAt,
32
+ }, { secrets, maxStringLength: 8_000 });
33
+ }
34
+ /** Backward-compatible read: no migration or reclassification of old saved text. */
35
+ export function restoreAppErrorPayload(value) {
36
+ const parsed = appErrorSchema.safeParse(value);
37
+ return parsed.success ? parsed.data : undefined;
38
+ }
39
+ //# sourceMappingURL=app-error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-error.js","sourceRoot":"","sources":["../src/app-error.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,WAAW,EAA2B,MAAM,aAAa,CAAC;AAEnE,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;AACpG,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;AACvE,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IAC1C,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC;IACtC,OAAO,EAAE,YAAY;IACrB,QAAQ,EAAE,YAAY;IACtB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC;IACtD,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC;IACtD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC;IACxD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC;IAC1E,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC;IAC1D,UAAU,EAAE,SAAS;IACrB,QAAQ,EAAE,SAAS;CACpB,CAAC,CAAC;AAGH,kFAAkF;AAClF,MAAM,UAAU,qBAAqB,CACnC,KAAyB,EACzB,KAAa,EACb,UAAkB,EAClB,OAAyB;IAEzB,OAAO,WAAW,CAChB;QACE,KAAK;QACL,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,UAAU;QACV,QAAQ,EAAE,KAAK,CAAC,QAAQ;KACzB,EACD,EAAE,OAAO,EAAE,eAAe,EAAE,KAAK,EAAE,CACpC,CAAC;AACJ,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,sBAAsB,CAAC,KAAc;IACnD,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/C,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;AAClD,CAAC"}
@@ -19,7 +19,8 @@ import path from "node:path";
19
19
  import { randomUUID } from "node:crypto";
20
20
  import { parseArgs } from "node:util";
21
21
  import { spawn } from "node:child_process";
22
- import { environmentSecrets, formatError, redactValue } from "@prestyj/ai";
22
+ import { environmentSecrets, formatChatError, redactValue, } from "@prestyj/ai";
23
+ import { createAppErrorPayload, restoreAppErrorPayload, } from "./app-error.js";
23
24
  import { runJsonMode } from "./modes/json-mode.js";
24
25
  import { runSubagentWorkerMode } from "./modes/subagent-worker-mode.js";
25
26
  import { setStreamDiagnostic } from "@prestyj/agent";
@@ -70,6 +71,7 @@ import { loadCustomCommands } from "./core/custom-commands.js";
70
71
  import { discoverProjects } from "./core/project-discovery.js";
71
72
  import { listSidecarSessions } from "./app-sidecar-sessions.js";
72
73
  import { loadTasksSync, saveTasksSync, pruneDoneTasksSync, getNextPendingTask, markTaskInProgress, } from "./core/task-store.js";
74
+ import { readChecklistSnapshot } from "./core/checklist-snapshot.js";
73
75
  import { initLogger, log } from "./core/logger.js";
74
76
  import { installTerminationHandlers } from "./core/shutdown.js";
75
77
  import { KeepAwake } from "./core/keep-awake.js";
@@ -1318,35 +1320,21 @@ async function createSession(deps, opts) {
1318
1320
  // `400 {"code":"400",...}` with no "is this me or them / when does it reset"
1319
1321
  // context that the CLI has always given.
1320
1322
  function broadcastError(type, logLabel, err) {
1321
- const f = formatError(err);
1323
+ const f = formatChatError(err);
1322
1324
  const message = f.message ? desktopGuidance(f.message) : undefined;
1323
1325
  const guidance = localNetworkGuidance(f.source) ?? desktopGuidance(f.guidance);
1326
+ const payload = createAppErrorPayload({ ...f, ...(message ? { message } : {}), guidance }, type, Date.now(), environmentSecrets(process.env));
1324
1327
  log("ERROR", "app-sidecar", logLabel, {
1325
- headline: f.headline,
1328
+ headline: payload.headline,
1326
1329
  source: f.source,
1327
- ...(message ? { message } : {}),
1328
- ...(f.provider ? { provider: f.provider } : {}),
1329
- ...(f.statusCode != null ? { statusCode: String(f.statusCode) } : {}),
1330
- ...(f.requestId ? { requestId: f.requestId } : {}),
1330
+ ...(payload.message ? { message: payload.message } : {}),
1331
+ ...(payload.provider ? { provider: payload.provider } : {}),
1332
+ ...(payload.statusCode != null ? { statusCode: String(payload.statusCode) } : {}),
1333
+ ...(payload.requestId ? { requestId: payload.requestId } : {}),
1331
1334
  });
1332
- broadcast(type, {
1333
- headline: f.headline,
1334
- ...(message ? { message } : {}),
1335
- guidance,
1336
- ...(f.provider ? { provider: f.provider } : {}),
1337
- ...(f.statusCode != null ? { statusCode: f.statusCode } : {}),
1338
- ...(f.resetsAt != null ? { resetsAt: f.resetsAt } : {}),
1339
- });
1340
- // Persist the error row (display-only marker) so a resumed session shows
1341
- // the same headline/message/guidance the live run did. Best-effort.
1342
- void session
1343
- .persistAppMarker("error", {
1344
- scope: type,
1345
- headline: f.headline,
1346
- ...(message ? { message } : {}),
1347
- guidance,
1348
- })
1349
- .catch(() => { });
1335
+ broadcast(type, payload);
1336
+ // Same sanitized snapshot for live and restored rows, including reset metadata.
1337
+ void session.persistAppMarker("error", payload).catch(() => { });
1350
1338
  }
1351
1339
  // ── MCP elicitation bridge ─────────────────────────────────
1352
1340
  // An MCP server can ask for user input in the middle of a tool call. The
@@ -3567,16 +3555,9 @@ async function createSession(deps, opts) {
3567
3555
  });
3568
3556
  }
3569
3557
  else if (marker.kind === "error" && typeof d.headline === "string") {
3570
- history.push({
3571
- role: "assistant",
3572
- text: "",
3573
- error: {
3574
- scope: typeof d.scope === "string" ? d.scope : "error",
3575
- headline: d.headline,
3576
- ...(typeof d.message === "string" ? { message: d.message } : {}),
3577
- ...(typeof d.guidance === "string" ? { guidance: d.guidance } : {}),
3578
- },
3579
- });
3558
+ const error = restoreAppErrorPayload(d);
3559
+ if (error)
3560
+ history.push({ role: "assistant", text: "", error });
3580
3561
  }
3581
3562
  else if (marker.kind === "interrupted_run") {
3582
3563
  // Rendered as an error row: the run's tools already changed the
@@ -4124,6 +4105,29 @@ async function createSession(deps, opts) {
4124
4105
  json(res, 200, { tasks: pruneDoneTasksSync(cwd) });
4125
4106
  return;
4126
4107
  }
4108
+ if (method === "GET" && url === "/checklist") {
4109
+ const controller = new AbortController();
4110
+ res.once("close", () => controller.abort());
4111
+ void (async () => {
4112
+ try {
4113
+ const result = await readChecklistSnapshot(cwd, new Date(), controller.signal);
4114
+ if (res.destroyed)
4115
+ return;
4116
+ if (!result.ok) {
4117
+ log("WARN", "app-sidecar", "checklist read failed", { error: result.error });
4118
+ json(res, 500, { error: result.error });
4119
+ return;
4120
+ }
4121
+ json(res, 200, result.value);
4122
+ }
4123
+ catch (error) {
4124
+ log("WARN", "app-sidecar", "checklist snapshot failed", { error: String(error) });
4125
+ if (!res.destroyed)
4126
+ json(res, 500, { error: "Could not read the project checklist" });
4127
+ }
4128
+ })();
4129
+ return;
4130
+ }
4127
4131
  // ── Radio (app-wide) ──────────────────────────────────────
4128
4132
  // Radio is now APP-WIDE: all windows share one daemon process, and the
4129
4133
  // player lives in `core/radio.ts` module-level singletons (one stream for