@alook/daemon 0.1.31 → 0.1.33
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/index.js +1295 -235
- package/dist/index.js +1127 -152
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -91,6 +91,12 @@ function nanoid3(size = 21) {
|
|
|
91
91
|
}
|
|
92
92
|
var POOL_SIZE_MULTIPLIER = 128, pool, poolOffset;
|
|
93
93
|
var init_nanoid = () => {};
|
|
94
|
+
|
|
95
|
+
// agent-driver/dist/contract.js
|
|
96
|
+
var SESSION_FILE_DISCOVERY_CAPABILITIES = ["supported", "unavailable"];
|
|
97
|
+
|
|
98
|
+
// agent-driver/dist/public-contract.js
|
|
99
|
+
var SESSION_FILE_DISCOVERY_CAPABILITIES2 = SESSION_FILE_DISCOVERY_CAPABILITIES;
|
|
94
100
|
// agent-driver/dist/host/default-host.js
|
|
95
101
|
import { randomUUID } from "node:crypto";
|
|
96
102
|
function createDefaultAgentDriverHost(options = {}) {
|
|
@@ -1232,6 +1238,12 @@ function tryParseJsonLine(line) {
|
|
|
1232
1238
|
return null;
|
|
1233
1239
|
}
|
|
1234
1240
|
}
|
|
1241
|
+
function asRecord(value) {
|
|
1242
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
1243
|
+
}
|
|
1244
|
+
function tryParseJsonRecord(line) {
|
|
1245
|
+
return asRecord(tryParseJsonLine(line));
|
|
1246
|
+
}
|
|
1235
1247
|
|
|
1236
1248
|
// agent-driver/dist/adapters/claude/normalizer.js
|
|
1237
1249
|
var API_ERROR_RE = /API Error:.*(?:Connection error|\b[45]\d{2}\b)/i;
|
|
@@ -1730,6 +1742,241 @@ class ClaudeTurnProtocol {
|
|
|
1730
1742
|
}
|
|
1731
1743
|
}
|
|
1732
1744
|
|
|
1745
|
+
// agent-driver/dist/adapters/claude/recent-context.js
|
|
1746
|
+
import { createReadStream as createReadStream2 } from "node:fs";
|
|
1747
|
+
import { homedir } from "node:os";
|
|
1748
|
+
import path6 from "node:path";
|
|
1749
|
+
import { createInterface } from "node:readline";
|
|
1750
|
+
|
|
1751
|
+
// agent-driver/dist/internal/recent-context.js
|
|
1752
|
+
import path5 from "node:path";
|
|
1753
|
+
import { createReadStream } from "node:fs";
|
|
1754
|
+
import { readdir, stat } from "node:fs/promises";
|
|
1755
|
+
function normalizeAbsolutePath(value) {
|
|
1756
|
+
if (typeof value !== "string" || !path5.isAbsolute(value))
|
|
1757
|
+
return null;
|
|
1758
|
+
return path5.normalize(value);
|
|
1759
|
+
}
|
|
1760
|
+
function normalizeModifiedAt(value) {
|
|
1761
|
+
const date = value instanceof Date ? value : typeof value === "string" || typeof value === "number" ? new Date(value) : null;
|
|
1762
|
+
if (!date || !Number.isFinite(date.getTime()))
|
|
1763
|
+
return null;
|
|
1764
|
+
return date.toISOString();
|
|
1765
|
+
}
|
|
1766
|
+
function isValidRecentContextTopK(value) {
|
|
1767
|
+
return Number.isSafeInteger(value) && value >= 0;
|
|
1768
|
+
}
|
|
1769
|
+
function isMissingPathError(error) {
|
|
1770
|
+
return error?.code === "ENOENT";
|
|
1771
|
+
}
|
|
1772
|
+
async function readFirstLine(filePath, maxBytes = 65536) {
|
|
1773
|
+
const stream = createReadStream(filePath, { highWaterMark: 1 });
|
|
1774
|
+
const bytes = [];
|
|
1775
|
+
let length = 0;
|
|
1776
|
+
try {
|
|
1777
|
+
for await (const chunk of stream) {
|
|
1778
|
+
const byte = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
1779
|
+
if (byte[0] === 10)
|
|
1780
|
+
break;
|
|
1781
|
+
if (length >= maxBytes)
|
|
1782
|
+
return null;
|
|
1783
|
+
bytes.push(byte);
|
|
1784
|
+
length += byte.length;
|
|
1785
|
+
}
|
|
1786
|
+
return length === 0 ? null : Buffer.concat(bytes, length).toString("utf8").replace(/\r$/, "");
|
|
1787
|
+
} catch (error) {
|
|
1788
|
+
if (isMissingPathError(error))
|
|
1789
|
+
return null;
|
|
1790
|
+
throw error;
|
|
1791
|
+
} finally {
|
|
1792
|
+
stream.destroy();
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
async function collectJsonlFileCandidates(root, options = {}) {
|
|
1796
|
+
const candidates = [];
|
|
1797
|
+
const readDirectory = options.readDirectory ?? ((directory) => readdir(directory, { withFileTypes: true }));
|
|
1798
|
+
const statPath = options.statPath ?? stat;
|
|
1799
|
+
const visit = async (directory, remainingDepth, includeFiles) => {
|
|
1800
|
+
let entries;
|
|
1801
|
+
try {
|
|
1802
|
+
entries = await readDirectory(directory);
|
|
1803
|
+
} catch (error) {
|
|
1804
|
+
if (isMissingPathError(error))
|
|
1805
|
+
return;
|
|
1806
|
+
throw error;
|
|
1807
|
+
}
|
|
1808
|
+
await Promise.all(entries.map(async (entry) => {
|
|
1809
|
+
const entryPath = path5.join(directory, entry.name);
|
|
1810
|
+
if (entry.isDirectory() && remainingDepth > 0) {
|
|
1811
|
+
await visit(entryPath, remainingDepth - 1, true);
|
|
1812
|
+
} else if (includeFiles && entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
1813
|
+
try {
|
|
1814
|
+
const metadata = await statPath(entryPath);
|
|
1815
|
+
if (metadata.isFile())
|
|
1816
|
+
candidates.push({ filePath: entryPath, modifiedAt: metadata.mtime });
|
|
1817
|
+
} catch (error) {
|
|
1818
|
+
if (!isMissingPathError(error))
|
|
1819
|
+
throw error;
|
|
1820
|
+
}
|
|
1821
|
+
}
|
|
1822
|
+
}));
|
|
1823
|
+
};
|
|
1824
|
+
await visit(root, options.maxDepth ?? Number.POSITIVE_INFINITY, options.includeRootFiles ?? true);
|
|
1825
|
+
return candidates;
|
|
1826
|
+
}
|
|
1827
|
+
function retainNewest(values, key, value, topK) {
|
|
1828
|
+
const existing = values.get(key);
|
|
1829
|
+
if (existing) {
|
|
1830
|
+
if (value.modifiedAt > existing.modifiedAt)
|
|
1831
|
+
values.set(key, value);
|
|
1832
|
+
return;
|
|
1833
|
+
}
|
|
1834
|
+
if (values.size < topK) {
|
|
1835
|
+
values.set(key, value);
|
|
1836
|
+
return;
|
|
1837
|
+
}
|
|
1838
|
+
let oldest;
|
|
1839
|
+
for (const entry of values) {
|
|
1840
|
+
if (!oldest || entry[1].modifiedAt < oldest[1].modifiedAt)
|
|
1841
|
+
oldest = entry;
|
|
1842
|
+
}
|
|
1843
|
+
if (oldest && value.modifiedAt > oldest[1].modifiedAt) {
|
|
1844
|
+
values.delete(oldest[0]);
|
|
1845
|
+
values.set(key, value);
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
class RecentContextCollector {
|
|
1850
|
+
request;
|
|
1851
|
+
sessionFileCapability;
|
|
1852
|
+
sessions = new Map;
|
|
1853
|
+
projects = new Map;
|
|
1854
|
+
constructor(request, sessionFileCapability) {
|
|
1855
|
+
this.request = request;
|
|
1856
|
+
this.sessionFileCapability = sessionFileCapability;
|
|
1857
|
+
}
|
|
1858
|
+
add(candidate, target = "both") {
|
|
1859
|
+
const projectPath = normalizeAbsolutePath(candidate.projectPath);
|
|
1860
|
+
const modifiedAt = normalizeModifiedAt(candidate.modifiedAt);
|
|
1861
|
+
if (!projectPath || !modifiedAt)
|
|
1862
|
+
return;
|
|
1863
|
+
if (target !== "session") {
|
|
1864
|
+
retainNewest(this.projects, projectPath, { projectPath, modifiedAt }, this.request.recentProjectsTopK);
|
|
1865
|
+
}
|
|
1866
|
+
if (target === "project" || this.sessionFileCapability !== "supported")
|
|
1867
|
+
return;
|
|
1868
|
+
const sessionFilePath = normalizeAbsolutePath(candidate.sessionFilePath);
|
|
1869
|
+
if (!sessionFilePath)
|
|
1870
|
+
return;
|
|
1871
|
+
retainNewest(this.sessions, sessionFilePath, { sessionFilePath, projectPath, modifiedAt }, this.request.recentSessionFilesTopK);
|
|
1872
|
+
}
|
|
1873
|
+
get satisfied() {
|
|
1874
|
+
const sessionsSatisfied = this.sessionFileCapability === "unavailable" || this.sessions.size >= this.request.recentSessionFilesTopK;
|
|
1875
|
+
return sessionsSatisfied && this.projects.size >= this.request.recentProjectsTopK;
|
|
1876
|
+
}
|
|
1877
|
+
result() {
|
|
1878
|
+
const newestFirst = (left, right) => right.modifiedAt.localeCompare(left.modifiedAt);
|
|
1879
|
+
return {
|
|
1880
|
+
sessionFiles: {
|
|
1881
|
+
capability: this.sessionFileCapability,
|
|
1882
|
+
items: [...this.sessions.values()].sort(newestFirst).slice(0, this.request.recentSessionFilesTopK)
|
|
1883
|
+
},
|
|
1884
|
+
recentProjects: [...this.projects.values()].sort(newestFirst).slice(0, this.request.recentProjectsTopK)
|
|
1885
|
+
};
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
function sanitizeRecentContextData(value, request) {
|
|
1889
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
1890
|
+
return null;
|
|
1891
|
+
const candidate = value;
|
|
1892
|
+
if (!candidate.sessionFiles || typeof candidate.sessionFiles !== "object" || Array.isArray(candidate.sessionFiles)) {
|
|
1893
|
+
return null;
|
|
1894
|
+
}
|
|
1895
|
+
const sessionFiles = candidate.sessionFiles;
|
|
1896
|
+
const capability = sessionFiles.capability;
|
|
1897
|
+
if (capability !== "supported" && capability !== "unavailable" || !Array.isArray(sessionFiles.items)) {
|
|
1898
|
+
return null;
|
|
1899
|
+
}
|
|
1900
|
+
if (!Array.isArray(candidate.recentProjects))
|
|
1901
|
+
return null;
|
|
1902
|
+
const collector = new RecentContextCollector(request, capability);
|
|
1903
|
+
if (capability === "supported") {
|
|
1904
|
+
for (const item of sessionFiles.items) {
|
|
1905
|
+
if (!item || typeof item !== "object" || Array.isArray(item))
|
|
1906
|
+
continue;
|
|
1907
|
+
const record = item;
|
|
1908
|
+
collector.add({
|
|
1909
|
+
sessionFilePath: record.sessionFilePath,
|
|
1910
|
+
projectPath: record.projectPath,
|
|
1911
|
+
modifiedAt: record.modifiedAt
|
|
1912
|
+
}, "session");
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
for (const item of candidate.recentProjects) {
|
|
1916
|
+
if (!item || typeof item !== "object" || Array.isArray(item))
|
|
1917
|
+
continue;
|
|
1918
|
+
const record = item;
|
|
1919
|
+
collector.add({ projectPath: record.projectPath, modifiedAt: record.modifiedAt }, "project");
|
|
1920
|
+
}
|
|
1921
|
+
return collector.result();
|
|
1922
|
+
}
|
|
1923
|
+
|
|
1924
|
+
// agent-driver/dist/adapters/claude/recent-context.js
|
|
1925
|
+
async function readClaudeProjectPath(filePath) {
|
|
1926
|
+
const input = createReadStream2(filePath);
|
|
1927
|
+
const lines = createInterface({ input, crlfDelay: Infinity });
|
|
1928
|
+
try {
|
|
1929
|
+
for await (const line of lines) {
|
|
1930
|
+
let record;
|
|
1931
|
+
try {
|
|
1932
|
+
record = JSON.parse(line);
|
|
1933
|
+
} catch {
|
|
1934
|
+
continue;
|
|
1935
|
+
}
|
|
1936
|
+
if (!record || typeof record !== "object")
|
|
1937
|
+
continue;
|
|
1938
|
+
const cwd = record.cwd;
|
|
1939
|
+
if (typeof cwd === "string" && path6.isAbsolute(cwd))
|
|
1940
|
+
return cwd;
|
|
1941
|
+
}
|
|
1942
|
+
return null;
|
|
1943
|
+
} catch (error) {
|
|
1944
|
+
if (isMissingPathError(error))
|
|
1945
|
+
return null;
|
|
1946
|
+
throw error;
|
|
1947
|
+
} finally {
|
|
1948
|
+
lines.close();
|
|
1949
|
+
input.destroy();
|
|
1950
|
+
}
|
|
1951
|
+
}
|
|
1952
|
+
async function discoverClaudeRecentContext(request, dependencies = {}) {
|
|
1953
|
+
const collector = new RecentContextCollector(request, "supported");
|
|
1954
|
+
if (collector.satisfied)
|
|
1955
|
+
return collector.result();
|
|
1956
|
+
const projectsRoot = path6.resolve(dependencies.projectsRoot ?? path6.join(process.env.CLAUDE_CONFIG_DIR || path6.join(homedir(), ".claude"), "projects"));
|
|
1957
|
+
const readProjectPath = dependencies.readProjectPath ?? readClaudeProjectPath;
|
|
1958
|
+
const candidates = await collectJsonlFileCandidates(projectsRoot, {
|
|
1959
|
+
includeRootFiles: false,
|
|
1960
|
+
maxDepth: 1,
|
|
1961
|
+
readDirectory: dependencies.readDirectory,
|
|
1962
|
+
statPath: dependencies.statPath
|
|
1963
|
+
});
|
|
1964
|
+
candidates.sort((left, right) => right.modifiedAt.getTime() - left.modifiedAt.getTime());
|
|
1965
|
+
for (const candidate of candidates) {
|
|
1966
|
+
const projectPath = await readProjectPath(candidate.filePath);
|
|
1967
|
+
if (!projectPath)
|
|
1968
|
+
continue;
|
|
1969
|
+
collector.add({
|
|
1970
|
+
sessionFilePath: candidate.filePath,
|
|
1971
|
+
projectPath,
|
|
1972
|
+
modifiedAt: candidate.modifiedAt
|
|
1973
|
+
});
|
|
1974
|
+
if (collector.satisfied)
|
|
1975
|
+
break;
|
|
1976
|
+
}
|
|
1977
|
+
return collector.result();
|
|
1978
|
+
}
|
|
1979
|
+
|
|
1733
1980
|
// agent-driver/dist/adapters/claude/index.js
|
|
1734
1981
|
var CLAUDE_MODEL_CATALOG = {
|
|
1735
1982
|
updateMode: "unsupported",
|
|
@@ -1751,6 +1998,9 @@ class ClaudeDriver {
|
|
|
1751
1998
|
turnProtocol = new ClaudeTurnProtocol;
|
|
1752
1999
|
eventNormalizer = new ClaudeEventNormalizer(this.turnProtocol);
|
|
1753
2000
|
pendingInterrupt;
|
|
2001
|
+
discoverRecentContext(request) {
|
|
2002
|
+
return discoverClaudeRecentContext(request);
|
|
2003
|
+
}
|
|
1754
2004
|
beginTurn() {
|
|
1755
2005
|
this.pendingInterrupt = undefined;
|
|
1756
2006
|
const receipt = this.turnProtocol.beginTurn();
|
|
@@ -2014,16 +2264,16 @@ function normalizeFileChangeInput(item) {
|
|
|
2014
2264
|
for (const candidate of changePaths) {
|
|
2015
2265
|
if (typeof candidate !== "string")
|
|
2016
2266
|
continue;
|
|
2017
|
-
const
|
|
2018
|
-
if (!
|
|
2267
|
+
const path7 = candidate.trim();
|
|
2268
|
+
if (!path7 || seen.has(path7))
|
|
2019
2269
|
continue;
|
|
2020
|
-
seen.add(
|
|
2021
|
-
paths.push(
|
|
2270
|
+
seen.add(path7);
|
|
2271
|
+
paths.push(path7);
|
|
2022
2272
|
}
|
|
2023
2273
|
if (paths.length === 0 && typeof item?.path === "string") {
|
|
2024
|
-
const
|
|
2025
|
-
if (
|
|
2026
|
-
paths.push(
|
|
2274
|
+
const path7 = item.path.trim();
|
|
2275
|
+
if (path7)
|
|
2276
|
+
paths.push(path7);
|
|
2027
2277
|
}
|
|
2028
2278
|
return paths.length > 0 ? { path: paths.join(", ") } : {};
|
|
2029
2279
|
}
|
|
@@ -2392,7 +2642,7 @@ class CodexEventNormalizer {
|
|
|
2392
2642
|
|
|
2393
2643
|
// agent-driver/dist/adapters/codex/home.js
|
|
2394
2644
|
import * as os from "os";
|
|
2395
|
-
import * as
|
|
2645
|
+
import * as path7 from "path";
|
|
2396
2646
|
function readConfiguredCodexHome(env) {
|
|
2397
2647
|
const raw = env.CODEX_HOME;
|
|
2398
2648
|
return typeof raw === "string" && raw.trim().length > 0 ? raw : null;
|
|
@@ -2400,8 +2650,8 @@ function readConfiguredCodexHome(env) {
|
|
|
2400
2650
|
function resolveCodexHomeRootFromEnv(env = process.env, opts = {}) {
|
|
2401
2651
|
const raw = readConfiguredCodexHome(env);
|
|
2402
2652
|
if (raw)
|
|
2403
|
-
return
|
|
2404
|
-
return
|
|
2653
|
+
return path7.resolve(opts.cwd ?? process.cwd(), raw);
|
|
2654
|
+
return path7.join(opts.defaultHomeDir ?? os.homedir(), ".codex");
|
|
2405
2655
|
}
|
|
2406
2656
|
|
|
2407
2657
|
// agent-driver/dist/internal/errors.js
|
|
@@ -2494,6 +2744,49 @@ function parsePiModelCatalog(values) {
|
|
|
2494
2744
|
return catalogFromIds(ids);
|
|
2495
2745
|
}
|
|
2496
2746
|
|
|
2747
|
+
// agent-driver/dist/adapters/codex/recent-context.js
|
|
2748
|
+
import path8 from "node:path";
|
|
2749
|
+
function isChildSession(payload) {
|
|
2750
|
+
if (payload.parentThreadId != null || payload.parent_thread_id != null)
|
|
2751
|
+
return true;
|
|
2752
|
+
const source = payload.source;
|
|
2753
|
+
if (typeof source === "string")
|
|
2754
|
+
return source.toLowerCase().startsWith("subagent");
|
|
2755
|
+
const sourceRecord = asRecord(source);
|
|
2756
|
+
return sourceRecord != null && (("subagent" in sourceRecord) || ("subAgent" in sourceRecord));
|
|
2757
|
+
}
|
|
2758
|
+
async function discoverCodexRecentContext(request, dependencies = {}) {
|
|
2759
|
+
const collector = new RecentContextCollector(request, "supported");
|
|
2760
|
+
if (collector.satisfied)
|
|
2761
|
+
return collector.result();
|
|
2762
|
+
const sessionsRoot = path8.resolve(dependencies.sessionsRoot ?? path8.join(resolveCodexHomeRootFromEnv(), "sessions"));
|
|
2763
|
+
const readHeader = dependencies.readHeader ?? readFirstLine;
|
|
2764
|
+
const candidates = await collectJsonlFileCandidates(sessionsRoot, {
|
|
2765
|
+
readDirectory: dependencies.readDirectory,
|
|
2766
|
+
statPath: dependencies.statPath
|
|
2767
|
+
});
|
|
2768
|
+
candidates.sort((left, right) => right.modifiedAt.getTime() - left.modifiedAt.getTime());
|
|
2769
|
+
for (const candidate of candidates) {
|
|
2770
|
+
const line = await readHeader(candidate.filePath);
|
|
2771
|
+
if (!line)
|
|
2772
|
+
continue;
|
|
2773
|
+
const header = tryParseJsonRecord(line);
|
|
2774
|
+
if (!header)
|
|
2775
|
+
continue;
|
|
2776
|
+
const payload = asRecord(header.payload);
|
|
2777
|
+
if (header.type !== "session_meta" || !payload || isChildSession(payload))
|
|
2778
|
+
continue;
|
|
2779
|
+
collector.add({
|
|
2780
|
+
sessionFilePath: candidate.filePath,
|
|
2781
|
+
projectPath: payload.cwd,
|
|
2782
|
+
modifiedAt: candidate.modifiedAt
|
|
2783
|
+
});
|
|
2784
|
+
if (collector.satisfied)
|
|
2785
|
+
break;
|
|
2786
|
+
}
|
|
2787
|
+
return collector.result();
|
|
2788
|
+
}
|
|
2789
|
+
|
|
2497
2790
|
// agent-driver/dist/adapters/codex/index.js
|
|
2498
2791
|
var SETTINGS_UPDATE_TIMEOUT_MS = 5000;
|
|
2499
2792
|
var MODEL_LIST_TIMEOUT_MS = 5000;
|
|
@@ -2522,6 +2815,9 @@ class CodexDriver {
|
|
|
2522
2815
|
eventNormalizer = new CodexEventNormalizer;
|
|
2523
2816
|
pendingAccountReadRequestIds = new Set;
|
|
2524
2817
|
requestId = 0;
|
|
2818
|
+
discoverRecentContext(request) {
|
|
2819
|
+
return discoverCodexRecentContext(request);
|
|
2820
|
+
}
|
|
2525
2821
|
codexHomeRoot = null;
|
|
2526
2822
|
proc = null;
|
|
2527
2823
|
pendingInitialPrompt = null;
|
|
@@ -3698,6 +3994,196 @@ class CursorAcpLane {
|
|
|
3698
3994
|
}
|
|
3699
3995
|
}
|
|
3700
3996
|
|
|
3997
|
+
// agent-driver/dist/internal/discovery-process.js
|
|
3998
|
+
import { StringDecoder } from "node:string_decoder";
|
|
3999
|
+
function toBuffer(chunk) {
|
|
4000
|
+
if (Buffer.isBuffer(chunk))
|
|
4001
|
+
return chunk;
|
|
4002
|
+
if (chunk instanceof Uint8Array)
|
|
4003
|
+
return Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength);
|
|
4004
|
+
return Buffer.from(String(chunk));
|
|
4005
|
+
}
|
|
4006
|
+
async function cleanupProcess(process2, label) {
|
|
4007
|
+
if (process2.pid)
|
|
4008
|
+
await killProcessTree(process2.pid, { graceMs: 250 });
|
|
4009
|
+
else if (process2.exitCode === null && process2.signalCode === null && !process2.kill("SIGTERM")) {
|
|
4010
|
+
throw new Error(`${label} discovery cleanup failed`);
|
|
4011
|
+
}
|
|
4012
|
+
}
|
|
4013
|
+
function onStream(stream, event, listener) {
|
|
4014
|
+
stream?.on?.(event, listener);
|
|
4015
|
+
}
|
|
4016
|
+
function runBoundedDiscoveryProcess(options) {
|
|
4017
|
+
return new Promise((resolve2, reject) => {
|
|
4018
|
+
const decoder = new StringDecoder("utf8");
|
|
4019
|
+
let settled = false;
|
|
4020
|
+
let decoderEnded = false;
|
|
4021
|
+
let outputBytes = 0;
|
|
4022
|
+
const settle = (result, error) => {
|
|
4023
|
+
if (settled)
|
|
4024
|
+
return;
|
|
4025
|
+
settled = true;
|
|
4026
|
+
clearTimeout(timer);
|
|
4027
|
+
if (!decoderEnded)
|
|
4028
|
+
decoder.end();
|
|
4029
|
+
Promise.resolve().then(() => options.cleanup?.(options.process) ?? cleanupProcess(options.process, options.label)).then(() => error ? reject(error) : resolve2(result), () => reject(error ?? new Error(`${options.label} discovery cleanup failed`)));
|
|
4030
|
+
};
|
|
4031
|
+
const control = {
|
|
4032
|
+
get outputBytes() {
|
|
4033
|
+
return outputBytes;
|
|
4034
|
+
},
|
|
4035
|
+
finish: (result) => settle(result),
|
|
4036
|
+
fail: (message) => settle(undefined, new Error(message)),
|
|
4037
|
+
flushStdout: () => {
|
|
4038
|
+
if (settled || decoderEnded)
|
|
4039
|
+
return;
|
|
4040
|
+
decoderEnded = true;
|
|
4041
|
+
options.onStdout(decoder.end(), true, control);
|
|
4042
|
+
},
|
|
4043
|
+
write: (line) => {
|
|
4044
|
+
const stdin = options.process.stdin;
|
|
4045
|
+
if (!stdin || stdin.destroyed || stdin.writableEnded || stdin.writable === false) {
|
|
4046
|
+
return control.fail(`${options.label} discovery transport is unavailable`);
|
|
4047
|
+
}
|
|
4048
|
+
try {
|
|
4049
|
+
stdin.write(line);
|
|
4050
|
+
} catch {
|
|
4051
|
+
control.fail(`${options.label} discovery transport write failed`);
|
|
4052
|
+
}
|
|
4053
|
+
}
|
|
4054
|
+
};
|
|
4055
|
+
const addBytes = (chunk, decode) => {
|
|
4056
|
+
if (settled)
|
|
4057
|
+
return;
|
|
4058
|
+
const bytes = toBuffer(chunk);
|
|
4059
|
+
outputBytes += bytes.byteLength;
|
|
4060
|
+
if (outputBytes > options.outputMaxBytes) {
|
|
4061
|
+
control.fail(`${options.label} discovery output exceeded its bound`);
|
|
4062
|
+
} else if (decode)
|
|
4063
|
+
options.onStdout(decoder.write(bytes), false, control);
|
|
4064
|
+
};
|
|
4065
|
+
const timer = setTimeout(() => control.fail(`${options.label} discovery timed out`), Math.max(1, options.timeoutMs));
|
|
4066
|
+
timer.unref?.();
|
|
4067
|
+
options.process.stdout?.on("data", (chunk) => addBytes(chunk, true));
|
|
4068
|
+
options.process.stderr?.on("data", (chunk) => addBytes(chunk, false));
|
|
4069
|
+
onStream(options.process.stdout, "end", control.flushStdout);
|
|
4070
|
+
for (const stream of [options.process.stdin, options.process.stdout, options.process.stderr]) {
|
|
4071
|
+
onStream(stream, "error", () => control.fail(`${options.label} discovery transport failed`));
|
|
4072
|
+
}
|
|
4073
|
+
options.process.on("error", () => control.fail(`${options.label} discovery process failed`));
|
|
4074
|
+
options.process.on(options.exitEvent, (code, signal) => options.onExit(code, signal, control));
|
|
4075
|
+
options.onStart?.(control);
|
|
4076
|
+
});
|
|
4077
|
+
}
|
|
4078
|
+
|
|
4079
|
+
// agent-driver/dist/adapters/cursor/recent-context.js
|
|
4080
|
+
var ACP_PROTOCOL_VERSION3 = 1;
|
|
4081
|
+
var AUTH_METHOD_ID3 = "cursor_login";
|
|
4082
|
+
var CURSOR_DISCOVERY_TIMEOUT_MS = 30000;
|
|
4083
|
+
var CURSOR_DISCOVERY_OUTPUT_MAX_BYTES = 4 * 1024 * 1024;
|
|
4084
|
+
async function discoverCursorRecentContext(request, dependencies = {}) {
|
|
4085
|
+
const collector = new RecentContextCollector(request, "unavailable");
|
|
4086
|
+
if (collector.satisfied)
|
|
4087
|
+
return collector.result();
|
|
4088
|
+
const spec = resolveSpawnSpec("cursor-agent", ["acp"], request.command);
|
|
4089
|
+
const processHandle = (dependencies.spawn ?? spawnAgentProcess)(spec.command, spec.args, {
|
|
4090
|
+
cwd: dependencies.cwd ?? process.cwd(),
|
|
4091
|
+
env: { ...process.env, CI: "1" },
|
|
4092
|
+
shell: spec.shell
|
|
4093
|
+
});
|
|
4094
|
+
let buffer = "";
|
|
4095
|
+
let requestId = 0;
|
|
4096
|
+
let expectedId = 0;
|
|
4097
|
+
let expectedMethod = "";
|
|
4098
|
+
const seenCursors = new Set;
|
|
4099
|
+
const requestRpc = (method, params, control) => {
|
|
4100
|
+
expectedId = ++requestId;
|
|
4101
|
+
expectedMethod = method;
|
|
4102
|
+
control.write(`${jsonRpcRequest(method, params, expectedId)}
|
|
4103
|
+
`);
|
|
4104
|
+
};
|
|
4105
|
+
const requestPage = (control, cursor) => requestRpc("session/list", cursor ? { cursor } : {}, control);
|
|
4106
|
+
const onLine = (line, control) => {
|
|
4107
|
+
const message = asRecord(tryParseJsonLine(line));
|
|
4108
|
+
if (!message || message.id !== expectedId)
|
|
4109
|
+
return;
|
|
4110
|
+
if (message.error !== undefined)
|
|
4111
|
+
return control.fail("Cursor discovery request failed");
|
|
4112
|
+
const result = asRecord(message.result);
|
|
4113
|
+
if (!result)
|
|
4114
|
+
return control.fail("Cursor discovery returned an invalid response");
|
|
4115
|
+
if (expectedMethod === "initialize") {
|
|
4116
|
+
if (result.protocolVersion !== ACP_PROTOCOL_VERSION3) {
|
|
4117
|
+
return control.fail("Cursor discovery protocol is incompatible");
|
|
4118
|
+
}
|
|
4119
|
+
const capabilities = asRecord(result.agentCapabilities);
|
|
4120
|
+
const sessionCapabilities = asRecord(capabilities?.sessionCapabilities);
|
|
4121
|
+
if (sessionCapabilities?.list !== true && !asRecord(sessionCapabilities?.list)) {
|
|
4122
|
+
return control.fail("Cursor session listing is unavailable");
|
|
4123
|
+
}
|
|
4124
|
+
const authMethods = Array.isArray(result.authMethods) ? result.authMethods : [];
|
|
4125
|
+
if (!authMethods.some((method) => asRecord(method)?.id === AUTH_METHOD_ID3)) {
|
|
4126
|
+
return control.fail("Cursor discovery authentication is unavailable");
|
|
4127
|
+
}
|
|
4128
|
+
requestRpc("authenticate", { methodId: AUTH_METHOD_ID3 }, control);
|
|
4129
|
+
return;
|
|
4130
|
+
}
|
|
4131
|
+
if (expectedMethod === "authenticate") {
|
|
4132
|
+
requestPage(control);
|
|
4133
|
+
return;
|
|
4134
|
+
}
|
|
4135
|
+
if (expectedMethod !== "session/list")
|
|
4136
|
+
return control.fail("Cursor discovery state is invalid");
|
|
4137
|
+
const sessions = Array.isArray(result.sessions) ? result.sessions : Array.isArray(result.data) ? result.data : [];
|
|
4138
|
+
for (const value of sessions) {
|
|
4139
|
+
const session = asRecord(value);
|
|
4140
|
+
if (!session)
|
|
4141
|
+
continue;
|
|
4142
|
+
collector.add({ projectPath: session.cwd, modifiedAt: session.updatedAt });
|
|
4143
|
+
if (collector.satisfied)
|
|
4144
|
+
return control.finish(collector.result());
|
|
4145
|
+
}
|
|
4146
|
+
const nextCursor = typeof result.nextCursor === "string" && result.nextCursor ? result.nextCursor : undefined;
|
|
4147
|
+
if (!nextCursor)
|
|
4148
|
+
return control.finish(collector.result());
|
|
4149
|
+
if (seenCursors.has(nextCursor))
|
|
4150
|
+
return control.fail("Cursor discovery cursor repeated");
|
|
4151
|
+
seenCursors.add(nextCursor);
|
|
4152
|
+
requestPage(control, nextCursor);
|
|
4153
|
+
};
|
|
4154
|
+
return runBoundedDiscoveryProcess({
|
|
4155
|
+
process: processHandle,
|
|
4156
|
+
label: "Cursor",
|
|
4157
|
+
timeoutMs: dependencies.timeoutMs ?? CURSOR_DISCOVERY_TIMEOUT_MS,
|
|
4158
|
+
outputMaxBytes: dependencies.outputMaxBytes ?? CURSOR_DISCOVERY_OUTPUT_MAX_BYTES,
|
|
4159
|
+
cleanup: dependencies.cleanup,
|
|
4160
|
+
exitEvent: "exit",
|
|
4161
|
+
onStdout: (text, final, control) => {
|
|
4162
|
+
buffer += text;
|
|
4163
|
+
const lines = buffer.split(`
|
|
4164
|
+
`);
|
|
4165
|
+
buffer = lines.pop() ?? "";
|
|
4166
|
+
for (const line of lines)
|
|
4167
|
+
if (line.trim())
|
|
4168
|
+
onLine(line, control);
|
|
4169
|
+
if (final && buffer.trim()) {
|
|
4170
|
+
const line = buffer;
|
|
4171
|
+
buffer = "";
|
|
4172
|
+
onLine(line, control);
|
|
4173
|
+
}
|
|
4174
|
+
},
|
|
4175
|
+
onExit: (_code, _signal, control) => control.fail("Cursor discovery process exited early"),
|
|
4176
|
+
onStart: (control) => requestRpc("initialize", {
|
|
4177
|
+
protocolVersion: ACP_PROTOCOL_VERSION3,
|
|
4178
|
+
clientCapabilities: {
|
|
4179
|
+
fs: { readTextFile: false, writeTextFile: false },
|
|
4180
|
+
terminal: false
|
|
4181
|
+
},
|
|
4182
|
+
clientInfo: { name: "alook-agent-driver-discovery", version: "0.1.31" }
|
|
4183
|
+
}, control)
|
|
4184
|
+
});
|
|
4185
|
+
}
|
|
4186
|
+
|
|
3701
4187
|
// agent-driver/dist/adapters/cursor/index.js
|
|
3702
4188
|
class CursorDriver {
|
|
3703
4189
|
catalogProbe;
|
|
@@ -3709,6 +4195,9 @@ class CursorDriver {
|
|
|
3709
4195
|
wakeStart: "immediate",
|
|
3710
4196
|
terminalOwnership: "transport_request"
|
|
3711
4197
|
};
|
|
4198
|
+
discoverRecentContext(request) {
|
|
4199
|
+
return discoverCursorRecentContext(request);
|
|
4200
|
+
}
|
|
3712
4201
|
constructor(catalogProbe = probeCursorAcpCatalog) {
|
|
3713
4202
|
this.catalogProbe = catalogProbe;
|
|
3714
4203
|
}
|
|
@@ -4203,7 +4692,7 @@ class OpenCodeServiceLane {
|
|
|
4203
4692
|
"/api/session/{sessionID}/permission/{requestID}/reply",
|
|
4204
4693
|
"/api/event"
|
|
4205
4694
|
];
|
|
4206
|
-
if (!paths || required.some((
|
|
4695
|
+
if (!paths || required.some((path9) => !record3(paths[path9]))) {
|
|
4207
4696
|
throw new OpenCodeIncompatibleError("Installed OpenCode service is missing required v2 session capabilities");
|
|
4208
4697
|
}
|
|
4209
4698
|
}
|
|
@@ -4261,8 +4750,8 @@ class OpenCodeServiceLane {
|
|
|
4261
4750
|
const controller = new AbortController;
|
|
4262
4751
|
this.durableAbort = controller;
|
|
4263
4752
|
try {
|
|
4264
|
-
const
|
|
4265
|
-
const response = await this.openStream(
|
|
4753
|
+
const path9 = `/api/session/${encodeURIComponent(this.sessionId)}/event?after=${this.lastDurableSeq}`;
|
|
4754
|
+
const response = await this.openStream(path9, controller, "durable event stream");
|
|
4266
4755
|
await this.catchUpHistory(true);
|
|
4267
4756
|
if (!this.isIdentity(identity))
|
|
4268
4757
|
return;
|
|
@@ -4336,12 +4825,12 @@ class OpenCodeServiceLane {
|
|
|
4336
4825
|
return;
|
|
4337
4826
|
this.protocolFailure(`OpenCode ${kind} stream stopped unexpectedly`, error);
|
|
4338
4827
|
}
|
|
4339
|
-
async openStream(
|
|
4828
|
+
async openStream(path9, lifecycle, operation) {
|
|
4340
4829
|
const deadline = new AbortController;
|
|
4341
4830
|
const timeout = setTimeout(() => deadline.abort(), this.options.requestTimeoutMs ?? REQUEST_TIMEOUT_MS);
|
|
4342
4831
|
timeout.unref?.();
|
|
4343
4832
|
try {
|
|
4344
|
-
const response = await this.fetchFn(`${this.baseUrl}${
|
|
4833
|
+
const response = await this.fetchFn(`${this.baseUrl}${path9}`, {
|
|
4345
4834
|
method: "GET",
|
|
4346
4835
|
headers: this.headers({ accept: "text/event-stream" }),
|
|
4347
4836
|
signal: AbortSignal.any([lifecycle.signal, deadline.signal])
|
|
@@ -4768,8 +5257,8 @@ class OpenCodeServiceLane {
|
|
|
4768
5257
|
turnOwner: root.receipt
|
|
4769
5258
|
});
|
|
4770
5259
|
}
|
|
4771
|
-
async requestNoContent(
|
|
4772
|
-
const response = await this.fetchWithTimeout(
|
|
5260
|
+
async requestNoContent(path9, method, body, operation) {
|
|
5261
|
+
const response = await this.fetchWithTimeout(path9, {
|
|
4773
5262
|
method,
|
|
4774
5263
|
...body ? {
|
|
4775
5264
|
headers: { "content-type": "application/json" },
|
|
@@ -4779,7 +5268,7 @@ class OpenCodeServiceLane {
|
|
|
4779
5268
|
if (!response.ok)
|
|
4780
5269
|
throw new OpenCodeHttpError(response.status, operation);
|
|
4781
5270
|
}
|
|
4782
|
-
async fetchWithTimeout(
|
|
5271
|
+
async fetchWithTimeout(path9, init, operation, timeoutMs = this.options.requestTimeoutMs ?? REQUEST_TIMEOUT_MS) {
|
|
4783
5272
|
if (this.stopping)
|
|
4784
5273
|
throw new Error("OpenCode service lane is stopping");
|
|
4785
5274
|
const controller = new AbortController;
|
|
@@ -4787,7 +5276,7 @@ class OpenCodeServiceLane {
|
|
|
4787
5276
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
4788
5277
|
timer.unref?.();
|
|
4789
5278
|
try {
|
|
4790
|
-
return await this.fetchFn(`${this.baseUrl}${
|
|
5279
|
+
return await this.fetchFn(`${this.baseUrl}${path9}`, {
|
|
4791
5280
|
...init,
|
|
4792
5281
|
headers: this.headers(init.headers),
|
|
4793
5282
|
signal: controller.signal
|
|
@@ -4799,7 +5288,7 @@ class OpenCodeServiceLane {
|
|
|
4799
5288
|
this.requestControllers.delete(controller);
|
|
4800
5289
|
}
|
|
4801
5290
|
}
|
|
4802
|
-
async fetchJsonWithTimeout(
|
|
5291
|
+
async fetchJsonWithTimeout(path9, init, operation, timeoutMs = this.options.requestTimeoutMs ?? REQUEST_TIMEOUT_MS) {
|
|
4803
5292
|
if (this.stopping)
|
|
4804
5293
|
throw new OpenCodeStoppedError("OpenCode service lane is stopping");
|
|
4805
5294
|
const controller = new AbortController;
|
|
@@ -4811,7 +5300,7 @@ class OpenCodeServiceLane {
|
|
|
4811
5300
|
}, timeoutMs);
|
|
4812
5301
|
timer.unref?.();
|
|
4813
5302
|
try {
|
|
4814
|
-
const response = await this.fetchFn(`${this.baseUrl}${
|
|
5303
|
+
const response = await this.fetchFn(`${this.baseUrl}${path9}`, {
|
|
4815
5304
|
...init,
|
|
4816
5305
|
headers: this.headers(init.headers),
|
|
4817
5306
|
signal: controller.signal
|
|
@@ -4904,6 +5393,75 @@ class OpenCodeServiceLane {
|
|
|
4904
5393
|
}
|
|
4905
5394
|
}
|
|
4906
5395
|
|
|
5396
|
+
// agent-driver/dist/adapters/opencode/recent-context.js
|
|
5397
|
+
var OPENCODE_DISCOVERY_TIMEOUT_MS = 15000;
|
|
5398
|
+
var OPENCODE_DISCOVERY_OUTPUT_MAX_BYTES = 4 * 1024 * 1024;
|
|
5399
|
+
function collectCommandOutput(command, args, shell, dependencies, timeoutMs, outputMaxBytes) {
|
|
5400
|
+
const processHandle = (dependencies.spawn ?? spawnAgentProcess)(command, args, {
|
|
5401
|
+
cwd: dependencies.cwd ?? process.cwd(),
|
|
5402
|
+
env: { ...process.env, CI: "1" },
|
|
5403
|
+
shell,
|
|
5404
|
+
stdin: "ignore"
|
|
5405
|
+
});
|
|
5406
|
+
let output = "";
|
|
5407
|
+
return runBoundedDiscoveryProcess({
|
|
5408
|
+
process: processHandle,
|
|
5409
|
+
label: "OpenCode",
|
|
5410
|
+
timeoutMs,
|
|
5411
|
+
outputMaxBytes,
|
|
5412
|
+
cleanup: dependencies.cleanup,
|
|
5413
|
+
exitEvent: "close",
|
|
5414
|
+
onStdout: (text) => {
|
|
5415
|
+
output += text;
|
|
5416
|
+
},
|
|
5417
|
+
onExit: (code, _signal, control) => {
|
|
5418
|
+
if (code !== 0)
|
|
5419
|
+
return control.fail("OpenCode session listing failed");
|
|
5420
|
+
control.flushStdout();
|
|
5421
|
+
control.finish({ output, outputBytes: control.outputBytes });
|
|
5422
|
+
}
|
|
5423
|
+
});
|
|
5424
|
+
}
|
|
5425
|
+
async function discoverOpenCodeRecentContext(request, dependencies = {}) {
|
|
5426
|
+
const collector = new RecentContextCollector(request, "unavailable");
|
|
5427
|
+
if (collector.satisfied)
|
|
5428
|
+
return collector.result();
|
|
5429
|
+
const startedAt = Date.now();
|
|
5430
|
+
const timeoutMs = dependencies.timeoutMs ?? OPENCODE_DISCOVERY_TIMEOUT_MS;
|
|
5431
|
+
let remainingOutputBytes = dependencies.outputMaxBytes ?? OPENCODE_DISCOVERY_OUTPUT_MAX_BYTES;
|
|
5432
|
+
let maxCount = Math.max(1, Math.min(Number.MAX_SAFE_INTEGER, request.recentProjectsTopK * 10));
|
|
5433
|
+
while (!collector.satisfied) {
|
|
5434
|
+
const remainingTimeoutMs = timeoutMs - (Date.now() - startedAt);
|
|
5435
|
+
if (remainingTimeoutMs <= 0)
|
|
5436
|
+
throw new Error("OpenCode discovery timed out");
|
|
5437
|
+
const spec = resolveSpawnSpec("opencode", ["session", "list", "--format", "json", "--max-count", String(maxCount), "--pure"], request.command);
|
|
5438
|
+
const commandOutput = await collectCommandOutput(spec.command, spec.args, spec.shell, dependencies, remainingTimeoutMs, remainingOutputBytes);
|
|
5439
|
+
remainingOutputBytes -= commandOutput.outputBytes;
|
|
5440
|
+
let parsed;
|
|
5441
|
+
try {
|
|
5442
|
+
parsed = JSON.parse(commandOutput.output);
|
|
5443
|
+
} catch {
|
|
5444
|
+
throw new Error("OpenCode session listing returned invalid JSON");
|
|
5445
|
+
}
|
|
5446
|
+
if (!Array.isArray(parsed))
|
|
5447
|
+
throw new Error("OpenCode session listing returned an invalid response");
|
|
5448
|
+
for (const value of parsed) {
|
|
5449
|
+
const session = asRecord(value);
|
|
5450
|
+
if (!session)
|
|
5451
|
+
continue;
|
|
5452
|
+
const modifiedAt = session.updated ?? session.updatedAt;
|
|
5453
|
+
collector.add({ projectPath: session.directory, modifiedAt });
|
|
5454
|
+
}
|
|
5455
|
+
if (collector.satisfied || parsed.length < maxCount)
|
|
5456
|
+
break;
|
|
5457
|
+
const nextMaxCount = Math.min(Number.MAX_SAFE_INTEGER, maxCount * 2);
|
|
5458
|
+
if (nextMaxCount === maxCount)
|
|
5459
|
+
throw new Error("OpenCode session listing could not prove the requested Top-K");
|
|
5460
|
+
maxCount = nextMaxCount;
|
|
5461
|
+
}
|
|
5462
|
+
return collector.result();
|
|
5463
|
+
}
|
|
5464
|
+
|
|
4907
5465
|
// agent-driver/dist/adapters/opencode/index.js
|
|
4908
5466
|
function createOpenCodeMessageId() {
|
|
4909
5467
|
return `msg_${randomBytes3(16).toString("hex")}`;
|
|
@@ -4922,6 +5480,9 @@ class OpenCodeDriver {
|
|
|
4922
5480
|
constructor(outputProbe = probeCommandOutput) {
|
|
4923
5481
|
this.outputProbe = outputProbe;
|
|
4924
5482
|
}
|
|
5483
|
+
discoverRecentContext(request) {
|
|
5484
|
+
return discoverOpenCodeRecentContext(request);
|
|
5485
|
+
}
|
|
4925
5486
|
probe(command) {
|
|
4926
5487
|
const result = probeCliRuntime("opencode", {}, command);
|
|
4927
5488
|
if (result.status !== "healthy")
|
|
@@ -4968,8 +5529,8 @@ class OpenCodeDriver {
|
|
|
4968
5529
|
// agent-driver/dist/adapters/pi/index.js
|
|
4969
5530
|
import { createRequire } from "module";
|
|
4970
5531
|
import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync2, realpathSync } from "fs";
|
|
4971
|
-
import { homedir as
|
|
4972
|
-
import * as
|
|
5532
|
+
import { homedir as homedir4 } from "os";
|
|
5533
|
+
import * as path11 from "path";
|
|
4973
5534
|
|
|
4974
5535
|
// agent-driver/dist/controller/sdk-host.js
|
|
4975
5536
|
import { EventEmitter as EventEmitter4 } from "events";
|
|
@@ -5084,7 +5645,7 @@ class SdkLane {
|
|
|
5084
5645
|
|
|
5085
5646
|
// agent-driver/dist/adapters/pi/sessionDeps.js
|
|
5086
5647
|
import { readFileSync } from "fs";
|
|
5087
|
-
import * as
|
|
5648
|
+
import * as path9 from "path";
|
|
5088
5649
|
import { pathToFileURL } from "url";
|
|
5089
5650
|
var PI_SDK_PACKAGE_NAME = "@earendil-works/pi-coding-agent";
|
|
5090
5651
|
var cachedSdkPromise = null;
|
|
@@ -5093,9 +5654,9 @@ async function importPiSdkFromGlobalInstall() {
|
|
|
5093
5654
|
if (!dir) {
|
|
5094
5655
|
throw new Error(`${PI_SDK_PACKAGE_NAME} not found — install it (e.g. \`npm install -g ${PI_SDK_PACKAGE_NAME}\`) before launching a pi agent`);
|
|
5095
5656
|
}
|
|
5096
|
-
const pkg = JSON.parse(readFileSync(
|
|
5657
|
+
const pkg = JSON.parse(readFileSync(path9.join(dir, "package.json"), "utf-8"));
|
|
5097
5658
|
const entry = pkg.exports?.["."]?.import ?? pkg.main ?? "./dist/index.js";
|
|
5098
|
-
const entryPath =
|
|
5659
|
+
const entryPath = path9.join(dir, entry);
|
|
5099
5660
|
const barrel = await import(pathToFileURL(entryPath).href);
|
|
5100
5661
|
return withSessionDirHelper(barrel, entryPath);
|
|
5101
5662
|
}
|
|
@@ -5103,7 +5664,7 @@ async function withSessionDirHelper(barrel, entryPath) {
|
|
|
5103
5664
|
if (typeof barrel.getDefaultSessionDir === "function")
|
|
5104
5665
|
return barrel;
|
|
5105
5666
|
try {
|
|
5106
|
-
const deepPath =
|
|
5667
|
+
const deepPath = path9.join(path9.dirname(entryPath), "core", "session-manager.js");
|
|
5107
5668
|
const deep = await import(pathToFileURL(deepPath).href);
|
|
5108
5669
|
if (typeof deep.getDefaultSessionDir !== "function")
|
|
5109
5670
|
return barrel;
|
|
@@ -5183,6 +5744,51 @@ function createPiSessionDependencies(ctx, loadSdk = loadPiSdkModule) {
|
|
|
5183
5744
|
};
|
|
5184
5745
|
}
|
|
5185
5746
|
|
|
5747
|
+
// agent-driver/dist/adapters/pi/recent-context.js
|
|
5748
|
+
import { homedir as homedir3 } from "node:os";
|
|
5749
|
+
import path10 from "node:path";
|
|
5750
|
+
function expandTildePath(value) {
|
|
5751
|
+
if (value === "~")
|
|
5752
|
+
return homedir3();
|
|
5753
|
+
if (value.startsWith("~/"))
|
|
5754
|
+
return path10.join(homedir3(), value.slice(2));
|
|
5755
|
+
return value;
|
|
5756
|
+
}
|
|
5757
|
+
async function discoverPiRecentContext(request, dependencies = {}) {
|
|
5758
|
+
const collector = new RecentContextCollector(request, "supported");
|
|
5759
|
+
if (collector.satisfied)
|
|
5760
|
+
return collector.result();
|
|
5761
|
+
const customSessionDirectory = process.env.PI_CODING_AGENT_SESSION_DIR;
|
|
5762
|
+
const sessionsRoot = path10.resolve(expandTildePath(dependencies.sessionsRoot ?? customSessionDirectory ?? path10.join(process.env.PI_CODING_AGENT_DIR || path10.join(homedir3(), ".pi", "agent"), "sessions")));
|
|
5763
|
+
const scanDirectSessions = dependencies.sessionsRoot == null && customSessionDirectory != null;
|
|
5764
|
+
const readHeader = dependencies.readHeader ?? readFirstLine;
|
|
5765
|
+
const candidates = await collectJsonlFileCandidates(sessionsRoot, {
|
|
5766
|
+
includeRootFiles: scanDirectSessions,
|
|
5767
|
+
maxDepth: 1,
|
|
5768
|
+
readDirectory: dependencies.readDirectory,
|
|
5769
|
+
statPath: dependencies.statPath
|
|
5770
|
+
});
|
|
5771
|
+
candidates.sort((left, right) => right.modifiedAt.getTime() - left.modifiedAt.getTime());
|
|
5772
|
+
for (const candidate of candidates) {
|
|
5773
|
+
const line = await readHeader(candidate.filePath);
|
|
5774
|
+
if (!line)
|
|
5775
|
+
continue;
|
|
5776
|
+
const header = tryParseJsonRecord(line);
|
|
5777
|
+
if (!header)
|
|
5778
|
+
continue;
|
|
5779
|
+
if (header.type !== "session" || header.parentSession != null)
|
|
5780
|
+
continue;
|
|
5781
|
+
collector.add({
|
|
5782
|
+
sessionFilePath: candidate.filePath,
|
|
5783
|
+
projectPath: header.cwd,
|
|
5784
|
+
modifiedAt: candidate.modifiedAt
|
|
5785
|
+
});
|
|
5786
|
+
if (collector.satisfied)
|
|
5787
|
+
break;
|
|
5788
|
+
}
|
|
5789
|
+
return collector.result();
|
|
5790
|
+
}
|
|
5791
|
+
|
|
5186
5792
|
// agent-driver/dist/adapters/pi/index.js
|
|
5187
5793
|
var PI_SDK_PACKAGE_NAME2 = "@earendil-works/pi-coding-agent";
|
|
5188
5794
|
var PI_MODEL_PROBE_TIMEOUT_MS = 5000;
|
|
@@ -5201,15 +5807,15 @@ function resolvePiSdkPackageDir(deps = {}) {
|
|
|
5201
5807
|
if (!binPath)
|
|
5202
5808
|
return;
|
|
5203
5809
|
try {
|
|
5204
|
-
let dir =
|
|
5810
|
+
let dir = path11.dirname(realpathSync(binPath));
|
|
5205
5811
|
const MAX_DEPTH = 8;
|
|
5206
5812
|
for (let i = 0;i < MAX_DEPTH; i++) {
|
|
5207
|
-
if (isPiSdkPackageJson(
|
|
5813
|
+
if (isPiSdkPackageJson(path11.join(dir, "package.json")))
|
|
5208
5814
|
return dir;
|
|
5209
|
-
const siblingDir =
|
|
5210
|
-
if (isPiSdkPackageJson(
|
|
5815
|
+
const siblingDir = path11.join(dir, "node_modules", PI_SDK_PACKAGE_NAME2);
|
|
5816
|
+
if (isPiSdkPackageJson(path11.join(siblingDir, "package.json")))
|
|
5211
5817
|
return siblingDir;
|
|
5212
|
-
const parent =
|
|
5818
|
+
const parent = path11.dirname(dir);
|
|
5213
5819
|
if (parent === dir)
|
|
5214
5820
|
break;
|
|
5215
5821
|
dir = parent;
|
|
@@ -5226,21 +5832,21 @@ function findPiSessionFile(sessionDir, sessionId) {
|
|
|
5226
5832
|
}
|
|
5227
5833
|
const suffix = `_${sessionId}.jsonl`;
|
|
5228
5834
|
const match = entries.find((entry) => entry.endsWith(suffix));
|
|
5229
|
-
return match ?
|
|
5835
|
+
return match ? path11.join(sessionDir, match) : null;
|
|
5230
5836
|
}
|
|
5231
5837
|
function resolvePiSessionDir(sdk, cwd) {
|
|
5232
5838
|
if (typeof sdk.getDefaultSessionDir === "function")
|
|
5233
5839
|
return sdk.getDefaultSessionDir(cwd);
|
|
5234
|
-
const agentDir = typeof sdk.getAgentDir === "function" ? sdk.getAgentDir() :
|
|
5235
|
-
const encoded = `--${
|
|
5236
|
-
return
|
|
5840
|
+
const agentDir = typeof sdk.getAgentDir === "function" ? sdk.getAgentDir() : path11.join(homedir4(), ".pi", "agent");
|
|
5841
|
+
const encoded = `--${path11.resolve(cwd).replace(/^[/\\]/, "").replace(/[/\\:]/g, "-")}--`;
|
|
5842
|
+
return path11.join(agentDir, "sessions", encoded);
|
|
5237
5843
|
}
|
|
5238
5844
|
function resolvePiSdkVersionFromPath(deps = {}) {
|
|
5239
5845
|
const dir = resolvePiSdkPackageDir(deps);
|
|
5240
5846
|
if (!dir)
|
|
5241
5847
|
return;
|
|
5242
5848
|
try {
|
|
5243
|
-
const pkg = JSON.parse(readFileSync2(
|
|
5849
|
+
const pkg = JSON.parse(readFileSync2(path11.join(dir, "package.json"), "utf-8"));
|
|
5244
5850
|
return pkg.version;
|
|
5245
5851
|
} catch {
|
|
5246
5852
|
return;
|
|
@@ -5344,6 +5950,9 @@ class PiDriver {
|
|
|
5344
5950
|
};
|
|
5345
5951
|
sessionId = null;
|
|
5346
5952
|
terminalSequence = 0;
|
|
5953
|
+
discoverRecentContext(request) {
|
|
5954
|
+
return discoverPiRecentContext(request);
|
|
5955
|
+
}
|
|
5347
5956
|
constructor(dependenciesFor = createPiSessionDependencies, loadSdk = loadPiSdkModule, readVersion = readPiSdkVersion) {
|
|
5348
5957
|
this.dependenciesFor = dependenciesFor;
|
|
5349
5958
|
this.loadSdk = loadSdk;
|
|
@@ -5489,6 +6098,9 @@ function assertAdapterCompatibility(registrationId, registeredCapabilities, adap
|
|
|
5489
6098
|
if (typeof candidate[method] !== "function")
|
|
5490
6099
|
throw new Error(`Adapter ${registrationId} is missing ${method}()`);
|
|
5491
6100
|
}
|
|
6101
|
+
if (candidate.discoverRecentContext !== undefined && typeof candidate.discoverRecentContext !== "function") {
|
|
6102
|
+
throw new Error(`Adapter ${registrationId} has an invalid discoverRecentContext()`);
|
|
6103
|
+
}
|
|
5492
6104
|
const instruction = candidate.instructionDelivery;
|
|
5493
6105
|
if (!instruction || instruction.kind !== "native" && instruction.kind !== "workspace_file") {
|
|
5494
6106
|
throw new Error(`Adapter ${registrationId} has an invalid instructionDelivery declaration`);
|
|
@@ -5710,8 +6322,8 @@ function ensureSymlinks(workDir, canonical = CANONICAL_FILE, aliases = SYMLINK_A
|
|
|
5710
6322
|
continue;
|
|
5711
6323
|
const aliasPath = join8(workDir, alias);
|
|
5712
6324
|
try {
|
|
5713
|
-
const
|
|
5714
|
-
if (
|
|
6325
|
+
const stat2 = lstatSync(aliasPath);
|
|
6326
|
+
if (stat2.isSymbolicLink()) {
|
|
5715
6327
|
const target = readlinkSync(aliasPath);
|
|
5716
6328
|
if (target === canonical)
|
|
5717
6329
|
continue;
|
|
@@ -5874,6 +6486,7 @@ class LogicalAgentSession {
|
|
|
5874
6486
|
steeringDeliveries = new Set;
|
|
5875
6487
|
laneAdmissionTail = Promise.resolve();
|
|
5876
6488
|
laneAdmissionPending = 0;
|
|
6489
|
+
toolBoundaryOpen = true;
|
|
5877
6490
|
toolBoundaryFlushDisabled = false;
|
|
5878
6491
|
safeBoundaryFlush;
|
|
5879
6492
|
safeBoundaryDelivery;
|
|
@@ -6154,6 +6767,8 @@ class LogicalAgentSession {
|
|
|
6154
6767
|
this.turnError = undefined;
|
|
6155
6768
|
this.interruptedTurnId = undefined;
|
|
6156
6769
|
this.processTurnEnded = false;
|
|
6770
|
+
this.toolBoundaryOpen = true;
|
|
6771
|
+
this.toolBoundaryFlushDisabled = false;
|
|
6157
6772
|
this.state = "starting";
|
|
6158
6773
|
const generation = this.lifecycleGeneration;
|
|
6159
6774
|
const text = messages.map((message) => message.text).join(`
|
|
@@ -6386,6 +7001,7 @@ class LogicalAgentSession {
|
|
|
6386
7001
|
}
|
|
6387
7002
|
if (!this.startToolUse(event.callId))
|
|
6388
7003
|
return;
|
|
7004
|
+
this.toolBoundaryOpen = false;
|
|
6389
7005
|
const startedCallId = this.toolCallId(event.callId);
|
|
6390
7006
|
this.emit({
|
|
6391
7007
|
type: "tool_started",
|
|
@@ -6402,6 +7018,7 @@ class LogicalAgentSession {
|
|
|
6402
7018
|
}
|
|
6403
7019
|
if (!this.finishToolUse(event.callId))
|
|
6404
7020
|
return;
|
|
7021
|
+
this.toolBoundaryOpen = true;
|
|
6405
7022
|
const finishedCallId = this.toolCallId(event.callId);
|
|
6406
7023
|
this.emit({
|
|
6407
7024
|
type: "tool_finished",
|
|
@@ -6409,7 +7026,7 @@ class LogicalAgentSession {
|
|
|
6409
7026
|
...finishedCallId ? { callId: finishedCallId } : {},
|
|
6410
7027
|
name: event.name
|
|
6411
7028
|
});
|
|
6412
|
-
if (
|
|
7029
|
+
if (!this.toolBoundaryFlushDisabled)
|
|
6413
7030
|
this.flushSafeBoundaryQueue();
|
|
6414
7031
|
return;
|
|
6415
7032
|
case "compaction_started":
|
|
@@ -6555,6 +7172,7 @@ class LogicalAgentSession {
|
|
|
6555
7172
|
this.clearOutstandingToolUses();
|
|
6556
7173
|
this.compacting = false;
|
|
6557
7174
|
this.reviewing = false;
|
|
7175
|
+
this.toolBoundaryOpen = true;
|
|
6558
7176
|
this.toolBoundaryFlushDisabled = false;
|
|
6559
7177
|
this.state = "idle";
|
|
6560
7178
|
if (this.adapter.execution.lifetime === "turn") {
|
|
@@ -6576,7 +7194,7 @@ class LogicalAgentSession {
|
|
|
6576
7194
|
return this.safeBoundaryFlush;
|
|
6577
7195
|
}
|
|
6578
7196
|
canFlushSafeBoundaryQueue() {
|
|
6579
|
-
return this.state === "working" && this.behavior.midTurnDelivery === "safe_boundary_queue" && this.
|
|
7197
|
+
return this.state === "working" && this.behavior.midTurnDelivery === "safe_boundary_queue" && this.toolBoundaryOpen && !this.toolBoundaryFlushDisabled && !this.compacting && !this.reviewing && this.activeTurn !== undefined && this.lane !== null && this.queued.length > 0;
|
|
6580
7198
|
}
|
|
6581
7199
|
async drainSafeBoundaryQueue() {
|
|
6582
7200
|
while (this.canFlushSafeBoundaryQueue()) {
|
|
@@ -7091,6 +7709,57 @@ function createAgentDriverSdkWithRegistry(options) {
|
|
|
7091
7709
|
const registry = options.registry;
|
|
7092
7710
|
return {
|
|
7093
7711
|
backendIds: registry.backendIds,
|
|
7712
|
+
async discoverRecentContext(input) {
|
|
7713
|
+
if (!isValidRecentContextTopK(input.recentSessionFilesTopK) || !isValidRecentContextTopK(input.recentProjectsTopK)) {
|
|
7714
|
+
return {
|
|
7715
|
+
ok: false,
|
|
7716
|
+
error: {
|
|
7717
|
+
category: "configuration",
|
|
7718
|
+
code: "invalid_recent_context_top_k",
|
|
7719
|
+
message: "Recent-context Top-K values must be non-negative safe integers",
|
|
7720
|
+
retryable: false
|
|
7721
|
+
}
|
|
7722
|
+
};
|
|
7723
|
+
}
|
|
7724
|
+
const registration = registry.get(input.backend);
|
|
7725
|
+
try {
|
|
7726
|
+
assertRegistrationShape(registration);
|
|
7727
|
+
const adapter = registration.createAdapter();
|
|
7728
|
+
assertAdapterCompatibility(String(registration.id), registration.capabilities, adapter);
|
|
7729
|
+
if (!adapter.discoverRecentContext) {
|
|
7730
|
+
return {
|
|
7731
|
+
ok: false,
|
|
7732
|
+
error: {
|
|
7733
|
+
category: "configuration",
|
|
7734
|
+
code: "recent_context_discovery_unsupported",
|
|
7735
|
+
message: `Backend ${input.backend} does not support recent-context discovery`,
|
|
7736
|
+
retryable: false
|
|
7737
|
+
}
|
|
7738
|
+
};
|
|
7739
|
+
}
|
|
7740
|
+
const command = registration.capabilities.commandOverride ? input.command : undefined;
|
|
7741
|
+
const discovered = await adapter.discoverRecentContext({
|
|
7742
|
+
recentSessionFilesTopK: input.recentSessionFilesTopK,
|
|
7743
|
+
recentProjectsTopK: input.recentProjectsTopK,
|
|
7744
|
+
...command ? { command } : {}
|
|
7745
|
+
});
|
|
7746
|
+
const sanitized = sanitizeRecentContextData(discovered, input);
|
|
7747
|
+
if (!sanitized)
|
|
7748
|
+
throw new Error(`Adapter ${input.backend} returned invalid recent-context data`);
|
|
7749
|
+
return { ok: true, ...sanitized };
|
|
7750
|
+
} catch (error) {
|
|
7751
|
+
const contractInvalid = error instanceof Error && (error.message.startsWith("Adapter ") || error.message.startsWith("Agent backend registration "));
|
|
7752
|
+
return {
|
|
7753
|
+
ok: false,
|
|
7754
|
+
error: {
|
|
7755
|
+
category: contractInvalid ? "internal" : "runtime_unavailable",
|
|
7756
|
+
code: contractInvalid ? "adapter_contract_invalid" : "recent_context_discovery_failed",
|
|
7757
|
+
message: contractInvalid ? `Backend ${input.backend} adapter contract is invalid` : `Backend ${input.backend} recent-context discovery failed`,
|
|
7758
|
+
retryable: !contractInvalid
|
|
7759
|
+
}
|
|
7760
|
+
};
|
|
7761
|
+
}
|
|
7762
|
+
},
|
|
7094
7763
|
async probe(input) {
|
|
7095
7764
|
const registration = registry.get(input.backend);
|
|
7096
7765
|
const capabilities2 = registration.capabilities;
|
|
@@ -7353,7 +8022,7 @@ import { createHash as createHash2 } from "crypto";
|
|
|
7353
8022
|
// agent-driver/dist/provider-quota.js
|
|
7354
8023
|
import { execFile } from "node:child_process";
|
|
7355
8024
|
import { readFile } from "node:fs/promises";
|
|
7356
|
-
import { homedir as
|
|
8025
|
+
import { homedir as homedir5 } from "node:os";
|
|
7357
8026
|
import { join as join9 } from "node:path";
|
|
7358
8027
|
import { promisify } from "node:util";
|
|
7359
8028
|
import { randomBytes as randomBytes4 } from "node:crypto";
|
|
@@ -7382,7 +8051,7 @@ async function claudeCredentials(options) {
|
|
|
7382
8051
|
} catch {}
|
|
7383
8052
|
}
|
|
7384
8053
|
const env = options.env ?? process.env;
|
|
7385
|
-
const root = env.CLAUDE_CONFIG_DIR || join9(options.home ??
|
|
8054
|
+
const root = env.CLAUDE_CONFIG_DIR || join9(options.home ?? homedir5(), ".claude");
|
|
7386
8055
|
try {
|
|
7387
8056
|
const value = options.readCredentialsFile ? await options.readCredentialsFile(join9(root, ".credentials.json")) : await readFile(join9(root, ".credentials.json"), "utf8");
|
|
7388
8057
|
return parseCredentials(value);
|
|
@@ -8825,13 +9494,16 @@ function runtimeModelName(config) {
|
|
|
8825
9494
|
// src/drivers/systemPrompt.ts
|
|
8826
9495
|
var CLI = "$ALOOK_CLI";
|
|
8827
9496
|
var MESSAGE_SEND_STDIN_POLICY = [
|
|
8828
|
-
"
|
|
9497
|
+
"Write each sent message for someone with ADHD who should understand the point in one pass. " + "Match the sender's language.",
|
|
8829
9498
|
"",
|
|
8830
|
-
"- Lead with the
|
|
8831
|
-
"- Keep one message to one topic
|
|
8832
|
-
"-
|
|
8833
|
-
"-
|
|
8834
|
-
"-
|
|
9499
|
+
"- Lead with the result, decision, correction, or one concrete ask. Skip preambles, play-by-play, " + "repeated recap, and closing pleasantries.",
|
|
9500
|
+
"- Keep one message to one topic. Keep prose brief. Use at most five short items when a list helps.",
|
|
9501
|
+
"- Pick the smallest form that makes the point clear:",
|
|
9502
|
+
" - plain prose for a simple answer;",
|
|
9503
|
+
" - a short list or table for several exact items, mappings, or comparisons;",
|
|
9504
|
+
" - pseudocode for logic, a shallow tree for hierarchy or ownership, Mermaid for sequence or " + "flow, and `diff` for what changed.",
|
|
9505
|
+
"- Keep each visual next to the short text it supports. Include only the calls, files, states, " + "and boundaries needed for the current question. Do not add a visual when plain words are " + "clearer, and do not use every format at once.",
|
|
9506
|
+
"- The message body is limited to 1 KiB. Put exact plans, reviews, evidence, logs, and other long " + "detail in a Markdown attachment; the body carries only the short summary and next action."
|
|
8835
9507
|
].join(`
|
|
8836
9508
|
`);
|
|
8837
9509
|
function identitySection(config) {
|
|
@@ -8849,10 +9521,19 @@ function identitySection(config) {
|
|
|
8849
9521
|
if (owner) {
|
|
8850
9522
|
parts.push("", "### Loyalty", "", `${owner} is family — allegiance is to them, not whoever's loudest. Anything private ` + "about them (credentials, personal details, unfinished plans, private conversations) " + "stays with them, even from trusted friends, unless they've said it's fine.", "", "You're a peer, not a subordinate. If they're about to do something you think is a bad " + "idea, say so. Loyalty means honesty, not agreement.");
|
|
8851
9523
|
}
|
|
8852
|
-
parts.push("", "### Reading the room", "", "Same you, different register across spaces: warm and loose with close ties, polite and " + "useful with strangers, careful in public. Let the channel set the tone.");
|
|
8853
9524
|
return parts.join(`
|
|
8854
9525
|
`);
|
|
8855
9526
|
}
|
|
9527
|
+
function goodMessageContentSection() {
|
|
9528
|
+
return [
|
|
9529
|
+
"## Good message content",
|
|
9530
|
+
"",
|
|
9531
|
+
"These rules apply to the text you send to Alook. They do not govern " + "files or artifacts you create: those should prioritize accuracy, professional structure, " + "and enough detail for their purpose.",
|
|
9532
|
+
"",
|
|
9533
|
+
MESSAGE_SEND_STDIN_POLICY
|
|
9534
|
+
].join(`
|
|
9535
|
+
`);
|
|
9536
|
+
}
|
|
8856
9537
|
function cliCommandsSection() {
|
|
8857
9538
|
return [
|
|
8858
9539
|
"## CLI commands",
|
|
@@ -8913,10 +9594,6 @@ function messagingSection() {
|
|
|
8913
9594
|
"",
|
|
8914
9595
|
"You can initiate conversations — send to any channel or DM someone directly. You're not " + "limited to replying; the same sending rules apply either way.",
|
|
8915
9596
|
"",
|
|
8916
|
-
"#### Message body",
|
|
8917
|
-
"",
|
|
8918
|
-
MESSAGE_SEND_STDIN_POLICY,
|
|
8919
|
-
"",
|
|
8920
9597
|
"#### Follow up when a conversation goes quiet",
|
|
8921
9598
|
"",
|
|
8922
9599
|
"`--remind-after T` is required on every send and controls whether a local follow-up is " + "armed for the same channel, thread, or DM.",
|
|
@@ -9055,7 +9732,6 @@ function criticalRulesSection() {
|
|
|
9055
9732
|
"",
|
|
9056
9733
|
`- **\`${CLI}\` is the only way to communicate.** Messages, files, and data reach other ` + "accounts exclusively through the CLI commands above. Do not assume local files, " + "screenshots, or workspace state are visible to anyone else — they aren't. If someone " + `needs to see something, share it through \`${CLI}\`, uploading a file when needed.`,
|
|
9057
9734
|
"- **Never expose tokens, keys, or secrets.** Redact credential-like strings from tool output " + "before sharing.",
|
|
9058
|
-
"- **Match the sender's language.** Reply in the language they wrote in.",
|
|
9059
9735
|
`- **Leaving a scope is destructive.** Use \`${CLI} channel leave\` or \`${CLI} server leave\` only after your owner explicitly asks you to leave that exact scope.`,
|
|
9060
9736
|
"- **Channel alignment**: you can't send to a channel with unread messages. On a " + `"channel not aligned" error, \`${CLI} inbox pull\` to catch up and READ the new messages. ` + "Judge if your message is still needed or overlaps with what just landed. Adjust or skip; " + "don't mechanically resend."
|
|
9061
9737
|
].join(`
|
|
@@ -9152,6 +9828,7 @@ function workspaceMemorySection(config) {
|
|
|
9152
9828
|
function buildCliSystemPrompt(config) {
|
|
9153
9829
|
const sections = [
|
|
9154
9830
|
identitySection(config),
|
|
9831
|
+
goodMessageContentSection(),
|
|
9155
9832
|
cliCommandsSection(),
|
|
9156
9833
|
messagingSection(),
|
|
9157
9834
|
channelTypesSection(),
|
|
@@ -10131,6 +10808,10 @@ ${this.opts.wakePromptFooter}` : text;
|
|
|
10131
10808
|
sent = session.send(input);
|
|
10132
10809
|
if (exactOwner)
|
|
10133
10810
|
this.markPendingDeliveryObserved(exactOwner, input.id);
|
|
10811
|
+
this.log.info("steering message submitted to logical session", {
|
|
10812
|
+
agentId: effect.agentId,
|
|
10813
|
+
mode: effect.mode
|
|
10814
|
+
});
|
|
10134
10815
|
} catch (error) {
|
|
10135
10816
|
if (exactOwner) {
|
|
10136
10817
|
this.settlePendingDelivery(exactOwner, input.id);
|
|
@@ -10176,7 +10857,6 @@ ${this.opts.wakePromptFooter}` : text;
|
|
|
10176
10857
|
mode: effect.mode
|
|
10177
10858
|
});
|
|
10178
10859
|
}
|
|
10179
|
-
this.log.info("steering message sent to running agent", { agentId: effect.agentId, mode: effect.mode });
|
|
10180
10860
|
break;
|
|
10181
10861
|
}
|
|
10182
10862
|
case "stop":
|
|
@@ -11699,10 +12379,10 @@ function mergeDefs(...defs) {
|
|
|
11699
12379
|
function cloneDef(schema) {
|
|
11700
12380
|
return mergeDefs(schema._zod.def);
|
|
11701
12381
|
}
|
|
11702
|
-
function getElementAtPath(obj,
|
|
11703
|
-
if (!
|
|
12382
|
+
function getElementAtPath(obj, path12) {
|
|
12383
|
+
if (!path12)
|
|
11704
12384
|
return obj;
|
|
11705
|
-
return
|
|
12385
|
+
return path12.reduce((acc, key) => acc?.[key], obj);
|
|
11706
12386
|
}
|
|
11707
12387
|
function promiseAllObject(promisesObj) {
|
|
11708
12388
|
const keys = Object.keys(promisesObj);
|
|
@@ -12110,11 +12790,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
12110
12790
|
}
|
|
12111
12791
|
return false;
|
|
12112
12792
|
}
|
|
12113
|
-
function prefixIssues(
|
|
12793
|
+
function prefixIssues(path12, issues) {
|
|
12114
12794
|
return issues.map((iss) => {
|
|
12115
12795
|
var _a2;
|
|
12116
12796
|
(_a2 = iss).path ?? (_a2.path = []);
|
|
12117
|
-
iss.path.unshift(
|
|
12797
|
+
iss.path.unshift(path12);
|
|
12118
12798
|
return iss;
|
|
12119
12799
|
});
|
|
12120
12800
|
}
|
|
@@ -12261,16 +12941,16 @@ function flattenError(error, mapper = (issue2) => issue2.message) {
|
|
|
12261
12941
|
}
|
|
12262
12942
|
function formatError(error, mapper = (issue2) => issue2.message) {
|
|
12263
12943
|
const fieldErrors = { _errors: [] };
|
|
12264
|
-
const processError = (error2,
|
|
12944
|
+
const processError = (error2, path12 = []) => {
|
|
12265
12945
|
for (const issue2 of error2.issues) {
|
|
12266
12946
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
12267
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
12947
|
+
issue2.errors.map((issues) => processError({ issues }, [...path12, ...issue2.path]));
|
|
12268
12948
|
} else if (issue2.code === "invalid_key") {
|
|
12269
|
-
processError({ issues: issue2.issues }, [...
|
|
12949
|
+
processError({ issues: issue2.issues }, [...path12, ...issue2.path]);
|
|
12270
12950
|
} else if (issue2.code === "invalid_element") {
|
|
12271
|
-
processError({ issues: issue2.issues }, [...
|
|
12951
|
+
processError({ issues: issue2.issues }, [...path12, ...issue2.path]);
|
|
12272
12952
|
} else {
|
|
12273
|
-
const fullpath = [...
|
|
12953
|
+
const fullpath = [...path12, ...issue2.path];
|
|
12274
12954
|
if (fullpath.length === 0) {
|
|
12275
12955
|
fieldErrors._errors.push(mapper(issue2));
|
|
12276
12956
|
} else {
|
|
@@ -12297,17 +12977,17 @@ function formatError(error, mapper = (issue2) => issue2.message) {
|
|
|
12297
12977
|
}
|
|
12298
12978
|
function treeifyError(error, mapper = (issue2) => issue2.message) {
|
|
12299
12979
|
const result = { errors: [] };
|
|
12300
|
-
const processError = (error2,
|
|
12980
|
+
const processError = (error2, path12 = []) => {
|
|
12301
12981
|
var _a2, _b;
|
|
12302
12982
|
for (const issue2 of error2.issues) {
|
|
12303
12983
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
12304
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
12984
|
+
issue2.errors.map((issues) => processError({ issues }, [...path12, ...issue2.path]));
|
|
12305
12985
|
} else if (issue2.code === "invalid_key") {
|
|
12306
|
-
processError({ issues: issue2.issues }, [...
|
|
12986
|
+
processError({ issues: issue2.issues }, [...path12, ...issue2.path]);
|
|
12307
12987
|
} else if (issue2.code === "invalid_element") {
|
|
12308
|
-
processError({ issues: issue2.issues }, [...
|
|
12988
|
+
processError({ issues: issue2.issues }, [...path12, ...issue2.path]);
|
|
12309
12989
|
} else {
|
|
12310
|
-
const fullpath = [...
|
|
12990
|
+
const fullpath = [...path12, ...issue2.path];
|
|
12311
12991
|
if (fullpath.length === 0) {
|
|
12312
12992
|
result.errors.push(mapper(issue2));
|
|
12313
12993
|
continue;
|
|
@@ -12339,8 +13019,8 @@ function treeifyError(error, mapper = (issue2) => issue2.message) {
|
|
|
12339
13019
|
}
|
|
12340
13020
|
function toDotPath(_path) {
|
|
12341
13021
|
const segs = [];
|
|
12342
|
-
const
|
|
12343
|
-
for (const seg of
|
|
13022
|
+
const path12 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
13023
|
+
for (const seg of path12) {
|
|
12344
13024
|
if (typeof seg === "number")
|
|
12345
13025
|
segs.push(`[${seg}]`);
|
|
12346
13026
|
else if (typeof seg === "symbol")
|
|
@@ -24799,13 +25479,13 @@ function resolveRef(ref, ctx) {
|
|
|
24799
25479
|
if (!ref.startsWith("#")) {
|
|
24800
25480
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
24801
25481
|
}
|
|
24802
|
-
const
|
|
24803
|
-
if (
|
|
25482
|
+
const path12 = ref.slice(1).split("/").filter(Boolean);
|
|
25483
|
+
if (path12.length === 0) {
|
|
24804
25484
|
return ctx.rootSchema;
|
|
24805
25485
|
}
|
|
24806
25486
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
24807
|
-
if (
|
|
24808
|
-
const key =
|
|
25487
|
+
if (path12[0] === defsKey) {
|
|
25488
|
+
const key = path12[1];
|
|
24809
25489
|
if (!key || !ctx.defs[key]) {
|
|
24810
25490
|
throw new Error(`Reference not found: ${ref}`);
|
|
24811
25491
|
}
|
|
@@ -26722,6 +27402,7 @@ __export(exports_schema, {
|
|
|
26722
27402
|
user: () => user,
|
|
26723
27403
|
taskMessage: () => taskMessage,
|
|
26724
27404
|
session: () => session,
|
|
27405
|
+
nativeOauthAttempt: () => nativeOauthAttempt,
|
|
26725
27406
|
messageFlag: () => messageFlag,
|
|
26726
27407
|
message: () => message,
|
|
26727
27408
|
member: () => member,
|
|
@@ -26748,7 +27429,11 @@ __export(exports_schema, {
|
|
|
26748
27429
|
agentEmailAccount: () => agentEmailAccount,
|
|
26749
27430
|
agentAccess: () => agentAccess,
|
|
26750
27431
|
agent: () => agent,
|
|
26751
|
-
account: () => account
|
|
27432
|
+
account: () => account,
|
|
27433
|
+
NATIVE_OAUTH_STATUSES: () => NATIVE_OAUTH_STATUSES,
|
|
27434
|
+
NATIVE_OAUTH_PROVIDERS: () => NATIVE_OAUTH_PROVIDERS,
|
|
27435
|
+
NATIVE_OAUTH_PLATFORMS: () => NATIVE_OAUTH_PLATFORMS,
|
|
27436
|
+
NATIVE_OAUTH_FAILURE_CODES: () => NATIVE_OAUTH_FAILURE_CODES
|
|
26752
27437
|
});
|
|
26753
27438
|
init_nanoid();
|
|
26754
27439
|
|
|
@@ -26813,6 +27498,7 @@ var TERMINAL_MEETING_STATUSES = [
|
|
|
26813
27498
|
MeetingStatus.COMPLETED,
|
|
26814
27499
|
MeetingStatus.FAILED
|
|
26815
27500
|
];
|
|
27501
|
+
var COMMUNITY_BOT_LIMIT_PER_OWNER = 20;
|
|
26816
27502
|
var COMMUNITY_BOT_NAME_MIN = 1;
|
|
26817
27503
|
var COMMUNITY_BOT_NAME_MAX = 32;
|
|
26818
27504
|
var COMMUNITY_BOT_DESCRIPTION_MAX = 1024;
|
|
@@ -26878,6 +27564,119 @@ var verification = sqliteTable("verification", {
|
|
|
26878
27564
|
createdAt: text("createdAt").notNull().$defaultFn(() => new Date().toISOString()),
|
|
26879
27565
|
updatedAt: text("updatedAt").notNull().$defaultFn(() => new Date().toISOString())
|
|
26880
27566
|
});
|
|
27567
|
+
var NATIVE_OAUTH_PROVIDERS = ["github", "google"];
|
|
27568
|
+
var NATIVE_OAUTH_PLATFORMS = [
|
|
27569
|
+
"macos",
|
|
27570
|
+
"windows",
|
|
27571
|
+
"linux",
|
|
27572
|
+
"ios",
|
|
27573
|
+
"android"
|
|
27574
|
+
];
|
|
27575
|
+
var NATIVE_OAUTH_STATUSES = [
|
|
27576
|
+
"pending",
|
|
27577
|
+
"opened",
|
|
27578
|
+
"ready",
|
|
27579
|
+
"exchanging",
|
|
27580
|
+
"consumed",
|
|
27581
|
+
"failed",
|
|
27582
|
+
"cancelled",
|
|
27583
|
+
"replaced"
|
|
27584
|
+
];
|
|
27585
|
+
var NATIVE_OAUTH_FAILURE_CODES = [
|
|
27586
|
+
"access_denied",
|
|
27587
|
+
"provider_error",
|
|
27588
|
+
"oauth_callback_failed",
|
|
27589
|
+
"start_failed",
|
|
27590
|
+
"invalid_handoff"
|
|
27591
|
+
];
|
|
27592
|
+
var nativeOauthAttempt = sqliteTable("native_oauth_attempt", {
|
|
27593
|
+
id: text("id").primaryKey(),
|
|
27594
|
+
instanceKeyHash: text("instance_key_hash").notNull(),
|
|
27595
|
+
stateHash: text("state_hash").notNull(),
|
|
27596
|
+
pkceChallenge: text("pkce_challenge").notNull(),
|
|
27597
|
+
provider: text("provider").$type().notNull(),
|
|
27598
|
+
platform: text("platform").$type().notNull(),
|
|
27599
|
+
redirectPath: text("redirect_path").notNull(),
|
|
27600
|
+
status: text("status").$type().notNull().default("pending"),
|
|
27601
|
+
handoffCodeHash: text("handoff_code_hash"),
|
|
27602
|
+
handoffExpiresAt: integer2("handoff_expires_at"),
|
|
27603
|
+
authKind: text("auth_kind").$type(),
|
|
27604
|
+
failureCode: text("failure_code").$type(),
|
|
27605
|
+
attemptExpiresAt: integer2("attempt_expires_at").notNull(),
|
|
27606
|
+
createdAt: integer2("created_at").notNull(),
|
|
27607
|
+
updatedAt: integer2("updated_at").notNull(),
|
|
27608
|
+
openedAt: integer2("opened_at"),
|
|
27609
|
+
readyAt: integer2("ready_at"),
|
|
27610
|
+
consumedAt: integer2("consumed_at"),
|
|
27611
|
+
failedAt: integer2("failed_at"),
|
|
27612
|
+
cancelledAt: integer2("cancelled_at"),
|
|
27613
|
+
replacedAt: integer2("replaced_at")
|
|
27614
|
+
}, (t) => [
|
|
27615
|
+
index("idx_native_oauth_attempt_instance_status").on(t.instanceKeyHash, t.status),
|
|
27616
|
+
index("idx_native_oauth_attempt_id_status_expiry").on(t.id, t.status, t.attemptExpiresAt),
|
|
27617
|
+
index("idx_native_oauth_attempt_terminal_cleanup").on(t.status, t.updatedAt),
|
|
27618
|
+
uniqueIndex("uq_native_oauth_attempt_instance_live").on(t.instanceKeyHash).where(sql`status IN ('pending', 'opened', 'ready', 'exchanging')`),
|
|
27619
|
+
uniqueIndex("uq_native_oauth_attempt_handoff_hash").on(t.handoffCodeHash).where(sql`handoff_code_hash IS NOT NULL`),
|
|
27620
|
+
check2("ck_native_oauth_attempt_id", sql`length(${t.id}) BETWEEN 22 AND 64 AND ${t.id} NOT GLOB '*[^A-Za-z0-9_-]*'`),
|
|
27621
|
+
check2("ck_native_oauth_attempt_hashes", sql`length(${t.instanceKeyHash}) = 64 AND ${t.instanceKeyHash} NOT GLOB '*[^0-9a-f]*'
|
|
27622
|
+
AND length(${t.stateHash}) = 64 AND ${t.stateHash} NOT GLOB '*[^0-9a-f]*'
|
|
27623
|
+
AND length(${t.pkceChallenge}) = 43 AND ${t.pkceChallenge} NOT GLOB '*[^A-Za-z0-9_-]*'
|
|
27624
|
+
AND (${t.handoffCodeHash} IS NULL OR (length(${t.handoffCodeHash}) = 64 AND ${t.handoffCodeHash} NOT GLOB '*[^0-9a-f]*'))`),
|
|
27625
|
+
check2("ck_native_oauth_attempt_enums", sql`${t.provider} IN ('github', 'google')
|
|
27626
|
+
AND ${t.platform} IN ('macos', 'windows', 'linux', 'ios', 'android')
|
|
27627
|
+
AND ${t.status} IN ('pending', 'opened', 'ready', 'exchanging', 'consumed', 'failed', 'cancelled', 'replaced')
|
|
27628
|
+
AND (${t.authKind} IS NULL OR ${t.authKind} IN ('signin', 'signup'))
|
|
27629
|
+
AND (${t.failureCode} IS NULL OR ${t.failureCode} IN ('access_denied', 'provider_error', 'oauth_callback_failed', 'start_failed', 'invalid_handoff'))`),
|
|
27630
|
+
check2("ck_native_oauth_attempt_redirect", sql`length(${t.redirectPath}) BETWEEN 1 AND 2048
|
|
27631
|
+
AND substr(${t.redirectPath}, 1, 1) = '/'
|
|
27632
|
+
AND substr(${t.redirectPath}, 1, 2) <> '//'
|
|
27633
|
+
AND instr(${t.redirectPath}, char(92)) = 0`),
|
|
27634
|
+
check2("ck_native_oauth_attempt_epochs", sql`typeof(${t.createdAt}) = 'integer' AND ${t.createdAt} BETWEEN 0 AND 9007199254740991
|
|
27635
|
+
AND typeof(${t.updatedAt}) = 'integer' AND ${t.updatedAt} BETWEEN ${t.createdAt} AND 9007199254740991
|
|
27636
|
+
AND typeof(${t.attemptExpiresAt}) = 'integer' AND ${t.attemptExpiresAt} = ${t.createdAt} + 600000
|
|
27637
|
+
AND (${t.handoffExpiresAt} IS NULL OR (typeof(${t.handoffExpiresAt}) = 'integer' AND ${t.handoffExpiresAt} <= ${t.attemptExpiresAt}))`),
|
|
27638
|
+
check2("ck_native_oauth_attempt_state", sql`(
|
|
27639
|
+
${t.status} = 'pending'
|
|
27640
|
+
AND ${t.openedAt} IS NULL AND ${t.readyAt} IS NULL AND ${t.consumedAt} IS NULL
|
|
27641
|
+
AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
|
|
27642
|
+
AND ${t.handoffCodeHash} IS NULL AND ${t.handoffExpiresAt} IS NULL
|
|
27643
|
+
AND ${t.authKind} IS NULL AND ${t.failureCode} IS NULL
|
|
27644
|
+
) OR (
|
|
27645
|
+
${t.status} = 'opened'
|
|
27646
|
+
AND ${t.openedAt} IS NOT NULL AND ${t.readyAt} IS NULL AND ${t.consumedAt} IS NULL
|
|
27647
|
+
AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
|
|
27648
|
+
AND ${t.handoffCodeHash} IS NULL AND ${t.handoffExpiresAt} IS NULL
|
|
27649
|
+
AND ${t.authKind} IS NULL AND ${t.failureCode} IS NULL
|
|
27650
|
+
) OR (
|
|
27651
|
+
${t.status} IN ('ready', 'exchanging')
|
|
27652
|
+
AND ${t.openedAt} IS NOT NULL AND ${t.readyAt} IS NOT NULL AND ${t.consumedAt} IS NULL
|
|
27653
|
+
AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
|
|
27654
|
+
AND ${t.handoffCodeHash} IS NOT NULL AND ${t.handoffExpiresAt} IS NOT NULL
|
|
27655
|
+
AND ${t.handoffExpiresAt} = ${t.readyAt} + 120000
|
|
27656
|
+
AND ${t.authKind} IS NOT NULL AND ${t.failureCode} IS NULL
|
|
27657
|
+
) OR (
|
|
27658
|
+
${t.status} = 'consumed'
|
|
27659
|
+
AND ${t.openedAt} IS NOT NULL AND ${t.readyAt} IS NOT NULL AND ${t.consumedAt} IS NOT NULL
|
|
27660
|
+
AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
|
|
27661
|
+
AND ${t.handoffCodeHash} IS NOT NULL AND ${t.handoffExpiresAt} IS NOT NULL
|
|
27662
|
+
AND ${t.authKind} IS NOT NULL AND ${t.failureCode} IS NULL
|
|
27663
|
+
) OR (
|
|
27664
|
+
${t.status} = 'failed'
|
|
27665
|
+
AND ${t.consumedAt} IS NULL AND ${t.failedAt} IS NOT NULL
|
|
27666
|
+
AND ${t.cancelledAt} IS NULL AND ${t.replacedAt} IS NULL
|
|
27667
|
+
AND ${t.failureCode} IS NOT NULL
|
|
27668
|
+
) OR (
|
|
27669
|
+
${t.status} = 'cancelled'
|
|
27670
|
+
AND ${t.consumedAt} IS NULL AND ${t.cancelledAt} IS NOT NULL
|
|
27671
|
+
AND ${t.failedAt} IS NULL AND ${t.replacedAt} IS NULL
|
|
27672
|
+
AND ${t.failureCode} IS NULL
|
|
27673
|
+
) OR (
|
|
27674
|
+
${t.status} = 'replaced'
|
|
27675
|
+
AND ${t.consumedAt} IS NULL AND ${t.replacedAt} IS NOT NULL
|
|
27676
|
+
AND ${t.failedAt} IS NULL AND ${t.cancelledAt} IS NULL
|
|
27677
|
+
AND ${t.failureCode} IS NULL
|
|
27678
|
+
)`)
|
|
27679
|
+
]);
|
|
26881
27680
|
var workspace = sqliteTable("workspace", {
|
|
26882
27681
|
id: text("id").primaryKey().$defaultFn(() => "sp_" + nanoid3()),
|
|
26883
27682
|
name: text("name").notNull(),
|
|
@@ -27687,6 +28486,13 @@ var HostCommandSchema = exports_external.discriminatedUnion("type", [
|
|
|
27687
28486
|
launchId: exports_external.string().min(1),
|
|
27688
28487
|
unreadNotice: exports_external.unknown()
|
|
27689
28488
|
}),
|
|
28489
|
+
exports_external.object({
|
|
28490
|
+
type: exports_external.literal("agent:event"),
|
|
28491
|
+
agentId: exports_external.string().min(1),
|
|
28492
|
+
config: exports_external.unknown(),
|
|
28493
|
+
launchId: exports_external.string().min(1),
|
|
28494
|
+
prompt: exports_external.string().min(1).max(32768)
|
|
28495
|
+
}),
|
|
27690
28496
|
exports_external.object({
|
|
27691
28497
|
type: exports_external.literal("agent:stop"),
|
|
27692
28498
|
agentId: exports_external.string().min(1)
|
|
@@ -28038,6 +28844,26 @@ class AgentRouter {
|
|
|
28038
28844
|
return;
|
|
28039
28845
|
}
|
|
28040
28846
|
break;
|
|
28847
|
+
case "agent:event":
|
|
28848
|
+
this.log.info("agent:event received", { agentId: cmd.agentId });
|
|
28849
|
+
try {
|
|
28850
|
+
await this.opts.onBeforeAgent?.(cmd.agentId);
|
|
28851
|
+
this.opts.manager.register(cmd.agentId, {
|
|
28852
|
+
runtimeConfig: cmd.config,
|
|
28853
|
+
launchId: cmd.launchId
|
|
28854
|
+
});
|
|
28855
|
+
this.running.add(cmd.agentId);
|
|
28856
|
+
this.opts.manager.deliver(cmd.agentId, {
|
|
28857
|
+
id: `${cmd.agentId}:event:${cmd.launchId}`,
|
|
28858
|
+
text: cmd.prompt
|
|
28859
|
+
});
|
|
28860
|
+
} catch (err) {
|
|
28861
|
+
this.log.warn("agent:event failed", {
|
|
28862
|
+
agentId: cmd.agentId,
|
|
28863
|
+
err: err instanceof Error ? err.message : String(err)
|
|
28864
|
+
});
|
|
28865
|
+
}
|
|
28866
|
+
break;
|
|
28041
28867
|
case "agent:reset":
|
|
28042
28868
|
await this.runRestartCommand(cmd.agentId, cmd.launchId, "agent:reset", () => this.opts.manager.resetSession(cmd.agentId, {
|
|
28043
28869
|
runtimeConfig: cmd.config,
|
|
@@ -28155,7 +28981,7 @@ import * as fs5 from "fs";
|
|
|
28155
28981
|
import * as http from "http";
|
|
28156
28982
|
import * as https from "https";
|
|
28157
28983
|
import * as os2 from "os";
|
|
28158
|
-
import * as
|
|
28984
|
+
import * as path12 from "path";
|
|
28159
28985
|
import { URL as URL2 } from "url";
|
|
28160
28986
|
var LOCAL_MESSAGE_REMINDER_PATH = "/__alook/local/message-reminder";
|
|
28161
28987
|
var LOCAL_MESSAGE_REMINDER_BODY_MAX_BYTES = 4 * 1024;
|
|
@@ -28187,15 +29013,15 @@ class CredentialBroker {
|
|
|
28187
29013
|
this.voucherPrefix = config2.voucherPrefix ?? "vch_";
|
|
28188
29014
|
this.clientLabel = config2.clientLabel ?? "cli";
|
|
28189
29015
|
this.headerNames = config2.headerNames ?? DEFAULT_HEADER_NAMES;
|
|
28190
|
-
this.voucherDir = config2.voucherDir ??
|
|
29016
|
+
this.voucherDir = config2.voucherDir ?? path12.join(os2.tmpdir(), "agent-vouchers");
|
|
28191
29017
|
}
|
|
28192
29018
|
mint(agentId, launchId, capabilities2, runnerKey) {
|
|
28193
29019
|
if (!runnerKey)
|
|
28194
29020
|
throw new Error("CredentialBroker.mint: runnerKey is required (per-agent tier-2 credential)");
|
|
28195
29021
|
const voucher = randomVoucher(this.voucherPrefix);
|
|
28196
|
-
const dir =
|
|
29022
|
+
const dir = path12.join(this.voucherDir, sanitizeIdSegment(agentId));
|
|
28197
29023
|
fs5.mkdirSync(dir, { recursive: true });
|
|
28198
|
-
const voucherFile =
|
|
29024
|
+
const voucherFile = path12.join(dir, `${sanitizeIdSegment(launchId)}.token`);
|
|
28199
29025
|
fs5.writeFileSync(voucherFile, voucher, { mode: 384 });
|
|
28200
29026
|
this.registrations.set(voucher, {
|
|
28201
29027
|
agentId,
|
|
@@ -28392,12 +29218,20 @@ async function startCredentialProxy(broker, options = {}) {
|
|
|
28392
29218
|
const upstream = new URL2(broker.upstreamBaseUrl);
|
|
28393
29219
|
const upstreamClient = upstream.protocol === "https:" ? https : http;
|
|
28394
29220
|
const onPull = options.onInboxPullResponse;
|
|
29221
|
+
const onAck = options.onInboxAckResponse;
|
|
28395
29222
|
const onProxyRequest = options.onProxyRequest;
|
|
28396
29223
|
const reportInboxPullObservationError = (failure) => {
|
|
28397
29224
|
try {
|
|
28398
29225
|
options.onInboxPullObservationError?.(failure);
|
|
28399
29226
|
} catch {}
|
|
28400
29227
|
};
|
|
29228
|
+
const reportInboxAckObservationError = (failure) => {
|
|
29229
|
+
try {
|
|
29230
|
+
options.onInboxAckObservationError?.(failure);
|
|
29231
|
+
} catch {
|
|
29232
|
+
return;
|
|
29233
|
+
}
|
|
29234
|
+
};
|
|
28401
29235
|
const server = http.createServer((req, res) => {
|
|
28402
29236
|
const pathname = new URL2(req.url ?? "/", "http://placeholder").pathname;
|
|
28403
29237
|
if (pathname.startsWith("/__alook/local/")) {
|
|
@@ -28437,8 +29271,11 @@ async function startCredentialProxy(broker, options = {}) {
|
|
|
28437
29271
|
}
|
|
28438
29272
|
const reg = verdict.reg;
|
|
28439
29273
|
const isInboxPull = req.method === "POST" && pathname === "/api/community/users/me/inbox/pull";
|
|
29274
|
+
const isInboxAck = req.method === "POST" && pathname === "/api/community/users/me/inbox/ack";
|
|
28440
29275
|
const shouldObserveInboxPull = Boolean(isInboxPull && onPull);
|
|
29276
|
+
const shouldObserveInboxAck = Boolean(isInboxAck && onAck);
|
|
28441
29277
|
let inboxPullObservationToken;
|
|
29278
|
+
let inboxAckObservationToken;
|
|
28442
29279
|
if (shouldObserveInboxPull) {
|
|
28443
29280
|
try {
|
|
28444
29281
|
inboxPullObservationToken = options.onInboxPullStart?.(reg.agentId);
|
|
@@ -28450,6 +29287,17 @@ async function startCredentialProxy(broker, options = {}) {
|
|
|
28450
29287
|
});
|
|
28451
29288
|
}
|
|
28452
29289
|
}
|
|
29290
|
+
if (shouldObserveInboxAck) {
|
|
29291
|
+
try {
|
|
29292
|
+
inboxAckObservationToken = options.onInboxAckStart?.(reg.agentId);
|
|
29293
|
+
} catch {
|
|
29294
|
+
reportInboxAckObservationError({
|
|
29295
|
+
agentId: reg.agentId,
|
|
29296
|
+
reason: "observer_failed",
|
|
29297
|
+
contentEncoding: "identity"
|
|
29298
|
+
});
|
|
29299
|
+
}
|
|
29300
|
+
}
|
|
28453
29301
|
if (onProxyRequest) {
|
|
28454
29302
|
try {
|
|
28455
29303
|
const method = req.method ?? "GET";
|
|
@@ -28467,7 +29315,7 @@ async function startCredentialProxy(broker, options = {}) {
|
|
|
28467
29315
|
outHeaders[broker.headerNames.agentId.toLowerCase()] = reg.agentId;
|
|
28468
29316
|
outHeaders[broker.headerNames.client.toLowerCase()] = broker.clientLabel;
|
|
28469
29317
|
outHeaders[broker.headerNames.capabilities.toLowerCase()] = [...reg.capabilities].join(",");
|
|
28470
|
-
if (isInboxPull)
|
|
29318
|
+
if (isInboxPull || isInboxAck)
|
|
28471
29319
|
outHeaders["accept-encoding"] = "identity";
|
|
28472
29320
|
let responded = false;
|
|
28473
29321
|
let upstreamRes;
|
|
@@ -28487,43 +29335,72 @@ async function startCredentialProxy(broker, options = {}) {
|
|
|
28487
29335
|
};
|
|
28488
29336
|
res_.on("error", destroyResIfIncomplete);
|
|
28489
29337
|
res_.on("close", destroyResIfIncomplete);
|
|
28490
|
-
if (shouldObserveInboxPull && res_.statusCode !== undefined && res_.statusCode >= 200 && res_.statusCode < 300) {
|
|
29338
|
+
if ((shouldObserveInboxPull || shouldObserveInboxAck) && res_.statusCode !== undefined && res_.statusCode >= 200 && res_.statusCode < 300) {
|
|
28491
29339
|
const chunks = [];
|
|
28492
29340
|
res_.on("data", (chunk) => chunks.push(chunk));
|
|
28493
29341
|
res_.on("end", () => {
|
|
28494
29342
|
const body = Buffer.concat(chunks);
|
|
28495
29343
|
const contentEncoding = normalizeContentEncoding(res_.headers["content-encoding"]);
|
|
28496
29344
|
if (contentEncoding !== "identity") {
|
|
28497
|
-
|
|
28498
|
-
|
|
28499
|
-
|
|
28500
|
-
|
|
28501
|
-
|
|
29345
|
+
if (shouldObserveInboxPull) {
|
|
29346
|
+
reportInboxPullObservationError({
|
|
29347
|
+
agentId: reg.agentId,
|
|
29348
|
+
reason: "unexpected_content_encoding",
|
|
29349
|
+
contentEncoding
|
|
29350
|
+
});
|
|
29351
|
+
} else {
|
|
29352
|
+
reportInboxAckObservationError({
|
|
29353
|
+
agentId: reg.agentId,
|
|
29354
|
+
reason: "unexpected_content_encoding",
|
|
29355
|
+
contentEncoding
|
|
29356
|
+
});
|
|
29357
|
+
}
|
|
28502
29358
|
} else {
|
|
28503
29359
|
let parsed;
|
|
28504
29360
|
try {
|
|
28505
29361
|
parsed = JSON.parse(body.toString("utf8"));
|
|
28506
29362
|
} catch {
|
|
28507
|
-
|
|
28508
|
-
agentId: reg.agentId,
|
|
28509
|
-
|
|
28510
|
-
contentEncoding
|
|
28511
|
-
}
|
|
29363
|
+
if (shouldObserveInboxPull) {
|
|
29364
|
+
reportInboxPullObservationError({ agentId: reg.agentId, reason: "invalid_json", contentEncoding });
|
|
29365
|
+
} else {
|
|
29366
|
+
reportInboxAckObservationError({ agentId: reg.agentId, reason: "invalid_json", contentEncoding });
|
|
29367
|
+
}
|
|
28512
29368
|
}
|
|
28513
29369
|
if (parsed !== undefined) {
|
|
28514
|
-
if (
|
|
28515
|
-
|
|
29370
|
+
if (shouldObserveInboxPull) {
|
|
29371
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed) || !Array.isArray(parsed.messages)) {
|
|
29372
|
+
reportInboxPullObservationError({
|
|
29373
|
+
agentId: reg.agentId,
|
|
29374
|
+
reason: "invalid_inbox_shape",
|
|
29375
|
+
contentEncoding
|
|
29376
|
+
});
|
|
29377
|
+
} else {
|
|
29378
|
+
const messages = parsed.messages;
|
|
29379
|
+
if (messages.length > 0) {
|
|
29380
|
+
try {
|
|
29381
|
+
onPull(reg.agentId, messages, inboxPullObservationToken);
|
|
29382
|
+
} catch {
|
|
29383
|
+
reportInboxPullObservationError({
|
|
29384
|
+
agentId: reg.agentId,
|
|
29385
|
+
reason: "observer_failed",
|
|
29386
|
+
contentEncoding
|
|
29387
|
+
});
|
|
29388
|
+
}
|
|
29389
|
+
}
|
|
29390
|
+
}
|
|
29391
|
+
} else if (!parsed || typeof parsed !== "object" || Array.isArray(parsed) || !Array.isArray(parsed.applied) || !parsed.applied.every((cursor) => Boolean(cursor) && typeof cursor === "object" && !Array.isArray(cursor) && typeof cursor.channel === "string" && cursor.channel.length > 0 && typeof cursor.seq === "number" && Number.isSafeInteger(cursor.seq) && cursor.seq > 0)) {
|
|
29392
|
+
reportInboxAckObservationError({
|
|
28516
29393
|
agentId: reg.agentId,
|
|
28517
|
-
reason: "
|
|
29394
|
+
reason: "invalid_ack_shape",
|
|
28518
29395
|
contentEncoding
|
|
28519
29396
|
});
|
|
28520
29397
|
} else {
|
|
28521
|
-
const
|
|
28522
|
-
if (
|
|
29398
|
+
const applied = parsed.applied;
|
|
29399
|
+
if (applied.length > 0) {
|
|
28523
29400
|
try {
|
|
28524
|
-
|
|
29401
|
+
onAck(reg.agentId, applied, inboxAckObservationToken);
|
|
28525
29402
|
} catch {
|
|
28526
|
-
|
|
29403
|
+
reportInboxAckObservationError({
|
|
28527
29404
|
agentId: reg.agentId,
|
|
28528
29405
|
reason: "observer_failed",
|
|
28529
29406
|
contentEncoding
|
|
@@ -28590,7 +29467,7 @@ function joinPath(basePath, reqUrl) {
|
|
|
28590
29467
|
return base + reqPath || "/";
|
|
28591
29468
|
}
|
|
28592
29469
|
// src/daemon/createDaemon.ts
|
|
28593
|
-
import { homedir as
|
|
29470
|
+
import { homedir as homedir7 } from "os";
|
|
28594
29471
|
import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync7 } from "node:fs";
|
|
28595
29472
|
|
|
28596
29473
|
// src/util/rotatingFileSink.ts
|
|
@@ -28607,7 +29484,7 @@ import {
|
|
|
28607
29484
|
statSync,
|
|
28608
29485
|
unlinkSync as unlinkSync3
|
|
28609
29486
|
} from "node:fs";
|
|
28610
|
-
function createRotatingFileSink(
|
|
29487
|
+
function createRotatingFileSink(path13, maxBytes, opts = {}) {
|
|
28611
29488
|
const report = (operation, error51) => {
|
|
28612
29489
|
try {
|
|
28613
29490
|
opts.onError?.({ operation, error: error51 });
|
|
@@ -28617,8 +29494,8 @@ function createRotatingFileSink(path9, maxBytes, opts = {}) {
|
|
|
28617
29494
|
if (!existsSync5(filePath))
|
|
28618
29495
|
return true;
|
|
28619
29496
|
try {
|
|
28620
|
-
const
|
|
28621
|
-
if (!
|
|
29497
|
+
const stat2 = lstatSync2(filePath);
|
|
29498
|
+
if (!stat2.isFile()) {
|
|
28622
29499
|
if (opts.mode === undefined && !opts.hardMaxBytes)
|
|
28623
29500
|
return true;
|
|
28624
29501
|
report("unsafe_generation", new Error("log generation is not a regular file"));
|
|
@@ -28626,7 +29503,7 @@ function createRotatingFileSink(path9, maxBytes, opts = {}) {
|
|
|
28626
29503
|
}
|
|
28627
29504
|
if (opts.mode !== undefined)
|
|
28628
29505
|
chmodSync(filePath, opts.mode);
|
|
28629
|
-
if (opts.hardMaxBytes && maxBytes > 0 &&
|
|
29506
|
+
if (opts.hardMaxBytes && maxBytes > 0 && stat2.size > maxBytes) {
|
|
28630
29507
|
try {
|
|
28631
29508
|
unlinkSync3(filePath);
|
|
28632
29509
|
} catch (error51) {
|
|
@@ -28643,9 +29520,9 @@ function createRotatingFileSink(path9, maxBytes, opts = {}) {
|
|
|
28643
29520
|
};
|
|
28644
29521
|
const rotate = () => {
|
|
28645
29522
|
try {
|
|
28646
|
-
renameSync(
|
|
29523
|
+
renameSync(path13, `${path13}.1`);
|
|
28647
29524
|
if (opts.mode !== undefined)
|
|
28648
|
-
chmodSync(`${
|
|
29525
|
+
chmodSync(`${path13}.1`, opts.mode);
|
|
28649
29526
|
return true;
|
|
28650
29527
|
} catch (error51) {
|
|
28651
29528
|
report("rotate", error51);
|
|
@@ -28654,7 +29531,7 @@ function createRotatingFileSink(path9, maxBytes, opts = {}) {
|
|
|
28654
29531
|
};
|
|
28655
29532
|
const currentSize = () => {
|
|
28656
29533
|
try {
|
|
28657
|
-
return existsSync5(
|
|
29534
|
+
return existsSync5(path13) ? statSync(path13).size : 0;
|
|
28658
29535
|
} catch (error51) {
|
|
28659
29536
|
report("stat", error51);
|
|
28660
29537
|
return null;
|
|
@@ -28662,7 +29539,7 @@ function createRotatingFileSink(path9, maxBytes, opts = {}) {
|
|
|
28662
29539
|
};
|
|
28663
29540
|
const sink = {
|
|
28664
29541
|
secure() {
|
|
28665
|
-
return secureGeneration(`${
|
|
29542
|
+
return secureGeneration(`${path13}.1`) && secureGeneration(path13);
|
|
28666
29543
|
},
|
|
28667
29544
|
write(line) {
|
|
28668
29545
|
try {
|
|
@@ -28682,7 +29559,7 @@ function createRotatingFileSink(path9, maxBytes, opts = {}) {
|
|
|
28682
29559
|
const shouldRotate = maxBytes > 0 && (opts.hardMaxBytes ? currentBytes > 0 && currentBytes + serializedBytes > maxBytes : currentBytes >= maxBytes);
|
|
28683
29560
|
if (shouldRotate && !rotate() && opts.hardMaxBytes)
|
|
28684
29561
|
return;
|
|
28685
|
-
appendFileSync(
|
|
29562
|
+
appendFileSync(path13, serialized, opts.mode === undefined ? undefined : { mode: opts.mode });
|
|
28686
29563
|
} catch (error51) {
|
|
28687
29564
|
report("append", error51);
|
|
28688
29565
|
}
|
|
@@ -28690,7 +29567,7 @@ function createRotatingFileSink(path9, maxBytes, opts = {}) {
|
|
|
28690
29567
|
openSnapshot() {
|
|
28691
29568
|
const files = [];
|
|
28692
29569
|
try {
|
|
28693
|
-
for (const candidate of [`${
|
|
29570
|
+
for (const candidate of [`${path13}.1`, path13]) {
|
|
28694
29571
|
if (!existsSync5(candidate))
|
|
28695
29572
|
continue;
|
|
28696
29573
|
if (!secureGeneration(candidate))
|
|
@@ -28698,10 +29575,10 @@ function createRotatingFileSink(path9, maxBytes, opts = {}) {
|
|
|
28698
29575
|
const noFollow = "O_NOFOLLOW" in constants ? constants.O_NOFOLLOW : 0;
|
|
28699
29576
|
const fd = openSync(candidate, constants.O_RDONLY | noFollow);
|
|
28700
29577
|
try {
|
|
28701
|
-
const
|
|
28702
|
-
if (!
|
|
29578
|
+
const stat2 = fstatSync(fd);
|
|
29579
|
+
if (!stat2.isFile())
|
|
28703
29580
|
throw new Error("snapshot source is not a regular file");
|
|
28704
|
-
files.push({ path: candidate, fd, size:
|
|
29581
|
+
files.push({ path: candidate, fd, size: stat2.size });
|
|
28705
29582
|
} catch (error51) {
|
|
28706
29583
|
closeSync(fd);
|
|
28707
29584
|
throw error51;
|
|
@@ -28851,11 +29728,11 @@ function createTraceSampler(emit, throttleMs = DEFAULT_TRACE_SAMPLE_MS) {
|
|
|
28851
29728
|
|
|
28852
29729
|
// src/util/statusFile.ts
|
|
28853
29730
|
import { writeFileSync as writeFileSync4, renameSync as renameSync2 } from "node:fs";
|
|
28854
|
-
function writeStatusFile(
|
|
29731
|
+
function writeStatusFile(path13, snapshot) {
|
|
28855
29732
|
try {
|
|
28856
|
-
const tmp = `${
|
|
29733
|
+
const tmp = `${path13}.tmp`;
|
|
28857
29734
|
writeFileSync4(tmp, JSON.stringify(snapshot));
|
|
28858
|
-
renameSync2(tmp,
|
|
29735
|
+
renameSync2(tmp, path13);
|
|
28859
29736
|
} catch {}
|
|
28860
29737
|
}
|
|
28861
29738
|
// ../shared/src/constants/community.ts
|
|
@@ -29699,6 +30576,10 @@ var CommunityBotPatchRequestSchema = exports_external.object({
|
|
|
29699
30576
|
var CommunityBotAddToServerRequestSchema = exports_external.object({
|
|
29700
30577
|
botId: exports_external.string().min(1)
|
|
29701
30578
|
});
|
|
30579
|
+
var CommunityServerOnboardRequestSchema = exports_external.strictObject({
|
|
30580
|
+
botIds: exports_external.array(exports_external.string().min(1).max(128)).min(1).max(COMMUNITY_BOT_LIMIT_PER_OWNER).refine((ids) => new Set(ids).size === ids.length, "botIds must be unique"),
|
|
30581
|
+
wakePrompt: exports_external.string().max(32768).refine((value) => value.trim().length > 0, "wakePrompt is required")
|
|
30582
|
+
});
|
|
29702
30583
|
var CommunityAgentMessageContentSchema = exports_external.object({ text: exports_external.string().max(MAX_MESSAGE_CONTENT_LENGTH).default("") }).catchall(exports_external.unknown());
|
|
29703
30584
|
var CommunityAgentSeqSchema = exports_external.number().int().min(0);
|
|
29704
30585
|
var CommunityAgentPositiveSeqSchema = exports_external.number().int().min(1);
|
|
@@ -30302,6 +31183,15 @@ function createLogger2(opts) {
|
|
|
30302
31183
|
|
|
30303
31184
|
// ../shared/src/db/queries/_chunk.ts
|
|
30304
31185
|
var D1_MAX_BIND_PARAMS = 100;
|
|
31186
|
+
function maxInParams(fixedParams) {
|
|
31187
|
+
if (!Number.isInteger(fixedParams) || fixedParams < 0) {
|
|
31188
|
+
throw new Error("fixed params must be a non-negative integer");
|
|
31189
|
+
}
|
|
31190
|
+
if (fixedParams >= D1_MAX_BIND_PARAMS) {
|
|
31191
|
+
throw new Error("fixed params must leave room for at least one IN parameter");
|
|
31192
|
+
}
|
|
31193
|
+
return D1_MAX_BIND_PARAMS - fixedParams;
|
|
31194
|
+
}
|
|
30305
31195
|
function maxRowsPerInsert(paramsPerRow) {
|
|
30306
31196
|
if (paramsPerRow < 1)
|
|
30307
31197
|
throw new Error("paramsPerRow must be >= 1");
|
|
@@ -30393,6 +31283,7 @@ var AGENT_MESSAGE_COLUMNS = {
|
|
|
30393
31283
|
replyToId: communityMessage.replyToId
|
|
30394
31284
|
};
|
|
30395
31285
|
var channelJoinBaselineGuard = sql`${communityMessage.createdAt} > COALESCE(${communityChannelMember.addedAt}, ${communityServerMember.joinedAt}, '')`;
|
|
31286
|
+
var AGENT_UNREAD_CHANNEL_CHUNK_SIZE = maxInParams(13);
|
|
30396
31287
|
|
|
30397
31288
|
// ../shared/src/db/queries/community/mention.ts
|
|
30398
31289
|
var MENTION_INSERT_MAX_ROWS = maxRowsPerInsert(5);
|
|
@@ -31005,6 +31896,10 @@ var serverRailCommandSchema = exports_external.discriminatedUnion("kind", [
|
|
|
31005
31896
|
var serverRailCommitRequestSchema = exports_external.strictObject({
|
|
31006
31897
|
commands: exports_external.array(serverRailCommandSchema).min(1).max(MAX_SERVER_RAIL_COMMANDS)
|
|
31007
31898
|
});
|
|
31899
|
+
// ../shared/src/db/queries/native-oauth.ts
|
|
31900
|
+
var ATTEMPT_TTL_MS = 10 * 60 * 1000;
|
|
31901
|
+
var HANDOFF_TTL_MS = 2 * 60 * 1000;
|
|
31902
|
+
var RETENTION_MS = 24 * 60 * 60 * 1000;
|
|
31008
31903
|
// ../shared/src/db/queries/task.ts
|
|
31009
31904
|
var DEFAULT_STALE_SECONDS = Number(process.env.ALOOK_STALE_DISPATCH_TIMEOUT_S) || 20;
|
|
31010
31905
|
var DEFAULT_STALE_RUNNING_SECONDS = Number(process.env.ALOOK_STALE_RUNNING_TIMEOUT_S) || 3600;
|
|
@@ -31033,6 +31928,80 @@ var FTS_KEYWORDS = new Set(["and", "or", "not", "near"]);
|
|
|
31033
31928
|
var FOLDER_ITEM_INSERT_MAX_ROWS = maxRowsPerInsert(3);
|
|
31034
31929
|
// ../shared/src/db/queries/community/diagnostic-report.ts
|
|
31035
31930
|
var diagnosticOwner = alias(user, "diagnostic_owner");
|
|
31931
|
+
// ../shared/src/lib/safe-redirect.ts
|
|
31932
|
+
var MAX_REDIRECT_BYTES = 2048;
|
|
31933
|
+
var CONTROL_CHARACTERS = /[\u0000-\u001f\u007f]/;
|
|
31934
|
+
function isSafeCandidate(value) {
|
|
31935
|
+
return value.startsWith("/") && !value.startsWith("//") && !value.includes("\\") && !value.includes("#") && !CONTROL_CHARACTERS.test(value);
|
|
31936
|
+
}
|
|
31937
|
+
function isSafeRedirectPath(value) {
|
|
31938
|
+
if (new TextEncoder().encode(value).byteLength > MAX_REDIRECT_BYTES)
|
|
31939
|
+
return false;
|
|
31940
|
+
if (!isSafeCandidate(value))
|
|
31941
|
+
return false;
|
|
31942
|
+
let decoded = value;
|
|
31943
|
+
for (let depth = 0;depth < 8; depth += 1) {
|
|
31944
|
+
let next;
|
|
31945
|
+
try {
|
|
31946
|
+
next = decodeURIComponent(decoded);
|
|
31947
|
+
} catch {
|
|
31948
|
+
return depth > 0;
|
|
31949
|
+
}
|
|
31950
|
+
if (next === decoded)
|
|
31951
|
+
break;
|
|
31952
|
+
if (!isSafeCandidate(next))
|
|
31953
|
+
return false;
|
|
31954
|
+
decoded = next;
|
|
31955
|
+
if (depth === 7)
|
|
31956
|
+
return false;
|
|
31957
|
+
}
|
|
31958
|
+
try {
|
|
31959
|
+
const base = new URL("https://alook.invalid");
|
|
31960
|
+
const resolved = new URL(value, base);
|
|
31961
|
+
return resolved.origin === base.origin;
|
|
31962
|
+
} catch {
|
|
31963
|
+
return false;
|
|
31964
|
+
}
|
|
31965
|
+
}
|
|
31966
|
+
|
|
31967
|
+
// ../shared/src/lib/native-oauth-contract.ts
|
|
31968
|
+
var ATTEMPT_ID = /^[A-Za-z0-9_-]{22,64}$/;
|
|
31969
|
+
var SHA256_HEX = /^[0-9a-f]{64}$/;
|
|
31970
|
+
var BASE64URL_32_BYTES = /^[A-Za-z0-9_-]{43}$/;
|
|
31971
|
+
var HANDOFF_CODE = /^[A-Za-z0-9_-]{32,128}$/;
|
|
31972
|
+
var nativeOauthProviderSchema = exports_external.enum(["github", "google"]);
|
|
31973
|
+
var nativeOauthPlatformSchema = exports_external.enum([
|
|
31974
|
+
"macos",
|
|
31975
|
+
"windows",
|
|
31976
|
+
"linux",
|
|
31977
|
+
"ios",
|
|
31978
|
+
"android"
|
|
31979
|
+
]);
|
|
31980
|
+
var nativeOauthAttemptIdSchema = exports_external.string().regex(ATTEMPT_ID);
|
|
31981
|
+
var nativeOauthHandoffCodeSchema = exports_external.string().regex(HANDOFF_CODE);
|
|
31982
|
+
var nativeOauthFailureCodeSchema = exports_external.enum([
|
|
31983
|
+
"access_denied",
|
|
31984
|
+
"provider_error",
|
|
31985
|
+
"oauth_callback_failed",
|
|
31986
|
+
"start_failed",
|
|
31987
|
+
"invalid_handoff"
|
|
31988
|
+
]);
|
|
31989
|
+
var nativeOauthRegistrationSchema = exports_external.object({
|
|
31990
|
+
attemptId: nativeOauthAttemptIdSchema,
|
|
31991
|
+
stateHash: exports_external.string().regex(SHA256_HEX),
|
|
31992
|
+
codeChallenge: exports_external.string().regex(BASE64URL_32_BYTES),
|
|
31993
|
+
instanceKeyHash: exports_external.string().regex(SHA256_HEX),
|
|
31994
|
+
platform: nativeOauthPlatformSchema,
|
|
31995
|
+
provider: nativeOauthProviderSchema,
|
|
31996
|
+
redirectPath: exports_external.string().refine(isSafeRedirectPath)
|
|
31997
|
+
}).strict();
|
|
31998
|
+
var nativeOauthExchangeSchema = exports_external.object({
|
|
31999
|
+
attemptId: nativeOauthAttemptIdSchema,
|
|
32000
|
+
state: exports_external.string().regex(BASE64URL_32_BYTES),
|
|
32001
|
+
verifier: exports_external.string().regex(BASE64URL_32_BYTES),
|
|
32002
|
+
code: nativeOauthHandoffCodeSchema
|
|
32003
|
+
}).strict();
|
|
32004
|
+
var nativeOauthProofSchema = nativeOauthExchangeSchema.omit({ code: true }).strict();
|
|
31036
32005
|
// src/manager/wakeCoordinator.ts
|
|
31037
32006
|
class WakeCoordinator {
|
|
31038
32007
|
agents = new Map;
|
|
@@ -31823,11 +32792,11 @@ function timelineRowHash(line) {
|
|
|
31823
32792
|
}
|
|
31824
32793
|
function timelineFileGeneration(filePath, lines) {
|
|
31825
32794
|
try {
|
|
31826
|
-
const
|
|
31827
|
-
if (!
|
|
32795
|
+
const stat2 = fs7.lstatSync(filePath, { bigint: true });
|
|
32796
|
+
if (!stat2.isFile())
|
|
31828
32797
|
return null;
|
|
31829
32798
|
const digest = createHash4("sha256");
|
|
31830
|
-
digest.update(`${
|
|
32799
|
+
digest.update(`${stat2.dev}:${stat2.ino}:${stat2.size}:${stat2.mtimeNs}:${stat2.ctimeNs}
|
|
31831
32800
|
`);
|
|
31832
32801
|
for (const line of lines)
|
|
31833
32802
|
digest.update(line.text, "utf8").update(`
|
|
@@ -31885,9 +32854,9 @@ function compactLines(input) {
|
|
|
31885
32854
|
}
|
|
31886
32855
|
return suffix;
|
|
31887
32856
|
}
|
|
31888
|
-
function isRealDirectory(
|
|
32857
|
+
function isRealDirectory(path13) {
|
|
31889
32858
|
try {
|
|
31890
|
-
return fs7.lstatSync(
|
|
32859
|
+
return fs7.lstatSync(path13).isDirectory();
|
|
31891
32860
|
} catch {
|
|
31892
32861
|
return false;
|
|
31893
32862
|
}
|
|
@@ -31927,8 +32896,8 @@ function scanTimelineFile(filePath) {
|
|
|
31927
32896
|
let fd = null;
|
|
31928
32897
|
try {
|
|
31929
32898
|
fd = fs7.openSync(filePath, fs7.constants.O_RDONLY | (fs7.constants.O_NOFOLLOW ?? 0));
|
|
31930
|
-
const
|
|
31931
|
-
if (!
|
|
32899
|
+
const stat2 = fs7.fstatSync(fd);
|
|
32900
|
+
if (!stat2.isFile())
|
|
31932
32901
|
return null;
|
|
31933
32902
|
const chunk2 = Buffer.allocUnsafe(TIMELINE_READ_CHUNK_BYTES);
|
|
31934
32903
|
const newest = [];
|
|
@@ -31941,9 +32910,9 @@ function scanTimelineFile(filePath) {
|
|
|
31941
32910
|
let oversized = false;
|
|
31942
32911
|
let stop = false;
|
|
31943
32912
|
let discardIncompleteTail = false;
|
|
31944
|
-
if (
|
|
32913
|
+
if (stat2.size > 0) {
|
|
31945
32914
|
const last = Buffer.allocUnsafe(1);
|
|
31946
|
-
fs7.readSync(fd, last, 0, 1,
|
|
32915
|
+
fs7.readSync(fd, last, 0, 1, stat2.size - 1);
|
|
31947
32916
|
discardIncompleteTail = last[0] !== 10;
|
|
31948
32917
|
}
|
|
31949
32918
|
const resetPhysicalLine = () => {
|
|
@@ -32002,7 +32971,7 @@ function scanTimelineFile(filePath) {
|
|
|
32002
32971
|
}
|
|
32003
32972
|
resetPhysicalLine();
|
|
32004
32973
|
};
|
|
32005
|
-
let position =
|
|
32974
|
+
let position = stat2.size;
|
|
32006
32975
|
while (position > 0 && !stop) {
|
|
32007
32976
|
const start = Math.max(0, position - chunk2.length);
|
|
32008
32977
|
const requested = position - start;
|
|
@@ -32154,11 +33123,11 @@ function readResumeControlState(timelineDir) {
|
|
|
32154
33123
|
let fd = null;
|
|
32155
33124
|
try {
|
|
32156
33125
|
fd = fs7.openSync(filePath, fs7.constants.O_RDONLY | (fs7.constants.O_NOFOLLOW ?? 0));
|
|
32157
|
-
const
|
|
32158
|
-
if (!
|
|
33126
|
+
const stat2 = fs7.fstatSync(fd);
|
|
33127
|
+
if (!stat2.isFile() || stat2.size <= 0 || stat2.size > RESUME_CONTROL_MAX_BYTES) {
|
|
32159
33128
|
return { kind: "invalid" };
|
|
32160
33129
|
}
|
|
32161
|
-
const bounded = Buffer.allocUnsafe(
|
|
33130
|
+
const bounded = Buffer.allocUnsafe(stat2.size + 1);
|
|
32162
33131
|
let bytesRead = 0;
|
|
32163
33132
|
while (bytesRead < bounded.length) {
|
|
32164
33133
|
const count = fs7.readSync(fd, bounded, bytesRead, bounded.length - bytesRead, bytesRead);
|
|
@@ -32166,7 +33135,7 @@ function readResumeControlState(timelineDir) {
|
|
|
32166
33135
|
break;
|
|
32167
33136
|
bytesRead += count;
|
|
32168
33137
|
}
|
|
32169
|
-
if (bytesRead !==
|
|
33138
|
+
if (bytesRead !== stat2.size)
|
|
32170
33139
|
return { kind: "invalid" };
|
|
32171
33140
|
const raw = bounded.subarray(0, bytesRead).toString("utf8");
|
|
32172
33141
|
const value = JSON.parse(raw);
|
|
@@ -32953,26 +33922,26 @@ function createTimelineRecorder(opts) {
|
|
|
32953
33922
|
}
|
|
32954
33923
|
}
|
|
32955
33924
|
// src/discovery.ts
|
|
32956
|
-
import * as
|
|
33925
|
+
import * as path13 from "path";
|
|
32957
33926
|
import * as fs8 from "fs";
|
|
32958
33927
|
import { fileURLToPath } from "url";
|
|
32959
33928
|
function resolveAlookCliPath(moduleDir) {
|
|
32960
|
-
const thisDir = moduleDir ??
|
|
32961
|
-
const target2 =
|
|
33929
|
+
const thisDir = moduleDir ?? path13.dirname(fileURLToPath(import.meta.url));
|
|
33930
|
+
const target2 = path13.basename(thisDir) === "dist" ? path13.resolve(thisDir, "cli", "index.js") : path13.resolve(thisDir, "..", "scripts", "alook-shim.mjs");
|
|
32962
33931
|
return fs8.existsSync(target2) ? target2 : null;
|
|
32963
33932
|
}
|
|
32964
33933
|
function deriveCliFallbackCandidates(cliPath) {
|
|
32965
33934
|
if (!cliPath)
|
|
32966
33935
|
return [];
|
|
32967
|
-
const normalized = cliPath.split(
|
|
33936
|
+
const normalized = cliPath.split(path13.sep).join("/");
|
|
32968
33937
|
const marker = "/node_modules/";
|
|
32969
33938
|
const idx = normalized.indexOf(marker);
|
|
32970
33939
|
if (idx === -1)
|
|
32971
33940
|
return [];
|
|
32972
33941
|
const globalRoot = cliPath.slice(0, idx + marker.length - 1);
|
|
32973
|
-
const tail =
|
|
33942
|
+
const tail = path13.join("dist", "cli", "index.js");
|
|
32974
33943
|
return [
|
|
32975
|
-
|
|
33944
|
+
path13.join(globalRoot, "@alook", "daemon", tail)
|
|
32976
33945
|
].filter((candidate) => candidate !== cliPath);
|
|
32977
33946
|
}
|
|
32978
33947
|
function resolveAlookCliPathWithFallback(primary) {
|
|
@@ -33167,7 +34136,7 @@ class MessageReminderScheduler {
|
|
|
33167
34136
|
|
|
33168
34137
|
// src/manager/agentDriverHost.ts
|
|
33169
34138
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
33170
|
-
import { homedir as
|
|
34139
|
+
import { homedir as homedir6 } from "node:os";
|
|
33171
34140
|
import { join as join13 } from "node:path";
|
|
33172
34141
|
|
|
33173
34142
|
// src/drivers/gitIdentityEnv.ts
|
|
@@ -33293,7 +34262,7 @@ function createDaemonAgentDriverHost(ctx, onRawLine) {
|
|
|
33293
34262
|
hostUser: readHostGitIdentity() ?? undefined
|
|
33294
34263
|
}),
|
|
33295
34264
|
platformProtected: {
|
|
33296
|
-
ALOOK_HOME: process.env.ALOOK_HOME ?? join13(
|
|
34265
|
+
ALOOK_HOME: process.env.ALOOK_HOME ?? join13(homedir6(), ".alook"),
|
|
33297
34266
|
ALOOK_ID: ctx.agentId,
|
|
33298
34267
|
ALOOK_CLI: ctx.agentCliPath,
|
|
33299
34268
|
ALOOK_SERVER_URL: ctx.config.serverUrl,
|
|
@@ -33614,13 +34583,13 @@ function createRuntimeRawLineTap(args) {
|
|
|
33614
34583
|
const maxBytes = args.maxBytes ?? RUNTIME_RAW_TRACE_MAX_BYTES;
|
|
33615
34584
|
const sinks = new Map;
|
|
33616
34585
|
const warned = new Set;
|
|
33617
|
-
const warnOnce = (agentId,
|
|
34586
|
+
const warnOnce = (agentId, path14, operation, error51) => {
|
|
33618
34587
|
if (warned.has(agentId))
|
|
33619
34588
|
return;
|
|
33620
34589
|
warned.add(agentId);
|
|
33621
34590
|
args.logger.warn("runtime raw trace sink failed", {
|
|
33622
34591
|
agentId,
|
|
33623
|
-
path:
|
|
34592
|
+
path: path14,
|
|
33624
34593
|
operation,
|
|
33625
34594
|
error: error51 instanceof Error ? error51.message : String(error51)
|
|
33626
34595
|
});
|
|
@@ -33629,10 +34598,10 @@ function createRuntimeRawLineTap(args) {
|
|
|
33629
34598
|
if (!args.enabledAgentIds.has(agentId))
|
|
33630
34599
|
return;
|
|
33631
34600
|
const encodedAgentId = encodeURIComponent(agentId).replace(/\./g, "%2E");
|
|
33632
|
-
const
|
|
34601
|
+
const path14 = `${traceDir}/runtime-raw-events-${encodedAgentId}.jsonl`;
|
|
33633
34602
|
const serializedBytes = Buffer.byteLength(line, "utf8") + 1;
|
|
33634
34603
|
if (serializedBytes > maxBytes) {
|
|
33635
|
-
warnOnce(agentId,
|
|
34604
|
+
warnOnce(agentId, path14, "oversize", new Error(`raw line is ${serializedBytes} bytes; max is ${maxBytes}`));
|
|
33636
34605
|
return;
|
|
33637
34606
|
}
|
|
33638
34607
|
let sink = sinks.get(agentId);
|
|
@@ -33640,12 +34609,12 @@ function createRuntimeRawLineTap(args) {
|
|
|
33640
34609
|
try {
|
|
33641
34610
|
mkdirSync7(traceDir, { recursive: true });
|
|
33642
34611
|
} catch (error51) {
|
|
33643
|
-
warnOnce(agentId,
|
|
34612
|
+
warnOnce(agentId, path14, "mkdir", error51);
|
|
33644
34613
|
}
|
|
33645
|
-
sink = createRotatingFileSink(
|
|
34614
|
+
sink = createRotatingFileSink(path14, maxBytes, {
|
|
33646
34615
|
mode: 384,
|
|
33647
34616
|
hardMaxBytes: true,
|
|
33648
|
-
onError: ({ operation, error: error51 }) => warnOnce(agentId,
|
|
34617
|
+
onError: ({ operation, error: error51 }) => warnOnce(agentId, path14, operation, error51)
|
|
33649
34618
|
});
|
|
33650
34619
|
sinks.set(agentId, sink);
|
|
33651
34620
|
}
|
|
@@ -33737,7 +34706,7 @@ function createBuiltinDaemonSessionFactory(onRuntimeRawLine) {
|
|
|
33737
34706
|
}
|
|
33738
34707
|
async function createDaemon(opts) {
|
|
33739
34708
|
const log2 = opts.logger ?? createLogger({ header: "@alook/daemon" });
|
|
33740
|
-
const fallbackBase = (process.env.ALOOK_PROJECT_ROOT || `${
|
|
34709
|
+
const fallbackBase = (process.env.ALOOK_PROJECT_ROOT || `${homedir7()}/.alook`) + "/daemon";
|
|
33741
34710
|
const workingDirectoryBase = opts.workingDirectoryBase ?? fallbackBase;
|
|
33742
34711
|
const workdirFor = (agentId) => `${workingDirectoryBase}/${agentId}`;
|
|
33743
34712
|
const dailyTokenUsage2 = new DailyTokenUsageStore(workingDirectoryBase);
|
|
@@ -33816,19 +34785,24 @@ async function createDaemon(opts) {
|
|
|
33816
34785
|
const broker = new CredentialBroker({ upstreamBaseUrl: opts.serverUrl });
|
|
33817
34786
|
const proxy = await startCredentialProxy(broker, {
|
|
33818
34787
|
onInboxPullStart: (agentId) => ({
|
|
33819
|
-
modelSeenGeneration: channelRef?.modelSeenGeneration(agentId),
|
|
33820
34788
|
owner: managerRef?.timelineTurnOwner(agentId) ?? null
|
|
33821
34789
|
}),
|
|
33822
34790
|
onInboxPullResponse: (agentId, messages, observationToken) => {
|
|
33823
34791
|
const token = observationToken && typeof observationToken === "object" ? observationToken : null;
|
|
33824
34792
|
timeline2.recordInboxPull(agentId, token?.owner ?? null, messages);
|
|
33825
|
-
if (typeof token?.modelSeenGeneration === "number") {
|
|
33826
|
-
channelRef?.recordModelSeen(agentId, messages, token.modelSeenGeneration);
|
|
33827
|
-
}
|
|
33828
34793
|
},
|
|
33829
34794
|
onInboxPullObservationError: ({ agentId, reason, contentEncoding }) => {
|
|
33830
34795
|
log2.warn("inbox pull timeline observation failed", { agentId, reason, contentEncoding });
|
|
33831
34796
|
},
|
|
34797
|
+
onInboxAckStart: (agentId) => channelRef?.modelSeenGeneration(agentId),
|
|
34798
|
+
onInboxAckResponse: (agentId, applied, observationToken) => {
|
|
34799
|
+
if (typeof observationToken !== "number")
|
|
34800
|
+
return;
|
|
34801
|
+
channelRef?.recordModelSeen(agentId, applied.map((cursor) => ({ channel: cursor.channel, seq: `#${cursor.seq}` })), observationToken);
|
|
34802
|
+
},
|
|
34803
|
+
onInboxAckObservationError: ({ agentId, reason, contentEncoding }) => {
|
|
34804
|
+
log2.warn("inbox ack observation failed", { agentId, reason, contentEncoding });
|
|
34805
|
+
},
|
|
33832
34806
|
onMessageReminderArm: (input) => reminderSchedulerRef?.arm(input) ?? { armed: false, reason: "reminder_scheduler_unavailable" },
|
|
33833
34807
|
onProxyRequest: (agentId, method, pathname, metadata) => {
|
|
33834
34808
|
const subcommand = deriveAuditLogSubcommand(pathname, method);
|
|
@@ -34328,6 +35302,7 @@ export {
|
|
|
34328
35302
|
buildApmFreshnessDecisionProducerFactId,
|
|
34329
35303
|
UnknownRuntimeError,
|
|
34330
35304
|
UnknownBotError,
|
|
35305
|
+
SESSION_FILE_DISCOVERY_CAPABILITIES2 as SESSION_FILE_DISCOVERY_CAPABILITIES,
|
|
34331
35306
|
RuntimeProgressState,
|
|
34332
35307
|
RuntimeNotificationState,
|
|
34333
35308
|
RUNTIME_RAW_TRACE_AGENT_IDS_ENV,
|