@rigxyz/tapd 0.5.3 → 0.6.1
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/bin.js +25 -4
- package/dist/bin.js.map +1 -1
- package/dist/{chunk-QZHSLNCO.js → chunk-RKOWUM3D.js} +395 -16
- package/dist/chunk-RKOWUM3D.js.map +1 -0
- package/dist/index.d.ts +83 -3
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-QZHSLNCO.js.map +0 -1
|
@@ -224,6 +224,43 @@ var RelayClient = class {
|
|
|
224
224
|
);
|
|
225
225
|
return expectJson(route, res);
|
|
226
226
|
}
|
|
227
|
+
// ────────── intents (Context Layer) ──────────
|
|
228
|
+
/** Open an intent. Actor (device/user) is taken from the token, not the body. */
|
|
229
|
+
async createIntent(body) {
|
|
230
|
+
const route = "POST /v1/bindings/:id/intents";
|
|
231
|
+
const res = await this.fetch(this.bindingPath("/intents"), {
|
|
232
|
+
method: "POST",
|
|
233
|
+
headers: this.authHeaders({ "content-type": "application/json" }),
|
|
234
|
+
body: JSON.stringify(body)
|
|
235
|
+
});
|
|
236
|
+
return expectJson(route, res);
|
|
237
|
+
}
|
|
238
|
+
/** Update / close an intent. Actor-only — the relay rejects a non-actor. */
|
|
239
|
+
async updateIntent(intentId, body) {
|
|
240
|
+
const route = "PATCH /v1/bindings/:id/intents/:intentId";
|
|
241
|
+
const res = await this.fetch(
|
|
242
|
+
this.bindingPath(`/intents/${encodeURIComponent(intentId)}`),
|
|
243
|
+
{
|
|
244
|
+
method: "PATCH",
|
|
245
|
+
headers: this.authHeaders({ "content-type": "application/json" }),
|
|
246
|
+
body: JSON.stringify(body)
|
|
247
|
+
}
|
|
248
|
+
);
|
|
249
|
+
return expectJson(route, res);
|
|
250
|
+
}
|
|
251
|
+
async listIntents(opts) {
|
|
252
|
+
const route = "GET /v1/bindings/:id/intents";
|
|
253
|
+
const params = new URLSearchParams();
|
|
254
|
+
if (opts?.status) params.set("status", opts.status);
|
|
255
|
+
if (opts?.after) params.set("after", opts.after);
|
|
256
|
+
if (opts?.limit) params.set("limit", String(opts.limit));
|
|
257
|
+
const qs = params.toString();
|
|
258
|
+
const res = await this.fetch(
|
|
259
|
+
this.bindingPath("/intents") + (qs ? `?${qs}` : ""),
|
|
260
|
+
{ headers: this.authHeaders() }
|
|
261
|
+
);
|
|
262
|
+
return expectJson(route, res);
|
|
263
|
+
}
|
|
227
264
|
// ────────── invites ──────────
|
|
228
265
|
/**
|
|
229
266
|
* Mint a new invite (owner-only). Returns the secret + a ready-to-share
|
|
@@ -435,6 +472,9 @@ var BUILTIN_IGNORE_LINES = [
|
|
|
435
472
|
"# Dependencies and build output",
|
|
436
473
|
"node_modules/",
|
|
437
474
|
"dist/",
|
|
475
|
+
// rig's default folder-registry target (`rig publish --registry`, default
|
|
476
|
+
// ./local-registry) — publish artifacts, not workspace content to sync.
|
|
477
|
+
"local-registry/",
|
|
438
478
|
".venv/",
|
|
439
479
|
"__pycache__/",
|
|
440
480
|
"*.pyc",
|
|
@@ -622,6 +662,9 @@ async function mapPool(items, limit, fn) {
|
|
|
622
662
|
function sha256OfBuffer(bytes) {
|
|
623
663
|
return `sha256:${createHash2("sha256").update(bytes).digest("hex")}`;
|
|
624
664
|
}
|
|
665
|
+
function isRecord(v) {
|
|
666
|
+
return typeof v === "object" && v !== null;
|
|
667
|
+
}
|
|
625
668
|
var UPLOAD_CONCURRENCY = 8;
|
|
626
669
|
var AlreadyInitializedError = class extends Error {
|
|
627
670
|
constructor(path) {
|
|
@@ -631,6 +674,16 @@ var AlreadyInitializedError = class extends Error {
|
|
|
631
674
|
}
|
|
632
675
|
path;
|
|
633
676
|
};
|
|
677
|
+
var OrgForbiddenError = class extends Error {
|
|
678
|
+
constructor(org) {
|
|
679
|
+
super(
|
|
680
|
+
`not a member of org "${org}" \u2014 ask an org admin for an invite, or check the slug`
|
|
681
|
+
);
|
|
682
|
+
this.org = org;
|
|
683
|
+
this.name = "OrgForbiddenError";
|
|
684
|
+
}
|
|
685
|
+
org;
|
|
686
|
+
};
|
|
634
687
|
async function init(opts) {
|
|
635
688
|
if (readBindingConfig(opts.rootDir)) {
|
|
636
689
|
throw new AlreadyInitializedError(join4(opts.rootDir, BINDING_CONFIG_PATH));
|
|
@@ -642,12 +695,20 @@ async function init(opts) {
|
|
|
642
695
|
const h = await hashFile(join4(opts.rootDir, f.path));
|
|
643
696
|
hashed.push({ path: f.path, size: f.size, hash: h });
|
|
644
697
|
}
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
698
|
+
let created;
|
|
699
|
+
try {
|
|
700
|
+
created = await createBinding({
|
|
701
|
+
baseUrl: opts.relayUrl,
|
|
702
|
+
request: { name: opts.bindingName, deviceLabel: opts.deviceLabel, org: opts.org },
|
|
703
|
+
accessToken: opts.accessToken,
|
|
704
|
+
fetch: opts.fetch
|
|
705
|
+
});
|
|
706
|
+
} catch (err) {
|
|
707
|
+
if (err instanceof RelayError && isRecord(err.body) && err.body.error === "org_forbidden" && opts.org) {
|
|
708
|
+
throw new OrgForbiddenError(opts.org);
|
|
709
|
+
}
|
|
710
|
+
throw err;
|
|
711
|
+
}
|
|
651
712
|
writeBindingConfig(opts.rootDir, {
|
|
652
713
|
bindingId: created.binding.id,
|
|
653
714
|
relayUrl: opts.relayUrl,
|
|
@@ -1044,7 +1105,7 @@ var ImportTokenScopeError = class extends Error {
|
|
|
1044
1105
|
}
|
|
1045
1106
|
ops;
|
|
1046
1107
|
};
|
|
1047
|
-
function
|
|
1108
|
+
function isRecord2(v) {
|
|
1048
1109
|
return typeof v === "object" && v !== null;
|
|
1049
1110
|
}
|
|
1050
1111
|
function deriveName(canonicalPath) {
|
|
@@ -1090,7 +1151,7 @@ async function addImport(opts) {
|
|
|
1090
1151
|
fetch: opts.fetch
|
|
1091
1152
|
});
|
|
1092
1153
|
} catch (err) {
|
|
1093
|
-
if (err instanceof RelayError &&
|
|
1154
|
+
if (err instanceof RelayError && isRecord2(err.body) && err.body.reason === "import_requires_read_subscribe") {
|
|
1094
1155
|
throw new ImportTokenScopeError();
|
|
1095
1156
|
}
|
|
1096
1157
|
throw err;
|
|
@@ -1687,6 +1748,7 @@ async function startSubscription(opts) {
|
|
|
1687
1748
|
import { createHash as createHash4 } from "crypto";
|
|
1688
1749
|
import { readFileSync as readFileSync8 } from "fs";
|
|
1689
1750
|
import { join as join8 } from "path";
|
|
1751
|
+
import { basename as basename2 } from "path";
|
|
1690
1752
|
var UPLOAD_CONCURRENCY2 = 8;
|
|
1691
1753
|
function sha256OfBuffer2(bytes) {
|
|
1692
1754
|
return `sha256:${createHash4("sha256").update(bytes).digest("hex")}`;
|
|
@@ -1751,8 +1813,16 @@ async function computeLocalDiff(opts) {
|
|
|
1751
1813
|
};
|
|
1752
1814
|
}
|
|
1753
1815
|
async function scanAndPush(opts) {
|
|
1754
|
-
const { rootDir, client, stateDb } = opts;
|
|
1816
|
+
const { rootDir, client, stateDb, resolveIntents } = opts;
|
|
1755
1817
|
const diff = await computeLocalDiff(opts);
|
|
1818
|
+
const divergedByPath = /* @__PURE__ */ new Map();
|
|
1819
|
+
for (const { path, sidecarPath } of findConflictSidecars(rootDir)) {
|
|
1820
|
+
const parsed = parseConflictSidecar(basename2(sidecarPath));
|
|
1821
|
+
if (!parsed) continue;
|
|
1822
|
+
const list2 = divergedByPath.get(path) ?? [];
|
|
1823
|
+
if (!list2.includes(parsed.chgId)) list2.push(parsed.chgId);
|
|
1824
|
+
divergedByPath.set(path, list2);
|
|
1825
|
+
}
|
|
1756
1826
|
const uniqueHashes = /* @__PURE__ */ new Map();
|
|
1757
1827
|
for (const w of diff.writes) if (!uniqueHashes.has(w.hash)) uniqueHashes.set(w.hash, w);
|
|
1758
1828
|
const mutatedPaths = /* @__PURE__ */ new Set();
|
|
@@ -1781,12 +1851,14 @@ async function scanAndPush(opts) {
|
|
|
1781
1851
|
if (mutatedPaths.has(w.path)) continue;
|
|
1782
1852
|
const repPath = (uniqueHashes.get(w.hash) ?? w).path;
|
|
1783
1853
|
if (mutatedPaths.has(repPath)) continue;
|
|
1854
|
+
const diverged = divergedByPath.get(w.path);
|
|
1784
1855
|
events.push({
|
|
1785
1856
|
op: "write",
|
|
1786
1857
|
path: w.path,
|
|
1787
1858
|
hash: w.hash,
|
|
1788
1859
|
size: w.size,
|
|
1789
|
-
...w.baseChangeId ? { baseChangeId: w.baseChangeId } : {}
|
|
1860
|
+
...w.baseChangeId ? { baseChangeId: w.baseChangeId } : {},
|
|
1861
|
+
...diverged && diverged.length > 0 ? { meta: { divergedFrom: diverged } } : {}
|
|
1790
1862
|
});
|
|
1791
1863
|
}
|
|
1792
1864
|
for (const d of diff.deletes) {
|
|
@@ -1802,6 +1874,15 @@ async function scanAndPush(opts) {
|
|
|
1802
1874
|
for (const path of diff.mkdirs) {
|
|
1803
1875
|
events.push({ op: "mkdir", path });
|
|
1804
1876
|
}
|
|
1877
|
+
if (resolveIntents && events.length > 0) {
|
|
1878
|
+
const assignments = await resolveIntents(events.map((e) => e.path));
|
|
1879
|
+
for (const ev of events) {
|
|
1880
|
+
const a = assignments.get(ev.path);
|
|
1881
|
+
if (!a) continue;
|
|
1882
|
+
ev.intentId = a.intentId;
|
|
1883
|
+
ev.meta = { ...ev.meta, attribution: a.attribution };
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1805
1886
|
let submitted = [];
|
|
1806
1887
|
if (events.length > 0) {
|
|
1807
1888
|
const result = await client.submitChanges(events);
|
|
@@ -1845,8 +1926,288 @@ function cursorLessThan(a, b) {
|
|
|
1845
1926
|
}
|
|
1846
1927
|
|
|
1847
1928
|
// src/start.ts
|
|
1848
|
-
import { join as
|
|
1929
|
+
import { join as join10 } from "path";
|
|
1849
1930
|
import chokidar from "chokidar";
|
|
1931
|
+
|
|
1932
|
+
// src/claude-code.ts
|
|
1933
|
+
import { existsSync as existsSync6, readdirSync as readdirSync4, readFileSync as readFileSync9, statSync as statSync3 } from "fs";
|
|
1934
|
+
import { homedir } from "os";
|
|
1935
|
+
import { join as join9, relative as relative3, sep as sep3 } from "path";
|
|
1936
|
+
function claudeProjectDirName(rootDir) {
|
|
1937
|
+
return rootDir.replace(/[/.]/g, "-");
|
|
1938
|
+
}
|
|
1939
|
+
function defaultClaudeProjectsRoot() {
|
|
1940
|
+
return join9(homedir(), ".claude", "projects");
|
|
1941
|
+
}
|
|
1942
|
+
var TITLE_MAX = 120;
|
|
1943
|
+
var BOUT_GAP_MS = 30 * 60 * 1e3;
|
|
1944
|
+
var READ_TOOLS = /* @__PURE__ */ new Set(["Read", "Grep", "Glob"]);
|
|
1945
|
+
var WRITE_TOOLS = /* @__PURE__ */ new Set([
|
|
1946
|
+
"Write",
|
|
1947
|
+
"Edit",
|
|
1948
|
+
"MultiEdit",
|
|
1949
|
+
"NotebookEdit",
|
|
1950
|
+
"mcp__acp__Write",
|
|
1951
|
+
"mcp__acp__Edit"
|
|
1952
|
+
]);
|
|
1953
|
+
function asObj(v) {
|
|
1954
|
+
return typeof v === "object" && v !== null ? v : null;
|
|
1955
|
+
}
|
|
1956
|
+
function userPromptText(line) {
|
|
1957
|
+
const msg = asObj(line.message);
|
|
1958
|
+
if (!msg) return null;
|
|
1959
|
+
const content = msg.content;
|
|
1960
|
+
if (typeof content === "string") return content.trim() || null;
|
|
1961
|
+
if (Array.isArray(content)) {
|
|
1962
|
+
for (const block of content) {
|
|
1963
|
+
const b = asObj(block);
|
|
1964
|
+
if (b && b.type === "text" && typeof b.text === "string" && b.text.trim()) {
|
|
1965
|
+
return b.text.trim();
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
return null;
|
|
1970
|
+
}
|
|
1971
|
+
function toolPathsFromAssistant(line, tools) {
|
|
1972
|
+
const msg = asObj(line.message);
|
|
1973
|
+
if (!msg || !Array.isArray(msg.content)) return [];
|
|
1974
|
+
const out = [];
|
|
1975
|
+
for (const block of msg.content) {
|
|
1976
|
+
const b = asObj(block);
|
|
1977
|
+
if (!b || b.type !== "tool_use" || typeof b.name !== "string") continue;
|
|
1978
|
+
if (!tools.has(b.name)) continue;
|
|
1979
|
+
const input = asObj(b.input);
|
|
1980
|
+
if (!input) continue;
|
|
1981
|
+
const p = input.file_path ?? input.notebook_path ?? input.path;
|
|
1982
|
+
if (typeof p === "string" && p) out.push(p);
|
|
1983
|
+
}
|
|
1984
|
+
return out;
|
|
1985
|
+
}
|
|
1986
|
+
function toRigRelative(absPath, rootDir) {
|
|
1987
|
+
const rel = relative3(rootDir, absPath);
|
|
1988
|
+
if (rel === "" || rel.startsWith("..") || sep3 !== "/" && rel.includes(".." + sep3)) {
|
|
1989
|
+
return null;
|
|
1990
|
+
}
|
|
1991
|
+
return sep3 === "/" ? rel : rel.replaceAll(sep3, "/");
|
|
1992
|
+
}
|
|
1993
|
+
var PROMPT_SNIPPET_MAX = 2e3;
|
|
1994
|
+
function num(v) {
|
|
1995
|
+
return typeof v === "number" && Number.isFinite(v) ? v : 0;
|
|
1996
|
+
}
|
|
1997
|
+
function toolNamesFromAssistant(line) {
|
|
1998
|
+
const msg = asObj(line.message);
|
|
1999
|
+
if (!msg || !Array.isArray(msg.content)) return [];
|
|
2000
|
+
const out = [];
|
|
2001
|
+
for (const block of msg.content) {
|
|
2002
|
+
const b = asObj(block);
|
|
2003
|
+
if (b && b.type === "tool_use" && typeof b.name === "string") out.push(b.name);
|
|
2004
|
+
}
|
|
2005
|
+
return out;
|
|
2006
|
+
}
|
|
2007
|
+
function parseSessions(transcriptPath, rootDir, opts = {}) {
|
|
2008
|
+
let raw;
|
|
2009
|
+
try {
|
|
2010
|
+
raw = readFileSync9(transcriptPath, "utf8");
|
|
2011
|
+
} catch {
|
|
2012
|
+
return [];
|
|
2013
|
+
}
|
|
2014
|
+
const fileId = basenameNoExt(transcriptPath);
|
|
2015
|
+
const gap = opts.boutGapMs ?? BOUT_GAP_MS;
|
|
2016
|
+
let aiTitle = null;
|
|
2017
|
+
const bouts = [];
|
|
2018
|
+
let cur = null;
|
|
2019
|
+
let prevMs = null;
|
|
2020
|
+
for (const rawLine of raw.split("\n")) {
|
|
2021
|
+
if (!rawLine) continue;
|
|
2022
|
+
let line;
|
|
2023
|
+
try {
|
|
2024
|
+
line = JSON.parse(rawLine);
|
|
2025
|
+
} catch {
|
|
2026
|
+
continue;
|
|
2027
|
+
}
|
|
2028
|
+
const type = line.type;
|
|
2029
|
+
if (type === "ai-title" && typeof line.aiTitle === "string") {
|
|
2030
|
+
aiTitle = line.aiTitle.trim() || aiTitle;
|
|
2031
|
+
continue;
|
|
2032
|
+
}
|
|
2033
|
+
const ts = typeof line.timestamp === "string" ? line.timestamp : null;
|
|
2034
|
+
const tsMs = ts ? Date.parse(ts) : null;
|
|
2035
|
+
const timed = tsMs !== null && Number.isFinite(tsMs);
|
|
2036
|
+
const contentLine = type === "user" || type === "assistant";
|
|
2037
|
+
const gapBreak = timed && cur !== null && prevMs !== null && tsMs - prevMs > gap;
|
|
2038
|
+
if (cur === null ? timed || contentLine : gapBreak) {
|
|
2039
|
+
cur = { index: bouts.length, firstTs: null, lastTs: null, model: null, firstPrompt: null, reads: /* @__PURE__ */ new Set(), writes: /* @__PURE__ */ new Set(), tokens: 0, tools: /* @__PURE__ */ new Map() };
|
|
2040
|
+
bouts.push(cur);
|
|
2041
|
+
}
|
|
2042
|
+
if (timed) prevMs = tsMs;
|
|
2043
|
+
if (cur === null) continue;
|
|
2044
|
+
if (type === "user") {
|
|
2045
|
+
if (!cur.firstPrompt) cur.firstPrompt = userPromptText(line);
|
|
2046
|
+
} else if (type === "assistant") {
|
|
2047
|
+
const msg = asObj(line.message);
|
|
2048
|
+
if (msg && typeof msg.model === "string") cur.model = msg.model;
|
|
2049
|
+
const usage = msg ? asObj(msg.usage) : null;
|
|
2050
|
+
if (usage) {
|
|
2051
|
+
cur.tokens += num(usage.output_tokens);
|
|
2052
|
+
}
|
|
2053
|
+
for (const name of toolNamesFromAssistant(line)) {
|
|
2054
|
+
cur.tools.set(name, (cur.tools.get(name) ?? 0) + 1);
|
|
2055
|
+
}
|
|
2056
|
+
for (const abs of toolPathsFromAssistant(line, READ_TOOLS)) {
|
|
2057
|
+
const rel = toRigRelative(abs, rootDir);
|
|
2058
|
+
if (rel) cur.reads.add(rel);
|
|
2059
|
+
}
|
|
2060
|
+
for (const abs of toolPathsFromAssistant(line, WRITE_TOOLS)) {
|
|
2061
|
+
const rel = toRigRelative(abs, rootDir);
|
|
2062
|
+
if (rel) cur.writes.add(rel);
|
|
2063
|
+
}
|
|
2064
|
+
}
|
|
2065
|
+
if (ts) {
|
|
2066
|
+
if (cur.firstTs === null || ts < cur.firstTs) cur.firstTs = ts;
|
|
2067
|
+
if (cur.lastTs === null || ts > cur.lastTs) cur.lastTs = ts;
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
const single = bouts.length <= 1;
|
|
2071
|
+
return bouts.map((b) => ({
|
|
2072
|
+
sessionId: single ? fileId : `${fileId}#${b.index}`,
|
|
2073
|
+
// aiTitle is the best concise label; bouts are disambiguated by their window.
|
|
2074
|
+
title: aiTitle ?? (b.firstPrompt ? truncate(b.firstPrompt, TITLE_MAX) : fileId),
|
|
2075
|
+
agent: "claude-code",
|
|
2076
|
+
model: b.model,
|
|
2077
|
+
firstTs: b.firstTs,
|
|
2078
|
+
lastTs: b.lastTs,
|
|
2079
|
+
readPaths: [...b.reads],
|
|
2080
|
+
writePaths: [...b.writes],
|
|
2081
|
+
detail: {
|
|
2082
|
+
model: b.model,
|
|
2083
|
+
promptSnippet: b.firstPrompt ? truncate(cleanPrompt(b.firstPrompt), PROMPT_SNIPPET_MAX) : null,
|
|
2084
|
+
tokens: b.tokens > 0 ? b.tokens : null,
|
|
2085
|
+
tools: [...b.tools.entries()].map(([name, count]) => ({ name, count })).sort((x, y) => y.count - x.count)
|
|
2086
|
+
},
|
|
2087
|
+
transcriptPath
|
|
2088
|
+
}));
|
|
2089
|
+
}
|
|
2090
|
+
var parseCache = /* @__PURE__ */ new Map();
|
|
2091
|
+
function listSessions(rootDir, opts = {}) {
|
|
2092
|
+
const dir = join9(opts.projectsRoot ?? defaultClaudeProjectsRoot(), claudeProjectDirName(rootDir));
|
|
2093
|
+
if (!existsSync6(dir)) return [];
|
|
2094
|
+
let files;
|
|
2095
|
+
try {
|
|
2096
|
+
files = readdirSync4(dir).filter((f) => f.endsWith(".jsonl"));
|
|
2097
|
+
} catch {
|
|
2098
|
+
return [];
|
|
2099
|
+
}
|
|
2100
|
+
const out = [];
|
|
2101
|
+
for (const f of files) {
|
|
2102
|
+
const abs = join9(dir, f);
|
|
2103
|
+
let st;
|
|
2104
|
+
try {
|
|
2105
|
+
st = statSync3(abs);
|
|
2106
|
+
} catch {
|
|
2107
|
+
continue;
|
|
2108
|
+
}
|
|
2109
|
+
const cached = parseCache.get(abs);
|
|
2110
|
+
if (cached && cached.mtimeMs === st.mtimeMs && cached.size === st.size) {
|
|
2111
|
+
out.push(...cached.bouts);
|
|
2112
|
+
continue;
|
|
2113
|
+
}
|
|
2114
|
+
const bouts = parseSessions(abs, rootDir);
|
|
2115
|
+
parseCache.set(abs, { mtimeMs: st.mtimeMs, size: st.size, bouts });
|
|
2116
|
+
out.push(...bouts);
|
|
2117
|
+
}
|
|
2118
|
+
out.sort((a, b) => (a.lastTs ?? "").localeCompare(b.lastTs ?? ""));
|
|
2119
|
+
return out;
|
|
2120
|
+
}
|
|
2121
|
+
var DEFAULT_IDLE_MS = 30 * 60 * 1e3;
|
|
2122
|
+
function recentSessions(rootDir, opts = {}) {
|
|
2123
|
+
const now = opts.now ?? Date.now();
|
|
2124
|
+
const idleMs = opts.idleMs ?? DEFAULT_IDLE_MS;
|
|
2125
|
+
return listSessions(rootDir, opts).filter((s) => {
|
|
2126
|
+
if (!s.lastTs) return false;
|
|
2127
|
+
const ms = Date.parse(s.lastTs);
|
|
2128
|
+
return Number.isFinite(ms) && now - ms <= idleMs;
|
|
2129
|
+
}).sort((a, b) => Date.parse(a.lastTs) - Date.parse(b.lastTs));
|
|
2130
|
+
}
|
|
2131
|
+
function basenameNoExt(p) {
|
|
2132
|
+
const base = p.slice(p.lastIndexOf(sep3 === "/" ? "/" : sep3) + 1);
|
|
2133
|
+
const dot = base.lastIndexOf(".");
|
|
2134
|
+
return dot > 0 ? base.slice(0, dot) : base;
|
|
2135
|
+
}
|
|
2136
|
+
function truncate(s, max) {
|
|
2137
|
+
return s.length <= max ? s : s.slice(0, max - 1) + "\u2026";
|
|
2138
|
+
}
|
|
2139
|
+
function cleanPrompt(s) {
|
|
2140
|
+
return s.split("\n").map((l) => l.replace(/^\s*>+\s?/, "")).join(" ").replace(/\s+/g, " ").trim();
|
|
2141
|
+
}
|
|
2142
|
+
|
|
2143
|
+
// src/intent-association.ts
|
|
2144
|
+
var META_INTENT_PREFIX = "intent:";
|
|
2145
|
+
var META_FP_PREFIX = "intentfp:";
|
|
2146
|
+
async function resolveIntentAssignments(deps, changedPaths) {
|
|
2147
|
+
const out = /* @__PURE__ */ new Map();
|
|
2148
|
+
if (changedPaths.length === 0) return out;
|
|
2149
|
+
const sessions = recentSessions(deps.rootDir, deps.sessionOpts);
|
|
2150
|
+
if (sessions.length === 0) return out;
|
|
2151
|
+
const claim = /* @__PURE__ */ new Map();
|
|
2152
|
+
for (const s of sessions) {
|
|
2153
|
+
for (const p of s.writePaths) claim.set(p, s);
|
|
2154
|
+
}
|
|
2155
|
+
const mostRecent = sessions[sessions.length - 1];
|
|
2156
|
+
const decided = /* @__PURE__ */ new Map();
|
|
2157
|
+
const used = /* @__PURE__ */ new Set();
|
|
2158
|
+
for (const path of changedPaths) {
|
|
2159
|
+
const claimed = claim.get(path);
|
|
2160
|
+
const session = claimed ?? mostRecent;
|
|
2161
|
+
decided.set(path, { session, attribution: claimed ? "confirmed" : "window" });
|
|
2162
|
+
used.add(session);
|
|
2163
|
+
}
|
|
2164
|
+
const intentBySession = /* @__PURE__ */ new Map();
|
|
2165
|
+
for (const s of used) {
|
|
2166
|
+
intentBySession.set(s, await ensureIntentForSession(deps, s));
|
|
2167
|
+
}
|
|
2168
|
+
for (const [path, d] of decided) {
|
|
2169
|
+
out.set(path, { intentId: intentBySession.get(d.session), attribution: d.attribution });
|
|
2170
|
+
}
|
|
2171
|
+
return out;
|
|
2172
|
+
}
|
|
2173
|
+
async function ensureIntentForSession(deps, session) {
|
|
2174
|
+
const { client, stateDb } = deps;
|
|
2175
|
+
const readPaths = mapReadPaths(stateDb, session.readPaths);
|
|
2176
|
+
const fp = fingerprint(session.title, readPaths);
|
|
2177
|
+
const cachedId = stateDb.getMeta(META_INTENT_PREFIX + session.sessionId);
|
|
2178
|
+
if (cachedId) {
|
|
2179
|
+
if (stateDb.getMeta(META_FP_PREFIX + session.sessionId) !== fp) {
|
|
2180
|
+
await client.updateIntent(cachedId, { title: session.title, readPaths });
|
|
2181
|
+
stateDb.setMeta(META_FP_PREFIX + session.sessionId, fp);
|
|
2182
|
+
}
|
|
2183
|
+
return cachedId;
|
|
2184
|
+
}
|
|
2185
|
+
const intent = await client.createIntent({
|
|
2186
|
+
agent: session.agent,
|
|
2187
|
+
title: session.title,
|
|
2188
|
+
readPaths,
|
|
2189
|
+
detail: session.detail,
|
|
2190
|
+
contextCursor: stateDb.getCursor(),
|
|
2191
|
+
payloadRef: `local:${session.transcriptPath}`
|
|
2192
|
+
});
|
|
2193
|
+
stateDb.setMeta(META_INTENT_PREFIX + session.sessionId, intent.id);
|
|
2194
|
+
stateDb.setMeta(META_FP_PREFIX + session.sessionId, fp);
|
|
2195
|
+
return intent.id;
|
|
2196
|
+
}
|
|
2197
|
+
function mapReadPaths(stateDb, paths) {
|
|
2198
|
+
const out = [];
|
|
2199
|
+
for (const path of paths) {
|
|
2200
|
+
const changeId = stateDb.getPath(path)?.lastAppliedChangeId;
|
|
2201
|
+
if (changeId) out.push({ path, changeId });
|
|
2202
|
+
}
|
|
2203
|
+
return out;
|
|
2204
|
+
}
|
|
2205
|
+
function fingerprint(title, readPaths) {
|
|
2206
|
+
const reads = readPaths.map((r) => `${r.path}@${r.changeId}`).sort().join(",");
|
|
2207
|
+
return `${title}\0${reads}`;
|
|
2208
|
+
}
|
|
2209
|
+
|
|
2210
|
+
// src/start.ts
|
|
1850
2211
|
var DEFAULT_POLL_SECONDS2 = 3;
|
|
1851
2212
|
var DEFAULT_DEBOUNCE_MS = 300;
|
|
1852
2213
|
var NOOP_APPLY = {
|
|
@@ -1890,6 +2251,20 @@ async function start(opts) {
|
|
|
1890
2251
|
let scanInFlight = Promise.resolve();
|
|
1891
2252
|
let writerClient;
|
|
1892
2253
|
const ignore2 = loadIgnore(opts.rootDir);
|
|
2254
|
+
const intentResolverFor = (client, stateDb2) => {
|
|
2255
|
+
if (opts.disableIntentCapture) return void 0;
|
|
2256
|
+
return async (changedPaths) => {
|
|
2257
|
+
try {
|
|
2258
|
+
return await resolveIntentAssignments(
|
|
2259
|
+
{ client, stateDb: stateDb2, rootDir: opts.rootDir, sessionOpts: opts.intentSessionOpts },
|
|
2260
|
+
changedPaths
|
|
2261
|
+
);
|
|
2262
|
+
} catch (err) {
|
|
2263
|
+
console.error("tapd intent capture error:", err);
|
|
2264
|
+
return /* @__PURE__ */ new Map();
|
|
2265
|
+
}
|
|
2266
|
+
};
|
|
2267
|
+
};
|
|
1893
2268
|
let importPaths = [];
|
|
1894
2269
|
if (config) {
|
|
1895
2270
|
primary = await startSubscription({
|
|
@@ -1930,7 +2305,8 @@ async function start(opts) {
|
|
|
1930
2305
|
client: writerClient,
|
|
1931
2306
|
stateDb: primaryStateDb,
|
|
1932
2307
|
ignore: ignore2,
|
|
1933
|
-
excludePaths: importPaths
|
|
2308
|
+
excludePaths: importPaths,
|
|
2309
|
+
resolveIntents: intentResolverFor(writerClient, primaryStateDb)
|
|
1934
2310
|
}).catch((err) => {
|
|
1935
2311
|
console.error("tapd scan error:", err);
|
|
1936
2312
|
});
|
|
@@ -1960,7 +2336,8 @@ async function start(opts) {
|
|
|
1960
2336
|
client: writerClient,
|
|
1961
2337
|
stateDb: primaryStateDb,
|
|
1962
2338
|
ignore: ignore2,
|
|
1963
|
-
excludePaths: importPaths
|
|
2339
|
+
excludePaths: importPaths,
|
|
2340
|
+
resolveIntents: intentResolverFor(writerClient, primaryStateDb)
|
|
1964
2341
|
}).catch((err) => {
|
|
1965
2342
|
console.error("tapd initial scan error:", err);
|
|
1966
2343
|
});
|
|
@@ -1971,7 +2348,7 @@ async function start(opts) {
|
|
|
1971
2348
|
for (const imp of validImports) {
|
|
1972
2349
|
try {
|
|
1973
2350
|
const sub = await startSubscription({
|
|
1974
|
-
rootDir:
|
|
2351
|
+
rootDir: join10(opts.rootDir, imp.path),
|
|
1975
2352
|
config: { bindingId: imp.bindingId, relayUrl: imp.relayUrl, token: imp.token },
|
|
1976
2353
|
stateDbPath: importStateDbPath(opts.rootDir, imp.name),
|
|
1977
2354
|
mode: "mirror",
|
|
@@ -2017,7 +2394,8 @@ async function start(opts) {
|
|
|
2017
2394
|
client: writerClient,
|
|
2018
2395
|
stateDb: primary.stateDb,
|
|
2019
2396
|
ignore: ignore2,
|
|
2020
|
-
excludePaths: importPaths
|
|
2397
|
+
excludePaths: importPaths,
|
|
2398
|
+
resolveIntents: intentResolverFor(writerClient, primary.stateDb)
|
|
2021
2399
|
});
|
|
2022
2400
|
},
|
|
2023
2401
|
stateDb,
|
|
@@ -2041,6 +2419,7 @@ export {
|
|
|
2041
2419
|
walk,
|
|
2042
2420
|
hashFile,
|
|
2043
2421
|
AlreadyInitializedError,
|
|
2422
|
+
OrgForbiddenError,
|
|
2044
2423
|
init,
|
|
2045
2424
|
mint,
|
|
2046
2425
|
list,
|
|
@@ -2075,4 +2454,4 @@ export {
|
|
|
2075
2454
|
scanAndPush,
|
|
2076
2455
|
start
|
|
2077
2456
|
};
|
|
2078
|
-
//# sourceMappingURL=chunk-
|
|
2457
|
+
//# sourceMappingURL=chunk-RKOWUM3D.js.map
|