@usecontextlayer/ctxs 0.5.4 → 0.5.6
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/cli.mjs +531 -111
- package/dist/cli.mjs.map +1 -1
- package/package.json +4 -3
package/dist/cli.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="
|
|
3
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="3dbc3cff-70da-5d01-b6fc-a83d63e0c3f3")}catch(e){}}();
|
|
4
4
|
import { createRequire } from "node:module";
|
|
5
5
|
import * as Sentry from "@sentry/node";
|
|
6
6
|
import * as fs$2 from "node:fs/promises";
|
|
@@ -8,8 +8,6 @@ import { access, mkdir, mkdtemp, open, readFile, readdir, realpath, rename, rm,
|
|
|
8
8
|
import path, { sep } from "node:path";
|
|
9
9
|
import { execFile } from "node:child_process";
|
|
10
10
|
import { formatWithOptions, promisify } from "node:util";
|
|
11
|
-
import { existsSync } from "node:fs";
|
|
12
|
-
import { fileURLToPath } from "node:url";
|
|
13
11
|
import { serve } from "@hono/node-server";
|
|
14
12
|
import { createNodeWebSocket } from "@hono/node-ws";
|
|
15
13
|
import { Hono } from "hono";
|
|
@@ -25,6 +23,8 @@ import tls from "tls";
|
|
|
25
23
|
import crypto$1 from "crypto";
|
|
26
24
|
import Stream from "stream";
|
|
27
25
|
import { performance } from "perf_hooks";
|
|
26
|
+
import { existsSync } from "node:fs";
|
|
27
|
+
import { fileURLToPath } from "node:url";
|
|
28
28
|
import { getSessionMessages } from "@anthropic-ai/claude-agent-sdk";
|
|
29
29
|
import { query } from "@anthropic-ai/claude-agent-sdk/browser";
|
|
30
30
|
import g$1 from "node:process";
|
|
@@ -60,7 +60,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
|
60
60
|
|
|
61
61
|
//#endregion
|
|
62
62
|
//#region package.json
|
|
63
|
-
var version$2 = "0.5.
|
|
63
|
+
var version$2 = "0.5.6";
|
|
64
64
|
|
|
65
65
|
//#endregion
|
|
66
66
|
//#region sentry.ts
|
|
@@ -264,13 +264,21 @@ async function cloneRepo(repo) {
|
|
|
264
264
|
], { auth: repo.remote });
|
|
265
265
|
}
|
|
266
266
|
/**
|
|
267
|
-
* Snapshot the working dir to pggit: `add -A` -> commit -> `push
|
|
267
|
+
* Snapshot the working dir to pggit: `add -A` -> commit -> plain `push`. A no-op if
|
|
268
268
|
* nothing changed (a per-turn snapshot may find no new bytes under eventual consistency).
|
|
269
269
|
* Excludes (`.credentials.json`, `.DS_Store`) come from a `.gitignore` the caller commits,
|
|
270
|
-
* not from this function. Self-initializes a fresh dir
|
|
271
|
-
*
|
|
270
|
+
* not from this function. Self-initializes a fresh dir, so it works for both the
|
|
271
|
+
* restored (slate) and fresh cases.
|
|
272
|
+
*
|
|
273
|
+
* NON-FORCE is load-bearing (the workspace-writes no-overwrites invariant):
|
|
274
|
+
* a snapshot may only ADVANCE the remote. A home is single-writer
|
|
275
|
+
* (one repoId ↔ one owning process — ClaudeRepo's premise), so its history is
|
|
276
|
+
* linear and a plain push always fast-forwards. The accident class this blocks:
|
|
277
|
+
* a self-inited fresh dir pushing over an existing remote's real history is a
|
|
278
|
+
* LOUD client-side rejection instead of silent destruction (and
|
|
279
|
+
* pggit's deny-non-FF is the server backstop).
|
|
272
280
|
*/
|
|
273
|
-
async function
|
|
281
|
+
async function pushSnapshot(repo, opts) {
|
|
274
282
|
await ensureGitRepo(repo);
|
|
275
283
|
await runGit(["add", "-A"], { cwd: repo.hostDir });
|
|
276
284
|
if ((await runGit([
|
|
@@ -289,7 +297,6 @@ async function forcePushSnapshot(repo, opts) {
|
|
|
289
297
|
], { cwd: repo.hostDir });
|
|
290
298
|
await runGit([
|
|
291
299
|
"push",
|
|
292
|
-
"--force",
|
|
293
300
|
"origin",
|
|
294
301
|
`HEAD:${BRANCH}`
|
|
295
302
|
], {
|
|
@@ -316,11 +323,33 @@ async function localHead(repo) {
|
|
|
316
323
|
return result.stdout.trim() || null;
|
|
317
324
|
}
|
|
318
325
|
/**
|
|
319
|
-
*
|
|
320
|
-
*
|
|
321
|
-
*
|
|
326
|
+
* Is there a writer's live work in the tree — uncommitted changes, untracked files,
|
|
327
|
+
* or a merge in flight? `status --porcelain` covers modified/untracked/conflicted;
|
|
328
|
+
* the MERGE_HEAD probe covers the one state porcelain can miss (a merge whose
|
|
329
|
+
* resolution happens to match HEAD exactly). Callers treat `true` as "the tree is
|
|
330
|
+
* owned; touching it would be an overwrite."
|
|
331
|
+
*/
|
|
332
|
+
async function hasUncommittedWork(repo) {
|
|
333
|
+
if ((await runGit(["status", "--porcelain"], { cwd: repo.hostDir })).stdout.trim() !== "") return true;
|
|
334
|
+
return (await runGit([
|
|
335
|
+
"rev-parse",
|
|
336
|
+
"-q",
|
|
337
|
+
"--verify",
|
|
338
|
+
"MERGE_HEAD"
|
|
339
|
+
], {
|
|
340
|
+
cwd: repo.hostDir,
|
|
341
|
+
throwOnNonZero: false
|
|
342
|
+
})).exitCode === 0;
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Fetch the remote tip and integrate by PURE fast-forward or not at all (`merge
|
|
346
|
+
* --ff-only`) — the refresh half of the landlord model. `refused` means local
|
|
347
|
+
* commits exist that origin lacks (an unfinished heal): the caller serves the
|
|
348
|
+
* local tree as-is — which history wins is the healing session's business, never
|
|
349
|
+
* this function's. Fetch failures (network, auth) still throw — those are
|
|
350
|
+
* infrastructure, not divergence.
|
|
322
351
|
*/
|
|
323
|
-
async function
|
|
352
|
+
async function fastForwardToRemote(repo) {
|
|
324
353
|
await runGit([
|
|
325
354
|
"fetch",
|
|
326
355
|
"origin",
|
|
@@ -329,11 +358,14 @@ async function fetchToHead(repo) {
|
|
|
329
358
|
auth: repo.remote,
|
|
330
359
|
cwd: repo.hostDir
|
|
331
360
|
});
|
|
332
|
-
await runGit([
|
|
333
|
-
"
|
|
334
|
-
"--
|
|
361
|
+
return (await runGit([
|
|
362
|
+
"merge",
|
|
363
|
+
"--ff-only",
|
|
335
364
|
"FETCH_HEAD"
|
|
336
|
-
], {
|
|
365
|
+
], {
|
|
366
|
+
cwd: repo.hostDir,
|
|
367
|
+
throwOnNonZero: false
|
|
368
|
+
})).exitCode === 0 ? "fast_forwarded" : "refused";
|
|
337
369
|
}
|
|
338
370
|
async function ensureGitRepo(repo) {
|
|
339
371
|
const inside = await runGit(["rev-parse", "--is-inside-work-tree"], {
|
|
@@ -593,9 +625,11 @@ var ClaudeRepo = class ClaudeRepo {
|
|
|
593
625
|
* Clone-on-first-use into the host dir (slate resume). A no-op for a capture-only
|
|
594
626
|
* home (`restore:false`) and after the first success — memoized so concurrent sessions
|
|
595
627
|
* don't double-clone. Restore failure **propagates**: the caller blocks the connection
|
|
596
|
-
* — no boot → no capture → the good repo is untouched (
|
|
597
|
-
*
|
|
598
|
-
*
|
|
628
|
+
* — no boot → no capture → the good repo is untouched. (Proceeding fresh would try to
|
|
629
|
+
* push a blank home over real history — a loud non-force rejection rather than
|
|
630
|
+
* silent destruction, but restore-first stays the invariant:
|
|
631
|
+
* a rejected capture is still a broken session.) The memo is cleared on failure so a
|
|
632
|
+
* later connection retries rather than inheriting a permanent rejection.
|
|
599
633
|
*/
|
|
600
634
|
async restore() {
|
|
601
635
|
if (!this.config.restore) return;
|
|
@@ -614,7 +648,8 @@ var ClaudeRepo = class ClaudeRepo {
|
|
|
614
648
|
}
|
|
615
649
|
/**
|
|
616
650
|
* The per-turn snapshot: serialized by the mutex — rebuild the index from the live
|
|
617
|
-
* home (when maintaining it), then
|
|
651
|
+
* home (when maintaining it), then push the whole dir (non-force; a home is
|
|
652
|
+
* single-writer so the push always fast-forwards). Capture failure is caught +
|
|
618
653
|
* logged **loud**, never propagated — the turn already happened and the next snapshot
|
|
619
654
|
* pushes the cumulative state. The one non-self-healing case is an expired token's 401:
|
|
620
655
|
* the push auth is the connection's upgrade-time user token (real mint TTL: 15 minutes),
|
|
@@ -628,7 +663,7 @@ var ClaudeRepo = class ClaudeRepo {
|
|
|
628
663
|
try {
|
|
629
664
|
await this.ensureGitignore();
|
|
630
665
|
if (this.config.maintainIndex) await this.writeSessionIndex();
|
|
631
|
-
await
|
|
666
|
+
await pushSnapshot(this.repo, { message: opts.message });
|
|
632
667
|
} catch (err) {
|
|
633
668
|
console.error(`[ClaudeRepo] capture failed (${this.repo.remote.repoId}):`, err);
|
|
634
669
|
}
|
|
@@ -793,6 +828,40 @@ async function drainExecStream(handle, options) {
|
|
|
793
828
|
signal?.removeEventListener("abort", onAbort);
|
|
794
829
|
}
|
|
795
830
|
}
|
|
831
|
+
const MICROSANDBOX_HOST_ALIAS = "host.microsandbox.internal";
|
|
832
|
+
const HOST_LOOPBACK_HOSTNAMES = new Set([
|
|
833
|
+
"localhost",
|
|
834
|
+
"127.0.0.1",
|
|
835
|
+
"0.0.0.0"
|
|
836
|
+
]);
|
|
837
|
+
const IPV6_LOOPBACK_HOSTNAMES = new Set(["[::1]", "[::]"]);
|
|
838
|
+
function rewriteHostUrlForGuest(url) {
|
|
839
|
+
const parsed = new URL(url);
|
|
840
|
+
const hostname = parsed.hostname.toLowerCase();
|
|
841
|
+
if (HOST_LOOPBACK_HOSTNAMES.has(hostname) || IPV6_LOOPBACK_HOSTNAMES.has(hostname)) {
|
|
842
|
+
parsed.hostname = MICROSANDBOX_HOST_ALIAS;
|
|
843
|
+
return parsed.toString();
|
|
844
|
+
}
|
|
845
|
+
return url;
|
|
846
|
+
}
|
|
847
|
+
function guestGitEnv(input) {
|
|
848
|
+
const guestBase = rewriteHostUrlForGuest(input.platformUrl).replace(/\/+$/, "");
|
|
849
|
+
const configs = [];
|
|
850
|
+
if (guestBase !== input.platformUrl) configs.push([`url.${guestBase}/git/.insteadOf`, `${input.platformUrl}/git/`]);
|
|
851
|
+
configs.push([`http.${guestBase}/git/.extraHeader`, `Authorization: Bearer ${input.token}`]);
|
|
852
|
+
const env = {
|
|
853
|
+
GIT_AUTHOR_EMAIL: `${input.sub}@users.noreply.usecontextlayer.com`,
|
|
854
|
+
GIT_AUTHOR_NAME: input.sub,
|
|
855
|
+
GIT_COMMITTER_EMAIL: `${input.sub}@users.noreply.usecontextlayer.com`,
|
|
856
|
+
GIT_COMMITTER_NAME: input.sub,
|
|
857
|
+
GIT_CONFIG_COUNT: String(configs.length)
|
|
858
|
+
};
|
|
859
|
+
configs.forEach(([key, value], i) => {
|
|
860
|
+
env[`GIT_CONFIG_KEY_${i}`] = key;
|
|
861
|
+
env[`GIT_CONFIG_VALUE_${i}`] = value;
|
|
862
|
+
});
|
|
863
|
+
return env;
|
|
864
|
+
}
|
|
796
865
|
const DEBUG_SANDBOX_NAME = "ctx-sandbox-debug";
|
|
797
866
|
const DEFAULT_BOOT_COMMAND = ["uname", "-a"];
|
|
798
867
|
async function runSandbox(input) {
|
|
@@ -4559,6 +4628,63 @@ function refine$1(fn, _params = {}) {
|
|
|
4559
4628
|
function superRefine$1(fn, params) {
|
|
4560
4629
|
return /* @__PURE__ */ _superRefine$1(fn, params);
|
|
4561
4630
|
}
|
|
4631
|
+
`${JSON.stringify({ render: {
|
|
4632
|
+
elements: {
|
|
4633
|
+
body: {
|
|
4634
|
+
props: { text: { $item: "body" } },
|
|
4635
|
+
type: "Text"
|
|
4636
|
+
},
|
|
4637
|
+
card: {
|
|
4638
|
+
children: ["body"],
|
|
4639
|
+
props: { title: { $item: "title" } },
|
|
4640
|
+
type: "Card"
|
|
4641
|
+
},
|
|
4642
|
+
detail: {
|
|
4643
|
+
children: ["card"],
|
|
4644
|
+
props: {
|
|
4645
|
+
className: "mx-auto max-w-md p-8",
|
|
4646
|
+
direction: "vertical",
|
|
4647
|
+
gap: "md"
|
|
4648
|
+
},
|
|
4649
|
+
repeat: {
|
|
4650
|
+
key: "path",
|
|
4651
|
+
statePath: "/items"
|
|
4652
|
+
},
|
|
4653
|
+
type: "Stack"
|
|
4654
|
+
}
|
|
4655
|
+
},
|
|
4656
|
+
root: "detail"
|
|
4657
|
+
} }, null, " ")}`, `${JSON.stringify({ render: {
|
|
4658
|
+
elements: {
|
|
4659
|
+
card: {
|
|
4660
|
+
props: { title: { $item: "title" } },
|
|
4661
|
+
type: "Card"
|
|
4662
|
+
},
|
|
4663
|
+
list: {
|
|
4664
|
+
children: ["row"],
|
|
4665
|
+
props: {
|
|
4666
|
+
className: "mx-auto max-w-md p-8",
|
|
4667
|
+
direction: "vertical",
|
|
4668
|
+
gap: "md"
|
|
4669
|
+
},
|
|
4670
|
+
repeat: {
|
|
4671
|
+
key: "path",
|
|
4672
|
+
statePath: "/items"
|
|
4673
|
+
},
|
|
4674
|
+
type: "Stack"
|
|
4675
|
+
},
|
|
4676
|
+
row: {
|
|
4677
|
+
children: ["card"],
|
|
4678
|
+
on: { press: {
|
|
4679
|
+
action: "navigate",
|
|
4680
|
+
params: { path: { $template: "${path}" } }
|
|
4681
|
+
} },
|
|
4682
|
+
props: { className: null },
|
|
4683
|
+
type: "Pressable"
|
|
4684
|
+
}
|
|
4685
|
+
},
|
|
4686
|
+
root: "list"
|
|
4687
|
+
} }, null, " ")}`;
|
|
4562
4688
|
const segmentSchema$1 = string$4().min(1, "a repoId segment must be non-empty").refine((s) => s !== "." && s !== ".." && !s.includes("/"), { message: "a repoId segment must not be '.'/'..' or contain '/'" });
|
|
4563
4689
|
function segment$1(value, label) {
|
|
4564
4690
|
const result = segmentSchema$1.safeParse(value);
|
|
@@ -4578,7 +4704,7 @@ const sessionMetaSchema$1 = object$3({
|
|
|
4578
4704
|
sessionId: string$4()
|
|
4579
4705
|
});
|
|
4580
4706
|
record$2(string$4(), sessionMetaSchema$1);
|
|
4581
|
-
async function
|
|
4707
|
+
async function ensureWorkspaceCheckout(workspaceId, ctx) {
|
|
4582
4708
|
const repo = await resolveRepo({
|
|
4583
4709
|
platformUrl: ctx.platformUrl,
|
|
4584
4710
|
repoId: buildRepoId$1({
|
|
@@ -4588,10 +4714,16 @@ async function materializeWorkspaceTree(workspaceId, ctx) {
|
|
|
4588
4714
|
}),
|
|
4589
4715
|
token: ctx.token
|
|
4590
4716
|
}, ctx.gitHostBaseDir);
|
|
4591
|
-
if (await isCloned(repo.hostDir)) {
|
|
4592
|
-
if (await remoteHead(repo) !== await localHead(repo)) await fetchToHead(repo);
|
|
4593
|
-
} else await cloneRepo(repo);
|
|
4594
4717
|
return {
|
|
4718
|
+
freshness: await (async () => {
|
|
4719
|
+
if (!await isCloned(repo.hostDir)) {
|
|
4720
|
+
await cloneRepo(repo);
|
|
4721
|
+
return "cloned";
|
|
4722
|
+
}
|
|
4723
|
+
if (await hasUncommittedWork(repo)) return "held_dirty";
|
|
4724
|
+
if (await remoteHead(repo) !== await localHead(repo)) return await fastForwardToRemote(repo) === "fast_forwarded" ? "fresh" : "held_diverged";
|
|
4725
|
+
return "fresh";
|
|
4726
|
+
})(),
|
|
4595
4727
|
head: await localHead(repo),
|
|
4596
4728
|
rootDir: repo.hostDir
|
|
4597
4729
|
};
|
|
@@ -4607,72 +4739,6 @@ async function isCloned(hostDir) {
|
|
|
4607
4739
|
}
|
|
4608
4740
|
}
|
|
4609
4741
|
|
|
4610
|
-
//#endregion
|
|
4611
|
-
//#region ../slate-bridge/dist/goldens-Kp_c_7Kf.mjs
|
|
4612
|
-
const PARITY_SCENARIOS = [
|
|
4613
|
-
{
|
|
4614
|
-
name: "text-only",
|
|
4615
|
-
turns: ["Reply with exactly one word: hello", "Now reply with exactly one word: goodbye"]
|
|
4616
|
-
},
|
|
4617
|
-
{
|
|
4618
|
-
name: "code-writing",
|
|
4619
|
-
turns: [
|
|
4620
|
-
"Create a file calc.js that exports a function add(a, b) returning a + b. Use module.exports. Just write the file, no explanation.",
|
|
4621
|
-
"Add a function sub(a, b) returning a - b to calc.js, keeping add. Export both.",
|
|
4622
|
-
"Create run.js that requires ./calc.js and prints add(2, 3) and sub(5, 1), then run it with `node run.js` and show the output.",
|
|
4623
|
-
"In one sentence, what does calc.js export now?"
|
|
4624
|
-
]
|
|
4625
|
-
},
|
|
4626
|
-
{
|
|
4627
|
-
name: "thinking-and-error",
|
|
4628
|
-
turns: [
|
|
4629
|
-
"Reason carefully step by step before answering: a train travels 90 km in 1 hour 12 minutes. What is its average speed in km/h? Show your reasoning, then the answer.",
|
|
4630
|
-
"Read the file /tmp/definitely-does-not-exist-9f3a.txt and tell me its contents.",
|
|
4631
|
-
"In one short sentence, acknowledge that the file could not be read."
|
|
4632
|
-
]
|
|
4633
|
-
},
|
|
4634
|
-
{
|
|
4635
|
-
name: "compaction",
|
|
4636
|
-
turns: [
|
|
4637
|
-
"In two short paragraphs, explain how the TCP three-way handshake works.",
|
|
4638
|
-
"Now, in two short paragraphs, explain how a TLS 1.3 handshake works.",
|
|
4639
|
-
"List three concrete differences between TCP and UDP.",
|
|
4640
|
-
"/compact",
|
|
4641
|
-
"What topics were we just discussing? Answer in one sentence.",
|
|
4642
|
-
"Reply with exactly one word: done"
|
|
4643
|
-
]
|
|
4644
|
-
},
|
|
4645
|
-
{
|
|
4646
|
-
name: "multi-file-tools",
|
|
4647
|
-
turns: ["Create three files in the current directory: a.txt containing exactly `alpha`, b.txt containing exactly `beta`, c.txt containing exactly `gamma`. Just create them, no explanation.", "Read a.txt, b.txt, and c.txt and tell me what each one contains."]
|
|
4648
|
-
},
|
|
4649
|
-
{
|
|
4650
|
-
name: "web-tools",
|
|
4651
|
-
turns: ["Use web search to find the current latest stable Node.js LTS major version. Report just the version number.", "In one sentence, what did you search for?"]
|
|
4652
|
-
},
|
|
4653
|
-
{
|
|
4654
|
-
name: "long-conversation",
|
|
4655
|
-
turns: [
|
|
4656
|
-
"Name a primary color. Reply with one word.",
|
|
4657
|
-
"Name a different primary color. Reply with one word.",
|
|
4658
|
-
"Name the third primary color. Reply with one word.",
|
|
4659
|
-
"What color do you get mixing red and blue? Reply with one word.",
|
|
4660
|
-
"Summarize this conversation in one short sentence.",
|
|
4661
|
-
"Reply with exactly one word: bye"
|
|
4662
|
-
]
|
|
4663
|
-
}
|
|
4664
|
-
];
|
|
4665
|
-
function resolveGoldensDir() {
|
|
4666
|
-
let dir = path.dirname(fileURLToPath(import.meta.url));
|
|
4667
|
-
while (true) {
|
|
4668
|
-
const candidate = path.join(dir, "slate-shared", "lib", "__goldens__");
|
|
4669
|
-
if (existsSync(candidate)) return candidate;
|
|
4670
|
-
const parent = path.dirname(dir);
|
|
4671
|
-
if (parent === dir) throw new Error(`[parity] could not locate slate-shared/lib/__goldens__ above ${fileURLToPath(import.meta.url)}`);
|
|
4672
|
-
dir = parent;
|
|
4673
|
-
}
|
|
4674
|
-
}
|
|
4675
|
-
|
|
4676
4742
|
//#endregion
|
|
4677
4743
|
//#region ../base-client/dist/index.mjs
|
|
4678
4744
|
/**
|
|
@@ -4757,6 +4823,19 @@ var ForbiddenError$1 = class extends BaseAPIError {
|
|
|
4757
4823
|
this.name = "ForbiddenError";
|
|
4758
4824
|
}
|
|
4759
4825
|
};
|
|
4826
|
+
var NotFoundError$1 = class extends BaseAPIError {
|
|
4827
|
+
constructor(body, rawResponse) {
|
|
4828
|
+
super({
|
|
4829
|
+
message: "NotFoundError",
|
|
4830
|
+
statusCode: 404,
|
|
4831
|
+
body,
|
|
4832
|
+
rawResponse
|
|
4833
|
+
});
|
|
4834
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
4835
|
+
if (Error.captureStackTrace) Error.captureStackTrace(this, this.constructor);
|
|
4836
|
+
this.name = "NotFoundError";
|
|
4837
|
+
}
|
|
4838
|
+
};
|
|
4760
4839
|
function mergeHeaders$1(...headersArray) {
|
|
4761
4840
|
const result = {};
|
|
4762
4841
|
for (const [key, value] of headersArray.filter((headers) => headers != null).flatMap((headers) => Object.entries(headers))) {
|
|
@@ -5976,7 +6055,7 @@ function createIdentitySchemaCreator$1(schemaType, validate) {
|
|
|
5976
6055
|
};
|
|
5977
6056
|
};
|
|
5978
6057
|
}
|
|
5979
|
-
function enum_(values) {
|
|
6058
|
+
function enum_$1(values) {
|
|
5980
6059
|
const validValues = new Set(values);
|
|
5981
6060
|
return createIdentitySchemaCreator$1(SchemaType$1.ENUM, (value, { allowUnrecognizedEnumValues, breadcrumbsPrefix = [] } = {}) => {
|
|
5982
6061
|
if (typeof value !== "string") return {
|
|
@@ -6542,7 +6621,7 @@ const _hasOwn$4 = Object.prototype.hasOwnProperty;
|
|
|
6542
6621
|
function union$1(discriminant, union) {
|
|
6543
6622
|
const rawDiscriminant = typeof discriminant === "string" ? discriminant : discriminant.rawDiscriminant;
|
|
6544
6623
|
const parsedDiscriminant = typeof discriminant === "string" ? discriminant : discriminant.parsedDiscriminant;
|
|
6545
|
-
const discriminantValueSchema = enum_(keys$1(union));
|
|
6624
|
+
const discriminantValueSchema = enum_$1(keys$1(union));
|
|
6546
6625
|
const baseSchema = {
|
|
6547
6626
|
parse: (raw, opts) => {
|
|
6548
6627
|
return transformAndValidateUnion({
|
|
@@ -6795,7 +6874,7 @@ const Binding = object$2({
|
|
|
6795
6874
|
updatedAt: property$1("updated_at", date$3())
|
|
6796
6875
|
});
|
|
6797
6876
|
const ListBindingsResponse = object$2({ bindings: list$1(Binding) });
|
|
6798
|
-
const RunStatus = enum_([
|
|
6877
|
+
const RunStatus = enum_$1([
|
|
6799
6878
|
"QUEUED",
|
|
6800
6879
|
"NOT_STARTED",
|
|
6801
6880
|
"MANAGED",
|
|
@@ -6844,7 +6923,7 @@ const BindingStateResponse = object$2({
|
|
|
6844
6923
|
bindings: record$1(string$3(), BindingState),
|
|
6845
6924
|
version: number$3()
|
|
6846
6925
|
});
|
|
6847
|
-
const DagsterAllPlanBindingMode = enum_(["dagster"]);
|
|
6926
|
+
const DagsterAllPlanBindingMode = enum_$1(["dagster"]);
|
|
6848
6927
|
const DagsterAllPlanBinding = object$2({
|
|
6849
6928
|
auth: BindingAuth,
|
|
6850
6929
|
bindingId: property$1("binding_id", string$3()),
|
|
@@ -7026,6 +7105,62 @@ var BasesClient = class {
|
|
|
7026
7105
|
}
|
|
7027
7106
|
return handleNonStatusCodeError$1(_response.error, _response.rawResponse, "GET", "/base/bases/{base_id}");
|
|
7028
7107
|
}
|
|
7108
|
+
/**
|
|
7109
|
+
* @param {BaseAPI.DeleteBaseRequest} request
|
|
7110
|
+
* @param {BasesClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
7111
|
+
*
|
|
7112
|
+
* @throws {@link BaseAPI.ForbiddenError}
|
|
7113
|
+
* @throws {@link BaseAPI.NotFoundError}
|
|
7114
|
+
*
|
|
7115
|
+
* @example
|
|
7116
|
+
* await client.bases.deleteBase({
|
|
7117
|
+
* baseId: "base_id"
|
|
7118
|
+
* })
|
|
7119
|
+
*/
|
|
7120
|
+
deleteBase(request, requestOptions) {
|
|
7121
|
+
return HttpResponsePromise$1.fromPromise(this.__deleteBase(request, requestOptions));
|
|
7122
|
+
}
|
|
7123
|
+
async __deleteBase(request, requestOptions) {
|
|
7124
|
+
const { baseId } = request;
|
|
7125
|
+
const _headers = mergeHeaders$1(this._options?.headers, requestOptions?.headers);
|
|
7126
|
+
const _response = await fetcher$1({
|
|
7127
|
+
url: join$1(await Supplier$1.get(this._options.baseUrl) ?? await Supplier$1.get(this._options.environment), `base/bases/${encodePathParam$1(baseId)}`),
|
|
7128
|
+
method: "DELETE",
|
|
7129
|
+
headers: _headers,
|
|
7130
|
+
queryString: queryBuilder$1().mergeAdditional(requestOptions?.queryParams).build(),
|
|
7131
|
+
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
7132
|
+
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
7133
|
+
abortSignal: requestOptions?.abortSignal,
|
|
7134
|
+
fetchFn: this._options?.fetch,
|
|
7135
|
+
logging: this._options.logging
|
|
7136
|
+
});
|
|
7137
|
+
if (_response.ok) return {
|
|
7138
|
+
data: void 0,
|
|
7139
|
+
rawResponse: _response.rawResponse
|
|
7140
|
+
};
|
|
7141
|
+
if (_response.error.reason === "status-code") switch (_response.error.statusCode) {
|
|
7142
|
+
case 403: throw new ForbiddenError$1(Error_$1.parseOrThrow(_response.error.body, {
|
|
7143
|
+
unrecognizedObjectKeys: "passthrough",
|
|
7144
|
+
allowUnrecognizedUnionMembers: true,
|
|
7145
|
+
allowUnrecognizedEnumValues: true,
|
|
7146
|
+
skipValidation: true,
|
|
7147
|
+
breadcrumbsPrefix: ["response"]
|
|
7148
|
+
}), _response.rawResponse);
|
|
7149
|
+
case 404: throw new NotFoundError$1(Error_$1.parseOrThrow(_response.error.body, {
|
|
7150
|
+
unrecognizedObjectKeys: "passthrough",
|
|
7151
|
+
allowUnrecognizedUnionMembers: true,
|
|
7152
|
+
allowUnrecognizedEnumValues: true,
|
|
7153
|
+
skipValidation: true,
|
|
7154
|
+
breadcrumbsPrefix: ["response"]
|
|
7155
|
+
}), _response.rawResponse);
|
|
7156
|
+
default: throw new BaseAPIError({
|
|
7157
|
+
statusCode: _response.error.statusCode,
|
|
7158
|
+
body: _response.error.body,
|
|
7159
|
+
rawResponse: _response.rawResponse
|
|
7160
|
+
});
|
|
7161
|
+
}
|
|
7162
|
+
return handleNonStatusCodeError$1(_response.error, _response.rawResponse, "DELETE", "/base/bases/{base_id}");
|
|
7163
|
+
}
|
|
7029
7164
|
};
|
|
7030
7165
|
var BindingPlanClient = class {
|
|
7031
7166
|
_options;
|
|
@@ -8662,7 +8797,7 @@ function decodeJwt(jwt) {
|
|
|
8662
8797
|
}
|
|
8663
8798
|
|
|
8664
8799
|
//#endregion
|
|
8665
|
-
//#region ../shared/dist/
|
|
8800
|
+
//#region ../shared/dist/verify-ctx-token-BbswNLaV.mjs
|
|
8666
8801
|
/**
|
|
8667
8802
|
* Global authentication middleware for a platform resource server: require a
|
|
8668
8803
|
* Bearer `aud=ctx` token and verify it offline via the injected verifier. A
|
|
@@ -8689,6 +8824,7 @@ function createCtxAuthMiddleware(verify, machineAzpAllowlist) {
|
|
|
8689
8824
|
if (!token) return c.json({ error: "Missing bearer token." }, 401);
|
|
8690
8825
|
const result = await verify(token);
|
|
8691
8826
|
if (!result.ok) return c.json({ error: "Invalid token." }, 401);
|
|
8827
|
+
c.set("bearer", token);
|
|
8692
8828
|
if (result.kind === "machine") {
|
|
8693
8829
|
if (!machineAzpAllowlist.has(result.azp)) return c.json({ error: "Machine client not allowed." }, 403);
|
|
8694
8830
|
c.set("machine", true);
|
|
@@ -8696,10 +8832,6 @@ function createCtxAuthMiddleware(verify, machineAzpAllowlist) {
|
|
|
8696
8832
|
await next();
|
|
8697
8833
|
};
|
|
8698
8834
|
}
|
|
8699
|
-
function ctxAuthHeaders(tokenProvider) {
|
|
8700
|
-
if (!tokenProvider) return {};
|
|
8701
|
-
return { headers: { Authorization: async () => `Bearer ${await tokenProvider()}` } };
|
|
8702
|
-
}
|
|
8703
8835
|
/**
|
|
8704
8836
|
* jose error codes that mean "the presented token is invalid" → reject (401),
|
|
8705
8837
|
* `reason` is the code (for logging only). Anything else — a JWKS timeout, a
|
|
@@ -8811,6 +8943,13 @@ function createDevJwtVerifier() {
|
|
|
8811
8943
|
};
|
|
8812
8944
|
}
|
|
8813
8945
|
|
|
8946
|
+
//#endregion
|
|
8947
|
+
//#region ../shared/dist/index.mjs
|
|
8948
|
+
function ctxAuthHeaders(tokenProvider) {
|
|
8949
|
+
if (!tokenProvider) return {};
|
|
8950
|
+
return { headers: { Authorization: async () => `Bearer ${await tokenProvider()}` } };
|
|
8951
|
+
}
|
|
8952
|
+
|
|
8814
8953
|
//#endregion
|
|
8815
8954
|
//#region ../slate-client/dist/index.mjs
|
|
8816
8955
|
/**
|
|
@@ -8895,6 +9034,19 @@ var ForbiddenError = class extends SlateAPIError {
|
|
|
8895
9034
|
this.name = "ForbiddenError";
|
|
8896
9035
|
}
|
|
8897
9036
|
};
|
|
9037
|
+
var NotFoundError = class extends SlateAPIError {
|
|
9038
|
+
constructor(body, rawResponse) {
|
|
9039
|
+
super({
|
|
9040
|
+
message: "NotFoundError",
|
|
9041
|
+
statusCode: 404,
|
|
9042
|
+
body,
|
|
9043
|
+
rawResponse
|
|
9044
|
+
});
|
|
9045
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
9046
|
+
if (Error.captureStackTrace) Error.captureStackTrace(this, this.constructor);
|
|
9047
|
+
this.name = "NotFoundError";
|
|
9048
|
+
}
|
|
9049
|
+
};
|
|
8898
9050
|
function mergeHeaders(...headersArray) {
|
|
8899
9051
|
const result = {};
|
|
8900
9052
|
for (const [key, value] of headersArray.filter((headers) => headers != null).flatMap((headers) => Object.entries(headers))) {
|
|
@@ -10114,6 +10266,29 @@ function createIdentitySchemaCreator(schemaType, validate) {
|
|
|
10114
10266
|
};
|
|
10115
10267
|
};
|
|
10116
10268
|
}
|
|
10269
|
+
function enum_(values) {
|
|
10270
|
+
const validValues = new Set(values);
|
|
10271
|
+
return createIdentitySchemaCreator(SchemaType.ENUM, (value, { allowUnrecognizedEnumValues, breadcrumbsPrefix = [] } = {}) => {
|
|
10272
|
+
if (typeof value !== "string") return {
|
|
10273
|
+
ok: false,
|
|
10274
|
+
errors: [{
|
|
10275
|
+
path: breadcrumbsPrefix,
|
|
10276
|
+
message: getErrorMessageForIncorrectType(value, "string")
|
|
10277
|
+
}]
|
|
10278
|
+
};
|
|
10279
|
+
if (!validValues.has(value) && !allowUnrecognizedEnumValues) return {
|
|
10280
|
+
ok: false,
|
|
10281
|
+
errors: [{
|
|
10282
|
+
path: breadcrumbsPrefix,
|
|
10283
|
+
message: getErrorMessageForIncorrectType(value, "enum")
|
|
10284
|
+
}]
|
|
10285
|
+
};
|
|
10286
|
+
return {
|
|
10287
|
+
ok: true,
|
|
10288
|
+
value
|
|
10289
|
+
};
|
|
10290
|
+
})();
|
|
10291
|
+
}
|
|
10117
10292
|
function entries(object) {
|
|
10118
10293
|
return Object.entries(object);
|
|
10119
10294
|
}
|
|
@@ -10688,6 +10863,8 @@ const CreateWorkspaceInput = object$1({
|
|
|
10688
10863
|
synthesizerImage: property("synthesizer_image", string$2().optional()),
|
|
10689
10864
|
tick: string$2().optional()
|
|
10690
10865
|
});
|
|
10866
|
+
const DeleteWorkspaceRequestDeleteBases = enum_(["true", "false"]);
|
|
10867
|
+
const DeleteWorkspaceRequestDeleteRepos = enum_(["true", "false"]);
|
|
10691
10868
|
const BridgePlan = object$1({
|
|
10692
10869
|
baseIds: property("base_ids", list(string$2())),
|
|
10693
10870
|
claudeOauthToken: property("claude_oauth_token", string$2().nullable()),
|
|
@@ -11129,6 +11306,72 @@ var WorkspacesClient = class {
|
|
|
11129
11306
|
}
|
|
11130
11307
|
return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/slate/workspaces");
|
|
11131
11308
|
}
|
|
11309
|
+
/**
|
|
11310
|
+
* @param {SlateAPI.DeleteWorkspaceRequest} request
|
|
11311
|
+
* @param {WorkspacesClient.RequestOptions} requestOptions - Request-specific configuration.
|
|
11312
|
+
*
|
|
11313
|
+
* @throws {@link SlateAPI.ForbiddenError}
|
|
11314
|
+
* @throws {@link SlateAPI.NotFoundError}
|
|
11315
|
+
*
|
|
11316
|
+
* @example
|
|
11317
|
+
* await client.workspaces.deleteWorkspace({
|
|
11318
|
+
* workspaceId: "workspace_id"
|
|
11319
|
+
* })
|
|
11320
|
+
*/
|
|
11321
|
+
deleteWorkspace(request, requestOptions) {
|
|
11322
|
+
return HttpResponsePromise.fromPromise(this.__deleteWorkspace(request, requestOptions));
|
|
11323
|
+
}
|
|
11324
|
+
async __deleteWorkspace(request, requestOptions) {
|
|
11325
|
+
const { workspaceId, deleteBases, deleteRepos } = request;
|
|
11326
|
+
const _queryParams = {
|
|
11327
|
+
delete_bases: deleteBases != null ? DeleteWorkspaceRequestDeleteBases.jsonOrThrow(deleteBases, {
|
|
11328
|
+
unrecognizedObjectKeys: "strip",
|
|
11329
|
+
omitUndefined: true
|
|
11330
|
+
}) : void 0,
|
|
11331
|
+
delete_repos: deleteRepos != null ? DeleteWorkspaceRequestDeleteRepos.jsonOrThrow(deleteRepos, {
|
|
11332
|
+
unrecognizedObjectKeys: "strip",
|
|
11333
|
+
omitUndefined: true
|
|
11334
|
+
}) : void 0
|
|
11335
|
+
};
|
|
11336
|
+
const _headers = mergeHeaders(this._options?.headers, requestOptions?.headers);
|
|
11337
|
+
const _response = await fetcher({
|
|
11338
|
+
url: join(await Supplier.get(this._options.baseUrl) ?? await Supplier.get(this._options.environment), `slate/workspaces/${encodePathParam(workspaceId)}`),
|
|
11339
|
+
method: "DELETE",
|
|
11340
|
+
headers: _headers,
|
|
11341
|
+
queryString: queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
|
|
11342
|
+
timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
|
|
11343
|
+
maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
|
|
11344
|
+
abortSignal: requestOptions?.abortSignal,
|
|
11345
|
+
fetchFn: this._options?.fetch,
|
|
11346
|
+
logging: this._options.logging
|
|
11347
|
+
});
|
|
11348
|
+
if (_response.ok) return {
|
|
11349
|
+
data: void 0,
|
|
11350
|
+
rawResponse: _response.rawResponse
|
|
11351
|
+
};
|
|
11352
|
+
if (_response.error.reason === "status-code") switch (_response.error.statusCode) {
|
|
11353
|
+
case 403: throw new ForbiddenError(Error_.parseOrThrow(_response.error.body, {
|
|
11354
|
+
unrecognizedObjectKeys: "passthrough",
|
|
11355
|
+
allowUnrecognizedUnionMembers: true,
|
|
11356
|
+
allowUnrecognizedEnumValues: true,
|
|
11357
|
+
skipValidation: true,
|
|
11358
|
+
breadcrumbsPrefix: ["response"]
|
|
11359
|
+
}), _response.rawResponse);
|
|
11360
|
+
case 404: throw new NotFoundError(Error_.parseOrThrow(_response.error.body, {
|
|
11361
|
+
unrecognizedObjectKeys: "passthrough",
|
|
11362
|
+
allowUnrecognizedUnionMembers: true,
|
|
11363
|
+
allowUnrecognizedEnumValues: true,
|
|
11364
|
+
skipValidation: true,
|
|
11365
|
+
breadcrumbsPrefix: ["response"]
|
|
11366
|
+
}), _response.rawResponse);
|
|
11367
|
+
default: throw new SlateAPIError({
|
|
11368
|
+
statusCode: _response.error.statusCode,
|
|
11369
|
+
body: _response.error.body,
|
|
11370
|
+
rawResponse: _response.rawResponse
|
|
11371
|
+
});
|
|
11372
|
+
}
|
|
11373
|
+
return handleNonStatusCodeError(_response.error, _response.rawResponse, "DELETE", "/slate/workspaces/{workspace_id}");
|
|
11374
|
+
}
|
|
11132
11375
|
};
|
|
11133
11376
|
var SlateAPIClient = class {
|
|
11134
11377
|
_options;
|
|
@@ -14811,6 +15054,9 @@ const ZodURL = /*@__PURE__*/ $constructor("ZodURL", (inst, def) => {
|
|
|
14811
15054
|
$ZodURL.init(inst, def);
|
|
14812
15055
|
ZodStringFormat.init(inst, def);
|
|
14813
15056
|
});
|
|
15057
|
+
function url(params) {
|
|
15058
|
+
return _url(ZodURL, params);
|
|
15059
|
+
}
|
|
14814
15060
|
const ZodEmoji = /*@__PURE__*/ $constructor("ZodEmoji", (inst, def) => {
|
|
14815
15061
|
$ZodEmoji.init(inst, def);
|
|
14816
15062
|
ZodStringFormat.init(inst, def);
|
|
@@ -15320,6 +15566,82 @@ function number(params) {
|
|
|
15320
15566
|
//#endregion
|
|
15321
15567
|
//#region ../slate-shared/dist/index.mjs
|
|
15322
15568
|
const WORKSPACE_DOCS_SUBDIR = "output";
|
|
15569
|
+
const INBOX_CONTENT_TREE = {
|
|
15570
|
+
"output/actions/reply-dana-uat-escalation.md": "---\ntype: Action\nstatus: open\n---\n# Reply to Dana Whitfield's UAT currency escalation\n\nDana escalated the multi-currency UAT blocker; reply today.\n",
|
|
15571
|
+
"output/actions/ship-final-invoice.md": "---\ntype: Action\nstatus: open\n---\n# Ship the final invoice\n\nClose out the quarter: send the last invoice and file it.\n",
|
|
15572
|
+
"output/types/action.loader.js": `export default async ({ vault, path }) => {
|
|
15573
|
+
const node = vault.get(path)
|
|
15574
|
+
return { items: [{ body: node.body, path: node.path, title: node.title }] }
|
|
15575
|
+
}
|
|
15576
|
+
`,
|
|
15577
|
+
"output/types/action.render-spec.json": `${JSON.stringify({ render: {
|
|
15578
|
+
elements: {
|
|
15579
|
+
body: {
|
|
15580
|
+
props: { text: { $item: "body" } },
|
|
15581
|
+
type: "Text"
|
|
15582
|
+
},
|
|
15583
|
+
card: {
|
|
15584
|
+
children: ["body"],
|
|
15585
|
+
props: { title: { $item: "title" } },
|
|
15586
|
+
type: "Card"
|
|
15587
|
+
},
|
|
15588
|
+
detail: {
|
|
15589
|
+
children: ["card"],
|
|
15590
|
+
props: {
|
|
15591
|
+
className: "mx-auto max-w-md p-8",
|
|
15592
|
+
direction: "vertical",
|
|
15593
|
+
gap: "md"
|
|
15594
|
+
},
|
|
15595
|
+
repeat: {
|
|
15596
|
+
key: "path",
|
|
15597
|
+
statePath: "/items"
|
|
15598
|
+
},
|
|
15599
|
+
type: "Stack"
|
|
15600
|
+
}
|
|
15601
|
+
},
|
|
15602
|
+
root: "detail"
|
|
15603
|
+
} }, null, " ")}\n`,
|
|
15604
|
+
"output/views/inbox.loader.js": `export default async ({ vault }) => {
|
|
15605
|
+
const items = vault
|
|
15606
|
+
.all()
|
|
15607
|
+
.filter((entry) => entry.type === "Action")
|
|
15608
|
+
.map((entry) => ({ path: entry.path, title: entry.title }))
|
|
15609
|
+
.sort((a, b) => a.title.localeCompare(b.title))
|
|
15610
|
+
return { items }
|
|
15611
|
+
}
|
|
15612
|
+
`,
|
|
15613
|
+
"output/views/inbox.render-spec.json": `${JSON.stringify({ render: {
|
|
15614
|
+
elements: {
|
|
15615
|
+
card: {
|
|
15616
|
+
props: { title: { $item: "title" } },
|
|
15617
|
+
type: "Card"
|
|
15618
|
+
},
|
|
15619
|
+
list: {
|
|
15620
|
+
children: ["row"],
|
|
15621
|
+
props: {
|
|
15622
|
+
className: "mx-auto max-w-md p-8",
|
|
15623
|
+
direction: "vertical",
|
|
15624
|
+
gap: "md"
|
|
15625
|
+
},
|
|
15626
|
+
repeat: {
|
|
15627
|
+
key: "path",
|
|
15628
|
+
statePath: "/items"
|
|
15629
|
+
},
|
|
15630
|
+
type: "Stack"
|
|
15631
|
+
},
|
|
15632
|
+
row: {
|
|
15633
|
+
children: ["card"],
|
|
15634
|
+
on: { press: {
|
|
15635
|
+
action: "navigate",
|
|
15636
|
+
params: { path: { $template: "${path}" } }
|
|
15637
|
+
} },
|
|
15638
|
+
props: { className: null },
|
|
15639
|
+
type: "Pressable"
|
|
15640
|
+
}
|
|
15641
|
+
},
|
|
15642
|
+
root: "list"
|
|
15643
|
+
} }, null, " ")}\n`
|
|
15644
|
+
};
|
|
15323
15645
|
const segmentSchema = string().min(1, "a repoId segment must be non-empty").refine((s) => s !== "." && s !== ".." && !s.includes("/"), { message: "a repoId segment must not be '.'/'..' or contain '/'" });
|
|
15324
15646
|
function segment(value, label) {
|
|
15325
15647
|
const result = segmentSchema.safeParse(value);
|
|
@@ -42900,16 +43222,16 @@ function osUsername() {
|
|
|
42900
43222
|
}
|
|
42901
43223
|
|
|
42902
43224
|
//#endregion
|
|
42903
|
-
//#region ../slate-bridge/dist/
|
|
43225
|
+
//#region ../slate-bridge/dist/goldens-C7JkwekQ.mjs
|
|
42904
43226
|
const nonEmptyStringSchema = string().trim().min(1);
|
|
42905
43227
|
const portSchema = number().int().min(0).max(65535).default(7777);
|
|
42906
43228
|
const envSchema = object({
|
|
42907
43229
|
CTX_AUTH_SKIP_VERIFY_JWT: string().optional().transform((v) => v === "true"),
|
|
42908
43230
|
CTX_GIT_HOST_BASE_DIR: nonEmptyStringSchema.default(() => path.join(os.homedir(), ".contextlayer", "repos")),
|
|
42909
|
-
CTX_PLATFORM_URL:
|
|
42910
|
-
CTX_WEB_URL:
|
|
43231
|
+
CTX_PLATFORM_URL: url().default("http://127.0.0.1:3010").transform((url) => url.replace(/\/+$/, "")),
|
|
43232
|
+
CTX_WEB_URL: url().default("http://localhost:3000").transform((url) => url.replace(/\/+$/, "")),
|
|
42911
43233
|
CTXS_BRIDGE_PORT: portSchema,
|
|
42912
|
-
CTXS_CLAUDE_IMAGE: nonEmptyStringSchema.default("ghcr.io/usecontextlayer/ctx-sandbox:0.5.
|
|
43234
|
+
CTXS_CLAUDE_IMAGE: nonEmptyStringSchema.default("ghcr.io/usecontextlayer/ctx-sandbox:0.5.6"),
|
|
42913
43235
|
CTXS_CLAUDE_MODEL: nonEmptyStringSchema.default("opus"),
|
|
42914
43236
|
CTXS_HOST_CLAUDE_JSON_PATH: nonEmptyStringSchema.default(() => path.join(os.homedir(), ".claude.json")),
|
|
42915
43237
|
NODE_ENV: _enum([
|
|
@@ -43263,7 +43585,21 @@ const CLAUDE_ARGS = [
|
|
|
43263
43585
|
"--thinking-display",
|
|
43264
43586
|
"summarized",
|
|
43265
43587
|
"--permission-mode",
|
|
43266
|
-
"bypassPermissions"
|
|
43588
|
+
"bypassPermissions",
|
|
43589
|
+
"--append-system-prompt",
|
|
43590
|
+
`You are working in the user's workspace: a directory of documents that is also a shared git repository. The synthesis engine, other sessions, and operators write to this same repository through its remote. Git is how your work persists and how everyone else learns about it — an edit that is not pushed does not exist yet.
|
|
43591
|
+
|
|
43592
|
+
1. When you complete a change the user asked for, immediately commit and push it: \`git add -A && git commit -m "<message>" && git push\`. Never use \`--force\` on a push, ever.
|
|
43593
|
+
|
|
43594
|
+
2. Commit messages carry your reasoning, not just a summary. They are how this workspace remembers why things changed — future sessions, the synthesis engine, and the user read them. When you change a document's status or make a judgment call, put the why in the message. When you need context on how the workspace got into its current state, read \`git log\`.
|
|
43595
|
+
|
|
43596
|
+
3. If a push is rejected, someone else pushed first. Run \`git pull --no-rebase\`. If the merge is clean, push again. If there are conflicts, resolve them together with the user: show what collided, prefer preserving the user's intent, ask when unsure — then commit and push. Never resolve a conflict by discarding someone else's work wholesale.
|
|
43597
|
+
|
|
43598
|
+
4. At session start the tree may already hold uncommitted changes, unpushed commits, or a merge a previous session left in flight. This is normal. Never discard that work — fold uncommitted changes into your next commit, and finish an in-flight merge before starting new work.
|
|
43599
|
+
|
|
43600
|
+
5. The \`.engine/\` directory is the synthesis engine's private state. Leave it alone unless the user explicitly asks.
|
|
43601
|
+
|
|
43602
|
+
Do this bookkeeping quietly. Don't narrate routine git operations — mention git only when something needs the user's attention: a conflict, a rejected push you cannot heal, or work you found and preserved.`
|
|
43267
43603
|
];
|
|
43268
43604
|
function bearerToken(c) {
|
|
43269
43605
|
const header = c.req.header("Authorization") ?? "";
|
|
@@ -43288,6 +43624,15 @@ function assertSingleBaseId(baseIds, workspaceId) {
|
|
|
43288
43624
|
if (baseId === void 0 || rest.length > 0) throw new Error(`render: workspace ${workspaceId} resolves to ${baseIds.length} base(s), but render-SQL requires exactly one (a sql() call runs against a single base DB). Link exactly one base to this workspace; multi-base render is deferred.`);
|
|
43289
43625
|
return baseId;
|
|
43290
43626
|
}
|
|
43627
|
+
function noteDivergedCheckout(workspaceId) {
|
|
43628
|
+
console.error(`[slate-bridge] workspace ${workspaceId} checkout has unpushed commits while origin moved (unfinished heal) — serving the local tree`);
|
|
43629
|
+
Sentry.addBreadcrumb({
|
|
43630
|
+
category: "workspace-checkout",
|
|
43631
|
+
data: { workspaceId },
|
|
43632
|
+
level: "warning",
|
|
43633
|
+
message: "diverged workspace checkout served as-is"
|
|
43634
|
+
});
|
|
43635
|
+
}
|
|
43291
43636
|
function isTurnResult(line) {
|
|
43292
43637
|
if (!line.includes("\"type\":\"result\"")) return false;
|
|
43293
43638
|
try {
|
|
@@ -43337,11 +43682,12 @@ async function createBridgeServer(opts) {
|
|
|
43337
43682
|
const rawParams = (await c.req.json()).params ?? {};
|
|
43338
43683
|
try {
|
|
43339
43684
|
const userToken = bearerToken(c);
|
|
43340
|
-
const { head, rootDir } = await
|
|
43685
|
+
const { head, rootDir, freshness } = await ensureWorkspaceCheckout(workspaceId, {
|
|
43341
43686
|
gitHostBaseDir,
|
|
43342
43687
|
platformUrl,
|
|
43343
43688
|
token: userToken
|
|
43344
43689
|
});
|
|
43690
|
+
if (freshness === "held_diverged") noteDivergedCheckout(workspaceId);
|
|
43345
43691
|
const result = await runWorkspaceView({
|
|
43346
43692
|
rawParams,
|
|
43347
43693
|
resolveDsn: () => resolveRenderDsn(platformUrl, workspaceId, userToken),
|
|
@@ -43361,11 +43707,12 @@ async function createBridgeServer(opts) {
|
|
|
43361
43707
|
const rawParams = body.params ?? {};
|
|
43362
43708
|
try {
|
|
43363
43709
|
const userToken = bearerToken(c);
|
|
43364
|
-
const { head, rootDir } = await
|
|
43710
|
+
const { head, rootDir, freshness } = await ensureWorkspaceCheckout(workspaceId, {
|
|
43365
43711
|
gitHostBaseDir,
|
|
43366
43712
|
platformUrl,
|
|
43367
43713
|
token: userToken
|
|
43368
43714
|
});
|
|
43715
|
+
if (freshness === "held_diverged") noteDivergedCheckout(workspaceId);
|
|
43369
43716
|
const vault = await vaults.get(rootDir, head);
|
|
43370
43717
|
const result = await runWorkspaceContent({
|
|
43371
43718
|
contentPath: body.path,
|
|
@@ -43411,11 +43758,13 @@ async function createBridgeServer(opts) {
|
|
|
43411
43758
|
let phase = "boot";
|
|
43412
43759
|
try {
|
|
43413
43760
|
const plan = await fetchBridgePlan(platformUrl, workspaceId, userToken);
|
|
43414
|
-
const [,
|
|
43761
|
+
const [, checkout] = await Promise.all([claudeRepo.restore(), ensureWorkspaceCheckout(workspaceId, {
|
|
43415
43762
|
gitHostBaseDir,
|
|
43416
43763
|
platformUrl,
|
|
43417
43764
|
token: userToken
|
|
43418
43765
|
})]);
|
|
43766
|
+
if (checkout.freshness === "held_diverged") noteDivergedCheckout(workspaceId);
|
|
43767
|
+
const rootDir = checkout.rootDir;
|
|
43419
43768
|
if (ac.signal.aborted) return;
|
|
43420
43769
|
session = await createClaudeMicrosandbox({
|
|
43421
43770
|
claudeHomeHostDir: claudeRepo.hostDir,
|
|
@@ -43435,7 +43784,12 @@ async function createBridgeServer(opts) {
|
|
|
43435
43784
|
],
|
|
43436
43785
|
env: {
|
|
43437
43786
|
CLAUDE_CODE_ENTRYPOINT: "sdk-ts",
|
|
43438
|
-
...plan.claudeOauthToken ? { CLAUDE_CODE_OAUTH_TOKEN: plan.claudeOauthToken } : {}
|
|
43787
|
+
...plan.claudeOauthToken ? { CLAUDE_CODE_OAUTH_TOKEN: plan.claudeOauthToken } : {},
|
|
43788
|
+
...guestGitEnv({
|
|
43789
|
+
platformUrl,
|
|
43790
|
+
sub: r.sub,
|
|
43791
|
+
token: userToken
|
|
43792
|
+
})
|
|
43439
43793
|
},
|
|
43440
43794
|
signal: ac.signal
|
|
43441
43795
|
});
|
|
@@ -43513,6 +43867,72 @@ async function createBridgeServer(opts) {
|
|
|
43513
43867
|
port: address.port
|
|
43514
43868
|
};
|
|
43515
43869
|
}
|
|
43870
|
+
const PARITY_SCENARIOS = [
|
|
43871
|
+
{
|
|
43872
|
+
name: "text-only",
|
|
43873
|
+
turns: ["Reply with exactly one word: hello", "Now reply with exactly one word: goodbye"]
|
|
43874
|
+
},
|
|
43875
|
+
{
|
|
43876
|
+
name: "code-writing",
|
|
43877
|
+
turns: [
|
|
43878
|
+
"Create a file calc.js that exports a function add(a, b) returning a + b. Use module.exports. Just write the file, no explanation.",
|
|
43879
|
+
"Add a function sub(a, b) returning a - b to calc.js, keeping add. Export both.",
|
|
43880
|
+
"Create run.js that requires ./calc.js and prints add(2, 3) and sub(5, 1), then run it with `node run.js` and show the output.",
|
|
43881
|
+
"In one sentence, what does calc.js export now?"
|
|
43882
|
+
]
|
|
43883
|
+
},
|
|
43884
|
+
{
|
|
43885
|
+
name: "thinking-and-error",
|
|
43886
|
+
turns: [
|
|
43887
|
+
"Reason carefully step by step before answering: a train travels 90 km in 1 hour 12 minutes. What is its average speed in km/h? Show your reasoning, then the answer.",
|
|
43888
|
+
"Read the file /tmp/definitely-does-not-exist-9f3a.txt and tell me its contents.",
|
|
43889
|
+
"In one short sentence, acknowledge that the file could not be read."
|
|
43890
|
+
]
|
|
43891
|
+
},
|
|
43892
|
+
{
|
|
43893
|
+
name: "compaction",
|
|
43894
|
+
turns: [
|
|
43895
|
+
"In two short paragraphs, explain how the TCP three-way handshake works.",
|
|
43896
|
+
"Now, in two short paragraphs, explain how a TLS 1.3 handshake works.",
|
|
43897
|
+
"List three concrete differences between TCP and UDP.",
|
|
43898
|
+
"/compact",
|
|
43899
|
+
"What topics were we just discussing? Answer in one sentence.",
|
|
43900
|
+
"Reply with exactly one word: done"
|
|
43901
|
+
]
|
|
43902
|
+
},
|
|
43903
|
+
{
|
|
43904
|
+
name: "multi-file-tools",
|
|
43905
|
+
turns: ["Create three files in the current directory: a.txt containing exactly `alpha`, b.txt containing exactly `beta`, c.txt containing exactly `gamma`. Just create them, no explanation.", "Read a.txt, b.txt, and c.txt and tell me what each one contains."]
|
|
43906
|
+
},
|
|
43907
|
+
{
|
|
43908
|
+
name: "web-tools",
|
|
43909
|
+
turns: ["Use web search to find the current latest stable Node.js LTS major version. Report just the version number.", "In one sentence, what did you search for?"]
|
|
43910
|
+
},
|
|
43911
|
+
{
|
|
43912
|
+
name: "long-conversation",
|
|
43913
|
+
turns: [
|
|
43914
|
+
"Name a primary color. Reply with one word.",
|
|
43915
|
+
"Name a different primary color. Reply with one word.",
|
|
43916
|
+
"Name the third primary color. Reply with one word.",
|
|
43917
|
+
"What color do you get mixing red and blue? Reply with one word.",
|
|
43918
|
+
"Summarize this conversation in one short sentence.",
|
|
43919
|
+
"Reply with exactly one word: bye"
|
|
43920
|
+
]
|
|
43921
|
+
}
|
|
43922
|
+
];
|
|
43923
|
+
function resolveGoldensDir() {
|
|
43924
|
+
let dir = path.dirname(fileURLToPath(import.meta.url));
|
|
43925
|
+
while (true) {
|
|
43926
|
+
const candidate = path.join(dir, "slate-shared", "lib", "__goldens__");
|
|
43927
|
+
if (existsSync(candidate)) return candidate;
|
|
43928
|
+
const parent = path.dirname(dir);
|
|
43929
|
+
if (parent === dir) throw new Error(`[parity] could not locate slate-shared/lib/__goldens__ above ${fileURLToPath(import.meta.url)}`);
|
|
43930
|
+
dir = parent;
|
|
43931
|
+
}
|
|
43932
|
+
}
|
|
43933
|
+
|
|
43934
|
+
//#endregion
|
|
43935
|
+
//#region ../slate-bridge/dist/index.mjs
|
|
43516
43936
|
async function writeJsonAtomic(filePath, value) {
|
|
43517
43937
|
const tmp = `${filePath}.tmp`;
|
|
43518
43938
|
await writeFile(tmp, `${JSON.stringify(value, null, 2)}\n`);
|
|
@@ -47661,4 +48081,4 @@ runCli().catch((error) => {
|
|
|
47661
48081
|
//#endregion
|
|
47662
48082
|
export { createProgram, runCli };
|
|
47663
48083
|
//# sourceMappingURL=cli.mjs.map
|
|
47664
|
-
//# debugId=
|
|
48084
|
+
//# debugId=3dbc3cff-70da-5d01-b6fc-a83d63e0c3f3
|