@usecontextlayer/ctxs 0.5.9 → 0.5.11
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 +134 -124
- package/dist/cli.mjs.map +1 -1
- package/package.json +4 -4
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]="e80413c9-3000-584e-9bcf-799375152efc")}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";
|
|
@@ -65,7 +65,7 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
|
65
65
|
|
|
66
66
|
//#endregion
|
|
67
67
|
//#region package.json
|
|
68
|
-
var version$2 = "0.5.
|
|
68
|
+
var version$2 = "0.5.11";
|
|
69
69
|
|
|
70
70
|
//#endregion
|
|
71
71
|
//#region sentry.ts
|
|
@@ -368,7 +368,7 @@ function pggitUrl(remote) {
|
|
|
368
368
|
* (RepoRemote, gitHostBaseDir) -> Repo. The all-slashes repoId IS the path under the
|
|
369
369
|
* base (`hostDir = <base>/<repoId>`) — one layout rule for every repo kind, and since
|
|
370
370
|
* `workspace/…` and `claude/…` are disjoint subtrees, a claude home can never land
|
|
371
|
-
* inside a
|
|
371
|
+
* inside a workspace repo. The returned `hostDir` is
|
|
372
372
|
* realpath-canonical: we realpath the base (which must already exist) and join the
|
|
373
373
|
* repoId, so macOS-dev symlinks (`/tmp -> /private/tmp`) are resolved up front. That
|
|
374
374
|
* matters because claude derives its session bucket from the cwd STRING — host-side
|
|
@@ -757,16 +757,16 @@ var ClaudeRepo = class ClaudeRepo {
|
|
|
757
757
|
/**
|
|
758
758
|
* One-sandbox-per-session — absorbs the bridge's `activeSessions`/4409 guard. The
|
|
759
759
|
* single-threaded event loop makes this check-and-set atomic at the WS upgrade.
|
|
760
|
-
*
|
|
761
|
-
*
|
|
760
|
+
* A pure guard — it spawns NO git work: a clone started here would have no owner to
|
|
761
|
+
* join it when a boot fails before the caller awaits restore(), leaving a writer
|
|
762
|
+
* racing teardown. A watching restore-less home is watchable immediately, so its
|
|
763
|
+
* first live session arms the convergence watcher here; a restoring home becomes
|
|
764
|
+
* watchable only inside restore().
|
|
762
765
|
*/
|
|
763
766
|
tryAcquireSession(sessionId) {
|
|
764
767
|
if (this.activeSessions.has(sessionId)) return false;
|
|
765
768
|
this.activeSessions.add(sessionId);
|
|
766
|
-
|
|
767
|
-
if (watch !== false && this.watchTimer === null) this.restore().then(() => {
|
|
768
|
-
if (this.activeSessions.size > 0 && this.watchTimer === null) this.startWatch(watch);
|
|
769
|
-
}, () => {});
|
|
769
|
+
if (!this.config.restore) this.maybeStartWatch();
|
|
770
770
|
return true;
|
|
771
771
|
}
|
|
772
772
|
releaseSession(sessionId) {
|
|
@@ -788,7 +788,9 @@ var ClaudeRepo = class ClaudeRepo {
|
|
|
788
788
|
if (this.watchTimer !== null && this.watchWakeAt - now > opened.wakeAfterMs) this.armWatch(watch, opened.wakeAfterMs);
|
|
789
789
|
}
|
|
790
790
|
/**
|
|
791
|
-
* Clone-on-first-use into the host dir (slate resume)
|
|
791
|
+
* Clone-on-first-use into the host dir (slate resume), and the ONE initiator of that
|
|
792
|
+
* clone. The call is the ownership contract: whoever starts the clone awaits it, so
|
|
793
|
+
* it can never outlive the scope that started it. A no-op for a capture-only
|
|
792
794
|
* home (`restore:false`) and after the first success — memoized so concurrent sessions
|
|
793
795
|
* don't double-clone. Restore failure **propagates**: the caller blocks the connection
|
|
794
796
|
* — no boot → no capture → the good repo is untouched. (Proceeding fresh would try to
|
|
@@ -796,6 +798,9 @@ var ClaudeRepo = class ClaudeRepo {
|
|
|
796
798
|
* silent destruction, but restore-first stays the invariant:
|
|
797
799
|
* a rejected capture is still a broken session.) The memo is cleared on failure so a
|
|
798
800
|
* later connection retries rather than inheriting a permanent rejection.
|
|
801
|
+
* Every success — fresh clone or memoized warm reconnect — arms the watcher when a
|
|
802
|
+
* session is live: the watcher stops with the last release, so a reconnect to the
|
|
803
|
+
* kept-warm singleton must re-arm here or the whole session runs unconverged.
|
|
799
804
|
*/
|
|
800
805
|
async restore() {
|
|
801
806
|
if (!this.config.restore) return;
|
|
@@ -803,7 +808,8 @@ var ClaudeRepo = class ClaudeRepo {
|
|
|
803
808
|
this.restorePromise = null;
|
|
804
809
|
throw err;
|
|
805
810
|
});
|
|
806
|
-
|
|
811
|
+
await this.restorePromise;
|
|
812
|
+
this.maybeStartWatch();
|
|
807
813
|
}
|
|
808
814
|
/**
|
|
809
815
|
* Does the (restored) home already hold this session's transcript? Drives `--resume` vs
|
|
@@ -858,6 +864,10 @@ var ClaudeRepo = class ClaudeRepo {
|
|
|
858
864
|
}
|
|
859
865
|
if (current !== CLAUDE_HOME_GITIGNORE) await writeFile(target, CLAUDE_HOME_GITIGNORE);
|
|
860
866
|
}
|
|
867
|
+
maybeStartWatch() {
|
|
868
|
+
const watch = this.config.watch;
|
|
869
|
+
if (watch !== false && this.activeSessions.size > 0 && this.watchTimer === null) this.startWatch(watch);
|
|
870
|
+
}
|
|
861
871
|
startWatch(config) {
|
|
862
872
|
const opened = openHotWindow(Date.now(), config);
|
|
863
873
|
this.watchState = opened.state;
|
|
@@ -14255,17 +14265,15 @@ function ctxAuthHeaders(tokenProvider) {
|
|
|
14255
14265
|
|
|
14256
14266
|
//#endregion
|
|
14257
14267
|
//#region ../slate-shared/dist/index.mjs
|
|
14258
|
-
const
|
|
14259
|
-
|
|
14260
|
-
|
|
14261
|
-
|
|
14262
|
-
|
|
14263
|
-
|
|
14264
|
-
if (!node) {
|
|
14265
|
-
throw new Error(\`update: no entry at "\${path}"\`)
|
|
14268
|
+
const INBOX_DOCS_TREE = {
|
|
14269
|
+
"docs/types/update.loader.js": `// types/update.loader.js
|
|
14270
|
+
export default async ({ docs, path }) => {
|
|
14271
|
+
const doc = docs.get(path)
|
|
14272
|
+
if (!doc) {
|
|
14273
|
+
throw new Error(\`update: no doc at "\${path}"\`)
|
|
14266
14274
|
}
|
|
14267
14275
|
|
|
14268
|
-
const item =
|
|
14276
|
+
const item = docs.query({
|
|
14269
14277
|
find: {
|
|
14270
14278
|
scalar: {
|
|
14271
14279
|
pattern: [
|
|
@@ -14283,13 +14291,13 @@ export default async ({ vault, path }) => {
|
|
|
14283
14291
|
where: [["?u", "path", path]],
|
|
14284
14292
|
})
|
|
14285
14293
|
if (!item) {
|
|
14286
|
-
throw new Error(\`update:
|
|
14294
|
+
throw new Error(\`update: doc "\${path}" not in the query index\`)
|
|
14287
14295
|
}
|
|
14288
14296
|
|
|
14289
|
-
return { items: [{ ...item, body:
|
|
14297
|
+
return { items: [{ ...item, body: doc.body }] }
|
|
14290
14298
|
}
|
|
14291
14299
|
`,
|
|
14292
|
-
"
|
|
14300
|
+
"docs/types/update.render-spec.json": `${JSON.stringify({ render: {
|
|
14293
14301
|
elements: {
|
|
14294
14302
|
body: {
|
|
14295
14303
|
props: { text: { $item: "body" } },
|
|
@@ -14367,20 +14375,20 @@ export default async ({ vault, path }) => {
|
|
|
14367
14375
|
},
|
|
14368
14376
|
root: "detail"
|
|
14369
14377
|
} }, null, " ")}\n`,
|
|
14370
|
-
"
|
|
14371
|
-
"
|
|
14372
|
-
"
|
|
14373
|
-
"
|
|
14374
|
-
"
|
|
14375
|
-
"
|
|
14376
|
-
"
|
|
14377
|
-
"
|
|
14378
|
+
"docs/updates/baltic-archival-scripts-revision-07-13.md": "---\ntype: Update\nproposed_title: Baltic - Revised Archival Scripts 07/13\nlane: Baltic - Data Archival\nkind: release\noccurred_on: 2026-07-13\nlast_updated: 2026-07-14\n---\n# Baltic - Revised Archival Scripts 07/13\n\nAdd **Baltic - Revised Archival Scripts 07/13** to the **Baltic - Data Archival** lane.\n\nYou sent the revised archival scripts on 2026-07-13 and the run window moved to Saturday night. Confirm the dry-run output lands in the shared drive before the window opens.\n",
|
|
14379
|
+
"docs/updates/baltic-dlp-matrix-redlines-07-06.md": "---\ntype: Update\nproposed_title: Baltic - DLP Matrix Redlines 07/06\nlane: Baltic - Data Archival\nkind: feedback\noccurred_on: 2026-07-06\nlast_updated: 2026-07-07\n---\n# Baltic - DLP Matrix Redlines 07/06\n\nAdd **Baltic - DLP Matrix Redlines 07/06** to the **Baltic - Data Archival** lane.\n\nMarcus Reid redlined the DLP sensitivity matrix on 2026-07-06: two label tiers collapsed into one and the finance share is missing. He expects a revised matrix this week.\n",
|
|
14380
|
+
"docs/updates/cascade-discovery-session-priya-07-12.md": "---\ntype: Update\nproposed_title: Cascade - Discovery Session (Priya) 07/12\nneeds_lane: true\nkind: call\noccurred_on: 2026-07-12\nlast_updated: 2026-07-13\n---\n# Cascade - Discovery Session (Priya) 07/12\n\nAdd **Cascade - Discovery Session (Priya) 07/12** — no lane confidently matches, so pick one.\n\nPriya Raman walked through the intake flow on the 2026-07-12 call and left three action items: the duplicate-vendor report, the approval-chain diagram, and a follow-up with her ops lead.\n",
|
|
14381
|
+
"docs/updates/cascade-final-invoice-06-30.md": "---\ntype: Update\nproposed_title: Cascade - Final Invoice 06/30\nlane: Cascade - ERP Cutover\nkind: followup\noccurred_on: 2026-06-30\nlast_updated: 2026-07-01\n---\n# Cascade - Final Invoice 06/30\n\nAdd **Cascade - Final Invoice 06/30** to the **Cascade - ERP Cutover** lane.\n\nClose out the quarter: the final cutover invoice is drafted but unsent. Ship it and file the copy against the engagement folder.\n",
|
|
14382
|
+
"docs/updates/harbor-training-proposal-followup-07-08.md": "---\ntype: Update\nproposed_title: Harbor - Training Proposal Follow-up 07/08\nlane: Harbor - Compliance Training\nkind: followup\noccurred_on: 2026-07-08\nlast_updated: 2026-07-09\n---\n# Harbor - Training Proposal Follow-up 07/08\n\nAdd **Harbor - Training Proposal Follow-up 07/08** to the **Harbor - Compliance Training** lane.\n\nThe training proposal went out 2026-07-01 and Harbor has not responded. A one-line nudge to Elena Cho keeps the September session dates holdable.\n",
|
|
14383
|
+
"docs/updates/meridian-migration-batch-alignment-07-10.md": "---\ntype: Update\nproposed_title: Meridian - Migration Batch Alignment 07/10\nlane: Meridian - Billing Portal\nkind: call\noccurred_on: 2026-07-10\nlast_updated: 2026-07-10\n---\n# Meridian - Migration Batch Alignment 07/10\n\nAdd **Meridian - Migration Batch Alignment 07/10** to the **Meridian - Billing Portal** lane.\n\nOn the 2026-07-10 call you agreed to re-sequence batches 3 and 4 so the vendor tables land before invoice history. The revised batch plan is owed to their team.\n",
|
|
14384
|
+
"docs/updates/meridian-uat-currency-escalation-07-14.md": "---\ntype: Update\nproposed_title: Meridian - UAT Currency Escalation 07/14\nlane: Meridian - Billing Portal\nkind: feedback\noccurred_on: 2026-07-14\nlast_updated: 2026-07-14\n---\n# Meridian - UAT Currency Escalation 07/14\n\nAdd **Meridian - UAT Currency Escalation 07/14** to the **Meridian - Billing Portal** lane.\n\nDana Whitfield (Meridian AP lead) escalated the multi-currency UAT blocker on 2026-07-14: mixed-currency invoices still post at the wrong rate.[^1] She wants a fix date before Thursday's steering call.\n\n[^1]: ctx:///mail/messages?id=fixture-meridian-uat-0714\n",
|
|
14385
|
+
"docs/views/inbox.loader.js": `// Inbox rows shaped for the Table view: the client/short-title split derived
|
|
14378
14386
|
// from the proposed_title house style "<Client> - <thing>", and lane emitted
|
|
14379
14387
|
// as its display value ("Needs a lane" when unresolved) so the spec's
|
|
14380
14388
|
// variantOverride can mark it.
|
|
14381
|
-
export default async ({
|
|
14389
|
+
export default async ({ docs }) => {
|
|
14382
14390
|
const sort = [{ direction: "desc", field: "occurred_on" }]
|
|
14383
|
-
const rows =
|
|
14391
|
+
const rows = docs.query(
|
|
14384
14392
|
{
|
|
14385
14393
|
find: {
|
|
14386
14394
|
coll: {
|
|
@@ -14420,7 +14428,7 @@ export default async ({ vault }) => {
|
|
|
14420
14428
|
return { items }
|
|
14421
14429
|
}
|
|
14422
14430
|
`,
|
|
14423
|
-
"
|
|
14431
|
+
"docs/views/inbox.render-spec.json": `${JSON.stringify({ render: {
|
|
14424
14432
|
elements: {
|
|
14425
14433
|
freshness: {
|
|
14426
14434
|
props: {
|
|
@@ -14503,6 +14511,7 @@ export default async ({ vault }) => {
|
|
|
14503
14511
|
root: "page"
|
|
14504
14512
|
} }, null, " ")}\n`
|
|
14505
14513
|
};
|
|
14514
|
+
const DOCS_SUBDIR = "docs";
|
|
14506
14515
|
const segmentSchema = string$1().min(1, "a repoId segment must be non-empty").refine((s) => s !== "." && s !== ".." && !s.includes("/"), { message: "a repoId segment must not be '.'/'..' or contain '/'" });
|
|
14507
14516
|
function segment(value, label) {
|
|
14508
14517
|
const result = segmentSchema.safeParse(value);
|
|
@@ -56240,7 +56249,7 @@ function createScheduleApiClient(config) {
|
|
|
56240
56249
|
}
|
|
56241
56250
|
};
|
|
56242
56251
|
}
|
|
56243
|
-
const SERVER_VERSION = "0.5.
|
|
56252
|
+
const SERVER_VERSION = "0.5.11";
|
|
56244
56253
|
const guidDescription = "GUID from the synced Postgres tables";
|
|
56245
56254
|
const labelDescription = "Human-readable label rendered on the approval card";
|
|
56246
56255
|
function scheduleApiFromRequest(requestInfo) {
|
|
@@ -81213,7 +81222,7 @@ var require_datascript = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
81213
81222
|
}));
|
|
81214
81223
|
|
|
81215
81224
|
//#endregion
|
|
81216
|
-
//#region ../
|
|
81225
|
+
//#region ../docs/dist/index.mjs
|
|
81217
81226
|
var import_datascript = /* @__PURE__ */ __toESM(require_datascript(), 1);
|
|
81218
81227
|
function toPosixPath(value) {
|
|
81219
81228
|
return value.replaceAll("\\", "/");
|
|
@@ -81243,7 +81252,7 @@ function posixBasename(value) {
|
|
|
81243
81252
|
function normalizeRelativePath(value) {
|
|
81244
81253
|
const normalized = posixNormalize(toPosixPath(value).replace(/^\/+/, "").replace(/^\.\//, ""));
|
|
81245
81254
|
if (normalized === ".") return "";
|
|
81246
|
-
if (normalized === ".." || normalized.startsWith("../")) throw new Error(`Path escapes
|
|
81255
|
+
if (normalized === ".." || normalized.startsWith("../")) throw new Error(`Path escapes docs root: ${value}`);
|
|
81247
81256
|
return normalized;
|
|
81248
81257
|
}
|
|
81249
81258
|
function ensureMarkdownPath(value) {
|
|
@@ -81319,13 +81328,13 @@ function extractMarkdownLinks(content, knownTargets = []) {
|
|
|
81319
81328
|
function extractOutgoingLinks(content, knownTargets = []) {
|
|
81320
81329
|
return uniqueSorted([...extractWikilinks(content), ...extractMarkdownLinks(content, knownTargets)]);
|
|
81321
81330
|
}
|
|
81322
|
-
function resolveWikilink(target,
|
|
81331
|
+
function resolveWikilink(target, docs) {
|
|
81323
81332
|
const normalized = normalizeLinkTarget(target);
|
|
81324
81333
|
const exactPath = ensureMarkdownPath(normalized);
|
|
81325
|
-
const exact =
|
|
81334
|
+
const exact = docs.find((doc) => doc.path === exactPath);
|
|
81326
81335
|
if (exact) return exact;
|
|
81327
81336
|
if (normalized.includes("/")) return null;
|
|
81328
|
-
const matches =
|
|
81337
|
+
const matches = docs.filter((doc) => stemOf(doc.path) === normalized);
|
|
81329
81338
|
return matches.length === 1 ? matches[0] ?? null : null;
|
|
81330
81339
|
}
|
|
81331
81340
|
function unique(values) {
|
|
@@ -81334,16 +81343,16 @@ function unique(values) {
|
|
|
81334
81343
|
function uniqueSorted(values) {
|
|
81335
81344
|
return unique(values).sort((left, right) => left.localeCompare(right, void 0, { sensitivity: "base" }));
|
|
81336
81345
|
}
|
|
81337
|
-
function computeBacklinks(
|
|
81346
|
+
function computeBacklinks(docs) {
|
|
81338
81347
|
const backlinks = /* @__PURE__ */ new Map();
|
|
81339
|
-
for (const
|
|
81340
|
-
for (const
|
|
81341
|
-
const targets = new Set([...
|
|
81348
|
+
for (const doc of docs) backlinks.set(normalizeLinkTarget(doc.path), backlinks.get(normalizeLinkTarget(doc.path)) ?? []);
|
|
81349
|
+
for (const doc of docs) {
|
|
81350
|
+
const targets = new Set([...doc.outgoingLinks, ...Object.values(doc.relationships).flat()]);
|
|
81342
81351
|
for (const target of targets) {
|
|
81343
81352
|
const normalized = normalizeLinkTarget(target);
|
|
81344
|
-
addBacklink(backlinks, normalized,
|
|
81345
|
-
const resolved = resolveWikilink(normalized,
|
|
81346
|
-
if (resolved) addBacklink(backlinks, normalizeLinkTarget(resolved.path),
|
|
81353
|
+
addBacklink(backlinks, normalized, doc.path);
|
|
81354
|
+
const resolved = resolveWikilink(normalized, docs);
|
|
81355
|
+
if (resolved) addBacklink(backlinks, normalizeLinkTarget(resolved.path), doc.path);
|
|
81347
81356
|
}
|
|
81348
81357
|
}
|
|
81349
81358
|
for (const [target, sources] of backlinks) backlinks.set(target, sources.sort(comparePath));
|
|
@@ -81456,15 +81465,15 @@ function coerce(value) {
|
|
|
81456
81465
|
value
|
|
81457
81466
|
};
|
|
81458
81467
|
}
|
|
81459
|
-
function buildDb(
|
|
81468
|
+
function buildDb(docs) {
|
|
81460
81469
|
const tempidByPath = /* @__PURE__ */ new Map();
|
|
81461
|
-
|
|
81462
|
-
tempidByPath.set(
|
|
81470
|
+
docs.forEach((doc, index) => {
|
|
81471
|
+
tempidByPath.set(doc.path, -(index + 1));
|
|
81463
81472
|
});
|
|
81464
81473
|
const refEdges = /* @__PURE__ */ new Set();
|
|
81465
|
-
for (const
|
|
81474
|
+
for (const doc of docs) for (const edge of Object.keys(doc.relationships)) if (edge !== "type") refEdges.add(edge);
|
|
81466
81475
|
const manyScalar = /* @__PURE__ */ new Set();
|
|
81467
|
-
for (const
|
|
81476
|
+
for (const doc of docs) for (const [key, value] of Object.entries(doc.frontmatter)) if (!RESERVED.has(key) && !refEdges.has(key) && Array.isArray(value) && value.every(isScalar)) manyScalar.add(key);
|
|
81468
81477
|
const schema = { path: { ":db/unique": ":db.unique/identity" } };
|
|
81469
81478
|
for (const edge of refEdges) schema[edge] = {
|
|
81470
81479
|
":db/cardinality": ":db.cardinality/many",
|
|
@@ -81472,24 +81481,24 @@ function buildDb(entries) {
|
|
|
81472
81481
|
};
|
|
81473
81482
|
for (const attr of manyScalar) schema[attr] = { ":db/cardinality": ":db.cardinality/many" };
|
|
81474
81483
|
const tx = [];
|
|
81475
|
-
for (const
|
|
81484
|
+
for (const doc of docs) {
|
|
81476
81485
|
const datom = {
|
|
81477
|
-
":db/id": tempidByPath.get(
|
|
81478
|
-
path:
|
|
81479
|
-
title:
|
|
81486
|
+
":db/id": tempidByPath.get(doc.path),
|
|
81487
|
+
path: doc.path,
|
|
81488
|
+
title: doc.title
|
|
81480
81489
|
};
|
|
81481
|
-
if (
|
|
81482
|
-
for (const [key, value] of Object.entries(
|
|
81490
|
+
if (doc.type) datom.type = doc.type;
|
|
81491
|
+
for (const [key, value] of Object.entries(doc.frontmatter)) {
|
|
81483
81492
|
if (RESERVED.has(key) || refEdges.has(key)) continue;
|
|
81484
81493
|
const coerced = coerce(value);
|
|
81485
81494
|
if (coerced.ok) datom[key] = coerced.value;
|
|
81486
81495
|
}
|
|
81487
81496
|
for (const edge of refEdges) {
|
|
81488
|
-
const targets =
|
|
81497
|
+
const targets = doc.relationships[edge];
|
|
81489
81498
|
if (!targets) continue;
|
|
81490
81499
|
const refs = [];
|
|
81491
81500
|
for (const target of targets) {
|
|
81492
|
-
const resolved = resolveWikilink(target,
|
|
81501
|
+
const resolved = resolveWikilink(target, docs);
|
|
81493
81502
|
if (!resolved) continue;
|
|
81494
81503
|
const tempid = tempidByPath.get(resolved.path);
|
|
81495
81504
|
if (tempid !== void 0) refs.push(tempid);
|
|
@@ -81619,7 +81628,7 @@ function sortRows(rows, sort) {
|
|
|
81619
81628
|
if (cmp !== 0) return spec.direction === "asc" ? cmp : -cmp;
|
|
81620
81629
|
}
|
|
81621
81630
|
return left.index - right.index;
|
|
81622
|
-
}).map((
|
|
81631
|
+
}).map((item) => item.row);
|
|
81623
81632
|
}
|
|
81624
81633
|
function getPath(row, field) {
|
|
81625
81634
|
let current = row;
|
|
@@ -81629,7 +81638,7 @@ function getPath(row, field) {
|
|
|
81629
81638
|
}
|
|
81630
81639
|
return current;
|
|
81631
81640
|
}
|
|
81632
|
-
var
|
|
81641
|
+
var Docs = class {
|
|
81633
81642
|
root;
|
|
81634
81643
|
fs;
|
|
81635
81644
|
parseConcurrency;
|
|
@@ -81650,9 +81659,9 @@ var Vault = class {
|
|
|
81650
81659
|
const results = await mapConcurrent(walk.markdownFiles, this.parseConcurrency, async (relPath) => this.parseFile(relPath, knownPaths));
|
|
81651
81660
|
const jsonResults = await mapConcurrent(walk.jsonFiles, this.parseConcurrency, async (relPath) => this.parseJsonFile(relPath));
|
|
81652
81661
|
this.index = /* @__PURE__ */ new Map();
|
|
81653
|
-
for (const result of results) if (result.kind === "
|
|
81662
|
+
for (const result of results) if (result.kind === "doc") this.index.set(result.doc.path, result.doc);
|
|
81654
81663
|
this.jsonIndex = /* @__PURE__ */ new Map();
|
|
81655
|
-
for (const result of jsonResults) if (result.kind === "json") this.jsonIndex.set(result.
|
|
81664
|
+
for (const result of jsonResults) if (result.kind === "json") this.jsonIndex.set(result.jsonDoc.path, result.jsonDoc);
|
|
81656
81665
|
this.backlinkIndex = computeBacklinks(this.all());
|
|
81657
81666
|
this.queryDb = buildDb(this.all());
|
|
81658
81667
|
}
|
|
@@ -81682,13 +81691,13 @@ var Vault = class {
|
|
|
81682
81691
|
try {
|
|
81683
81692
|
const stat = await this.fs.stat(this.abs(relPath));
|
|
81684
81693
|
return {
|
|
81685
|
-
|
|
81694
|
+
doc: {
|
|
81686
81695
|
...parseMarkdown(await this.fs.readFile(this.abs(relPath), "utf8"), relPath, { knownPaths }),
|
|
81687
81696
|
createdAt: stat.birthtimeMs,
|
|
81688
81697
|
fileSize: stat.size,
|
|
81689
81698
|
modifiedAt: stat.mtimeMs
|
|
81690
81699
|
},
|
|
81691
|
-
kind: "
|
|
81700
|
+
kind: "doc"
|
|
81692
81701
|
};
|
|
81693
81702
|
} catch (error) {
|
|
81694
81703
|
if (isNotFound(error)) return { kind: "missing" };
|
|
@@ -81701,7 +81710,7 @@ var Vault = class {
|
|
|
81701
81710
|
const stat = await this.fs.stat(this.abs(relPath));
|
|
81702
81711
|
const content = await this.fs.readFile(this.abs(relPath), "utf8");
|
|
81703
81712
|
return {
|
|
81704
|
-
|
|
81713
|
+
jsonDoc: {
|
|
81705
81714
|
createdAt: stat.birthtimeMs,
|
|
81706
81715
|
fileSize: stat.size,
|
|
81707
81716
|
modifiedAt: stat.mtimeMs,
|
|
@@ -83706,7 +83715,7 @@ function osUsername() {
|
|
|
83706
83715
|
}
|
|
83707
83716
|
|
|
83708
83717
|
//#endregion
|
|
83709
|
-
//#region ../slate-bridge/dist/goldens-
|
|
83718
|
+
//#region ../slate-bridge/dist/goldens-BlwT0koM.mjs
|
|
83710
83719
|
const nonEmptyStringSchema = string$1().trim().min(1);
|
|
83711
83720
|
const portSchema = number$1().int().min(0).max(65535).default(7777);
|
|
83712
83721
|
const envSchema = object$2({
|
|
@@ -83715,7 +83724,7 @@ const envSchema = object$2({
|
|
|
83715
83724
|
CTX_PLATFORM_URL: url().default("http://127.0.0.1:3010").transform((url) => url.replace(/\/+$/, "")),
|
|
83716
83725
|
CTX_WEB_URL: url().default("http://localhost:3000").transform((url) => url.replace(/\/+$/, "")),
|
|
83717
83726
|
CTXS_BRIDGE_PORT: portSchema,
|
|
83718
|
-
CTXS_CLAUDE_IMAGE: nonEmptyStringSchema.default("ghcr.io/usecontextlayer/ctx-sandbox:0.5.
|
|
83727
|
+
CTXS_CLAUDE_IMAGE: nonEmptyStringSchema.default("ghcr.io/usecontextlayer/ctx-sandbox:0.5.11"),
|
|
83719
83728
|
CTXS_CLAUDE_MODEL: nonEmptyStringSchema.default("opus"),
|
|
83720
83729
|
CTXS_HOST_CLAUDE_JSON_PATH: nonEmptyStringSchema.default(() => path.join(os.homedir(), ".claude.json")),
|
|
83721
83730
|
NODE_ENV: _enum([
|
|
@@ -83735,7 +83744,7 @@ function fetchBridgePlan(platformUrl, workspaceId, userToken) {
|
|
|
83735
83744
|
}).plan.getBridgePlan({ workspaceId });
|
|
83736
83745
|
}
|
|
83737
83746
|
const CHAT_SYSTEM_PROMPT_GUEST_PATH = "/opt/ctx/chat-system-prompt.md";
|
|
83738
|
-
const CHAT_SYSTEM_PROMPT = `Your working directory is the user's workspace. The synthesized documents live under \`./
|
|
83747
|
+
const CHAT_SYSTEM_PROMPT = `Your working directory is the user's workspace. The synthesized documents live under \`./docs/\` — that is what the user sees and refers to in conversation. When the user mentions a document, project, or view, look in \`./docs/\` first. Files under \`./docs/\` are typed docs markdown — follow the \`docs-markdown-format\` skill when creating or editing them.
|
|
83739
83748
|
|
|
83740
83749
|
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.
|
|
83741
83750
|
|
|
@@ -84139,31 +84148,31 @@ const renderSpecSchema = strictObject({
|
|
|
84139
84148
|
async function runWorkspaceView(opts) {
|
|
84140
84149
|
if (!VIEW_NAME.test(opts.view)) throw new Error(`views/run: invalid view name "${opts.view}"`);
|
|
84141
84150
|
return runSurfacePair({
|
|
84151
|
+
docs: opts.docs,
|
|
84142
84152
|
missingLoader: `views/run: view "${opts.view}" has no loader (expected views/${opts.view}.loader.js)`,
|
|
84143
84153
|
rawParams: opts.rawParams,
|
|
84144
84154
|
resolveDsn: opts.resolveDsn,
|
|
84145
84155
|
rootDir: opts.rootDir,
|
|
84146
|
-
stem: `views/${opts.view}
|
|
84147
|
-
vault: opts.vault
|
|
84156
|
+
stem: `views/${opts.view}`
|
|
84148
84157
|
});
|
|
84149
84158
|
}
|
|
84150
|
-
async function
|
|
84151
|
-
const
|
|
84152
|
-
if (!
|
|
84153
|
-
if (!
|
|
84154
|
-
const slug = kebabCase(
|
|
84159
|
+
async function runWorkspaceDoc(opts) {
|
|
84160
|
+
const doc = opts.docs.get(opts.docPath);
|
|
84161
|
+
if (!doc) throw new Error(`docs/run: no doc at "${opts.docPath}"`);
|
|
84162
|
+
if (!doc.type) throw new Error(`docs/run: doc "${opts.docPath}" has no type`);
|
|
84163
|
+
const slug = kebabCase(doc.type);
|
|
84155
84164
|
return runSurfacePair({
|
|
84156
|
-
|
|
84157
|
-
|
|
84165
|
+
docPath: doc.path,
|
|
84166
|
+
docs: opts.docs,
|
|
84167
|
+
missingLoader: `docs/run: type "${doc.type}" has no loader (expected types/${slug}.loader.js)`,
|
|
84158
84168
|
rawParams: opts.rawParams,
|
|
84159
84169
|
resolveDsn: opts.resolveDsn,
|
|
84160
84170
|
rootDir: opts.rootDir,
|
|
84161
|
-
stem: `types/${slug}
|
|
84162
|
-
vault: opts.vault
|
|
84171
|
+
stem: `types/${slug}`
|
|
84163
84172
|
});
|
|
84164
84173
|
}
|
|
84165
84174
|
async function runSurfacePair(opts) {
|
|
84166
|
-
const base = path.join(opts.rootDir,
|
|
84175
|
+
const base = path.join(opts.rootDir, DOCS_SUBDIR, opts.stem);
|
|
84167
84176
|
const loaderSource = await readLoaderSource(`${base}.loader.js`, opts.missingLoader);
|
|
84168
84177
|
const def = renderSpecSchema.parse(JSON.parse(await fs$2.readFile(`${base}.render-spec.json`, "utf8")));
|
|
84169
84178
|
const { defaults, effective } = resolveParams(def.params ?? {}, opts.rawParams);
|
|
@@ -84171,10 +84180,10 @@ async function runSurfacePair(opts) {
|
|
|
84171
84180
|
try {
|
|
84172
84181
|
return {
|
|
84173
84182
|
data: await executeLoader(loaderSource, `${opts.stem}.loader.js`, {
|
|
84183
|
+
docs: docsFacade(opts.docs),
|
|
84174
84184
|
params: effective,
|
|
84175
|
-
...opts.
|
|
84176
|
-
sql: sqlRunner.sql
|
|
84177
|
-
vault: vaultFacade(opts.vault)
|
|
84185
|
+
...opts.docPath === void 0 ? {} : { path: opts.docPath },
|
|
84186
|
+
sql: sqlRunner.sql
|
|
84178
84187
|
}),
|
|
84179
84188
|
paramDefaults: defaults,
|
|
84180
84189
|
params: effective,
|
|
@@ -84204,13 +84213,13 @@ function resolveParams(defs, raw) {
|
|
|
84204
84213
|
effective
|
|
84205
84214
|
};
|
|
84206
84215
|
}
|
|
84207
|
-
function
|
|
84216
|
+
function docsFacade(docs) {
|
|
84208
84217
|
return {
|
|
84209
|
-
all: () =>
|
|
84210
|
-
backlinks: (target) =>
|
|
84211
|
-
get: (
|
|
84212
|
-
getJson: (jsonPath) =>
|
|
84213
|
-
query: (query, queryOpts) =>
|
|
84218
|
+
all: () => docs.all(),
|
|
84219
|
+
backlinks: (target) => docs.backlinks(target),
|
|
84220
|
+
get: (docPath) => docs.get(docPath),
|
|
84221
|
+
getJson: (jsonPath) => docs.getJson(jsonPath),
|
|
84222
|
+
query: (query, queryOpts) => docs.query(query, queryOpts)
|
|
84214
84223
|
};
|
|
84215
84224
|
}
|
|
84216
84225
|
function createSqlRunner(resolveDsn) {
|
|
@@ -84245,16 +84254,16 @@ function marshalCapabilities(capabilities) {
|
|
|
84245
84254
|
const marshalArg = (value) => value !== null && typeof value === "object" ? structuredClone(value) : value;
|
|
84246
84255
|
const marshalFn = (fn) => (...args) => fn(...args.map(marshalArg));
|
|
84247
84256
|
return {
|
|
84257
|
+
docs: {
|
|
84258
|
+
all: marshalFn(capabilities.docs.all),
|
|
84259
|
+
backlinks: marshalFn(capabilities.docs.backlinks),
|
|
84260
|
+
get: marshalFn(capabilities.docs.get),
|
|
84261
|
+
getJson: marshalFn(capabilities.docs.getJson),
|
|
84262
|
+
query: marshalFn(capabilities.docs.query)
|
|
84263
|
+
},
|
|
84248
84264
|
params: capabilities.params,
|
|
84249
84265
|
...capabilities.path === void 0 ? {} : { path: capabilities.path },
|
|
84250
|
-
sql: marshalFn(capabilities.sql)
|
|
84251
|
-
vault: {
|
|
84252
|
-
all: marshalFn(capabilities.vault.all),
|
|
84253
|
-
backlinks: marshalFn(capabilities.vault.backlinks),
|
|
84254
|
-
get: marshalFn(capabilities.vault.get),
|
|
84255
|
-
getJson: marshalFn(capabilities.vault.getJson),
|
|
84256
|
-
query: marshalFn(capabilities.vault.query)
|
|
84257
|
-
}
|
|
84266
|
+
sql: marshalFn(capabilities.sql)
|
|
84258
84267
|
};
|
|
84259
84268
|
}
|
|
84260
84269
|
async function executeLoader(source, filename, capabilities) {
|
|
@@ -84266,7 +84275,7 @@ async function executeLoader(source, filename, capabilities) {
|
|
|
84266
84275
|
});
|
|
84267
84276
|
new vm.Script(cjs, { filename }).runInContext(context, { timeout: EVAL_TIMEOUT_MS });
|
|
84268
84277
|
const loader = module.exports;
|
|
84269
|
-
if (typeof loader !== "function") throw new Error(`${filename}: expected \`export default async ({
|
|
84278
|
+
if (typeof loader !== "function") throw new Error(`${filename}: expected \`export default async ({ docs, sql, ... }) => ...\``);
|
|
84270
84279
|
const result = await loader(marshalCapabilities(capabilities));
|
|
84271
84280
|
if (result === null || typeof result !== "object" || Array.isArray(result)) throw new Error(`${filename}: loader must return a JSON object (got ${Array.isArray(result) ? "an array" : typeof result})`);
|
|
84272
84281
|
const data = JSON.parse(JSON.stringify(result));
|
|
@@ -84281,30 +84290,30 @@ function loaderConsole(filename) {
|
|
|
84281
84290
|
warn: (...args) => console.warn(prefix, ...args)
|
|
84282
84291
|
};
|
|
84283
84292
|
}
|
|
84284
|
-
var
|
|
84285
|
-
|
|
84293
|
+
var WorkspaceDocsCache = class {
|
|
84294
|
+
docsByRootDir = /* @__PURE__ */ new Map();
|
|
84286
84295
|
get(rootDir, head) {
|
|
84287
|
-
const
|
|
84288
|
-
if (
|
|
84296
|
+
const cached = this.docsByRootDir.get(rootDir);
|
|
84297
|
+
if (cached && cached.head === head) return cached.docs;
|
|
84289
84298
|
const created = (async () => {
|
|
84290
|
-
const root = path.join(rootDir,
|
|
84299
|
+
const root = path.join(rootDir, DOCS_SUBDIR);
|
|
84291
84300
|
await fs$2.mkdir(root, { recursive: true });
|
|
84292
|
-
const
|
|
84301
|
+
const docs = new Docs({
|
|
84293
84302
|
fs: fs$2,
|
|
84294
|
-
onError: (error, context) => console.error(`[slate-bridge]
|
|
84303
|
+
onError: (error, context) => console.error(`[slate-bridge] docs ${rootDir} (${context}):`, error),
|
|
84295
84304
|
root
|
|
84296
84305
|
});
|
|
84297
|
-
await
|
|
84298
|
-
return
|
|
84306
|
+
await docs.load();
|
|
84307
|
+
return docs;
|
|
84299
84308
|
})();
|
|
84300
84309
|
const fresh = {
|
|
84301
|
-
|
|
84302
|
-
|
|
84310
|
+
docs: created,
|
|
84311
|
+
head
|
|
84303
84312
|
};
|
|
84304
84313
|
created.catch(() => {
|
|
84305
|
-
if (this.
|
|
84314
|
+
if (this.docsByRootDir.get(rootDir) === fresh) this.docsByRootDir.delete(rootDir);
|
|
84306
84315
|
});
|
|
84307
|
-
this.
|
|
84316
|
+
this.docsByRootDir.set(rootDir, fresh);
|
|
84308
84317
|
return created;
|
|
84309
84318
|
}
|
|
84310
84319
|
};
|
|
@@ -84376,7 +84385,7 @@ async function createBridgeServer(opts) {
|
|
|
84376
84385
|
});
|
|
84377
84386
|
let boundPort = 0;
|
|
84378
84387
|
const inflight = /* @__PURE__ */ new Set();
|
|
84379
|
-
const
|
|
84388
|
+
const docsCache = new WorkspaceDocsCache();
|
|
84380
84389
|
const app = new Hono();
|
|
84381
84390
|
const wss = new WebSocketServer({ noServer: true });
|
|
84382
84391
|
app.use(cors());
|
|
@@ -84394,10 +84403,10 @@ async function createBridgeServer(opts) {
|
|
|
84394
84403
|
});
|
|
84395
84404
|
if (freshness === "held_diverged") noteDivergedCheckout(workspaceId);
|
|
84396
84405
|
const result = await runWorkspaceView({
|
|
84406
|
+
docs: await docsCache.get(rootDir, head),
|
|
84397
84407
|
rawParams,
|
|
84398
84408
|
resolveDsn: () => resolveRenderDsn(platformUrl, workspaceId, userToken),
|
|
84399
84409
|
rootDir,
|
|
84400
|
-
vault: await vaults.get(rootDir, head),
|
|
84401
84410
|
view
|
|
84402
84411
|
});
|
|
84403
84412
|
return c.json(result);
|
|
@@ -84405,7 +84414,7 @@ async function createBridgeServer(opts) {
|
|
|
84405
84414
|
return c.text(err instanceof Error ? err.message : String(err), 400);
|
|
84406
84415
|
}
|
|
84407
84416
|
});
|
|
84408
|
-
app.post("/bridge/workspaces/:workspaceId/
|
|
84417
|
+
app.post("/bridge/workspaces/:workspaceId/docs/run", renderAuth, async (c) => {
|
|
84409
84418
|
const workspaceId = c.req.param("workspaceId") ?? "";
|
|
84410
84419
|
const body = await c.req.json();
|
|
84411
84420
|
if (typeof body.path !== "string" || body.path.length === 0) return c.text("body must carry a non-empty string `path`", 400);
|
|
@@ -84418,13 +84427,13 @@ async function createBridgeServer(opts) {
|
|
|
84418
84427
|
token: userToken
|
|
84419
84428
|
});
|
|
84420
84429
|
if (freshness === "held_diverged") noteDivergedCheckout(workspaceId);
|
|
84421
|
-
const
|
|
84422
|
-
const result = await
|
|
84423
|
-
|
|
84430
|
+
const docs = await docsCache.get(rootDir, head);
|
|
84431
|
+
const result = await runWorkspaceDoc({
|
|
84432
|
+
docPath: body.path,
|
|
84433
|
+
docs,
|
|
84424
84434
|
rawParams,
|
|
84425
84435
|
resolveDsn: () => resolveRenderDsn(platformUrl, workspaceId, userToken),
|
|
84426
|
-
rootDir
|
|
84427
|
-
vault
|
|
84436
|
+
rootDir
|
|
84428
84437
|
});
|
|
84429
84438
|
return c.json(result);
|
|
84430
84439
|
} catch (err) {
|
|
@@ -84466,7 +84475,7 @@ async function createBridgeServer(opts) {
|
|
|
84466
84475
|
try {
|
|
84467
84476
|
const plan = await fetchBridgePlan(platformUrl, workspaceId, userToken);
|
|
84468
84477
|
const chatBaseId = resolveChatBaseId(plan.baseIds, workspaceId);
|
|
84469
|
-
const
|
|
84478
|
+
const bootTasks = [
|
|
84470
84479
|
claudeRepo.restore(),
|
|
84471
84480
|
ensureWorkspaceCheckout(workspaceId, {
|
|
84472
84481
|
gitHostBaseDir,
|
|
@@ -84474,7 +84483,8 @@ async function createBridgeServer(opts) {
|
|
|
84474
84483
|
token: userToken
|
|
84475
84484
|
}),
|
|
84476
84485
|
chatBaseId === void 0 ? Promise.resolve(void 0) : fetchBaseDsn(platformUrl, chatBaseId, userToken)
|
|
84477
|
-
]
|
|
84486
|
+
];
|
|
84487
|
+
const [, checkout, baseDsn] = await Promise.all(bootTasks).finally(() => Promise.allSettled(bootTasks));
|
|
84478
84488
|
if (checkout.freshness === "held_diverged") noteDivergedCheckout(workspaceId);
|
|
84479
84489
|
const rootDir = checkout.rootDir;
|
|
84480
84490
|
if (ac.signal.aborted) return;
|
|
@@ -88751,4 +88761,4 @@ runCli().catch((error) => {
|
|
|
88751
88761
|
//#endregion
|
|
88752
88762
|
export { createProgram, runCli };
|
|
88753
88763
|
//# sourceMappingURL=cli.mjs.map
|
|
88754
|
-
//# debugId=
|
|
88764
|
+
//# debugId=e80413c9-3000-584e-9bcf-799375152efc
|