@oxygen-agent/cli 1.591.1 → 1.615.0

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 (28) hide show
  1. package/README.md +1 -1
  2. package/dist/command-manifest.d.ts +18 -0
  3. package/dist/command-manifest.js +106 -5
  4. package/dist/help.js +2 -1
  5. package/dist/index.js +273 -38
  6. package/dist/skills.d.ts +6 -0
  7. package/dist/skills.js +200 -1
  8. package/node_modules/@oxygen/shared/dist/capability-discovery.d.ts +36 -0
  9. package/node_modules/@oxygen/shared/dist/capability-discovery.js +766 -0
  10. package/node_modules/@oxygen/shared/dist/cli-result.js +4 -3
  11. package/node_modules/@oxygen/shared/dist/index.d.ts +2 -0
  12. package/node_modules/@oxygen/shared/dist/index.js +2 -0
  13. package/node_modules/@oxygen/shared/dist/pricing-sheet.d.ts +1 -1
  14. package/node_modules/@oxygen/shared/dist/pricing-sheet.js +1 -1
  15. package/node_modules/@oxygen/shared/dist/recipes.d.ts +1 -1
  16. package/node_modules/@oxygen/shared/dist/recipes.js +4 -2
  17. package/node_modules/@oxygen/shared/dist/sequence-template.js +0 -0
  18. package/node_modules/@oxygen/shared/dist/sequence-terminal-events.d.ts +47 -0
  19. package/node_modules/@oxygen/shared/dist/sequence-terminal-events.js +70 -0
  20. package/node_modules/@oxygen/shared/dist/version.d.ts +1 -1
  21. package/node_modules/@oxygen/shared/dist/version.js +1 -1
  22. package/node_modules/@oxygen/workflows/dist/graph/lint.js +3 -0
  23. package/node_modules/@oxygen/workflows/dist/graph/manifest-schema.d.ts +5 -0
  24. package/node_modules/@oxygen/workflows/dist/graph/manifest-schema.js +5 -0
  25. package/node_modules/@oxygen/workflows/dist/graph/types.d.ts +2 -0
  26. package/node_modules/@oxygen/workflows/dist/index.d.ts +4 -0
  27. package/node_modules/@oxygen/workflows/dist/index.js +5 -0
  28. 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.591.1
37
+ Version: 1.615.0
@@ -17,6 +17,7 @@ export type CommandManifestEntry = {
17
17
  flags: CommandManifestFlag[];
18
18
  spends_credits: boolean;
19
19
  mutates: boolean;
20
+ preview_by_default: boolean;
20
21
  json_supported: boolean;
21
22
  hidden: boolean;
22
23
  };
@@ -27,4 +28,21 @@ export type CommandManifest = {
27
28
  exit_codes: Record<string, string>;
28
29
  commands: CommandManifestEntry[];
29
30
  };
31
+ export type CommandSearchResult = {
32
+ query: string;
33
+ total_matches: number;
34
+ returned: number;
35
+ route: Record<string, unknown> | null;
36
+ commands: Array<Pick<CommandManifestEntry, "name" | "group" | "description" | "spends_credits" | "mutates" | "json_supported" | "hidden"> & {
37
+ score: number;
38
+ }>;
39
+ hydrate: string;
40
+ };
30
41
  export declare function buildCommandManifest(program: Command, binaryName: string): CommandManifest;
42
+ /** Bounded natural-language projection over the complete local manifest. */
43
+ export declare function searchCommandManifest(manifest: CommandManifest, query: string, requestedLimit?: number): CommandSearchResult;
44
+ /** Exact second hop after search; avoids serializing the full command grammar. */
45
+ export declare function getCommandManifestEntry(manifest: CommandManifest, exactName: string): (CommandManifestEntry & {
46
+ invoke: string;
47
+ }) | null;
48
+ export declare function suggestCommandNames(manifest: CommandManifest, query: string, limit?: number): string[];
@@ -1,4 +1,10 @@
1
- import { CLI_EXIT_CODE_TABLE, OXYGEN_VERSION } from "@oxygen/shared";
1
+ import { CLI_EXIT_CODE_TABLE, OXYGEN_VERSION, inferCapabilityRoute, serializeCapabilityRoute, } from "@oxygen/shared";
2
+ const DEFAULT_COMMAND_SEARCH_LIMIT = 10;
3
+ const MAX_COMMAND_SEARCH_LIMIT = 25;
4
+ const COMMAND_SEARCH_STOP_WORDS = new Set([
5
+ "a", "an", "and", "for", "from", "get", "i", "in", "into", "is", "me",
6
+ "of", "on", "or", "please", "show", "the", "to", "want", "with",
7
+ ]);
2
8
  // Leaf verbs (or their hyphen-prefix) that name a state mutation, external
3
9
  // write, or paid side effect. `mutates` is derived from this set (see
4
10
  // toManifestEntry). It is hand-curated and cross-checked against the real leaf
@@ -47,14 +53,108 @@ export function buildCommandManifest(program, binaryName) {
47
53
  commands,
48
54
  };
49
55
  }
56
+ /** Bounded natural-language projection over the complete local manifest. */
57
+ export function searchCommandManifest(manifest, query, requestedLimit = DEFAULT_COMMAND_SEARCH_LIMIT) {
58
+ const normalized = query.trim();
59
+ const tokens = tokenizeCommandQuery(normalized);
60
+ const route = inferCapabilityRoute(normalized);
61
+ const limit = Math.min(MAX_COMMAND_SEARCH_LIMIT, Math.max(1, Math.floor(requestedLimit)));
62
+ const matches = tokens.length === 0
63
+ ? []
64
+ : manifest.commands
65
+ .map((command) => ({ command, score: scoreCommand(command, tokens, route) }))
66
+ .filter((entry) => entry.score > 0)
67
+ .sort((a, b) => b.score - a.score || a.command.name.localeCompare(b.command.name));
68
+ return {
69
+ query: normalized,
70
+ total_matches: matches.length,
71
+ returned: Math.min(limit, matches.length),
72
+ route: serializeCapabilityRoute(route),
73
+ commands: matches.slice(0, limit).map(({ command, score }) => ({
74
+ name: command.name,
75
+ group: command.group,
76
+ description: command.description,
77
+ spends_credits: command.spends_credits,
78
+ mutates: command.mutates,
79
+ json_supported: command.json_supported,
80
+ hidden: command.hidden,
81
+ score,
82
+ })),
83
+ hydrate: `${manifest.binary} commands get <exact-command> --json`,
84
+ };
85
+ }
86
+ /** Exact second hop after search; avoids serializing the full command grammar. */
87
+ export function getCommandManifestEntry(manifest, exactName) {
88
+ const normalized = exactName.trim().replace(/\s+/g, " ");
89
+ const command = manifest.commands.find((entry) => entry.name === normalized);
90
+ return command ? { ...command, invoke: `${manifest.binary} ${command.name}` } : null;
91
+ }
92
+ export function suggestCommandNames(manifest, query, limit = 3) {
93
+ const tokens = tokenizeCommandQuery(query);
94
+ return manifest.commands
95
+ .map((command) => ({ command, score: scoreCommand(command, tokens, null) }))
96
+ .filter((entry) => entry.score > 0)
97
+ .sort((a, b) => b.score - a.score || a.command.name.localeCompare(b.command.name))
98
+ .slice(0, Math.max(1, limit))
99
+ .map((entry) => entry.command.name);
100
+ }
101
+ function tokenizeCommandQuery(query) {
102
+ return query
103
+ .toLowerCase()
104
+ .split(/[^a-z0-9]+/)
105
+ .filter((token) => token.length > 0 && !COMMAND_SEARCH_STOP_WORDS.has(token));
106
+ }
107
+ function scoreCommand(command, tokens, route) {
108
+ const name = command.name.toLowerCase();
109
+ const description = command.description.toLowerCase();
110
+ const searchableDetails = [
111
+ ...command.arguments.map((argument) => `${argument.name} ${argument.description}`),
112
+ ...command.flags.map((flag) => `${flag.flags} ${flag.description}`),
113
+ ].join(" ").toLowerCase();
114
+ let score = 0;
115
+ let matched = 0;
116
+ for (const token of tokens) {
117
+ let tokenMatched = false;
118
+ if (name.includes(token)) {
119
+ score += 8;
120
+ tokenMatched = true;
121
+ }
122
+ if (description.includes(token)) {
123
+ score += 3;
124
+ tokenMatched = true;
125
+ }
126
+ if (searchableDetails.includes(token)) {
127
+ score += 1;
128
+ tokenMatched = true;
129
+ }
130
+ if (tokenMatched)
131
+ matched += 1;
132
+ }
133
+ const routeIndex = route?.recommendedCommands.findIndex((recommended) => name === recommended || name.startsWith(`${recommended} `)) ?? -1;
134
+ const routeGroups = new Set([
135
+ ...(route?.card.endpointSections ?? []),
136
+ ...(route?.card.gatewayCommands ?? []).map((recommended) => recommended.split(" ")[0] ?? ""),
137
+ ...(route?.recommendedCommands ?? []).map((recommended) => recommended.split(" ")[0] ?? ""),
138
+ ]);
139
+ if (route && routeIndex < 0 && !routeGroups.has(command.group))
140
+ return 0;
141
+ if (routeIndex < 0 && matched < Math.ceil(tokens.length / 2))
142
+ return 0;
143
+ if (tokens.length > 0 && matched > 0)
144
+ score += Math.round((matched / tokens.length) * 20);
145
+ if (routeIndex >= 0)
146
+ score += 500 - (routeIndex * 25);
147
+ return score;
148
+ }
50
149
  function collectCommand(command, ancestors, out) {
51
150
  const path = [...ancestors, command.name()];
52
151
  const children = command.commands;
53
- // Group commands (e.g. `oxygen tables`) exist to hold subcommands; only leaf
54
- // commands are invocable work, so only leaves become manifest entries.
55
- if (children.length === 0) {
152
+ // Most group commands only hold children. A small number (notably the
153
+ // backwards-compatible `commands` index) also have their own action, so
154
+ // preserve them as invocable entries while still walking their children.
155
+ const hasAction = Boolean(command._actionHandler);
156
+ if (children.length === 0 || hasAction) {
56
157
  out.push(toManifestEntry(command, path));
57
- return;
58
158
  }
59
159
  for (const child of children) {
60
160
  collectCommand(child, path, out);
@@ -92,6 +192,7 @@ function toManifestEntry(command, path) {
92
192
  (path[0] === "copilot" &&
93
193
  (leafVerb === "send" || leafVerb === "approve")),
94
194
  mutates: MUTATING_VERBS.has(leafVerb) || MUTATING_VERBS.has(verbPrefix),
195
+ preview_by_default: flagStrings.some((flags) => flags.includes("--live")),
95
196
  json_supported: flagStrings.some((flags) => flags.includes("--json")),
96
197
  hidden: isHiddenCommand(command),
97
198
  };
package/dist/help.js CHANGED
@@ -136,7 +136,8 @@ export function applyOxygenHelp(program, binaryName) {
136
136
  // OXYGEN_API_KEY never runs it — without this step nothing on any
137
137
  // first-touch surface names the skill that teaches the GTM loops.
138
138
  ` 2. ${binaryName} skills install --json load the skills that teach the GTM loops (automatic after login)`,
139
- ` 3. ${binaryName} commands --json full machine-readable command grammar (this CLI's self-index)`,
139
+ ` 3. ${binaryName} context resolve --json load workspace context before operating primitives`,
140
+ ` 4. ${binaryName} capabilities search "<goal>" --json route the goal, then hydrate one exact command`,
140
141
  ` Recurring monitors: use a shareable Blueprint; start with ${binaryName} blueprints list --json.`,
141
142
  "",
142
143
  "Conventions:",