@oxygen-agent/cli 1.982.3 → 1.1003.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/admin-primary-providers-render.d.ts +0 -2
- package/dist/admin-primary-providers-render.js +1 -1
- package/dist/browser-login.js +1 -4
- package/dist/command-manifest.d.ts +3 -2
- package/dist/command-manifest.js +10 -0
- package/dist/credentials.d.ts +1 -1
- package/dist/functions-commands.js +27 -7
- package/dist/help.d.ts +29 -0
- package/dist/help.js +139 -0
- package/dist/index.js +1875 -164
- package/dist/knowledge-mirror.d.ts +2 -2
- package/dist/runtime.d.ts +0 -15
- package/dist/runtime.js +1 -1
- package/dist/session.d.ts +4 -3
- package/dist/skills.d.ts +8 -7
- package/dist/skills.js +24 -10
- package/dist/transcript.d.ts +2 -1
- package/dist/ugc-commands.d.ts +3 -6
- package/dist/ugc-commands.js +2 -1200
- package/dist/util.d.ts +1 -1
- package/dist/util.js +1 -3
- package/node_modules/@oxygen/cli-ugc/dist/commands.d.ts +3 -0
- package/node_modules/@oxygen/cli-ugc/dist/commands.js +1178 -0
- package/node_modules/@oxygen/cli-ugc/dist/field-parser.d.ts +7 -0
- package/node_modules/@oxygen/cli-ugc/dist/field-parser.js +25 -0
- package/node_modules/@oxygen/cli-ugc/dist/index.d.ts +14 -0
- package/node_modules/@oxygen/cli-ugc/dist/index.js +5 -0
- package/node_modules/@oxygen/cli-ugc/package.json +15 -0
- package/node_modules/@oxygen/formula/dist/coerce.d.ts +10 -0
- package/node_modules/@oxygen/formula/dist/coerce.js +10 -0
- package/node_modules/@oxygen/formula/dist/expression.js +14 -1
- package/node_modules/@oxygen/formula/dist/formula-functions.js +136 -1
- package/node_modules/@oxygen/formula/dist/hash.d.ts +19 -0
- package/node_modules/@oxygen/formula/dist/hash.js +199 -0
- package/node_modules/@oxygen/formula/dist/index.d.ts +1 -0
- package/node_modules/@oxygen/formula/dist/index.js +1 -0
- package/node_modules/@oxygen/formula/dist/value-cleaners.d.ts +74 -0
- package/node_modules/@oxygen/formula/dist/value-cleaners.js +358 -0
- package/node_modules/@oxygen/shared/dist/array-utils.d.ts +5 -0
- package/node_modules/@oxygen/shared/dist/array-utils.js +11 -0
- package/node_modules/@oxygen/shared/dist/billing.d.ts +103 -47
- package/node_modules/@oxygen/shared/dist/billing.js +150 -40
- package/node_modules/@oxygen/shared/dist/capability-discovery.d.ts +17 -0
- package/node_modules/@oxygen/shared/dist/capability-discovery.js +114 -16
- package/node_modules/@oxygen/shared/dist/column-autofill.d.ts +52 -0
- package/node_modules/@oxygen/shared/dist/column-autofill.js +80 -0
- package/node_modules/@oxygen/shared/dist/column-output-fields.js +14 -10
- package/node_modules/@oxygen/shared/dist/company-enrichment-fields.d.ts +108 -0
- package/node_modules/@oxygen/shared/dist/company-enrichment-fields.js +545 -0
- package/node_modules/@oxygen/shared/dist/copilot-playbooks.d.ts +18 -0
- package/node_modules/@oxygen/shared/dist/copilot-playbooks.js +43 -0
- package/node_modules/@oxygen/shared/dist/copilot-skills.d.ts +15 -0
- package/node_modules/@oxygen/shared/dist/copilot-skills.generated.d.ts +31 -0
- package/node_modules/@oxygen/shared/dist/copilot-skills.generated.js +41 -0
- package/node_modules/@oxygen/shared/dist/copilot-skills.js +6 -0
- package/node_modules/@oxygen/shared/dist/deploy-env.d.ts +74 -0
- package/node_modules/@oxygen/shared/dist/deploy-env.js +82 -0
- package/node_modules/@oxygen/shared/dist/dnc-rules.d.ts +130 -0
- package/node_modules/@oxygen/shared/dist/dnc-rules.js +221 -0
- package/node_modules/@oxygen/shared/dist/enrichment-intents.d.ts +103 -0
- package/node_modules/@oxygen/shared/dist/enrichment-intents.js +819 -0
- package/node_modules/@oxygen/shared/dist/error-message.d.ts +1 -0
- package/node_modules/@oxygen/shared/dist/error-message.js +3 -0
- package/node_modules/@oxygen/shared/dist/error-redaction.js +1 -3
- package/node_modules/@oxygen/shared/dist/external-write-policy.d.ts +33 -0
- package/node_modules/@oxygen/shared/dist/external-write-policy.js +68 -0
- package/node_modules/@oxygen/shared/dist/format-percent.d.ts +8 -0
- package/node_modules/@oxygen/shared/dist/format-percent.js +13 -0
- package/node_modules/@oxygen/shared/dist/freemail-domains.d.ts +81 -0
- package/node_modules/@oxygen/shared/dist/freemail-domains.js +157 -0
- package/node_modules/@oxygen/shared/dist/future-signup-lifecycle-projection.d.ts +1 -0
- package/node_modules/@oxygen/shared/dist/future-signup-lifecycle-projection.js +1 -1
- package/node_modules/@oxygen/shared/dist/index.d.ts +14 -0
- package/node_modules/@oxygen/shared/dist/index.js +14 -0
- package/node_modules/@oxygen/shared/dist/json-path.js +1 -3
- package/node_modules/@oxygen/shared/dist/knowledge-bases.js +1 -3
- package/node_modules/@oxygen/shared/dist/knowledge-bootstrap.d.ts +17 -2
- package/node_modules/@oxygen/shared/dist/knowledge-bootstrap.js +28 -6
- package/node_modules/@oxygen/shared/dist/langfuse.d.ts +12 -1
- package/node_modules/@oxygen/shared/dist/langfuse.js +57 -8
- package/node_modules/@oxygen/shared/dist/linkedin-countries.d.ts +32 -0
- package/node_modules/@oxygen/shared/dist/linkedin-countries.js +359 -0
- package/node_modules/@oxygen/shared/dist/log-sink-selector.d.ts +39 -0
- package/node_modules/@oxygen/shared/dist/log-sink-selector.js +56 -0
- package/node_modules/@oxygen/shared/dist/log.d.ts +1 -0
- package/node_modules/@oxygen/shared/dist/log.js +6 -1
- package/node_modules/@oxygen/shared/dist/object-storage.d.ts +17 -0
- package/node_modules/@oxygen/shared/dist/object-storage.js +21 -0
- package/node_modules/@oxygen/shared/dist/otlp-log-sink.d.ts +54 -0
- package/node_modules/@oxygen/shared/dist/otlp-log-sink.js +213 -0
- package/node_modules/@oxygen/shared/dist/plan-capabilities.js +1 -0
- package/node_modules/@oxygen/shared/dist/plan-limits.d.ts +23 -22
- package/node_modules/@oxygen/shared/dist/plan-limits.js +45 -18
- package/node_modules/@oxygen/shared/dist/pricing-sheet.d.ts +48 -41
- package/node_modules/@oxygen/shared/dist/pricing-sheet.js +36 -25
- package/node_modules/@oxygen/shared/dist/pricing-snapshot.generated.d.ts +22 -22
- package/node_modules/@oxygen/shared/dist/pricing-snapshot.generated.js +40 -34
- package/node_modules/@oxygen/shared/dist/product-analytics-environment.js +9 -0
- package/node_modules/@oxygen/shared/dist/product-analytics-events.d.ts +15 -0
- package/node_modules/@oxygen/shared/dist/product-analytics-events.js +15 -0
- package/node_modules/@oxygen/shared/dist/rate-window.d.ts +5 -0
- package/node_modules/@oxygen/shared/dist/rate-window.js +8 -0
- package/node_modules/@oxygen/shared/dist/research-output-contract.d.ts +33 -1
- package/node_modules/@oxygen/shared/dist/research-output-contract.js +65 -5
- package/node_modules/@oxygen/shared/dist/search-vocab.js +4 -5
- package/node_modules/@oxygen/shared/dist/select-options.js +6 -1
- package/node_modules/@oxygen/shared/dist/sequence-crm-events.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/sequence-failures.js +1 -5
- package/node_modules/@oxygen/shared/dist/sequence-hubspot-sync.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/sequences.d.ts +49 -0
- package/node_modules/@oxygen/shared/dist/sequences.js +134 -4
- package/node_modules/@oxygen/shared/dist/spend-safety.d.ts +22 -10
- package/node_modules/@oxygen/shared/dist/spend-safety.js +15 -21
- package/node_modules/@oxygen/shared/dist/sql-rows.d.ts +1 -0
- package/node_modules/@oxygen/shared/dist/sql-rows.js +3 -0
- package/node_modules/@oxygen/shared/dist/telemetry.js +9 -1
- package/node_modules/@oxygen/shared/dist/type-guards.d.ts +22 -0
- package/node_modules/@oxygen/shared/dist/type-guards.js +35 -0
- package/node_modules/@oxygen/shared/dist/value-readers.d.ts +21 -0
- package/node_modules/@oxygen/shared/dist/value-readers.js +59 -0
- package/node_modules/@oxygen/shared/dist/version.js +1 -1
- package/node_modules/@oxygen/shared/package.json +60 -0
- package/node_modules/@oxygen/workflows/dist/graph/expression.js +2 -5
- package/node_modules/@oxygen/workflows/dist/graph/manifest-schema.d.ts +15 -15
- package/node_modules/@oxygen/workflows/dist/graph/params.js +1 -1
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -47,7 +47,7 @@ function pct(value) {
|
|
|
47
47
|
return `${Math.round(parsed * 100)}%`;
|
|
48
48
|
}
|
|
49
49
|
/** Age of an ISO stamp as a short human span, measured against `now`. */
|
|
50
|
-
|
|
50
|
+
function ago(iso, now = new Date()) {
|
|
51
51
|
const raw = str(iso);
|
|
52
52
|
if (!raw)
|
|
53
53
|
return "never";
|
package/dist/browser-login.js
CHANGED
|
@@ -2,7 +2,7 @@ import { execFileSync } from "node:child_process";
|
|
|
2
2
|
import { randomBytes, timingSafeEqual } from "node:crypto";
|
|
3
3
|
import { createServer } from "node:http";
|
|
4
4
|
import { hostname } from "node:os";
|
|
5
|
-
import { OXYGEN_VERSION, OxygenError, deriveCliLoginConfirmationCode } from "@oxygen/shared";
|
|
5
|
+
import { OXYGEN_VERSION, OxygenError, deriveCliLoginConfirmationCode, sleep } from "@oxygen/shared";
|
|
6
6
|
import { requestOxygen } from "./http-client.js";
|
|
7
7
|
import { readErrorMessage } from "./util.js";
|
|
8
8
|
const CALLBACK_HOST = "127.0.0.1";
|
|
@@ -133,9 +133,6 @@ function safeHostname() {
|
|
|
133
133
|
return undefined;
|
|
134
134
|
}
|
|
135
135
|
}
|
|
136
|
-
function sleep(ms) {
|
|
137
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
138
|
-
}
|
|
139
136
|
export async function createBrowserLoginSession(apiUrl) {
|
|
140
137
|
const state = randomBytes(32).toString("base64url");
|
|
141
138
|
let settled = false;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { Command } from "commander";
|
|
2
|
-
|
|
2
|
+
type CommandManifestFlag = {
|
|
3
3
|
flags: string;
|
|
4
4
|
description: string;
|
|
5
5
|
required: boolean;
|
|
6
6
|
};
|
|
7
|
-
|
|
7
|
+
type CommandManifestArgument = {
|
|
8
8
|
name: string;
|
|
9
9
|
required: boolean;
|
|
10
10
|
description: string;
|
|
@@ -46,3 +46,4 @@ export declare function getCommandManifestEntry(manifest: CommandManifest, exact
|
|
|
46
46
|
invoke: string;
|
|
47
47
|
}) | null;
|
|
48
48
|
export declare function suggestCommandNames(manifest: CommandManifest, query: string, limit?: number): string[];
|
|
49
|
+
export {};
|
package/dist/command-manifest.js
CHANGED
|
@@ -37,6 +37,16 @@ const MUTATING_VERBS = new Set([
|
|
|
37
37
|
// recurring write, and --run can connect newly eligible mailboxes immediately.
|
|
38
38
|
"auto-enroll",
|
|
39
39
|
"backfill",
|
|
40
|
+
// `dashboards widgets refresh` calls a provider and bills the workspace. It is
|
|
41
|
+
// currently the only `refresh` leaf; the default (mutates:false) would
|
|
42
|
+
// advertise the one dashboard command that spends money as a read, to every
|
|
43
|
+
// agent and in the public CLI reference.
|
|
44
|
+
"refresh",
|
|
45
|
+
// Exact hyphenated leaf, because the `backfill` entry above matches the whole
|
|
46
|
+
// leaf token and never `crm-backfill`. `suppressions crm-backfill --live`
|
|
47
|
+
// creates CRM person records for everyone on the do-not-contact list, so the
|
|
48
|
+
// default (mutates:false) would advertise a bulk workspace write as a read.
|
|
49
|
+
"crm-backfill",
|
|
40
50
|
// A noun leaf, so the default would advertise `projects color` — a tenant
|
|
41
51
|
// write — to every agent as a read. `decide` is the same case.
|
|
42
52
|
"color",
|
package/dist/credentials.d.ts
CHANGED
|
@@ -34,7 +34,7 @@ export declare function defaultApiUrl(env?: NodeJS.ProcessEnv): string;
|
|
|
34
34
|
* look identical, and a drifted profile turns a prod-labelled binary into a report
|
|
35
35
|
* about dev that reads as a production outage (OXY-4091).
|
|
36
36
|
*/
|
|
37
|
-
|
|
37
|
+
type CliEndpointContext = {
|
|
38
38
|
apiUrl: string;
|
|
39
39
|
/** Active profile name, or null when no named profile supplied the credentials. */
|
|
40
40
|
profile: string | null;
|
|
@@ -3,12 +3,28 @@ import { parseJsonObject } from "./cli-values.js";
|
|
|
3
3
|
import { requestOxygen } from "./http-client.js";
|
|
4
4
|
export function registerFunctionsCommands(program, handle) {
|
|
5
5
|
const functions = program.command("functions")
|
|
6
|
-
.description("
|
|
7
|
-
.addHelpText("after", "\nDraft edits are isolated. Publishing updates future invocations of every caller; queued, in-flight and past runs retain their captured version. Existing caller caps never increase automatically.\nFlow: draft → describe → publish → bind → columns run --dry-run → approved run → runs.\nA bound Function executes on its own published execution table and writes named outputs back to the calling table. The call stays visible from the caller: `table-runs list --table <caller> --status all` lists the run, and the binding column's cell holds the outcome (status, outputs, credits, invocation and run ids). Address a Function by id, slug, or the display name shown by `functions list`.\nWorked example with commands: `oxygen skills install --skill oxygen-gtm --project`, then read its recipes/callable-tables.md.\n");
|
|
8
|
-
functions.command("list").description("List the Function library,
|
|
6
|
+
.description("Browse OXYGEN's ready-made Functions (work email, mobile phone, company funding stage, ...), favourite them, bind them to a table, or create, edit and publish your own Functions backed by ordinary Tables.")
|
|
7
|
+
.addHelpText("after", "\nOXYGEN-managed Functions are pre-built and priced: `functions list --managed` shows each one with its per-row credit estimate before you attach it. Attaching (`functions bind`) is free; only `columns run` spends, after a dry run. A managed Function is read-only; `functions duplicate <function>` gives you an editable copy.\nDraft edits are isolated. Publishing updates future invocations of every caller; queued, in-flight and past runs retain their captured version. Existing caller caps never increase automatically.\nFlow: draft → describe → publish → bind → columns run --dry-run → approved run → runs.\nA bound Function executes on its own published execution table and writes named outputs back to the calling table. The call stays visible from the caller: `table-runs list --table <caller> --status all` lists the run, and the binding column's cell holds the outcome (status, outputs, credits, invocation and run ids). Address a Function by id, slug, or the display name shown by `functions list`.\nWorked example with commands: `oxygen skills install --skill oxygen-gtm --project`, then read its recipes/callable-tables.md.\n");
|
|
8
|
+
functions.command("list").description("List the Function library: OXYGEN-managed Functions with their per-row credit estimate, plus your workspace's own drafts and published Functions (up to 500).")
|
|
9
|
+
.option("--managed", "Only OXYGEN-managed Functions (pre-built, priced, read-only; duplicate to customize).")
|
|
10
|
+
.option("--favorites", "Only the Functions you favourited (`functions favorite <function>`).")
|
|
9
11
|
.option("--json", "Print a JSON envelope.")
|
|
10
|
-
.action((options) => handle("functions list", options, () =>
|
|
11
|
-
|
|
12
|
+
.action((options) => handle("functions list", options, () => {
|
|
13
|
+
if (options.managed && options.favorites)
|
|
14
|
+
throw new OxygenError("invalid_request", "Pass --managed or --favorites, not both.", { exitCode: 1 });
|
|
15
|
+
const filter = options.managed ? "managed" : options.favorites ? "favorites" : null;
|
|
16
|
+
return requestOxygen(filter ? `/api/cli/functions?${new URLSearchParams({ filter })}` : "/api/cli/functions");
|
|
17
|
+
}));
|
|
18
|
+
for (const [command, label] of [["favorite", "Favourite a Function so it appears under `functions list --favorites` and the Favorites tab; per user, per workspace."], ["unfavorite", "Remove a Function from your favourites."]]) {
|
|
19
|
+
functions.command(`${command} <function>`).description(label)
|
|
20
|
+
.option("--json", "Print a JSON envelope.")
|
|
21
|
+
.action((ref, options) => handle(`functions ${command}`, options, () => requestOxygen("/api/cli/functions", { method: "POST", body: { operation: command, function: ref } })));
|
|
22
|
+
}
|
|
23
|
+
functions.command("duplicate <function>").description("Copy a Function's steps into a new editable draft of your own (same inputs and outputs, no rows). The way to customize an OXYGEN-managed Function.")
|
|
24
|
+
.option("--name <name>", "Display name for the copy. Defaults to '<source> (copy)'.")
|
|
25
|
+
.option("--json", "Print a JSON envelope.")
|
|
26
|
+
.action((ref, options) => handle("functions duplicate", options, () => requestOxygen("/api/cli/functions", { method: "POST", body: { operation: "duplicate", function: ref, ...(options.name ? { display_name: options.name } : {}) } })));
|
|
27
|
+
functions.command("describe <function>").description("Inspect a Function's inputs, outputs, steps, per-row credit estimate, caps, and whether it is OXYGEN-managed or your own draft/published version.")
|
|
12
28
|
.option("--json", "Print a JSON envelope.")
|
|
13
29
|
.action((ref, options) => handle("functions describe", options, () => requestOxygen(`/api/cli/functions?${new URLSearchParams({ function: ref })}`)));
|
|
14
30
|
functions.command("draft [function]").description("Create a Function draft, or save an existing Function's draft; executes nothing.")
|
|
@@ -31,11 +47,15 @@ export function registerFunctionsCommands(program, handle) {
|
|
|
31
47
|
functions.command("rename <function> <name>").description("Rename a Function while preserving its identity, callers and published execution.")
|
|
32
48
|
.option("--json", "Print a JSON envelope.")
|
|
33
49
|
.action((ref, name, options) => handle("functions rename", options, () => requestOxygen("/api/cli/functions", { method: "POST", body: { operation: "rename", function: ref, display_name: name } })));
|
|
34
|
-
functions.command("delete <function>").description("Preview removal from the Function library; preserves backing tables, rows and run history. Connected callers or active runs block deletion.")
|
|
35
|
-
.addHelpText("after", "\
|
|
50
|
+
functions.command("delete <function>").description("Preview removal from the Function library, then remove it with --yes; preserves backing tables, rows and run history. Connected callers or active runs block deletion. Works on an OXYGEN-managed Function too: it leaves this workspace's library and is not seeded back.")
|
|
51
|
+
.addHelpText("after", "\nDeleting your own Function is final: there is no restore, unlike `tables delete`. To reuse the logic, `tables duplicate` the backing Table and draft a new Function from the copy.\nDeleting an OXYGEN-managed Function only removes it from THIS workspace; `functions restore` brings OXYGEN's ready-made Functions back.\n")
|
|
36
52
|
.option("--yes", "Confirm removal of this Function after reviewing its callers.")
|
|
37
53
|
.option("--json", "Print a JSON envelope.")
|
|
38
54
|
.action((ref, options) => handle("functions delete", options, () => requestOxygen("/api/cli/functions", { method: "POST", body: { operation: "delete", function: ref, approved: options.yes === true } })));
|
|
55
|
+
functions.command("restore").description("Put back the OXYGEN-managed Functions this workspace deleted. They are rebuilt at the current catalog version in the background; `functions list --managed` shows them as they land.")
|
|
56
|
+
.option("--catalog-id <id...>", "Restore only these catalog entries (the managed.catalogId from `functions describe`). Defaults to every removed one.")
|
|
57
|
+
.option("--json", "Print a JSON envelope.")
|
|
58
|
+
.action((options) => handle("functions restore", options, () => requestOxygen("/api/cli/functions", { method: "POST", body: { operation: "restore_managed", ...(options.catalogId?.length ? { catalog_ids: options.catalogId } : {}) } })));
|
|
39
59
|
functions.command("bind <table> <function>").description("Add a Function column with explicit input/output mappings and a caller credit cap. Create each mapped output column on the caller table first with `columns add`; bind rejects an output mapped to a column the caller table does not have.")
|
|
40
60
|
.requiredOption("--inputs-json <json>", "Object mapping Function input keys to caller column keys.")
|
|
41
61
|
.requiredOption("--outputs-json <json>", "Object mapping Function output keys to existing caller column keys.")
|
package/dist/help.d.ts
CHANGED
|
@@ -1,2 +1,31 @@
|
|
|
1
1
|
import type { Command } from "commander";
|
|
2
2
|
export declare function applyOxygenHelp(program: Command, binaryName: string): void;
|
|
3
|
+
/**
|
|
4
|
+
* Turn commander's own edit-distance suggester on for EVERY command.
|
|
5
|
+
*
|
|
6
|
+
* It defaults to on, but `copyInheritedSettings` only runs for children created
|
|
7
|
+
* through `.command()`; the hundreds of subcommands this CLI registers with
|
|
8
|
+
* `.addCommand(new Command(...))` carry whatever their own constructor set.
|
|
9
|
+
* Walking the tree makes the setting a property of the whole surface rather
|
|
10
|
+
* than of how each command happened to be built, the same reason
|
|
11
|
+
* `installCommanderExitOverride` recurses.
|
|
12
|
+
*/
|
|
13
|
+
export declare function enableCommandSuggestions(command: Command): void;
|
|
14
|
+
/**
|
|
15
|
+
* The extra line printed after `error: unknown command '<x>'`.
|
|
16
|
+
*
|
|
17
|
+
* Commander's message names what is wrong and nothing a user can do next. This
|
|
18
|
+
* resolves the command they were actually inside, offers the synonym or unique
|
|
19
|
+
* prefix match commander cannot reach, and always names the exact `--help` that
|
|
20
|
+
* lists the real subcommands. Returns null when argv does not describe an
|
|
21
|
+
* unknown subcommand (an unknown OPTION has its own handling).
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Hint for `error: unknown option '--filter'`. Commander's own suggester stops
|
|
25
|
+
* at three edits, so `--filter` never reaches `--filter-json`; a flag that is a
|
|
26
|
+
* prefix of exactly one option on that command (or of which exactly one option
|
|
27
|
+
* is a prefix) names it. Returns null when commander's output already says it
|
|
28
|
+
* all, or when the flag is not a long option.
|
|
29
|
+
*/
|
|
30
|
+
export declare function unknownOptionHint(program: Command, argv: readonly string[], message: string): string | null;
|
|
31
|
+
export declare function unknownCommandHint(program: Command, argv: readonly string[]): string | null;
|
package/dist/help.js
CHANGED
|
@@ -139,6 +139,10 @@ export function applyOxygenHelp(program, binaryName) {
|
|
|
139
139
|
` 2. ${binaryName} skills install --json load the skills that teach the GTM loops (automatic after login)`,
|
|
140
140
|
" Add --project to keep the skills inside the current project, including confined agent sessions.",
|
|
141
141
|
` 3. ${binaryName} context resolve --json load workspace context before operating primitives`,
|
|
142
|
+
// A new workspace's first sessions are onboarding, and the consultant guide is
|
|
143
|
+
// a served skill an agent has to be TOLD about: nothing else on a first-touch
|
|
144
|
+
// surface named it (blind eval, 2026-09-16).
|
|
145
|
+
` New or thin workspace? load the onboarding consultant first: ${binaryName} skills get oxygen-onboarding --json`,
|
|
142
146
|
` 4. ${binaryName} capabilities search "<goal>" --json route the goal, then hydrate one exact command`,
|
|
143
147
|
` ${binaryName} commands search "<term>" --json find a command by name or purpose instead of dumping the manifest`,
|
|
144
148
|
` 5. ${binaryName} recipes list --json choose a play from the Recipe catalog for your goal`,
|
|
@@ -155,3 +159,138 @@ export function applyOxygenHelp(program, binaryName) {
|
|
|
155
159
|
`Exit codes: ${exitCodeLine}`,
|
|
156
160
|
].join("\n"));
|
|
157
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* Turn commander's own edit-distance suggester on for EVERY command.
|
|
164
|
+
*
|
|
165
|
+
* It defaults to on, but `copyInheritedSettings` only runs for children created
|
|
166
|
+
* through `.command()`; the hundreds of subcommands this CLI registers with
|
|
167
|
+
* `.addCommand(new Command(...))` carry whatever their own constructor set.
|
|
168
|
+
* Walking the tree makes the setting a property of the whole surface rather
|
|
169
|
+
* than of how each command happened to be built, the same reason
|
|
170
|
+
* `installCommanderExitOverride` recurses.
|
|
171
|
+
*/
|
|
172
|
+
export function enableCommandSuggestions(command) {
|
|
173
|
+
command.showSuggestionAfterError(true);
|
|
174
|
+
for (const child of command.commands)
|
|
175
|
+
enableCommandSuggestions(child);
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Verbs a user reaches for that this CLI spells differently.
|
|
179
|
+
*
|
|
180
|
+
* Commander's suggester is edit distance only, so it fires for a typo
|
|
181
|
+
* (`describ` → `describe`) and never for a synonym: `get` is seven edits from
|
|
182
|
+
* `describe`, so `oxygen tables get` answered `error: unknown command 'get'`
|
|
183
|
+
* and stopped there with nothing to try next (blind user eval, 2026-09-17).
|
|
184
|
+
* Values are candidate real subcommand names, best first; only names the
|
|
185
|
+
* command actually has are ever offered.
|
|
186
|
+
*/
|
|
187
|
+
const COMMAND_SYNONYMS = {
|
|
188
|
+
get: ["describe", "show", "view", "status", "preview"],
|
|
189
|
+
show: ["describe", "get", "list", "preview"],
|
|
190
|
+
view: ["describe", "preview", "show", "get"],
|
|
191
|
+
info: ["describe", "status", "show"],
|
|
192
|
+
inspect: ["describe", "preview", "show"],
|
|
193
|
+
read: ["describe", "query", "export", "get"],
|
|
194
|
+
ls: ["list"],
|
|
195
|
+
all: ["list"],
|
|
196
|
+
new: ["create", "add"],
|
|
197
|
+
make: ["create", "add"],
|
|
198
|
+
rm: ["delete", "remove", "archive"],
|
|
199
|
+
del: ["delete", "remove", "archive"],
|
|
200
|
+
remove: ["delete", "archive"],
|
|
201
|
+
destroy: ["delete", "archive"],
|
|
202
|
+
edit: ["update", "set", "rename"],
|
|
203
|
+
modify: ["update", "set"],
|
|
204
|
+
exec: ["run", "start", "call"],
|
|
205
|
+
execute: ["run", "start", "call"],
|
|
206
|
+
find: ["search", "query", "list"],
|
|
207
|
+
};
|
|
208
|
+
/**
|
|
209
|
+
* The extra line printed after `error: unknown command '<x>'`.
|
|
210
|
+
*
|
|
211
|
+
* Commander's message names what is wrong and nothing a user can do next. This
|
|
212
|
+
* resolves the command they were actually inside, offers the synonym or unique
|
|
213
|
+
* prefix match commander cannot reach, and always names the exact `--help` that
|
|
214
|
+
* lists the real subcommands. Returns null when argv does not describe an
|
|
215
|
+
* unknown subcommand (an unknown OPTION has its own handling).
|
|
216
|
+
*/
|
|
217
|
+
/**
|
|
218
|
+
* Hint for `error: unknown option '--filter'`. Commander's own suggester stops
|
|
219
|
+
* at three edits, so `--filter` never reaches `--filter-json`; a flag that is a
|
|
220
|
+
* prefix of exactly one option on that command (or of which exactly one option
|
|
221
|
+
* is a prefix) names it. Returns null when commander's output already says it
|
|
222
|
+
* all, or when the flag is not a long option.
|
|
223
|
+
*/
|
|
224
|
+
export function unknownOptionHint(program, argv, message) {
|
|
225
|
+
const flag = /unknown option '(--[^']+)'/.exec(message)?.[1];
|
|
226
|
+
if (!flag)
|
|
227
|
+
return null;
|
|
228
|
+
const [command, path] = resolveCommandPath(program, argv);
|
|
229
|
+
const longs = new Set();
|
|
230
|
+
for (let current = command; current; current = current.parent) {
|
|
231
|
+
for (const option of current.options)
|
|
232
|
+
if (option.long)
|
|
233
|
+
longs.add(option.long);
|
|
234
|
+
}
|
|
235
|
+
const bare = flag.split("=")[0].toLowerCase();
|
|
236
|
+
if (longs.has(bare))
|
|
237
|
+
return null;
|
|
238
|
+
const candidates = [...longs].filter((long) => long.startsWith(bare) || bare.startsWith(long));
|
|
239
|
+
const helpLine = `Run \`${path} --help\` for its options.`;
|
|
240
|
+
if (candidates.length === 1) {
|
|
241
|
+
return `Hint: \`${path}\` has no \`${bare}\`. Did you mean \`${candidates[0]}\`? ${helpLine}`;
|
|
242
|
+
}
|
|
243
|
+
if (candidates.length > 1 && candidates.length <= 4) {
|
|
244
|
+
return `Hint: \`${path}\` has no \`${bare}\`. Did you mean one of ${candidates.map((c) => `\`${c}\``).join(", ")}? ${helpLine}`;
|
|
245
|
+
}
|
|
246
|
+
return `Hint: \`${path}\` has no \`${bare}\`. ${helpLine}`;
|
|
247
|
+
}
|
|
248
|
+
/** Walk the command path in argv (stopping at the first option) and return the deepest command with its printable path. */
|
|
249
|
+
function resolveCommandPath(program, argv) {
|
|
250
|
+
let current = program;
|
|
251
|
+
let path = program.name();
|
|
252
|
+
for (const token of argv) {
|
|
253
|
+
if (token.startsWith("-"))
|
|
254
|
+
break;
|
|
255
|
+
const child = current.commands.find((candidate) => candidate.name() === token || candidate.aliases().includes(token));
|
|
256
|
+
if (!child)
|
|
257
|
+
break;
|
|
258
|
+
current = child;
|
|
259
|
+
path = `${path} ${token}`;
|
|
260
|
+
}
|
|
261
|
+
return [current, path];
|
|
262
|
+
}
|
|
263
|
+
export function unknownCommandHint(program, argv) {
|
|
264
|
+
let current = program;
|
|
265
|
+
let path = program.name();
|
|
266
|
+
for (const token of argv) {
|
|
267
|
+
// Options and their values are commander's business; only the command path
|
|
268
|
+
// is walked here.
|
|
269
|
+
if (token.startsWith("-"))
|
|
270
|
+
break;
|
|
271
|
+
const child = current.commands.find((candidate) => candidate.name() === token || candidate.aliases().includes(token));
|
|
272
|
+
if (child) {
|
|
273
|
+
current = child;
|
|
274
|
+
path = `${path} ${token}`;
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
if (current.commands.length === 0)
|
|
278
|
+
return null;
|
|
279
|
+
return buildUnknownCommandHint(current, path, token);
|
|
280
|
+
}
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
function buildUnknownCommandHint(parent, path, token) {
|
|
284
|
+
const names = parent.commands.map((command) => command.name()).filter((name) => name !== "help");
|
|
285
|
+
const lower = token.toLowerCase();
|
|
286
|
+
const synonym = (COMMAND_SYNONYMS[lower] ?? []).find((candidate) => names.includes(candidate));
|
|
287
|
+
// A unique prefix is the other guess commander cannot make: `tables desc`
|
|
288
|
+
// scores too far from `describe` on edit distance, but it names exactly one
|
|
289
|
+
// command.
|
|
290
|
+
const prefixMatches = names.filter((name) => name.startsWith(lower));
|
|
291
|
+
const suggestion = synonym ?? (prefixMatches.length === 1 ? prefixMatches[0] : null);
|
|
292
|
+
const helpLine = `Run \`${path} --help\` for the ${names.length} subcommands of \`${path}\`.`;
|
|
293
|
+
return suggestion
|
|
294
|
+
? `Hint: \`${path}\` has no \`${token}\`. Did you mean \`${path} ${suggestion}\`? ${helpLine}`
|
|
295
|
+
: `Hint: \`${path}\` has no \`${token}\`. ${helpLine}`;
|
|
296
|
+
}
|