@oxygen-agent/cli 1.1014.69 → 1.1014.81
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/help.d.ts +1 -1
- package/dist/help.js +8 -6
- package/dist/index.js +32 -3
- package/dist/workspace-skill-commands.js +5 -4
- package/node_modules/@oxygen/shared/dist/column-decision.js +1 -1
- package/node_modules/@oxygen/shared/dist/contracts/workspace-skills.js +11 -11
- package/node_modules/@oxygen/shared/dist/dev-eval-classifier.d.ts +3 -0
- package/node_modules/@oxygen/shared/dist/dev-eval-classifier.js +4 -0
- package/node_modules/@oxygen/shared/dist/dev-eval-context.d.ts +35 -0
- package/node_modules/@oxygen/shared/dist/dev-eval-context.js +108 -0
- package/node_modules/@oxygen/shared/dist/version.generated.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/version.generated.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/help.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CommanderError, type Command } from "commander";
|
|
2
2
|
import { type CliFailure } from "@oxygen/shared/cli-result";
|
|
3
|
-
export declare function applyOxygenHelp(program: Command, binaryName: string): void;
|
|
3
|
+
export declare function applyOxygenHelp(program: Command, binaryName: string, docsUrl?: string): void;
|
|
4
4
|
/**
|
|
5
5
|
* Turn commander's own edit-distance suggester on for EVERY command.
|
|
6
6
|
*
|
package/dist/help.js
CHANGED
|
@@ -125,13 +125,11 @@ const HELP_GROUPS = [
|
|
|
125
125
|
},
|
|
126
126
|
];
|
|
127
127
|
const FALLBACK_HEADING = "Other commands:";
|
|
128
|
-
export function applyOxygenHelp(program, binaryName) {
|
|
128
|
+
export function applyOxygenHelp(program, binaryName, docsUrl = "https://oxygen-agent.com/docs") {
|
|
129
129
|
program.option("--help-full", "Show expanded command and option descriptions.");
|
|
130
130
|
const configure = (command) => {
|
|
131
131
|
command.configureHelp({
|
|
132
|
-
commandDescription: (cmd) => shortHelpDescription(cmd.description()),
|
|
133
132
|
subcommandDescription: (cmd) => shortHelpDescription(cmd.description()),
|
|
134
|
-
optionDescription: (option) => shortHelpDescription(option.description),
|
|
135
133
|
});
|
|
136
134
|
for (const child of command.commands)
|
|
137
135
|
configure(child);
|
|
@@ -171,7 +169,7 @@ export function applyOxygenHelp(program, binaryName) {
|
|
|
171
169
|
` 5. ${binaryName} recipes list "<goal>" --view summary --json choose a play from the Recipe catalog for your goal`,
|
|
172
170
|
` Provider inventory: ${binaryName} tools search <brand> --json, then ${binaryName} tools search --provider <provider-id> --all --json (Blitz uses blitzapi).`,
|
|
173
171
|
` Installable systems and recurring monitors: ${binaryName} blueprints list --json.`,
|
|
174
|
-
|
|
172
|
+
` Docs: ${docsUrl}`,
|
|
175
173
|
"",
|
|
176
174
|
"Conventions:",
|
|
177
175
|
" --json prints a stable envelope {ok, data|error, meta}; errors always print it.",
|
|
@@ -186,8 +184,12 @@ export function applyOxygenHelp(program, binaryName) {
|
|
|
186
184
|
function shortHelpDescription(description) {
|
|
187
185
|
if (process.argv.includes("--help-full"))
|
|
188
186
|
return description;
|
|
189
|
-
|
|
190
|
-
|
|
187
|
+
// Summarize navigation cards only. Selected commands and option grammar stay
|
|
188
|
+
// complete: cutting a flag at "e.g." or dropping its mode restriction caused
|
|
189
|
+
// a dead end in the native blind acceptance. Never truncate inside examples.
|
|
190
|
+
const sentences = description.split(/(?<!\be\.g\.)(?<!\bi\.e\.)(?<=[.!?])\s+/);
|
|
191
|
+
const safety = /\b(?:credits?|read-only|free|preview\w*|approv\w*|purg\w*|permanent\w*|irreversible)\b|--(?:yes|now)\b/i;
|
|
192
|
+
return sentences.filter((sentence, index) => index === 0 || safety.test(sentence)).join(" ");
|
|
191
193
|
}
|
|
192
194
|
/**
|
|
193
195
|
* Turn commander's own edit-distance suggester on for EVERY command.
|
package/dist/index.js
CHANGED
|
@@ -3672,7 +3672,7 @@ export function createProgram() {
|
|
|
3672
3672
|
.name(binaryName)
|
|
3673
3673
|
.description("Revenue infrastructure for B2B startups — agent-operated GTM: tables, enrichment, sequences, workflows, CRM, knowledge. Everything here also runs in the web app and over MCP; every state-changing action returns a web_url deep-link.")
|
|
3674
3674
|
.version(OXYGEN_VERSION)
|
|
3675
|
-
.option("--pretty", "Indent JSON
|
|
3675
|
+
.option("--pretty", "Indent JSON for human reading; omit for compact agent output.")
|
|
3676
3676
|
.option("--profile <name>", "Use a stored CLI profile for this command.")
|
|
3677
3677
|
.option("--org <organization>", "Use an organization id, Clerk org id, or slug for this command.");
|
|
3678
3678
|
program.hook("preAction", (_root, selected) => {
|
|
@@ -7241,7 +7241,7 @@ fixed scan; watermark_cursor starts a later bounded replay. Consumers must retai
|
|
|
7241
7241
|
});
|
|
7242
7242
|
}))
|
|
7243
7243
|
.addCommand(addContractFlags(new Command("query"), TABLE_QUERY_GRID_CONTRACT, {
|
|
7244
|
-
format: { valueName: "<format>", help: "Grid cell previews/state: default 50, cap 200, optional stats/fill/window. Omit for raw filters, fields, search, sorts or offsets." },
|
|
7244
|
+
format: { valueName: "<format>", help: "Grid cell previews/state: default 50, cap 200, optional stats/fill/window. Omit for raw filters, fields, search, sorts or offsets. JSON cells are null; their digests live in __oxygen_grid_cell_previews. Use tables rows inspect --projection value for complete values." },
|
|
7245
7245
|
max_chars: { help: "Maximum compact JSON envelope characters for raw or grid reads (1,000-100,000). Raw defaults to 12,000." },
|
|
7246
7246
|
})
|
|
7247
7247
|
.description("Read raw Table rows or --format grid cell previews/state with grid.nextCursor, in a JSON envelope. Use tables preview --summary-only for fill rates; tables export <table> --format table renders raw rows. Grid supports stats/fill/window options and refuses raw selectors.")
|
|
@@ -12742,6 +12742,32 @@ Examples:
|
|
|
12742
12742
|
program
|
|
12743
12743
|
.command("copilot")
|
|
12744
12744
|
.description("Workspace Copilot: an attended workspace agent you drive turn by turn from the terminal. Start a session, send it messages and watch the reply stream, approve the actions it proposes, then cancel when done. Managed inference uses workspace credits; paid or external actions keep their own approval gates. Web: /copilot.")
|
|
12745
|
+
.addCommand(new Command("dev-eval")
|
|
12746
|
+
.description("DEV staff owner only: immutable USD30 campaign and supplier ledger; classify dispatches guarded inference.")
|
|
12747
|
+
.argument("<operation>", "create, register, readiness, ledger, effects, classify, accept-pilot or end")
|
|
12748
|
+
.option("--campaign-id <uuid>")
|
|
12749
|
+
.option("--session-id <uuid>")
|
|
12750
|
+
.option("--models <ids>", "Comma-separated exact priced model IDs for create")
|
|
12751
|
+
.option("--question-set <name>", "Pinned thesis-icp-1 or title-fit-1")
|
|
12752
|
+
.option("--state-json <json>", "Classifier state from the native readout")
|
|
12753
|
+
.option("--json", "Print a JSON envelope.")
|
|
12754
|
+
.action(async (operation, options) => {
|
|
12755
|
+
await handleAsyncAction("copilot dev-eval", options, () => {
|
|
12756
|
+
if (operation === "readiness")
|
|
12757
|
+
return requestOxygen("/api/cli/copilot/dev-eval?readiness=1");
|
|
12758
|
+
if (operation === "effects")
|
|
12759
|
+
return requestOxygen(`/api/cli/copilot/dev-eval?campaign_id=${encodeURIComponent(options.campaignId ?? "")}&session_id=${encodeURIComponent(options.sessionId ?? "")}`);
|
|
12760
|
+
if (operation === "ledger")
|
|
12761
|
+
return requestOxygen(`/api/cli/copilot/dev-eval?campaign_id=${encodeURIComponent(options.campaignId ?? "")}`);
|
|
12762
|
+
if (!["create", "register", "end", "classify", "accept-pilot"].includes(operation))
|
|
12763
|
+
throw new OxygenError("invalid_input", "Unknown campaign operation.", { exitCode: 1 });
|
|
12764
|
+
return requestOxygen("/api/cli/copilot/dev-eval", { method: "POST", body: {
|
|
12765
|
+
operation, campaign_id: options.campaignId, session_id: options.sessionId,
|
|
12766
|
+
...(options.questionSet ? { question_set: options.questionSet, state: JSON.parse(options.stateJson ?? "null") } : {}),
|
|
12767
|
+
...(options.models ? { models: options.models.split(",").map(value => value.trim()) } : {}),
|
|
12768
|
+
} });
|
|
12769
|
+
});
|
|
12770
|
+
}), { hidden: true })
|
|
12745
12771
|
.addCommand(new Command("start")
|
|
12746
12772
|
.description("Start an attended Workspace Copilot session on Oxygen Balanced by default. Starting is free; the next send starts inference using workspace credits. No inference budget is required. Legacy budget flags remain accepted but do not authorize or cap spend. Paid or external actions require separate approval.")
|
|
12747
12773
|
.option("--budget-credits <number>", "Legacy compatibility only: accepted and clamped, but does not authorize or cap attended Copilot inference.")
|
|
@@ -12804,6 +12830,7 @@ Examples:
|
|
|
12804
12830
|
.argument("<sessionId>", "Copilot session id.")
|
|
12805
12831
|
.option("--after-seq <n>", "Only return events after this sequence number.")
|
|
12806
12832
|
.option("--events <n>", "Maximum events to return.")
|
|
12833
|
+
.option("--wait-seconds <n>", "Native bounded event long-poll, requires --after-seq (maximum 50 seconds).")
|
|
12807
12834
|
.option("--json", "Print a JSON envelope.")
|
|
12808
12835
|
.action(async (sessionId, options) => {
|
|
12809
12836
|
await handleAsyncAction("copilot get", options, () => {
|
|
@@ -12812,6 +12839,8 @@ Examples:
|
|
|
12812
12839
|
const eventLimit = readPositiveInt(options.events);
|
|
12813
12840
|
if (afterSeq !== undefined)
|
|
12814
12841
|
query.set("after_seq", String(afterSeq));
|
|
12842
|
+
if (options.waitSeconds !== undefined)
|
|
12843
|
+
query.set("wait_seconds", String(options.waitSeconds));
|
|
12815
12844
|
if (eventLimit !== undefined)
|
|
12816
12845
|
query.set("event_limit", String(eventLimit));
|
|
12817
12846
|
const suffix = query.toString() ? `?${query.toString()}` : "";
|
|
@@ -20549,7 +20578,7 @@ Full trigger schema: oxygen workflows schema --subject trigger --json
|
|
|
20549
20578
|
// exist when this runs, and a family registered later fell into commander's
|
|
20550
20579
|
// trailing default "Commands:" list (the 2026-09-30 blind agent read the first
|
|
20551
20580
|
// 80 lines of help and missed `connectors` there).
|
|
20552
|
-
applyOxygenHelp(program, binaryName);
|
|
20581
|
+
applyOxygenHelp(program, binaryName, `${defaultApiUrl().replace(/\/+$/, "")}/docs`);
|
|
20553
20582
|
// Last, so every command registered above is covered.
|
|
20554
20583
|
enableCommandSuggestions(program);
|
|
20555
20584
|
return program;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { lstat, readdir, readFile } from "node:fs/promises";
|
|
2
2
|
import { join, resolve } from "node:path";
|
|
3
3
|
import { OxygenError } from "@oxygen/shared/cli-result";
|
|
4
|
+
import { WORKSPACE_SKILL_OPERATIONS } from "@oxygen/shared/contracts/workspace-skills";
|
|
4
5
|
import { authorWorkspaceSkill, parseWorkspaceSkillBundle, WORKSPACE_SKILL_MAX_BYTES, WORKSPACE_SKILL_MAX_FILES, WORKSPACE_SKILL_MAX_FILE_BYTES, } from "@oxygen/shared/workspace-skills";
|
|
5
6
|
import { requestOxygen } from "./http-client.js";
|
|
6
7
|
/** Never follow symlinks or read binary files out of a local skill folder. */
|
|
@@ -47,11 +48,11 @@ export function registerWorkspaceSkillCommands(program, handle) {
|
|
|
47
48
|
const skills = program.commands.find((command) => command.name() === "skills");
|
|
48
49
|
const workspace = skills
|
|
49
50
|
.command("workspace")
|
|
50
|
-
.description("Create, upload, find and edit private
|
|
51
|
+
.description("Create, upload, find and edit skills private to this workspace's members.");
|
|
51
52
|
workspace
|
|
52
53
|
.command("create")
|
|
53
|
-
.description(
|
|
54
|
-
.requiredOption("--name <name>", "Lowercase-hyphen
|
|
54
|
+
.description(WORKSPACE_SKILL_OPERATIONS.find((operation) => operation.id === "workspace_skills.create").cli.summary)
|
|
55
|
+
.requiredOption("--name <name>", "Lowercase-hyphen name; stored as workspace-<name>.")
|
|
55
56
|
.requiredOption("--description <text>", "When to use this skill.")
|
|
56
57
|
.requiredOption("--instructions <text>", "Instructions to save.")
|
|
57
58
|
.option("--json", "Print a JSON envelope.")
|
|
@@ -68,7 +69,7 @@ export function registerWorkspaceSkillCommands(program, handle) {
|
|
|
68
69
|
}));
|
|
69
70
|
workspace
|
|
70
71
|
.command("import")
|
|
71
|
-
.description(
|
|
72
|
+
.description(WORKSPACE_SKILL_OPERATIONS.find((operation) => operation.id === "workspace_skills.import").cli.summary)
|
|
72
73
|
.option("--file <path>", "Local SKILL.md file.")
|
|
73
74
|
.option("--directory <path>", "Local skill directory including SKILL.md and supporting text files.")
|
|
74
75
|
.option("--url <url>", "Import a public HTTPS SKILL.md URL. Supporting files require --directory or --files-json.")
|
|
@@ -218,7 +218,7 @@ export function columnDecisionOutputSchema(decision) {
|
|
|
218
218
|
confidence: { type: "number", description: decision.mode === "score"
|
|
219
219
|
? "System One confidence, 0 to 1. It is separate from level probabilities, not their top share or the gap between the top two."
|
|
220
220
|
: "How sure the classifier is, 0 to 1." },
|
|
221
|
-
uncertain: { type: "boolean", description: "True when confidence is below the
|
|
221
|
+
uncertain: { type: "boolean", description: "True when confidence is below the floor, selected evidence is missing or shortened, or required grounding is unusable." },
|
|
222
222
|
reason: { type: "string", description: decision.mode === "score"
|
|
223
223
|
? "Readable level, confidence, and top probabilities; it does not explain the row evidence."
|
|
224
224
|
: "The answer and its confidence in words." },
|
|
@@ -33,16 +33,16 @@ const operation = (verb, method, contract, summary, manualCli = false) => ({
|
|
|
33
33
|
});
|
|
34
34
|
export const WORKSPACE_SKILL_OPERATIONS = [
|
|
35
35
|
operation("list", "GET", obj({
|
|
36
|
-
query: str(),
|
|
37
|
-
cursor: str(),
|
|
38
|
-
limit: int({ minimum: 1, maximum: 100 }),
|
|
39
|
-
}), "Find
|
|
36
|
+
query: str({ description: "Case-insensitive literal substring of the name or description; short keywords work best." }),
|
|
37
|
+
cursor: str({ description: "Exact next_cursor from the previous list response." }),
|
|
38
|
+
limit: int({ minimum: 1, maximum: 100, description: "Skills per page, from 1 to 100." }),
|
|
39
|
+
}), "Find skills shared with workspace members by literal substring of name or description; short keywords work best; read-only, 0 credits; next_cursor continues the list."),
|
|
40
40
|
operation("get", "GET", obj({ name, file }, { required: ["name"] }), "Read a workspace skill's SKILL.md or one supporting text file, with exact content, revision and the document index. Skills are task guidance; they grant no tool, spend or approval authority."),
|
|
41
41
|
operation("create", "POST", obj({
|
|
42
|
-
name: str({ minLength: 1, maxLength: 64 }),
|
|
42
|
+
name: str({ minLength: 1, maxLength: 64, description: "Lowercase-hyphen name; stored as workspace-<name>." }),
|
|
43
43
|
description: str({ minLength: 1, maxLength: 1_024 }),
|
|
44
44
|
instructions: str({ minLength: 1, maxLength: 120_000 }),
|
|
45
|
-
}, { required: ["name", "description", "instructions"] }), "
|
|
45
|
+
}, { required: ["name", "description", "instructions"] }), "Create workspace-<name>, visible to this workspace's members; 0 credits, no inference/provider calls or new tool/spend/approval authority. Creates SKILL.md in Knowledge from a lowercase-hyphen name, description and instructions.", true),
|
|
46
46
|
operation("import", "POST", obj({
|
|
47
47
|
name: str({ maxLength: 64 }),
|
|
48
48
|
files: arr(WORKSPACE_SKILL_FILE_CONTRACT, { minItems: 1, maxItems: 50 }),
|
|
@@ -51,12 +51,12 @@ export const WORKSPACE_SKILL_OPERATIONS = [
|
|
|
51
51
|
description: "Public HTTPS SKILL.md URL (raw text or GitHub file). Choose url or files. A URL imports the entrypoint only; supply files for a complete folder.",
|
|
52
52
|
}),
|
|
53
53
|
source_url,
|
|
54
|
-
}), "Import
|
|
54
|
+
}), "Import to workspace members atomically, create-only; ≤50 text files/1 MB; scripts inert; 0 credits, no inference/paid provider calls or new tool/spend/approval authority. Supply root SKILL.md plus supporting text files, or a public HTTPS SKILL.md URL. Preserves content and source. CLI accepts --file, --directory or --url.", true),
|
|
55
55
|
operation("update", "POST", obj({
|
|
56
56
|
name,
|
|
57
57
|
file,
|
|
58
|
-
content: str({ maxLength: 120_000 }),
|
|
59
|
-
expected_revision: int({ minimum: 1 }),
|
|
60
|
-
}, { required: ["name", "content", "expected_revision"] }), "
|
|
61
|
-
operation("archive", "POST", obj({ name, expected_revision: int({ minimum: 1 }) }, { required: ["name", "expected_revision"] }), "Archive a workspace skill
|
|
58
|
+
content: str({ maxLength: 120_000, description: "Full replacement file; SKILL.md must include YAML frontmatter. Its description drives discovery." }),
|
|
59
|
+
expected_revision: int({ minimum: 1, description: "Revision last read; a stale revision refuses the edit." }),
|
|
60
|
+
}, { required: ["name", "content", "expected_revision"] }), "Replace a skill file at its expected revision; read first, stale revisions refuse; 0 credits, no inference/provider calls or new tool/spend/approval authority. Preserves Knowledge history; defaults to SKILL.md."),
|
|
61
|
+
operation("archive", "POST", obj({ name, expected_revision: int({ minimum: 1, description: "Entrypoint revision last read; stale revisions refuse." }) }, { required: ["name", "expected_revision"] }), "Archive a workspace skill, retaining files and Knowledge history; 0 credits, no inference/provider calls or new tool/spend/approval authority. Requires the entrypoint's expected revision; removes it from discovery."),
|
|
62
62
|
];
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare const ICP_ACCOUNT = "Is the company this person works for a SMALL SOFTWARE STARTUP based in the UNITED STATES: roughly 2 to 50 employees, seed to Series A, selling software or a software-enabled service? Judge from the company name, domain, industry, size and location fields and from the person's own profile text (headline, about, experience). Answer true only when the evidence supports every part; a large company, a non-software business, or a non-US company is false.";
|
|
2
|
+
export declare const ICP_PERSONA = "Is this person a GO-TO-MARKET ENGINEER, a GROWTH or REVENUE OPERATOR (growth, revenue operations, demand generation, outbound, sales development leadership), or a FOUNDER who runs go-to-market at a startup? Judge from the title, headline and experience. Answer true only when the role clearly carries go-to-market or growth responsibility; an engineer without go-to-market scope, a finance, legal, HR or product role, or an unrelated title is false.";
|
|
3
|
+
export declare const TITLE_FIT = "Is this job title a go-to-market, growth, revenue-operations, sales-leadership, marketing-leadership or founder/CEO role? Answer true for titles such as GTM engineer, head of growth, growth lead, revenue operations, director of sales, VP marketing, founder, CEO, co-founder; false for engineering without go-to-market scope, finance, legal, HR, product, design, support or unrelated titles.";
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
// Exact source question text from scripts/evals/copilot-intent/classifier.mjs.
|
|
2
|
+
export const ICP_ACCOUNT = "Is the company this person works for a SMALL SOFTWARE STARTUP based in the UNITED STATES: roughly 2 to 50 employees, seed to Series A, selling software or a software-enabled service? Judge from the company name, domain, industry, size and location fields and from the person's own profile text (headline, about, experience). Answer true only when the evidence supports every part; a large company, a non-software business, or a non-US company is false.";
|
|
3
|
+
export const ICP_PERSONA = "Is this person a GO-TO-MARKET ENGINEER, a GROWTH or REVENUE OPERATOR (growth, revenue operations, demand generation, outbound, sales development leadership), or a FOUNDER who runs go-to-market at a startup? Judge from the title, headline and experience. Answer true only when the role clearly carries go-to-market or growth responsibility; an engineer without go-to-market scope, a finance, legal, HR or product role, or an unrelated title is false.";
|
|
4
|
+
export const TITLE_FIT = "Is this job title a go-to-market, growth, revenue-operations, sales-leadership, marketing-leadership or founder/CEO role? Answer true for titles such as GTM engineer, head of growth, growth lead, revenue operations, director of sales, VP marketing, founder, CEO, co-founder; false for engineering without go-to-market scope, finance, legal, HR, product, design, support or unrelated titles.";
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export type DevEvalContext = Readonly<{
|
|
2
|
+
campaignId: string;
|
|
3
|
+
organizationId: string;
|
|
4
|
+
sessionId: string;
|
|
5
|
+
actionRunId?: string;
|
|
6
|
+
/** Installed by the authenticated host after control-DB lookup, never deserialized. */
|
|
7
|
+
fetch: (provider: string, operation: string, input: string | Request | URL, init: RequestInit | undefined, transport: typeof fetch) => Promise<Response>;
|
|
8
|
+
}>;
|
|
9
|
+
export declare const currentDevEvalContext: () => Readonly<{
|
|
10
|
+
campaignId: string;
|
|
11
|
+
organizationId: string;
|
|
12
|
+
sessionId: string;
|
|
13
|
+
actionRunId?: string;
|
|
14
|
+
/** Installed by the authenticated host after control-DB lookup, never deserialized. */
|
|
15
|
+
fetch: (provider: string, operation: string, input: string | Request | URL, init: RequestInit | undefined, transport: typeof fetch) => Promise<Response>;
|
|
16
|
+
}> | null;
|
|
17
|
+
export declare const withDevEvalContext: <T>(context: DevEvalContext | null, fn: () => T) => T;
|
|
18
|
+
export declare const initializeDevEvalRequest: () => void;
|
|
19
|
+
export declare const enterDevEvalContext: (context: DevEvalContext | null) => void;
|
|
20
|
+
export declare function devEvalRefusal(reason: string, outcome?: "not_applied" | "unknown"): never;
|
|
21
|
+
export declare function devEvalFetch(provider: string, operation: string, input: string | Request | URL, init: RequestInit | undefined, transport?: typeof fetch): Promise<Response>;
|
|
22
|
+
export declare const DEV_EVAL_SAFE_CAPABILITIES: Set<string>;
|
|
23
|
+
/** No approval or model-provided argument can override this trial policy. */
|
|
24
|
+
export declare function assertDevEvalCapability(name: string, args?: Record<string, unknown>): void;
|
|
25
|
+
export declare const DEV_EVAL_BLITZ_OPERATIONS: Set<string>;
|
|
26
|
+
export declare function assertDevEvalTool(toolId: string): void;
|
|
27
|
+
export declare function devEvalActionMetadata(metadata?: Record<string, unknown>): Record<string, unknown>;
|
|
28
|
+
export declare function assertDevEvalOrganization(organizationId: string | null | undefined): void;
|
|
29
|
+
/** Native queued-column entry: unsupported child engines cannot shed attribution. */
|
|
30
|
+
export declare function assertDevEvalColumn(column: {
|
|
31
|
+
kind: string;
|
|
32
|
+
definition: unknown;
|
|
33
|
+
}, actionType?: string): void;
|
|
34
|
+
/** Native host marker only requires a matching ledger; it never creates authority. */
|
|
35
|
+
export declare function assertDevEvalSessionContext(metadata: Record<string, unknown>, context: DevEvalContext | null): void;
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
2
|
+
import { OxygenError } from "./cli-result.js";
|
|
3
|
+
// Mutable carrier is installed synchronously before the route awaits authentication.
|
|
4
|
+
// The authenticated resolver populates this carrier; enterWith after an await
|
|
5
|
+
// would only alter the resolver continuation and lose attribution in its caller.
|
|
6
|
+
const scope = new AsyncLocalStorage();
|
|
7
|
+
export const currentDevEvalContext = () => scope.getStore()?.context ?? null;
|
|
8
|
+
export const withDevEvalContext = (context, fn) => scope.run({ context }, fn);
|
|
9
|
+
export const initializeDevEvalRequest = () => scope.enterWith({ context: null });
|
|
10
|
+
export const enterDevEvalContext = (context) => {
|
|
11
|
+
const carrier = scope.getStore();
|
|
12
|
+
if (!carrier) {
|
|
13
|
+
if (context)
|
|
14
|
+
devEvalRefusal("request_carrier_missing");
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
carrier.context = context;
|
|
18
|
+
};
|
|
19
|
+
export function devEvalRefusal(reason, outcome = "not_applied") {
|
|
20
|
+
const error = new OxygenError("dev_eval_policy_refused", `Dev campaign dispatch refused: ${reason}.`, {
|
|
21
|
+
details: { reason, effect_outcome: outcome, retryable: false }, exitCode: 1,
|
|
22
|
+
});
|
|
23
|
+
Object.assign(error, { retryable: false, effect_outcome: outcome });
|
|
24
|
+
throw error;
|
|
25
|
+
}
|
|
26
|
+
export async function devEvalFetch(provider, operation, input, init, transport = fetch) {
|
|
27
|
+
const context = currentDevEvalContext();
|
|
28
|
+
return context ? context.fetch(provider, operation, input, init, transport) : transport(input, init);
|
|
29
|
+
}
|
|
30
|
+
export const DEV_EVAL_SAFE_CAPABILITIES = new Set([
|
|
31
|
+
"oxygen_tables_list", "oxygen_tables_sources", "oxygen_tables_describe", "oxygen_tables_preview", "oxygen_tables_query", "oxygen_tables_create", "oxygen_tables_update", "oxygen_tables_rows_add", "oxygen_tables_rows_update",
|
|
32
|
+
"oxygen_columns_catalog", "oxygen_columns_deps", "oxygen_columns_add", "oxygen_columns_update", "oxygen_columns_run", "oxygen_columns_materialize",
|
|
33
|
+
"oxygen_enrichment_catalog", "oxygen_tools_search", "oxygen_tools_describe", "oxygen_tools_check_access", "oxygen_tools_plan_table_batch", "oxygen_tools_run_dry", "oxygen_tools_run_live",
|
|
34
|
+
"oxygen_people_search_preview", "oxygen_people_search_plan", "oxygen_people_search_run", "oxygen_companies_search_preview", "oxygen_companies_search_plan", "oxygen_companies_search_run",
|
|
35
|
+
"oxygen_sequences_list", "oxygen_sequences_create", "oxygen_sequences_draft", "oxygen_sequences_update", "oxygen_sequences_get", "oxygen_sequences_stats", "oxygen_sequences_events", "oxygen_sequences_render", "oxygen_sequences_enroll", "oxygen_sequences_enrollments", "oxygen_sequences_contacts", "oxygen_sequences_analytics"
|
|
36
|
+
]);
|
|
37
|
+
/** No approval or model-provided argument can override this trial policy. */
|
|
38
|
+
export function assertDevEvalCapability(name, args = {}) {
|
|
39
|
+
if (!currentDevEvalContext())
|
|
40
|
+
return;
|
|
41
|
+
if (name === "oxygen_sequences_start" && args.approved === false)
|
|
42
|
+
return; // Native nonexecuting preview remains available.
|
|
43
|
+
if (!DEV_EVAL_SAFE_CAPABILITIES.has(name))
|
|
44
|
+
devEvalRefusal("capability_not_trial_safe");
|
|
45
|
+
if (args.then !== undefined || args.chain !== undefined)
|
|
46
|
+
devEvalRefusal("unsupported_chain_dispatch");
|
|
47
|
+
if (typeof args.max_credits === "number" && (!Number.isFinite(args.max_credits) || args.max_credits > 200))
|
|
48
|
+
devEvalRefusal("declared_credit_ceiling_too_large");
|
|
49
|
+
if (/(send|start|resume|publish|purchase|invite|mailbox|warmup|domain|crm|composio|custom_http|sandbox|infra|workflows|agents_)/i.test(name)) {
|
|
50
|
+
devEvalRefusal("forbidden_effect");
|
|
51
|
+
}
|
|
52
|
+
if (/sequence/i.test(name)) {
|
|
53
|
+
if (!/^oxygen_sequences_(list|create|draft|update|get|stats|events|render|enroll|enrollments|contacts|analytics)$/.test(name))
|
|
54
|
+
devEvalRefusal("sequence_effect_not_draft");
|
|
55
|
+
const inspect = (value) => {
|
|
56
|
+
if (!value || typeof value !== "object")
|
|
57
|
+
return;
|
|
58
|
+
for (const [key, child] of Object.entries(value)) {
|
|
59
|
+
if (/sender|mailbox|account.*id|emailConnection|emailProviderCampaign/i.test(key) && child !== null && child !== undefined && child !== "" && !(Array.isArray(child) && child.length === 0))
|
|
60
|
+
devEvalRefusal("draft_requires_no_sender");
|
|
61
|
+
if (/^(status|state)$/.test(key) && child !== "draft" && child !== undefined && child !== null)
|
|
62
|
+
devEvalRefusal("sequence_requires_draft");
|
|
63
|
+
inspect(child);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
if (args.enroll === true || args.auto_start === true)
|
|
67
|
+
devEvalRefusal("draft_creation_with_automatic_enrollment");
|
|
68
|
+
inspect(args);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
export const DEV_EVAL_BLITZ_OPERATIONS = new Set(["company_search", "people_search", "employee_search", "waterfall_person_search", "waterfall_icp_search", "person_enrich", "person_profile_enrich", "company_profile_enrich", "domain_to_linkedin", "company_enrich", "key_info"]);
|
|
72
|
+
export function assertDevEvalTool(toolId) {
|
|
73
|
+
if (!currentDevEvalContext())
|
|
74
|
+
return;
|
|
75
|
+
if (!toolId.startsWith("blitzapi.") || !DEV_EVAL_BLITZ_OPERATIONS.has(toolId.slice(9)))
|
|
76
|
+
devEvalRefusal("data_provider_or_operation");
|
|
77
|
+
}
|
|
78
|
+
export function devEvalActionMetadata(metadata = {}) {
|
|
79
|
+
const { dev_eval: _untrusted, ...rest } = metadata;
|
|
80
|
+
const context = currentDevEvalContext();
|
|
81
|
+
return context ? { ...rest, dev_eval: { campaignId: context.campaignId,
|
|
82
|
+
organizationId: context.organizationId, sessionId: context.sessionId } } : rest;
|
|
83
|
+
}
|
|
84
|
+
export function assertDevEvalOrganization(organizationId) {
|
|
85
|
+
const context = currentDevEvalContext();
|
|
86
|
+
if (context && context.organizationId !== organizationId)
|
|
87
|
+
devEvalRefusal("organization_attribution_mismatch");
|
|
88
|
+
}
|
|
89
|
+
/** Native queued-column entry: unsupported child engines cannot shed attribution. */
|
|
90
|
+
export function assertDevEvalColumn(column, actionType = "tool_column") {
|
|
91
|
+
if (!currentDevEvalContext())
|
|
92
|
+
return;
|
|
93
|
+
if (actionType !== "tool_column" || !['ai', 'research', 'tool', 'formula'].includes(column.kind))
|
|
94
|
+
devEvalRefusal('unsupported_column_child_engine');
|
|
95
|
+
const definition = column.definition;
|
|
96
|
+
if (definition?.mode === 'composio' || definition?.mode === 'custom_http')
|
|
97
|
+
devEvalRefusal('forbidden_column_transport');
|
|
98
|
+
if (column.kind === 'tool')
|
|
99
|
+
assertDevEvalTool(String(definition?.toolId ?? ''));
|
|
100
|
+
}
|
|
101
|
+
/** Native host marker only requires a matching ledger; it never creates authority. */
|
|
102
|
+
export function assertDevEvalSessionContext(metadata, context) {
|
|
103
|
+
const marker = metadata.dev_eval;
|
|
104
|
+
if (!marker)
|
|
105
|
+
return;
|
|
106
|
+
if (typeof marker !== 'object' || !context || marker.campaignId !== context.campaignId)
|
|
107
|
+
devEvalRefusal('registered_session_context_unavailable');
|
|
108
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const OXYGEN_BUILD_VERSION = "1.1014.
|
|
1
|
+
export declare const OXYGEN_BUILD_VERSION = "1.1014.81";
|
|
@@ -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.1014.
|
|
2
|
+
export const OXYGEN_BUILD_VERSION = "1.1014.81";
|