toolroll 0.9.41 → 0.9.42

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 (67) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/cli.js +3 -1
  3. package/dist/coding-types.d.ts +2 -24
  4. package/dist/coding-workspace.js +12 -11
  5. package/dist/contracts/cli.d.ts +736 -0
  6. package/dist/contracts/cli.js +223 -0
  7. package/dist/contracts/coding-activity.d.ts +64 -0
  8. package/dist/contracts/coding-activity.js +58 -0
  9. package/dist/contracts/console-api.d.ts +483 -0
  10. package/dist/contracts/console-api.js +273 -0
  11. package/dist/contracts/diff-stat.d.ts +58 -0
  12. package/dist/contracts/diff-stat.js +59 -0
  13. package/dist/contracts/integration-metadata.d.ts +99 -0
  14. package/dist/contracts/integration-metadata.js +101 -0
  15. package/dist/contracts/model-catalog.d.ts +21 -0
  16. package/dist/contracts/model-catalog.js +14 -0
  17. package/dist/contracts/native-census.d.ts +42 -0
  18. package/dist/contracts/native-census.js +36 -0
  19. package/dist/contracts/observation-request.d.ts +37 -0
  20. package/dist/contracts/observation-request.js +25 -0
  21. package/dist/contracts/provider.d.ts +30 -0
  22. package/dist/contracts/provider.js +15 -0
  23. package/dist/contracts/recipes.d.ts +166 -0
  24. package/dist/contracts/recipes.js +52 -0
  25. package/dist/contracts/retention.d.ts +42 -0
  26. package/dist/contracts/retention.js +24 -0
  27. package/dist/contracts/storage.d.ts +23 -0
  28. package/dist/contracts/storage.js +10 -0
  29. package/dist/contracts/store-json.d.ts +315 -0
  30. package/dist/contracts/store-json.js +196 -0
  31. package/dist/contracts/trigger-payloads.d.ts +369 -0
  32. package/dist/contracts/trigger-payloads.js +144 -0
  33. package/dist/contracts/update-journal.d.ts +254 -0
  34. package/dist/contracts/update-journal.js +155 -0
  35. package/dist/contracts/verification-view.d.ts +93 -0
  36. package/dist/contracts/verification-view.js +43 -0
  37. package/dist/control-setup.d.ts +1 -1
  38. package/dist/desktop-update.d.ts +7 -40
  39. package/dist/desktop-update.js +36 -8
  40. package/dist/evidence.d.ts +3 -19
  41. package/dist/flow-triggers.js +61 -60
  42. package/dist/mcp-connect.js +37 -22
  43. package/dist/model-catalog.js +8 -6
  44. package/dist/observations.d.ts +2 -6
  45. package/dist/observations.js +13 -9
  46. package/dist/operate.js +2 -1
  47. package/dist/process-recovery-native.d.ts +2 -13
  48. package/dist/process-recovery-native.js +8 -5
  49. package/dist/project-tools.d.ts +6 -24
  50. package/dist/project-tools.js +22 -18
  51. package/dist/provider.d.ts +3 -8
  52. package/dist/provider.js +15 -11
  53. package/dist/recipes.d.ts +3 -28
  54. package/dist/recipes.js +79 -52
  55. package/dist/retention.d.ts +4 -5
  56. package/dist/retention.js +5 -4
  57. package/dist/serve.js +142 -28
  58. package/dist/storage.d.ts +2 -1
  59. package/dist/storage.js +12 -9
  60. package/dist/store.d.ts +3 -15
  61. package/dist/store.js +80 -158
  62. package/dist/surface.d.ts +6 -54
  63. package/dist/surface.js +6 -1
  64. package/dist/toolroll-update.d.ts +8 -99
  65. package/dist/toolroll-update.js +28 -18
  66. package/dist/verification-evidence.js +27 -12
  67. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.9.42 — 2026-10-06
4
+
5
+ - **Zod revamp, waves 3 and 4.** What comes into Toolroll from outside and
6
+ what it reads back from disk now goes through one schema each in
7
+ `src/contracts/`: console forms and JSON, CLI `--json` output, webhook,
8
+ GitHub, Linear, email and form payloads, OAuth replies and tool specs,
9
+ settings, every JSON column in the database, update and recovery journals,
10
+ and evidence files. All of it is read as leniently as before. Replayed
11
+ against real data with 0 differences: 655 runs and 984 evidence folders,
12
+ 5,158 database rows, 7 tool connections. Console JSON and CLI `--json` bytes
13
+ are unchanged. Console API and CLI input are partly done; what remains is
14
+ listed in `docs/plans/zod-revamp.md`.
15
+ - **Changed on purpose.** Recipe refusals start with the field's path. An
16
+ unknown provider is refused as `provider: unknown provider`, without
17
+ repeating what was typed. A sign-in that answers with an empty token says
18
+ it couldn't be reached instead of crashing. An update journal missing its
19
+ core fields (no release since 0.8.0 writes one) is refused rather than read.
20
+
3
21
  ## 0.9.41 — 2026-10-06
4
22
 
5
23
  - **A read-only PostHog connection works for research.** PostHog adds
package/dist/cli.js CHANGED
@@ -17,7 +17,9 @@ import { fileURLToPath, pathToFileURL } from "node:url";
17
17
  import { configPath, loadRepos } from "./repos.js";
18
18
  import { addedWords, admitProject, commandLineActor, consoleRunning, proveProjectRoot, registryBeside, releaseProject } from "./project-admission.js";
19
19
  import { envValue } from "./names.js";
20
- import { CAPABILITIES, ENVELOPE_VERSION, capturedEnvelope, envelopeJson, onEnvelopeCaptured, resetCapturedEnvelope } from "./envelope.js";
20
+ import { CAPABILITIES, ENVELOPE_VERSION, capturedEnvelope, onEnvelopeCaptured, resetCapturedEnvelope } from "./envelope.js";
21
+ // Every envelope is checked against its command's schema (logged, never refused), then serialized unchanged.
22
+ import { checkedEnvelopeJson as envelopeJson } from "./contracts/cli.js";
21
23
  import { applyClaudeCodeInstall, applyInstall, contextBlock, defaultClaudeCodeSkillDir, planClaudeCodeInstall, planInstall, } from "./skills.js";
22
24
  import { GUIDES, guideNamed } from "./guides.js";
23
25
  import { parseGithubRepo, previewGithubRepo, cloneGithubRepo, isLargeRepo } from "./onboard.js";
@@ -1,29 +1,7 @@
1
1
  export type { CodingSession, CodingStatus } from './contracts/coding-workspace.js';
2
2
  import type { CodingSession } from './contracts/coding-workspace.js';
3
- export type CodingItem = {
4
- id: string;
5
- type: string;
6
- text: string;
7
- status: string | null;
8
- clientId?: string;
9
- };
10
- export type CodingQuestion = {
11
- id: string;
12
- header: string;
13
- question: string;
14
- options: {
15
- label: string;
16
- description: string;
17
- }[];
18
- };
19
- export type CodingRequest = {
20
- id: string;
21
- kind: 'command' | 'files' | 'questions';
22
- method: string;
23
- title: string;
24
- detail: string;
25
- questions: CodingQuestion[];
26
- };
3
+ export type { CodingItem, CodingQuestion, CodingRequest } from './contracts/coding-activity.js';
4
+ import type { CodingItem, CodingRequest } from './contracts/coding-activity.js';
27
5
  export type CodingSnapshot = {
28
6
  session: CodingSession;
29
7
  items: CodingItem[];
@@ -10,6 +10,7 @@ import { processMayBeAlive } from './process-liveness.js';
10
10
  import { createCodexCodingProvider } from './coding-provider.js';
11
11
  import { verifyCodingContext } from './coding-context.js';
12
12
  import { codingSessionDocument, parseCodingSessionDocument } from './contracts/coding-workspace.js';
13
+ import { readCodingCustodyWitness, readCodingItem, readCodingRequest, readCodingRpcId } from './contracts/coding-activity.js';
13
14
  export class CodingActionError extends Error {
14
15
  delivery;
15
16
  sessionId;
@@ -163,8 +164,8 @@ export class CodingWorkspace {
163
164
  }
164
165
  snapshot(id, actor) {
165
166
  const session = this.get(id, actor);
166
- const items = this.db.prepare('SELECT payload FROM coding_item WHERE session=? ORDER BY position').all(id).map(row => JSON.parse(String(row['payload'])));
167
- const requests = this.db.prepare("SELECT payload FROM coding_request WHERE session=? AND status='pending' ORDER BY rowid").all(id).map(row => JSON.parse(String(row['payload'])));
167
+ const items = this.db.prepare('SELECT payload FROM coding_item WHERE session=? ORDER BY position').all(id).map(row => readCodingItem(String(row['payload'])));
168
+ const requests = this.db.prepare("SELECT payload FROM coding_request WHERE session=? AND status='pending' ORDER BY rowid").all(id).map(row => readCodingRequest(String(row['payload'])));
168
169
  const revision = Number(this.db.prepare('SELECT revision FROM coding_session WHERE id=?').get(id)?.['revision']);
169
170
  return { session, items, requests, revision };
170
171
  }
@@ -174,8 +175,8 @@ export class CodingWorkspace {
174
175
  const session = this.get(id, actor);
175
176
  const itemRows = this.db.prepare('SELECT payload FROM coding_item WHERE session=? ORDER BY position DESC LIMIT 101').all(id);
176
177
  const requestRows = this.db.prepare("SELECT payload FROM coding_request WHERE session=? AND status='pending' ORDER BY rowid LIMIT 51").all(id);
177
- const items = itemRows.slice(0, 100).reverse().map(row => JSON.parse(String(row['payload'])));
178
- const requests = requestRows.slice(0, 50).map(row => JSON.parse(String(row['payload'])));
178
+ const items = itemRows.slice(0, 100).reverse().map(row => readCodingItem(String(row['payload'])));
179
+ const requests = requestRows.slice(0, 50).map(row => readCodingRequest(String(row['payload'])));
179
180
  const revision = Number(this.db.prepare('SELECT revision FROM coding_session WHERE id=?').get(id)?.['revision']);
180
181
  return { session, items, requests, revision, truncated: itemRows.length > items.length || requestRows.length > requests.length };
181
182
  }
@@ -373,7 +374,7 @@ export class CodingWorkspace {
373
374
  }
374
375
  else if (event.method === 'item/agentMessage/delta') {
375
376
  const id = string(p['itemId']), key = `${session.id}:${id}`;
376
- const prior = this.pendingItems.get(key)?.item ?? (() => { const row = this.db.prepare('SELECT payload FROM coding_item WHERE session=? AND id=?').get(session.id, id); return row ? JSON.parse(String(row['payload'])) : { id, type: 'agentMessage', text: '', status: 'inProgress' }; })();
377
+ const prior = this.pendingItems.get(key)?.item ?? (() => { const row = this.db.prepare('SELECT payload FROM coding_item WHERE session=? AND id=?').get(session.id, id); return row ? readCodingItem(String(row['payload'])) : { id, type: 'agentMessage', text: '', status: 'inProgress' }; })();
377
378
  prior.text += string(p['delta']);
378
379
  if (prior.text.length > 100_000)
379
380
  prior.text = prior.text.slice(0, 100_000);
@@ -524,8 +525,8 @@ export class CodingWorkspace {
524
525
  if (!row)
525
526
  return false;
526
527
  try {
527
- const c = JSON.parse(String(row['payload']));
528
- if (c.host !== hostname() || !Array.isArray(c.descendants) || typeof c.observationUnknown !== 'boolean')
528
+ const c = readCodingCustodyWitness(String(row['payload']));
529
+ if (c === null || c.host !== hostname())
529
530
  return false;
530
531
  if (provenDeadByBootChange(c))
531
532
  return true;
@@ -688,8 +689,8 @@ export class CodingWorkspace {
688
689
  if (!session.nativeThreadId || !session.turnId || !busy.has(session.status))
689
690
  throw new CodingActionError('There is no running turn to stop.', 'rejected', id);
690
691
  for (const row of this.db.prepare("SELECT token,rpc_id,payload FROM coding_request WHERE session=? AND status='pending'").all(id)) {
691
- const request = JSON.parse(String(row['payload']));
692
- this.native().respond(JSON.parse(String(row['rpc_id'])), request.kind === 'questions' ? { answers: {} } : { decision: 'cancel' });
692
+ const request = readCodingRequest(String(row['payload']));
693
+ this.native().respond(readCodingRpcId(String(row['rpc_id'])), request.kind === 'questions' ? { answers: {} } : { decision: 'cancel' });
693
694
  this.db.prepare("UPDATE coding_request SET status='withdrawn' WHERE token=?").run(String(row['token']));
694
695
  }
695
696
  this.save({ ...session, status: 'stopping' });
@@ -700,11 +701,11 @@ export class CodingWorkspace {
700
701
  const row = this.db.prepare("SELECT * FROM coding_request WHERE session=? AND token=? AND status='pending'").get(id, token);
701
702
  if (!row || session.status !== 'needs-input' || !this.loaded.has(id))
702
703
  throw Error('This request is no longer waiting for an answer.');
703
- const request = JSON.parse(String(row['payload']));
704
+ const request = readCodingRequest(String(row['payload']));
704
705
  if (!['accept', 'decline', 'cancel'].includes(decision))
705
706
  throw Error('Choose an available decision.');
706
707
  const result = request.kind === 'questions' ? { answers: decision === 'accept' ? this.validateAnswers(request, answers) : {} } : { decision };
707
- this.native().respond(JSON.parse(String(row['rpc_id'])), result);
708
+ this.native().respond(readCodingRpcId(String(row['rpc_id'])), result);
708
709
  this.db.prepare("UPDATE coding_request SET status='answered' WHERE token=?").run(token);
709
710
  const remaining = this.db.prepare("SELECT 1 FROM coding_request WHERE session=? AND status='pending'").get(id);
710
711
  this.save({ ...session, status: remaining ? 'needs-input' : 'working' });