@oxygen-agent/cli 1.1014.19 → 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.
Files changed (37) hide show
  1. package/README.md +1 -1
  2. package/dist/command-manifest.js +1 -1
  3. package/dist/help.d.ts +1 -1
  4. package/dist/help.js +25 -3
  5. package/dist/index.js +81 -16
  6. package/dist/json-output.d.ts +3 -0
  7. package/dist/json-output.js +33 -0
  8. package/dist/workspace-skill-commands.d.ts +9 -0
  9. package/dist/workspace-skill-commands.js +135 -0
  10. package/node_modules/@oxygen/shared/dist/capability-discovery.js +9 -0
  11. package/node_modules/@oxygen/shared/dist/column-decision.js +1 -1
  12. package/node_modules/@oxygen/shared/dist/contracts/operations.js +4 -3
  13. package/node_modules/@oxygen/shared/dist/contracts/table-query-grid.d.ts +1 -1
  14. package/node_modules/@oxygen/shared/dist/contracts/table-query-grid.js +7 -4
  15. package/node_modules/@oxygen/shared/dist/contracts/table-query-raw.d.ts +14 -0
  16. package/node_modules/@oxygen/shared/dist/contracts/table-query-raw.js +18 -0
  17. package/node_modules/@oxygen/shared/dist/contracts/workspace-skills.d.ts +6 -0
  18. package/node_modules/@oxygen/shared/dist/contracts/workspace-skills.js +62 -0
  19. package/node_modules/@oxygen/shared/dist/dev-eval-classifier.d.ts +3 -0
  20. package/node_modules/@oxygen/shared/dist/dev-eval-classifier.js +4 -0
  21. package/node_modules/@oxygen/shared/dist/dev-eval-context.d.ts +35 -0
  22. package/node_modules/@oxygen/shared/dist/dev-eval-context.js +108 -0
  23. package/node_modules/@oxygen/shared/dist/diagnostic-storage-lock.js +5 -1
  24. package/node_modules/@oxygen/shared/dist/diagnostic-storage.js +178 -63
  25. package/node_modules/@oxygen/shared/dist/email-health-status.d.ts +11 -0
  26. package/node_modules/@oxygen/shared/dist/email-health-status.js +16 -0
  27. package/node_modules/@oxygen/shared/dist/hosted-ai.d.ts +3 -2
  28. package/node_modules/@oxygen/shared/dist/hosted-ai.js +9 -6
  29. package/node_modules/@oxygen/shared/dist/langfuse.d.ts +4 -2
  30. package/node_modules/@oxygen/shared/dist/langfuse.js +123 -66
  31. package/node_modules/@oxygen/shared/dist/table-run-summary.d.ts +2 -0
  32. package/node_modules/@oxygen/shared/dist/table-run-summary.js +26 -0
  33. package/node_modules/@oxygen/shared/dist/version.generated.d.ts +1 -1
  34. package/node_modules/@oxygen/shared/dist/version.generated.js +1 -1
  35. package/node_modules/@oxygen/shared/dist/workspace-skills.d.ts +26 -0
  36. package/node_modules/@oxygen/shared/dist/workspace-skills.js +102 -0
  37. package/package.json +1 -1
package/README.md CHANGED
@@ -34,4 +34,4 @@ oxygen update
34
34
 
35
35
  For product documentation, visit https://oxygen-agent.com/docs. For support, visit https://oxygen-agent.com.
36
36
 
37
- Version: 1.1014.19
37
+ Version: 1.1014.81
@@ -306,7 +306,7 @@ export function searchCommandManifest(manifest, query, requestedLimit = DEFAULT_
306
306
  commands: matches.slice(0, limit).map(({ command, score }) => ({
307
307
  name: command.name,
308
308
  group: command.group,
309
- description: command.description,
309
+ description: (command.description.split(/(?<=[.!?])\s/)[0] ?? command.description).slice(0, 180),
310
310
  spends_credits: command.spends_credits,
311
311
  mutates: command.mutates,
312
312
  destructive: command.destructive,
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,7 +125,16 @@ 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
+ program.option("--help-full", "Show expanded command and option descriptions.");
130
+ const configure = (command) => {
131
+ command.configureHelp({
132
+ subcommandDescription: (cmd) => shortHelpDescription(cmd.description()),
133
+ });
134
+ for (const child of command.commands)
135
+ configure(child);
136
+ };
137
+ configure(program);
129
138
  const headingByCommand = new Map();
130
139
  for (const group of HELP_GROUPS) {
131
140
  for (const name of group.commands)
@@ -140,6 +149,7 @@ export function applyOxygenHelp(program, binaryName) {
140
149
  program.addHelpText("before", [
141
150
  "",
142
151
  "Agent quickstart:",
152
+ " Help is concise; --help-full or commands get <name> --json retains complete grammar.",
143
153
  ` 1. ${binaryName} login connect this terminal (or set OXYGEN_API_KEY)`,
144
154
  ` ${binaryName} whoami --summary-json confirm the active workspace and identity (0 credits)`,
145
155
  // `login` auto-installs the skills, but an agent authenticating with
@@ -159,7 +169,7 @@ export function applyOxygenHelp(program, binaryName) {
159
169
  ` 5. ${binaryName} recipes list "<goal>" --view summary --json choose a play from the Recipe catalog for your goal`,
160
170
  ` Provider inventory: ${binaryName} tools search <brand> --json, then ${binaryName} tools search --provider <provider-id> --all --json (Blitz uses blitzapi).`,
161
171
  ` Installable systems and recurring monitors: ${binaryName} blueprints list --json.`,
162
- " Docs: https://oxygen-agent.com/docs",
172
+ ` Docs: ${docsUrl}`,
163
173
  "",
164
174
  "Conventions:",
165
175
  " --json prints a stable envelope {ok, data|error, meta}; errors always print it.",
@@ -171,6 +181,16 @@ export function applyOxygenHelp(program, binaryName) {
171
181
  ].join("\n"));
172
182
  program.addHelpText("afterAll", `\nExit codes: ${exitCodeLine}`);
173
183
  }
184
+ function shortHelpDescription(description) {
185
+ if (process.argv.includes("--help-full"))
186
+ return description;
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(" ");
193
+ }
174
194
  /**
175
195
  * Turn commander's own edit-distance suggester on for EVERY command.
176
196
  *
@@ -443,7 +463,9 @@ function buildUnknownCommandHint(parent, path, token) {
443
463
  // command.
444
464
  const prefixMatches = names.filter((name) => name.startsWith(lower));
445
465
  const suggestion = synonym ?? (prefixMatches.length === 1 ? prefixMatches[0] : null);
446
- const helpLine = `Run \`${path} --help\` for the ${names.length} subcommands of \`${path}\`.`;
466
+ const query = path.split(" ").slice(1).concat(token).join(" ");
467
+ const quotedQuery = `'${query.replace(/'/g, "'\\''")}'`;
468
+ const helpLine = `Find the command with \`${path.split(" ")[0]} commands search ${quotedQuery} --json\`; hydrate the selected name with \`${path.split(" ")[0]} commands get <name> --json\`.`;
447
469
  return suggestion
448
470
  ? `Hint: \`${path}\` has no \`${token}\`. Did you mean \`${path} ${suggestion}\`? ${helpLine}`
449
471
  : `Hint: \`${path}\` has no \`${token}\`. ${helpLine}`;
package/dist/index.js CHANGED
@@ -20,6 +20,7 @@ import { applyOxygenHelp, argvRequestsJson, commanderUsageFailure, commandNameFo
20
20
  import { homeStandupMarksSeen } from "./home-standup.js";
21
21
  import { ensureFreshCliForApiUrl, requestOxygen } from "./http-client.js";
22
22
  import { formatInboxNeedsReplyNotice } from "./inbox-needs-reply-notice.js";
23
+ import { serializeCliJson, writeExclusiveJson } from "./json-output.js";
23
24
  import { acquireMirrorLock, clearConflictFiles, deletePageFile, emptyMirrorState, findMirrorSlugByPageId, isFileDirty, listConflictFiles, listLocalMirrors, localPageSha256, markMirrorStale, mirrorExists, pageFilePath, planMirrorPush, purgeMirror, resetMirrorForFullResync, quarantineDirtyFile, readMirrorState, releaseMirrorLock, resolveDefaultConfigDir, resolveMirrorDir, writeGeneratedIndexFile, writeGeneratedLogFile, writeMirrorState, writePageFile, } from "./knowledge-mirror.js";
24
25
  import { registerKnowledgeRepositoryCommands } from "./knowledge-repository-commands.js";
25
26
  import { runLocalCustomHttpColumn } from "./local-custom-http-column.js";
@@ -42,6 +43,7 @@ import { registerVisualCommands } from "./visual-commands.js";
42
43
  import { WHATSAPP_ACCOUNT_FLAGS, whatsappAccountQuery } from "./whatsapp-account-flags.js";
43
44
  import { formatWorkflowPlanLimitNotices } from "./workflow-plan-limit-notices.js";
44
45
  import { WORKFLOW_RUN_LIST_FLAG_OVERLAY, readWorkflowRunListFlags } from "./workflow-run-list-flags.js";
46
+ import { registerWorkspaceSkillCommands } from "./workspace-skill-commands.js";
45
47
  import { addProviderLimitFlags, addSuppressionListFlags, providerLimitBody, providerLimitQuery, suppressionListQuery } from "./workspace-utility-flags.js";
46
48
  import { isRecipeDefinition } from "@oxygen/recipe-sdk";
47
49
  import { AGENCY_DIRECTORY_REGIONS, AGENCY_DIRECTORY_SERVICES, COLLAB_GATE_KINDS, COLLAB_GATE_PROSE, COLLAB_SUBJECT_KINDS, COLLAB_SUBJECT_KINDS_PROSE, COLLAB_SUBJECT_LABELS, COLLAB_SUBJECT_PROSE, GATE_KIND_SUBJECTS, describeWorkflowStatusChange, formatCellForDisplay, formatCopilotPlanDuration, formatCopilotPlanSeconds, formatPublicBudgetScopes, SUBJECT_PATH_FORMS_PROSE, formatSubjectPath, exitCodeForOxygenError, parseSubjectPath, parseSubjectRef, parseWorkflowStatusChange, chunk, isVersionGreater, isVersionLess, KNOWLEDGE_BOOTSTRAP_MAX_CREDITS, MAX_CLI_JSON_BODY_BYTES, MAX_MCP_TOOL_NAME_LENGTH, normalizeCopilotPlanStepStatus, OXYGEN_CAPABILITY_ROUTES, OXYGEN_VERSION, OxygenError, getCapabilityRouteMatch, inferUserCapabilityRoute, parseKnowledgePageMarkdown, PLAN_LIMITS, serializeCapabilityRoute, sleep, success, TAG_KINDS_PROSE, toFailure, workflowMcpToolName, } from "@oxygen/shared";
@@ -65,6 +67,7 @@ import { SEQUENCE_LIST_PROJECTION_CONTRACT } from "@oxygen/shared/contracts/sequ
65
67
  import { TABLE_FEED_UPDATE_CONTRACT, tableFeedUpdateIssues } from "@oxygen/shared/contracts/table-feed-update";
66
68
  import { TABLE_LIST_QUERY_CONTRACT, tableListQueryParams } from "@oxygen/shared/contracts/table-list";
67
69
  import { TABLE_QUERY_GRID_CONTRACT } from "@oxygen/shared/contracts/table-query-grid";
70
+ import { TABLE_QUERY_CLI_DEFAULT_LIMIT, TABLE_QUERY_CLI_DEFAULT_MAX_CHARS, tableQueryRawResultFits, tableQueryRawRecovery } from "@oxygen/shared/contracts/table-query-raw";
68
71
  import { WHATSAPP_ACCOUNTS_READ_CONTRACT } from "@oxygen/shared/contracts/whatsapp-reads";
69
72
  import { WORKFLOW_RUN_LIST_CONTRACT, workflowRunListQueryParams } from "@oxygen/shared/contracts/workflow-run-list";
70
73
  import { COPILOT_ASK_USER_TOOL_NAME, normalizeCopilotQuestions } from "@oxygen/shared/copilot-questions";
@@ -79,6 +82,7 @@ import { TAG_COLORS } from "@oxygen/shared/select-options";
79
82
  import { SEQUENCE_LIFECYCLES, sequenceDisplayStatus } from "@oxygen/shared/sequence-lifecycle";
80
83
  import { lookupColumnDataType } from "@oxygen/shared/table-field-types";
81
84
  import { FILTER_TREE_OPERATORS } from "@oxygen/shared/table-filter-operators";
85
+ import { tableRunSummary } from "@oxygen/shared/table-run-summary";
82
86
  import { assertRecipeBundleSafe, assertPortableWorkflowDefinition, assertWorkflowGraphManifest, assertWorkflowManifest, buildRecipeManifest, compileWorkflowDefinition, isAnyWorkflowManifest, isRecipeManifest, isWorkflowDefinition, isWorkflowGraphManifest, isWorkflowManifest, hashPortableWorkflowGraphManifest, WORKFLOW_GRAPH_COMPILER_VERSION, WORKFLOW_GRAPH_MANIFEST_VERSION, } from "@oxygen/workflows";
83
87
  import { Command, CommanderError, Option } from "commander";
84
88
  import { execFileSync } from "node:child_process";
@@ -435,7 +439,7 @@ const RECIPE_ESBUILD_NODE_PATHS = [
435
439
  resolve(CLI_MODULE_DIR, "../../../node_modules"),
436
440
  ];
437
441
  function writeJson(value) {
438
- process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
442
+ process.stdout.write(serializeCliJson(value, process.argv.includes("--pretty")));
439
443
  }
440
444
  function linkBar(coverage, width = 36) {
441
445
  const filled = Math.max(0, Math.min(width, Math.round(coverage * width)));
@@ -3668,6 +3672,7 @@ export function createProgram() {
3668
3672
  .name(binaryName)
3669
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.")
3670
3674
  .version(OXYGEN_VERSION)
3675
+ .option("--pretty", "Indent JSON for human reading; omit for compact agent output.")
3671
3676
  .option("--profile <name>", "Use a stored CLI profile for this command.")
3672
3677
  .option("--org <organization>", "Use an organization id, Clerk org id, or slug for this command.");
3673
3678
  program.hook("preAction", (_root, selected) => {
@@ -7236,11 +7241,12 @@ fixed scan; watermark_cursor starts a later bounded replay. Consumers must retai
7236
7241
  });
7237
7242
  }))
7238
7243
  .addCommand(addContractFlags(new Command("query"), TABLE_QUERY_GRID_CONTRACT, {
7239
- 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
+ max_chars: { help: "Maximum compact JSON envelope characters for raw or grid reads (1,000-100,000). Raw defaults to 12,000." },
7240
7246
  })
7241
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.")
7242
7248
  .argument("<table>", "Table id or slug.")
7243
- .option("--limit <n>", "Raw: default 100, native cap 2000. Grid: default 50, cap 200.")
7249
+ .option("--limit <n>", "Raw: default 20, native cap 2000; --full restores default 100. Grid: default 50, cap 200.")
7244
7250
  .option("--cursor <cursor>", "Pagination cursor returned by a previous query. Walks forward one page at a time; mutually exclusive with --offset.")
7245
7251
  .option("--offset <n>", "Skip this many rows and start there — jump straight to a row without paging to it. Mutually exclusive with --cursor.")
7246
7252
  .option("--fields <columns>", "Comma-separated column keys or ids to include.")
@@ -7250,14 +7256,21 @@ fixed scan; watermark_cursor starts a later bounded replay. Consumers must retai
7250
7256
  .option("--formula-values <mode>", "Formula filters are refused by default because displayed formulas are evaluated live. Refresh the formula's stored cells with `columns run <table> <column> --force` (0 credits), then pass 'materialized'; filtering uses that stored snapshot and returns a freshness note. A fill-empty field a bundle adds (definition fill: \"empty\", such as Headcount or Job title) is stored, not live: its cell is the value, so 'materialized' filters it exactly.")
7251
7257
  .option("--sort-json <json>", "Ordered sort rules, e.g. '[{\"columnKey\":\"_created_at\",\"direction\":\"desc\"}]'. Earlier rules dominate. Mutually exclusive with --filter-json.")
7252
7258
  .option("--no-system-fields", "Omit _row_id, _created_at, and _updated_at from returned rows (included by default).")
7259
+ .option("--full", "Read legacy full rows without the default character limit.")
7260
+ .option("--output <path>", "Write full JSON for this page to a new local file; print a small receipt.")
7253
7261
  .option("--json", "Print a JSON envelope.")
7254
7262
  .action(async (table, options) => {
7255
- await handleAsyncAction("tables query", options, () => {
7263
+ await handleAsyncAction("tables query", options, async () => {
7256
7264
  const gridArgs = readContractFlags(options, TABLE_QUERY_GRID_CONTRACT);
7257
- if (gridArgs.format !== "grid" && Object.keys(gridArgs).length > 0) {
7265
+ if (gridArgs.format !== "grid" && Object.keys(gridArgs).some((key) => key !== "max_chars")) {
7258
7266
  throw new OxygenError("invalid_request", "Grid options require --format grid.", { exitCode: 1 });
7259
7267
  }
7260
- const limit = readPositiveInt(options.limit);
7268
+ const full = options.full || Boolean(options.output);
7269
+ if (full && options.format === "grid")
7270
+ throw new OxygenError("invalid_request", "--full/--output require raw rows; omit --format grid.", { exitCode: 2 });
7271
+ const limit = readPositiveInt(options.limit) ?? (options.format !== "grid" && !full ? TABLE_QUERY_CLI_DEFAULT_LIMIT : undefined);
7272
+ if (options.format !== "grid" && !full && gridArgs.max_chars === undefined)
7273
+ gridArgs.max_chars = TABLE_QUERY_CLI_DEFAULT_MAX_CHARS;
7261
7274
  const filters = readFilterJsonOption(options.filterJson);
7262
7275
  const filterTree = readJsonObjectOption(options.filterTreeJson);
7263
7276
  const formulaValues = readFormulaValuesOption(options.formulaValues);
@@ -7276,7 +7289,7 @@ fixed scan; watermark_cursor starts a later bounded replay. Consumers must retai
7276
7289
  readOption(options.search) || formulaValues || sorts?.length || (offset !== undefined && offset > 0))) {
7277
7290
  throw new OxygenError("invalid_request", '--format grid takes only table, --limit, --cursor and optional --include-stats/--include-fill; omit --format for filters, fields, search, sorts or offsets.', { exitCode: 1 });
7278
7291
  }
7279
- return requestOxygen("/api/cli/tables/query", {
7292
+ const data = await requestOxygen("/api/cli/tables/query", {
7280
7293
  method: "POST",
7281
7294
  body: {
7282
7295
  table,
@@ -7293,6 +7306,17 @@ fixed scan; watermark_cursor starts a later bounded replay. Consumers must retai
7293
7306
  ...(options.systemFields === false ? { include_system_fields: false } : {}),
7294
7307
  },
7295
7308
  });
7309
+ // Enforce the window even against an older compatible serving API.
7310
+ if (options.format !== "grid" && !tableQueryRawResultFits(data, typeof gridArgs.max_chars === "number" ? gridArgs.max_chars : undefined)) {
7311
+ const firstRow = Array.isArray(data.rows) ? data.rows[0] : undefined;
7312
+ throw new OxygenError("table_query_result_too_large", "Table rows exceed the requested result window.", {
7313
+ details: { max_chars: gridArgs.max_chars, ...tableQueryRawRecovery(table, typeof firstRow?._row_id === "string" ? firstRow._row_id : undefined) }, exitCode: 2,
7314
+ });
7315
+ }
7316
+ if (!options.output)
7317
+ return data;
7318
+ const output = await writeExclusiveJson(options.output, success("tables query", data), process.argv.includes("--pretty"));
7319
+ return { output, returned_count: data.returned_count ?? data.returnedCount, total_count: data.total_count ?? data.totalCount, hasMore: data.hasMore, nextCursor: data.nextCursor, web_url: data.web_url };
7296
7320
  });
7297
7321
  }))
7298
7322
  .addCommand(new Command("preview")
@@ -10656,11 +10680,17 @@ Examples:
10656
10680
  .addCommand(new Command("functions")
10657
10681
  .description("List every formula function (name, signature, examples), the operator grammar, and the expression_notes that a signature cannot teach (bare column keys, string escapes, no regex flags, read-time evaluation). The same language powers formula columns and --run-condition gates.")
10658
10682
  .option("--category <category>", "Filter by category: logic, string, number, date, url_email, array, json, null_handling, cross_row.")
10683
+ .option("--query <text>", "Find functions by name, signature or description.")
10659
10684
  .option("--json", "Print a JSON envelope.")
10660
10685
  .action(async (options) => {
10661
10686
  await handleAsyncAction("formulas functions", options, () => {
10662
10687
  const category = readOption(options.category);
10663
- const query = category ? `?category=${encodeURIComponent(category)}` : "";
10688
+ const params = new URLSearchParams();
10689
+ if (category)
10690
+ params.set("category", category);
10691
+ if (readOption(options.query))
10692
+ params.set("query", readOption(options.query));
10693
+ const query = params.size ? `?${params.toString()}` : "";
10664
10694
  return requestOxygen(`/api/cli/tables/formulas/functions${query}`, { method: "GET" });
10665
10695
  });
10666
10696
  }))
@@ -10739,9 +10769,11 @@ Examples:
10739
10769
  .addCommand(new Command("get")
10740
10770
  .description("Get one durable table action run. For a Function run, selection.rowIds are rows of the Function's execution table, not the calling table; list the calling table's rows it wrote with `tables query <caller> --filter-tree-json` on the Function column's \"action_run_id\" path.")
10741
10771
  .argument("<run_id>", "Table action run UUID or parent workspace run UUID.")
10772
+ .option("--full", "Read the full run, including stored inputs and metadata.")
10742
10773
  .option("--json", "Print a JSON envelope.")
10743
10774
  .action(async (runId, options) => {
10744
- await handleAsyncAction("table-runs get", options, () => requestOxygen(`/api/cli/table-action-runs/${encodeURIComponent(runId)}`));
10775
+ await handleAsyncAction("table-runs get", options, () => requestOxygen(`/api/cli/table-action-runs/${encodeURIComponent(runId)}?view=${options.full ? "full" : "summary"}`)
10776
+ .then((run) => options.full ? run : tableRunSummary(run)));
10745
10777
  }))
10746
10778
  .addCommand(new Command("items")
10747
10779
  .description("List row items for a durable table action run. For a Function run, list the calling table's rows it wrote with `tables query <caller> --filter-tree-json` on the Function column's \"action_run_id\" path instead of joining items.")
@@ -10766,6 +10798,7 @@ Examples:
10766
10798
  .argument("<run_id>", "Table action run UUID or parent workspace run UUID.")
10767
10799
  .option("--timeout-seconds <n>", "Maximum time to wait. Defaults to 600.")
10768
10800
  .option("--interval-seconds <n>", "Polling interval. Defaults to 5.")
10801
+ .option("--full", "Return the full completed run instead of a progress summary.")
10769
10802
  .option("--json", "Print a JSON envelope.")
10770
10803
  .action(async (runId, options) => {
10771
10804
  await handleAsyncAction("table-runs wait", options, () => waitForTableActionRun(runId, options));
@@ -12709,6 +12742,32 @@ Examples:
12709
12742
  program
12710
12743
  .command("copilot")
12711
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 })
12712
12771
  .addCommand(new Command("start")
12713
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.")
12714
12773
  .option("--budget-credits <number>", "Legacy compatibility only: accepted and clamped, but does not authorize or cap attended Copilot inference.")
@@ -12771,6 +12830,7 @@ Examples:
12771
12830
  .argument("<sessionId>", "Copilot session id.")
12772
12831
  .option("--after-seq <n>", "Only return events after this sequence number.")
12773
12832
  .option("--events <n>", "Maximum events to return.")
12833
+ .option("--wait-seconds <n>", "Native bounded event long-poll, requires --after-seq (maximum 50 seconds).")
12774
12834
  .option("--json", "Print a JSON envelope.")
12775
12835
  .action(async (sessionId, options) => {
12776
12836
  await handleAsyncAction("copilot get", options, () => {
@@ -12779,6 +12839,8 @@ Examples:
12779
12839
  const eventLimit = readPositiveInt(options.events);
12780
12840
  if (afterSeq !== undefined)
12781
12841
  query.set("after_seq", String(afterSeq));
12842
+ if (options.waitSeconds !== undefined)
12843
+ query.set("wait_seconds", String(options.waitSeconds));
12782
12844
  if (eventLimit !== undefined)
12783
12845
  query.set("event_limit", String(eventLimit));
12784
12846
  const suffix = query.toString() ? `?${query.toString()}` : "";
@@ -16689,10 +16751,11 @@ Examples:
16689
16751
  .option("--status <status>", "Filter by enrollment status (pending, active, waiting_connection, waiting_signal, replied, completed, stopped, failed, excluded). pending = enrolled, not started (next_due not_started); waiting_connection = invite sent, not accepted yet. Status is the lead's progress, not its invite: use --invite accepted for the leads that accepted.")
16690
16752
  .option("--step <n>", "Only leads currently on this step (0-based index, as in the sequence's steps).")
16691
16753
  .option("--invite <state>", "Only leads in this LinkedIn invite state: accepted (invited and connected), pending (invited, not accepted yet) or not_invited (no invite: already connected before, suppressed or email-only).")
16692
- .option("--view <view>", "full (default, every enrollment field) or compact (one short row per lead with next_due in words and local time).")
16754
+ .option("--view <view>", "compact (default) or full (every enrollment field) (one short row per lead with next_due in words and local time).")
16693
16755
  .option("--order <order>", "created (default) or due: soonest next_due first, then waiting leads by gives_up_at, then leads with nothing due.")
16694
16756
  .option("--limit <n>", "Maximum enrollments to return (1-500).")
16695
16757
  .option("--offset <n>", "Skip this many enrollments; pass next_offset from the previous page to continue.")
16758
+ .option("--full", "Read every enrollment field (same as --view full).")
16696
16759
  .option("--json", "Print a JSON envelope.")
16697
16760
  .action(async (sequence, options) => {
16698
16761
  await handleAsyncAction("sequences enrollments", options, () => {
@@ -16706,7 +16769,7 @@ Examples:
16706
16769
  const invite = readOption(options.invite);
16707
16770
  if (invite)
16708
16771
  params.set("invite", invite);
16709
- const view = readOption(options.view);
16772
+ const view = options.full ? "full" : readOption(options.view) ?? "compact";
16710
16773
  if (view)
16711
16774
  params.set("view", view);
16712
16775
  const order = readOption(options.order);
@@ -20456,7 +20519,7 @@ Full trigger schema: oxygen workflows schema --subject trigger --json
20456
20519
  })));
20457
20520
  program
20458
20521
  .command("skills")
20459
- .description("Agent skill discovery and installation commands.")
20522
+ .description("Find and install Oxygen guides, or create and import private workspace skills with skills workspace.")
20460
20523
  .addCommand(new Command("list")
20461
20524
  .description("List Oxygen agent skills available from the hosted skill index.")
20462
20525
  .option("--api-url <url>", "Oxygen app URL. Defaults to OXYGEN_API_URL or https://oxygen-agent.com.")
@@ -20508,13 +20571,14 @@ Full trigger schema: oxygen workflows schema --subject trigger --json
20508
20571
  registerConnectorsCommands(program, handleAsyncAction);
20509
20572
  registerSettingsCommands(program, handleAsyncAction);
20510
20573
  registerCrmSupportFlags(program);
20574
+ registerWorkspaceSkillCommands(program, handleAsyncAction);
20511
20575
  registerCustomerOperationCommands(program, handleAsyncAction);
20512
20576
  registerCrmFileReadCommands(program, handleAsyncAction);
20513
20577
  // After the register* helpers: help groups are assigned to the commands that
20514
20578
  // exist when this runs, and a family registered later fell into commander's
20515
20579
  // trailing default "Commands:" list (the 2026-09-30 blind agent read the first
20516
20580
  // 80 lines of help and missed `connectors` there).
20517
- applyOxygenHelp(program, binaryName);
20581
+ applyOxygenHelp(program, binaryName, `${defaultApiUrl().replace(/\/+$/, "")}/docs`);
20518
20582
  // Last, so every command registered above is covered.
20519
20583
  enableCommandSuggestions(program);
20520
20584
  return program;
@@ -24314,12 +24378,12 @@ function buildGetSurfaceRunWaitConfig(params) {
24314
24378
  defaultTimeoutSeconds: params.defaultTimeoutSeconds,
24315
24379
  defaultIntervalSeconds: params.defaultIntervalSeconds,
24316
24380
  retryTransientNetworkErrors: params.retryTransientNetworkErrors === true,
24317
- fetchRun: (signal) => requestOxygen(`${params.endpoint}/${encodeURIComponent(params.runId)}`, signal ? { signal } : {}),
24381
+ fetchRun: (signal) => requestOxygen(`${params.endpoint}/${encodeURIComponent(params.runId)}${params.view ? `?view=${params.view}` : ""}`, signal ? { signal } : {}),
24318
24382
  isTerminal: params.isTerminal,
24319
24383
  shapeTerminal: (run, status, polls, elapsedMs) => {
24320
24384
  const webUrl = readRecordString(run, "web_url");
24321
24385
  return {
24322
- [params.runKey]: run,
24386
+ [params.runKey]: params.view === "summary" ? tableRunSummary(run) : run,
24323
24387
  [params.runIdKey]: readRecordString(run, "id") ?? params.runId,
24324
24388
  status,
24325
24389
  terminal: true,
@@ -24372,6 +24436,7 @@ function waitForTableActionRun(runId, options) {
24372
24436
  return waitForCliRun(buildGetSurfaceRunWaitConfig({
24373
24437
  runId,
24374
24438
  endpoint: "/api/cli/table-action-runs",
24439
+ view: options.full ? "full" : "summary",
24375
24440
  requestedTimeoutSeconds: options.timeoutSeconds,
24376
24441
  requestedIntervalSeconds: options.intervalSeconds,
24377
24442
  defaultTimeoutSeconds: TABLE_ACTION_RUN_WAIT_DEFAULT_TIMEOUT_SECONDS,
@@ -30623,7 +30688,7 @@ beginCliDiagnostics();
30623
30688
  maybeScheduleBackgroundUpdate();
30624
30689
  const program = createProgram();
30625
30690
  installCommanderExitOverride(program);
30626
- const argv = withoutHelpForUnknownCommand(program, process.argv);
30691
+ const argv = withoutHelpForUnknownCommand(program, process.argv.map((arg) => arg === "--help-full" ? "--help" : arg));
30627
30692
  setCliDiagnosticOperation(commandNameForArgv(program, argv.slice(2)));
30628
30693
  try {
30629
30694
  await program.parseAsync(argv);
@@ -0,0 +1,3 @@
1
+ export declare function serializeCliJson(value: unknown, pretty?: boolean): string;
2
+ /** Own only the newly created file; preserve an existing destination on every failure. */
3
+ export declare function writeExclusiveJson(path: string, value: unknown, pretty?: boolean): Promise<string>;
@@ -0,0 +1,33 @@
1
+ import { open, unlink } from "node:fs/promises";
2
+ import { resolve } from "node:path";
3
+ import { OxygenError } from "@oxygen/shared/cli-result";
4
+ export function serializeCliJson(value, pretty = false) {
5
+ return `${JSON.stringify(value, null, pretty ? 2 : undefined)}\n`;
6
+ }
7
+ /** Own only the newly created file; preserve an existing destination on every failure. */
8
+ export async function writeExclusiveJson(path, value, pretty = false) {
9
+ const destination = resolve(path);
10
+ const serialized = serializeCliJson(value, pretty);
11
+ let handle;
12
+ try {
13
+ handle = await open(destination, "wx", 0o600);
14
+ }
15
+ catch (error) {
16
+ if (error.code === "EEXIST") {
17
+ throw new OxygenError("output_exists", "Output file already exists. Choose a new path.", { exitCode: 2 });
18
+ }
19
+ throw new OxygenError("output_write_failed", "Unable to create the output file. Check the path and permissions.", { exitCode: 2 });
20
+ }
21
+ try {
22
+ await handle.writeFile(serialized, "utf8");
23
+ await handle.close();
24
+ return destination;
25
+ }
26
+ catch {
27
+ await handle.close().catch(() => undefined);
28
+ const removed = await unlink(destination).then(() => true, () => false);
29
+ throw new OxygenError("output_write_failed", removed
30
+ ? "Unable to write the output file. The partial file was removed."
31
+ : "Unable to write or remove the partial output file. Check the destination before retrying.", { exitCode: 2 });
32
+ }
33
+ }
@@ -0,0 +1,9 @@
1
+ import { Command } from "commander";
2
+ import { type WorkspaceSkillFile } from "@oxygen/shared/workspace-skills";
3
+ /** Never follow symlinks or read binary files out of a local skill folder. */
4
+ export declare function readWorkspaceSkillDirectory(directory: string): Promise<WorkspaceSkillFile[]>;
5
+ type Handle = (command: string, options: {
6
+ json?: boolean;
7
+ }, action: () => Promise<unknown>) => Promise<void>;
8
+ export declare function registerWorkspaceSkillCommands(program: Command, handle: Handle): void;
9
+ export {};
@@ -0,0 +1,135 @@
1
+ import { lstat, readdir, readFile } from "node:fs/promises";
2
+ import { join, resolve } from "node:path";
3
+ import { OxygenError } from "@oxygen/shared/cli-result";
4
+ import { WORKSPACE_SKILL_OPERATIONS } from "@oxygen/shared/contracts/workspace-skills";
5
+ import { authorWorkspaceSkill, parseWorkspaceSkillBundle, WORKSPACE_SKILL_MAX_BYTES, WORKSPACE_SKILL_MAX_FILES, WORKSPACE_SKILL_MAX_FILE_BYTES, } from "@oxygen/shared/workspace-skills";
6
+ import { requestOxygen } from "./http-client.js";
7
+ /** Never follow symlinks or read binary files out of a local skill folder. */
8
+ export async function readWorkspaceSkillDirectory(directory) {
9
+ const root = resolve(directory);
10
+ const files = [];
11
+ let bytes = 0;
12
+ const visit = async (relative, depth) => {
13
+ if (depth > 15)
14
+ throw new OxygenError("invalid_workspace_skill", "Skill directory nesting exceeds 15 levels.", { exitCode: 2 });
15
+ const path = join(root, relative);
16
+ const stat = await lstat(path);
17
+ if (stat.isSymbolicLink())
18
+ throw new OxygenError("invalid_workspace_skill", "Skill imports do not follow symbolic links.", { exitCode: 2 });
19
+ if (stat.isDirectory()) {
20
+ for (const child of (await readdir(path)).sort()) {
21
+ if ([".git", "node_modules", ".DS_Store"].includes(child))
22
+ continue;
23
+ await visit(relative ? `${relative}/${child}` : child, depth + 1);
24
+ }
25
+ return;
26
+ }
27
+ if (!stat.isFile() ||
28
+ stat.size > WORKSPACE_SKILL_MAX_FILE_BYTES ||
29
+ files.length >= WORKSPACE_SKILL_MAX_FILES ||
30
+ bytes + stat.size > WORKSPACE_SKILL_MAX_BYTES) {
31
+ throw new OxygenError("invalid_workspace_skill", "Import supports at most 50 text files, 120 KB per file and 1 MB total.", { exitCode: 2 });
32
+ }
33
+ const buffer = await readFile(path);
34
+ bytes += buffer.byteLength;
35
+ let content;
36
+ try {
37
+ content = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(buffer);
38
+ }
39
+ catch {
40
+ throw new OxygenError("invalid_workspace_skill", `File ${relative} is not UTF-8 text.`, { exitCode: 2 });
41
+ }
42
+ files.push({ path: relative, content });
43
+ };
44
+ await visit("", 0);
45
+ return files;
46
+ }
47
+ export function registerWorkspaceSkillCommands(program, handle) {
48
+ const skills = program.commands.find((command) => command.name() === "skills");
49
+ const workspace = skills
50
+ .command("workspace")
51
+ .description("Create, upload, find and edit skills private to this workspace's members.");
52
+ workspace
53
+ .command("create")
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>.")
56
+ .requiredOption("--description <text>", "When to use this skill.")
57
+ .requiredOption("--instructions <text>", "Instructions to save.")
58
+ .option("--json", "Print a JSON envelope.")
59
+ .action((options, command) => handle("skills workspace create", { json: command.optsWithGlobals().json === true }, async () => {
60
+ authorWorkspaceSkill(options);
61
+ return requestOxygen("/api/cli/skills/workspace/create", {
62
+ method: "POST",
63
+ body: {
64
+ name: options.name,
65
+ description: options.description,
66
+ instructions: options.instructions,
67
+ },
68
+ });
69
+ }));
70
+ workspace
71
+ .command("import")
72
+ .description(WORKSPACE_SKILL_OPERATIONS.find((operation) => operation.id === "workspace_skills.import").cli.summary)
73
+ .option("--file <path>", "Local SKILL.md file.")
74
+ .option("--directory <path>", "Local skill directory including SKILL.md and supporting text files.")
75
+ .option("--url <url>", "Import a public HTTPS SKILL.md URL. Supporting files require --directory or --files-json.")
76
+ .option("--files-json <json>", "Inline array of {path, content}; alternative to --file or --directory.")
77
+ .option("--name <name>", "Destination name; otherwise use SKILL.md frontmatter name.")
78
+ .option("--source-url <url>", "HTTPS source provenance; content must already be downloaded.")
79
+ .option("--json", "Print a JSON envelope.")
80
+ .action((options, command) => handle("skills workspace import", { json: command.optsWithGlobals().json === true }, async () => {
81
+ if ([
82
+ options.file,
83
+ options.directory,
84
+ options.url,
85
+ options.filesJson,
86
+ ].filter((value) => value !== undefined).length !== 1)
87
+ throw new OxygenError("invalid_workspace_skill", "Choose exactly one of --file, --directory, --url or --files-json.", { exitCode: 2 });
88
+ if (options.url !== undefined) {
89
+ if (options.sourceUrl !== undefined)
90
+ throw new OxygenError("invalid_workspace_skill", "--source-url is for uploaded files. A URL import records its own source.", { exitCode: 2 });
91
+ return requestOxygen("/api/cli/skills/workspace/import", {
92
+ method: "POST",
93
+ body: {
94
+ url: options.url,
95
+ ...(options.name ? { name: options.name } : {}),
96
+ },
97
+ });
98
+ }
99
+ let files;
100
+ if (options.directory)
101
+ files = await readWorkspaceSkillDirectory(options.directory);
102
+ else if (options.file) {
103
+ const stat = await lstat(options.file);
104
+ if (!stat.isFile() || stat.size > WORKSPACE_SKILL_MAX_FILE_BYTES)
105
+ throw new OxygenError("invalid_workspace_skill", "Provide a regular SKILL.md text file of at most 120 KB.", { exitCode: 2 });
106
+ files = [
107
+ {
108
+ path: "SKILL.md",
109
+ content: new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(await readFile(options.file)),
110
+ },
111
+ ];
112
+ }
113
+ else {
114
+ try {
115
+ files = JSON.parse(options.filesJson);
116
+ }
117
+ catch {
118
+ throw new OxygenError("invalid_workspace_skill", "--files-json must be a JSON array of {path, content}.", { exitCode: 2 });
119
+ }
120
+ }
121
+ const bundle = parseWorkspaceSkillBundle({
122
+ files,
123
+ ...(options.name ? { name: options.name } : {}),
124
+ ...(options.sourceUrl ? { source_url: options.sourceUrl } : {}),
125
+ });
126
+ return requestOxygen("/api/cli/skills/workspace/import", {
127
+ method: "POST",
128
+ body: {
129
+ name: bundle.name,
130
+ files: bundle.files,
131
+ ...(bundle.source_url ? { source_url: bundle.source_url } : {}),
132
+ },
133
+ });
134
+ }));
135
+ }
@@ -1877,7 +1877,12 @@ function isSubscriptionRetentionIntent(query) {
1877
1877
  return /\b(retention offer|win[ -]?back discount|cancellation (?:reason|feedback)|written cancellation)\b/.test(query)
1878
1878
  || /\b(stay|cancel|cancelling)\b/.test(query) && /\b(discount|next month|subscription reason)\b/.test(query);
1879
1879
  }
1880
+ function isWorkspaceSkillIntent(query) {
1881
+ return /\bskills?\b/.test(query) && /\b(create|author|write|upload|import|edit|update|archive|private|workspace|custom|own|reusable)\b/.test(query);
1882
+ }
1880
1883
  function explicitCapabilityIntent(query) {
1884
+ if (isWorkspaceSkillIntent(query))
1885
+ return ROUTE_BY_ID.get("knowledge-graph") ?? null;
1881
1886
  // Importing an AI answer is GEO evidence, rather than a Table file import.
1882
1887
  if (/\b(?:geo|aeo|ai (?:(?:search|answer) )?visibility|consumer ai answers?|answer engine optimization|generative engine optimization)\b/.test(query))
1883
1888
  return ROUTE_BY_ID.get("geo") ?? null;
@@ -2207,6 +2212,10 @@ function isPublishingPostIntent(query) {
2207
2212
  && !(/\b(find|search|scrape|research)\b/.test(query) && /\b(about|mention|containing)\b/.test(query));
2208
2213
  }
2209
2214
  function recommendationsFor(card, query) {
2215
+ if (card.id === "knowledge-graph" && isWorkspaceSkillIntent(query)) {
2216
+ return { tools: ["oxygen_workspace_skills_list", "oxygen_workspace_skills_create", "oxygen_workspace_skills_import", "oxygen_workspace_skills_get", "oxygen_workspace_skills_update", "oxygen_workspace_skills_archive"],
2217
+ commands: ["skills workspace list", "skills workspace create", "skills workspace import", "skills workspace get", "skills workspace update", "skills workspace archive"] };
2218
+ }
2210
2219
  const contactFind = card.id === "sourcing-and-provider-tools" ? oneShotContactFindingRecommendation(query) : null;
2211
2220
  if (contactFind)
2212
2221
  return contactFind;
@@ -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 column's floor." },
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." },
@@ -13,6 +13,7 @@ import { TABLE_FEED_UPDATE_OPERATION } from "./table-feed-update.js";
13
13
  import { GEO_OPERATIONS } from "./geo.js";
14
14
  import { CUSTOMER_OPERATIONS } from "./customer-operations.js";
15
15
  import { AGENT_SESSION_OPERATIONS } from "./agent-sessions.js";
16
+ import { WORKSPACE_SKILL_OPERATIONS } from "./workspace-skills.js";
16
17
  /** The route with its `{param}` segments filled in, each URL-encoded. */
17
18
  export function operationPath(spec, params) {
18
19
  return spec.route.replace(/\{(\w+)\}/g, (_match, name) => {
@@ -82,6 +83,6 @@ export function operationFormData(spec, body) {
82
83
  }
83
84
  return form;
84
85
  }
85
- export const OPERATION_SPECS = [SENDER_LIMITS_SET_OPERATION, CONNECTOR_UPDATE_OPERATION, CONNECTOR_EVENTS_REVOKE_OPERATION, WORKSPACE_PAGES_GET_OPERATION, WORKSPACE_PAGES_UPDATE_OPERATION, TABLE_FEED_UPDATE_OPERATION, ...CUSTOMER_OPERATIONS, ...GEO_OPERATIONS, ...BROWSER_OPERATIONS, ...AGENT_SESSION_OPERATIONS];
86
- export const CLI_OPERATIONS = [...CUSTOMER_OPERATIONS, ...GEO_OPERATIONS, ...BROWSER_OPERATIONS, ...AGENT_SESSION_OPERATIONS].filter((spec) => spec.generated?.cli !== false);
87
- export const MCP_OPERATIONS = [...CUSTOMER_OPERATIONS, ...GEO_OPERATIONS, ...BROWSER_OPERATIONS, ...AGENT_SESSION_OPERATIONS].filter((spec) => spec.generated?.mcp !== false);
86
+ export const OPERATION_SPECS = [SENDER_LIMITS_SET_OPERATION, CONNECTOR_UPDATE_OPERATION, CONNECTOR_EVENTS_REVOKE_OPERATION, WORKSPACE_PAGES_GET_OPERATION, WORKSPACE_PAGES_UPDATE_OPERATION, TABLE_FEED_UPDATE_OPERATION, ...CUSTOMER_OPERATIONS, ...GEO_OPERATIONS, ...BROWSER_OPERATIONS, ...AGENT_SESSION_OPERATIONS, ...WORKSPACE_SKILL_OPERATIONS];
87
+ export const CLI_OPERATIONS = [...CUSTOMER_OPERATIONS, ...GEO_OPERATIONS, ...BROWSER_OPERATIONS, ...AGENT_SESSION_OPERATIONS, ...WORKSPACE_SKILL_OPERATIONS].filter((spec) => spec.generated?.cli !== false);
88
+ export const MCP_OPERATIONS = [...CUSTOMER_OPERATIONS, ...GEO_OPERATIONS, ...BROWSER_OPERATIONS, ...AGENT_SESSION_OPERATIONS, ...WORKSPACE_SKILL_OPERATIONS].filter((spec) => spec.generated?.mcp !== false);
@@ -17,7 +17,7 @@ export declare const TABLE_QUERY_GRID_CONTRACT: import("./schema.js").ContractOb
17
17
  }, never>;
18
18
  export declare const TABLE_QUERY_GRID_NATIVE_WINDOW = 10000;
19
19
  export declare const TABLE_QUERY_GRID_BUILTIN_WINDOW = 4000;
20
- export declare const TABLE_QUERY_GRID_COPILOT_WINDOW = 24000;
20
+ export declare const TABLE_QUERY_GRID_COPILOT_WINDOW = 50000;
21
21
  /** The window a built-in host reads tables in; other clients have none. */
22
22
  export declare function tableQueryBuiltinWindow(surface: string | null | undefined): number | undefined;
23
23
  /** Measure the complete native receipt and the escaped built-in host receipt. */