@trydreamstate/cli 1.3.6 → 1.3.8
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.
- package/README.md +1 -1
- package/agent-plugin/.claude-plugin/plugin.json +1 -1
- package/agent-plugin/.codex-plugin/plugin.json +1 -1
- package/agent-plugin/skills/crm/SKILL.md +2 -2
- package/agent-plugin/skills/diagnostics/SKILL.md +1 -1
- package/agent-plugin/skills/dreamstate/SKILL.md +4 -4
- package/agent-plugin/skills/facebook-posts/SKILL.md +46 -0
- package/agent-plugin/skills/first-win/SKILL.md +6 -6
- package/agent-plugin/skills/inbox-replies/SKILL.md +1 -1
- package/agent-plugin/skills/instagram-posts/SKILL.md +56 -0
- package/agent-plugin/skills/knowledge/SKILL.md +1 -1
- package/agent-plugin/skills/linkedin-posts/SKILL.md +1 -1
- package/agent-plugin/skills/linkedin-warm-signals/SKILL.md +1 -1
- package/agent-plugin/skills/list-building/SKILL.md +5 -2
- package/agent-plugin/skills/list-building/column-authoring.md +4 -0
- package/agent-plugin/skills/list-building/incoming-people.md +32 -0
- package/agent-plugin/skills/list-building/sourcing.md +8 -1
- package/agent-plugin/skills/outreach/SKILL.md +2 -1
- package/agent-plugin/skills/outreach/channels.md +3 -1
- package/agent-plugin/skills/outreach/enrollment.md +2 -0
- package/agent-plugin/skills/outreach/replies.md +2 -0
- package/agent-plugin/skills/outreach/steps-and-timing.md +5 -1
- package/agent-plugin/skills/plays/SKILL.md +1 -1
- package/agent-plugin/skills/reddit-posts/SKILL.md +1 -1
- package/agent-plugin/skills/skill-authoring/SKILL.md +6 -6
- package/agent-plugin/skills/social/SKILL.md +5 -1
- package/agent-plugin/skills/tiktok-posts/SKILL.md +51 -0
- package/agent-plugin/skills/visibility/SKILL.md +5 -1
- package/agent-plugin/skills/workflows/SKILL.md +3 -1
- package/agent-plugin/skills/workflows/lifecycle-and-enrollment.md +2 -0
- package/agent-plugin/skills/worksheet-tidy/SKILL.md +2 -2
- package/agent-plugin/skills/writing/SKILL.md +1 -1
- package/agent-plugin/skills/writing/publishing.md +1 -1
- package/agent-plugin/skills/writing/revision-and-voice.md +1 -1
- package/agent-plugin/skills/x-posts/SKILL.md +1 -1
- package/agent-plugin/skills/youtube-posts/SKILL.md +49 -0
- package/dist/agentGuidance.generated.json +4 -4
- package/dist/client.d.ts +6 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +35 -11
- package/dist/commandTable.d.ts +2 -2
- package/dist/commandTable.d.ts.map +1 -1
- package/dist/commandTable.js +5 -2
- package/dist/commands/genericPack.d.ts +13 -0
- package/dist/commands/genericPack.d.ts.map +1 -0
- package/dist/commands/genericPack.js +31 -0
- package/dist/commands/knowledge.d.ts +2 -0
- package/dist/commands/knowledge.d.ts.map +1 -0
- package/dist/commands/knowledge.js +6 -0
- package/dist/commands/shared.d.ts +3 -1
- package/dist/commands/shared.d.ts.map +1 -1
- package/dist/commands/shared.js +14 -5
- package/dist/commands/tables.d.ts +2 -0
- package/dist/commands/tables.d.ts.map +1 -0
- package/dist/commands/tables.js +6 -0
- package/dist/commands/unibox.d.ts +2 -0
- package/dist/commands/unibox.d.ts.map +1 -0
- package/dist/commands/unibox.js +6 -0
- package/dist/gatedRun.d.ts.map +1 -1
- package/dist/gatedRun.js +145 -54
- package/dist/generated/packVerbs.generated.json +332 -4
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +31 -3
- package/dist/money.d.ts +2 -1
- package/dist/money.d.ts.map +1 -1
- package/dist/money.js +22 -5
- package/dist/runWait.d.ts +1 -1
- package/dist/runWait.d.ts.map +1 -1
- package/dist/runWait.js +37 -5
- package/dist/tablesImport.d.ts.map +1 -1
- package/dist/tablesImport.js +15 -1
- package/dist/turnCache.d.ts +5 -1
- package/dist/turnCache.d.ts.map +1 -1
- package/dist/turnCache.js +5 -3
- package/package.json +3 -2
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var _a;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.runKnowledgeCommand = exports.parseKnowledgeCommand = exports.KNOWLEDGE_USAGE = exports.KNOWLEDGE_VERBS = void 0;
|
|
5
|
+
const genericPack_1 = require("./genericPack");
|
|
6
|
+
_a = (0, genericPack_1.packSurface)('knowledge'), exports.KNOWLEDGE_VERBS = _a.verbs, exports.KNOWLEDGE_USAGE = _a.usage, exports.parseKnowledgeCommand = _a.parse, exports.runKnowledgeCommand = _a.run;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { type CliCommand } from '../index';
|
|
2
2
|
import { type GatedRunContext } from '../gatedRun';
|
|
3
|
+
/** First-class CLI pack groups. sequences and workflows also carry the shared authoring kind. */
|
|
4
|
+
export type PackName = 'sequences' | 'workflows' | 'knowledge' | 'unibox' | 'tables';
|
|
3
5
|
export interface PackVerbSpec {
|
|
4
6
|
verb: string;
|
|
5
7
|
capabilityId: string;
|
|
@@ -18,7 +20,7 @@ export interface PackVerbSpec {
|
|
|
18
20
|
/** Local-only route; `init` accepts --name and --file without an API schema. */
|
|
19
21
|
local?: 'init';
|
|
20
22
|
}
|
|
21
|
-
export declare function buildPackParser(pack:
|
|
23
|
+
export declare function buildPackParser(pack: PackName, kind: 'sequence' | 'workflow' | undefined, specs: PackVerbSpec[], usage: string): (argv: string[]) => CliCommand;
|
|
22
24
|
/**
|
|
23
25
|
* A starter document written to disk, so authoring can begin from a file the way the
|
|
24
26
|
* rest of this pack now accepts one. It writes nothing to the workspace and calls no
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/commands/shared.ts"],"names":[],"mappings":"AAKA,OAAO,EAAc,KAAK,UAAU,EAAiC,MAAM,UAAU,CAAC;AAEtF,OAAO,EAA4B,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAS7E,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IACnC;;;;;;OAMG;IACH,UAAU,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC;IAClE,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA4CD,wBAAgB,eAAe,CAC7B,IAAI,EAAE,
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/commands/shared.ts"],"names":[],"mappings":"AAKA,OAAO,EAAc,KAAK,UAAU,EAAiC,MAAM,UAAU,CAAC;AAEtF,OAAO,EAA4B,KAAK,eAAe,EAAE,MAAM,aAAa,CAAC;AAS7E,iGAAiG;AACjG,MAAM,MAAM,QAAQ,GAAG,WAAW,GAAG,WAAW,GAAG,WAAW,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAErF,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IACnC;;;;;;OAMG;IACH,UAAU,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,EAAE,CAAC;IAClE,gFAAgF;IAChF,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA4CD,wBAAgB,eAAe,CAC7B,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,GAAC,UAAU,GAAC,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,MAAM,GAC1F,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,UAAU,CAsFhC;AAGD;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAKjG;AAED,wBAAgB,WAAW,CACzB,IAAI,EAAE,UAAU,GAAG,UAAU,EAC7B,OAAO,EAAE,UAAU,EACnB,MAAM,EAAE,MAAM,CAAC,cAAc,GAC5B,IAAI,CAuBN;AAYD,wBAAsB,cAAc,CAClC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,UAAU,EACnB,MAAM,EAAE,MAAM,CAAC,cAAc,GAC5B,OAAO,CAAC,IAAI,CAAC,CA6Df;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,MAAM,CAK3E"}
|
package/dist/commands/shared.js
CHANGED
|
@@ -132,7 +132,7 @@ function buildPackParser(pack, kind, specs, usage) {
|
|
|
132
132
|
// family-specific capabilities have strict schemas that do not declare it,
|
|
133
133
|
// so injecting it everywhere made every one of those verbs fail validation
|
|
134
134
|
// with an unrecognized key before it reached the server's real work.
|
|
135
|
-
if (spec.capabilityId.startsWith('workflow.automations.'))
|
|
135
|
+
if (kind !== undefined && spec.capabilityId.startsWith('workflow.automations.'))
|
|
136
136
|
input.kind = kind;
|
|
137
137
|
// No default mode. A mutating verb run with no mode used to be rewritten to dry_run
|
|
138
138
|
// silently, where `tools run` sends none and lets the server answer mode_required
|
|
@@ -238,10 +238,7 @@ async function runPackCommand(context, command, stdout) {
|
|
|
238
238
|
const outcome = await (0, gatedRun_1.runGated)(context, {
|
|
239
239
|
capabilityId: command.capabilityId,
|
|
240
240
|
body: {
|
|
241
|
-
params:
|
|
242
|
-
...command.input,
|
|
243
|
-
...(command.maxLiveSends === undefined ? {} : { max_live_sends: command.maxLiveSends }),
|
|
244
|
-
},
|
|
241
|
+
params: command.input,
|
|
245
242
|
...(command.mode ? { mode: command.mode } : {}),
|
|
246
243
|
...(maxCredits === undefined ? {} : { max_credits: maxCredits }),
|
|
247
244
|
...(command.approved ? { approved: true } : {}),
|
|
@@ -254,6 +251,18 @@ async function runPackCommand(context, command, stdout) {
|
|
|
254
251
|
waitTimeout: command.waitTimeout,
|
|
255
252
|
...(command.noWait ? { noWait: true } : {}),
|
|
256
253
|
coerceParams: true,
|
|
254
|
+
// max_live_sends is a capability param, not a door control. It belongs in
|
|
255
|
+
// params only where the live schema declares it; sequence lifecycle and
|
|
256
|
+
// enrollment capabilities (for example sequence.sequences.activate_audience)
|
|
257
|
+
// have a strict, cap-free schema, so injecting it there was refused before
|
|
258
|
+
// the request left the CLI.
|
|
259
|
+
...(command.maxLiveSends === undefined ? {} : { adjustParams: (params, capability) => {
|
|
260
|
+
const schema = capability?.input_json_schema;
|
|
261
|
+
const properties = schema && typeof schema === 'object' ? schema.properties : null;
|
|
262
|
+
return properties && typeof properties === 'object' && Object.prototype.hasOwnProperty.call(properties, 'max_live_sends')
|
|
263
|
+
? { ...params, max_live_sends: command.maxLiveSends }
|
|
264
|
+
: params;
|
|
265
|
+
} }),
|
|
257
266
|
});
|
|
258
267
|
const result = outcome.value;
|
|
259
268
|
if (outcome.timedOut)
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const TABLES_VERBS: import("./shared").PackVerbSpec[], TABLES_USAGE: string, parseTablesCommand: (argv: string[]) => import("..").CliCommand, runTablesCommand: (context: import("../gatedRun").GatedRunContext | undefined, command: import("..").CliCommand, stdout: NodeJS.WritableStream) => Promise<void>;
|
|
2
|
+
//# sourceMappingURL=tables.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tables.d.ts","sourceRoot":"","sources":["../../src/commands/tables.ts"],"names":[],"mappings":"AAEA,eAAO,MACE,YAAY,qCACZ,YAAY,UACZ,kBAAkB,+CACpB,gBAAgB,gJACE,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var _a;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.runTablesCommand = exports.parseTablesCommand = exports.TABLES_USAGE = exports.TABLES_VERBS = void 0;
|
|
5
|
+
const genericPack_1 = require("./genericPack");
|
|
6
|
+
_a = (0, genericPack_1.packSurface)('tables'), exports.TABLES_VERBS = _a.verbs, exports.TABLES_USAGE = _a.usage, exports.parseTablesCommand = _a.parse, exports.runTablesCommand = _a.run;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export declare const UNIBOX_VERBS: import("./shared").PackVerbSpec[], UNIBOX_USAGE: string, parseUniboxCommand: (argv: string[]) => import("..").CliCommand, runUniboxCommand: (context: import("../gatedRun").GatedRunContext | undefined, command: import("..").CliCommand, stdout: NodeJS.WritableStream) => Promise<void>;
|
|
2
|
+
//# sourceMappingURL=unibox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unibox.d.ts","sourceRoot":"","sources":["../../src/commands/unibox.ts"],"names":[],"mappings":"AAEA,eAAO,MACE,YAAY,qCACZ,YAAY,UACZ,kBAAkB,+CACpB,gBAAgB,gJACE,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var _a;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.runUniboxCommand = exports.parseUniboxCommand = exports.UNIBOX_USAGE = exports.UNIBOX_VERBS = void 0;
|
|
5
|
+
const genericPack_1 = require("./genericPack");
|
|
6
|
+
_a = (0, genericPack_1.packSurface)('unibox'), exports.UNIBOX_VERBS = _a.verbs, exports.UNIBOX_USAGE = _a.usage, exports.parseUniboxCommand = _a.parse, exports.runUniboxCommand = _a.run;
|
package/dist/gatedRun.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gatedRun.d.ts","sourceRoot":"","sources":["../src/gatedRun.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAA0B,KAAK,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAEnF,OAAO,EAA4F,KAAK,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAoBnJ,wBAAgB,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAIvD;AAUD,4FAA4F;AAC5F,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAKjF;AAgBD;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,mBAAmB,GAAG,MAAM,GAAG,IAAI,CAKrI;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,SAAS,CAKzF;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,QAAQ,GAAG,IAAI,CAazF;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAMrE;
|
|
1
|
+
{"version":3,"file":"gatedRun.d.ts","sourceRoot":"","sources":["../src/gatedRun.ts"],"names":[],"mappings":"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"}
|
package/dist/gatedRun.js
CHANGED
|
@@ -121,7 +121,19 @@ function planFingerprint(body) {
|
|
|
121
121
|
delete params[key];
|
|
122
122
|
return (0, node_crypto_1.createHash)('sha256').update((0, idempotency_1.stableJson)({ params, max_credits: body.max_credits ?? null })).digest('hex');
|
|
123
123
|
}
|
|
124
|
-
|
|
124
|
+
function creditsPhrase(estimate) {
|
|
125
|
+
if (!estimate)
|
|
126
|
+
return null;
|
|
127
|
+
const { minimum_credits: minimum, maximum_credits: maximum, expected_credits: expected } = estimate;
|
|
128
|
+
if (typeof minimum === 'number' && typeof maximum === 'number' && minimum !== maximum)
|
|
129
|
+
return `${minimum}..${maximum} credits`;
|
|
130
|
+
if (typeof minimum !== 'number' && typeof maximum === 'number')
|
|
131
|
+
return `up to ${maximum} credits`;
|
|
132
|
+
if (typeof expected === 'number')
|
|
133
|
+
return `${expected} credits`;
|
|
134
|
+
return typeof maximum === 'number' ? `${maximum} credits` : null;
|
|
135
|
+
}
|
|
136
|
+
/** The quote a supported rehearsal returned, wherever the envelope nests its outputs. */
|
|
125
137
|
function quoteFromResult(value, depth = 0) {
|
|
126
138
|
if (!value || typeof value !== 'object' || depth > 6)
|
|
127
139
|
return null;
|
|
@@ -135,10 +147,14 @@ function quoteFromResult(value, depth = 0) {
|
|
|
135
147
|
}
|
|
136
148
|
const entry = value;
|
|
137
149
|
if (typeof entry.quote_hash === 'string' && runContract_1.QUOTE_HASH_PATTERN.test(entry.quote_hash)) {
|
|
138
|
-
const estimate = entry.
|
|
150
|
+
const estimate = record(entry.credit_estimate) ?? record(entry.estimate);
|
|
151
|
+
const affected = record(entry.affected_count);
|
|
152
|
+
const rows = affected?.rows ?? affected?.row_or_recipient_count;
|
|
139
153
|
return {
|
|
140
154
|
quote_hash: entry.quote_hash,
|
|
141
155
|
maximum_credits: typeof estimate?.maximum_credits === 'number' ? estimate.maximum_credits : null,
|
|
156
|
+
rows: typeof rows === 'number' ? rows : null,
|
|
157
|
+
credits: creditsPhrase(estimate),
|
|
142
158
|
};
|
|
143
159
|
}
|
|
144
160
|
for (const key of ['data', 'run', 'outputs', 'steps']) {
|
|
@@ -148,19 +164,20 @@ function quoteFromResult(value, depth = 0) {
|
|
|
148
164
|
}
|
|
149
165
|
return null;
|
|
150
166
|
}
|
|
151
|
-
function quotePriced(capabilityId, body,
|
|
167
|
+
function quotePriced(capabilityId, body, price, rehearsal = 'dry_run') {
|
|
152
168
|
const params = body.params && typeof body.params === 'object' ? body.params : {};
|
|
153
|
-
const
|
|
154
|
-
const
|
|
155
|
-
|
|
169
|
+
const rowCount = price.rows ?? (typeof params.max_rows === 'number' ? params.max_rows : null);
|
|
170
|
+
const rows = rowCount === null ? 'rows not stated' : `${rowCount} rows`;
|
|
171
|
+
const credits = price.credits ?? 'credits not stated';
|
|
172
|
+
const name = rehearsal === 'smoke_test' ? 'Smoke test' : rehearsal === 'dry_run' ? 'Dry run' : 'Rehearsal';
|
|
173
|
+
return `${name} of ${capabilityId} priced: ${rows}, ${credits}.`;
|
|
156
174
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
return true;
|
|
175
|
+
function rehearsalMode(fetched) {
|
|
176
|
+
const contract = record(capabilityRecord(fetched)?.execution_mode_contract);
|
|
177
|
+
const supported = Array.isArray(contract?.supported_modes) ? contract.supported_modes : [];
|
|
178
|
+
if (supported.includes('dry_run'))
|
|
179
|
+
return 'dry_run';
|
|
180
|
+
return supported.includes('smoke_test') ? 'smoke_test' : null;
|
|
164
181
|
}
|
|
165
182
|
const CREDENTIALS_REQUIRED_SENTENCE = 'A connected credential is required before this run can continue.';
|
|
166
183
|
function readinessRecord(value) {
|
|
@@ -246,6 +263,41 @@ function readinessRefusal(value) {
|
|
|
246
263
|
const code = credentials ? 'credentials_required' : codes[0] ?? 'not_ready';
|
|
247
264
|
return new client_1.CliError(sentence, code, 409, { retryable: false });
|
|
248
265
|
}
|
|
266
|
+
const UNSUCCESSFUL_TERMINAL_RUN_STATUSES = new Set(['failed', 'completed_with_errors', 'partially_completed']);
|
|
267
|
+
/**
|
|
268
|
+
* A runs.get HTTP 200 says read succeeded, not that durable work succeeded.
|
|
269
|
+
* Keep the terminal receipt in error details so callers can inspect or resume
|
|
270
|
+
* without treating a failed run as a successful CLI command.
|
|
271
|
+
*/
|
|
272
|
+
function terminalRunOutcomeRefusal(value) {
|
|
273
|
+
const root = readinessRecord(value);
|
|
274
|
+
const data = readinessRecord(root?.data) ?? root;
|
|
275
|
+
const run = readinessRecord(data?.run);
|
|
276
|
+
const status = typeof run?.status === 'string' ? run.status : null;
|
|
277
|
+
if (!run || !status || !UNSUCCESSFUL_TERMINAL_RUN_STATUSES.has(status))
|
|
278
|
+
return null;
|
|
279
|
+
const runId = typeof run.run_id === 'string' ? run.run_id : typeof run.id === 'string' ? run.id : null;
|
|
280
|
+
const stepErrors = Array.isArray(run.steps)
|
|
281
|
+
? run.steps.flatMap((step) => {
|
|
282
|
+
const record = readinessRecord(step);
|
|
283
|
+
return [readinessRecord(record?.error), readinessRecord(record?.user_error)];
|
|
284
|
+
})
|
|
285
|
+
: [];
|
|
286
|
+
const typedError = [readinessRecord(run.error), readinessRecord(run.user_error), ...stepErrors]
|
|
287
|
+
.find((error) => typeof error?.code === 'string' && typeof error.message === 'string');
|
|
288
|
+
const typedDetails = readinessRecord(typedError?.details);
|
|
289
|
+
const details = {
|
|
290
|
+
...(typedDetails ?? {}),
|
|
291
|
+
...(typedError?.details !== undefined && !typedDetails ? { run_error_details: typedError.details } : {}),
|
|
292
|
+
...(runId ? { run_id: runId } : {}),
|
|
293
|
+
status,
|
|
294
|
+
};
|
|
295
|
+
return new client_1.CliError(typeof typedError?.message === 'string' ? typedError.message : `Run${runId ? ` ${runId}` : ''} ended with status ${status}.`, typeof typedError?.code === 'string' ? typedError.code : 'run_failed', typeof typedError?.http_status === 'number' ? typedError.http_status : 409, {
|
|
296
|
+
details,
|
|
297
|
+
retryable: typeof typedError?.retryable === 'boolean' ? typedError.retryable : false,
|
|
298
|
+
...(typedError?.repair !== undefined ? { repair: typedError.repair } : {}),
|
|
299
|
+
});
|
|
300
|
+
}
|
|
249
301
|
/** Adds the idempotency key to the printed meta, so a user can see which key to re-run with. */
|
|
250
302
|
function withIdempotencyMeta(value, key) {
|
|
251
303
|
const envelope = record(value);
|
|
@@ -288,10 +340,10 @@ async function runGated(context, input) {
|
|
|
288
340
|
if (params)
|
|
289
341
|
body.params = params;
|
|
290
342
|
}
|
|
291
|
-
// A
|
|
292
|
-
// and
|
|
293
|
-
// only while a quote is pending, together with
|
|
294
|
-
//
|
|
343
|
+
// A quote-bound live run needs the quote_hash of a supported rehearsal of
|
|
344
|
+
// the same input, and the quote is bound to the turn that asked for it. So a
|
|
345
|
+
// turn is reused only while a quote is pending, together with that quote,
|
|
346
|
+
// and forgotten once the live run is admitted.
|
|
295
347
|
const explicitKey = parameterIdempotencyKey(body) ?? input.idempotencyKey;
|
|
296
348
|
const fingerprint = planFingerprint(body);
|
|
297
349
|
const cached = input.turnToken
|
|
@@ -305,7 +357,7 @@ async function runGated(context, input) {
|
|
|
305
357
|
const inlineFromCache = !input.turnToken && !pending && !explicitKey && cachedPosture?.inlineRead === true;
|
|
306
358
|
if (!input.turnToken && !pending && !inlineFromCache)
|
|
307
359
|
await contract();
|
|
308
|
-
|
|
360
|
+
let posture = fetched ? (0, capabilityPosture_1.postureFromContract)(fetched) : cachedPosture;
|
|
309
361
|
if (fetched && posture)
|
|
310
362
|
(0, registryManifest_1.rememberPosture)(capabilityId, posture);
|
|
311
363
|
const refusal = fetched ? cliSurfaceRefusal(capabilityId, fetched) : null;
|
|
@@ -319,11 +371,13 @@ async function runGated(context, input) {
|
|
|
319
371
|
let quoteHash = explicitQuote
|
|
320
372
|
? body.quote_hash
|
|
321
373
|
: live ? cached?.quote_hash ?? undefined : undefined;
|
|
322
|
-
//
|
|
323
|
-
|
|
324
|
-
let
|
|
374
|
+
// The price of the quote in hand. A cached quote prices this input only when it
|
|
375
|
+
// is the quote named (explicit --quote-hash) or the quote this input was dry run for.
|
|
376
|
+
let quotedPrice = cached?.quote_hash && (!explicitQuote || cached.quote_hash === body.quote_hash)
|
|
377
|
+
? { quote_hash: cached.quote_hash, maximum_credits: cached.maximum_credits, rows: cached.rows ?? null, credits: cached.credits ?? null }
|
|
378
|
+
: null;
|
|
379
|
+
let ranRehearsal = false;
|
|
325
380
|
let sentKey = null;
|
|
326
|
-
const approvalRequired = () => new client_1.CliError('This run spends credits. Rerun the same command with --approved.', 'approval_required', 409, { retryable: false, repair: { kind: 'ask_user', hint: 'Rerun the same command with --approved.' } });
|
|
327
381
|
const requestBody = () => ({
|
|
328
382
|
...body,
|
|
329
383
|
...(turnToken ? { tool_turn_token: turnToken } : {}),
|
|
@@ -353,23 +407,48 @@ async function runGated(context, input) {
|
|
|
353
407
|
sentKey = await keyFor(sent);
|
|
354
408
|
return client.runCapability(capabilityId, sent, sentKey);
|
|
355
409
|
};
|
|
410
|
+
let retriedCapabilityDigestStale = false;
|
|
411
|
+
const refreshCapabilityAfterDigestStale = async () => {
|
|
412
|
+
retriedCapabilityDigestStale = true;
|
|
413
|
+
// A stale refusal is terminal for the original logical attempt. A new
|
|
414
|
+
// contract starts a fresh generated key, while a caller-supplied key keeps
|
|
415
|
+
// its explicit replay semantics.
|
|
416
|
+
if (attemptIdentity) {
|
|
417
|
+
await (0, idempotency_1.finishIdempotencyAttempt)(idempotencyPath, attemptIdentity);
|
|
418
|
+
attemptIdentity = null;
|
|
419
|
+
}
|
|
420
|
+
if (!input.turnToken) {
|
|
421
|
+
await (0, turnCache_1.forgetTurnToken)(context.turnsPath, context.baseUrl, context.turnKey, capabilityId, warnTurnCache);
|
|
422
|
+
}
|
|
423
|
+
fetched = await client.getTool(capabilityId);
|
|
424
|
+
posture = (0, capabilityPosture_1.postureFromContract)(fetched);
|
|
425
|
+
(0, registryManifest_1.rememberPosture)(capabilityId, posture);
|
|
426
|
+
const refreshedTurnToken = optionalToolTurnToken(fetched);
|
|
427
|
+
turnToken = refreshedTurnToken;
|
|
428
|
+
// A cached quote is bound to the stale turn. An explicitly supplied quote
|
|
429
|
+
// remains caller intent and the server decides whether it is still valid.
|
|
430
|
+
if (!explicitQuote) {
|
|
431
|
+
quoteHash = undefined;
|
|
432
|
+
quotedPrice = null;
|
|
433
|
+
}
|
|
434
|
+
};
|
|
356
435
|
let result;
|
|
357
436
|
try {
|
|
358
437
|
try {
|
|
359
438
|
if (live && quoteHash) {
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
}
|
|
365
|
-
if (body.approved === true || maximum === 0) {
|
|
366
|
-
stderr.write(`${quotePriced(capabilityId, body, { quote_hash: quoteHash, maximum_credits: maximum })}\nRunning live on that quote.\n`);
|
|
367
|
-
}
|
|
439
|
+
// The shared gateway owns per-call paid, external-effect and recurring
|
|
440
|
+
// consent. A positive quote alone does not require human approval.
|
|
441
|
+
// Forward only caller-supplied approval; preserve every server refusal.
|
|
442
|
+
stderr.write(`${quotePriced(capabilityId, body, quotedPrice ?? { rows: null, credits: null }, rehearsalMode(fetched))}\nRunning live on that quote.\n`);
|
|
368
443
|
}
|
|
369
444
|
result = await run();
|
|
370
445
|
}
|
|
371
446
|
catch (error) {
|
|
372
|
-
if (
|
|
447
|
+
if (code(error) === 'capability_digest_stale') {
|
|
448
|
+
await refreshCapabilityAfterDigestStale();
|
|
449
|
+
result = await run();
|
|
450
|
+
}
|
|
451
|
+
else if (!input.turnToken && code(error) === 'capability_not_fetched') {
|
|
373
452
|
// Capability posture can change between tools get and run. Refresh it
|
|
374
453
|
// once rather than maintaining a client-side list of token-free reads.
|
|
375
454
|
fetched = await client.getTool(capabilityId);
|
|
@@ -380,17 +459,18 @@ async function runGated(context, input) {
|
|
|
380
459
|
result = await run();
|
|
381
460
|
}
|
|
382
461
|
else if (live && code(error) === 'quote_required' && !quoteHash && turnToken) {
|
|
383
|
-
// A live
|
|
384
|
-
//
|
|
385
|
-
//
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
462
|
+
// A live quote is minted by the capability's advertised rehearsal.
|
|
463
|
+
// Most capabilities use dry_run; activation intentionally has only
|
|
464
|
+
// smoke_test and live, so never invent an unsupported dry_run mode.
|
|
465
|
+
const rehearsal = rehearsalMode(fetched);
|
|
466
|
+
if (!rehearsal)
|
|
467
|
+
throw error;
|
|
468
|
+
const rehearsalResult = await client.runCapability(capabilityId, {
|
|
389
469
|
...body,
|
|
390
|
-
mode:
|
|
470
|
+
mode: rehearsal,
|
|
391
471
|
tool_turn_token: turnToken,
|
|
392
472
|
}, null);
|
|
393
|
-
const quote = quoteFromResult(
|
|
473
|
+
const quote = quoteFromResult(rehearsalResult);
|
|
394
474
|
if (!quote)
|
|
395
475
|
throw error;
|
|
396
476
|
// The no-quote call was definitively refused before execution. Its
|
|
@@ -399,13 +479,11 @@ async function runGated(context, input) {
|
|
|
399
479
|
await (0, idempotency_1.finishIdempotencyAttempt)(idempotencyPath, attemptIdentity);
|
|
400
480
|
attemptIdentity = null;
|
|
401
481
|
}
|
|
402
|
-
|
|
482
|
+
ranRehearsal = true;
|
|
403
483
|
quoteHash = quote.quote_hash;
|
|
404
|
-
|
|
405
|
-
stderr.write(`${quotePriced(capabilityId, body, quote)}\n`);
|
|
406
|
-
await (0, turnCache_1.rememberTurnToken)(context.turnsPath, context.baseUrl, context.turnKey, capabilityId, turnToken, Date.now(), warnTurnCache, { quote_hash: quote.quote_hash, fingerprint, maximum_credits: quote.maximum_credits });
|
|
407
|
-
if (spendNeedsApproval(quote.maximum_credits, body.approved === true))
|
|
408
|
-
throw approvalRequired();
|
|
484
|
+
quotedPrice = quote;
|
|
485
|
+
stderr.write(`${quotePriced(capabilityId, body, quote, rehearsal)}\n`);
|
|
486
|
+
await (0, turnCache_1.rememberTurnToken)(context.turnsPath, context.baseUrl, context.turnKey, capabilityId, turnToken, Date.now(), warnTurnCache, { quote_hash: quote.quote_hash, fingerprint, maximum_credits: quote.maximum_credits, rows: quote.rows, credits: quote.credits });
|
|
409
487
|
stderr.write('Running live on that quote.\n');
|
|
410
488
|
result = await run();
|
|
411
489
|
}
|
|
@@ -421,19 +499,22 @@ async function runGated(context, input) {
|
|
|
421
499
|
if (code(error) === 'approval_required') {
|
|
422
500
|
stderr.write('This run needs a person\'s approval. Show them the rows and cost above; when they agree, rerun the same command with --approved.\n');
|
|
423
501
|
}
|
|
424
|
-
await (0, turnCache_1.rememberTurnToken)(context.turnsPath, context.baseUrl, context.turnKey, capabilityId, turnToken, Date.now(), warnTurnCache, quoteHash ? { quote_hash: quoteHash, fingerprint,
|
|
502
|
+
await (0, turnCache_1.rememberTurnToken)(context.turnsPath, context.baseUrl, context.turnKey, capabilityId, turnToken, Date.now(), warnTurnCache, quoteHash ? { quote_hash: quoteHash, fingerprint, maximum_credits: quotedPrice?.maximum_credits ?? null, rows: quotedPrice?.rows ?? null, credits: quotedPrice?.credits ?? null } : undefined);
|
|
425
503
|
}
|
|
426
504
|
// Only an unknown or transient result may resume an attempt. A server
|
|
427
505
|
// refusal with retryable:false is terminal and must receive a new key.
|
|
428
|
-
|
|
506
|
+
// A response body that cannot be parsed is an unknown-effect outcome: the
|
|
507
|
+
// server may have admitted the write before its reply was damaged. Keep the
|
|
508
|
+
// generated key so the unchanged retry can replay that exact attempt.
|
|
509
|
+
const transient = error instanceof client_1.CliError && (error.code === 'request_timeout' || error.code === 'network_error' || error.code === 'invalid_response' || error.retryable === true || error.status >= 500);
|
|
429
510
|
if (attemptIdentity && !transient)
|
|
430
511
|
await (0, idempotency_1.finishIdempotencyAttempt)(idempotencyPath, attemptIdentity);
|
|
431
512
|
throw error;
|
|
432
513
|
}
|
|
433
514
|
if (!input.turnToken) {
|
|
434
|
-
if (body.mode === 'dry_run' && turnToken) {
|
|
515
|
+
if ((body.mode === 'dry_run' || body.mode === 'smoke_test') && turnToken) {
|
|
435
516
|
const quote = quoteFromResult(result);
|
|
436
|
-
await (0, turnCache_1.rememberTurnToken)(context.turnsPath, context.baseUrl, context.turnKey, capabilityId, turnToken, Date.now(), warnTurnCache, quote ? { quote_hash: quote.quote_hash, fingerprint, maximum_credits: quote.maximum_credits } : undefined);
|
|
517
|
+
await (0, turnCache_1.rememberTurnToken)(context.turnsPath, context.baseUrl, context.turnKey, capabilityId, turnToken, Date.now(), warnTurnCache, quote ? { quote_hash: quote.quote_hash, fingerprint, maximum_credits: quote.maximum_credits, rows: quote.rows, credits: quote.credits } : undefined);
|
|
437
518
|
}
|
|
438
519
|
}
|
|
439
520
|
let timedOut = false;
|
|
@@ -442,23 +523,33 @@ async function runGated(context, input) {
|
|
|
442
523
|
result = waited.value;
|
|
443
524
|
timedOut = waited.timedOut;
|
|
444
525
|
}
|
|
526
|
+
let outcomeRefusal = refusalFromRunResult(result);
|
|
527
|
+
if (!retriedCapabilityDigestStale && code(outcomeRefusal) === 'capability_digest_stale') {
|
|
528
|
+
await refreshCapabilityAfterDigestStale();
|
|
529
|
+
result = await run();
|
|
530
|
+
if (!input.noWait && !posture?.returnsRunId) {
|
|
531
|
+
const waited = await (0, runWait_1.waitForRun)(client, result, input.waitTimeout, context.sleep);
|
|
532
|
+
result = waited.value;
|
|
533
|
+
timedOut = waited.timedOut;
|
|
534
|
+
}
|
|
535
|
+
outcomeRefusal = refusalFromRunResult(result);
|
|
536
|
+
}
|
|
445
537
|
// A timeout still owns the quote and the idempotency key. Forgetting the
|
|
446
538
|
// turn here made the rerun hash a body with no quote_hash and start a second run.
|
|
447
|
-
if (!input.turnToken && body.mode !== 'dry_run' && (pending ||
|
|
539
|
+
if (!input.turnToken && body.mode !== 'dry_run' && body.mode !== 'smoke_test' && (pending || ranRehearsal) && !timedOut) {
|
|
448
540
|
await (0, turnCache_1.forgetTurnToken)(context.turnsPath, context.baseUrl, context.turnKey, capabilityId, warnTurnCache);
|
|
449
541
|
}
|
|
450
542
|
// A run still active after waiting has unknown outcome; retain its key for
|
|
451
543
|
// the read-back/retry rule. A terminal response completes this attempt.
|
|
452
544
|
if (attemptIdentity && !timedOut)
|
|
453
545
|
await (0, idempotency_1.finishIdempotencyAttempt)(idempotencyPath, attemptIdentity);
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
throw blocked;
|
|
546
|
+
if (outcomeRefusal)
|
|
547
|
+
throw outcomeRefusal;
|
|
457
548
|
return { value: withIdempotencyMeta(result, explicitKey ? null : sentKey), timedOut, idempotencyKey: sentKey, turnToken: turnToken ?? null };
|
|
458
549
|
}
|
|
459
550
|
/** Blocker refusal for a run envelope that did not go through runGated (runs wait). */
|
|
460
551
|
function refusalFromRunResult(value) {
|
|
461
|
-
return readinessRefusal(value);
|
|
552
|
+
return readinessRefusal(value) ?? terminalRunOutcomeRefusal(value);
|
|
462
553
|
}
|
|
463
554
|
/** A read the CLI needs before it can form a write, run through the same gate as any other run. */
|
|
464
555
|
async function readCapability(context, capabilityId, params, waitTimeout) {
|