@agentsky/sky 2.24.1 → 2.26.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.
- package/dist/{chunk-KWLEADJQ.js → chunk-K3LB4K2C.js} +6 -2
- package/dist/{chunk-S4YG3TXA.js → chunk-UZ7KWRQH.js} +1 -1
- package/dist/index.js +364 -105
- package/dist/{src-BMXKAMOB.js → src-OBSBFTDB.js} +1 -1
- package/dist/{trace-WLTD4C22.js → trace-OPRHOP2E.js} +2 -2
- package/dist/{trace-library-YMAVLH4Y.js → trace-library-SB7QYAU5.js} +3 -3
- package/package.json +1 -1
- /package/dist/{chunk-D3WG4BMK.js → chunk-CJBZVPDF.js} +0 -0
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
apiBase,
|
|
4
4
|
apiToken,
|
|
5
5
|
currentUniverse
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-UZ7KWRQH.js";
|
|
7
7
|
|
|
8
8
|
// src/api.ts
|
|
9
9
|
import { createWriteStream, writeFileSync } from "fs";
|
|
@@ -97,6 +97,9 @@ async function downloadFileTo(fileId, outPath) {
|
|
|
97
97
|
headers: { "user-agent": USER_AGENT, ...authHeaders() }
|
|
98
98
|
});
|
|
99
99
|
if (!res.ok) await parseError(res);
|
|
100
|
+
return writeResponseFile(res, outPath);
|
|
101
|
+
}
|
|
102
|
+
async function writeResponseFile(res, outPath) {
|
|
100
103
|
if (!res.body) {
|
|
101
104
|
writeFileSync(outPath, new Uint8Array(0));
|
|
102
105
|
return 0;
|
|
@@ -145,7 +148,7 @@ async function resolveSessionRef(ref) {
|
|
|
145
148
|
return agent.defaultSessionId;
|
|
146
149
|
}
|
|
147
150
|
async function* streamEvents(sessionId, signal) {
|
|
148
|
-
const { parseSseStream } = await import("./src-
|
|
151
|
+
const { parseSseStream } = await import("./src-OBSBFTDB.js");
|
|
149
152
|
const res = await fetch(
|
|
150
153
|
`${apiBase()}/sessions/${encodeURIComponent(sessionId)}/stream`,
|
|
151
154
|
{
|
|
@@ -189,6 +192,7 @@ export {
|
|
|
189
192
|
uploadFile,
|
|
190
193
|
apiForm,
|
|
191
194
|
downloadFileTo,
|
|
195
|
+
writeResponseFile,
|
|
192
196
|
apiBytes,
|
|
193
197
|
resolveSessionRef,
|
|
194
198
|
streamEvents,
|
package/dist/index.js
CHANGED
|
@@ -9,8 +9,9 @@ import {
|
|
|
9
9
|
postEvents,
|
|
10
10
|
resolveSessionRef,
|
|
11
11
|
streamEvents,
|
|
12
|
-
uploadFile
|
|
13
|
-
|
|
12
|
+
uploadFile,
|
|
13
|
+
writeResponseFile
|
|
14
|
+
} from "./chunk-K3LB4K2C.js";
|
|
14
15
|
import {
|
|
15
16
|
CLI_VERSION,
|
|
16
17
|
USER_AGENT,
|
|
@@ -21,7 +22,7 @@ import {
|
|
|
21
22
|
currentUniverse,
|
|
22
23
|
loadConfig,
|
|
23
24
|
saveConfig
|
|
24
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-UZ7KWRQH.js";
|
|
25
26
|
import {
|
|
26
27
|
AGENT_TYPES,
|
|
27
28
|
MODEL_SUBSCRIPTION_PLAN_PHRASE,
|
|
@@ -43,11 +44,11 @@ import {
|
|
|
43
44
|
skillRefSchema,
|
|
44
45
|
splitMcpServers,
|
|
45
46
|
supersededBy
|
|
46
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-CJBZVPDF.js";
|
|
47
48
|
import "./chunk-MLKGABMK.js";
|
|
48
49
|
|
|
49
50
|
// src/index.ts
|
|
50
|
-
import { existsSync as existsSync13, readFileSync as
|
|
51
|
+
import { existsSync as existsSync13, readFileSync as readFileSync20, writeFileSync as writeFileSync10 } from "fs";
|
|
51
52
|
import { basename as basename9, resolve as resolve9 } from "path";
|
|
52
53
|
import { createInterface as createInterface6 } from "readline";
|
|
53
54
|
import { Command } from "commander";
|
|
@@ -2643,6 +2644,42 @@ it, and name its path in the brief.
|
|
|
2643
2644
|
6. Tell the person what was done, which agent did which part, and what it cost
|
|
2644
2645
|
(\`get_task\` reports the task's cost).
|
|
2645
2646
|
|
|
2647
|
+
## Share an existing Library document
|
|
2648
|
+
|
|
2649
|
+
Use \`read_library_file_links\` with the document's exact \`ref\` to read its
|
|
2650
|
+
current revision, supported access and real available members. The reference
|
|
2651
|
+
can name a Drive file (including an uploaded meeting note), task file, memory
|
|
2652
|
+
note, skill file, agent user instructions (\`{kind:"agent_prompt",agentId}\`), saved artifact or platform artifact. Only the user-authored AGENTS.md is shared; system instructions and credentials are never included. \`workspace\` names the
|
|
2653
|
+
audience workspace, never a storage move or the connection's default.
|
|
2654
|
+
For a DesignSystem file, use \`platform_artifact\` with the exact full native
|
|
2655
|
+
manifest \`path\`: its actual \`root\` plus an \`editable_files\` path, or the
|
|
2656
|
+
native document reader's \`libraryRef\`. Do not guess a folder prefix or use
|
|
2657
|
+
an editor's relative transport path. Omitting \`path\` shares the entire
|
|
2658
|
+
artifact entry. A token reads only its original file; it cannot select a
|
|
2659
|
+
sibling with a query parameter. Editable DesignSystem files save through
|
|
2660
|
+
that system's versioned writer, including derived files and republishing.
|
|
2661
|
+
\`share_library_file\` changes only the requested workspace/member grants;
|
|
2662
|
+
\`publish_library_file\` enables or disables a public view-only link while
|
|
2663
|
+
preserving other grants. Both read first and merge against the current
|
|
2664
|
+
revision. \`revoke_library_file_links\` needs the explicit revision you reviewed.
|
|
2665
|
+
A conflict is an error: read the current state before intentionally retrying.
|
|
2666
|
+
These tools send no messages and start no sessions. CLI equivalents are
|
|
2667
|
+
\`sky library links show\`, \`share\`, \`publish\` and \`revoke\`; their help
|
|
2668
|
+
shows every reference shape. Existing artifact links and version pins keep
|
|
2669
|
+
using their existing controls and \`share_artifact\`.
|
|
2670
|
+
|
|
2671
|
+
When you receive a Library shared/public URL, \`read_shared_library_file\`
|
|
2672
|
+
accepts the 43-character token at its end; \`public: true\` chooses the public
|
|
2673
|
+
view-only reader. A recipient with a live edit grant can use
|
|
2674
|
+
\`save_shared_library_file\` with the opaque source revision from that read
|
|
2675
|
+
and exactly one native text/HTML/Office/restore field. Public links have no
|
|
2676
|
+
writer. The CLI equivalents are \`sky library links read --token \u2026\`
|
|
2677
|
+
(\`--output\` streams original bytes) and \`sky library links save --token \u2026
|
|
2678
|
+
--revision \u2026 --file \u2026\`; \`--data\` accepts the other native save fields.
|
|
2679
|
+
A 403 is not a saved result; a 409 requires reading current state before an
|
|
2680
|
+
intentional retry. This source revision is distinct from the integer revision
|
|
2681
|
+
of the sharing settings.
|
|
2682
|
+
|
|
2646
2683
|
## Build an agent that the person's own application runs
|
|
2647
2684
|
|
|
2648
2685
|
When the person wants an agent their product starts for its customers, built
|
|
@@ -5261,6 +5298,83 @@ function renderThreadSummary(t) {
|
|
|
5261
5298
|
return `${t.id.slice(0, 12)} ${flag}${t.title.slice(0, 40).padEnd(44)} [${agents}] ${status}`;
|
|
5262
5299
|
}
|
|
5263
5300
|
|
|
5301
|
+
// src/library.ts
|
|
5302
|
+
import { readFileSync as readFileSync17 } from "fs";
|
|
5303
|
+
|
|
5304
|
+
// src/api-command.ts
|
|
5305
|
+
import { readFileSync as readFileSync16 } from "fs";
|
|
5306
|
+
var API_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
5307
|
+
function readData(data, stdin = () => readFileSync16(0, "utf8")) {
|
|
5308
|
+
if (data === void 0) return void 0;
|
|
5309
|
+
const raw = data === "-" ? stdin() : data.startsWith("@") ? readFileSync16(data.slice(1), "utf8") : data;
|
|
5310
|
+
try {
|
|
5311
|
+
JSON.parse(raw);
|
|
5312
|
+
} catch {
|
|
5313
|
+
throw new Error("--data must be JSON (inline, @file or - for stdin)");
|
|
5314
|
+
}
|
|
5315
|
+
return raw;
|
|
5316
|
+
}
|
|
5317
|
+
function requestPath(path, query = []) {
|
|
5318
|
+
if (!path.startsWith("/") || path.startsWith("//")) throw new Error("path must start with /, e.g. /threads");
|
|
5319
|
+
const clean = path.replace(/^\/v1(?=\/)/, "");
|
|
5320
|
+
const params = new URLSearchParams();
|
|
5321
|
+
for (const pair of query) {
|
|
5322
|
+
const at = pair.indexOf("=");
|
|
5323
|
+
if (at <= 0) throw new Error(`--query needs key=value, got "${pair}"`);
|
|
5324
|
+
params.append(pair.slice(0, at), pair.slice(at + 1));
|
|
5325
|
+
}
|
|
5326
|
+
const sep4 = clean.includes("?") ? "&" : "?";
|
|
5327
|
+
const encoded = params.toString();
|
|
5328
|
+
return encoded ? `${clean}${sep4}${encoded}` : clean;
|
|
5329
|
+
}
|
|
5330
|
+
function matchOperations(doc, words) {
|
|
5331
|
+
const needles = words.map((w) => w.toLowerCase());
|
|
5332
|
+
const out = [];
|
|
5333
|
+
for (const [path, item] of Object.entries(doc.paths ?? {})) {
|
|
5334
|
+
for (const [method, op] of Object.entries(item)) {
|
|
5335
|
+
if (!API_METHODS.includes(method.toUpperCase())) continue;
|
|
5336
|
+
const hay = `${method} ${path} ${op.summary ?? ""} ${op.operationId ?? ""}`.toLowerCase();
|
|
5337
|
+
if (needles.every((n) => hay.includes(n))) out.push({ method: method.toUpperCase(), path, summary: op.summary, operationId: op.operationId });
|
|
5338
|
+
}
|
|
5339
|
+
}
|
|
5340
|
+
return out.sort((a, b) => a.path.localeCompare(b.path) || a.method.localeCompare(b.method));
|
|
5341
|
+
}
|
|
5342
|
+
async function searchApi(words) {
|
|
5343
|
+
const res = await apiRaw("GET", "/openapi.json", { auth: false });
|
|
5344
|
+
if (!res.ok) throw new Error(`could not read the API reference (${res.status})`);
|
|
5345
|
+
const ops = matchOperations(await res.json(), words);
|
|
5346
|
+
if (!ops.length) {
|
|
5347
|
+
console.log("no operations match");
|
|
5348
|
+
return;
|
|
5349
|
+
}
|
|
5350
|
+
for (const op of ops) console.log(`${op.method.padEnd(6)} ${op.path}${op.summary ? ` \u2014 ${op.summary}` : ""}`);
|
|
5351
|
+
}
|
|
5352
|
+
async function callApi(method, path, opts) {
|
|
5353
|
+
const verb = method.toUpperCase();
|
|
5354
|
+
if (!API_METHODS.includes(verb)) throw new Error(`method must be one of ${API_METHODS.join(", ")} or "search"`);
|
|
5355
|
+
const body = readData(opts.data);
|
|
5356
|
+
if (body !== void 0 && verb === "GET") throw new Error("a GET takes no --data; use --query");
|
|
5357
|
+
const res = await apiRaw(verb, requestPath(path, opts.query), { body, idempotencyKey: opts.idempotencyKey, universe: opts.workspace });
|
|
5358
|
+
const type = res.headers.get("content-type") ?? "";
|
|
5359
|
+
if (opts.output) {
|
|
5360
|
+
await writeResponseFile(res, opts.output);
|
|
5361
|
+
console.error(`${res.status} \u2192 ${opts.output}`);
|
|
5362
|
+
} else if (/json/.test(type)) {
|
|
5363
|
+
const text = await res.text();
|
|
5364
|
+
let printed = text;
|
|
5365
|
+
try {
|
|
5366
|
+
printed = JSON.stringify(JSON.parse(text), null, 2);
|
|
5367
|
+
} catch {
|
|
5368
|
+
}
|
|
5369
|
+
(res.ok ? console.log : console.error)(printed);
|
|
5370
|
+
} else if (/^text\/|xml|csv|markdown/.test(type) || !type) {
|
|
5371
|
+
(res.ok ? console.log : console.error)(await res.text());
|
|
5372
|
+
} else {
|
|
5373
|
+
console.error(`${res.status}: ${type} body (${res.headers.get("content-length") ?? "?"} bytes); pass --output <file> to save it`);
|
|
5374
|
+
}
|
|
5375
|
+
if (!res.ok && res.status !== 304) process.exitCode = 1;
|
|
5376
|
+
}
|
|
5377
|
+
|
|
5264
5378
|
// src/library.ts
|
|
5265
5379
|
var artifactPath = (id) => `/library/artifacts/${encodeURIComponent(id)}`;
|
|
5266
5380
|
async function listLibrary(query = {}) {
|
|
@@ -5295,9 +5409,139 @@ function renderLibraryArtifact(artifact2) {
|
|
|
5295
5409
|
const version = artifact2.currentVersion ? `v${artifact2.currentVersion}` : "";
|
|
5296
5410
|
return `${artifact2.id} ${artifact2.name} ${version}${artifact2.shared ? " shared" : ""}`;
|
|
5297
5411
|
}
|
|
5412
|
+
var libraryFileRefSchema = external_exports.discriminatedUnion("kind", [
|
|
5413
|
+
external_exports.object({ kind: external_exports.literal("agent_prompt"), agentId: external_exports.string().min(1).max(200).regex(/^[a-zA-Z0-9_-]+$/) }).strict(),
|
|
5414
|
+
external_exports.object({ kind: external_exports.literal("file"), fileId: external_exports.string().min(1), sessionId: external_exports.string().min(1).optional() }).strict(),
|
|
5415
|
+
external_exports.object({ kind: external_exports.literal("task_file"), taskId: external_exports.string().min(1), path: external_exports.string().min(1) }).strict(),
|
|
5416
|
+
external_exports.object({ kind: external_exports.literal("memory_note"), storeId: external_exports.string().min(1), memoryId: external_exports.string().min(1) }).strict(),
|
|
5417
|
+
external_exports.object({ kind: external_exports.literal("skill_file"), skillId: external_exports.string().min(1), path: external_exports.string().min(1) }).strict(),
|
|
5418
|
+
external_exports.object({ kind: external_exports.literal("artifact"), artifactId: external_exports.string().min(1) }).strict(),
|
|
5419
|
+
external_exports.object({ kind: external_exports.literal("platform_artifact"), artifactId: external_exports.string().min(1), path: external_exports.string().min(1).optional() }).strict()
|
|
5420
|
+
]);
|
|
5421
|
+
var linkAccessSchema = external_exports.enum(["none", "view", "edit"]);
|
|
5422
|
+
var linkMemberSchema = external_exports.object({ userId: external_exports.string().min(1), access: external_exports.enum(["view", "edit"]) });
|
|
5423
|
+
var linkRevisionSchema = external_exports.number().int().nonnegative();
|
|
5424
|
+
var libraryLinksSchema = external_exports.object({
|
|
5425
|
+
link: external_exports.object({
|
|
5426
|
+
id: external_exports.string().nullable(),
|
|
5427
|
+
ref: libraryFileRefSchema,
|
|
5428
|
+
workspace: external_exports.string().nullable(),
|
|
5429
|
+
revision: linkRevisionSchema,
|
|
5430
|
+
editable: external_exports.boolean(),
|
|
5431
|
+
workspaceAccess: linkAccessSchema,
|
|
5432
|
+
members: external_exports.array(linkMemberSchema),
|
|
5433
|
+
publicEnabled: external_exports.boolean(),
|
|
5434
|
+
sharedUrl: external_exports.string().nullable(),
|
|
5435
|
+
publicUrl: external_exports.string().nullable()
|
|
5436
|
+
}),
|
|
5437
|
+
availableMembers: external_exports.array(external_exports.object({ userId: external_exports.string(), name: external_exports.string().nullable(), email: external_exports.string().nullable() }))
|
|
5438
|
+
});
|
|
5439
|
+
function parseLibraryFileRef(value) {
|
|
5440
|
+
return libraryFileRefSchema.parse(JSON.parse(value));
|
|
5441
|
+
}
|
|
5442
|
+
async function getLibraryLinks(ref, workspace2) {
|
|
5443
|
+
const params = new URLSearchParams({ ref: JSON.stringify(libraryFileRefSchema.parse(ref)), ...workspace2 ? { workspace: workspace2 } : {} });
|
|
5444
|
+
const result = libraryLinksSchema.parse(await api("GET", `/library/links?${params}`));
|
|
5445
|
+
if (JSON.stringify(result.link.ref) !== JSON.stringify(libraryFileRefSchema.parse(ref)) || workspace2 !== void 0 && result.link.workspace !== workspace2) throw new Error("The API returned sharing for a different source. No access was changed.");
|
|
5446
|
+
return result;
|
|
5447
|
+
}
|
|
5448
|
+
async function updateLibraryLinks(ref, change) {
|
|
5449
|
+
const current = await getLibraryLinks(ref, change.workspace);
|
|
5450
|
+
if (change.revision !== void 0 && linkRevisionSchema.parse(change.revision) !== current.link.revision) throw new Error("Sharing changed since that revision. Read the current links and retry.");
|
|
5451
|
+
const members = new Map(current.link.members.map((member) => [member.userId, member]));
|
|
5452
|
+
for (const member of change.memberChanges ?? []) {
|
|
5453
|
+
const userId = external_exports.string().min(1).parse(member.userId);
|
|
5454
|
+
const access = linkAccessSchema.parse(member.access);
|
|
5455
|
+
if (access === "none") members.delete(userId);
|
|
5456
|
+
else members.set(userId, { userId, access });
|
|
5457
|
+
}
|
|
5458
|
+
return libraryLinksSchema.parse(await api("PUT", "/library/links", {
|
|
5459
|
+
ref,
|
|
5460
|
+
workspace: current.link.workspace,
|
|
5461
|
+
revision: current.link.revision,
|
|
5462
|
+
workspaceAccess: change.workspaceAccess === void 0 ? current.link.workspaceAccess : linkAccessSchema.parse(change.workspaceAccess),
|
|
5463
|
+
members: [...members.values()],
|
|
5464
|
+
publicEnabled: change.publicEnabled === void 0 ? current.link.publicEnabled : external_exports.boolean().parse(change.publicEnabled)
|
|
5465
|
+
}));
|
|
5466
|
+
}
|
|
5467
|
+
async function revokeLibraryLinks(ref, revision, workspace2) {
|
|
5468
|
+
return libraryLinksSchema.parse(await api("DELETE", "/library/links", {
|
|
5469
|
+
ref: libraryFileRefSchema.parse(ref),
|
|
5470
|
+
revision: linkRevisionSchema.parse(revision),
|
|
5471
|
+
...workspace2 ? { workspace: workspace2 } : {}
|
|
5472
|
+
}));
|
|
5473
|
+
}
|
|
5474
|
+
var sharedLibraryToken = external_exports.string().length(43).regex(/^[A-Za-z0-9_-]{43}$/, "use the 43-character token from the Library shared or public URL");
|
|
5475
|
+
var sharedLibrarySource = external_exports.object({
|
|
5476
|
+
name: external_exports.string(),
|
|
5477
|
+
format: external_exports.enum(["file", "site"]),
|
|
5478
|
+
mediaType: external_exports.string(),
|
|
5479
|
+
revision: external_exports.string(),
|
|
5480
|
+
editable: external_exports.boolean(),
|
|
5481
|
+
url: external_exports.string(),
|
|
5482
|
+
maxBytes: external_exports.number(),
|
|
5483
|
+
history: external_exports.array(external_exports.record(external_exports.string(), external_exports.unknown()))
|
|
5484
|
+
}).passthrough();
|
|
5485
|
+
var sharedLibrarySaved = external_exports.object({ url: external_exports.string(), revision: external_exports.string().min(1), publishedAt: external_exports.string().datetime({ offset: true }), text: external_exports.string().nullable().optional(), historyRevision: external_exports.string().optional() });
|
|
5486
|
+
var sharedLibrarySaveSchema = external_exports.object({
|
|
5487
|
+
revision: external_exports.string().min(1),
|
|
5488
|
+
text: external_exports.string().optional(),
|
|
5489
|
+
html: external_exports.string().optional(),
|
|
5490
|
+
office: external_exports.string().optional(),
|
|
5491
|
+
docx: external_exports.string().optional(),
|
|
5492
|
+
restoreRevision: external_exports.string().min(1).optional(),
|
|
5493
|
+
requestId: external_exports.string().uuid().optional()
|
|
5494
|
+
}).strict().refine((body) => [body.text, body.html, body.office, body.docx, body.restoreRevision].filter((field) => field !== void 0).length === 1, "provide exactly one of text, html, office, docx or restoreRevision");
|
|
5495
|
+
async function readSharedLibraryFile(token, options = {}) {
|
|
5496
|
+
const path = `/library/${options.public ? "public" : "shared"}/${sharedLibraryToken.parse(token)}`;
|
|
5497
|
+
if (!options.output) return sharedLibrarySource.parse(await api("GET", path, void 0, { auth: options.public !== true }));
|
|
5498
|
+
const response = await apiRaw("GET", `${path}?raw=1`, { auth: options.public !== true });
|
|
5499
|
+
if (!response.ok) {
|
|
5500
|
+
const body = await response.json().catch(() => null);
|
|
5501
|
+
throw new ApiError(response.status, body?.error?.code ?? "http_error", body?.error?.message ?? `Download failed (${response.status}).`);
|
|
5502
|
+
}
|
|
5503
|
+
return { output: options.output, bytes: await writeResponseFile(response, options.output) };
|
|
5504
|
+
}
|
|
5505
|
+
async function saveSharedLibraryFile(token, body) {
|
|
5506
|
+
return sharedLibrarySaved.parse(await api("PUT", `/library/shared/${sharedLibraryToken.parse(token)}`, sharedLibrarySaveSchema.parse(body)));
|
|
5507
|
+
}
|
|
5508
|
+
function registerLibraryLinkCommands(library2) {
|
|
5509
|
+
const libraryLinks = library2.command("links").description("share or publish any Library file; --workspace selects the sharing audience without moving the file");
|
|
5510
|
+
libraryLinks.command("read").description("read a shared native document snapshot; --public reads a public view-only link").requiredOption("--token <token>", "43-character token from a Library shared or public URL").option("--public", "use the public reader without sending your API key").option("--output <file>", "stream the original bytes to this file instead of printing the JSON snapshot").action(async (opts) => {
|
|
5511
|
+
console.log(JSON.stringify(await readSharedLibraryFile(opts.token, opts), null, 2));
|
|
5512
|
+
});
|
|
5513
|
+
libraryLinks.command("save").description("save through a live recipient edit grant; --revision is the opaque source revision from links read").requiredOption("--token <token>", "43-character token from the authenticated shared URL (public URLs have no writer)").requiredOption("--revision <revision>", "native source revision from links read; stale revisions fail without retry").option("--file <path>", "UTF-8 text file to save").option("--data <json>", "instead of --file, JSON/ @file / - containing exactly one text/html/office/docx/restoreRevision and optional requestId").action(async (opts) => {
|
|
5514
|
+
if (opts.file !== void 0 === (opts.data !== void 0)) throw new Error("Choose exactly one of --file or --data.");
|
|
5515
|
+
const body = opts.file !== void 0 ? { text: new TextDecoder("utf-8", { fatal: true }).decode(readFileSync17(opts.file)) } : JSON.parse(readData(opts.data));
|
|
5516
|
+
if (!body || typeof body !== "object" || Array.isArray(body)) throw new Error("--data must be a JSON object with one native save field.");
|
|
5517
|
+
if ("revision" in body && body.revision !== opts.revision) throw new Error("--data revision must match --revision.");
|
|
5518
|
+
console.log(JSON.stringify(await saveSharedLibraryFile(opts.token, sharedLibrarySaveSchema.parse({ ...body, revision: opts.revision })), null, 2));
|
|
5519
|
+
});
|
|
5520
|
+
const linkRefOption = (command) => command.requiredOption("--ref <json>", 'file reference JSON, e.g. {"kind":"file","fileId":"file_\u2026"}').option("--workspace <slug>", "the team audience for this link (omit for private/public-only sharing)");
|
|
5521
|
+
const linkRevision = (value) => value === void 0 ? void 0 : linkRevisionSchema.parse(Number(external_exports.string().regex(/^\d+$/, "revision must be a nonnegative integer").parse(value)));
|
|
5522
|
+
const printLibraryLinks = (value) => console.log(JSON.stringify(value, null, 2));
|
|
5523
|
+
linkRefOption(libraryLinks.command("show").description("read sharing, real workspace members and the current revision without creating a link")).action(async (opts) => printLibraryLinks(await getLibraryLinks(parseLibraryFileRef(opts.ref), opts.workspace)));
|
|
5524
|
+
linkRefOption(libraryLinks.command("share").description("change workspace or specific members' access while preserving every unmentioned grant")).option("--workspace-access <access>", "none, view or edit (edit requires an editable source)").option("--member <user:access>", "grant a member view or edit; repeat to update several members", (value, previous) => [...previous, value], []).option("--remove-member <user>", "clear a member override; workspace access still applies", (value, previous) => [...previous, value], []).option("--revision <n>", "refuse if sharing changed since this reviewed revision").action(async (opts) => {
|
|
5525
|
+
if (opts.workspaceAccess === void 0 && !opts.member?.length && !opts.removeMember?.length) throw new Error("Choose --workspace-access, --member or --remove-member; links show reads without changing access.");
|
|
5526
|
+
const memberChanges = (opts.member ?? []).map((value) => {
|
|
5527
|
+
const colon = value.lastIndexOf(":");
|
|
5528
|
+
if (colon < 1) throw new Error("--member must be a user id followed by :view or :edit");
|
|
5529
|
+
return { userId: value.slice(0, colon), access: external_exports.enum(["view", "edit"]).parse(value.slice(colon + 1)) };
|
|
5530
|
+
});
|
|
5531
|
+
memberChanges.push(...(opts.removeMember ?? []).map((userId) => ({ userId, access: "none" })));
|
|
5532
|
+
printLibraryLinks(await updateLibraryLinks(parseLibraryFileRef(opts.ref), {
|
|
5533
|
+
workspace: opts.workspace,
|
|
5534
|
+
revision: linkRevision(opts.revision),
|
|
5535
|
+
memberChanges,
|
|
5536
|
+
workspaceAccess: opts.workspaceAccess === void 0 ? void 0 : external_exports.enum(["none", "view", "edit"]).parse(opts.workspaceAccess)
|
|
5537
|
+
}));
|
|
5538
|
+
});
|
|
5539
|
+
linkRefOption(libraryLinks.command("publish").description("create a public view-only link; --disable revokes only public access and keeps other grants")).option("--disable", "turn off public viewing").option("--revision <n>", "refuse if sharing changed since this reviewed revision").action(async (opts) => printLibraryLinks(await updateLibraryLinks(parseLibraryFileRef(opts.ref), { workspace: opts.workspace, revision: linkRevision(opts.revision), publicEnabled: !opts.disable })));
|
|
5540
|
+
linkRefOption(libraryLinks.command("revoke").description("stop all sharing at an explicitly reviewed revision")).requiredOption("--revision <n>", "current revision from links show; stale revisions fail without retry").action(async (opts) => printLibraryLinks(await revokeLibraryLinks(parseLibraryFileRef(opts.ref), linkRevision(opts.revision), opts.workspace)));
|
|
5541
|
+
}
|
|
5298
5542
|
|
|
5299
5543
|
// src/design-systems.ts
|
|
5300
|
-
import { readdirSync as readdirSync8, readFileSync as
|
|
5544
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync18, statSync as statSync9 } from "fs";
|
|
5301
5545
|
import { join as join18, relative as relative5, sep as sep3 } from "path";
|
|
5302
5546
|
var TEXT2 = /\.(mdx?|markdown|txt|json|m?js|cjs|jsx|tsx?|css|html?|svg|xml|csv|ya?ml|toml)$/i;
|
|
5303
5547
|
var MEDIA = {
|
|
@@ -5330,6 +5574,13 @@ async function saveDesignTokens(id, baseVersion, tokens, note) {
|
|
|
5330
5574
|
...note ? { note } : {}
|
|
5331
5575
|
})).artifact;
|
|
5332
5576
|
}
|
|
5577
|
+
async function saveDesignSystemFile(id, path, baseVersion, change, note) {
|
|
5578
|
+
return (await api("PUT", `/artifacts/${encodeURIComponent(id)}/design-system/files/${path.split("/").map(encodeURIComponent).join("/")}`, {
|
|
5579
|
+
base_version: baseVersion,
|
|
5580
|
+
...change,
|
|
5581
|
+
...note ? { note } : {}
|
|
5582
|
+
})).artifact;
|
|
5583
|
+
}
|
|
5333
5584
|
function fileTableFrom(dir) {
|
|
5334
5585
|
const files2 = {};
|
|
5335
5586
|
const walk = (current) => {
|
|
@@ -5341,7 +5592,7 @@ function fileTableFrom(dir) {
|
|
|
5341
5592
|
continue;
|
|
5342
5593
|
}
|
|
5343
5594
|
const key = relative5(dir, path).split(sep3).join("/");
|
|
5344
|
-
const bytes =
|
|
5595
|
+
const bytes = readFileSync18(path);
|
|
5345
5596
|
files2[key] = TEXT2.test(name) ? bytes.toString("utf8") : `data:${MEDIA[name.split(".").pop()?.toLowerCase() ?? ""] ?? "application/octet-stream"};base64,${bytes.toString("base64")}`;
|
|
5346
5597
|
}
|
|
5347
5598
|
};
|
|
@@ -5364,80 +5615,6 @@ async function designComments(id, input) {
|
|
|
5364
5615
|
return api(input ? "POST" : "GET", `/artifacts/${encodeURIComponent(id)}/design-system/comments`, input);
|
|
5365
5616
|
}
|
|
5366
5617
|
|
|
5367
|
-
// src/api-command.ts
|
|
5368
|
-
import { readFileSync as readFileSync17, writeFileSync as writeFileSync9 } from "fs";
|
|
5369
|
-
var API_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
5370
|
-
function readData(data, stdin = () => readFileSync17(0, "utf8")) {
|
|
5371
|
-
if (data === void 0) return void 0;
|
|
5372
|
-
const raw = data === "-" ? stdin() : data.startsWith("@") ? readFileSync17(data.slice(1), "utf8") : data;
|
|
5373
|
-
try {
|
|
5374
|
-
JSON.parse(raw);
|
|
5375
|
-
} catch {
|
|
5376
|
-
throw new Error("--data must be JSON (inline, @file or - for stdin)");
|
|
5377
|
-
}
|
|
5378
|
-
return raw;
|
|
5379
|
-
}
|
|
5380
|
-
function requestPath(path, query = []) {
|
|
5381
|
-
if (!path.startsWith("/") || path.startsWith("//")) throw new Error("path must start with /, e.g. /threads");
|
|
5382
|
-
const clean = path.replace(/^\/v1(?=\/)/, "");
|
|
5383
|
-
const params = new URLSearchParams();
|
|
5384
|
-
for (const pair of query) {
|
|
5385
|
-
const at = pair.indexOf("=");
|
|
5386
|
-
if (at <= 0) throw new Error(`--query needs key=value, got "${pair}"`);
|
|
5387
|
-
params.append(pair.slice(0, at), pair.slice(at + 1));
|
|
5388
|
-
}
|
|
5389
|
-
const sep4 = clean.includes("?") ? "&" : "?";
|
|
5390
|
-
const encoded = params.toString();
|
|
5391
|
-
return encoded ? `${clean}${sep4}${encoded}` : clean;
|
|
5392
|
-
}
|
|
5393
|
-
function matchOperations(doc, words) {
|
|
5394
|
-
const needles = words.map((w) => w.toLowerCase());
|
|
5395
|
-
const out = [];
|
|
5396
|
-
for (const [path, item] of Object.entries(doc.paths ?? {})) {
|
|
5397
|
-
for (const [method, op] of Object.entries(item)) {
|
|
5398
|
-
if (!API_METHODS.includes(method.toUpperCase())) continue;
|
|
5399
|
-
const hay = `${method} ${path} ${op.summary ?? ""} ${op.operationId ?? ""}`.toLowerCase();
|
|
5400
|
-
if (needles.every((n) => hay.includes(n))) out.push({ method: method.toUpperCase(), path, summary: op.summary, operationId: op.operationId });
|
|
5401
|
-
}
|
|
5402
|
-
}
|
|
5403
|
-
return out.sort((a, b) => a.path.localeCompare(b.path) || a.method.localeCompare(b.method));
|
|
5404
|
-
}
|
|
5405
|
-
async function searchApi(words) {
|
|
5406
|
-
const res = await apiRaw("GET", "/openapi.json", { auth: false });
|
|
5407
|
-
if (!res.ok) throw new Error(`could not read the API reference (${res.status})`);
|
|
5408
|
-
const ops = matchOperations(await res.json(), words);
|
|
5409
|
-
if (!ops.length) {
|
|
5410
|
-
console.log("no operations match");
|
|
5411
|
-
return;
|
|
5412
|
-
}
|
|
5413
|
-
for (const op of ops) console.log(`${op.method.padEnd(6)} ${op.path}${op.summary ? ` \u2014 ${op.summary}` : ""}`);
|
|
5414
|
-
}
|
|
5415
|
-
async function callApi(method, path, opts) {
|
|
5416
|
-
const verb = method.toUpperCase();
|
|
5417
|
-
if (!API_METHODS.includes(verb)) throw new Error(`method must be one of ${API_METHODS.join(", ")} or "search"`);
|
|
5418
|
-
const body = readData(opts.data);
|
|
5419
|
-
if (body !== void 0 && verb === "GET") throw new Error("a GET takes no --data; use --query");
|
|
5420
|
-
const res = await apiRaw(verb, requestPath(path, opts.query), { body, idempotencyKey: opts.idempotencyKey, universe: opts.workspace });
|
|
5421
|
-
const type = res.headers.get("content-type") ?? "";
|
|
5422
|
-
if (opts.output) {
|
|
5423
|
-
writeFileSync9(opts.output, new Uint8Array(await res.arrayBuffer()));
|
|
5424
|
-
console.error(`${res.status} \u2192 ${opts.output}`);
|
|
5425
|
-
} else if (/json/.test(type)) {
|
|
5426
|
-
const text = await res.text();
|
|
5427
|
-
let printed = text;
|
|
5428
|
-
try {
|
|
5429
|
-
printed = JSON.stringify(JSON.parse(text), null, 2);
|
|
5430
|
-
} catch {
|
|
5431
|
-
}
|
|
5432
|
-
(res.ok ? console.log : console.error)(printed);
|
|
5433
|
-
} else if (/^text\/|xml|csv|markdown/.test(type) || !type) {
|
|
5434
|
-
(res.ok ? console.log : console.error)(await res.text());
|
|
5435
|
-
} else {
|
|
5436
|
-
console.error(`${res.status}: ${type} body (${res.headers.get("content-length") ?? "?"} bytes); pass --output <file> to save it`);
|
|
5437
|
-
}
|
|
5438
|
-
if (!res.ok && res.status !== 304) process.exitCode = 1;
|
|
5439
|
-
}
|
|
5440
|
-
|
|
5441
5618
|
// src/billing-plans.ts
|
|
5442
5619
|
var readCodingPlan = () => api("GET", "/billing/coding-plan");
|
|
5443
5620
|
function joinCodingPlan(dollars2, requestId) {
|
|
@@ -5524,7 +5701,7 @@ function workspaceFlagIsCommands(argv, commandPath) {
|
|
|
5524
5701
|
}
|
|
5525
5702
|
|
|
5526
5703
|
// src/harness.ts
|
|
5527
|
-
import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as
|
|
5704
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync19, writeFileSync as writeFileSync9 } from "fs";
|
|
5528
5705
|
import { dirname as dirname9, join as join19, resolve as resolve8 } from "path";
|
|
5529
5706
|
var HARNESS_FILE = "harness.json";
|
|
5530
5707
|
function harnessFilePath(dir) {
|
|
@@ -5536,7 +5713,7 @@ function readHarnessFile(dir) {
|
|
|
5536
5713
|
throw new Error(`no ${HARNESS_FILE} found in ${resolve8(dir)} \u2014 run \`sky harness init\` first`);
|
|
5537
5714
|
}
|
|
5538
5715
|
try {
|
|
5539
|
-
return JSON.parse(
|
|
5716
|
+
return JSON.parse(readFileSync19(path, "utf8"));
|
|
5540
5717
|
} catch (err) {
|
|
5541
5718
|
throw new Error(`could not parse ${path}: ${err instanceof Error ? err.message : String(err)}`);
|
|
5542
5719
|
}
|
|
@@ -5567,7 +5744,7 @@ function harnessInit(dir) {
|
|
|
5567
5744
|
throw new Error(`${path} already exists \u2014 delete it to re-init`);
|
|
5568
5745
|
}
|
|
5569
5746
|
mkdirSync6(dirname9(path), { recursive: true });
|
|
5570
|
-
|
|
5747
|
+
writeFileSync9(path, `${JSON.stringify(INIT_SKELETON, null, 2)}
|
|
5571
5748
|
`);
|
|
5572
5749
|
console.log(`Created ${path}`);
|
|
5573
5750
|
console.log(INIT_COMMENT);
|
|
@@ -6306,7 +6483,7 @@ sessionWorkspace.command("cat <ref> <path>").description("print a file (up to 1
|
|
|
6306
6483
|
run(async (ref, path, opts) => {
|
|
6307
6484
|
const bytes = await readFile(await resolveSessionRef(ref), path);
|
|
6308
6485
|
if (opts.out) {
|
|
6309
|
-
|
|
6486
|
+
writeFileSync10(opts.out, bytes);
|
|
6310
6487
|
console.error(`saved ${bytes.length} bytes to ${opts.out}`);
|
|
6311
6488
|
} else process.stdout.write(bytes);
|
|
6312
6489
|
})
|
|
@@ -6323,7 +6500,7 @@ sessionWorkspace.command("patch <ref> [repo]").description("the work in a reposi
|
|
|
6323
6500
|
console.error(`${meta.repo}: ${meta.commits.length} commit${meta.commits.length === 1 ? "" : "s"} since ${meta.base_branch || "the imported copy"} (${meta.base_commit.slice(0, 12)})`);
|
|
6324
6501
|
if (!patch.length) console.error("nothing changed");
|
|
6325
6502
|
else if (opts.out) {
|
|
6326
|
-
|
|
6503
|
+
writeFileSync10(opts.out, patch);
|
|
6327
6504
|
console.error(`wrote ${opts.out} \u2014 apply with: git apply ${opts.out}`);
|
|
6328
6505
|
} else process.stdout.write(patch);
|
|
6329
6506
|
})
|
|
@@ -6828,14 +7005,14 @@ task.command("get <task> <path>").description("read one task file; prints it, or
|
|
|
6828
7005
|
run(async (taskId, path, opts) => {
|
|
6829
7006
|
const bytes = await readTaskFile(taskId, path);
|
|
6830
7007
|
if (opts.out) {
|
|
6831
|
-
|
|
7008
|
+
writeFileSync10(opts.out, bytes);
|
|
6832
7009
|
console.log(`Wrote ${bytes.length} bytes to ${opts.out}`);
|
|
6833
7010
|
} else process.stdout.write(bytes);
|
|
6834
7011
|
})
|
|
6835
7012
|
);
|
|
6836
7013
|
task.command("put <task> <path> <local>").description("write a local file to <path> in the task's files (every session of the task sees it)").action(
|
|
6837
7014
|
run(async (taskId, path, local) => {
|
|
6838
|
-
const { file, conflict } = await writeTaskFile(taskId, path,
|
|
7015
|
+
const { file, conflict } = await writeTaskFile(taskId, path, readFileSync20(local), mediaTypeFor(local));
|
|
6839
7016
|
console.log(`${renderTaskFile(file)}${conflict ? " (replaced a version you had not seen)" : ""}`);
|
|
6840
7017
|
})
|
|
6841
7018
|
);
|
|
@@ -6908,6 +7085,80 @@ task.command("verdict <task> <did-the-job>").description("record whether the tas
|
|
|
6908
7085
|
console.log(`Recorded verdict on task ${updated.id}: did_the_job=${value === "yes"}`);
|
|
6909
7086
|
})
|
|
6910
7087
|
);
|
|
7088
|
+
var plugins = program.command("plugins").description("Claude Code plugins in the workspace: install from GitHub, list, remove");
|
|
7089
|
+
plugins.command("list").description("the workspace's installed plugins and the skills each one installed").option("--json", "print the list as JSON").action(
|
|
7090
|
+
run(async (opts) => {
|
|
7091
|
+
const { plugins: list } = await api("GET", "/plugins");
|
|
7092
|
+
if (opts.json) return void console.log(JSON.stringify(list));
|
|
7093
|
+
if (list.length === 0) return void console.log("No plugins. `sky plugins install github:owner/repo[/path][@ref]`");
|
|
7094
|
+
for (const p of list) console.log(`${p.name} ${p.skills.length} skill${p.skills.length === 1 ? "" : "s"}: ${p.skills.map((s) => s.displayName.split("/").pop()).join(", ")}`);
|
|
7095
|
+
})
|
|
7096
|
+
);
|
|
7097
|
+
plugins.command("install <source>").description("install or update a plugin: github:owner/repo[/path][@ref] or a github.com URL").option("--mcp-token <server=token...>", "a bearer token for one of the plugin's remote MCP servers (repeatable)").option("--json", "print the result as JSON").action(
|
|
7098
|
+
run(async (source, opts) => {
|
|
7099
|
+
const mcp_tokens = Object.fromEntries((opts.mcpToken ?? []).map((pair) => [pair.slice(0, pair.indexOf("=")), pair.slice(pair.indexOf("=") + 1)]).filter(([k, v]) => k && v));
|
|
7100
|
+
const result = await api("POST", "/plugins", { source, ...Object.keys(mcp_tokens).length ? { mcp_tokens } : {} });
|
|
7101
|
+
if (opts.json) return void console.log(JSON.stringify(result));
|
|
7102
|
+
console.log(`Installed ${result.plugin.name}${result.plugin.version ? ` ${result.plugin.version}` : ""} from ${result.plugin.source}: ${result.skills.length} skill(s), on for every new session.`);
|
|
7103
|
+
for (const c of result.connectors) {
|
|
7104
|
+
const state = c.app === null ? "no AgentSky connector for it yet" : c.connected ? `uses your ${c.app} connection` : `connect ${c.app}: ${c.connect_url}`;
|
|
7105
|
+
console.log(` connector ${c.server}: ${state}`);
|
|
7106
|
+
}
|
|
7107
|
+
for (const s of result.skipped) console.log(` skipped ${s.part}: ${s.reason}`);
|
|
7108
|
+
for (const r of result.removed) console.log(` ${r.part}: ${r.result.replace("_", " ")} (no longer in the plugin)`);
|
|
7109
|
+
})
|
|
7110
|
+
);
|
|
7111
|
+
plugins.command("rm <name>").description("remove a plugin's skills (a skill a session still holds is switched off)").action(
|
|
7112
|
+
run(async (name) => {
|
|
7113
|
+
const result = await api("DELETE", `/plugins/${encodeURIComponent(name)}`);
|
|
7114
|
+
console.log(`Removed ${result.name}: ${result.parts.map((p) => `${p.part} ${p.result.replace("_", " ")}`).join(", ")}`);
|
|
7115
|
+
})
|
|
7116
|
+
);
|
|
7117
|
+
for (const [verb, enabled] of [["enable", true], ["disable", false]]) {
|
|
7118
|
+
plugins.command(`${verb} <name>`).description(enabled ? "switch a plugin back on: its skills attach to new sessions again" : "switch a plugin off: its skills stop attaching to new sessions and plugin sessions refuse to start").action(
|
|
7119
|
+
run(async (name) => {
|
|
7120
|
+
await api("PATCH", `/plugins/${encodeURIComponent(name)}`, { enabled });
|
|
7121
|
+
console.log(`${name} is ${enabled ? "on" : "off"}.`);
|
|
7122
|
+
})
|
|
7123
|
+
);
|
|
7124
|
+
}
|
|
7125
|
+
plugins.command("run <name> <message>").description("start a plugin session: only that plugin's skills and MCP servers, and connected apps limited to the ones it declared").option("--agent <id>", "the agent to run (default: the workspace's Sky)").option("--json", "print the created session as JSON").action(
|
|
7126
|
+
run(async (name, message2, opts) => {
|
|
7127
|
+
const session2 = await api("POST", `/plugins/${encodeURIComponent(name)}/sessions`, { message: message2, ...opts.agent ? { agent: opts.agent } : {} });
|
|
7128
|
+
if (opts.json) return void console.log(JSON.stringify(session2));
|
|
7129
|
+
console.log(`Started ${session2.id} for ${name}. Follow it: sky session read ${session2.id} --wait`);
|
|
7130
|
+
})
|
|
7131
|
+
);
|
|
7132
|
+
plugins.command("policy <name> <policy>").description("workspace owners and admins: recommended | default | blocked | none (default installs it now)").option("--source <source>", "where a default plugin installs from (github:owner/repo[/path][@ref])").action(
|
|
7133
|
+
run(async (name, policy2, opts) => {
|
|
7134
|
+
const value = policy2 === "none" ? null : policy2;
|
|
7135
|
+
const result = await api("PUT", `/plugins/${encodeURIComponent(name)}/policy`, { policy: value, ...opts.source ? { source: opts.source } : {} });
|
|
7136
|
+
console.log(`${result.name}: ${result.policy ?? "no policy"}${result.installed ? " (installed)" : ""}`);
|
|
7137
|
+
})
|
|
7138
|
+
);
|
|
7139
|
+
var market = plugins.command("market").description("Claude Code marketplaces the workspace lists plugins from");
|
|
7140
|
+
market.command("list").description("every plugin the workspace's marketplaces list, with its install source, policy and whether it is installed").option("--json", "print the marketplaces as JSON").action(
|
|
7141
|
+
run(async (opts) => {
|
|
7142
|
+
const { marketplaces } = await api("GET", "/plugins/marketplaces");
|
|
7143
|
+
if (opts.json) return void console.log(JSON.stringify(marketplaces));
|
|
7144
|
+
for (const m of marketplaces) {
|
|
7145
|
+
console.log(`${m.name} (${m.source})${m.error ? `: ${m.error}` : ""}`);
|
|
7146
|
+
for (const p of m.plugins) console.log(` ${p.installed ? "\u25CF" : "\u25CB"} ${p.name}${p.policy ? ` [${p.policy}]` : ""} ${p.source ?? "(not on GitHub)"} ${p.description.slice(0, 80)}`);
|
|
7147
|
+
}
|
|
7148
|
+
})
|
|
7149
|
+
);
|
|
7150
|
+
market.command("add <source>").description("workspace owners and admins: list plugins from a folder holding .claude-plugin/marketplace.json").action(
|
|
7151
|
+
run(async (source) => {
|
|
7152
|
+
const m = await api("POST", "/plugins/marketplaces", { source });
|
|
7153
|
+
console.log(`Added ${m.name} (${m.source}): ${m.plugins.length} plugins.`);
|
|
7154
|
+
})
|
|
7155
|
+
);
|
|
7156
|
+
market.command("rm <source>").description("workspace owners and admins: stop listing a marketplace (installed plugins stay)").action(
|
|
7157
|
+
run(async (source) => {
|
|
7158
|
+
await api("DELETE", `/plugins/marketplaces?source=${encodeURIComponent(source)}`);
|
|
7159
|
+
console.log(`Removed ${source}.`);
|
|
7160
|
+
})
|
|
7161
|
+
);
|
|
6911
7162
|
var skills = program.command("skills").description("the workspace's skill store: upload a skill, then attach it to an agent (sky skills attach, or [[skills]] in agent.toml)");
|
|
6912
7163
|
skills.command("upload <dir>").description("upload a skill directory (SKILL.md at its root) as a new skill").option("--name <name>", "display name (default: the directory's name)").option("--json", "print the stored skill as JSON").action(
|
|
6913
7164
|
run(async (dir, opts) => {
|
|
@@ -6999,7 +7250,7 @@ library.command("list").description("your Library, newest first").option("--sear
|
|
|
6999
7250
|
);
|
|
7000
7251
|
library.command("upload <path>").description("save a file from this computer to your Library").option("--workspace <key>", "place it in this workspace").action(
|
|
7001
7252
|
run(async (path, opts) => {
|
|
7002
|
-
const bytes =
|
|
7253
|
+
const bytes = readFileSync20(path);
|
|
7003
7254
|
const { artifact: artifact2 } = await uploadToLibrary({ bytes, name: basename9(path), mediaType: "application/octet-stream" }, `sky-upload-${crypto.randomUUID()}`, opts.workspace);
|
|
7004
7255
|
console.log(renderLibraryArtifact(artifact2));
|
|
7005
7256
|
})
|
|
@@ -7030,10 +7281,11 @@ library.command("place <id> <workspace>").description('place your artifact in a
|
|
|
7030
7281
|
library.command("download <id> <out>").description("save one version's bytes to a file").option("--version <n>", "a saved version (the current one when omitted)").action(
|
|
7031
7282
|
run(async (id, out, opts) => {
|
|
7032
7283
|
const { bytes } = await downloadLibraryArtifact(id, opts.version ? Number(opts.version) : void 0);
|
|
7033
|
-
|
|
7284
|
+
writeFileSync10(out, bytes);
|
|
7034
7285
|
console.log(`wrote ${bytes.length} bytes to ${out}`);
|
|
7035
7286
|
})
|
|
7036
7287
|
);
|
|
7288
|
+
registerLibraryLinkCommands(library);
|
|
7037
7289
|
var artifact = program.command("artifact").description("artifacts: publish a task's files as a named, shareable result");
|
|
7038
7290
|
artifact.command("list").description("the workspace's artifacts, or one task's with --task").option("--task <task>", "only this task's artifacts").action(
|
|
7039
7291
|
run(async (opts) => {
|
|
@@ -7051,7 +7303,7 @@ artifact.command("get <id> <path>").description("read one file of an artifact; p
|
|
|
7051
7303
|
run(async (id, path, opts) => {
|
|
7052
7304
|
const bytes = await readArtifactFile(id, path);
|
|
7053
7305
|
if (opts.out) {
|
|
7054
|
-
|
|
7306
|
+
writeFileSync10(opts.out, bytes);
|
|
7055
7307
|
console.log(`Wrote ${bytes.length} bytes to ${opts.out}`);
|
|
7056
7308
|
} else process.stdout.write(bytes);
|
|
7057
7309
|
})
|
|
@@ -7089,10 +7341,17 @@ designSystem.command("import <task> <folder>").description("import a local desig
|
|
|
7089
7341
|
);
|
|
7090
7342
|
designSystem.command("tokens <id> <file>").description("save a tokens.json file as the system's next version; --base is the version you edited").requiredOption("--base <version>", "the version the file was edited from", (value) => Number(value)).option("--note <note>", "one line saying what changed").action(
|
|
7091
7343
|
run(async (id, file, opts) => {
|
|
7092
|
-
const tokens = JSON.parse(
|
|
7344
|
+
const tokens = JSON.parse(readFileSync20(resolve9(file), "utf8"));
|
|
7093
7345
|
console.log(renderArtifact(await saveDesignTokens(id, opts.base, tokens, opts.note)));
|
|
7094
7346
|
})
|
|
7095
7347
|
);
|
|
7348
|
+
designSystem.command("write <id> <path> [file]").description("save one of the system's editable files (path such as project/README.md) from a local file as its next version, or put back an earlier version's copy with --restore").requiredOption("--base <version>", "the version the file was edited from", (value) => Number(value)).option("--restore <version>", "restore the file as it was in this version instead of reading [file]", (value) => Number(value)).option("--note <note>", "one line saying what changed").action(
|
|
7349
|
+
run(async (id, path, file, opts) => {
|
|
7350
|
+
if (file === void 0 === (opts.restore === void 0)) throw Error("Give a local [file] to save, or --restore <version>.");
|
|
7351
|
+
const change = opts.restore === void 0 ? { content: readFileSync20(resolve9(file), "utf8") } : { restore_version: opts.restore };
|
|
7352
|
+
console.log(renderArtifact(await saveDesignSystemFile(id, path, opts.base, change, opts.note)));
|
|
7353
|
+
})
|
|
7354
|
+
);
|
|
7096
7355
|
designSystem.command("comments <id>").description("read design-system comments, or add one with --text and --base").option("--text <text>", "comment to add").option("--target <target>", "overview, color:<name> or component:<name>", "overview").option("--base <version>", "the version you viewed", Number).action(run(async (id, opts) => {
|
|
7097
7356
|
if (opts.text !== void 0 && (!Number.isInteger(opts.base) || opts.base < 1)) throw Error("Adding a comment requires --base <version>.");
|
|
7098
7357
|
console.log(JSON.stringify(await designComments(id, opts.text === void 0 ? void 0 : { text: opts.text, target: opts.target, base_version: opts.base }), null, 2));
|
|
@@ -7402,7 +7661,7 @@ usageOptions(
|
|
|
7402
7661
|
run(async (opts) => {
|
|
7403
7662
|
const { bytes } = await apiBytes("GET", `/billing/usage/export${usageQuery(opts)}`);
|
|
7404
7663
|
if (opts.out) {
|
|
7405
|
-
|
|
7664
|
+
writeFileSync10(opts.out, bytes);
|
|
7406
7665
|
console.log(`Wrote ${bytes.length} bytes to ${opts.out}`);
|
|
7407
7666
|
} else {
|
|
7408
7667
|
process.stdout.write(bytes);
|
|
@@ -7481,7 +7740,7 @@ memory.command("edit <index> <text...>").description("replace entry <index>").ac
|
|
|
7481
7740
|
memory.command("rm <index>").description("remove entry <index>").action(run(async (index) => writeMemory({ op: "remove", index: memoryIndex(index) })));
|
|
7482
7741
|
memory.command("clear").description("remove every entry").action(run(async () => writeMemory({ op: "clear" })));
|
|
7483
7742
|
var context = program.command("context").description("search everything you can open in the workspace, and read a hit");
|
|
7484
|
-
context.command("search <words...>").description('plain words, "exact phrase" or /regex/ (every matching line, like grep); follow --cursor for more').option("--scope <folder>", "memory/, chats, traces,
|
|
7743
|
+
context.command("search <words...>").description('plain words, "exact phrase" or /regex/ (every matching line, like grep); follow --cursor for more').option("--scope <folder>", "memory/, chats, traces, artifacts/, files/, meetings/, skills/<name>/, agents/ or docs/ (default everything)").option("--limit <n>", "hits per page (default 20)").option("--cursor <cursor>", "continue a previous search").option("--since <iso>", "inclusive lower time bound").option("--until <iso>", "exclusive upper time bound").option("--json", "print the API's answer as JSON").action(
|
|
7485
7744
|
run(async (words, opts) => {
|
|
7486
7745
|
const page = await searchContext(words.join(" "), opts);
|
|
7487
7746
|
console.log(opts.json ? JSON.stringify(page, null, 2) : renderContextPage(page));
|
|
@@ -8014,7 +8273,7 @@ notes.command("read <storeId> <noteId>").description("print one note").action(
|
|
|
8014
8273
|
notes.command("save <storeId> <file>").description("write a note from a local file: --path creates one, --note saves a new version of one").option("--path <path>", "path of a new note, e.g. /projects/launch.md").option("--note <noteId>", "the note to update").action(
|
|
8015
8274
|
run(async (storeId, file, opts) => {
|
|
8016
8275
|
if (!opts.path === !opts.note) throw new Error("pass exactly one of --path (new note) or --note (update)");
|
|
8017
|
-
const content =
|
|
8276
|
+
const content = readFileSync20(file, "utf8");
|
|
8018
8277
|
const target = `/memory_stores/${encodeURIComponent(storeId)}/memories${opts.note ? `/${encodeURIComponent(opts.note)}` : ""}`;
|
|
8019
8278
|
const { memory: memory2 } = await api("POST", target, { content, ...opts.path ? { path: opts.path } : {} });
|
|
8020
8279
|
console.log(`Saved ${memory2.path} (${memory2.id})`);
|
|
@@ -8114,7 +8373,7 @@ harness.command("connect").description("run an ACP agent (the command after --)
|
|
|
8114
8373
|
}));
|
|
8115
8374
|
var traceCmd = program.command("trace").description("correlate this machine's agent work with the cloud sessions it starts (metadata only unless you choose content)");
|
|
8116
8375
|
traceCmd.command("start").description("start a trace: a grant for this machine, a root span, and the spool the hooks write to").option("--name <name>", "a name for the task").option("--source <source>", "how this machine reports itself", "claude-code").option("--hooks [settings]", "also install the Claude Code hooks (default: ./.claude/settings.local.json)").option("--capture <scopes>", "also send content, redacted on this machine first: any of prompts,tool_output,files").option("--file <path>", "a file the files scope may send (repeatable)", collect).option("--dir <path>", "a folder whose files the files scope may send when a file tool touches them (repeatable)", collect).action(run(async (opts) => {
|
|
8117
|
-
const { readState, writeState, record, installClaudeHooks, parseContentScopes, chosenPaths, fileEvent } = await import("./trace-
|
|
8376
|
+
const { readState, writeState, record, installClaudeHooks, parseContentScopes, chosenPaths, fileEvent } = await import("./trace-OPRHOP2E.js");
|
|
8118
8377
|
if (readState()) throw new Error("a trace is already running here \u2014 `sky trace stop` it first");
|
|
8119
8378
|
const scopes = parseContentScopes(opts.capture);
|
|
8120
8379
|
const chosen = chosenPaths(opts.file ?? [], opts.dir ?? []);
|
|
@@ -8149,7 +8408,7 @@ traceCmd.command("start").description("start a trace: a grant for this machine,
|
|
|
8149
8408
|
}));
|
|
8150
8409
|
traceCmd.command("hook").description("record one Claude Code hook event read from stdin (run by the installed hooks; never fails, prints nothing)").action(async () => {
|
|
8151
8410
|
try {
|
|
8152
|
-
const { readState, record, flush, grantSender, eventsForClaudeHook, contentForClaudeHook, clearState } = await import("./trace-
|
|
8411
|
+
const { readState, record, flush, grantSender, eventsForClaudeHook, contentForClaudeHook, clearState } = await import("./trace-OPRHOP2E.js");
|
|
8153
8412
|
const chunks = [];
|
|
8154
8413
|
for await (const chunk of process.stdin) chunks.push(chunk);
|
|
8155
8414
|
const input = JSON.parse(Buffer.concat(chunks).toString("utf8") || "{}");
|
|
@@ -8162,14 +8421,14 @@ traceCmd.command("hook").description("record one Claude Code hook event read fro
|
|
|
8162
8421
|
}
|
|
8163
8422
|
});
|
|
8164
8423
|
traceCmd.command("flush").description("send what the spool holds, retrying with backoff").action(run(async () => {
|
|
8165
|
-
const { readState, flush, grantSender } = await import("./trace-
|
|
8424
|
+
const { readState, flush, grantSender } = await import("./trace-OPRHOP2E.js");
|
|
8166
8425
|
const state = readState();
|
|
8167
8426
|
if (!state) throw new Error("no trace is running here");
|
|
8168
8427
|
const outcome = await flush(grantSender(state), { attempts: 4 });
|
|
8169
8428
|
console.log(`sent ${outcome.sent}, refused ${outcome.refused}, given up ${outcome.expired}, still pending ${outcome.pending}${outcome.stopped ? ` (stopped: ${outcome.stopped})` : ""}`);
|
|
8170
8429
|
}));
|
|
8171
8430
|
traceCmd.command("status").description("the running trace and its spool").action(run(async () => {
|
|
8172
|
-
const { readState, spoolStatus } = await import("./trace-
|
|
8431
|
+
const { readState, spoolStatus } = await import("./trace-OPRHOP2E.js");
|
|
8173
8432
|
const state = readState();
|
|
8174
8433
|
if (!state) {
|
|
8175
8434
|
console.log("No trace is running here.");
|
|
@@ -8179,7 +8438,7 @@ traceCmd.command("status").description("the running trace and its spool").action
|
|
|
8179
8438
|
console.log(`${state.trace_id} as ${state.source}: ${spool.pending} pending, ${spool.dropped_full} dropped (spool full), ${spool.dropped_expired} given up, ${spool.refused} refused`);
|
|
8180
8439
|
}));
|
|
8181
8440
|
traceCmd.command("show [id]").description("the trace bundle: spans, the sessions they reach, cost counted once per session").option("--json", "print the bundle as JSON").action(run(async (id, opts) => {
|
|
8182
|
-
const { readState } = await import("./trace-
|
|
8441
|
+
const { readState } = await import("./trace-OPRHOP2E.js");
|
|
8183
8442
|
const ref = id ?? readState()?.trace_id;
|
|
8184
8443
|
if (!ref) throw new Error("name a trace, or start one here");
|
|
8185
8444
|
const bundle = await api("GET", `/traces/${ref}`);
|
|
@@ -8206,7 +8465,7 @@ traceCmd.command("show [id]").description("the trace bundle: spans, the sessions
|
|
|
8206
8465
|
for (const gap of bundle.gaps) console.log(` gap: ${gap.span_id} ${gap.reason}`);
|
|
8207
8466
|
}));
|
|
8208
8467
|
traceCmd.command("stop").description("end the root span, send what is left, and revoke this machine's grant").action(run(async () => {
|
|
8209
|
-
const { readState, record, flush, grantSender, clearState } = await import("./trace-
|
|
8468
|
+
const { readState, record, flush, grantSender, clearState } = await import("./trace-OPRHOP2E.js");
|
|
8210
8469
|
const state = readState();
|
|
8211
8470
|
if (!state) throw new Error("no trace is running here");
|
|
8212
8471
|
if (state.root_span) record(() => [{ span_id: state.root_span, kind: "end", outcome: "completed" }]);
|
|
@@ -8216,7 +8475,7 @@ traceCmd.command("stop").description("end the root span, send what is left, and
|
|
|
8216
8475
|
console.log(`Stopped ${state.trace_id}${outcome.pending ? ` (${outcome.pending} events could not be sent)` : ""}`);
|
|
8217
8476
|
}));
|
|
8218
8477
|
traceCmd.command("sync [payload]").description("upload this machine's agent sessions (Claude Code, Codex, Cursor, Gemini CLI and every other agent `--agents` lists) to the matching workspace's trace library, redacted here first").option("--enable", "turn sync on for this machine").option("--disable", "turn sync off; nothing more is uploaded").option("--route <match=workspace>", "send sessions whose folder path contains <match> to <workspace> (repeatable; replaces the saved rules)", collect).option("--default <workspace>", "where a session no rule matches goes").option("--keep-local", "keep sessions no rule matches on this machine (the default)").option("--session <ref>", "only this session: its id or transcript path (repeatable)", collect).option("--import <export>", "add a downloaded cloud export (claude.ai, ChatGPT, Gemini, Grok, DeepSeek \u2026: its .zip, folder or file) so sync uploads it (repeatable)", collect).option("--agents", "list the agents sync reads and which are on this machine").option("--full", "re-read every session, not only files that changed").option("--limit <n>", "at most this many changed sessions this run", (v) => Number.parseInt(v, 10)).option("--dry-run", "show what would be uploaded without uploading").option("--hook", "run from a Claude Code SessionEnd hook or Codex notify: upload that session in the background and return at once").option("--install-schedule", "also sweep every 15 minutes (macOS launchd)").option("--status", "what sync has done on this machine").option("--quiet", "print only failures").action(async (payload, opts) => {
|
|
8219
|
-
const lib = await import("./trace-library-
|
|
8478
|
+
const lib = await import("./trace-library-SB7QYAU5.js");
|
|
8220
8479
|
if (opts.hook) {
|
|
8221
8480
|
try {
|
|
8222
8481
|
let raw = payload ?? "";
|
|
@@ -8288,11 +8547,11 @@ traceCmd.command("sync [payload]").description("upload this machine's agent sess
|
|
|
8288
8547
|
console.log(`Sweeping every 15 minutes (${plist}); a full re-read runs weekly. Log: ${log}`);
|
|
8289
8548
|
}
|
|
8290
8549
|
if (opts.status) {
|
|
8291
|
-
const { readFileSync:
|
|
8550
|
+
const { readFileSync: readFileSync21 } = await import("fs");
|
|
8292
8551
|
const { join: join20 } = await import("path");
|
|
8293
8552
|
let state = { sessions: {} };
|
|
8294
8553
|
try {
|
|
8295
|
-
state = JSON.parse(
|
|
8554
|
+
state = JSON.parse(readFileSync21(join20(lib.syncConfigPath(), "..", "trace-sync-state.json"), "utf8"));
|
|
8296
8555
|
} catch {
|
|
8297
8556
|
}
|
|
8298
8557
|
const counts = /* @__PURE__ */ new Map();
|
|
@@ -8331,7 +8590,7 @@ traceCmd.command("search <query...>").description("search every session in a wor
|
|
|
8331
8590
|
console.log(opts.json ? JSON.stringify(page, null, 2) : renderContextPage(page));
|
|
8332
8591
|
}));
|
|
8333
8592
|
traceCmd.command("library").description("list the sessions in a workspace's trace library, most recently updated first").option("--workspace <slug>", "the workspace (default: the current one)").option("--limit <n>", "how many", (v) => Number.parseInt(v, 10), 20).option("--json", "print the page as JSON").action(run(async (opts) => {
|
|
8334
|
-
const { libraryRequest } = await import("./trace-library-
|
|
8593
|
+
const { libraryRequest } = await import("./trace-library-SB7QYAU5.js");
|
|
8335
8594
|
const workspace2 = opts.workspace ?? currentUniverse();
|
|
8336
8595
|
if (!workspace2) throw new Error("name a workspace with --workspace");
|
|
8337
8596
|
const page = await libraryRequest("GET", `/trace-library?limit=${opts.limit}`, workspace2);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
USER_AGENT,
|
|
3
3
|
configPath
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-UZ7KWRQH.js";
|
|
5
5
|
import {
|
|
6
6
|
TRACE_CONTENT_SCOPES,
|
|
7
7
|
redactTraceText
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-CJBZVPDF.js";
|
|
9
9
|
import "./chunk-MLKGABMK.js";
|
|
10
10
|
|
|
11
11
|
// src/trace.ts
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ApiError
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-K3LB4K2C.js";
|
|
4
4
|
import {
|
|
5
5
|
USER_AGENT,
|
|
6
6
|
apiBase,
|
|
7
7
|
apiToken
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-UZ7KWRQH.js";
|
|
9
9
|
import {
|
|
10
10
|
SessionSourceCollector,
|
|
11
11
|
publicRemote,
|
|
12
12
|
redactTraceText
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-CJBZVPDF.js";
|
|
14
14
|
import "./chunk-MLKGABMK.js";
|
|
15
15
|
|
|
16
16
|
// src/trace-library.ts
|
package/package.json
CHANGED
|
File without changes
|