@usecontextlayer/ctxs 0.5.5 → 0.5.7

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 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]="5e70b90f-e938-570a-b3e3-d35af180a822")}catch(e){}}();
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]="a525501b-8c62-5a9e-a76f-b82b01d56d75")}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.5";
63
+ var version$2 = "0.5.7";
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 --force`. A no-op if
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 (the capture-only engine home is
271
- * never cloned), so it works for both the restored (slate) and fresh (engine) cases.
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 forcePushSnapshot(repo, opts) {
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
- * Fast-forward the working dir to the remote tip (`fetch` + `reset --hard`) the
320
- * refresh half of the read-copy model: callers HEAD-gate it so a reader catches the
321
- * engine's pushes without paying a fetch when nothing changed.
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 fetchToHead(repo) {
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
- "reset",
334
- "--hard",
361
+ return (await runGit([
362
+ "merge",
363
+ "--ff-only",
335
364
  "FETCH_HEAD"
336
- ], { cwd: repo.hostDir });
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 (proceeding fresh would
597
- * force-push a blank home over real history). The memo is cleared on failure so a later
598
- * connection retries rather than inheriting a permanent rejection.
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 force-push the whole dir. Capture failure is caught +
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 forcePushSnapshot(this.repo, { message: opts.message });
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,99 @@ 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
+ ask: {
4634
+ children: ["askLabel"],
4635
+ on: { press: {
4636
+ action: "openChat",
4637
+ params: {
4638
+ autoSend: false,
4639
+ content: { $template: "What should I know about @output/${path}?" }
4640
+ }
4641
+ } },
4642
+ props: { className: null },
4643
+ type: "Pressable"
4644
+ },
4645
+ askLabel: {
4646
+ props: { text: "Ask about this doc" },
4647
+ type: "Text"
4648
+ },
4649
+ body: {
4650
+ props: { text: { $item: "body" } },
4651
+ type: "Text"
4652
+ },
4653
+ card: {
4654
+ children: [
4655
+ "body",
4656
+ "draft",
4657
+ "ask"
4658
+ ],
4659
+ props: { title: { $item: "title" } },
4660
+ type: "Card"
4661
+ },
4662
+ detail: {
4663
+ children: ["card"],
4664
+ props: {
4665
+ className: "mx-auto max-w-md p-8",
4666
+ direction: "vertical",
4667
+ gap: "md"
4668
+ },
4669
+ repeat: {
4670
+ key: "path",
4671
+ statePath: "/items"
4672
+ },
4673
+ type: "Stack"
4674
+ },
4675
+ draft: {
4676
+ children: ["draftLabel"],
4677
+ on: { press: {
4678
+ action: "openChat",
4679
+ params: {
4680
+ autoSend: true,
4681
+ content: { $template: "Draft a reply to @output/${path}" }
4682
+ }
4683
+ } },
4684
+ props: { className: null },
4685
+ type: "Pressable"
4686
+ },
4687
+ draftLabel: {
4688
+ props: { text: "Draft reply" },
4689
+ type: "Text"
4690
+ }
4691
+ },
4692
+ root: "detail"
4693
+ } }, null, " ")}`, `${JSON.stringify({ render: {
4694
+ elements: {
4695
+ card: {
4696
+ props: { title: { $item: "title" } },
4697
+ type: "Card"
4698
+ },
4699
+ list: {
4700
+ children: ["row"],
4701
+ props: {
4702
+ className: "mx-auto max-w-md p-8",
4703
+ direction: "vertical",
4704
+ gap: "md"
4705
+ },
4706
+ repeat: {
4707
+ key: "path",
4708
+ statePath: "/items"
4709
+ },
4710
+ type: "Stack"
4711
+ },
4712
+ row: {
4713
+ children: ["card"],
4714
+ on: { press: {
4715
+ action: "navigate",
4716
+ params: { path: { $template: "${path}" } }
4717
+ } },
4718
+ props: { className: null },
4719
+ type: "Pressable"
4720
+ }
4721
+ },
4722
+ root: "list"
4723
+ } }, null, " ")}`;
4562
4724
  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
4725
  function segment$1(value, label) {
4564
4726
  const result = segmentSchema$1.safeParse(value);
@@ -4578,7 +4740,7 @@ const sessionMetaSchema$1 = object$3({
4578
4740
  sessionId: string$4()
4579
4741
  });
4580
4742
  record$2(string$4(), sessionMetaSchema$1);
4581
- async function materializeWorkspaceTree(workspaceId, ctx) {
4743
+ async function ensureWorkspaceCheckout(workspaceId, ctx) {
4582
4744
  const repo = await resolveRepo({
4583
4745
  platformUrl: ctx.platformUrl,
4584
4746
  repoId: buildRepoId$1({
@@ -4588,10 +4750,16 @@ async function materializeWorkspaceTree(workspaceId, ctx) {
4588
4750
  }),
4589
4751
  token: ctx.token
4590
4752
  }, 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
4753
  return {
4754
+ freshness: await (async () => {
4755
+ if (!await isCloned(repo.hostDir)) {
4756
+ await cloneRepo(repo);
4757
+ return "cloned";
4758
+ }
4759
+ if (await hasUncommittedWork(repo)) return "held_dirty";
4760
+ if (await remoteHead(repo) !== await localHead(repo)) return await fastForwardToRemote(repo) === "fast_forwarded" ? "fresh" : "held_diverged";
4761
+ return "fresh";
4762
+ })(),
4595
4763
  head: await localHead(repo),
4596
4764
  rootDir: repo.hostDir
4597
4765
  };
@@ -4607,72 +4775,6 @@ async function isCloned(hostDir) {
4607
4775
  }
4608
4776
  }
4609
4777
 
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
4778
  //#endregion
4677
4779
  //#region ../base-client/dist/index.mjs
4678
4780
  /**
@@ -4757,6 +4859,19 @@ var ForbiddenError$1 = class extends BaseAPIError {
4757
4859
  this.name = "ForbiddenError";
4758
4860
  }
4759
4861
  };
4862
+ var NotFoundError$1 = class extends BaseAPIError {
4863
+ constructor(body, rawResponse) {
4864
+ super({
4865
+ message: "NotFoundError",
4866
+ statusCode: 404,
4867
+ body,
4868
+ rawResponse
4869
+ });
4870
+ Object.setPrototypeOf(this, new.target.prototype);
4871
+ if (Error.captureStackTrace) Error.captureStackTrace(this, this.constructor);
4872
+ this.name = "NotFoundError";
4873
+ }
4874
+ };
4760
4875
  function mergeHeaders$1(...headersArray) {
4761
4876
  const result = {};
4762
4877
  for (const [key, value] of headersArray.filter((headers) => headers != null).flatMap((headers) => Object.entries(headers))) {
@@ -5976,7 +6091,7 @@ function createIdentitySchemaCreator$1(schemaType, validate) {
5976
6091
  };
5977
6092
  };
5978
6093
  }
5979
- function enum_(values) {
6094
+ function enum_$1(values) {
5980
6095
  const validValues = new Set(values);
5981
6096
  return createIdentitySchemaCreator$1(SchemaType$1.ENUM, (value, { allowUnrecognizedEnumValues, breadcrumbsPrefix = [] } = {}) => {
5982
6097
  if (typeof value !== "string") return {
@@ -6542,7 +6657,7 @@ const _hasOwn$4 = Object.prototype.hasOwnProperty;
6542
6657
  function union$1(discriminant, union) {
6543
6658
  const rawDiscriminant = typeof discriminant === "string" ? discriminant : discriminant.rawDiscriminant;
6544
6659
  const parsedDiscriminant = typeof discriminant === "string" ? discriminant : discriminant.parsedDiscriminant;
6545
- const discriminantValueSchema = enum_(keys$1(union));
6660
+ const discriminantValueSchema = enum_$1(keys$1(union));
6546
6661
  const baseSchema = {
6547
6662
  parse: (raw, opts) => {
6548
6663
  return transformAndValidateUnion({
@@ -6795,7 +6910,7 @@ const Binding = object$2({
6795
6910
  updatedAt: property$1("updated_at", date$3())
6796
6911
  });
6797
6912
  const ListBindingsResponse = object$2({ bindings: list$1(Binding) });
6798
- const RunStatus = enum_([
6913
+ const RunStatus = enum_$1([
6799
6914
  "QUEUED",
6800
6915
  "NOT_STARTED",
6801
6916
  "MANAGED",
@@ -6844,7 +6959,7 @@ const BindingStateResponse = object$2({
6844
6959
  bindings: record$1(string$3(), BindingState),
6845
6960
  version: number$3()
6846
6961
  });
6847
- const DagsterAllPlanBindingMode = enum_(["dagster"]);
6962
+ const DagsterAllPlanBindingMode = enum_$1(["dagster"]);
6848
6963
  const DagsterAllPlanBinding = object$2({
6849
6964
  auth: BindingAuth,
6850
6965
  bindingId: property$1("binding_id", string$3()),
@@ -7026,6 +7141,62 @@ var BasesClient = class {
7026
7141
  }
7027
7142
  return handleNonStatusCodeError$1(_response.error, _response.rawResponse, "GET", "/base/bases/{base_id}");
7028
7143
  }
7144
+ /**
7145
+ * @param {BaseAPI.DeleteBaseRequest} request
7146
+ * @param {BasesClient.RequestOptions} requestOptions - Request-specific configuration.
7147
+ *
7148
+ * @throws {@link BaseAPI.ForbiddenError}
7149
+ * @throws {@link BaseAPI.NotFoundError}
7150
+ *
7151
+ * @example
7152
+ * await client.bases.deleteBase({
7153
+ * baseId: "base_id"
7154
+ * })
7155
+ */
7156
+ deleteBase(request, requestOptions) {
7157
+ return HttpResponsePromise$1.fromPromise(this.__deleteBase(request, requestOptions));
7158
+ }
7159
+ async __deleteBase(request, requestOptions) {
7160
+ const { baseId } = request;
7161
+ const _headers = mergeHeaders$1(this._options?.headers, requestOptions?.headers);
7162
+ const _response = await fetcher$1({
7163
+ url: join$1(await Supplier$1.get(this._options.baseUrl) ?? await Supplier$1.get(this._options.environment), `base/bases/${encodePathParam$1(baseId)}`),
7164
+ method: "DELETE",
7165
+ headers: _headers,
7166
+ queryString: queryBuilder$1().mergeAdditional(requestOptions?.queryParams).build(),
7167
+ timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
7168
+ maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
7169
+ abortSignal: requestOptions?.abortSignal,
7170
+ fetchFn: this._options?.fetch,
7171
+ logging: this._options.logging
7172
+ });
7173
+ if (_response.ok) return {
7174
+ data: void 0,
7175
+ rawResponse: _response.rawResponse
7176
+ };
7177
+ if (_response.error.reason === "status-code") switch (_response.error.statusCode) {
7178
+ case 403: throw new ForbiddenError$1(Error_$1.parseOrThrow(_response.error.body, {
7179
+ unrecognizedObjectKeys: "passthrough",
7180
+ allowUnrecognizedUnionMembers: true,
7181
+ allowUnrecognizedEnumValues: true,
7182
+ skipValidation: true,
7183
+ breadcrumbsPrefix: ["response"]
7184
+ }), _response.rawResponse);
7185
+ case 404: throw new NotFoundError$1(Error_$1.parseOrThrow(_response.error.body, {
7186
+ unrecognizedObjectKeys: "passthrough",
7187
+ allowUnrecognizedUnionMembers: true,
7188
+ allowUnrecognizedEnumValues: true,
7189
+ skipValidation: true,
7190
+ breadcrumbsPrefix: ["response"]
7191
+ }), _response.rawResponse);
7192
+ default: throw new BaseAPIError({
7193
+ statusCode: _response.error.statusCode,
7194
+ body: _response.error.body,
7195
+ rawResponse: _response.rawResponse
7196
+ });
7197
+ }
7198
+ return handleNonStatusCodeError$1(_response.error, _response.rawResponse, "DELETE", "/base/bases/{base_id}");
7199
+ }
7029
7200
  };
7030
7201
  var BindingPlanClient = class {
7031
7202
  _options;
@@ -8662,7 +8833,7 @@ function decodeJwt(jwt) {
8662
8833
  }
8663
8834
 
8664
8835
  //#endregion
8665
- //#region ../shared/dist/index.mjs
8836
+ //#region ../shared/dist/verify-ctx-token-BbswNLaV.mjs
8666
8837
  /**
8667
8838
  * Global authentication middleware for a platform resource server: require a
8668
8839
  * Bearer `aud=ctx` token and verify it offline via the injected verifier. A
@@ -8689,6 +8860,7 @@ function createCtxAuthMiddleware(verify, machineAzpAllowlist) {
8689
8860
  if (!token) return c.json({ error: "Missing bearer token." }, 401);
8690
8861
  const result = await verify(token);
8691
8862
  if (!result.ok) return c.json({ error: "Invalid token." }, 401);
8863
+ c.set("bearer", token);
8692
8864
  if (result.kind === "machine") {
8693
8865
  if (!machineAzpAllowlist.has(result.azp)) return c.json({ error: "Machine client not allowed." }, 403);
8694
8866
  c.set("machine", true);
@@ -8696,10 +8868,6 @@ function createCtxAuthMiddleware(verify, machineAzpAllowlist) {
8696
8868
  await next();
8697
8869
  };
8698
8870
  }
8699
- function ctxAuthHeaders(tokenProvider) {
8700
- if (!tokenProvider) return {};
8701
- return { headers: { Authorization: async () => `Bearer ${await tokenProvider()}` } };
8702
- }
8703
8871
  /**
8704
8872
  * jose error codes that mean "the presented token is invalid" → reject (401),
8705
8873
  * `reason` is the code (for logging only). Anything else — a JWKS timeout, a
@@ -8811,6 +8979,13 @@ function createDevJwtVerifier() {
8811
8979
  };
8812
8980
  }
8813
8981
 
8982
+ //#endregion
8983
+ //#region ../shared/dist/index.mjs
8984
+ function ctxAuthHeaders(tokenProvider) {
8985
+ if (!tokenProvider) return {};
8986
+ return { headers: { Authorization: async () => `Bearer ${await tokenProvider()}` } };
8987
+ }
8988
+
8814
8989
  //#endregion
8815
8990
  //#region ../slate-client/dist/index.mjs
8816
8991
  /**
@@ -8895,6 +9070,19 @@ var ForbiddenError = class extends SlateAPIError {
8895
9070
  this.name = "ForbiddenError";
8896
9071
  }
8897
9072
  };
9073
+ var NotFoundError = class extends SlateAPIError {
9074
+ constructor(body, rawResponse) {
9075
+ super({
9076
+ message: "NotFoundError",
9077
+ statusCode: 404,
9078
+ body,
9079
+ rawResponse
9080
+ });
9081
+ Object.setPrototypeOf(this, new.target.prototype);
9082
+ if (Error.captureStackTrace) Error.captureStackTrace(this, this.constructor);
9083
+ this.name = "NotFoundError";
9084
+ }
9085
+ };
8898
9086
  function mergeHeaders(...headersArray) {
8899
9087
  const result = {};
8900
9088
  for (const [key, value] of headersArray.filter((headers) => headers != null).flatMap((headers) => Object.entries(headers))) {
@@ -10114,6 +10302,29 @@ function createIdentitySchemaCreator(schemaType, validate) {
10114
10302
  };
10115
10303
  };
10116
10304
  }
10305
+ function enum_(values) {
10306
+ const validValues = new Set(values);
10307
+ return createIdentitySchemaCreator(SchemaType.ENUM, (value, { allowUnrecognizedEnumValues, breadcrumbsPrefix = [] } = {}) => {
10308
+ if (typeof value !== "string") return {
10309
+ ok: false,
10310
+ errors: [{
10311
+ path: breadcrumbsPrefix,
10312
+ message: getErrorMessageForIncorrectType(value, "string")
10313
+ }]
10314
+ };
10315
+ if (!validValues.has(value) && !allowUnrecognizedEnumValues) return {
10316
+ ok: false,
10317
+ errors: [{
10318
+ path: breadcrumbsPrefix,
10319
+ message: getErrorMessageForIncorrectType(value, "enum")
10320
+ }]
10321
+ };
10322
+ return {
10323
+ ok: true,
10324
+ value
10325
+ };
10326
+ })();
10327
+ }
10117
10328
  function entries(object) {
10118
10329
  return Object.entries(object);
10119
10330
  }
@@ -10688,6 +10899,8 @@ const CreateWorkspaceInput = object$1({
10688
10899
  synthesizerImage: property("synthesizer_image", string$2().optional()),
10689
10900
  tick: string$2().optional()
10690
10901
  });
10902
+ const DeleteWorkspaceRequestDeleteBases = enum_(["true", "false"]);
10903
+ const DeleteWorkspaceRequestDeleteRepos = enum_(["true", "false"]);
10691
10904
  const BridgePlan = object$1({
10692
10905
  baseIds: property("base_ids", list(string$2())),
10693
10906
  claudeOauthToken: property("claude_oauth_token", string$2().nullable()),
@@ -11129,6 +11342,72 @@ var WorkspacesClient = class {
11129
11342
  }
11130
11343
  return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/slate/workspaces");
11131
11344
  }
11345
+ /**
11346
+ * @param {SlateAPI.DeleteWorkspaceRequest} request
11347
+ * @param {WorkspacesClient.RequestOptions} requestOptions - Request-specific configuration.
11348
+ *
11349
+ * @throws {@link SlateAPI.ForbiddenError}
11350
+ * @throws {@link SlateAPI.NotFoundError}
11351
+ *
11352
+ * @example
11353
+ * await client.workspaces.deleteWorkspace({
11354
+ * workspaceId: "workspace_id"
11355
+ * })
11356
+ */
11357
+ deleteWorkspace(request, requestOptions) {
11358
+ return HttpResponsePromise.fromPromise(this.__deleteWorkspace(request, requestOptions));
11359
+ }
11360
+ async __deleteWorkspace(request, requestOptions) {
11361
+ const { workspaceId, deleteBases, deleteRepos } = request;
11362
+ const _queryParams = {
11363
+ delete_bases: deleteBases != null ? DeleteWorkspaceRequestDeleteBases.jsonOrThrow(deleteBases, {
11364
+ unrecognizedObjectKeys: "strip",
11365
+ omitUndefined: true
11366
+ }) : void 0,
11367
+ delete_repos: deleteRepos != null ? DeleteWorkspaceRequestDeleteRepos.jsonOrThrow(deleteRepos, {
11368
+ unrecognizedObjectKeys: "strip",
11369
+ omitUndefined: true
11370
+ }) : void 0
11371
+ };
11372
+ const _headers = mergeHeaders(this._options?.headers, requestOptions?.headers);
11373
+ const _response = await fetcher({
11374
+ url: join(await Supplier.get(this._options.baseUrl) ?? await Supplier.get(this._options.environment), `slate/workspaces/${encodePathParam(workspaceId)}`),
11375
+ method: "DELETE",
11376
+ headers: _headers,
11377
+ queryString: queryBuilder().addMany(_queryParams).mergeAdditional(requestOptions?.queryParams).build(),
11378
+ timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1e3,
11379
+ maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
11380
+ abortSignal: requestOptions?.abortSignal,
11381
+ fetchFn: this._options?.fetch,
11382
+ logging: this._options.logging
11383
+ });
11384
+ if (_response.ok) return {
11385
+ data: void 0,
11386
+ rawResponse: _response.rawResponse
11387
+ };
11388
+ if (_response.error.reason === "status-code") switch (_response.error.statusCode) {
11389
+ case 403: throw new ForbiddenError(Error_.parseOrThrow(_response.error.body, {
11390
+ unrecognizedObjectKeys: "passthrough",
11391
+ allowUnrecognizedUnionMembers: true,
11392
+ allowUnrecognizedEnumValues: true,
11393
+ skipValidation: true,
11394
+ breadcrumbsPrefix: ["response"]
11395
+ }), _response.rawResponse);
11396
+ case 404: throw new NotFoundError(Error_.parseOrThrow(_response.error.body, {
11397
+ unrecognizedObjectKeys: "passthrough",
11398
+ allowUnrecognizedUnionMembers: true,
11399
+ allowUnrecognizedEnumValues: true,
11400
+ skipValidation: true,
11401
+ breadcrumbsPrefix: ["response"]
11402
+ }), _response.rawResponse);
11403
+ default: throw new SlateAPIError({
11404
+ statusCode: _response.error.statusCode,
11405
+ body: _response.error.body,
11406
+ rawResponse: _response.rawResponse
11407
+ });
11408
+ }
11409
+ return handleNonStatusCodeError(_response.error, _response.rawResponse, "DELETE", "/slate/workspaces/{workspace_id}");
11410
+ }
11132
11411
  };
11133
11412
  var SlateAPIClient = class {
11134
11413
  _options;
@@ -14811,6 +15090,9 @@ const ZodURL = /*@__PURE__*/ $constructor("ZodURL", (inst, def) => {
14811
15090
  $ZodURL.init(inst, def);
14812
15091
  ZodStringFormat.init(inst, def);
14813
15092
  });
15093
+ function url(params) {
15094
+ return _url(ZodURL, params);
15095
+ }
14814
15096
  const ZodEmoji = /*@__PURE__*/ $constructor("ZodEmoji", (inst, def) => {
14815
15097
  $ZodEmoji.init(inst, def);
14816
15098
  ZodStringFormat.init(inst, def);
@@ -15320,6 +15602,118 @@ function number(params) {
15320
15602
  //#endregion
15321
15603
  //#region ../slate-shared/dist/index.mjs
15322
15604
  const WORKSPACE_DOCS_SUBDIR = "output";
15605
+ const INBOX_CONTENT_TREE = {
15606
+ "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",
15607
+ "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",
15608
+ "output/types/action.loader.js": `export default async ({ vault, path }) => {
15609
+ const node = vault.get(path)
15610
+ return { items: [{ body: node.body, path: node.path, title: node.title }] }
15611
+ }
15612
+ `,
15613
+ "output/types/action.render-spec.json": `${JSON.stringify({ render: {
15614
+ elements: {
15615
+ ask: {
15616
+ children: ["askLabel"],
15617
+ on: { press: {
15618
+ action: "openChat",
15619
+ params: {
15620
+ autoSend: false,
15621
+ content: { $template: "What should I know about @output/${path}?" }
15622
+ }
15623
+ } },
15624
+ props: { className: null },
15625
+ type: "Pressable"
15626
+ },
15627
+ askLabel: {
15628
+ props: { text: "Ask about this doc" },
15629
+ type: "Text"
15630
+ },
15631
+ body: {
15632
+ props: { text: { $item: "body" } },
15633
+ type: "Text"
15634
+ },
15635
+ card: {
15636
+ children: [
15637
+ "body",
15638
+ "draft",
15639
+ "ask"
15640
+ ],
15641
+ props: { title: { $item: "title" } },
15642
+ type: "Card"
15643
+ },
15644
+ detail: {
15645
+ children: ["card"],
15646
+ props: {
15647
+ className: "mx-auto max-w-md p-8",
15648
+ direction: "vertical",
15649
+ gap: "md"
15650
+ },
15651
+ repeat: {
15652
+ key: "path",
15653
+ statePath: "/items"
15654
+ },
15655
+ type: "Stack"
15656
+ },
15657
+ draft: {
15658
+ children: ["draftLabel"],
15659
+ on: { press: {
15660
+ action: "openChat",
15661
+ params: {
15662
+ autoSend: true,
15663
+ content: { $template: "Draft a reply to @output/${path}" }
15664
+ }
15665
+ } },
15666
+ props: { className: null },
15667
+ type: "Pressable"
15668
+ },
15669
+ draftLabel: {
15670
+ props: { text: "Draft reply" },
15671
+ type: "Text"
15672
+ }
15673
+ },
15674
+ root: "detail"
15675
+ } }, null, " ")}\n`,
15676
+ "output/views/inbox.loader.js": `export default async ({ vault }) => {
15677
+ const items = vault
15678
+ .all()
15679
+ .filter((entry) => entry.type === "Action")
15680
+ .map((entry) => ({ path: entry.path, title: entry.title }))
15681
+ .sort((a, b) => a.title.localeCompare(b.title))
15682
+ return { items }
15683
+ }
15684
+ `,
15685
+ "output/views/inbox.render-spec.json": `${JSON.stringify({ render: {
15686
+ elements: {
15687
+ card: {
15688
+ props: { title: { $item: "title" } },
15689
+ type: "Card"
15690
+ },
15691
+ list: {
15692
+ children: ["row"],
15693
+ props: {
15694
+ className: "mx-auto max-w-md p-8",
15695
+ direction: "vertical",
15696
+ gap: "md"
15697
+ },
15698
+ repeat: {
15699
+ key: "path",
15700
+ statePath: "/items"
15701
+ },
15702
+ type: "Stack"
15703
+ },
15704
+ row: {
15705
+ children: ["card"],
15706
+ on: { press: {
15707
+ action: "navigate",
15708
+ params: { path: { $template: "${path}" } }
15709
+ } },
15710
+ props: { className: null },
15711
+ type: "Pressable"
15712
+ }
15713
+ },
15714
+ root: "list"
15715
+ } }, null, " ")}\n`
15716
+ };
15323
15717
  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
15718
  function segment(value, label) {
15325
15719
  const result = segmentSchema.safeParse(value);
@@ -42900,16 +43294,16 @@ function osUsername() {
42900
43294
  }
42901
43295
 
42902
43296
  //#endregion
42903
- //#region ../slate-bridge/dist/index.mjs
43297
+ //#region ../slate-bridge/dist/goldens-bnwfOrjq.mjs
42904
43298
  const nonEmptyStringSchema = string().trim().min(1);
42905
43299
  const portSchema = number().int().min(0).max(65535).default(7777);
42906
43300
  const envSchema = object({
42907
43301
  CTX_AUTH_SKIP_VERIFY_JWT: string().optional().transform((v) => v === "true"),
42908
43302
  CTX_GIT_HOST_BASE_DIR: nonEmptyStringSchema.default(() => path.join(os.homedir(), ".contextlayer", "repos")),
42909
- CTX_PLATFORM_URL: nonEmptyStringSchema.default("http://127.0.0.1:3010"),
42910
- CTX_WEB_URL: nonEmptyStringSchema.default("http://localhost:3000").transform((url) => url.replace(/\/+$/, "")),
43303
+ CTX_PLATFORM_URL: url().default("http://127.0.0.1:3010").transform((url) => url.replace(/\/+$/, "")),
43304
+ CTX_WEB_URL: url().default("http://localhost:3000").transform((url) => url.replace(/\/+$/, "")),
42911
43305
  CTXS_BRIDGE_PORT: portSchema,
42912
- CTXS_CLAUDE_IMAGE: nonEmptyStringSchema.default("ghcr.io/usecontextlayer/ctx-sandbox:0.5.5"),
43306
+ CTXS_CLAUDE_IMAGE: nonEmptyStringSchema.default("ghcr.io/usecontextlayer/ctx-sandbox:0.5.7"),
42913
43307
  CTXS_CLAUDE_MODEL: nonEmptyStringSchema.default("opus"),
42914
43308
  CTXS_HOST_CLAUDE_JSON_PATH: nonEmptyStringSchema.default(() => path.join(os.homedir(), ".claude.json")),
42915
43309
  NODE_ENV: _enum([
@@ -43263,7 +43657,21 @@ const CLAUDE_ARGS = [
43263
43657
  "--thinking-display",
43264
43658
  "summarized",
43265
43659
  "--permission-mode",
43266
- "bypassPermissions"
43660
+ "bypassPermissions",
43661
+ "--append-system-prompt",
43662
+ `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.
43663
+
43664
+ 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.
43665
+
43666
+ 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\`.
43667
+
43668
+ 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.
43669
+
43670
+ 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.
43671
+
43672
+ 5. The \`.engine/\` directory is the synthesis engine's private state. Leave it alone unless the user explicitly asks.
43673
+
43674
+ 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
43675
  ];
43268
43676
  function bearerToken(c) {
43269
43677
  const header = c.req.header("Authorization") ?? "";
@@ -43288,6 +43696,15 @@ function assertSingleBaseId(baseIds, workspaceId) {
43288
43696
  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
43697
  return baseId;
43290
43698
  }
43699
+ function noteDivergedCheckout(workspaceId) {
43700
+ console.error(`[slate-bridge] workspace ${workspaceId} checkout has unpushed commits while origin moved (unfinished heal) — serving the local tree`);
43701
+ Sentry.addBreadcrumb({
43702
+ category: "workspace-checkout",
43703
+ data: { workspaceId },
43704
+ level: "warning",
43705
+ message: "diverged workspace checkout served as-is"
43706
+ });
43707
+ }
43291
43708
  function isTurnResult(line) {
43292
43709
  if (!line.includes("\"type\":\"result\"")) return false;
43293
43710
  try {
@@ -43337,11 +43754,12 @@ async function createBridgeServer(opts) {
43337
43754
  const rawParams = (await c.req.json()).params ?? {};
43338
43755
  try {
43339
43756
  const userToken = bearerToken(c);
43340
- const { head, rootDir } = await materializeWorkspaceTree(workspaceId, {
43757
+ const { head, rootDir, freshness } = await ensureWorkspaceCheckout(workspaceId, {
43341
43758
  gitHostBaseDir,
43342
43759
  platformUrl,
43343
43760
  token: userToken
43344
43761
  });
43762
+ if (freshness === "held_diverged") noteDivergedCheckout(workspaceId);
43345
43763
  const result = await runWorkspaceView({
43346
43764
  rawParams,
43347
43765
  resolveDsn: () => resolveRenderDsn(platformUrl, workspaceId, userToken),
@@ -43361,11 +43779,12 @@ async function createBridgeServer(opts) {
43361
43779
  const rawParams = body.params ?? {};
43362
43780
  try {
43363
43781
  const userToken = bearerToken(c);
43364
- const { head, rootDir } = await materializeWorkspaceTree(workspaceId, {
43782
+ const { head, rootDir, freshness } = await ensureWorkspaceCheckout(workspaceId, {
43365
43783
  gitHostBaseDir,
43366
43784
  platformUrl,
43367
43785
  token: userToken
43368
43786
  });
43787
+ if (freshness === "held_diverged") noteDivergedCheckout(workspaceId);
43369
43788
  const vault = await vaults.get(rootDir, head);
43370
43789
  const result = await runWorkspaceContent({
43371
43790
  contentPath: body.path,
@@ -43411,11 +43830,13 @@ async function createBridgeServer(opts) {
43411
43830
  let phase = "boot";
43412
43831
  try {
43413
43832
  const plan = await fetchBridgePlan(platformUrl, workspaceId, userToken);
43414
- const [, { rootDir }] = await Promise.all([claudeRepo.restore(), materializeWorkspaceTree(workspaceId, {
43833
+ const [, checkout] = await Promise.all([claudeRepo.restore(), ensureWorkspaceCheckout(workspaceId, {
43415
43834
  gitHostBaseDir,
43416
43835
  platformUrl,
43417
43836
  token: userToken
43418
43837
  })]);
43838
+ if (checkout.freshness === "held_diverged") noteDivergedCheckout(workspaceId);
43839
+ const rootDir = checkout.rootDir;
43419
43840
  if (ac.signal.aborted) return;
43420
43841
  session = await createClaudeMicrosandbox({
43421
43842
  claudeHomeHostDir: claudeRepo.hostDir,
@@ -43435,7 +43856,12 @@ async function createBridgeServer(opts) {
43435
43856
  ],
43436
43857
  env: {
43437
43858
  CLAUDE_CODE_ENTRYPOINT: "sdk-ts",
43438
- ...plan.claudeOauthToken ? { CLAUDE_CODE_OAUTH_TOKEN: plan.claudeOauthToken } : {}
43859
+ ...plan.claudeOauthToken ? { CLAUDE_CODE_OAUTH_TOKEN: plan.claudeOauthToken } : {},
43860
+ ...guestGitEnv({
43861
+ platformUrl,
43862
+ sub: r.sub,
43863
+ token: userToken
43864
+ })
43439
43865
  },
43440
43866
  signal: ac.signal
43441
43867
  });
@@ -43513,6 +43939,72 @@ async function createBridgeServer(opts) {
43513
43939
  port: address.port
43514
43940
  };
43515
43941
  }
43942
+ const PARITY_SCENARIOS = [
43943
+ {
43944
+ name: "text-only",
43945
+ turns: ["Reply with exactly one word: hello", "Now reply with exactly one word: goodbye"]
43946
+ },
43947
+ {
43948
+ name: "code-writing",
43949
+ turns: [
43950
+ "Create a file calc.js that exports a function add(a, b) returning a + b. Use module.exports. Just write the file, no explanation.",
43951
+ "Add a function sub(a, b) returning a - b to calc.js, keeping add. Export both.",
43952
+ "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.",
43953
+ "In one sentence, what does calc.js export now?"
43954
+ ]
43955
+ },
43956
+ {
43957
+ name: "thinking-and-error",
43958
+ turns: [
43959
+ "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.",
43960
+ "Read the file /tmp/definitely-does-not-exist-9f3a.txt and tell me its contents.",
43961
+ "In one short sentence, acknowledge that the file could not be read."
43962
+ ]
43963
+ },
43964
+ {
43965
+ name: "compaction",
43966
+ turns: [
43967
+ "In two short paragraphs, explain how the TCP three-way handshake works.",
43968
+ "Now, in two short paragraphs, explain how a TLS 1.3 handshake works.",
43969
+ "List three concrete differences between TCP and UDP.",
43970
+ "/compact",
43971
+ "What topics were we just discussing? Answer in one sentence.",
43972
+ "Reply with exactly one word: done"
43973
+ ]
43974
+ },
43975
+ {
43976
+ name: "multi-file-tools",
43977
+ 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."]
43978
+ },
43979
+ {
43980
+ name: "web-tools",
43981
+ 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?"]
43982
+ },
43983
+ {
43984
+ name: "long-conversation",
43985
+ turns: [
43986
+ "Name a primary color. Reply with one word.",
43987
+ "Name a different primary color. Reply with one word.",
43988
+ "Name the third primary color. Reply with one word.",
43989
+ "What color do you get mixing red and blue? Reply with one word.",
43990
+ "Summarize this conversation in one short sentence.",
43991
+ "Reply with exactly one word: bye"
43992
+ ]
43993
+ }
43994
+ ];
43995
+ function resolveGoldensDir() {
43996
+ let dir = path.dirname(fileURLToPath(import.meta.url));
43997
+ while (true) {
43998
+ const candidate = path.join(dir, "slate-shared", "lib", "__goldens__");
43999
+ if (existsSync(candidate)) return candidate;
44000
+ const parent = path.dirname(dir);
44001
+ if (parent === dir) throw new Error(`[parity] could not locate slate-shared/lib/__goldens__ above ${fileURLToPath(import.meta.url)}`);
44002
+ dir = parent;
44003
+ }
44004
+ }
44005
+
44006
+ //#endregion
44007
+ //#region ../slate-bridge/dist/index.mjs
43516
44008
  async function writeJsonAtomic(filePath, value) {
43517
44009
  const tmp = `${filePath}.tmp`;
43518
44010
  await writeFile(tmp, `${JSON.stringify(value, null, 2)}\n`);
@@ -47661,4 +48153,4 @@ runCli().catch((error) => {
47661
48153
  //#endregion
47662
48154
  export { createProgram, runCli };
47663
48155
  //# sourceMappingURL=cli.mjs.map
47664
- //# debugId=5e70b90f-e938-570a-b3e3-d35af180a822
48156
+ //# debugId=a525501b-8c62-5a9e-a76f-b82b01d56d75