@agentsky/sky 2.11.0 → 2.12.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-7LUCHBX6.js +168 -0
- package/dist/{chunk-RWPPIEHH.js → chunk-RF5JICNX.js} +1 -1
- package/dist/{chunk-WC7GJSAJ.js → chunk-XXDQKVPS.js} +25 -3
- package/dist/index.js +154 -164
- package/dist/products.d.ts +6 -0
- package/dist/products.js +1 -1
- package/dist/{src-HVCP3PPM.js → src-S777KCS5.js} +20 -2
- package/dist/{trace-MPGQYXNR.js → trace-UJTFSXNM.js} +2 -2
- package/dist/trace-library-474QJTAZ.js +710 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
ApiError,
|
|
4
|
+
api,
|
|
5
|
+
apiBytes,
|
|
6
|
+
apiForm,
|
|
7
|
+
downloadFile,
|
|
8
|
+
postEvents,
|
|
9
|
+
resolveSessionRef,
|
|
10
|
+
streamEvents,
|
|
11
|
+
uploadFile
|
|
12
|
+
} from "./chunk-7LUCHBX6.js";
|
|
2
13
|
import {
|
|
3
14
|
CLI_VERSION,
|
|
4
15
|
USER_AGENT,
|
|
@@ -9,7 +20,7 @@ import {
|
|
|
9
20
|
currentUniverse,
|
|
10
21
|
loadConfig,
|
|
11
22
|
saveConfig
|
|
12
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-RF5JICNX.js";
|
|
13
24
|
import {
|
|
14
25
|
AGENT_TYPES,
|
|
15
26
|
MODEL_SUBSCRIPTION_PLAN_PHRASE,
|
|
@@ -28,7 +39,7 @@ import {
|
|
|
28
39
|
skillRefSchema,
|
|
29
40
|
splitMcpServers,
|
|
30
41
|
supersededBy
|
|
31
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-XXDQKVPS.js";
|
|
32
43
|
import "./chunk-MLKGABMK.js";
|
|
33
44
|
|
|
34
45
|
// src/index.ts
|
|
@@ -37,156 +48,6 @@ import { basename as basename4, resolve as resolve6 } from "path";
|
|
|
37
48
|
import { createInterface as createInterface4 } from "readline";
|
|
38
49
|
import { Command } from "commander";
|
|
39
50
|
|
|
40
|
-
// src/api.ts
|
|
41
|
-
var ApiError = class extends Error {
|
|
42
|
-
constructor(status, code, message2) {
|
|
43
|
-
super(message2);
|
|
44
|
-
this.status = status;
|
|
45
|
-
this.code = code;
|
|
46
|
-
}
|
|
47
|
-
status;
|
|
48
|
-
code;
|
|
49
|
-
};
|
|
50
|
-
function authHeaders() {
|
|
51
|
-
const token = apiToken();
|
|
52
|
-
if (!token) {
|
|
53
|
-
throw new ApiError(401, "not_logged_in", "not logged in \u2014 run `sky auth login`");
|
|
54
|
-
}
|
|
55
|
-
const headers = { authorization: `Bearer ${token}` };
|
|
56
|
-
const universe2 = currentUniverse();
|
|
57
|
-
if (universe2) headers["x-universe"] = universe2;
|
|
58
|
-
return headers;
|
|
59
|
-
}
|
|
60
|
-
async function parseError(res) {
|
|
61
|
-
let code = "http_error";
|
|
62
|
-
let message2 = `${res.status} ${res.statusText}`;
|
|
63
|
-
try {
|
|
64
|
-
const body = await res.json();
|
|
65
|
-
if (body.error?.message) {
|
|
66
|
-
code = body.error.code ?? code;
|
|
67
|
-
message2 = body.error.message;
|
|
68
|
-
}
|
|
69
|
-
} catch {
|
|
70
|
-
}
|
|
71
|
-
throw new ApiError(res.status, code, message2);
|
|
72
|
-
}
|
|
73
|
-
async function api(method, path, body, opts = {}) {
|
|
74
|
-
const res = await fetch(`${apiBase()}${path}`, {
|
|
75
|
-
method,
|
|
76
|
-
headers: {
|
|
77
|
-
"user-agent": USER_AGENT,
|
|
78
|
-
...opts.auth === false ? {} : authHeaders(),
|
|
79
|
-
...body !== void 0 ? { "content-type": "application/json" } : {},
|
|
80
|
-
...opts.idempotencyKey ? { "idempotency-key": opts.idempotencyKey } : {}
|
|
81
|
-
},
|
|
82
|
-
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
83
|
-
});
|
|
84
|
-
if (!res.ok) await parseError(res);
|
|
85
|
-
if (res.status === 204) return void 0;
|
|
86
|
-
return await res.json();
|
|
87
|
-
}
|
|
88
|
-
async function postEvents(sessionId, events, idempotencyKey) {
|
|
89
|
-
const res = await fetch(`${apiBase()}/sessions/${encodeURIComponent(sessionId)}/events`, {
|
|
90
|
-
method: "POST",
|
|
91
|
-
headers: {
|
|
92
|
-
"user-agent": USER_AGENT,
|
|
93
|
-
...authHeaders(),
|
|
94
|
-
"content-type": "application/json",
|
|
95
|
-
...idempotencyKey ? { "idempotency-key": idempotencyKey } : {}
|
|
96
|
-
},
|
|
97
|
-
body: JSON.stringify({ events })
|
|
98
|
-
});
|
|
99
|
-
if (!res.ok) await parseError(res);
|
|
100
|
-
return await res.json();
|
|
101
|
-
}
|
|
102
|
-
async function uploadFile(bytes, filename, mediaType, expiresInSeconds) {
|
|
103
|
-
const form = new FormData();
|
|
104
|
-
form.append("file", new Blob([new Uint8Array(bytes)], { type: mediaType }), filename);
|
|
105
|
-
if (expiresInSeconds) form.append("expires_in_seconds", String(expiresInSeconds));
|
|
106
|
-
const res = await fetch(`${apiBase()}/files`, {
|
|
107
|
-
method: "POST",
|
|
108
|
-
headers: { "user-agent": USER_AGENT, ...authHeaders() },
|
|
109
|
-
body: form
|
|
110
|
-
});
|
|
111
|
-
if (!res.ok) await parseError(res);
|
|
112
|
-
return await res.json();
|
|
113
|
-
}
|
|
114
|
-
async function apiForm(method, path, form) {
|
|
115
|
-
const res = await fetch(`${apiBase()}${path}`, {
|
|
116
|
-
method,
|
|
117
|
-
headers: { "user-agent": USER_AGENT, ...authHeaders() },
|
|
118
|
-
body: form
|
|
119
|
-
});
|
|
120
|
-
if (!res.ok) await parseError(res);
|
|
121
|
-
return await res.json();
|
|
122
|
-
}
|
|
123
|
-
async function downloadFile(fileId) {
|
|
124
|
-
const res = await fetch(`${apiBase()}/files/${encodeURIComponent(fileId)}/content`, {
|
|
125
|
-
headers: { "user-agent": USER_AGENT, ...authHeaders() }
|
|
126
|
-
});
|
|
127
|
-
if (!res.ok) await parseError(res);
|
|
128
|
-
return { bytes: new Uint8Array(await res.arrayBuffer()), mediaType: res.headers.get("content-type") ?? "application/octet-stream" };
|
|
129
|
-
}
|
|
130
|
-
async function apiBytes(method, path, body) {
|
|
131
|
-
const res = await fetch(`${apiBase()}${path}`, {
|
|
132
|
-
method,
|
|
133
|
-
headers: {
|
|
134
|
-
"user-agent": USER_AGENT,
|
|
135
|
-
...authHeaders(),
|
|
136
|
-
...body ? { "content-type": body.mediaType } : {}
|
|
137
|
-
},
|
|
138
|
-
body: body ? new Uint8Array(body.bytes) : void 0
|
|
139
|
-
});
|
|
140
|
-
if (!res.ok) await parseError(res);
|
|
141
|
-
const bytes = new Uint8Array(await res.arrayBuffer());
|
|
142
|
-
return {
|
|
143
|
-
bytes,
|
|
144
|
-
mediaType: res.headers.get("content-type") ?? "application/octet-stream",
|
|
145
|
-
json: () => JSON.parse(new TextDecoder().decode(bytes))
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
async function resolveSessionRef(ref) {
|
|
149
|
-
if (ref.startsWith("sess-")) return ref;
|
|
150
|
-
const { agent: agent2 } = await api(
|
|
151
|
-
"GET",
|
|
152
|
-
`/agents/${encodeURIComponent(ref)}`
|
|
153
|
-
).catch(async () => {
|
|
154
|
-
await api("GET", `/sessions/${encodeURIComponent(ref)}`);
|
|
155
|
-
return { agent: { id: ref, defaultSessionId: ref } };
|
|
156
|
-
});
|
|
157
|
-
if (!agent2.defaultSessionId) {
|
|
158
|
-
throw new ApiError(
|
|
159
|
-
404,
|
|
160
|
-
"no_sessions",
|
|
161
|
-
`agent ${agent2.id} has no sessions \u2014 create one: sky session create ${agent2.id}`
|
|
162
|
-
);
|
|
163
|
-
}
|
|
164
|
-
return agent2.defaultSessionId;
|
|
165
|
-
}
|
|
166
|
-
async function* streamEvents(sessionId, signal) {
|
|
167
|
-
const { parseSseStream } = await import("./src-HVCP3PPM.js");
|
|
168
|
-
const res = await fetch(
|
|
169
|
-
`${apiBase()}/sessions/${encodeURIComponent(sessionId)}/stream`,
|
|
170
|
-
{
|
|
171
|
-
headers: { "user-agent": USER_AGENT, ...authHeaders(), accept: "text/event-stream" },
|
|
172
|
-
signal
|
|
173
|
-
}
|
|
174
|
-
);
|
|
175
|
-
if (!res.ok) await parseError(res);
|
|
176
|
-
if (!res.body) throw new ApiError(502, "no_body", "stream returned no body");
|
|
177
|
-
try {
|
|
178
|
-
for await (const frame of parseSseStream(res.body)) {
|
|
179
|
-
if (!frame.data) continue;
|
|
180
|
-
try {
|
|
181
|
-
yield { id: frame.id, event: frame.event, data: JSON.parse(frame.data) };
|
|
182
|
-
} catch {
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
} catch (error) {
|
|
186
|
-
if (!(error instanceof DOMException && error.name === "AbortError")) throw error;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
51
|
// src/files.ts
|
|
191
52
|
import { readFileSync } from "fs";
|
|
192
53
|
import { basename, extname } from "path";
|
|
@@ -1511,7 +1372,7 @@ at the end; they do the same things, one agent at a time.
|
|
|
1511
1372
|
|
|
1512
1373
|
Use the workspace the person named. If they named none, check the git root for
|
|
1513
1374
|
\`.agentsky.json\` \u2014 if it has a \`"workspace"\` key, use that. Otherwise use the
|
|
1514
|
-
account default
|
|
1375
|
+
account default workspace. Never ask. Pass the chosen slug as \`workspace\` on
|
|
1515
1376
|
every MCP tool that accepts it, or as \`--workspace <slug>\` on sky commands.
|
|
1516
1377
|
Details: \`${REFERENCES_DIR}/workspaces.md\` in this skill's folder.
|
|
1517
1378
|
|
|
@@ -2990,7 +2851,7 @@ auth.command("whoami").description("who the current token acts as").action(
|
|
|
2990
2851
|
run(async () => {
|
|
2991
2852
|
const who = await api("GET", "/whoami");
|
|
2992
2853
|
console.log(
|
|
2993
|
-
`${who.user.email ?? "unknown"} \xB7 universe ${who.universe.slug}${who.universe.isPersonal ? " (
|
|
2854
|
+
`${who.user.email ?? "unknown"} \xB7 universe ${who.universe.slug}${who.universe.isPersonal ? " (default)" : ""} \xB7 scopes ${who.scopes.join(",")}`
|
|
2994
2855
|
);
|
|
2995
2856
|
})
|
|
2996
2857
|
);
|
|
@@ -3010,7 +2871,7 @@ universe.command("list").action(
|
|
|
3010
2871
|
const current = currentUniverse();
|
|
3011
2872
|
for (const u of universes) {
|
|
3012
2873
|
const marker = u.slug === current || !current && u.isPersonal ? "*" : " ";
|
|
3013
|
-
console.log(`${marker} ${u.slug}${u.isPersonal ? " (
|
|
2874
|
+
console.log(`${marker} ${u.slug}${u.isPersonal ? " (default)" : ""}`);
|
|
3014
2875
|
}
|
|
3015
2876
|
})
|
|
3016
2877
|
);
|
|
@@ -3036,7 +2897,7 @@ universe.command("show").action(
|
|
|
3036
2897
|
console.log(`${u.slug} \u2014 ${u.name} \xB7 ${u.agents} agents \xB7 ${u.members} members`);
|
|
3037
2898
|
} else {
|
|
3038
2899
|
const who = await api("GET", path);
|
|
3039
|
-
console.log(`${who.universe.slug} (
|
|
2900
|
+
console.log(`${who.universe.slug} (default)`);
|
|
3040
2901
|
}
|
|
3041
2902
|
})
|
|
3042
2903
|
);
|
|
@@ -3084,7 +2945,7 @@ workspace.command("list").action(
|
|
|
3084
2945
|
const current = currentUniverse();
|
|
3085
2946
|
for (const u of universes) {
|
|
3086
2947
|
const marker = u.slug === current || !current && u.isPersonal ? "*" : " ";
|
|
3087
|
-
console.log(`${marker} ${u.slug}${u.isPersonal ? " (
|
|
2948
|
+
console.log(`${marker} ${u.slug}${u.isPersonal ? " (default)" : ""}`);
|
|
3088
2949
|
}
|
|
3089
2950
|
})
|
|
3090
2951
|
);
|
|
@@ -4096,7 +3957,7 @@ program.command("config").description("show the CLI config location and current
|
|
|
4096
3957
|
console.log(`config: ${configPath()}`);
|
|
4097
3958
|
console.log(` apiBase: ${config.apiBase ?? "(default)"}`);
|
|
4098
3959
|
console.log(` token: ${config.token ? `${config.token.slice(0, 10)}\u2026` : "(none)"}`);
|
|
4099
|
-
console.log(` universe: ${config.currentUniverse ?? "(
|
|
3960
|
+
console.log(` universe: ${config.currentUniverse ?? "(default)"}`);
|
|
4100
3961
|
});
|
|
4101
3962
|
var harness = program.command("harness").description("workspace harnesses: init, verify, push");
|
|
4102
3963
|
harness.command("init [dir]").description("write a harness.json profile skeleton in the given directory (default: .)").action(run(async (dir) => {
|
|
@@ -4121,7 +3982,7 @@ harness.command("connect").description("run an ACP agent (the command after --)
|
|
|
4121
3982
|
}));
|
|
4122
3983
|
var traceCmd = program.command("trace").description("correlate this machine's agent work with the cloud sessions it starts (metadata only unless you choose content)");
|
|
4123
3984
|
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) => {
|
|
4124
|
-
const { readState, writeState, record, installClaudeHooks, parseContentScopes, chosenPaths, fileEvent } = await import("./trace-
|
|
3985
|
+
const { readState, writeState, record, installClaudeHooks, parseContentScopes, chosenPaths, fileEvent } = await import("./trace-UJTFSXNM.js");
|
|
4125
3986
|
if (readState()) throw new Error("a trace is already running here \u2014 `sky trace stop` it first");
|
|
4126
3987
|
const scopes = parseContentScopes(opts.capture);
|
|
4127
3988
|
const chosen = chosenPaths(opts.file ?? [], opts.dir ?? []);
|
|
@@ -4156,7 +4017,7 @@ traceCmd.command("start").description("start a trace: a grant for this machine,
|
|
|
4156
4017
|
}));
|
|
4157
4018
|
traceCmd.command("hook").description("record one Claude Code hook event read from stdin (run by the installed hooks; never fails, prints nothing)").action(async () => {
|
|
4158
4019
|
try {
|
|
4159
|
-
const { readState, record, flush, grantSender, eventsForClaudeHook, contentForClaudeHook, clearState } = await import("./trace-
|
|
4020
|
+
const { readState, record, flush, grantSender, eventsForClaudeHook, contentForClaudeHook, clearState } = await import("./trace-UJTFSXNM.js");
|
|
4160
4021
|
const chunks = [];
|
|
4161
4022
|
for await (const chunk of process.stdin) chunks.push(chunk);
|
|
4162
4023
|
const input = JSON.parse(Buffer.concat(chunks).toString("utf8") || "{}");
|
|
@@ -4169,14 +4030,14 @@ traceCmd.command("hook").description("record one Claude Code hook event read fro
|
|
|
4169
4030
|
}
|
|
4170
4031
|
});
|
|
4171
4032
|
traceCmd.command("flush").description("send what the spool holds, retrying with backoff").action(run(async () => {
|
|
4172
|
-
const { readState, flush, grantSender } = await import("./trace-
|
|
4033
|
+
const { readState, flush, grantSender } = await import("./trace-UJTFSXNM.js");
|
|
4173
4034
|
const state = readState();
|
|
4174
4035
|
if (!state) throw new Error("no trace is running here");
|
|
4175
4036
|
const outcome = await flush(grantSender(state), { attempts: 4 });
|
|
4176
4037
|
console.log(`sent ${outcome.sent}, refused ${outcome.refused}, given up ${outcome.expired}, still pending ${outcome.pending}${outcome.stopped ? ` (stopped: ${outcome.stopped})` : ""}`);
|
|
4177
4038
|
}));
|
|
4178
4039
|
traceCmd.command("status").description("the running trace and its spool").action(run(async () => {
|
|
4179
|
-
const { readState, spoolStatus } = await import("./trace-
|
|
4040
|
+
const { readState, spoolStatus } = await import("./trace-UJTFSXNM.js");
|
|
4180
4041
|
const state = readState();
|
|
4181
4042
|
if (!state) {
|
|
4182
4043
|
console.log("No trace is running here.");
|
|
@@ -4186,7 +4047,7 @@ traceCmd.command("status").description("the running trace and its spool").action
|
|
|
4186
4047
|
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`);
|
|
4187
4048
|
}));
|
|
4188
4049
|
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) => {
|
|
4189
|
-
const { readState } = await import("./trace-
|
|
4050
|
+
const { readState } = await import("./trace-UJTFSXNM.js");
|
|
4190
4051
|
const ref = id ?? readState()?.trace_id;
|
|
4191
4052
|
if (!ref) throw new Error("name a trace, or start one here");
|
|
4192
4053
|
const bundle = await api("GET", `/traces/${ref}`);
|
|
@@ -4213,7 +4074,7 @@ traceCmd.command("show [id]").description("the trace bundle: spans, the sessions
|
|
|
4213
4074
|
for (const gap of bundle.gaps) console.log(` gap: ${gap.span_id} ${gap.reason}`);
|
|
4214
4075
|
}));
|
|
4215
4076
|
traceCmd.command("stop").description("end the root span, send what is left, and revoke this machine's grant").action(run(async () => {
|
|
4216
|
-
const { readState, record, flush, grantSender, clearState } = await import("./trace-
|
|
4077
|
+
const { readState, record, flush, grantSender, clearState } = await import("./trace-UJTFSXNM.js");
|
|
4217
4078
|
const state = readState();
|
|
4218
4079
|
if (!state) throw new Error("no trace is running here");
|
|
4219
4080
|
if (state.root_span) record(() => [{ span_id: state.root_span, kind: "end", outcome: "completed" }]);
|
|
@@ -4222,6 +4083,135 @@ traceCmd.command("stop").description("end the root span, send what is left, and
|
|
|
4222
4083
|
clearState();
|
|
4223
4084
|
console.log(`Stopped ${state.trace_id}${outcome.pending ? ` (${outcome.pending} events could not be sent)` : ""}`);
|
|
4224
4085
|
}));
|
|
4086
|
+
traceCmd.command("sync [payload]").description("upload this machine's Claude Code and Codex sessions 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("--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) => {
|
|
4087
|
+
const lib = await import("./trace-library-474QJTAZ.js");
|
|
4088
|
+
if (opts.hook) {
|
|
4089
|
+
try {
|
|
4090
|
+
let raw = payload ?? "";
|
|
4091
|
+
if (!raw && !process.stdin.isTTY) {
|
|
4092
|
+
const chunks = [];
|
|
4093
|
+
for await (const chunk of process.stdin) chunks.push(chunk);
|
|
4094
|
+
raw = Buffer.concat(chunks).toString("utf8");
|
|
4095
|
+
}
|
|
4096
|
+
if (!lib.loadSyncConfig().enabled) return;
|
|
4097
|
+
const ref = lib.hookSessionRef(raw);
|
|
4098
|
+
const { spawn: spawn4 } = await import("child_process");
|
|
4099
|
+
spawn4(process.execPath, [process.argv[1], "trace", "sync", "--quiet", ...ref ? ["--session", ref] : []], { detached: true, stdio: "ignore" }).unref();
|
|
4100
|
+
} catch {
|
|
4101
|
+
}
|
|
4102
|
+
return;
|
|
4103
|
+
}
|
|
4104
|
+
await run(async () => {
|
|
4105
|
+
const config = lib.loadSyncConfig();
|
|
4106
|
+
if (opts.disable) {
|
|
4107
|
+
lib.saveSyncConfig({ ...config, enabled: false });
|
|
4108
|
+
console.log("Trace sync is off on this machine. Uploaded traces stay in their workspaces until deleted there.");
|
|
4109
|
+
return;
|
|
4110
|
+
}
|
|
4111
|
+
const changedSettings = opts.enable || opts.route || opts.default || opts.keepLocal;
|
|
4112
|
+
if (changedSettings) {
|
|
4113
|
+
if (opts.enable && !apiToken()) throw new Error("not logged in \u2014 run `sky auth login` first");
|
|
4114
|
+
const rules = opts.route ? opts.route.map((spec) => {
|
|
4115
|
+
const at = spec.lastIndexOf("=");
|
|
4116
|
+
if (at <= 0 || at === spec.length - 1) throw new Error(`--route takes match=workspace, got "${spec}"`);
|
|
4117
|
+
return { match: spec.slice(0, at), workspace: spec.slice(at + 1) };
|
|
4118
|
+
}) : config.rules;
|
|
4119
|
+
const next = {
|
|
4120
|
+
...config,
|
|
4121
|
+
rules,
|
|
4122
|
+
enabled: opts.enable ? true : config.enabled,
|
|
4123
|
+
enabledAt: opts.enable ? (/* @__PURE__ */ new Date()).toISOString() : config.enabledAt,
|
|
4124
|
+
fallback: opts.keepLocal ? void 0 : opts.default ?? config.fallback
|
|
4125
|
+
};
|
|
4126
|
+
lib.saveSyncConfig(next);
|
|
4127
|
+
console.log(`Trace sync is ${next.enabled ? "on" : "off"} on this machine. It reads only:`);
|
|
4128
|
+
for (const folder of lib.sourceFolders()) console.log(` ${folder}`);
|
|
4129
|
+
console.log("and sends each session, redacted here first, to:");
|
|
4130
|
+
for (const rule of next.rules) console.log(` folder path contains "${rule.match}" \u2192 ${rule.workspace}`);
|
|
4131
|
+
console.log(` anything else \u2192 ${next.fallback ?? "stays on this machine"}`);
|
|
4132
|
+
console.log(`A repository's .agentsky.json "workspace" wins over these rules.`);
|
|
4133
|
+
}
|
|
4134
|
+
if (opts.installSchedule) {
|
|
4135
|
+
const { join: join10 } = await import("path");
|
|
4136
|
+
const { homedir: homedir6 } = await import("os");
|
|
4137
|
+
const { execFileSync } = await import("child_process");
|
|
4138
|
+
const log = join10(homedir6(), ".config", "sky", "trace-sync.log");
|
|
4139
|
+
const plist = lib.installLaunchd([process.execPath, process.argv[1], "trace", "sync", "--quiet"], log);
|
|
4140
|
+
try {
|
|
4141
|
+
execFileSync("launchctl", ["unload", plist], { stdio: "ignore" });
|
|
4142
|
+
} catch {
|
|
4143
|
+
}
|
|
4144
|
+
execFileSync("launchctl", ["load", plist]);
|
|
4145
|
+
console.log(`Sweeping every 15 minutes (${plist}); a full re-read runs weekly. Log: ${log}`);
|
|
4146
|
+
}
|
|
4147
|
+
if (opts.status) {
|
|
4148
|
+
const { readFileSync: readFileSync12 } = await import("fs");
|
|
4149
|
+
const { join: join10 } = await import("path");
|
|
4150
|
+
let state = { sessions: {} };
|
|
4151
|
+
try {
|
|
4152
|
+
state = JSON.parse(readFileSync12(join10(lib.syncConfigPath(), "..", "trace-sync-state.json"), "utf8"));
|
|
4153
|
+
} catch {
|
|
4154
|
+
}
|
|
4155
|
+
const counts = /* @__PURE__ */ new Map();
|
|
4156
|
+
for (const entry2 of Object.values(state.sessions)) {
|
|
4157
|
+
const label = entry2.status === "stored" ? `stored in ${entry2.workspace}` : entry2.status;
|
|
4158
|
+
counts.set(label, (counts.get(label) ?? 0) + 1);
|
|
4159
|
+
}
|
|
4160
|
+
console.log(`Trace sync is ${config.enabled ? "on" : "off"}${config.enabledAt ? ` (since ${config.enabledAt})` : ""}. Last full sweep: ${state.lastFullAt ?? "never"}.`);
|
|
4161
|
+
for (const [label, count] of [...counts].sort((a, b) => b[1] - a[1])) console.log(` ${count} ${label}`);
|
|
4162
|
+
return;
|
|
4163
|
+
}
|
|
4164
|
+
if (changedSettings && !opts.full && !opts.session) return;
|
|
4165
|
+
const report = await lib.syncTraces({
|
|
4166
|
+
full: opts.full,
|
|
4167
|
+
only: opts.session,
|
|
4168
|
+
dryRun: opts.dryRun,
|
|
4169
|
+
limit: opts.limit,
|
|
4170
|
+
onProgress: opts.quiet ? void 0 : (line) => console.log(line)
|
|
4171
|
+
});
|
|
4172
|
+
if (!report) {
|
|
4173
|
+
if (!opts.quiet) console.log("Another sync is running on this machine; it will pick these up.");
|
|
4174
|
+
return;
|
|
4175
|
+
}
|
|
4176
|
+
if (!opts.quiet || report.failed) {
|
|
4177
|
+
const where = Object.entries(report.byWorkspace).map(([workspace2, count]) => `${count} \u2192 ${workspace2}`).join(", ");
|
|
4178
|
+
console.log(`${opts.dryRun ? "Would upload" : "Uploaded"} ${report.uploaded}${where ? ` (${where})` : ""}; unchanged ${report.unchanged}; kept local ${report.local}; empty ${report.empty}; another member's ${report.owned}; failed ${report.failed}. Scanned ${report.scanned}, ${report.changed} changed.`);
|
|
4179
|
+
for (const error of report.errors.slice(0, 20)) console.error(` ${error}`);
|
|
4180
|
+
}
|
|
4181
|
+
if (report.failed) process.exitCode = 1;
|
|
4182
|
+
})();
|
|
4183
|
+
});
|
|
4184
|
+
traceCmd.command("search <query...>").description("search every session in a workspace's trace library (literal substring)").option("--workspace <slug>", "the workspace to search (default: the current one)").option("--limit <n>", "hits per page", (v) => Number.parseInt(v, 10), 20).option("--cursor <cursor>", "the next page of an earlier search").option("--json", "print the page as JSON").action(run(async (words, opts) => {
|
|
4185
|
+
const { libraryRequest } = await import("./trace-library-474QJTAZ.js");
|
|
4186
|
+
const workspace2 = opts.workspace ?? currentUniverse();
|
|
4187
|
+
if (!workspace2) throw new Error("name a workspace with --workspace");
|
|
4188
|
+
const params = new URLSearchParams({ q: words.join(" "), scope: "traces", limit: String(opts.limit), ...opts.cursor ? { cursor: opts.cursor } : {} });
|
|
4189
|
+
const page = await libraryRequest("GET", `/context/search?${params}`, workspace2);
|
|
4190
|
+
if (opts.json) {
|
|
4191
|
+
console.log(JSON.stringify(page, null, 2));
|
|
4192
|
+
return;
|
|
4193
|
+
}
|
|
4194
|
+
if (!page.hits.length) console.log(page.partial ? `No hits, but the search was cut short (${page.coverage}).` : "No hits.");
|
|
4195
|
+
for (const { hit } of page.hits) {
|
|
4196
|
+
console.log(`${hit.occurredAt?.slice(0, 16).replace("T", " ") ?? " "} ${hit.title}`);
|
|
4197
|
+
console.log(` ${hit.snippet.replace(/\s+/g, " ")}`);
|
|
4198
|
+
}
|
|
4199
|
+
if (page.nextCursor) console.log(`More: sky trace search ${JSON.stringify(words.join(" "))} --workspace ${workspace2} --cursor ${page.nextCursor}`);
|
|
4200
|
+
}));
|
|
4201
|
+
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) => {
|
|
4202
|
+
const { libraryRequest } = await import("./trace-library-474QJTAZ.js");
|
|
4203
|
+
const workspace2 = opts.workspace ?? currentUniverse();
|
|
4204
|
+
if (!workspace2) throw new Error("name a workspace with --workspace");
|
|
4205
|
+
const page = await libraryRequest("GET", `/trace-library?limit=${opts.limit}`, workspace2);
|
|
4206
|
+
if (opts.json) {
|
|
4207
|
+
console.log(JSON.stringify(page, null, 2));
|
|
4208
|
+
return;
|
|
4209
|
+
}
|
|
4210
|
+
console.log(`${page.total} sessions in ${workspace2}'s trace library`);
|
|
4211
|
+
for (const trace of page.traces) {
|
|
4212
|
+
console.log(`${trace.updated_at.slice(0, 16).replace("T", " ")} ${trace.harness.padEnd(11)} ${(trace.project ?? "").padEnd(16)} ${String(trace.messages).padStart(5)} msgs ${trace.title ?? trace.session_id}`);
|
|
4213
|
+
}
|
|
4214
|
+
}));
|
|
4225
4215
|
var workerCmd = program.command("worker").description("run a pod on this machine and connect it to a worker pool");
|
|
4226
4216
|
workerCmd.command("start <pool>").description("start a worker connected to the given pool (wpool_\u2026 id)").option("--token <token>", "bearer token (default: $SKY_WORKER_TOKEN)").option("--label <label>", "a human-readable name for this machine", "cli").action(async (poolId, options) => {
|
|
4227
4217
|
const { startWorker } = await import("./worker-6Q4K4HZW.js");
|
package/dist/products.d.ts
CHANGED
|
@@ -95,6 +95,8 @@ declare const agentAddonsSchema: z.ZodObject<{
|
|
|
95
95
|
"meta.transcribe": "meta.transcribe";
|
|
96
96
|
"minimax.tts": "minimax.tts";
|
|
97
97
|
"elevenlabs.sound": "elevenlabs.sound";
|
|
98
|
+
"elevenlabs.tts": "elevenlabs.tts";
|
|
99
|
+
"elevenlabs.music": "elevenlabs.music";
|
|
98
100
|
"zai.transcribe": "zai.transcribe";
|
|
99
101
|
"openai.transcribe": "openai.transcribe";
|
|
100
102
|
"fish-audio.tts": "fish-audio.tts";
|
|
@@ -235,6 +237,8 @@ declare const createProductAgentSchema: z.ZodObject<{
|
|
|
235
237
|
"meta.transcribe": "meta.transcribe";
|
|
236
238
|
"minimax.tts": "minimax.tts";
|
|
237
239
|
"elevenlabs.sound": "elevenlabs.sound";
|
|
240
|
+
"elevenlabs.tts": "elevenlabs.tts";
|
|
241
|
+
"elevenlabs.music": "elevenlabs.music";
|
|
238
242
|
"zai.transcribe": "zai.transcribe";
|
|
239
243
|
"openai.transcribe": "openai.transcribe";
|
|
240
244
|
"fish-audio.tts": "fish-audio.tts";
|
|
@@ -375,6 +379,8 @@ declare const prepareProductSessionSchema: z.ZodObject<{
|
|
|
375
379
|
"meta.transcribe": "meta.transcribe";
|
|
376
380
|
"minimax.tts": "minimax.tts";
|
|
377
381
|
"elevenlabs.sound": "elevenlabs.sound";
|
|
382
|
+
"elevenlabs.tts": "elevenlabs.tts";
|
|
383
|
+
"elevenlabs.music": "elevenlabs.music";
|
|
378
384
|
"zai.transcribe": "zai.transcribe";
|
|
379
385
|
"openai.transcribe": "openai.transcribe";
|
|
380
386
|
"fish-audio.tts": "fish-audio.tts";
|
package/dist/products.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
external_exports,
|
|
3
3
|
messagePartSchema
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-XXDQKVPS.js";
|
|
5
5
|
import "./chunk-MLKGABMK.js";
|
|
6
6
|
|
|
7
7
|
// ../../packages/chat/src/stream.ts
|
|
@@ -97,6 +97,16 @@ var internalEventSchema = external_exports.object({
|
|
|
97
97
|
* session.deleted) — emitted verbatim; the host already persisted it. */
|
|
98
98
|
lifecycle: external_exports.object({ id: external_exports.string().min(1), type: external_exports.string().min(1) }).passthrough().optional()
|
|
99
99
|
});
|
|
100
|
+
function personalContextForPod(body, supported) {
|
|
101
|
+
const { personal_context: grant, ...rest } = body;
|
|
102
|
+
if (!grant || supported) return body;
|
|
103
|
+
const text = `This runtime cannot receive the private personal-context credential file. Use this value instead, as X-Personal-Context on memory and context API requests and as ACTL_PERSONAL_CONTEXT for actl grep: ${grant}. Never print, persist or share it.`;
|
|
104
|
+
const parts = [...rest.parts, { type: "text", index: Math.max(-1, ...rest.parts.map((part) => part.index)) + 1, text }];
|
|
105
|
+
if (!rest.events) return { ...rest, parts };
|
|
106
|
+
const previous = rest.events.find((event) => event.type === "system.message");
|
|
107
|
+
const system = { type: "system.message", content: [{ type: "text", text: [...previous?.type === "system.message" ? previous.content.map((block) => block.text) : [], text].join("\n\n") }] };
|
|
108
|
+
return { ...rest, parts, events: [...rest.events.filter((event) => event.type !== "system.message"), system] };
|
|
109
|
+
}
|
|
100
110
|
function podMessageBody(messageId, turn, resourcesRevision = 0) {
|
|
101
111
|
if ("events" in turn) {
|
|
102
112
|
const envelope = {
|
|
@@ -144,6 +154,7 @@ function classifyPodSendStatus(status, detail) {
|
|
|
144
154
|
if (status >= 500) return { kind: "uncertain", reason: "server_error", status, detail };
|
|
145
155
|
return { kind: "rejected", status, detail };
|
|
146
156
|
}
|
|
157
|
+
var PERSONAL_CONTEXT_PODS = /* @__PURE__ */ new Set();
|
|
147
158
|
async function sendPodMessage(baseUrl, body, options = {}) {
|
|
148
159
|
const headers = {
|
|
149
160
|
"content-type": "application/json",
|
|
@@ -152,6 +163,11 @@ async function sendPodMessage(baseUrl, body, options = {}) {
|
|
|
152
163
|
if (options.idempotencyKey) headers["idempotency-key"] = options.idempotencyKey;
|
|
153
164
|
let res;
|
|
154
165
|
try {
|
|
166
|
+
if (body.personal_context && !PERSONAL_CONTEXT_PODS.has(baseUrl)) {
|
|
167
|
+
const health = await getPodHealth(baseUrl, options);
|
|
168
|
+
if (health.personalContext) PERSONAL_CONTEXT_PODS.add(baseUrl);
|
|
169
|
+
else if (health.ok) body = personalContextForPod(body, false);
|
|
170
|
+
}
|
|
155
171
|
const user = body.events?.find((event) => event.type === "user.message");
|
|
156
172
|
const mode = user?.type === "user.message" ? user.interaction_mode : body.interaction_mode;
|
|
157
173
|
if (mode) {
|
|
@@ -197,7 +213,8 @@ async function getPodHealth(baseUrl, options = {}) {
|
|
|
197
213
|
status: res.status,
|
|
198
214
|
state: typeof body.state === "string" ? body.state : void 0,
|
|
199
215
|
openMessageId: typeof open === "string" && open ? open : null,
|
|
200
|
-
interactionModes: Array.isArray(body.interaction_modes) ? body.interaction_modes.filter((mode) => mode === "plan" || mode === "build") : void 0
|
|
216
|
+
interactionModes: Array.isArray(body.interaction_modes) ? body.interaction_modes.filter((mode) => mode === "plan" || mode === "build") : void 0,
|
|
217
|
+
personalContext: body.personal_context === true
|
|
201
218
|
};
|
|
202
219
|
} catch {
|
|
203
220
|
return { ok: false, openMessageId: null };
|
|
@@ -295,6 +312,7 @@ export {
|
|
|
295
312
|
interruptSession,
|
|
296
313
|
legacyPartsOf,
|
|
297
314
|
parseSseStream,
|
|
315
|
+
personalContextForPod,
|
|
298
316
|
podMessageBody,
|
|
299
317
|
postSessionEvents,
|
|
300
318
|
sendPodMessage,
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
USER_AGENT,
|
|
3
3
|
configPath
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-RF5JICNX.js";
|
|
5
5
|
import {
|
|
6
6
|
TRACE_CONTENT_SCOPES,
|
|
7
7
|
redactTraceText
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-XXDQKVPS.js";
|
|
9
9
|
import "./chunk-MLKGABMK.js";
|
|
10
10
|
|
|
11
11
|
// src/trace.ts
|