@trydreamstate/cli 1.3.2 → 1.3.4

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/README.md +36 -16
  2. package/agent-plugin/.claude-plugin/plugin.json +1 -1
  3. package/agent-plugin/.codex-plugin/plugin.json +1 -1
  4. package/agent-plugin/hooks/approve-readonly.sh +15 -0
  5. package/agent-plugin/hooks/hooks.json +17 -0
  6. package/agent-plugin/skills/crm/SKILL.md +2 -2
  7. package/agent-plugin/skills/diagnostics/SKILL.md +3 -1
  8. package/agent-plugin/skills/dreamstate/SKILL.md +15 -5
  9. package/agent-plugin/skills/first-win/SKILL.md +2 -2
  10. package/agent-plugin/skills/inbox-replies/SKILL.md +3 -1
  11. package/agent-plugin/skills/knowledge/SKILL.md +3 -5
  12. package/agent-plugin/skills/linkedin-posts/SKILL.md +3 -1
  13. package/agent-plugin/skills/linkedin-warm-signals/SKILL.md +2 -2
  14. package/agent-plugin/skills/list-building/SKILL.md +5 -10
  15. package/agent-plugin/skills/list-building/column-authoring.md +1 -1
  16. package/agent-plugin/skills/list-building/sourcing.md +2 -2
  17. package/agent-plugin/skills/outreach/SKILL.md +2 -2
  18. package/agent-plugin/skills/outreach/steps-and-timing.md +1 -1
  19. package/agent-plugin/skills/plays/SKILL.md +3 -3
  20. package/agent-plugin/skills/reddit-posts/SKILL.md +3 -1
  21. package/agent-plugin/skills/skill-authoring/SKILL.md +3 -1
  22. package/agent-plugin/skills/social/SKILL.md +4 -6
  23. package/agent-plugin/skills/visibility/SKILL.md +2 -6
  24. package/agent-plugin/skills/workflows/SKILL.md +3 -3
  25. package/agent-plugin/skills/workflows/lifecycle-and-enrollment.md +1 -1
  26. package/agent-plugin/skills/worksheet-tidy/SKILL.md +3 -1
  27. package/agent-plugin/skills/writing/SKILL.md +3 -5
  28. package/agent-plugin/skills/x-posts/SKILL.md +3 -1
  29. package/dist/agentGuidance.generated.json +35 -0
  30. package/dist/capabilityPosture.d.ts +12 -0
  31. package/dist/capabilityPosture.d.ts.map +1 -0
  32. package/dist/capabilityPosture.js +39 -0
  33. package/dist/client.d.ts +33 -2
  34. package/dist/client.d.ts.map +1 -1
  35. package/dist/client.js +155 -64
  36. package/dist/commandTable.d.ts +26 -0
  37. package/dist/commandTable.d.ts.map +1 -0
  38. package/dist/commandTable.js +54 -0
  39. package/dist/commands/sequences.d.ts +3 -2
  40. package/dist/commands/sequences.d.ts.map +1 -1
  41. package/dist/commands/sequences.js +17 -34
  42. package/dist/commands/shared.d.ts +4 -26
  43. package/dist/commands/shared.d.ts.map +1 -1
  44. package/dist/commands/shared.js +136 -158
  45. package/dist/commands/workflows.d.ts +3 -2
  46. package/dist/commands/workflows.d.ts.map +1 -1
  47. package/dist/commands/workflows.js +17 -39
  48. package/dist/errors.d.ts +74 -0
  49. package/dist/errors.d.ts.map +1 -0
  50. package/dist/errors.js +84 -0
  51. package/dist/gatedRun.d.ts +79 -0
  52. package/dist/gatedRun.d.ts.map +1 -0
  53. package/dist/gatedRun.js +346 -0
  54. package/dist/generated/packVerbs.generated.json +492 -0
  55. package/dist/generated/runContract.generated.d.ts +4 -0
  56. package/dist/generated/runContract.generated.d.ts.map +1 -0
  57. package/dist/generated/runContract.generated.js +7 -0
  58. package/dist/idempotency.d.ts +38 -0
  59. package/dist/idempotency.d.ts.map +1 -0
  60. package/dist/idempotency.js +106 -0
  61. package/dist/index.d.ts +22 -35
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +405 -378
  64. package/dist/registryManifest.d.ts +6 -0
  65. package/dist/registryManifest.d.ts.map +1 -0
  66. package/dist/registryManifest.js +66 -0
  67. package/dist/runContract.d.ts +10 -0
  68. package/dist/runContract.d.ts.map +1 -0
  69. package/dist/runContract.js +13 -0
  70. package/dist/runWait.d.ts +2 -2
  71. package/dist/runWait.d.ts.map +1 -1
  72. package/dist/runWait.js +3 -14
  73. package/dist/schemaCoercion.d.ts +20 -0
  74. package/dist/schemaCoercion.d.ts.map +1 -0
  75. package/dist/schemaCoercion.js +123 -0
  76. package/dist/skillInstaller.d.ts +40 -0
  77. package/dist/skillInstaller.d.ts.map +1 -1
  78. package/dist/skillInstaller.js +108 -9
  79. package/dist/tableFilePreview.d.ts +14 -0
  80. package/dist/tableFilePreview.d.ts.map +1 -1
  81. package/dist/tableFilePreview.js +19 -8
  82. package/dist/tableFileReader.d.ts +26 -0
  83. package/dist/tableFileReader.d.ts.map +1 -0
  84. package/dist/tableFileReader.js +108 -0
  85. package/dist/tablesImport.d.ts +57 -0
  86. package/dist/tablesImport.d.ts.map +1 -0
  87. package/dist/tablesImport.js +263 -0
  88. package/dist/turnCache.d.ts +14 -1
  89. package/dist/turnCache.d.ts.map +1 -1
  90. package/dist/turnCache.js +25 -8
  91. package/package.json +6 -3
@@ -3,7 +3,7 @@ name: workflows
3
3
  description: "Best practices for building and running automations that are not outreach sequences: frame the job, smallest graph, validate after every change, runtime inputs, safe recovery of failed runs."
4
4
  ---
5
5
 
6
- Run this through the Dreamstate MCP tools: `packs_get` for the pack's capabilities, `tools_get` for the exact input schema, then `tools_run` (`dry_run` first for anything that writes, spends credits or reaches a person). If the server asks you to sign in, approve it in the browser.
6
+ Run this through the Dreamstate MCP tools: `packs_get` for the pack's capabilities, `tools_get` for the exact input schema, then `tools_run`. Anything that writes, spends credits or reaches a person: dry_run first, then live with the quote_hash the dry_run returned, a max_credits ceiling and an idempotency_key. max_credits 0 is valid only when that quote is 0. A larger paid run, or a live external send above the server's recipient threshold, also needs the user's yes before you send approved: true; never send it on your own. `max_rows` is a param of `tables.columns.run` and `tables.table_sources.run`, not of `tools_run`. `max_live_sends` is a param of the external-send sequence capabilities (`sequence.sequences.activate_audience`, `sequence.sequences.resume`, and the rest of that family), sent inside `params`, not a gating input of `tools_run`. The paid-run consent rule is one sentence in the MCP server instructions, rendered from consentRule.json and PAID_RUN_APPROVAL_THRESHOLDS: rows, dollars, credits, and the conversion. If the server asks you to sign in, approve it in the browser.
7
7
 
8
8
  # Workflows
9
9
 
@@ -19,7 +19,7 @@ Run this through the Dreamstate MCP tools: `packs_get` for the pack's capabiliti
19
19
  Best practices for building and running automations. The workflow pack lists the tools and their exact inputs; this skill is how to use them well. Outreach cadences to people are sequences, covered by the outreach skill. Everything else is a workflow.
20
20
 
21
21
  1. Build new unless asked. A new request gets a new automation built from scratch. When the user names an existing one to change, resolve that name among existing automations by listing workflows and sequences with that name as the search text, then change the match. A named thing that is not a workflow or sequence may be a task, a record or a worksheet; check those only after automations come back empty. A step inside a workflow, such as a task step, is edited in that workflow's graph, not in the task list.
22
- 1a. "Enroll these in a workflow" is never a missing input. Use a workflow whose table trigger is the worksheet the user is looking at, or one they named; otherwise build a new draft for that worksheet (worksheet rows trigger plus fitting steps, a follow-up task per person by default), validate, and enroll. Never ask which workflow.
22
+ 1a. "Enroll these in a workflow" is never a missing input. Use a workflow whose table trigger is the worksheet the user is looking at, or one they named; otherwise build a new draft for that worksheet (worksheet rows trigger plus fitting steps, a follow-up task per person by default), validate, and enroll. Never ask which workflow. Filters on any worksheet column narrow who enrolls; with no filter every row enrolls. When the user said who should enroll, filter on the columns that hold it and report how many enrolled and how many were held back.
23
23
  2. Frame the job before building: what triggers it, who or what it acts on, what it changes, what it costs, when it stops and how often it runs.
24
24
  2a. Use a blueprint when one does exactly what you need; otherwise build your own. Workflow blueprints already cover common jobs: CRM syncs, list and do-not-contact syncs, routers, digests and signal monitors. List blueprints of the workflow kind, read what the closest one creates and what it still needs, install it, then adapt it to this request. Installing never needs answers or connections; the result names what is still to pick, so say that. Build from scratch only when no blueprint fits, and say which one came closest.
25
25
  3. Ask one clarifying question only when a required input is missing. Otherwise build with sensible defaults and say what you assumed.
@@ -31,7 +31,7 @@ Best practices for building and running automations. The workflow pack lists the
31
31
  8a. Building never waits on rows. A worksheet trigger on an empty or still-filling worksheet is still a valid enrollment: build, validate and turn it on, and rows enroll as they land. Say it is waiting for rows, never stop because the worksheet is empty.
32
32
  8b. Use the row-created trigger when each new worksheet row must enter once. It watches future row arrivals on one worksheet, carries that row identity through the graph, and does not reuse or freeze a saved selection. Use the table trigger only when user wants a selected saved-view audience.
33
33
  8c. To tag or mark a triggering row, add the worksheet-row update step. Choose its column and either replace its value or append a value to its existing list. Do not ask user to export, reimport, or manually tag rows when workflow already has triggering row identity.
34
- 9. Decide by judgment whether to confirm before activating something that sends or spends. When the user already asked for it, do it. There is no system approval step.
34
+ 9. Activating something that sends or spends follows the paid-run consent rule.
35
35
  10. Draft, published, active, running and finished are separate facts. Report only what the last result proves.
36
36
 
37
37
  ## Delete and archive
@@ -6,6 +6,6 @@ Missing connections never block building, editing, saving a draft or validating.
6
6
 
7
7
  Enrollment, activation and delivery are different events. Read the result after each one. After an unclear result, check current state before retrying, and never enroll twice or replay an effect that already happened.
8
8
 
9
- Preview first. Activation needs `params.max_credits` on `workflow.workflows.activate`: read exact `required_caps.max_credits` from preview, then resend that value unchanged. Live enrollment takes no send cap: every eligible selected row is enrolled. The activation ceiling is a caller input, not user approval. Never guess it or ask the user to approve it.
9
+ Preview first. Activation stores `params.max_credits` on `workflow.workflows.activate`: read exact `required_caps.max_credits` from preview, then resend that value unchanged. This persisted per-delivery ceiling is a declared domain input, not run `max_credits`; put run gating fields at door. Live enrollment takes no send cap: every eligible selected row is enrolled. Never guess it or ask user to approve it.
10
10
 
11
11
  An active worksheet trigger snapshots its saved view on periodic ticks and idempotently enrolls rows that arrive later; draft, paused, and inactive workflows never refill.
@@ -3,7 +3,7 @@ name: worksheet-tidy
3
3
  description: "Review a workbook worksheet's structure and values, including duplicate or overlapping columns, column order, types and formatting, columns to hide, criteria and run conditions that never vary, and suspicious values, then apply reversible fixes. Use it when a worksheet has grown messy, before sharing it, or before enrolling it into a sequence. It does not merge CRM records across the workspace, rebuild the list's source (list-building does) or explain failed runs (diagnostics does)."
4
4
  ---
5
5
 
6
- Run this through the Dreamstate MCP tools: `packs_get` for the pack's capabilities, `tools_get` for the exact input schema, then `tools_run` (`dry_run` first for anything that writes, spends credits or reaches a person). If the server asks you to sign in, approve it in the browser.
6
+ Run this through the Dreamstate MCP tools: `packs_get` for the pack's capabilities, `tools_get` for the exact input schema, then `tools_run`. Anything that writes, spends credits or reaches a person: dry_run first, then live with the quote_hash the dry_run returned, a max_credits ceiling and an idempotency_key. max_credits 0 is valid only when that quote is 0. A larger paid run, or a live external send above the server's recipient threshold, also needs the user's yes before you send approved: true; never send it on your own. `max_rows` is a param of `tables.columns.run` and `tables.table_sources.run`, not of `tools_run`. `max_live_sends` is a param of the external-send sequence capabilities (`sequence.sequences.activate_audience`, `sequence.sequences.resume`, and the rest of that family), sent inside `params`, not a gating input of `tools_run`. The paid-run consent rule is one sentence in the MCP server instructions, rendered from consentRule.json and PAID_RUN_APPROVAL_THRESHOLDS: rows, dollars, credits, and the conversion. If the server asks you to sign in, approve it in the browser.
7
7
 
8
8
  # Worksheet Tidy
9
9
 
@@ -59,3 +59,5 @@ Search the workbook tool for each change. The search returns runnable schemas fo
59
59
  ## Check it works
60
60
 
61
61
  Done means checked, not built. Before you report, read back everything you made or changed, and run, test or preview it where that is offered; publish or send only when the user asked. An empty, failed or wrong result means an input or setting is wrong: find which from the error or the output, correct it and check again, until it is right or a real blocker stops it. Report what you checked and what it showed.
62
+
63
+ Paid and outward runs follow the paid-run consent rule.
@@ -3,7 +3,7 @@ name: writing
3
3
  description: "Draft, revise and publish articles and landing copy grounded in workspace context and a target query."
4
4
  ---
5
5
 
6
- Run this through the Dreamstate MCP tools: `packs_get` for the pack's capabilities, `tools_get` for the exact input schema, then `tools_run` (`dry_run` first for anything that writes, spends credits or reaches a person). If the server asks you to sign in, approve it in the browser.
6
+ Run this through the Dreamstate MCP tools: `packs_get` for the pack's capabilities, `tools_get` for the exact input schema, then `tools_run`. Anything that writes, spends credits or reaches a person: dry_run first, then live with the quote_hash the dry_run returned, a max_credits ceiling and an idempotency_key. max_credits 0 is valid only when that quote is 0. A larger paid run, or a live external send above the server's recipient threshold, also needs the user's yes before you send approved: true; never send it on your own. `max_rows` is a param of `tables.columns.run` and `tables.table_sources.run`, not of `tools_run`. `max_live_sends` is a param of the external-send sequence capabilities (`sequence.sequences.activate_audience`, `sequence.sequences.resume`, and the rest of that family), sent inside `params`, not a gating input of `tools_run`. The paid-run consent rule is one sentence in the MCP server instructions, rendered from consentRule.json and PAID_RUN_APPROVAL_THRESHOLDS: rows, dollars, credits, and the conversion. If the server asks you to sign in, approve it in the browser.
7
7
 
8
8
  # Writing
9
9
 
@@ -14,10 +14,6 @@ Run this through the Dreamstate MCP tools: `packs_get` for the pack's capabiliti
14
14
  - Short-form social posts: [`social`].
15
15
  - The `social` pack lists the tools and their exact inputs.
16
16
 
17
- <!-- architect-operation-contract
18
- {"required_capability_ids":[]}
19
- -->
20
-
21
17
  Own the draft, review, revise, and publish lifecycle for long-form articles and landing copy. Every factual claim traces to a workspace-wiki fact, cited evidence, or a dated external source; the voice matches what the workspace has already published; and each lifecycle step is a deliberate, verifiable state change. Traditional keyword, ranking, and generative-citation evidence belongs to `visibility`; current external evidence and durable facts about the business belong to `knowledge`. Never re-derive those measurements or restate a business fact from memory.
22
18
 
23
19
  Authoring: prepare brief, evidence ledger, novelty decision, destination, and voice; compose internally; discover owner and hydrate schema; save complete artifact; read result before showing or advancing. Unsaved long-form copy in chat is not an article. Preserve exact user-named title. A rewrite is not persisted until live result says save succeeded.
@@ -82,3 +78,5 @@ Report the missing source, stale revision, failed destination, or missing publis
82
78
  ## Check it works
83
79
 
84
80
  Done means checked, not built. Before you report, read back everything you made or changed, and run, test or preview it where that is offered; publish or send only when the user asked. An empty, failed or wrong result means an input or setting is wrong: find which from the error or the output, correct it and check again, until it is right or a real blocker stops it. Report what you checked and what it showed.
81
+
82
+ Paid and outward runs follow the paid-run consent rule.
@@ -3,7 +3,7 @@ name: x-posts
3
3
  description: "Write and revise X posts and threads: the first line, single post versus thread, weighted length and Premium limits, thread structure, post types, replies and links, and phrases to avoid. Use it for the copy of any post going to X. It does not cover scheduling, publishing or automations (social does)."
4
4
  ---
5
5
 
6
- Run this through the Dreamstate MCP tools: `packs_get` for the pack's capabilities, `tools_get` for the exact input schema, then `tools_run` (`dry_run` first for anything that writes, spends credits or reaches a person). If the server asks you to sign in, approve it in the browser.
6
+ Run this through the Dreamstate MCP tools: `packs_get` for the pack's capabilities, `tools_get` for the exact input schema, then `tools_run`. Anything that writes, spends credits or reaches a person: dry_run first, then live with the quote_hash the dry_run returned, a max_credits ceiling and an idempotency_key. max_credits 0 is valid only when that quote is 0. A larger paid run, or a live external send above the server's recipient threshold, also needs the user's yes before you send approved: true; never send it on your own. `max_rows` is a param of `tables.columns.run` and `tables.table_sources.run`, not of `tools_run`. `max_live_sends` is a param of the external-send sequence capabilities (`sequence.sequences.activate_audience`, `sequence.sequences.resume`, and the rest of that family), sent inside `params`, not a gating input of `tools_run`. The paid-run consent rule is one sentence in the MCP server instructions, rendered from consentRule.json and PAID_RUN_APPROVAL_THRESHOLDS: rows, dollars, credits, and the conversion. If the server asks you to sign in, approve it in the browser.
7
7
 
8
8
  # X posts
9
9
 
@@ -71,3 +71,5 @@ Change what was asked and keep the rest verbatim. If a thread post runs long, sp
71
71
  ## Check it works
72
72
 
73
73
  Read the saved draft back: the hook alone justifies post two, each post is under the account's limit, each thread post stands alone, every number traces to something real, and nothing contains an em dash.
74
+
75
+ Paid and outward runs follow the paid-run consent rule.
@@ -0,0 +1,35 @@
1
+ {
2
+ "generated_by": "packages/cli/scripts/build-agent-plugin.mjs from apps/backend/src/services/mcp/consentRule.json; do not edit by hand",
3
+ "consent": {
4
+ "summary": "Anything that writes, spends credits or reaches a person: dry_run first, then live with the quote_hash the dry_run returned, a max_credits ceiling and an idempotency_key. max_credits 0 is valid only when that quote is 0. A larger paid run, or a live external send above the server's recipient threshold, also needs the user's yes before you send approved: true; never send it on your own.",
5
+ "paid_run": "Anything that writes, spends credits or reaches a real person: run mode dry_run first, show the user the preview, the row count and the credit estimate, then run live with the quote_hash that dry_run returned, a max_credits ceiling and an idempotency_key. max_credits 0 is valid only when that quote is 0. A live paid run states max_rows; an external send states max_live_sends of at least the dry_run recipient_count. A quote returned by a refused live call is only a price, never a confirmation.",
6
+ "human_approval": "A paid run above the server's row or provider-spend limit, a live external send above the server's recipient threshold, or a run that turns on a recurring trigger, also needs the user's yes. Ask them, and only then send approved: true with the same quote_hash. You are asserting that you asked a person; never send it on your own."
7
+ },
8
+ "router_steps": [
9
+ {
10
+ "mcp": "whoami",
11
+ "cli": "dreamstate whoami --json",
12
+ "text": "names the user and the active workspace. If it lists several workspaces, confirm the right one before writing anything."
13
+ },
14
+ {
15
+ "mcp": "packs_route",
16
+ "cli": "dreamstate packs route --goal \"<goal>\" --json",
17
+ "text": "maps a goal to a domain; `packs_get` returns that domain's capabilities and skills."
18
+ },
19
+ {
20
+ "mcp": "tools_search",
21
+ "cli": "dreamstate tools search --goal \"<goal>\" --toolset <pack_id> --json",
22
+ "text": "finds the capability for the goal; `tools_get` returns its exact input schema. Read the schema every time, never guess params from memory."
23
+ },
24
+ {
25
+ "mcp": "tools_run",
26
+ "cli": "dreamstate tools run <capability_id> --params '{...}' --mode <dry_run|live> --json",
27
+ "text": "runs it with `capability_id` and `params`. The gating inputs (`mode`, `max_credits`, `idempotency_key`, `quote_hash`, `approved`) go on the run call itself, never inside `params`. `max_rows` is a param of `tables.columns.run` and `tables.table_sources.run`, not of `tools_run`. `max_live_sends` is a param of the external-send sequence capabilities (`sequence.sequences.activate_audience`, `sequence.sequences.resume`, and the rest of that family), sent inside `params`, not a gating input of `tools_run`."
28
+ },
29
+ {
30
+ "mcp": "runs_get",
31
+ "cli": "dreamstate runs get <run_id> --json",
32
+ "text": "follows long work; `runs_events` and `runs_list` read more of it and `runs_cancel` stops a run."
33
+ }
34
+ ]
35
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Inline-read and column-run hand-off, derived from the tools-get capability
3
+ * record. No capability id list: a free synchronous read omits the turn token,
4
+ * and a queued external test run (column runs and the same posture class)
5
+ * returns without waiting.
6
+ */
7
+ export interface CapabilityPosture {
8
+ inlineRead: boolean;
9
+ returnsRunId: boolean;
10
+ }
11
+ export declare function postureFromContract(fetched: unknown): CapabilityPosture;
12
+ //# sourceMappingURL=capabilityPosture.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilityPosture.d.ts","sourceRoot":"","sources":["../src/capabilityPosture.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,iBAAiB;IAChC,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;CACvB;AAaD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,iBAAiB,CAkBvE"}
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ /**
3
+ * Inline-read and column-run hand-off, derived from the tools-get capability
4
+ * record. No capability id list: a free synchronous read omits the turn token,
5
+ * and a queued external test run (column runs and the same posture class)
6
+ * returns without waiting.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.postureFromContract = postureFromContract;
10
+ function record(value) {
11
+ return value && typeof value === 'object' && !Array.isArray(value) ? value : null;
12
+ }
13
+ function capabilityOf(fetched) {
14
+ const root = record(fetched);
15
+ if (!root)
16
+ return null;
17
+ const data = record(root.data);
18
+ return record(data?.capability) ?? record(root.capability);
19
+ }
20
+ function postureFromContract(fetched) {
21
+ const capability = capabilityOf(fetched);
22
+ if (!capability)
23
+ return { inlineRead: false, returnsRunId: false };
24
+ const asyncPolicy = record(capability.async_policy);
25
+ const asyncMode = typeof asyncPolicy?.mode === 'string' ? asyncPolicy.mode : undefined;
26
+ const credit = typeof capability.credit_class === 'string' ? capability.credit_class : undefined;
27
+ const consequence = typeof capability.consequence === 'string' ? capability.consequence : undefined;
28
+ const effect = typeof capability.effect_class === 'string' ? capability.effect_class : undefined;
29
+ // Missing async_policy is unknown. Do not guess sync, and do not treat it as a hand-off.
30
+ const inlineRead = capability.mutates !== true
31
+ && asyncMode === 'sync'
32
+ && (credit === 'free' || credit === undefined)
33
+ && (consequence === 'read_only' || consequence === 'test_run');
34
+ const returnsRunId = asyncMode === 'async'
35
+ && consequence === 'test_run'
36
+ && credit === 'dynamic'
37
+ && effect === 'external';
38
+ return { inlineRead, returnsRunId };
39
+ }
package/dist/client.d.ts CHANGED
@@ -1,4 +1,21 @@
1
1
  export declare const CLI_VERSION: string;
2
+ /** Command that updates the CLI. One constant so every surface prints the same one. */
3
+ export declare const CLI_UPDATE_COMMAND = "npm install -g @trydreamstate/cli@latest";
4
+ /**
5
+ * Release identity the server stamps on every /api/v1 response (contract C2):
6
+ * meta.server_version, meta.minimum_cli_version, meta.release_sha and
7
+ * meta.registry_hash in the JSON envelope (whoami also puts registry_hash on
8
+ * data), and X-Dreamstate-Server-Version / -Minimum-Cli-Version / -Release-Sha
9
+ * / -Registry-Hash as response headers. The client reads both so a server that
10
+ * only sets one of them (a proxy that rewrites bodies, an error page with no
11
+ * envelope) still reports skew.
12
+ */
13
+ export interface ServerReleaseInfo {
14
+ server_version: string | null;
15
+ minimum_cli_version: string | null;
16
+ release_sha: string | null;
17
+ registry_hash: string | null;
18
+ }
2
19
  export interface DreamstateClientOptions {
3
20
  apiKey: string;
4
21
  baseUrl: string;
@@ -37,7 +54,6 @@ export interface WhoamiWorkspace {
37
54
  export interface CapabilityRunBody {
38
55
  params: Record<string, unknown>;
39
56
  mode?: 'smoke_test' | 'dry_run' | 'live';
40
- agent_session_id?: string;
41
57
  approved?: boolean;
42
58
  max_credits?: number;
43
59
  [key: string]: unknown;
@@ -71,6 +87,8 @@ export declare class CliError extends Error {
71
87
  /** The server's retry decision and repair, forwarded unchanged so the CLI never re-derives them. */
72
88
  readonly retryable?: boolean;
73
89
  readonly repair?: unknown;
90
+ /** The server's own envelope meta (trace_id, server_version, ...), kept whole so a refusal prints what the server said. */
91
+ readonly meta?: Record<string, unknown>;
74
92
  constructor(message: string, code: string, status: number, options?: {
75
93
  details?: unknown;
76
94
  retryAfter?: string;
@@ -78,8 +96,18 @@ export declare class CliError extends Error {
78
96
  idempotencyKey?: string;
79
97
  retryable?: boolean;
80
98
  repair?: unknown;
99
+ meta?: Record<string, unknown>;
81
100
  });
82
101
  }
102
+ /**
103
+ * Release identity from one response, preferring the JSON envelope and falling
104
+ * back to the X-Dreamstate-* headers. Success and error envelopes carry it
105
+ * alike (contract C2), so this runs on both.
106
+ */
107
+ export declare function readServerReleaseInfo(payload: unknown, headers?: Headers): ServerReleaseInfo;
108
+ /** How far this CLI is from the server it just talked to. */
109
+ export type VersionSkew = 'compatible' | 'cli_behind_server' | 'cli_below_minimum' | 'unknown';
110
+ export declare function describeVersionSkew(info: ServerReleaseInfo, cliVersion?: string): VersionSkew;
83
111
  export declare function readToolEnvelopeTraceId(value: unknown): string | undefined;
84
112
  export declare function requestDeviceAuthorization(baseUrl: string, body: {
85
113
  state: string;
@@ -96,6 +124,9 @@ export declare class DreamstateClient {
96
124
  private readonly workspace?;
97
125
  private readonly requestTimeoutMs?;
98
126
  private readonly onVersionWarning?;
127
+ private releaseInfo;
128
+ /** Release identity from the most recent response, success or error. */
129
+ get serverInfo(): ServerReleaseInfo;
99
130
  constructor(options: DreamstateClientOptions);
100
131
  getWhoami(): Promise<unknown>;
101
132
  /** Status reports server compatibility, including a requirement this CLI cannot satisfy. */
@@ -113,9 +144,9 @@ export declare class DreamstateClient {
113
144
  runCapability(capabilityId: string, body: CapabilityRunBody, idempotencyKey?: string | null): Promise<unknown>;
114
145
  getRun(id: string): Promise<unknown>;
115
146
  listRuns(query?: Record<string, unknown>): Promise<unknown>;
116
- resumeRun(id: string, body: Record<string, unknown>, idempotencyKey?: string): Promise<unknown>;
117
147
  getRunEvents(id: string, query?: Record<string, unknown>): Promise<unknown>;
118
148
  cancelRun(id: string, body: Record<string, unknown>, idempotencyKey?: string): Promise<unknown>;
149
+ private noteServerInfo;
119
150
  private request;
120
151
  }
121
152
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/client.js CHANGED
@@ -1,15 +1,26 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DreamstateClient = exports.CliError = exports.TOOL_AND_RUN_REQUEST_TIMEOUT_MS = exports.DEFAULT_REQUEST_TIMEOUT_MS = exports.CLI_VERSION = void 0;
3
+ exports.DreamstateClient = exports.CliError = exports.TOOL_AND_RUN_REQUEST_TIMEOUT_MS = exports.DEFAULT_REQUEST_TIMEOUT_MS = exports.CLI_UPDATE_COMMAND = exports.CLI_VERSION = void 0;
4
+ exports.readServerReleaseInfo = readServerReleaseInfo;
5
+ exports.describeVersionSkew = describeVersionSkew;
4
6
  exports.readToolEnvelopeTraceId = readToolEnvelopeTraceId;
5
7
  exports.requestDeviceAuthorization = requestDeviceAuthorization;
6
8
  exports.claimDeviceAuthorization = claimDeviceAuthorization;
7
- const node_crypto_1 = require("node:crypto");
9
+ const idempotency_1 = require("./idempotency");
10
+ const errors_1 = require("./errors");
11
+ const registryManifest_1 = require("./registryManifest");
8
12
  exports.CLI_VERSION = require('../package.json').version;
13
+ /** Command that updates the CLI. One constant so every surface prints the same one. */
14
+ exports.CLI_UPDATE_COMMAND = 'npm install -g @trydreamstate/cli@latest';
9
15
  exports.DEFAULT_REQUEST_TIMEOUT_MS = 15_000;
10
16
  exports.TOOL_AND_RUN_REQUEST_TIMEOUT_MS = 60_000;
11
- /** Server workspace refusals rewritten so the message says what to run next. */
12
- const WORKSPACE_ERROR_MESSAGES = {
17
+ /**
18
+ * Next steps for server workspace refusals. The server's message is forwarded
19
+ * unchanged; the CLI's own guidance travels beside it as details.cli_hint, so
20
+ * an agent reading either surface sees the same message and a script can tell
21
+ * what the server said from what the CLI added.
22
+ */
23
+ const WORKSPACE_ERROR_HINTS = {
13
24
  workspace_required: 'No workspace is selected. Run dreamstate workspaces list, then dreamstate workspaces use <workspace> (or pass --workspace <id|slug>).',
14
25
  workspace_forbidden: 'You are not a member of that workspace. Run dreamstate workspaces list to see the workspaces you can use, then dreamstate workspaces use <workspace>.',
15
26
  workspace_scoped_credential: 'This key is bound to one workspace. Run dreamstate login for a user session that can switch, or remove --workspace and DREAMSTATE_WORKSPACE.',
@@ -24,6 +35,8 @@ class CliError extends Error {
24
35
  /** The server's retry decision and repair, forwarded unchanged so the CLI never re-derives them. */
25
36
  retryable;
26
37
  repair;
38
+ /** The server's own envelope meta (trace_id, server_version, ...), kept whole so a refusal prints what the server said. */
39
+ meta;
27
40
  constructor(message, code, status, options = {}) {
28
41
  super(message);
29
42
  this.name = 'CliError';
@@ -41,9 +54,52 @@ class CliError extends Error {
41
54
  this.retryable = options.retryable;
42
55
  if (options.repair !== undefined)
43
56
  this.repair = options.repair;
57
+ else if (code in errors_1.CLI_LOCAL_ERROR_REPAIRS)
58
+ this.repair = errors_1.CLI_LOCAL_ERROR_REPAIRS[code];
59
+ if (options.meta !== undefined)
60
+ this.meta = options.meta;
44
61
  }
45
62
  }
46
63
  exports.CliError = CliError;
64
+ function objectRecord(value) {
65
+ return value && typeof value === 'object' && !Array.isArray(value) ? value : undefined;
66
+ }
67
+ function metaRecord(payload) {
68
+ return objectRecord(objectRecord(payload)?.meta);
69
+ }
70
+ function nonEmptyString(value) {
71
+ return typeof value === 'string' && value.trim() ? value.trim() : null;
72
+ }
73
+ /**
74
+ * Release identity from one response, preferring the JSON envelope and falling
75
+ * back to the X-Dreamstate-* headers. Success and error envelopes carry it
76
+ * alike (contract C2), so this runs on both.
77
+ */
78
+ function readServerReleaseInfo(payload, headers) {
79
+ const meta = metaRecord(payload);
80
+ const header = (name) => nonEmptyString(typeof headers?.get === 'function' ? headers.get(name) : null);
81
+ const data = objectRecord(objectRecord(payload)?.data);
82
+ return {
83
+ server_version: nonEmptyString(meta?.server_version) ?? header('X-Dreamstate-Server-Version'),
84
+ minimum_cli_version: nonEmptyString(meta?.minimum_cli_version) ?? header('X-Dreamstate-Minimum-Cli-Version'),
85
+ release_sha: nonEmptyString(meta?.release_sha) ?? header('X-Dreamstate-Release-Sha'),
86
+ registry_hash: nonEmptyString(meta?.registry_hash) ?? nonEmptyString(data?.registry_hash) ?? header('X-Dreamstate-Registry-Hash'),
87
+ };
88
+ }
89
+ function describeVersionSkew(info, cliVersion = exports.CLI_VERSION) {
90
+ if (info.minimum_cli_version && isVersionGreater(info.minimum_cli_version, cliVersion))
91
+ return 'cli_below_minimum';
92
+ if (info.server_version && isVersionGreater(info.server_version, cliVersion))
93
+ return 'cli_behind_server';
94
+ return info.server_version || info.minimum_cli_version ? 'compatible' : 'unknown';
95
+ }
96
+ function updateRequiredError(minimum, cliVersion, status, details, meta) {
97
+ return new CliError(`CLI ${minimum} or newer is required (this is ${cliVersion}). Run: ${exports.CLI_UPDATE_COMMAND}`, 'cli_update_required', status, {
98
+ details: { ...details, minimum_cli_version: minimum, cli_version: cliVersion, update_command: exports.CLI_UPDATE_COMMAND },
99
+ retryable: false,
100
+ ...(meta ? { meta } : {}),
101
+ });
102
+ }
47
103
  function isApiErrorBody(value) {
48
104
  const error = value && typeof value === 'object' ? value.error : null;
49
105
  if (!error || typeof error !== 'object')
@@ -110,24 +166,61 @@ function waitForRetryAfter(value) {
110
166
  function versionAtMost(current, target) {
111
167
  return !isVersionGreater(current, target);
112
168
  }
113
- function responseError(payload, status) {
114
- if (isApiErrorBody(payload)) {
115
- return new CliError(payload.error.message, payload.error.code, status, {
116
- details: payload.error.details,
117
- ...(typeof payload.error.retryable === 'boolean'
118
- ? { retryable: payload.error.retryable }
119
- : {}),
120
- ...(payload.error.repair && typeof payload.error.repair === 'object'
121
- ? { repair: payload.error.repair }
122
- : {}),
169
+ function errorEnvelope(payload) {
170
+ return isApiErrorBody(payload) ? payload : null;
171
+ }
172
+ /**
173
+ * The one parser for an error envelope. request() and the public login
174
+ * requests both use it, so rate-limit receipts, cli_update_required, repair,
175
+ * trace, meta and the idempotency key are not a second copy.
176
+ */
177
+ function cliErrorFromEnvelope(payload, status, extras = {}) {
178
+ const meta = metaRecord(payload);
179
+ const envelope = errorEnvelope(payload);
180
+ if (envelope) {
181
+ const retryAfterValue = extras.response ? retryAfter(extras.response, envelope) : undefined;
182
+ const repair = envelope.error.repair && typeof envelope.error.repair === 'object' ? { repair: envelope.error.repair } : {};
183
+ if (envelope.error.code === 'cli_update_required') {
184
+ const minimum = extras.info?.minimum_cli_version ?? '';
185
+ const serverDetails = envelope.error.details;
186
+ return new CliError(envelope.error.message, 'cli_update_required', status, {
187
+ details: {
188
+ ...(serverDetails && typeof serverDetails === 'object' && !Array.isArray(serverDetails) ? serverDetails : {}),
189
+ ...(minimum ? { minimum_cli_version: minimum } : {}),
190
+ cli_version: exports.CLI_VERSION,
191
+ update_command: exports.CLI_UPDATE_COMMAND,
192
+ },
193
+ retryAfter: retryAfterValue,
194
+ traceId: readToolEnvelopeTraceId(payload),
195
+ idempotencyKey: extras.idempotencyKey,
196
+ retryable: false,
197
+ ...repair,
198
+ ...(meta ? { meta } : {}),
199
+ });
200
+ }
201
+ const hint = WORKSPACE_ERROR_HINTS[envelope.error.code];
202
+ const serverDetails = envelope.error.details;
203
+ return new CliError(envelope.error.message, envelope.error.code, status, {
204
+ ...(hint
205
+ ? { details: { ...(serverDetails && typeof serverDetails === 'object' && !Array.isArray(serverDetails) ? serverDetails : {}), cli_hint: hint } }
206
+ : { details: serverDetails }),
207
+ retryAfter: retryAfterValue,
208
+ traceId: readToolEnvelopeTraceId(payload),
209
+ idempotencyKey: extras.idempotencyKey,
210
+ ...(typeof envelope.error.retryable === 'boolean' ? { retryable: envelope.error.retryable } : {}),
211
+ ...repair,
212
+ ...(meta ? { meta } : {}),
123
213
  });
124
214
  }
125
215
  const error = payload && typeof payload === 'object' ? payload.error : null;
126
- if (error &&
127
- typeof error === 'object' &&
128
- typeof error.code === 'string') {
216
+ if (error && typeof error === 'object' && typeof error.code === 'string') {
129
217
  const code = error.code;
130
- return new CliError(code, code, status);
218
+ const message = typeof error.message === 'string' ? error.message : code;
219
+ return new CliError(message, code, status, {
220
+ idempotencyKey: extras.idempotencyKey,
221
+ traceId: readToolEnvelopeTraceId(payload),
222
+ ...(meta ? { meta } : {}),
223
+ });
131
224
  }
132
225
  return null;
133
226
  }
@@ -166,7 +259,7 @@ async function requestPublic(baseUrl, path, init) {
166
259
  catch {
167
260
  throw new CliError(`Dreamstate API returned invalid JSON (HTTP ${response.status})`, 'invalid_response', response.status);
168
261
  }
169
- const apiError = responseError(payload, response.status);
262
+ const apiError = cliErrorFromEnvelope(payload, response.status, { response });
170
263
  if (apiError)
171
264
  throw apiError;
172
265
  if (!response.ok)
@@ -182,6 +275,11 @@ class DreamstateClient {
182
275
  workspace;
183
276
  requestTimeoutMs;
184
277
  onVersionWarning;
278
+ releaseInfo = { server_version: null, minimum_cli_version: null, release_sha: null, registry_hash: null };
279
+ /** Release identity from the most recent response, success or error. */
280
+ get serverInfo() {
281
+ return { ...this.releaseInfo };
282
+ }
185
283
  constructor(options) {
186
284
  this.apiKey = options.apiKey;
187
285
  this.baseUrl = options.baseUrl.replace(/\/+$/, '');
@@ -240,25 +338,28 @@ class DreamstateClient {
240
338
  listRuns(query = {}) {
241
339
  return this.request(`/runs${queryString(query)}`, {}, exports.TOOL_AND_RUN_REQUEST_TIMEOUT_MS);
242
340
  }
243
- resumeRun(id, body, idempotencyKey) {
244
- const key = idempotencyKey ?? (0, node_crypto_1.randomUUID)();
245
- return this.request(`/runs/${encodeURIComponent(id)}/resume`, {
246
- method: 'POST',
247
- body: JSON.stringify(body),
248
- headers: { 'Idempotency-Key': key },
249
- }, exports.TOOL_AND_RUN_REQUEST_TIMEOUT_MS);
250
- }
251
341
  getRunEvents(id, query = {}) {
252
342
  return this.request(`/runs/${encodeURIComponent(id)}/events${queryString(query)}`);
253
343
  }
254
344
  cancelRun(id, body, idempotencyKey) {
255
- const key = idempotencyKey ?? (0, node_crypto_1.randomUUID)();
345
+ // A re-run of the same cancel presents the same key, so a cancel whose reply was
346
+ // lost replays instead of racing the run's own state version.
347
+ const key = idempotencyKey ?? (0, idempotency_1.deterministicIdempotencyKey)({ scope: 'runs.cancel', workspace: this.workspace, body: { run_id: id, ...body } });
256
348
  return this.request(`/runs/${encodeURIComponent(id)}/cancel`, {
257
349
  method: 'POST',
258
350
  body: JSON.stringify(body),
259
- ...(key ? { headers: { 'Idempotency-Key': key } } : {}),
351
+ headers: { 'Idempotency-Key': key },
260
352
  });
261
353
  }
354
+ noteServerInfo(info) {
355
+ (0, registryManifest_1.noteRegistryHash)(info.registry_hash);
356
+ this.releaseInfo = {
357
+ server_version: info.server_version ?? this.releaseInfo.server_version,
358
+ minimum_cli_version: info.minimum_cli_version ?? this.releaseInfo.minimum_cli_version,
359
+ release_sha: info.release_sha ?? this.releaseInfo.release_sha,
360
+ registry_hash: info.registry_hash ?? this.releaseInfo.registry_hash,
361
+ };
362
+ }
262
363
  async request(path, init = {}, defaultTimeoutMs = exports.DEFAULT_REQUEST_TIMEOUT_MS, allowIncompatibleCli = false) {
263
364
  const requestTimeoutMs = this.requestTimeoutMs ?? defaultTimeoutMs;
264
365
  let response;
@@ -283,9 +384,9 @@ class DreamstateClient {
283
384
  }
284
385
  catch (error) {
285
386
  if (controller.signal.aborted) {
286
- throw new CliError(`Request timed out after ${requestTimeoutMs}ms`, 'request_timeout', 0, { idempotencyKey });
387
+ throw new CliError(errors_1.CLI_LOCAL_ERROR_CODES.request_timeout, 'request_timeout', 0, { idempotencyKey, repair: errors_1.CLI_LOCAL_ERROR_REPAIRS.request_timeout });
287
388
  }
288
- throw new CliError(`Request failed: ${error instanceof Error ? error.message : String(error)}`, 'network_error', 0);
389
+ throw new CliError(`Request failed: ${error instanceof Error ? error.message : String(error)}`, 'network_error', 0, { repair: errors_1.CLI_LOCAL_ERROR_REPAIRS.network_error });
289
390
  }
290
391
  finally {
291
392
  clearTimeout(timeout);
@@ -295,48 +396,38 @@ class DreamstateClient {
295
396
  payload = await response.json();
296
397
  }
297
398
  catch {
298
- throw new CliError(`Dreamstate API returned invalid JSON (HTTP ${response.status})`, 'invalid_response', response.status);
399
+ this.noteServerInfo(readServerReleaseInfo(undefined, response.headers));
400
+ throw new CliError(`Dreamstate API returned invalid JSON (HTTP ${response.status})`, 'invalid_response', response.status, { idempotencyKey, repair: errors_1.CLI_LOCAL_ERROR_REPAIRS.invalid_response });
299
401
  }
300
- if (isApiErrorBody(payload)) {
301
- const retryAfterValue = retryAfter(response, payload);
302
- if (!retriedRateLimit &&
303
- response.status === 429 &&
304
- retryAfterValue &&
305
- retryAfterDelayMs(retryAfterValue) !== null) {
402
+ const info = readServerReleaseInfo(payload, response.headers);
403
+ this.noteServerInfo(info);
404
+ const meta = metaRecord(payload);
405
+ const envelopeError = errorEnvelope(payload);
406
+ if (envelopeError && response.status === 429 && !retriedRateLimit) {
407
+ const retryAfterValue = retryAfter(response, envelopeError);
408
+ if (retryAfterValue && retryAfterDelayMs(retryAfterValue) !== null) {
306
409
  retriedRateLimit = true;
307
410
  await waitForRetryAfter(retryAfterValue);
308
411
  continue;
309
412
  }
310
- throw new CliError(WORKSPACE_ERROR_MESSAGES[payload.error.code] ?? payload.error.message, payload.error.code, response.status, {
311
- details: payload.error.details,
312
- retryAfter: retryAfterValue,
313
- traceId: readToolEnvelopeTraceId(payload),
314
- idempotencyKey,
315
- ...(typeof payload.error.retryable === 'boolean'
316
- ? { retryable: payload.error.retryable }
317
- : {}),
318
- ...(payload.error.repair && typeof payload.error.repair === 'object'
319
- ? { repair: payload.error.repair }
320
- : {}),
321
- });
322
413
  }
414
+ const parsed = cliErrorFromEnvelope(payload, response.status, { idempotencyKey, response, info });
415
+ if (parsed)
416
+ throw parsed;
323
417
  if (!response.ok)
324
- throw new CliError(`Dreamstate API request failed (HTTP ${response.status})`, 'request_failed', response.status);
325
- const minimum = payload && typeof payload === 'object'
326
- ? payload.meta?.minimum_cli_version
327
- : undefined;
328
- if (!allowIncompatibleCli &&
329
- typeof minimum === 'string' &&
330
- isVersionGreater(minimum, exports.CLI_VERSION)) {
331
- throw new CliError(`CLI ${minimum} or newer is required. Run: npm install -g @trydreamstate/cli@latest`, 'cli_update_required', 0);
418
+ throw new CliError(`Dreamstate API request failed (HTTP ${response.status})`, 'request_failed', response.status, { idempotencyKey, ...(meta ? { meta } : {}) });
419
+ const minimum = info.minimum_cli_version;
420
+ if (!allowIncompatibleCli && minimum && isVersionGreater(minimum, exports.CLI_VERSION)) {
421
+ // A conforming server refuses first (C3), so reaching here means the
422
+ // request may already have executed. The body is kept in the error so a
423
+ // write's receipt is not lost behind the update notice.
424
+ throw updateRequiredError(minimum, exports.CLI_VERSION, 0, init.method && init.method !== 'GET' ? { response: payload } : undefined, meta);
332
425
  }
333
- const server = payload && typeof payload === 'object'
334
- ? payload.meta?.server_version
335
- : undefined;
336
- if (typeof server === 'string' &&
426
+ const server = info.server_version;
427
+ if (server &&
337
428
  isVersionGreater(server, exports.CLI_VERSION) &&
338
- (typeof minimum !== 'string' || versionAtMost(minimum, exports.CLI_VERSION))) {
339
- this.onVersionWarning?.(`Warning: CLI ${exports.CLI_VERSION} is behind server ${server}. Proceeding; server minimum is ${minimum ?? 'not declared'}.`);
429
+ (!minimum || versionAtMost(minimum, exports.CLI_VERSION))) {
430
+ this.onVersionWarning?.(`Warning: CLI ${exports.CLI_VERSION} is behind server ${server}. Proceeding; server minimum is ${minimum ?? 'not declared'}. Update: ${exports.CLI_UPDATE_COMMAND}`);
340
431
  }
341
432
  return payload;
342
433
  }