@oxygen-agent/cli 1.1011.767 → 1.1011.803

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 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.1011.767
37
+ Version: 1.1011.803
package/dist/index.js CHANGED
@@ -1,85 +1,86 @@
1
- import { knowledgeIndexReadContract, knowledgePageReadContract } from "@oxygen/shared/contracts/knowledge-content-reads";
2
- import { DATABASE_ATTACH_CONTRACT, DATABASE_MIGRATE_CONTRACT, DATABASE_QUERY_CONTRACT } from "@oxygen/shared/contracts/database";
3
- import { DATABASE_QUERY_FLAG_OVERLAY } from "./database-query-flags.js";
4
- import { LINKEDIN_SENT_INVITES_QUERY_CONTRACT } from "@oxygen/shared/contracts/linkedin-invites-list";
5
- import { PIPEDRIVE_CATALOG_QUERY_CONTRACT, pipedriveCatalogQueryParams } from "@oxygen/shared/contracts/pipedrive-catalog";
1
+ import { renderPrimaryProviderBoard } from "./admin-primary-providers-render.js";
2
+ import { markStdinConsumed, maybeScheduleBackgroundUpdate, readAutoUpdateStatus, runBackgroundUpdate, } from "./auto-update.js";
3
+ import { createBrowserLoginSession, createRelayLoginSession, openBrowser } from "./browser-login.js";
4
+ import { assertModeFlagsExclusive, parseKeyValuePairs, parseJsonObject, readJsonObjectOption, readNonNegativeInt, readPositiveInt, readRecordString, resolveLiveDryRunMode, } from "./cli-values.js";
5
+ import { readColumnDecisionFlags } from "./column-decision-options.js";
6
+ import { formatAiPromptPreviewNotice, formatColumnReferenceNotices, formatEnrichmentInputMappingNotice, formatProviderLaneNotices, } from "./column-run-notices.js";
7
+ import { buildCommandManifest, getCommandManifestEntry, searchCommandManifest, suggestCommandNames, } from "./command-manifest.js";
8
+ import { registerConnectorsCommands } from "./connectors-commands.js";
9
+ import { addContractFlags, readContractFlags } from "./contract-flags.js";
10
+ import { clearCredentials, defaultApiUrl, listCredentialProfiles, loadCredentials, normalizeApiUrl, pickProfileNameForIdentity, pickProfileNameForUserSession, resolveActiveProfile, saveCredentials, switchCredentialProfile, updateActiveOrganizationForProfile, } from "./credentials.js";
6
11
  import { registerCrmFileReadCommands } from "./crm-file-read-commands.js";
7
- import { WHATSAPP_ACCOUNTS_READ_CONTRACT } from "@oxygen/shared/contracts/whatsapp-reads";
8
- import { WHATSAPP_ACCOUNT_FLAGS, whatsappAccountQuery } from "./whatsapp-account-flags.js";
9
- import { BILLING_OWNER_READ_CONTRACT } from "@oxygen/shared/contracts/billing-owner-read";
10
- import { publishingAmplificationListQueryContract, publishingAmplificationActionsQueryContract, publishingNotesQueryContract, publishingRevisionsQueryContract, publishingAnalyticsQueryContract, publishingReadQueryParams, } from "@oxygen/shared/contracts/publishing-reads";
11
- import { COPILOT_SESSIONS_LIST_CONTRACT } from "@oxygen/shared/contracts/copilot-sessions";
12
- import { SEQUENCE_ANALYTICS_READ_CONTRACT } from "@oxygen/shared/contracts/sequence-analytics-read";
13
- import { WORKFLOW_RUN_LIST_CONTRACT, workflowRunListQueryParams } from "@oxygen/shared/contracts/workflow-run-list";
14
- import { WORKFLOW_RUN_LIST_FLAG_OVERLAY, readWorkflowRunListFlags } from "./workflow-run-list-flags.js";
15
12
  import { registerCrmSupportFlags, readCrmNoteEditFields, readCrmPhotoFields, readCrmFileLabel, buildCrmObjectsPath, buildCrmConnectionsPath } from "./crm-support-flags.js";
16
- import { addToolCatalogSearchWindowFlag, readToolCatalogSearchWindow } from "./tool-catalog-search-window.js";
17
- import { createToolCatalogDetailCommand } from "./tool-catalog-detail-command.js";
18
- import { LIMITS_READ_QUERY_CONTRACT, limitsReadQueryIssue } from "@oxygen/shared/contracts/limits-read";
19
- import { execFileSync } from "node:child_process";
20
- import { createHash, randomUUID } from "node:crypto";
21
- import { closeSync, createReadStream, createWriteStream, existsSync, mkdirSync, mkdtempSync, openSync, readFileSync, readSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, } from "node:fs";
22
- import { tmpdir } from "node:os";
23
- import { basename, dirname, extname, join, resolve } from "node:path";
24
- import { createInterface } from "node:readline/promises";
25
- import { stdin as input, stdout as output } from "node:process";
26
- import { fileURLToPath, pathToFileURL } from "node:url";
27
- import { Command, CommanderError, Option } from "commander";
28
- import { registerUgcCommands } from "./ugc-commands.js";
29
- import { registerConnectorsCommands } from "./connectors-commands.js";
30
- import { registerSettingsCommands } from "./settings-commands.js";
31
13
  import { registerCustomerOperationCommands } from "./customer-operation-commands.js";
32
- import { registerKnowledgeRepositoryCommands } from "./knowledge-repository-commands.js";
33
- import { registerVisualCommands } from "./visual-commands.js";
34
- import { renderPrimaryProviderBoard } from "./admin-primary-providers-render.js";
14
+ import { DATABASE_QUERY_FLAG_OVERLAY } from "./database-query-flags.js";
15
+ import { addFeedReadFlags, feedReadWindowParams } from "./feed-read-flags.js";
35
16
  import { registerFunctionsCommands } from "./functions-commands.js";
36
- import { STREAMED_FILE_IMPORT_MIN_BYTES, putImportFileStream, rowsForStreamedImportTarget, scanStreamedImportFile, shouldStreamFileImport, } from "./streamed-file-import.js";
37
17
  import { applyOxygenHelp, argvRequestsJson, commanderUsageFailure, commandNameForArgv, enableCommandSuggestions, unknownCommandHint, unknownOptionHint, withoutHelpForUnknownCommand, validateRequiredOptionValues, } from "./help.js";
38
- import { buildCommandManifest, getCommandManifestEntry, searchCommandManifest, suggestCommandNames, } from "./command-manifest.js";
18
+ import { ensureFreshCliForApiUrl, requestOxygen } from "./http-client.js";
19
+ import { formatInboxNeedsReplyNotice } from "./inbox-needs-reply-notice.js";
20
+ 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";
21
+ import { registerKnowledgeRepositoryCommands } from "./knowledge-repository-commands.js";
22
+ import { runLocalCustomHttpColumn } from "./local-custom-http-column.js";
23
+ import { formatMailboxRampNotice } from "./mailbox-ramp-notice.js";
24
+ import { waitForCliRun } from "./run-wait.js";
25
+ import { resolveCliBinaryName } from "./runtime.js";
26
+ import { formatSearchAiFilterTotalsNotice } from "./search-ai-filter-notice.js";
27
+ import { buildSenderLimitsBody, parseWorkingDaysOption, SENDER_LIMITS_FLAG_OVERLAY } from "./sender-limits-flags.js";
28
+ import { addSessionOutput, addSessionStatus, getSessionUsage, startSession, updateSessionStep, } from "./session.js";
29
+ import { registerSettingsCommands } from "./settings-commands.js";
30
+ import { doctorAgentSkills, getAgentSkill, installAgentSkills, listAgentSkills, runAutomaticSkillsInstall, searchAgentSkills, } from "./skills.js";
31
+ import { STREAMED_FILE_IMPORT_MIN_BYTES, putImportFileStream, rowsForStreamedImportTarget, scanStreamedImportFile, shouldStreamFileImport, } from "./streamed-file-import.js";
32
+ import { createToolCatalogDetailCommand } from "./tool-catalog-detail-command.js";
33
+ import { addToolCatalogSearchWindowFlag, readToolCatalogSearchWindow } from "./tool-catalog-search-window.js";
34
+ import { captureCurrentTranscript, collectFeedbackEnvironment, redactTranscriptSecrets, TranscriptCaptureError, } from "./transcript.js";
35
+ import { registerUgcCommands } from "./ugc-commands.js";
36
+ import { updateCli } from "./update.js";
37
+ import { isRecord, readClearableOption, readErrorMessage, readOption } from "./util.js";
38
+ import { registerVisualCommands } from "./visual-commands.js";
39
+ import { WHATSAPP_ACCOUNT_FLAGS, whatsappAccountQuery } from "./whatsapp-account-flags.js";
40
+ import { formatWorkflowPlanLimitNotices } from "./workflow-plan-limit-notices.js";
41
+ import { WORKFLOW_RUN_LIST_FLAG_OVERLAY, readWorkflowRunListFlags } from "./workflow-run-list-flags.js";
42
+ import { isRecipeDefinition } from "@oxygen/recipe-sdk";
39
43
  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";
40
44
  import { PURCHASABLE_PLAN_KEYS, planVolumeBonusPercent, resolveBasePricingPlan } from "@oxygen/shared/billing";
41
- import { TAG_COLORS } from "@oxygen/shared/select-options";
42
- import { PUBLIC_WEBHOOK_INGRESS_PER_TARGET_PER_MINUTE } from "@oxygen/shared/plan-band";
43
- import { AI_COLUMN_CREDITS, AI_COLUMN_WEB_SEARCH_TYPICAL_CREDITS } from "@oxygen/shared/pricing-sheet";
44
- import { LINKEDIN_SENDER_LIMIT_DEFAULTS, LINKEDIN_SENDER_LIMIT_MAXIMUMS, } from "@oxygen/shared/linkedin-sequences";
45
- import { SEQUENCE_LIFECYCLES, sequenceDisplayStatus } from "@oxygen/shared/sequence-lifecycle";
46
- import { operationPath } from "@oxygen/shared/contracts/operations";
47
- import { SENDER_LIMITS_SET_OPERATION } from "@oxygen/shared/contracts/sender-limits";
48
- import { addContractFlags, readContractFlags } from "./contract-flags.js";
49
- import { addFeedReadFlags, feedReadWindowParams } from "./feed-read-flags.js";
50
- import { TABLE_QUERY_GRID_CONTRACT } from "@oxygen/shared/contracts/table-query-grid";
51
- import { INTEGRATION_CONNECT_ACCOUNT_CONTRACT } from "@oxygen/shared/contracts/integration-connect";
45
+ import { COMPANY_REPLY_PAUSE_DEFAULT_STATUSES, COMPANY_REPLY_PAUSE_LEGACY_STATUSES, COMPANY_REPLY_PAUSE_STATUS_KEY_PATTERN, } from "@oxygen/shared/company-reply-pause";
46
+ import { BILLING_OWNER_READ_CONTRACT } from "@oxygen/shared/contracts/billing-owner-read";
47
+ import { COPILOT_SESSIONS_LIST_CONTRACT } from "@oxygen/shared/contracts/copilot-sessions";
52
48
  import { CRM_ENRICHMENT_READ_CONTRACT } from "@oxygen/shared/contracts/crm-enrichment-read";
49
+ import { DATABASE_ATTACH_CONTRACT, DATABASE_MIGRATE_CONTRACT, DATABASE_QUERY_CONTRACT } from "@oxygen/shared/contracts/database";
53
50
  import { INBOX_DRAFTS_READ_CONTRACT } from "@oxygen/shared/contracts/inbox-drafts-read";
51
+ import { INTEGRATION_CONNECT_ACCOUNT_CONTRACT } from "@oxygen/shared/contracts/integration-connect";
52
+ import { knowledgeIndexReadContract, knowledgePageReadContract } from "@oxygen/shared/contracts/knowledge-content-reads";
53
+ import { LIMITS_READ_QUERY_CONTRACT, limitsReadQueryIssue } from "@oxygen/shared/contracts/limits-read";
54
+ import { LINKEDIN_SENT_INVITES_QUERY_CONTRACT } from "@oxygen/shared/contracts/linkedin-invites-list";
55
+ import { operationPath } from "@oxygen/shared/contracts/operations";
56
+ import { PIPEDRIVE_CATALOG_QUERY_CONTRACT, pipedriveCatalogQueryParams } from "@oxygen/shared/contracts/pipedrive-catalog";
57
+ import { publishingAmplificationListQueryContract, publishingAmplificationActionsQueryContract, publishingNotesQueryContract, publishingRevisionsQueryContract, publishingAnalyticsQueryContract, publishingReadQueryParams, } from "@oxygen/shared/contracts/publishing-reads";
58
+ import { SENDER_LIMITS_SET_OPERATION } from "@oxygen/shared/contracts/sender-limits";
59
+ import { SEQUENCE_ANALYTICS_READ_CONTRACT } from "@oxygen/shared/contracts/sequence-analytics-read";
54
60
  import { SEQUENCE_LIST_PROJECTION_CONTRACT } from "@oxygen/shared/contracts/sequence-list";
61
+ import { TABLE_FEED_UPDATE_CONTRACT, tableFeedUpdateIssues } from "@oxygen/shared/contracts/table-feed-update";
55
62
  import { TABLE_LIST_QUERY_CONTRACT, tableListQueryParams } from "@oxygen/shared/contracts/table-list";
56
- import { buildSenderLimitsBody, parseWorkingDaysOption, SENDER_LIMITS_FLAG_OVERLAY } from "./sender-limits-flags.js";
57
- import { readColumnDecisionFlags } from "./column-decision-options.js";
63
+ import { TABLE_QUERY_GRID_CONTRACT } from "@oxygen/shared/contracts/table-query-grid";
64
+ import { WHATSAPP_ACCOUNTS_READ_CONTRACT } from "@oxygen/shared/contracts/whatsapp-reads";
65
+ import { WORKFLOW_RUN_LIST_CONTRACT, workflowRunListQueryParams } from "@oxygen/shared/contracts/workflow-run-list";
58
66
  import { MANAGED_DATA_SUPPLIERS } from "@oxygen/shared/data-suppliers";
59
- import { COMPANY_REPLY_PAUSE_DEFAULT_STATUSES, COMPANY_REPLY_PAUSE_LEGACY_STATUSES, COMPANY_REPLY_PAUSE_STATUS_KEY_PATTERN, } from "@oxygen/shared/company-reply-pause";
60
67
  import { MAX_BUFFERED_IMPORT_PARSE_BYTES, assertImportFormatWithinBufferedLimit, inferImportColumnLabels, inferRowsFileFormat, normalizeImportColumnKey, normalizeRowsForNewTable, normalizeRowsFormat, parseRowsFileBuffer, parseXlsxWorkbookBuffer, } from "@oxygen/shared/file-import";
68
+ import { LINKEDIN_SENDER_LIMIT_DEFAULTS, LINKEDIN_SENDER_LIMIT_MAXIMUMS, } from "@oxygen/shared/linkedin-sequences";
61
69
  import { MAILBOX_IMPORT_FILE_MAX_BYTES as SHARED_MAILBOX_IMPORT_FILE_MAX_BYTES, MAILBOX_IMPORT_ROW_LIMIT as SHARED_MAILBOX_IMPORT_ROW_LIMIT, normalizeMailboxImportFile as normalizeSharedMailboxImportFile, normalizeMailboxImportVendor as normalizeSharedMailboxImportVendor, normalizeMailboxWorkbookRows, parseMailboxImportText, summarizeMailboxImportValidation as summarizeSharedMailboxImportValidation, } from "@oxygen/shared/mailbox-import";
70
+ import { PUBLIC_WEBHOOK_INGRESS_PER_TARGET_PER_MINUTE } from "@oxygen/shared/plan-band";
71
+ import { AI_COLUMN_CREDITS, AI_COLUMN_WEB_SEARCH_TYPICAL_CREDITS } from "@oxygen/shared/pricing-sheet";
72
+ import { TAG_COLORS } from "@oxygen/shared/select-options";
73
+ import { SEQUENCE_LIFECYCLES, sequenceDisplayStatus } from "@oxygen/shared/sequence-lifecycle";
62
74
  import { assertRecipeBundleSafe, assertPortableWorkflowDefinition, assertWorkflowGraphManifest, assertWorkflowManifest, buildRecipeManifest, compileWorkflowDefinition, isAnyWorkflowManifest, isRecipeManifest, isWorkflowDefinition, isWorkflowGraphManifest, isWorkflowManifest, hashPortableWorkflowGraphManifest, WORKFLOW_GRAPH_COMPILER_VERSION, WORKFLOW_GRAPH_MANIFEST_VERSION, } from "@oxygen/workflows";
63
- import { isRecipeDefinition } from "@oxygen/recipe-sdk";
64
- import { createBrowserLoginSession, createRelayLoginSession, openBrowser } from "./browser-login.js";
65
- import { clearCredentials, defaultApiUrl, listCredentialProfiles, loadCredentials, normalizeApiUrl, pickProfileNameForIdentity, pickProfileNameForUserSession, resolveActiveProfile, saveCredentials, switchCredentialProfile, updateActiveOrganizationForProfile, } from "./credentials.js";
66
- import { ensureFreshCliForApiUrl, requestOxygen } from "./http-client.js";
67
- 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";
68
- import { waitForCliRun } from "./run-wait.js";
69
- import { assertModeFlagsExclusive, parseKeyValuePairs, parseJsonObject, readJsonObjectOption, readNonNegativeInt, readPositiveInt, readRecordString, resolveLiveDryRunMode, } from "./cli-values.js";
70
- import { formatAiPromptPreviewNotice, formatColumnReferenceNotices, formatEnrichmentInputMappingNotice, formatProviderLaneNotices, } from "./column-run-notices.js";
71
- import { runLocalCustomHttpColumn } from "./local-custom-http-column.js";
72
- import { formatSearchAiFilterTotalsNotice } from "./search-ai-filter-notice.js";
73
- import { formatInboxNeedsReplyNotice } from "./inbox-needs-reply-notice.js";
74
- import { formatMailboxRampNotice } from "./mailbox-ramp-notice.js";
75
- import { formatWorkflowPlanLimitNotices } from "./workflow-plan-limit-notices.js";
76
- import { captureCurrentTranscript, collectFeedbackEnvironment, redactTranscriptSecrets, TranscriptCaptureError, } from "./transcript.js";
77
- import { addSessionOutput, addSessionStatus, getSessionUsage, startSession, updateSessionStep, } from "./session.js";
78
- import { doctorAgentSkills, getAgentSkill, installAgentSkills, listAgentSkills, runAutomaticSkillsInstall, searchAgentSkills, } from "./skills.js";
79
- import { resolveCliBinaryName } from "./runtime.js";
80
- import { updateCli } from "./update.js";
81
- import { markStdinConsumed, maybeScheduleBackgroundUpdate, readAutoUpdateStatus, runBackgroundUpdate, } from "./auto-update.js";
82
- import { isRecord, readClearableOption, readErrorMessage, readOption } from "./util.js";
75
+ import { Command, CommanderError, Option } from "commander";
76
+ import { execFileSync } from "node:child_process";
77
+ import { createHash, randomUUID } from "node:crypto";
78
+ import { closeSync, createReadStream, createWriteStream, existsSync, mkdirSync, mkdtempSync, openSync, readFileSync, readSync, renameSync, rmSync, statSync, unlinkSync, writeFileSync, } from "node:fs";
79
+ import { tmpdir } from "node:os";
80
+ import { basename, dirname, extname, join, resolve } from "node:path";
81
+ import { stdin as input, stdout as output } from "node:process";
82
+ import { createInterface } from "node:readline/promises";
83
+ import { fileURLToPath, pathToFileURL } from "node:url";
83
84
  const AGENT_MODEL_POLICY_HELP = "Model policy JSON: level low (Fast), medium (Balanced, default), or high (Max); credential_mode managed or organization_byok.";
84
85
  const AGENT_TOOL_POLICY_HELP = "Tool policy JSON. Effects: read, internal_write, paid, external_write. Ask-before-changes preset: {\"mode\":\"scoped\",\"rules\":[{\"decision\":\"allow\",\"effect\":\"read\"},{\"decision\":\"ask\",\"effect\":\"internal_write\"},{\"decision\":\"ask\",\"effect\":\"paid\"},{\"decision\":\"ask\",\"effect\":\"external_write\"}]}. Full mode requires --confirm-full-access.";
85
86
  /**
@@ -5809,7 +5810,7 @@ fixed scan; watermark_cursor starts a later bounded replay. Consumers must retai
5809
5810
  }));
5810
5811
  }))
5811
5812
  .addCommand(new Command("delete")
5812
- .description("Delete a CUSTOM CRM object: removes the object and schedules its backing table for deletion (restorable for 14 days). Standard objects (companies, people, deals) are permanent and refused. Defaults to dry-run; --live requires --confirm.")
5813
+ .description("Delete a CUSTOM CRM object: removes the object and schedules its backing table for deletion (restorable for 14 days). Standard objects (companies, people, deals) are permanent and refused. Defaults to dry-run; --live requires --confirm. Re-run on an object a teammate already deleted, it reports alreadyArchived with the table's deletion state and purge date.")
5813
5814
  .argument("<object>", "Custom CRM object slug, such as projects or tasks.")
5814
5815
  .option("--keep-table", "Deregister the object but keep its table as an ordinary workspace table (no delete timer).")
5815
5816
  .option("--purge-after <days>", "Days until the backing table's physical purge. Defaults to 14; restorable via `tables restore` until then.")
@@ -6257,7 +6258,7 @@ fixed scan; watermark_cursor starts a later bounded replay. Consumers must retai
6257
6258
  await handleAsyncAction("crm activity timeline", options, () => requestOxygen(buildCrmTimelinePath(object, rowId, options)));
6258
6259
  })))
6259
6260
  .addCommand(new Command("describe")
6260
- .description("Describe one configured CRM object: its fields, identities and relationships. Pass --field <key> to read just one field (its name, type, choices, flags) instead of the whole object.")
6261
+ .description("Describe one configured CRM object: its fields, identities and relationships. Pass --field <key> to read just one field (its name, type, choices, flags) instead of the whole object. A deleted custom object answers not found; `crm objects delete <slug> --dry-run` shows its archived state.")
6261
6262
  .argument("<object>", "CRM object slug, such as companies or people.")
6262
6263
  .option("--field <key>", "Narrow the answer to one field by its key, e.g. --field pipeline_stage. Also accepted as --attribute.")
6263
6264
  .option("--attribute <key>", "Alias for --field.")
@@ -8076,6 +8077,7 @@ fixed scan; watermark_cursor starts a later bounded replay. Consumers must retai
8076
8077
  .addCommand(addFeedReadFlags(new Command("get")
8077
8078
  .description("Get one table feed. Optional summary or lossless value JSON windows recover every public setting; resume value-cursor with the same feed/path/include-cursor. Read-only.")
8078
8079
  .argument("<feed>", "Feed id or endpoint id.")
8080
+ .option("--include-route", "Include the complete frozen request and fallback lanes for an in-place update.")
8079
8081
  .option("--include-cursor", "Include the opaque provider page token in the cursor block.")
8080
8082
  .option("--json", "Print a JSON envelope.")
8081
8083
  .action((feed, options) => handleAsyncAction("feeds get", options, () => requestOxygen(feedsGetPath(feed, options)))), true))
@@ -8157,6 +8159,26 @@ Examples:
8157
8159
  return data;
8158
8160
  });
8159
8161
  }))
8162
+ .addCommand(addContractFlags(new Command("update")
8163
+ .description("Update an existing feed in place. Inspect feeds get --include-route first. Source replacement resets its cursor; cadence, cap and source changes keep native standing authorization and budget checks. Configuration spends nothing.")
8164
+ .argument("<feed>", "Feed id or endpoint id.")
8165
+ .option("--json", "Print a JSON envelope."), TABLE_FEED_UPDATE_CONTRACT, {
8166
+ feed: { omit: true }, sync: { flatten: true },
8167
+ "sync.max_credits_per_cycle": { flag: "max-credits" },
8168
+ "sync.max_rows_per_cycle": { flag: "max-rows" },
8169
+ approved: { noNegate: true },
8170
+ })
8171
+ .action((feed, options) => handleAsyncAction("feeds update", options, () => {
8172
+ const body = { ...readContractFlags(options, TABLE_FEED_UPDATE_CONTRACT, {
8173
+ feed: { omit: true }, sync: { flatten: true },
8174
+ "sync.max_credits_per_cycle": { flag: "max-credits" },
8175
+ "sync.max_rows_per_cycle": { flag: "max-rows" }, approved: { noNegate: true },
8176
+ }), feed };
8177
+ const errors = tableFeedUpdateIssues(body);
8178
+ if (errors.length)
8179
+ throw new OxygenError("invalid_request", errors.join(" "), { exitCode: 1 });
8180
+ return requestOxygen("/api/cli/tables/feeds", { method: "PATCH", body });
8181
+ })))
8160
8182
  .addCommand(new Command("pause")
8161
8183
  .description("Pause a feed: the cron stays armed but every cycle it fires is refused, so nothing is fetched and nothing is billed until you resume. Free.")
8162
8184
  .argument("<feed>", "Feed id or endpoint id.")
@@ -22215,8 +22237,9 @@ function feedsListPath(options, tableArgument) {
22215
22237
  function feedsGetPath(feed, options) {
22216
22238
  const params = feedReadWindowParams(options, true);
22217
22239
  params.set("feed", feed);
22218
- if (options.includeCursor)
22219
- params.set("include", "cursor");
22240
+ const include = [options.includeCursor ? "cursor" : null, options.includeRoute ? "route" : null].filter(Boolean);
22241
+ if (include.length)
22242
+ params.set("include", include.join(","));
22220
22243
  return `/api/cli/tables/feeds?${params.toString()}`;
22221
22244
  }
22222
22245
  // The bind body mirrors the route's reader: everything the provider is asked for
@@ -25329,10 +25352,24 @@ async function handleOrgUseAction(organization, options, command) {
25329
25352
  credentials: context.resolution.credentials,
25330
25353
  organization: data.currentOrganization,
25331
25354
  });
25355
+ // OXYGEN_ORG outranks the stored selection on every later command (the
25356
+ // oxygen-dev wrapper exports one), so a selection it contradicts is saved
25357
+ // but never used. Reported 2026-09-22: three "successful" selects in a row.
25358
+ const envOrganization = process.env.OXYGEN_ORG?.trim();
25359
+ const selected = data.currentOrganization;
25360
+ const environmentOverride = envOrganization && selected
25361
+ && envOrganization !== selected.id && envOrganization !== selected.slug
25362
+ ? {
25363
+ variable: "OXYGEN_ORG",
25364
+ organization: envOrganization,
25365
+ message: `OXYGEN_ORG=${envOrganization} is set, so later commands still use that workspace. Unset it, set it to ${selected.slug ?? selected.id}, or pass --org.`,
25366
+ }
25367
+ : null;
25332
25368
  const result = {
25333
25369
  ...data,
25334
25370
  profile,
25335
25371
  selection_persisted: selectionPersisted,
25372
+ ...(environmentOverride ? { environment_override: environmentOverride } : {}),
25336
25373
  };
25337
25374
  if (options.json) {
25338
25375
  writeJson(success(command, result));
@@ -25341,6 +25378,8 @@ async function handleOrgUseAction(organization, options, command) {
25341
25378
  writeJson(result);
25342
25379
  }
25343
25380
  writeCredentialNotice(data.credential);
25381
+ if (environmentOverride)
25382
+ process.stderr.write(`${environmentOverride.message}\n`);
25344
25383
  }
25345
25384
  catch (error) {
25346
25385
  emitCliFailure(command, error);
@@ -979,6 +979,9 @@ const CRM_ENRICHMENT_READ_VIEW = {
979
979
  function routeCardFor(card, query) {
980
980
  if (card.id === "records" && isCrmEnrichmentConfigurationRead(query))
981
981
  return { ...card, ...CRM_ENRICHMENT_READ_VIEW };
982
+ const feed = card.primitive === "tables" ? tableFeedRecommendation(query) : null;
983
+ if (feed)
984
+ return { ...card, execution: feed.execution };
982
985
  if (card.primitive === "publishing" && isUgcIntent(query))
983
986
  return { ...card, ...UGC_ROUTE_VIEW };
984
987
  const contactFind = card.id === "sourcing-and-provider-tools" ? oneShotContactFindingRecommendation(query) : null;
@@ -1488,7 +1491,7 @@ function tableMaintenanceRecommendation(query) {
1488
1491
  if (table && /\bfeeds?\b/.test(query)) {
1489
1492
  return /\b(bind|attach|create|new)\b/.test(query)
1490
1493
  ? result(["oxygen_feeds_bind", "oxygen_feeds_list"], ["feeds bind", "feeds list"], "Bind the native Table feed: a declared-schema push source or scheduled provider pull. Inspect source, cadence and standing credit scope first; a pull feed is not an inbound webhook endpoint.")
1491
- : result(["oxygen_feeds_list", "oxygen_feeds_get"], ["feeds list", "feeds get"], "Inspect the native Table feed's source, cadence, caps and state. Pull feeds refill Tables on their own schedule. The current MCP catalog has no general cadence-update tool; do not substitute a Workflow or generic HTTP call.");
1494
+ : result(["oxygen_feeds_list", "oxygen_feeds_get", "oxygen_feeds_update"], ["feeds list", "feeds get", "feeds update"], "Inspect the Table feed with feeds_get(include_route=true), then update it in place via oxygen_feeds_update (Signals pack/core write gateway) or feeds update. Preserve the full frozen request; source replacement resets its cursor. Scheduled replacements require one executable lane; fallbacks require no cadence. Native changed cadence or expanded paid source/cap authority can require renewed standing approval; configuration is free.");
1492
1495
  }
1493
1496
  const file = /\b(csv|jsonl?|xlsx|excel|spreadsheet|staged|uploaded|file)\b/.test(query)
1494
1497
  || /\b(?:pending|stuck|abandoned) imports?\b|\bimports?\b.{0,30}\b(pending|stuck|recover\w*)\b/.test(query);
@@ -1562,6 +1565,20 @@ function oneShotContactFindingRecommendation(query) {
1562
1565
  execution: "Hydrate the selected native one-shot lookup schema. mode=dry_run previews its waterfall; live requires the user's approved exact scope and positive max_credits. readOnlyHint=false and openWorldHint=true still apply to previews. External MCP uses oxygen_capabilities_call for an unlisted lookup; built-in agents call the native capability under their existing policy. Free catalog metadata uses the read gateway. Sending and bulk Table enrichment have separate owners.",
1563
1566
  };
1564
1567
  }
1568
+ /** Native row-supply feeds belong to Tables; Signals is their registered MCP pack. */
1569
+ function tableFeedRecommendation(rawQuery) {
1570
+ // A pasted URL (e.g. linkedin.com/feed/update/...) names a resource, not a Table feed.
1571
+ const query = rawQuery.replace(/\bhttps?:\/\/\S+/g, " ");
1572
+ if (/\b(workflows?|agents?|rss|knowledge|mailbox\w*|crm|attachments?|webhooks?|inbound endpoints?|sequences?|publishing)\b/.test(query))
1573
+ return null;
1574
+ const explicit = /\bfeeds?\b/.test(query) && /\b(tables?|pull|cadence|refresh|saved search|source|filters?|credit|credits|caps?|update|bind)\b/.test(query);
1575
+ const saved = /\btables?\b/.test(query) && /\bsaved search\b/.test(query) && /\b(refill\w*|refresh\w*|scheduled|cadence)\b/.test(query);
1576
+ if (!explicit && !saved)
1577
+ return null;
1578
+ if (/\b(bind|attach|create|new)\b/.test(query))
1579
+ return { tools: ["oxygen_feeds_bind", "oxygen_feeds_list"], commands: ["feeds bind", "feeds list"], execution: "Bind the native Table row-supply feed. Inspect source, cadence and standing credit scope first; pull feeds are distinct from inbound webhook endpoints. Feed tools are executable through the core gateways or Signals pack." };
1580
+ return { tools: ["oxygen_feeds_list", "oxygen_feeds_get", "oxygen_feeds_update"], commands: ["feeds list", "feeds get", "feeds update"], execution: "Inspect the existing Table feed with feeds_get(include_route=true), then update it in place with oxygen_feeds_update (Signals pack or core write gateway). Preserve the complete frozen request; source replacement resets the cursor. Scheduled replacements require one executable lane; fallbacks require no cadence. Changed cadence, increased paid cap or replaced paid source can require renewed standing authorization. Configuration is free; future refreshes retain their approved cycle ceiling." };
1581
+ }
1565
1582
  function explicitCapabilityIntent(query) {
1566
1583
  if (sentLinkedInInvitationReadRecommendation(query))
1567
1584
  return ROUTE_BY_ID.get("connected-linkedin") ?? null;
@@ -1575,6 +1592,8 @@ function explicitCapabilityIntent(query) {
1575
1592
  return ROUTE_BY_ID.get("records") ?? null;
1576
1593
  if (storedReplyDraftReadRecommendation(query))
1577
1594
  return ROUTE_BY_PRIMITIVE.get("messages") ?? null;
1595
+ if (tableFeedRecommendation(query))
1596
+ return ROUTE_BY_PRIMITIVE.get("tables") ?? null;
1578
1597
  if (isConnectedAppsIntent(query) || isConnectedAppEventsIntent(query) || isConnectedAppSpendIntent(query)) {
1579
1598
  return ROUTE_BY_ID.get("workspace-access") ?? null;
1580
1599
  }
@@ -1882,6 +1901,9 @@ function recommendationsFor(card, query) {
1882
1901
  const database = card.id === "platform-operations" ? databaseRecommendation(query) : null;
1883
1902
  if (database)
1884
1903
  return database;
1904
+ const feed = card.primitive === "tables" ? tableFeedRecommendation(query) : null;
1905
+ if (feed)
1906
+ return { tools: feed.tools, commands: feed.commands };
1885
1907
  if (card.id === "billing-and-budgets" && /\b(credit prices|credit price catalog|customer credit)\b/.test(query)) {
1886
1908
  return { tools: ["oxygen_customer_credit_prices"], commands: ["pricing customer-credit-prices"] };
1887
1909
  }
@@ -9,6 +9,7 @@ import { str } from "./schema.js";
9
9
  import { SENDER_LIMITS_SET_OPERATION } from "./sender-limits.js";
10
10
  import { WORKSPACE_PAGES_GET_OPERATION, WORKSPACE_PAGES_UPDATE_OPERATION } from "./workspace-pages.js";
11
11
  import { BROWSER_OPERATIONS } from "./browser-operations.js";
12
+ import { TABLE_FEED_UPDATE_OPERATION } from "./table-feed-update.js";
12
13
  import { CUSTOMER_OPERATIONS } from "./customer-operations.js";
13
14
  /** The route with its `{param}` segments filled in, each URL-encoded. */
14
15
  export function operationPath(spec, params) {
@@ -79,6 +80,6 @@ export function operationFormData(spec, body) {
79
80
  }
80
81
  return form;
81
82
  }
82
- export const OPERATION_SPECS = [SENDER_LIMITS_SET_OPERATION, CONNECTOR_UPDATE_OPERATION, CONNECTOR_EVENTS_REVOKE_OPERATION, WORKSPACE_PAGES_GET_OPERATION, WORKSPACE_PAGES_UPDATE_OPERATION, ...CUSTOMER_OPERATIONS, ...BROWSER_OPERATIONS];
83
+ 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, ...BROWSER_OPERATIONS];
83
84
  export const CLI_OPERATIONS = [...CUSTOMER_OPERATIONS, ...BROWSER_OPERATIONS].filter((spec) => spec.generated?.cli !== false);
84
85
  export const MCP_OPERATIONS = [...CUSTOMER_OPERATIONS, ...BROWSER_OPERATIONS].filter((spec) => spec.generated?.mcp !== false);
@@ -0,0 +1,222 @@
1
+ /** Native Table feed PATCH grammar. Scheduling and credit authority remain server-owned. */
2
+ import { type ContractObject } from "./schema.js";
3
+ import type { OperationSpec } from "./operations.js";
4
+ export declare const TABLE_FEED_LANE_CONTRACT: ContractObject<{
5
+ readonly tool_id: import("./schema.js").StringProperty;
6
+ readonly request: {
7
+ type: "object";
8
+ additionalProperties: boolean;
9
+ };
10
+ readonly rows_path: {
11
+ oneOf: [import("./schema.js").StringProperty, import("./schema.js").NullProperty];
12
+ description?: string;
13
+ };
14
+ readonly row_mapping: {
15
+ oneOf: [{
16
+ type: "object";
17
+ additionalProperties: boolean;
18
+ }, import("./schema.js").NullProperty];
19
+ description?: string;
20
+ };
21
+ readonly cursor_path: {
22
+ oneOf: [import("./schema.js").StringProperty, import("./schema.js").NullProperty];
23
+ description?: string;
24
+ };
25
+ readonly cursor_request_key: {
26
+ oneOf: [import("./schema.js").StringProperty, import("./schema.js").NullProperty];
27
+ description?: string;
28
+ };
29
+ }, "request" | "tool_id">;
30
+ export declare const TABLE_FEED_ROUTE_CONTRACT: ContractObject<{
31
+ readonly tool_id: import("./schema.js").StringProperty;
32
+ readonly request: {
33
+ type: "object";
34
+ additionalProperties: boolean;
35
+ };
36
+ readonly rows_path: {
37
+ oneOf: [import("./schema.js").StringProperty, import("./schema.js").NullProperty];
38
+ description?: string;
39
+ };
40
+ readonly row_mapping: {
41
+ oneOf: [{
42
+ type: "object";
43
+ additionalProperties: boolean;
44
+ }, import("./schema.js").NullProperty];
45
+ description?: string;
46
+ };
47
+ readonly cursor_path: {
48
+ oneOf: [import("./schema.js").StringProperty, import("./schema.js").NullProperty];
49
+ description?: string;
50
+ };
51
+ readonly cursor_request_key: {
52
+ oneOf: [import("./schema.js").StringProperty, import("./schema.js").NullProperty];
53
+ description?: string;
54
+ };
55
+ readonly tool_ids: import("./schema.js").ArrayProperty<import("./schema.js").StringProperty>;
56
+ readonly lanes: import("./schema.js").ArrayProperty<ContractObject<{
57
+ readonly tool_id: import("./schema.js").StringProperty;
58
+ readonly request: {
59
+ type: "object";
60
+ additionalProperties: boolean;
61
+ };
62
+ readonly rows_path: {
63
+ oneOf: [import("./schema.js").StringProperty, import("./schema.js").NullProperty];
64
+ description?: string;
65
+ };
66
+ readonly row_mapping: {
67
+ oneOf: [{
68
+ type: "object";
69
+ additionalProperties: boolean;
70
+ }, import("./schema.js").NullProperty];
71
+ description?: string;
72
+ };
73
+ readonly cursor_path: {
74
+ oneOf: [import("./schema.js").StringProperty, import("./schema.js").NullProperty];
75
+ description?: string;
76
+ };
77
+ readonly cursor_request_key: {
78
+ oneOf: [import("./schema.js").StringProperty, import("./schema.js").NullProperty];
79
+ description?: string;
80
+ };
81
+ }, "request" | "tool_id">>;
82
+ readonly max_pages: {
83
+ type: "integer";
84
+ description?: string;
85
+ minimum?: number;
86
+ maximum?: number;
87
+ "x-clamp"?: true;
88
+ };
89
+ readonly upsert_key: {
90
+ oneOf: [import("./schema.js").StringProperty, import("./schema.js").NullProperty];
91
+ description?: string;
92
+ };
93
+ }, "request" | "tool_id">;
94
+ export declare const TABLE_FEED_GET_OPTIONS_CONTRACT: ContractObject<{
95
+ readonly include_route: import("./schema.js").BooleanProperty;
96
+ }, never>;
97
+ export declare const TABLE_FEED_UPDATE_CONTRACT: ContractObject<{
98
+ readonly feed: import("./schema.js").StringProperty;
99
+ readonly name: import("./schema.js").StringProperty;
100
+ readonly status: {
101
+ type: "string";
102
+ enum: readonly ("active" | "disabled")[];
103
+ description?: string;
104
+ };
105
+ readonly run_state: {
106
+ type: "string";
107
+ enum: readonly ("error" | "exhausted" | "idle" | "running")[];
108
+ description?: string;
109
+ };
110
+ readonly sync: ContractObject<{
111
+ readonly every: {
112
+ oneOf: [import("./schema.js").StringProperty, import("./schema.js").NullProperty];
113
+ description?: string;
114
+ };
115
+ readonly max_credits_per_cycle: {
116
+ readonly type: "number";
117
+ readonly exclusiveMinimum: 0;
118
+ readonly description: "Future-cycle ceiling; configuration spends nothing.";
119
+ };
120
+ readonly max_rows_per_cycle: {
121
+ type: "integer";
122
+ description?: string;
123
+ minimum?: number;
124
+ maximum?: number;
125
+ "x-clamp"?: true;
126
+ };
127
+ }, "every" | "max_credits_per_cycle" | "max_rows_per_cycle">;
128
+ readonly route: {
129
+ readonly type: "object";
130
+ readonly additionalProperties: false;
131
+ readonly properties: {
132
+ readonly tool_id: import("./schema.js").StringProperty;
133
+ readonly request: {
134
+ type: "object";
135
+ additionalProperties: boolean;
136
+ };
137
+ readonly rows_path: {
138
+ oneOf: [import("./schema.js").StringProperty, import("./schema.js").NullProperty];
139
+ description?: string;
140
+ };
141
+ readonly row_mapping: {
142
+ oneOf: [{
143
+ type: "object";
144
+ additionalProperties: boolean;
145
+ }, import("./schema.js").NullProperty];
146
+ description?: string;
147
+ };
148
+ readonly cursor_path: {
149
+ oneOf: [import("./schema.js").StringProperty, import("./schema.js").NullProperty];
150
+ description?: string;
151
+ };
152
+ readonly cursor_request_key: {
153
+ oneOf: [import("./schema.js").StringProperty, import("./schema.js").NullProperty];
154
+ description?: string;
155
+ };
156
+ readonly tool_ids: import("./schema.js").ArrayProperty<import("./schema.js").StringProperty>;
157
+ readonly lanes: import("./schema.js").ArrayProperty<ContractObject<{
158
+ readonly tool_id: import("./schema.js").StringProperty;
159
+ readonly request: {
160
+ type: "object";
161
+ additionalProperties: boolean;
162
+ };
163
+ readonly rows_path: {
164
+ oneOf: [import("./schema.js").StringProperty, import("./schema.js").NullProperty];
165
+ description?: string;
166
+ };
167
+ readonly row_mapping: {
168
+ oneOf: [{
169
+ type: "object";
170
+ additionalProperties: boolean;
171
+ }, import("./schema.js").NullProperty];
172
+ description?: string;
173
+ };
174
+ readonly cursor_path: {
175
+ oneOf: [import("./schema.js").StringProperty, import("./schema.js").NullProperty];
176
+ description?: string;
177
+ };
178
+ readonly cursor_request_key: {
179
+ oneOf: [import("./schema.js").StringProperty, import("./schema.js").NullProperty];
180
+ description?: string;
181
+ };
182
+ }, "request" | "tool_id">>;
183
+ readonly max_pages: {
184
+ type: "integer";
185
+ description?: string;
186
+ minimum?: number;
187
+ maximum?: number;
188
+ "x-clamp"?: true;
189
+ };
190
+ readonly upsert_key: {
191
+ oneOf: [import("./schema.js").StringProperty, import("./schema.js").NullProperty];
192
+ description?: string;
193
+ };
194
+ };
195
+ readonly required?: readonly ("request" | "tool_id")[];
196
+ readonly 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.";
197
+ };
198
+ readonly filters: {
199
+ type: "object";
200
+ additionalProperties: boolean;
201
+ };
202
+ readonly intent_id: import("./schema.js").StringProperty;
203
+ readonly input_shape: import("./schema.js").StringProperty;
204
+ readonly route_id: import("./schema.js").StringProperty;
205
+ readonly registry_version: import("./schema.js").StringProperty;
206
+ readonly source_prompt: import("./schema.js").StringProperty;
207
+ readonly approved: import("./schema.js").BooleanProperty;
208
+ }, "feed">;
209
+ /** New surfaces refuse provenance edits the native PATCH would otherwise ignore. */
210
+ export declare function tableFeedUpdateIssues(args: Record<string, unknown>): string[];
211
+ export declare const TABLE_FEED_UPDATE_OPERATION: OperationSpec<ContractObject>;
212
+ /** The existing native PATCH scope comparison, separate from configuration cost. */
213
+ export declare function tableFeedUpdateScopeChange(args: Record<string, unknown>, current: {
214
+ every: string | null;
215
+ maxCredits: number | null;
216
+ }): {
217
+ every: string | null;
218
+ raisesCap: boolean;
219
+ replacesSource: boolean;
220
+ changesCadence: boolean;
221
+ needsReapproval: boolean;
222
+ };
@@ -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
+ }
@@ -9,7 +9,7 @@ export declare const COPILOT_PLAYBOOKS_GENERATED: readonly [{
9
9
  }, {
10
10
  readonly slug: "inbound-led-outbound";
11
11
  readonly title: "Inbound-led outbound";
12
- readonly prompt: "Turn the people paying attention to us on LinkedIn into pipeline: people reacting to my posts or posts I pick, my followers and connections, or my profile viewers. Score them against our ideal customer and send a short LinkedIn message only to the good fits, a few a day.";
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";
@@ -16,7 +16,7 @@ export const COPILOT_PLAYBOOKS_GENERATED = [
16
16
  {
17
17
  slug: "inbound-led-outbound",
18
18
  title: "Inbound-led outbound",
19
- prompt: "Turn the people paying attention to us on LinkedIn into pipeline: people reacting to my posts or posts I pick, my followers and connections, or my profile viewers. Score them against our ideal customer and send a short LinkedIn message only to the good fits, a few a day.",
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",
@@ -1 +1 @@
1
- export declare const OXYGEN_BUILD_VERSION = "1.1011.767";
1
+ export declare const OXYGEN_BUILD_VERSION = "1.1011.803";
@@ -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.767";
2
+ export const OXYGEN_BUILD_VERSION = "1.1011.803";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oxygen-agent/cli",
3
- "version": "1.1011.767",
3
+ "version": "1.1011.803",
4
4
  "private": false,
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",