@oxygen-agent/cli 1.936.1 → 1.982.3
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.js +9 -1
- package/dist/cli-values.d.ts +14 -0
- package/dist/cli-values.js +26 -0
- package/dist/command-manifest.js +30 -2
- package/dist/functions-commands.js +13 -5
- package/dist/help.js +2 -0
- package/dist/index.js +1509 -290
- package/dist/knowledge-repository-commands.d.ts +6 -0
- package/dist/knowledge-repository-commands.js +198 -0
- package/dist/skills.js +20 -0
- package/dist/ugc-commands.js +470 -15
- package/node_modules/@oxygen/recipe-sdk/dist/index.d.ts +2 -0
- package/node_modules/@oxygen/shared/dist/byok-connect.d.ts +11 -6
- package/node_modules/@oxygen/shared/dist/byok-connect.js +14 -6
- package/node_modules/@oxygen/shared/dist/capability-discovery.d.ts +8 -0
- package/node_modules/@oxygen/shared/dist/capability-discovery.js +152 -20
- package/node_modules/@oxygen/shared/dist/copilot-errors.js +3 -0
- package/node_modules/@oxygen/shared/dist/copilot-journeys.d.ts +19 -1
- package/node_modules/@oxygen/shared/dist/copilot-journeys.generated.d.ts +19 -0
- package/node_modules/@oxygen/shared/dist/copilot-journeys.generated.js +26 -0
- package/node_modules/@oxygen/shared/dist/copilot-journeys.js +8 -41
- package/node_modules/@oxygen/shared/dist/email-dsn.d.ts +60 -0
- package/node_modules/@oxygen/shared/dist/email-dsn.js +120 -0
- package/node_modules/@oxygen/shared/dist/email-warmup-readiness.d.ts +64 -0
- package/node_modules/@oxygen/shared/dist/email-warmup-readiness.js +90 -0
- package/node_modules/@oxygen/shared/dist/inbox-avatar-url.d.ts +28 -0
- package/node_modules/@oxygen/shared/dist/inbox-avatar-url.js +57 -0
- package/node_modules/@oxygen/shared/dist/index.d.ts +10 -0
- package/node_modules/@oxygen/shared/dist/index.js +10 -0
- package/node_modules/@oxygen/shared/dist/knowledge-bases.d.ts +74 -0
- package/node_modules/@oxygen/shared/dist/knowledge-bases.js +456 -0
- package/node_modules/@oxygen/shared/dist/knowledge-bootstrap.d.ts +56 -48
- package/node_modules/@oxygen/shared/dist/knowledge-bootstrap.js +50 -49
- package/node_modules/@oxygen/shared/dist/knowledge-repository.d.ts +22 -0
- package/node_modules/@oxygen/shared/dist/knowledge-repository.js +121 -0
- package/node_modules/@oxygen/shared/dist/knowledge-vault-markdown.d.ts +20 -0
- package/node_modules/@oxygen/shared/dist/knowledge-vault-markdown.js +155 -0
- package/node_modules/@oxygen/shared/dist/langfuse.d.ts +8 -3
- package/node_modules/@oxygen/shared/dist/langfuse.js +177 -130
- package/node_modules/@oxygen/shared/dist/llm-payload.d.ts +10 -0
- package/node_modules/@oxygen/shared/dist/llm-payload.js +54 -0
- package/node_modules/@oxygen/shared/dist/llm-usage.d.ts +11 -0
- package/node_modules/@oxygen/shared/dist/llm-usage.js +30 -0
- package/node_modules/@oxygen/shared/dist/mailbox-import.d.ts +10 -0
- package/node_modules/@oxygen/shared/dist/mailbox-import.js +53 -0
- package/node_modules/@oxygen/shared/dist/plan-limits.d.ts +8 -0
- package/node_modules/@oxygen/shared/dist/plan-limits.js +8 -0
- package/node_modules/@oxygen/shared/dist/pricing-sheet.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/pricing-sheet.js +1 -1
- package/node_modules/@oxygen/shared/dist/product-analytics-core.d.ts +98 -0
- package/node_modules/@oxygen/shared/dist/product-analytics-core.js +159 -0
- package/node_modules/@oxygen/shared/dist/product-analytics-environment.d.ts +18 -0
- package/node_modules/@oxygen/shared/dist/product-analytics-environment.js +46 -0
- package/node_modules/@oxygen/shared/dist/product-analytics-events.d.ts +116 -0
- package/node_modules/@oxygen/shared/dist/product-analytics-events.js +120 -0
- package/node_modules/@oxygen/shared/dist/recipes.d.ts +6 -0
- package/node_modules/@oxygen/shared/dist/recipes.js +23 -0
- package/node_modules/@oxygen/shared/dist/sequences.d.ts +126 -2
- package/node_modules/@oxygen/shared/dist/sequences.js +280 -4
- package/node_modules/@oxygen/shared/dist/ugc-amplification-identity.d.ts +2 -0
- package/node_modules/@oxygen/shared/dist/ugc-amplification-identity.js +24 -0
- package/node_modules/@oxygen/shared/dist/ugc.d.ts +29 -1
- package/node_modules/@oxygen/shared/dist/user-capability-routing.js +8 -1
- package/node_modules/@oxygen/shared/dist/version.d.ts +1 -1
- package/node_modules/@oxygen/shared/dist/version.js +3 -1
- package/node_modules/@oxygen/shared/dist/workspace-file-storage.d.ts +6 -2
- package/node_modules/@oxygen/shared/dist/workspace-file-storage.js +15 -4
- package/node_modules/@oxygen/shared/package.json +15 -0
- package/node_modules/@oxygen/workflows/dist/graph/lint.js +22 -0
- package/package.json +2 -1
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
type Handle = (command: string, options: {
|
|
3
|
+
json?: boolean;
|
|
4
|
+
}, action: () => Promise<unknown>) => Promise<void>;
|
|
5
|
+
export declare function registerKnowledgeRepositoryCommands(program: Command, handle: Handle): void;
|
|
6
|
+
export {};
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { readFile, writeFile, stat } from "node:fs/promises";
|
|
2
|
+
import { createHash } from "node:crypto";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import { requestOxygen } from "./http-client.js";
|
|
5
|
+
const post = (path, body) => {
|
|
6
|
+
if (Buffer.byteLength(JSON.stringify(body)) > 2_000_000)
|
|
7
|
+
throw new Error("This inline request exceeds 2 MB. Add larger attachments through the connected GitHub repository.");
|
|
8
|
+
return requestOxygen(`/api/cli/knowledge/${path}`, { method: "POST", body });
|
|
9
|
+
};
|
|
10
|
+
export function registerKnowledgeRepositoryCommands(program, handle) {
|
|
11
|
+
const knowledge = program.commands.find((c) => c.name() === "knowledge");
|
|
12
|
+
if (!knowledge)
|
|
13
|
+
throw new Error("Knowledge commands must be registered first.");
|
|
14
|
+
const repos = knowledge
|
|
15
|
+
.command("repositories")
|
|
16
|
+
.description("Import an existing GitHub or Obsidian repository into Knowledge, or keep it automatically in sync. Start with integrations connect github; web setup: /knowledge/repositories; docs: /docs/knowledge/knowledge-graph.");
|
|
17
|
+
repos
|
|
18
|
+
.command("list")
|
|
19
|
+
.description("Read connected repositories, import progress, sync freshness, pending changes, and errors. 0 credits.")
|
|
20
|
+
.option("--json", "Print a JSON envelope.")
|
|
21
|
+
.action((o) => handle("knowledge repositories list", o, () => post("repositories/list", {})));
|
|
22
|
+
for (const operation of ["preview", "connect"]) {
|
|
23
|
+
const cmd = repos
|
|
24
|
+
.command(operation)
|
|
25
|
+
.description(operation === "preview"
|
|
26
|
+
? "Preview branch/folder contents, exclusions and the future sync policy. Does not activate sync. 0 credits."
|
|
27
|
+
: "Approve the exact preview and start importing. two_way authorizes future automatic GitHub writes to the selected branch. 0 Oxygen credits.")
|
|
28
|
+
.requiredOption("--connection-id <id>", "GitHub connection ID from integrations list.")
|
|
29
|
+
.requiredOption("--repository-id <id>", "Repository ID from integrations github repositories.")
|
|
30
|
+
.requiredOption("--branch <name>", "Connected branch; unmerged feature branches are separate.")
|
|
31
|
+
.option("--root-path <path>", "Repository subfolder; omit for the entire repository.", "")
|
|
32
|
+
.option("--mode <mode>", "two_way or import (one-time copy).", "two_way")
|
|
33
|
+
.option("--json", "Print a JSON envelope.");
|
|
34
|
+
if (operation === "connect")
|
|
35
|
+
cmd
|
|
36
|
+
.requiredOption("--preview-token <token>", "Exact token returned by repositories preview.")
|
|
37
|
+
.option("--approved", "Approve the displayed import and future sync policy.");
|
|
38
|
+
cmd.action((o) => handle(`knowledge repositories ${operation}`, o, () => post(`repositories/${operation}`, {
|
|
39
|
+
connectionId: o.connectionId,
|
|
40
|
+
repositoryId: Number(o.repositoryId),
|
|
41
|
+
branch: o.branch,
|
|
42
|
+
rootPath: o.rootPath,
|
|
43
|
+
mode: o.mode,
|
|
44
|
+
...(operation === "connect"
|
|
45
|
+
? { previewToken: o.previewToken, approved: o.approved === true }
|
|
46
|
+
: {}),
|
|
47
|
+
})));
|
|
48
|
+
}
|
|
49
|
+
for (const action of ["sync", "pause", "resume", "disconnect"]) {
|
|
50
|
+
const description = {
|
|
51
|
+
sync: "Request an immediate sync attempt. Saved changes remain safe if GitHub is unavailable.",
|
|
52
|
+
pause: "Pause automatic sync; keep all imported files and history.",
|
|
53
|
+
resume: "Resume the previously approved sync policy.",
|
|
54
|
+
disconnect: "Disconnect this repository; keep its files and history in Knowledge.",
|
|
55
|
+
}[action];
|
|
56
|
+
repos
|
|
57
|
+
.command(action)
|
|
58
|
+
.description(description)
|
|
59
|
+
.requiredOption("--id <id>", "Connected repository mount ID.")
|
|
60
|
+
.option("--json", "Print a JSON envelope.")
|
|
61
|
+
.action((o) => handle(`knowledge repositories ${action}`, o, () => post("repositories/action", { id: o.id, action })));
|
|
62
|
+
}
|
|
63
|
+
repos
|
|
64
|
+
.command("conflicts")
|
|
65
|
+
.description("Read conflicts; add --path to inspect preserved base, Oxygen, and GitHub versions.")
|
|
66
|
+
.requiredOption("--mount-id <id>", "Connected repository mount ID.")
|
|
67
|
+
.option("--path <path>", "Exact file path.")
|
|
68
|
+
.option("--json", "Print a JSON envelope.")
|
|
69
|
+
.action((o) => handle("knowledge repositories conflicts", o, () => post("repositories/conflicts", {
|
|
70
|
+
mountId: o.mountId,
|
|
71
|
+
...(o.path ? { path: o.path } : {}),
|
|
72
|
+
})));
|
|
73
|
+
repos
|
|
74
|
+
.command("resolve")
|
|
75
|
+
.description("Apply a reviewed conflict decision. Canonical copy remains proposal-gated; GitHub publishes under the saved sync policy.")
|
|
76
|
+
.requiredOption("--mount-id <id>", "Connected repository mount ID.")
|
|
77
|
+
.requiredOption("--path <path>", "Exact file path.")
|
|
78
|
+
.requiredOption("--local-revision <revision|null>", "Reviewed Oxygen revision or null.")
|
|
79
|
+
.requiredOption("--remote-sha <sha|null>", "Reviewed GitHub blob SHA or null.")
|
|
80
|
+
.requiredOption("--decision <choice>", "oxygen, github, or merged.")
|
|
81
|
+
.option("--file <path>", "Complete edited UTF-8 file for merged.")
|
|
82
|
+
.option("--approved", "Approve this exact decision.")
|
|
83
|
+
.option("--json", "Print a JSON envelope.")
|
|
84
|
+
.action((o) => handle("knowledge repositories resolve", o, async () => post("repositories/resolve", {
|
|
85
|
+
mountId: o.mountId,
|
|
86
|
+
path: o.path,
|
|
87
|
+
expectedLocalRevision: o.localRevision === "null" ? null : Number(o.localRevision),
|
|
88
|
+
expectedRemoteSha: o.remoteSha === "null" ? null : o.remoteSha,
|
|
89
|
+
decision: o.decision,
|
|
90
|
+
...(o.file ? { text: await readFile(String(o.file), "utf8") } : {}),
|
|
91
|
+
approved: o.approved === true,
|
|
92
|
+
})));
|
|
93
|
+
const files = knowledge
|
|
94
|
+
.command("files")
|
|
95
|
+
.description("Original repository paths and immutable file revisions, including attachments.");
|
|
96
|
+
files
|
|
97
|
+
.command("list")
|
|
98
|
+
.requiredOption("--mount-id <id>", "Connected repository ID.")
|
|
99
|
+
.option("--cursor <cursor>", "Continue the previous page.")
|
|
100
|
+
.option("--limit <number>", "Maximum files, up to 500.", "100")
|
|
101
|
+
.option("--json", "Print a JSON envelope.")
|
|
102
|
+
.action((o) => handle("knowledge files list", o, () => post("files/list", {
|
|
103
|
+
mountId: o.mountId,
|
|
104
|
+
limit: Number(o.limit),
|
|
105
|
+
...(o.cursor ? { cursor: o.cursor } : {}),
|
|
106
|
+
})));
|
|
107
|
+
files
|
|
108
|
+
.command("get")
|
|
109
|
+
.description("Read original file content, properties and download link at an optional immutable revision.")
|
|
110
|
+
.requiredOption("--id <id>", "File ID from files list.")
|
|
111
|
+
.option("--revision <number>", "Specific saved file revision.")
|
|
112
|
+
.option("--json", "Print a JSON envelope.")
|
|
113
|
+
.action((o) => handle("knowledge files get", o, () => post("files/get", {
|
|
114
|
+
id: o.id,
|
|
115
|
+
...(o.revision ? { revision: Number(o.revision) } : {}),
|
|
116
|
+
})));
|
|
117
|
+
files
|
|
118
|
+
.command("upsert")
|
|
119
|
+
.description("Create or replace an original file, or update frontmatter properties. Canonical copy still requires a proposal.")
|
|
120
|
+
.requiredOption("--mount-id <id>", "Connected repository ID.")
|
|
121
|
+
.option("--id <id>", "Existing file ID.")
|
|
122
|
+
.option("--path <path>", "Exact repository-relative path; required for new files.")
|
|
123
|
+
.requiredOption("--expected-revision <number>", "Reviewed file revision; 0 creates a new file.")
|
|
124
|
+
.option("--file <path>", "Complete local file, including any frontmatter or binary bytes.")
|
|
125
|
+
.option("--properties-json <json>", "Frontmatter properties to change; mutually exclusive with --file.")
|
|
126
|
+
.option("--json", "Print a JSON envelope.")
|
|
127
|
+
.action((o) => handle("knowledge files upsert", o, async () => {
|
|
128
|
+
if (Boolean(o.file) === Boolean(o.propertiesJson))
|
|
129
|
+
throw new Error("Provide exactly one of --file or --properties-json.");
|
|
130
|
+
if (o.file && (await stat(String(o.file))).size > 1_500_000)
|
|
131
|
+
throw new Error("Inline file uploads must fit a 2 MB JSON request (including base64). Add larger attachments through the connected GitHub repository.");
|
|
132
|
+
const patch = o.propertiesJson
|
|
133
|
+
? JSON.parse(String(o.propertiesJson))
|
|
134
|
+
: undefined;
|
|
135
|
+
if (patch !== undefined &&
|
|
136
|
+
(!patch || typeof patch !== "object" || Array.isArray(patch)))
|
|
137
|
+
throw new Error("--properties-json must contain an object.");
|
|
138
|
+
return post("files/upsert", {
|
|
139
|
+
mountId: o.mountId,
|
|
140
|
+
...(o.id ? { id: o.id } : {}),
|
|
141
|
+
...(o.path ? { path: o.path } : {}),
|
|
142
|
+
expectedFileRevision: Number(o.expectedRevision),
|
|
143
|
+
...(o.file
|
|
144
|
+
? {
|
|
145
|
+
bytesBase64: (await readFile(String(o.file))).toString("base64"),
|
|
146
|
+
}
|
|
147
|
+
: { propertyPatch: patch }),
|
|
148
|
+
});
|
|
149
|
+
}));
|
|
150
|
+
files
|
|
151
|
+
.command("archive")
|
|
152
|
+
.description("Archive a file with revision checking. A connected two-way repository publishes the deletion; history remains.")
|
|
153
|
+
.requiredOption("--id <id>", "File ID.")
|
|
154
|
+
.requiredOption("--expected-revision <number>", "Reviewed file revision.")
|
|
155
|
+
.option("--json", "Print a JSON envelope.")
|
|
156
|
+
.action((o) => handle("knowledge files archive", o, () => post("files/archive", {
|
|
157
|
+
id: o.id,
|
|
158
|
+
expectedFileRevision: Number(o.expectedRevision),
|
|
159
|
+
})));
|
|
160
|
+
files
|
|
161
|
+
.command("download")
|
|
162
|
+
.description("Download exact original bytes with digest verification; refuses to overwrite an existing local file.")
|
|
163
|
+
.requiredOption("--id <id>", "File ID.")
|
|
164
|
+
.requiredOption("--out <path>", "New local destination filename.")
|
|
165
|
+
.option("--revision <number>", "Specific immutable revision.")
|
|
166
|
+
.option("--json", "Print a JSON envelope.")
|
|
167
|
+
.action((o) => handle("knowledge files download", o, async () => {
|
|
168
|
+
const query = new URLSearchParams({
|
|
169
|
+
id: String(o.id),
|
|
170
|
+
...(o.revision ? { revision: String(o.revision) } : {}),
|
|
171
|
+
});
|
|
172
|
+
const data = await requestOxygen(`/api/cli/knowledge/files/get?${query}`);
|
|
173
|
+
const bytes = await requestOxygen(`/api/cli/knowledge/files/download?${query}`, { binaryMaxBytes: Math.max(1, data.file.sizeBytes) });
|
|
174
|
+
if (bytes.length !== data.file.sizeBytes ||
|
|
175
|
+
createHash("sha256").update(bytes).digest("hex") !== data.file.sha256)
|
|
176
|
+
throw new Error("Downloaded bytes do not match the saved file revision.");
|
|
177
|
+
await writeFile(String(o.out), bytes, { flag: "wx", mode: 0o600 });
|
|
178
|
+
return { path: resolve(String(o.out)), ...data.file };
|
|
179
|
+
}));
|
|
180
|
+
const integrations = program.commands.find((c) => c.name() === "integrations");
|
|
181
|
+
if (integrations) {
|
|
182
|
+
const github = integrations
|
|
183
|
+
.command("github")
|
|
184
|
+
.description("Choose repositories authorized through the GitHub App. Connect first with integrations connect github. The Oxygen GitHub App requests Contents read and write plus Metadata read on the repositories you select, and push events; it requests no account or organization permissions. integrations list reports GitHub availability for this deployment.");
|
|
185
|
+
github
|
|
186
|
+
.command("repositories")
|
|
187
|
+
.requiredOption("--connection-id <id>", "GitHub connection ID.")
|
|
188
|
+
.option("--json", "Print a JSON envelope.")
|
|
189
|
+
.action((o) => handle("integrations github repositories", o, () => requestOxygen(`/api/cli/integrations/github/repositories?connection_id=${encodeURIComponent(String(o.connectionId))}`)));
|
|
190
|
+
github
|
|
191
|
+
.command("branches")
|
|
192
|
+
.requiredOption("--connection-id <id>", "GitHub connection ID.")
|
|
193
|
+
.requiredOption("--repository-id <id>", "Immutable GitHub repository ID.")
|
|
194
|
+
.option("--page <number>", "Page to read.", "1")
|
|
195
|
+
.option("--json", "Print a JSON envelope.")
|
|
196
|
+
.action((o) => handle("integrations github branches", o, () => requestOxygen(`/api/cli/integrations/github/branches?${new URLSearchParams({ connection_id: String(o.connectionId), repository_id: String(o.repositoryId), page: String(o.page) })}`)));
|
|
197
|
+
}
|
|
198
|
+
}
|
package/dist/skills.js
CHANGED
|
@@ -66,6 +66,17 @@ export async function resolveSkillsInstallSource(options) {
|
|
|
66
66
|
return publicSource(`access_unavailable:${code}`);
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
|
+
function requireSkillContentAccess(index, source) {
|
|
70
|
+
if (!index.authentication_required)
|
|
71
|
+
return;
|
|
72
|
+
throw new OxygenError("skills_authentication_required", "Sign in to download Oxygen agent instructions.", {
|
|
73
|
+
details: {
|
|
74
|
+
next_step: "Run `oxygen login`, then retry `oxygen skills install` or `oxygen skills get`.",
|
|
75
|
+
...(source.fallback_reason ? { access_fallback: source.fallback_reason } : {}),
|
|
76
|
+
},
|
|
77
|
+
exitCode: 1,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
69
80
|
export async function listAgentSkills(options, runtime = {}) {
|
|
70
81
|
const apiUrl = normalizeApiUrl(readOption(options.apiUrl) ?? defaultApiUrl());
|
|
71
82
|
const source = await resolveSkillsInstallSource({ apiUrl, ...runtime });
|
|
@@ -137,6 +148,7 @@ export async function getAgentSkill(skillName, options, runtime = {}) {
|
|
|
137
148
|
exitCode: 1,
|
|
138
149
|
});
|
|
139
150
|
}
|
|
151
|
+
requireSkillContentAccess(index, source);
|
|
140
152
|
const normalized = skillName.trim();
|
|
141
153
|
const skill = index.skills.find((entry) => entry.name === normalized);
|
|
142
154
|
if (!skill) {
|
|
@@ -203,6 +215,12 @@ options, runtime = {}) {
|
|
|
203
215
|
...(runtime.credentials !== undefined ? { credentials: runtime.credentials } : {}),
|
|
204
216
|
...(runtime.fetch ? { fetch: runtime.fetch } : {}),
|
|
205
217
|
});
|
|
218
|
+
if (!source.authenticated) {
|
|
219
|
+
// Public discovery remains usable. New servers explicitly mark that their
|
|
220
|
+
// instruction bodies require a signed workspace link; never invoke the
|
|
221
|
+
// installer against that discovery-only catalog.
|
|
222
|
+
requireSkillContentAccess(await inspectSkillIndex(source.index_url, runtime.fetch), source);
|
|
223
|
+
}
|
|
206
224
|
const agents = readWords(options.agents ?? DEFAULT_SKILL_AGENTS);
|
|
207
225
|
const skill = readOption(options.skill) ?? "*";
|
|
208
226
|
const env = runtime.env ?? process.env;
|
|
@@ -599,6 +617,7 @@ async function inspectSkillIndex(indexUrl, fetchImpl = fetch) {
|
|
|
599
617
|
}
|
|
600
618
|
return {
|
|
601
619
|
reachable: true,
|
|
620
|
+
authentication_required: index.authentication_required === true,
|
|
602
621
|
status: response.status,
|
|
603
622
|
version: index.version,
|
|
604
623
|
base_url: index.base_url,
|
|
@@ -667,6 +686,7 @@ function parseSkillIndex(value) {
|
|
|
667
686
|
})
|
|
668
687
|
.filter((entry) => entry !== null);
|
|
669
688
|
return {
|
|
689
|
+
authentication_required: value.authentication_required === true,
|
|
670
690
|
version: typeof value.version === "string" ? value.version : null,
|
|
671
691
|
base_url: typeof value.base_url === "string" ? value.base_url : null,
|
|
672
692
|
skills,
|