@oxygen-agent/cli 1.1011.687 → 1.1011.800
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/dist/column-run-notices.js +2 -0
- package/dist/help.d.ts +2 -0
- package/dist/help.js +5 -0
- package/dist/index.js +245 -158
- package/dist/workflow-run-list-flags.d.ts +3 -0
- package/dist/workflow-run-list-flags.js +21 -0
- package/node_modules/@oxygen/shared/dist/capability-discovery.js +65 -14
- package/node_modules/@oxygen/shared/dist/contracts/crm-enrichment-read.js +1 -1
- package/node_modules/@oxygen/shared/dist/contracts/crm-support.d.ts +1 -0
- package/node_modules/@oxygen/shared/dist/contracts/crm-support.js +1 -0
- package/node_modules/@oxygen/shared/dist/contracts/customer-operations.js +8 -6
- package/node_modules/@oxygen/shared/dist/contracts/operations.js +2 -1
- package/node_modules/@oxygen/shared/dist/contracts/schema.d.ts +8 -0
- package/node_modules/@oxygen/shared/dist/contracts/schema.js +6 -0
- package/node_modules/@oxygen/shared/dist/contracts/sequence-analytics-read.d.ts +38 -0
- package/node_modules/@oxygen/shared/dist/contracts/sequence-analytics-read.js +22 -0
- package/node_modules/@oxygen/shared/dist/contracts/table-feed-update.d.ts +222 -0
- package/node_modules/@oxygen/shared/dist/contracts/table-feed-update.js +55 -0
- package/node_modules/@oxygen/shared/dist/contracts/table-list.d.ts +31 -0
- package/node_modules/@oxygen/shared/dist/contracts/table-list.js +22 -0
- package/node_modules/@oxygen/shared/dist/contracts/table-operations.d.ts +58 -0
- package/node_modules/@oxygen/shared/dist/contracts/table-operations.js +30 -0
- package/node_modules/@oxygen/shared/dist/contracts/workflow-run-list.d.ts +79 -0
- package/node_modules/@oxygen/shared/dist/contracts/workflow-run-list.js +38 -0
- package/node_modules/@oxygen/shared/dist/copilot-journeys.d.ts +2 -2
- package/node_modules/@oxygen/shared/dist/copilot-journeys.generated.d.ts +2 -2
- package/node_modules/@oxygen/shared/dist/copilot-journeys.generated.js +2 -2
- package/node_modules/@oxygen/shared/dist/copilot-playbooks.generated.d.ts +3 -3
- package/node_modules/@oxygen/shared/dist/copilot-playbooks.generated.js +3 -3
- package/node_modules/@oxygen/shared/dist/hosted-ai.js +24 -0
- package/node_modules/@oxygen/shared/dist/recipes.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/recipes.js +4 -9
- package/node_modules/@oxygen/shared/dist/version.generated.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/version.generated.js +1 -1
- package/node_modules/@oxygen/workflows/dist/graph/expression.d.ts +1 -0
- package/node_modules/@oxygen/workflows/dist/graph/expression.js +15 -0
- package/node_modules/@oxygen/workflows/dist/graph/lint.js +8 -2
- package/package.json +1 -1
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** Native Table feed PATCH grammar. Scheduling and credit authority remain server-owned. */
|
|
2
|
+
import { arr, bool, enumOf, int, nullable, obj, str, validateContract } from "./schema.js";
|
|
3
|
+
const json = { type: "object", additionalProperties: true };
|
|
4
|
+
const path = () => nullable(str());
|
|
5
|
+
export const TABLE_FEED_LANE_CONTRACT = obj({
|
|
6
|
+
tool_id: str({ minLength: 1 }), request: json,
|
|
7
|
+
rows_path: path(), row_mapping: nullable(json), cursor_path: path(), cursor_request_key: path(),
|
|
8
|
+
}, { required: ["tool_id", "request"] });
|
|
9
|
+
export const TABLE_FEED_ROUTE_CONTRACT = obj({
|
|
10
|
+
...TABLE_FEED_LANE_CONTRACT.properties,
|
|
11
|
+
tool_ids: arr(str({ minLength: 1 })), lanes: arr(TABLE_FEED_LANE_CONTRACT, { minItems: 1 }),
|
|
12
|
+
max_pages: int({ minimum: 1 }), upsert_key: path(),
|
|
13
|
+
}, { required: ["tool_id", "request"] });
|
|
14
|
+
export const TABLE_FEED_GET_OPTIONS_CONTRACT = obj({ include_route: bool({ description: "Complete frozen request/mappings/lanes; no runtime cursor or resolved credentials." }) });
|
|
15
|
+
export const TABLE_FEED_UPDATE_CONTRACT = obj({
|
|
16
|
+
feed: str({ minLength: 1 }), name: str(), status: enumOf(["active", "disabled"]),
|
|
17
|
+
run_state: enumOf(["idle", "running", "error", "exhausted"]),
|
|
18
|
+
sync: obj({
|
|
19
|
+
every: nullable(str({ description: "hourly, every_6h, daily@<0-23>, weekly@<day><hour>; UTC. null removes the cron." })),
|
|
20
|
+
max_credits_per_cycle: { type: "number", exclusiveMinimum: 0, description: "Future-cycle ceiling; configuration spends nothing." },
|
|
21
|
+
max_rows_per_cycle: int({ minimum: 1 }),
|
|
22
|
+
}, { description: "Omitted fields keep their values." }),
|
|
23
|
+
route: { ...TABLE_FEED_ROUTE_CONTRACT, description: "Full frozen route from feeds_get(include_route=true). Replacement resets cursor/error. Scheduled replacements require one executable lane; distinct fallbacks require no cadence." },
|
|
24
|
+
filters: json, intent_id: str(), input_shape: str(), route_id: str(), registry_version: str(), source_prompt: str(),
|
|
25
|
+
approved: bool({ description: "Human authorization for expanded recurring scope; a free config call grants no future spend." }),
|
|
26
|
+
}, { required: ["feed"] });
|
|
27
|
+
/** New surfaces refuse provenance edits the native PATCH would otherwise ignore. */
|
|
28
|
+
export function tableFeedUpdateIssues(args) {
|
|
29
|
+
const checked = validateContract(TABLE_FEED_UPDATE_CONTRACT, args, { unknown: "reject", overMax: "reject" });
|
|
30
|
+
const errors = checked.ok ? [] : checked.issues.map(issue => issue.message);
|
|
31
|
+
if (!args.route && ["filters", "intent_id", "input_shape", "route_id", "registry_version", "source_prompt"].some(key => args[key] !== undefined)) {
|
|
32
|
+
errors.push("Source provenance changes require the complete route; edit its request to change executable filters.");
|
|
33
|
+
}
|
|
34
|
+
return errors;
|
|
35
|
+
}
|
|
36
|
+
export const TABLE_FEED_UPDATE_OPERATION = {
|
|
37
|
+
id: "tables.feeds.update", route: "/api/cli/tables/feeds", method: "PATCH", contract: TABLE_FEED_UPDATE_CONTRACT,
|
|
38
|
+
generated: { cli: false, mcp: false },
|
|
39
|
+
cli: { path: ["feeds", "update"], summary: "Update an existing Table feed in place; changed cadence, increased cap or source scope can require renewed standing authorization." },
|
|
40
|
+
mcp: { name: "oxygen_feeds_update", title: "Oxygen: Update Table Feed", pack: "signals",
|
|
41
|
+
description: "Update an existing Table feed in place. Inspect feeds_get(include_route=true) first. Replacement resets cursor/error. Changed cadence, raised cap or source can require approved=true. Scheduled replacements require one executable lane; distinct fallbacks require no cadence. Native approval, budget and incremental guards apply. Configuration is free; future spend remains governed. Omitted fields stay unchanged. Use table_webhook_update for inbound endpoints." },
|
|
42
|
+
mutates: true, spends: false,
|
|
43
|
+
};
|
|
44
|
+
/** The existing native PATCH scope comparison, separate from configuration cost. */
|
|
45
|
+
export function tableFeedUpdateScopeChange(args, current) {
|
|
46
|
+
const sync = args.sync && typeof args.sync === "object" && !Array.isArray(args.sync) ? args.sync : args;
|
|
47
|
+
const cadenceGiven = Object.hasOwn(args, "every") || Object.hasOwn(args, "cadence") || Object.hasOwn(sync, "every") || Object.hasOwn(sync, "cadence");
|
|
48
|
+
const every = cadenceGiven ? typeof (sync.every ?? sync.cadence) === "string" && String(sync.every ?? sync.cadence).trim() ? String(sync.every ?? sync.cadence).trim() : null : current.every;
|
|
49
|
+
const rawCap = sync.max_credits_per_cycle ?? sync.maxCreditsPerCycle ?? sync.max_credits ?? sync.maxCredits;
|
|
50
|
+
const cap = rawCap === undefined || rawCap === null || rawCap === "" ? null : Number(rawCap);
|
|
51
|
+
const raisesCap = cap !== null && current.maxCredits !== null && cap > current.maxCredits;
|
|
52
|
+
const replacesSource = Boolean(args.route && typeof args.route === "object" && !Array.isArray(args.route)) || Boolean(args.source && typeof args.source === "object" && !Array.isArray(args.source));
|
|
53
|
+
const changesCadence = cadenceGiven && every !== null && every !== current.every;
|
|
54
|
+
return { every, raisesCap, replacesSource, changesCadence, needsReapproval: raisesCap || replacesSource || changesCadence };
|
|
55
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/** Bounded table discovery, shared by the HTTP query, CLI flags and MCP. */
|
|
2
|
+
import { type Infer } from "./schema.js";
|
|
3
|
+
export declare const TABLE_LIST_QUERY_CONTRACT: import("./schema.js").ContractObject<{
|
|
4
|
+
readonly project: import("./schema.js").StringProperty;
|
|
5
|
+
readonly tag: import("./schema.js").StringProperty;
|
|
6
|
+
readonly include_archived: import("./schema.js").BooleanProperty;
|
|
7
|
+
readonly limit: {
|
|
8
|
+
type: "integer";
|
|
9
|
+
description?: string;
|
|
10
|
+
minimum?: number;
|
|
11
|
+
maximum?: number;
|
|
12
|
+
"x-clamp"?: true;
|
|
13
|
+
};
|
|
14
|
+
readonly cursor: import("./schema.js").StringProperty;
|
|
15
|
+
readonly query: import("./schema.js").StringProperty;
|
|
16
|
+
readonly projection: {
|
|
17
|
+
type: "string";
|
|
18
|
+
enum: readonly ("full" | "summary")[];
|
|
19
|
+
description?: string;
|
|
20
|
+
};
|
|
21
|
+
readonly max_chars: {
|
|
22
|
+
type: "integer";
|
|
23
|
+
description?: string;
|
|
24
|
+
minimum?: number;
|
|
25
|
+
maximum?: number;
|
|
26
|
+
"x-clamp"?: true;
|
|
27
|
+
};
|
|
28
|
+
}, never>;
|
|
29
|
+
export type TableListQuery = Infer<typeof TABLE_LIST_QUERY_CONTRACT>;
|
|
30
|
+
/** Unknown query keys are ignored for compatibility; only declared keys travel. */
|
|
31
|
+
export declare function tableListQueryParams(query: TableListQuery): URLSearchParams;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** Bounded table discovery, shared by the HTTP query, CLI flags and MCP. */
|
|
2
|
+
import { bool, enumOf, int, obj, str } from "./schema.js";
|
|
3
|
+
export const TABLE_LIST_QUERY_CONTRACT = obj({
|
|
4
|
+
project: str({ minLength: 1, maxLength: 200 }),
|
|
5
|
+
tag: str(),
|
|
6
|
+
include_archived: bool(),
|
|
7
|
+
limit: int({ minimum: 1, maximum: 1000, clamp: true }),
|
|
8
|
+
cursor: str({ maxLength: 2000 }),
|
|
9
|
+
query: str({ maxLength: 200, description: "Name/slug substring." }),
|
|
10
|
+
projection: enumOf(["full", "summary"]),
|
|
11
|
+
max_chars: int({ minimum: 2000, maximum: 40000 }),
|
|
12
|
+
});
|
|
13
|
+
/** Unknown query keys are ignored for compatibility; only declared keys travel. */
|
|
14
|
+
export function tableListQueryParams(query) {
|
|
15
|
+
const params = new URLSearchParams();
|
|
16
|
+
for (const key of Object.keys(TABLE_LIST_QUERY_CONTRACT.properties)) {
|
|
17
|
+
const value = query[key];
|
|
18
|
+
if (value !== undefined)
|
|
19
|
+
params.set(key, String(value));
|
|
20
|
+
}
|
|
21
|
+
return params;
|
|
22
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export declare const MAX_TABLE_RECOVERY_ITEMS = 1000;
|
|
2
|
+
export declare const TABLE_FAVORITES_LIST_CONTRACT: import("./schema.js").ContractObject<{
|
|
3
|
+
readonly limit: {
|
|
4
|
+
type: "integer";
|
|
5
|
+
description?: string;
|
|
6
|
+
minimum?: number;
|
|
7
|
+
maximum?: number;
|
|
8
|
+
"x-clamp"?: true;
|
|
9
|
+
};
|
|
10
|
+
readonly cursor: import("./schema.js").StringProperty;
|
|
11
|
+
readonly max_chars: {
|
|
12
|
+
type: "integer";
|
|
13
|
+
description?: string;
|
|
14
|
+
minimum?: number;
|
|
15
|
+
maximum?: number;
|
|
16
|
+
"x-clamp"?: true;
|
|
17
|
+
};
|
|
18
|
+
}, never>;
|
|
19
|
+
export declare const TABLE_FAVORITE_CONTRACT: import("./schema.js").ContractObject<{
|
|
20
|
+
readonly table: import("./schema.js").StringProperty;
|
|
21
|
+
readonly folder: import("./schema.js").StringProperty;
|
|
22
|
+
readonly favorite: import("./schema.js").BooleanProperty;
|
|
23
|
+
}, "favorite">;
|
|
24
|
+
export declare const TABLE_LINK_SUGGEST_CONTRACT: import("./schema.js").ContractObject<{
|
|
25
|
+
readonly table: import("./schema.js").StringProperty;
|
|
26
|
+
readonly to: import("./schema.js").StringProperty;
|
|
27
|
+
readonly on: import("./schema.js").StringProperty;
|
|
28
|
+
readonly scan_limit: {
|
|
29
|
+
type: "number";
|
|
30
|
+
description?: string;
|
|
31
|
+
minimum?: number;
|
|
32
|
+
maximum?: number;
|
|
33
|
+
"x-clamp"?: true;
|
|
34
|
+
};
|
|
35
|
+
}, "table" | "to">;
|
|
36
|
+
export declare const TABLE_EFFECT_OUTCOMES: readonly ["applied", "not_applied"];
|
|
37
|
+
export declare const TABLE_ITEM_RESOLVE_CONTRACT: import("./schema.js").ContractObject<{
|
|
38
|
+
readonly outcome: {
|
|
39
|
+
type: "string";
|
|
40
|
+
enum: readonly ("applied" | "not_applied")[];
|
|
41
|
+
description?: string;
|
|
42
|
+
};
|
|
43
|
+
readonly note: import("./schema.js").StringProperty;
|
|
44
|
+
readonly value: {
|
|
45
|
+
type?: never;
|
|
46
|
+
description?: string;
|
|
47
|
+
};
|
|
48
|
+
}, "outcome">;
|
|
49
|
+
export declare const TABLE_RECOVER_PENDING_CONTRACT: import("./schema.js").ContractObject<{
|
|
50
|
+
readonly table: import("./schema.js").StringProperty;
|
|
51
|
+
readonly max_items: {
|
|
52
|
+
type: "integer";
|
|
53
|
+
description?: string;
|
|
54
|
+
minimum?: number;
|
|
55
|
+
maximum?: number;
|
|
56
|
+
"x-clamp"?: true;
|
|
57
|
+
};
|
|
58
|
+
}, "table">;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** Customer Table operations; the native routes retain identity and effect guards. */
|
|
2
|
+
import { bool, enumOf, int, jsonValue, num, obj, str } from "./schema.js";
|
|
3
|
+
const table = str({ minLength: 1, description: "Table id, slug, or Oxygen table URL." });
|
|
4
|
+
export const MAX_TABLE_RECOVERY_ITEMS = 1000;
|
|
5
|
+
export const TABLE_FAVORITES_LIST_CONTRACT = obj({
|
|
6
|
+
limit: int({ minimum: 1, maximum: 200, description: "Page size; MCP default 20." }),
|
|
7
|
+
cursor: str({ maxLength: 512, description: "Previous next_cursor; restart if stars changed." }),
|
|
8
|
+
max_chars: int({ minimum: 500, maximum: 10_000, description: "Complete response cap in characters." }),
|
|
9
|
+
});
|
|
10
|
+
export const TABLE_FAVORITE_CONTRACT = obj({
|
|
11
|
+
table: str({ minLength: 1, description: "Table id, slug, or Oxygen table URL. Pass exactly one of table or folder." }),
|
|
12
|
+
folder: str({ minLength: 1, description: "Folder id or slug. Pass exactly one of table or folder." }),
|
|
13
|
+
favorite: bool({ description: "true stars; false unstars." }),
|
|
14
|
+
}, { required: ["favorite"] });
|
|
15
|
+
export const TABLE_LINK_SUGGEST_CONTRACT = obj({
|
|
16
|
+
table,
|
|
17
|
+
to: table,
|
|
18
|
+
on: str({ description: "Optional join column key or id." }),
|
|
19
|
+
scan_limit: num({ description: "Native planner scan limit; bounded server-side." }),
|
|
20
|
+
}, { required: ["table", "to"] });
|
|
21
|
+
export const TABLE_EFFECT_OUTCOMES = ["applied", "not_applied"];
|
|
22
|
+
export const TABLE_ITEM_RESOLVE_CONTRACT = obj({
|
|
23
|
+
outcome: enumOf(TABLE_EFFECT_OUTCOMES),
|
|
24
|
+
note: str(),
|
|
25
|
+
value: jsonValue({ description: "Verified cell result; any JSON, including null." }),
|
|
26
|
+
}, { required: ["outcome"] });
|
|
27
|
+
export const TABLE_RECOVER_PENDING_CONTRACT = obj({
|
|
28
|
+
table: str({ minLength: 1, description: "Table id or slug." }),
|
|
29
|
+
max_items: int({ minimum: 1, maximum: MAX_TABLE_RECOVERY_ITEMS, description: "Pending requests to poll; default 1000." }),
|
|
30
|
+
}, { required: ["table"] });
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export declare const WORKFLOW_RUN_STATUS_VALUES: readonly ["queued", "running", "waiting", "awaiting_approval", "completed", "failed", "canceling", "canceled"];
|
|
2
|
+
export declare const WORKFLOW_RUN_MODE_VALUES: readonly ["dry_run", "live", "smoke_test"];
|
|
3
|
+
export declare const WORKFLOW_RUN_LIST_CONTRACT: import("./schema.js").ContractObject<{
|
|
4
|
+
readonly projection: {
|
|
5
|
+
type: "string";
|
|
6
|
+
enum: readonly ("full" | "summary" | "value")[];
|
|
7
|
+
description?: string;
|
|
8
|
+
};
|
|
9
|
+
readonly path: import("./schema.js").StringProperty;
|
|
10
|
+
readonly value_cursor: import("./schema.js").StringProperty;
|
|
11
|
+
readonly max_chars: {
|
|
12
|
+
type: "integer";
|
|
13
|
+
description?: string;
|
|
14
|
+
minimum?: number;
|
|
15
|
+
maximum?: number;
|
|
16
|
+
"x-clamp"?: true;
|
|
17
|
+
};
|
|
18
|
+
readonly workflow: import("./schema.js").StringProperty;
|
|
19
|
+
readonly workflow_id: import("./schema.js").StringProperty;
|
|
20
|
+
readonly status: import("./schema.js").StringProperty;
|
|
21
|
+
readonly mode: import("./schema.js").StringProperty;
|
|
22
|
+
readonly cursor: import("./schema.js").StringProperty;
|
|
23
|
+
readonly limit: {
|
|
24
|
+
type: "integer";
|
|
25
|
+
description?: string;
|
|
26
|
+
minimum?: number;
|
|
27
|
+
maximum?: number;
|
|
28
|
+
"x-clamp"?: true;
|
|
29
|
+
};
|
|
30
|
+
readonly run_id: import("./schema.js").StringProperty;
|
|
31
|
+
}, never>;
|
|
32
|
+
export declare const WORKFLOW_RUN_LIST_MCP_CONTRACT: import("./schema.js").ContractObject<{
|
|
33
|
+
readonly projection: {
|
|
34
|
+
type: "string";
|
|
35
|
+
enum: readonly ("full" | "summary" | "value")[];
|
|
36
|
+
description?: string;
|
|
37
|
+
};
|
|
38
|
+
readonly path: import("./schema.js").StringProperty;
|
|
39
|
+
readonly value_cursor: import("./schema.js").StringProperty;
|
|
40
|
+
readonly max_chars: {
|
|
41
|
+
type: "integer";
|
|
42
|
+
description?: string;
|
|
43
|
+
minimum?: number;
|
|
44
|
+
maximum?: number;
|
|
45
|
+
"x-clamp"?: true;
|
|
46
|
+
};
|
|
47
|
+
readonly workflow: import("./schema.js").StringProperty;
|
|
48
|
+
readonly workflow_id: import("./schema.js").StringProperty;
|
|
49
|
+
readonly cursor: import("./schema.js").StringProperty;
|
|
50
|
+
readonly limit: {
|
|
51
|
+
type: "integer";
|
|
52
|
+
description?: string;
|
|
53
|
+
minimum?: number;
|
|
54
|
+
maximum?: number;
|
|
55
|
+
"x-clamp"?: true;
|
|
56
|
+
};
|
|
57
|
+
readonly run_id: import("./schema.js").StringProperty;
|
|
58
|
+
readonly status: {
|
|
59
|
+
type: "string";
|
|
60
|
+
enum: readonly ("awaiting_approval" | "canceled" | "canceling" | "completed" | "failed" | "queued" | "running" | "waiting")[];
|
|
61
|
+
description?: string;
|
|
62
|
+
};
|
|
63
|
+
readonly mode: {
|
|
64
|
+
type: "string";
|
|
65
|
+
enum: readonly ("dry_run" | "live" | "smoke_test")[];
|
|
66
|
+
description?: string;
|
|
67
|
+
};
|
|
68
|
+
}, never>;
|
|
69
|
+
/** The native GET keeps raw strings, canonical alias precedence and absent
|
|
70
|
+
* values. CLI legacy trimming is an explicit adapter above this contract. */
|
|
71
|
+
export declare function workflowRunListQueryParams(args: Record<string, unknown>): URLSearchParams;
|
|
72
|
+
/** Exact native HTTP scalar selection, including blank canonical precedence. */
|
|
73
|
+
export declare function readWorkflowRunListSelectors(params: URLSearchParams): {
|
|
74
|
+
workflowIdOrSlug: string | null;
|
|
75
|
+
status: string | null;
|
|
76
|
+
mode: string | null;
|
|
77
|
+
cursor: string | null;
|
|
78
|
+
runId: string | null;
|
|
79
|
+
};
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { enumOf, int, obj, str } from "./schema.js";
|
|
2
|
+
import { STORED_READ_WINDOW_FIELDS } from "./stored-read-window.js";
|
|
3
|
+
export const WORKFLOW_RUN_STATUS_VALUES = ["queued", "running", "waiting", "awaiting_approval", "completed", "failed", "canceling", "canceled"];
|
|
4
|
+
export const WORKFLOW_RUN_MODE_VALUES = ["dry_run", "live", "smoke_test"];
|
|
5
|
+
export const WORKFLOW_RUN_LIST_CONTRACT = obj({
|
|
6
|
+
workflow: str({ minLength: 1, maxLength: 400, description: "Workflow id, slug, exact name, or copied URL." }),
|
|
7
|
+
workflow_id: str({ minLength: 1, maxLength: 400, description: "Canonical workflow ref; takes precedence over workflow on HTTP/MCP." }),
|
|
8
|
+
status: str({ description: "Stored status filter: queued, running, waiting, awaiting_approval, completed, failed, canceling, canceled. Native validation trims and ignores case." }),
|
|
9
|
+
mode: str({ description: "Stored execution mode filter: dry_run, live or smoke_test. Never runs a workflow." }),
|
|
10
|
+
cursor: str({ description: "Previous nextCursor, echoed unchanged with the same filters." }),
|
|
11
|
+
limit: int({ minimum: 1, maximum: 500, description: "Runs per page; native default 50." }),
|
|
12
|
+
run_id: str({ minLength: 1, maxLength: 80, description: "Exact stored run UUID within the same workflow/status/mode/cursor filters; opt-in windows only." }),
|
|
13
|
+
...STORED_READ_WINDOW_FIELDS,
|
|
14
|
+
});
|
|
15
|
+
export const WORKFLOW_RUN_LIST_MCP_CONTRACT = obj({
|
|
16
|
+
...WORKFLOW_RUN_LIST_CONTRACT.properties,
|
|
17
|
+
status: enumOf(WORKFLOW_RUN_STATUS_VALUES, { description: "Stored run status filter." }),
|
|
18
|
+
mode: enumOf(WORKFLOW_RUN_MODE_VALUES, { description: "Stored execution mode filter; executes nothing." }),
|
|
19
|
+
});
|
|
20
|
+
/** The native GET keeps raw strings, canonical alias precedence and absent
|
|
21
|
+
* values. CLI legacy trimming is an explicit adapter above this contract. */
|
|
22
|
+
export function workflowRunListQueryParams(args) {
|
|
23
|
+
const pairs = [];
|
|
24
|
+
for (const key of Object.keys(WORKFLOW_RUN_LIST_CONTRACT.properties)) {
|
|
25
|
+
const value = args[key];
|
|
26
|
+
if (value !== undefined && value !== null)
|
|
27
|
+
pairs.push([key, String(value)]);
|
|
28
|
+
}
|
|
29
|
+
return new URLSearchParams(pairs);
|
|
30
|
+
}
|
|
31
|
+
/** Exact native HTTP scalar selection, including blank canonical precedence. */
|
|
32
|
+
export function readWorkflowRunListSelectors(params) {
|
|
33
|
+
return {
|
|
34
|
+
workflowIdOrSlug: params.get("workflow_id") ?? params.get("workflow"),
|
|
35
|
+
status: params.get("status"), mode: params.get("mode"),
|
|
36
|
+
cursor: params.get("cursor"), runId: params.get("run_id"),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -12,8 +12,8 @@ export declare const COPILOT_JOURNEYS: readonly [{
|
|
|
12
12
|
readonly slug: "inbound-led-outbound";
|
|
13
13
|
readonly title: "Inbound-led outbound";
|
|
14
14
|
readonly description: "Turn the people who engage with your LinkedIn posts into a capped, evidence-gated warm sequence with replies routed to your CRM.";
|
|
15
|
-
readonly recipeSlugs: readonly ["inbound-led-outbound", "
|
|
16
|
-
readonly seedMessage: "I chose the inbound-led-outbound recipe. Help me
|
|
15
|
+
readonly recipeSlugs: readonly ["inbound-led-outbound", "founder-posting-system", "reply-to-meeting"];
|
|
16
|
+
readonly seedMessage: "I chose the inbound-led-outbound recipe. Help me turn the people paying attention to me on LinkedIn into conversations: capture a small sample, score each person against my ideal customer, show me the good fits and draft a LinkedIn message I approve. Inspect the workspace first and resume from what exists. Do not connect an account, enroll anyone, send anything, or spend credits without asking me first.";
|
|
17
17
|
}, {
|
|
18
18
|
readonly slug: "email-infra-setup";
|
|
19
19
|
readonly title: "Outbound infrastructure";
|
|
@@ -2,8 +2,8 @@ export declare const COPILOT_JOURNEYS_GENERATED: readonly [{
|
|
|
2
2
|
readonly slug: "inbound-led-outbound";
|
|
3
3
|
readonly title: "Inbound-led outbound";
|
|
4
4
|
readonly description: "Turn the people who engage with your LinkedIn posts into a capped, evidence-gated warm sequence with replies routed to your CRM.";
|
|
5
|
-
readonly recipeSlugs: readonly ["inbound-led-outbound", "
|
|
6
|
-
readonly seedMessage: "I chose the inbound-led-outbound recipe. Help me
|
|
5
|
+
readonly recipeSlugs: readonly ["inbound-led-outbound", "founder-posting-system", "reply-to-meeting"];
|
|
6
|
+
readonly seedMessage: "I chose the inbound-led-outbound recipe. Help me turn the people paying attention to me on LinkedIn into conversations: capture a small sample, score each person against my ideal customer, show me the good fits and draft a LinkedIn message I approve. Inspect the workspace first and resume from what exists. Do not connect an account, enroll anyone, send anything, or spend credits without asking me first.";
|
|
7
7
|
}, {
|
|
8
8
|
readonly slug: "email-infra-setup";
|
|
9
9
|
readonly title: "Outbound infrastructure";
|
|
@@ -6,8 +6,8 @@ export const COPILOT_JOURNEYS_GENERATED = [
|
|
|
6
6
|
slug: "inbound-led-outbound",
|
|
7
7
|
title: "Inbound-led outbound",
|
|
8
8
|
description: "Turn the people who engage with your LinkedIn posts into a capped, evidence-gated warm sequence with replies routed to your CRM.",
|
|
9
|
-
recipeSlugs: ["inbound-led-outbound", "
|
|
10
|
-
seedMessage: "I chose the inbound-led-outbound recipe. Help me
|
|
9
|
+
recipeSlugs: ["inbound-led-outbound", "founder-posting-system", "reply-to-meeting"],
|
|
10
|
+
seedMessage: "I chose the inbound-led-outbound recipe. Help me turn the people paying attention to me on LinkedIn into conversations: capture a small sample, score each person against my ideal customer, show me the good fits and draft a LinkedIn message I approve. Inspect the workspace first and resume from what exists. Do not connect an account, enroll anyone, send anything, or spend credits without asking me first.",
|
|
11
11
|
},
|
|
12
12
|
{
|
|
13
13
|
slug: "email-infra-setup",
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
export declare const COPILOT_PLAYBOOKS_GENERATED: readonly [{
|
|
2
2
|
readonly slug: "icp-to-account-map";
|
|
3
3
|
readonly title: "TAM sourcing";
|
|
4
|
-
readonly prompt: "
|
|
4
|
+
readonly prompt: "Find about 25 companies that look like our best customers, grade how well each one fits and why, and show me which kinds fit best. If I share a list, portfolio page or event list, grade that instead.";
|
|
5
5
|
}, {
|
|
6
6
|
readonly slug: "founder-posting-system";
|
|
7
7
|
readonly title: "LinkedIn content strategy";
|
|
8
|
-
readonly prompt: "Help me post on LinkedIn
|
|
8
|
+
readonly prompt: "Help me post on LinkedIn regularly in my own voice: draft a few posts about what we do and who we help, or plan a whole week, let me approve each one before it goes out, and show me how they do.";
|
|
9
9
|
}, {
|
|
10
10
|
readonly slug: "inbound-led-outbound";
|
|
11
11
|
readonly title: "Inbound-led outbound";
|
|
12
|
-
readonly prompt: "Turn the people
|
|
12
|
+
readonly prompt: "Turn the people paying attention to us on LinkedIn into pipeline: people reacting to my posts or to posts by people I pick, my followers and connections, or my profile viewers. Score them against our ideal customer and message only the good fits on LinkedIn, a few a day.";
|
|
13
13
|
}, {
|
|
14
14
|
readonly slug: "daily-warm-lead-queue";
|
|
15
15
|
readonly title: "Signal-based outbound";
|
|
@@ -6,17 +6,17 @@ export const COPILOT_PLAYBOOKS_GENERATED = [
|
|
|
6
6
|
{
|
|
7
7
|
slug: "icp-to-account-map",
|
|
8
8
|
title: "TAM sourcing",
|
|
9
|
-
prompt: "
|
|
9
|
+
prompt: "Find about 25 companies that look like our best customers, grade how well each one fits and why, and show me which kinds fit best. If I share a list, portfolio page or event list, grade that instead.",
|
|
10
10
|
},
|
|
11
11
|
{
|
|
12
12
|
slug: "founder-posting-system",
|
|
13
13
|
title: "LinkedIn content strategy",
|
|
14
|
-
prompt: "Help me post on LinkedIn
|
|
14
|
+
prompt: "Help me post on LinkedIn regularly in my own voice: draft a few posts about what we do and who we help, or plan a whole week, let me approve each one before it goes out, and show me how they do.",
|
|
15
15
|
},
|
|
16
16
|
{
|
|
17
17
|
slug: "inbound-led-outbound",
|
|
18
18
|
title: "Inbound-led outbound",
|
|
19
|
-
prompt: "Turn the people
|
|
19
|
+
prompt: "Turn the people paying attention to us on LinkedIn into pipeline: people reacting to my posts or to posts by people I pick, my followers and connections, or my profile viewers. Score them against our ideal customer and message only the good fits on LinkedIn, a few a day.",
|
|
20
20
|
},
|
|
21
21
|
{
|
|
22
22
|
slug: "daily-warm-lead-queue",
|
|
@@ -240,6 +240,23 @@ export const LEGACY_MANAGED_AI_COLUMN_MODELS = {
|
|
|
240
240
|
"deepseek/deepseek-v4-pro": "medium",
|
|
241
241
|
"moonshotai/kimi-k2.6": "high",
|
|
242
242
|
};
|
|
243
|
+
/**
|
|
244
|
+
* Managed model ids OXYGEN ran that never sat in the registry above, mapped to
|
|
245
|
+
* the tier they read as. Labeling only: unlike LEGACY_MANAGED_AI_COLUMN_MODELS,
|
|
246
|
+
* none of these is a valid managed column pin. The credit ledger keeps every id
|
|
247
|
+
* it ever recorded, so `billing usage` and `billing audit --group-by model`
|
|
248
|
+
* returned them raw (OXP-1.6.96, 2026-10-04): in production 25 workspaces hold
|
|
249
|
+
* managed openai/gpt-4.1-mini spend from before the July registry, billed at the
|
|
250
|
+
* low tier; gpt-4.1-nano ran on dev only; deepseek/deepseek-chat is the spintax
|
|
251
|
+
* generator's fixed model.
|
|
252
|
+
*/
|
|
253
|
+
const UNREGISTERED_MANAGED_MODEL_LEVELS = {
|
|
254
|
+
"openai/gpt-4.1-mini": "low",
|
|
255
|
+
"openai/gpt-4.1-nano": "low",
|
|
256
|
+
"deepseek/deepseek-chat": "low",
|
|
257
|
+
};
|
|
258
|
+
/** Dev throughput probe pin (tenant-db `resolveManagedAiModelTier` bills it at low). */
|
|
259
|
+
const PERF_TEST_MODEL_ENV = "OXYGEN_OPENROUTER_MODEL_PERF_TEST";
|
|
243
260
|
/** The tier a retired managed AI-column model id billed at, or null. */
|
|
244
261
|
export function legacyManagedAiColumnLevel(model) {
|
|
245
262
|
return Object.prototype.hasOwnProperty.call(LEGACY_MANAGED_AI_COLUMN_MODELS, model)
|
|
@@ -442,6 +459,13 @@ function managedModelLabels(preferredUseCase, env = typeof process === "undefine
|
|
|
442
459
|
if (!labels.has(model))
|
|
443
460
|
labels.set(model, MANAGED_AI_TIER_LABELS[level]);
|
|
444
461
|
}
|
|
462
|
+
for (const [model, level] of Object.entries(UNREGISTERED_MANAGED_MODEL_LEVELS)) {
|
|
463
|
+
if (!labels.has(model))
|
|
464
|
+
labels.set(model, MANAGED_AI_TIER_LABELS[level]);
|
|
465
|
+
}
|
|
466
|
+
const perfTestModel = readTrimmedEnv(env, PERF_TEST_MODEL_ENV);
|
|
467
|
+
if (perfTestModel && !labels.has(perfTestModel))
|
|
468
|
+
labels.set(perfTestModel, MANAGED_AI_TIER_LABELS.low);
|
|
445
469
|
for (const useCase of ordered) {
|
|
446
470
|
for (const spec of Object.values(HOSTED_AI_MODEL_REGISTRY[useCase])) {
|
|
447
471
|
for (const fallback of spec.fallbackModels) {
|
|
@@ -13,7 +13,7 @@ export declare const RECIPE_PRIMITIVES: readonly ["knowledge-graph", "recipes",
|
|
|
13
13
|
export type RecipePrimitive = typeof RECIPE_PRIMITIVES[number];
|
|
14
14
|
export declare const RECIPE_PREREQUISITE_KINDS: readonly ["sender", "mailbox", "domain", "integration", "knowledge", "asset", "plan", "data"];
|
|
15
15
|
export type RecipePrerequisiteKind = typeof RECIPE_PREREQUISITE_KINDS[number];
|
|
16
|
-
export declare const RECIPE_BODY_SECTIONS: readonly ["The Play", "
|
|
16
|
+
export declare const RECIPE_BODY_SECTIONS: readonly ["The Play", "Before You Start", "Steps", "If It Goes Wrong"];
|
|
17
17
|
export declare const RECIPE_SLUG_PATTERN: RegExp;
|
|
18
18
|
export declare function recipeWikiSlug(recipeSlug: string): string;
|
|
19
19
|
export declare const RECIPE_KIT_MAX_STAGES = 6;
|
|
@@ -67,19 +67,14 @@ export const RECIPE_PREREQUISITE_KINDS = [
|
|
|
67
67
|
"plan",
|
|
68
68
|
"data",
|
|
69
69
|
];
|
|
70
|
-
// The
|
|
71
|
-
//
|
|
70
|
+
// The four body sections every recipe carries, in order and no others
|
|
71
|
+
// (founder, 2026-10-04): a production audit found lost founders' agents
|
|
72
|
+
// stalling in ten-section essays. The catalog lint enforces exact H2 headings.
|
|
72
73
|
export const RECIPE_BODY_SECTIONS = [
|
|
73
74
|
"The Play",
|
|
74
|
-
"What You Get",
|
|
75
|
-
"When To Run (And When Not To)",
|
|
76
75
|
"Before You Start",
|
|
77
76
|
"Steps",
|
|
78
|
-
"
|
|
79
|
-
"Calibrate",
|
|
80
|
-
"Troubleshooting",
|
|
81
|
-
"Operator Notes",
|
|
82
|
-
"Related",
|
|
77
|
+
"If It Goes Wrong",
|
|
83
78
|
];
|
|
84
79
|
export const RECIPE_SLUG_PATTERN = /^[a-z0-9][a-z0-9-]{0,119}$/;
|
|
85
80
|
// Wiki slug an install writes: slots into the starter wiki's seeded
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const OXYGEN_BUILD_VERSION = "1.1011.
|
|
1
|
+
export declare const OXYGEN_BUILD_VERSION = "1.1011.800";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// GENERATED by scripts/ci/version-stamp.mjs from VERSION + git history. Do not edit; do not commit.
|
|
2
|
-
export const OXYGEN_BUILD_VERSION = "1.1011.
|
|
2
|
+
export const OXYGEN_BUILD_VERSION = "1.1011.800";
|
|
@@ -32,6 +32,7 @@ export declare class WorkflowValueCoercionError extends Error {
|
|
|
32
32
|
export declare class WorkflowValueRefUnresolvedError extends Error {
|
|
33
33
|
readonly path: string;
|
|
34
34
|
readonly code = "workflow_value_ref_unresolved";
|
|
35
|
+
readonly nextStep: string;
|
|
35
36
|
constructor(path: string);
|
|
36
37
|
}
|
|
37
38
|
/** Apply one explicit scalar conversion without lossy truthiness or truncation. */
|
|
@@ -40,14 +40,29 @@ function unresolvedRefRemedy(path) {
|
|
|
40
40
|
const skeleton = parts.slice(2).reduceRight((inner, key) => ({ [key]: inner }), "…");
|
|
41
41
|
return ` Supply it with --input-json '${JSON.stringify(skeleton)}'.`;
|
|
42
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* The caller-facing repair, short enough to survive the run-fault collapse
|
|
45
|
+
* (`next_step` is the one free-text field it keeps). An absent optional input
|
|
46
|
+
* is the common case: lint and publish accept the ref, and only the run fails.
|
|
47
|
+
*/
|
|
48
|
+
function unresolvedRefNextStep(path) {
|
|
49
|
+
const parts = path.split(".");
|
|
50
|
+
const coalesce = `bind it as a formula, COALESCE(${path}, ""), so a missing value is allowed`;
|
|
51
|
+
if (parts.length >= 3 && parts[0] === "trigger" && parts[1] === "input") {
|
|
52
|
+
return `'${path}' was not in the run input. Pass it in --input-json, list it in input_schema.required, or ${coalesce}.`;
|
|
53
|
+
}
|
|
54
|
+
return `'${path}' was not produced by an earlier step. Check that step's output, or ${coalesce}.`;
|
|
55
|
+
}
|
|
43
56
|
/** A direct mapping named data the run does not carry; sending undefined is never intentional. */
|
|
44
57
|
export class WorkflowValueRefUnresolvedError extends Error {
|
|
45
58
|
path;
|
|
46
59
|
code = "workflow_value_ref_unresolved";
|
|
60
|
+
nextStep;
|
|
47
61
|
constructor(path) {
|
|
48
62
|
super(`Mapped field '${path}' did not resolve in this run.${unresolvedRefRemedy(path)}`);
|
|
49
63
|
this.path = path;
|
|
50
64
|
this.name = "WorkflowValueRefUnresolvedError";
|
|
65
|
+
this.nextStep = unresolvedRefNextStep(path);
|
|
51
66
|
}
|
|
52
67
|
}
|
|
53
68
|
/** Apply one explicit scalar conversion without lossy truthiness or truncation. */
|
|
@@ -138,7 +138,11 @@ export function assertWorkflowGraphManifest(value, options = {}) {
|
|
|
138
138
|
if (result.ok)
|
|
139
139
|
return;
|
|
140
140
|
const first = result.issues[0];
|
|
141
|
-
|
|
141
|
+
// The path is the only pointer to the offending node once a caller turns
|
|
142
|
+
// this throw into a typed error (the CLI's local compile keeps the message).
|
|
143
|
+
throw new Error(first
|
|
144
|
+
? `${first.code}: ${first.message}${first.path ? ` (at ${first.path})` : ""}`
|
|
145
|
+
: "Invalid workflow graph manifest.");
|
|
142
146
|
}
|
|
143
147
|
/**
|
|
144
148
|
* Validate one nested oxygen-js-v1 envelope without requiring its surrounding
|
|
@@ -1484,7 +1488,9 @@ value, path, add, scope, depth = 0) {
|
|
|
1484
1488
|
if (value.type === "compare") {
|
|
1485
1489
|
validateValueRef(value.left, `${path}.left`, add, scope);
|
|
1486
1490
|
if (!isCompareOp(value.op)) {
|
|
1487
|
-
|
|
1491
|
+
// Blind evals reached for `is_true`, a Tables filter op: name the valid
|
|
1492
|
+
// workflow ops and the boolean spelling instead of only saying "invalid".
|
|
1493
|
+
add(`${path}.op`, "invalid_condition", `Condition op ${JSON.stringify(value.op)?.slice(0, 40) ?? "(missing)"} is not a workflow operator. Use one of: ${[...WORKFLOW_COMPARE_OPS].join(", ")}. For a boolean, compare eq with a literal true.`);
|
|
1488
1494
|
return;
|
|
1489
1495
|
}
|
|
1490
1496
|
if (isUnaryCompareOp(value.op)) {
|