@fdcn/sourcefed 0.3.5 → 0.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -7
- package/dist/{chunk-X3BZSHKZ.js → chunk-E6J3BAXP.js} +198 -160
- package/dist/cli.js +215 -222
- package/dist/daemon.js +200 -162
- package/dist/mcp.js +1 -1
- package/dist/opencode.js +258 -121
- package/dist/pi.js +1 -1
- package/dist/tui-compiled.mjs +57 -67
- package/dist.dts/adapters/opencode/bridge.d.ts +66 -22
- package/dist.dts/adapters/opencode/subscriptions.d.ts +46 -0
- package/dist.dts/adapters/opencode/tool-result.d.ts +2 -1
- package/dist.dts/adapters/opencode/tools/monitor_create.d.ts +3 -2
- package/dist.dts/adapters/opencode/tools/monitor_list.d.ts +3 -2
- package/dist.dts/adapters/opencode/tools/monitor_start.d.ts +3 -2
- package/dist.dts/adapters/opencode/tools/monitor_status.d.ts +3 -2
- package/dist.dts/adapters/opencode/tools/monitor_stop.d.ts +3 -2
- package/dist.dts/packages/cli/src/utils/setup.d.ts +0 -1
- package/dist.dts/packages/daemon/src/event-stream.d.ts +26 -0
- package/dist.dts/packages/daemon/src/types/client.d.ts +3 -1
- package/dist.dts/packages/daemon/src/utils/index.d.ts +0 -1
- package/package.json +1 -1
- package/dist.dts/packages/daemon/src/utils/forward.d.ts +0 -32
- package/dist.dts/packages/daemon/src/utils/gate.d.ts +0 -33
- package/dist.dts/packages/daemon/src/utils/request-router.d.ts +0 -11
- /package/dist.dts/{packages/daemon/src/forward.test.d.ts → adapters/opencode/lifecycle.test.d.ts} +0 -0
- /package/dist.dts/packages/daemon/src/{gate.test.d.ts → stream-lifecycle.test.d.ts} +0 -0
package/dist/cli.js
CHANGED
|
@@ -11363,36 +11363,10 @@ async function writeResponse(outgoing, response) {
|
|
|
11363
11363
|
stream.pipe(outgoing);
|
|
11364
11364
|
});
|
|
11365
11365
|
}
|
|
11366
|
-
var RequestRouter = class {
|
|
11367
|
-
pending = /* @__PURE__ */ new Map();
|
|
11368
|
-
cursor = 1;
|
|
11369
|
-
nextID() {
|
|
11370
|
-
return this.cursor++;
|
|
11371
|
-
}
|
|
11372
|
-
register(id) {
|
|
11373
|
-
return new Promise((resolve, reject) => {
|
|
11374
|
-
this.pending.set(id, { resolve, reject });
|
|
11375
|
-
});
|
|
11376
|
-
}
|
|
11377
|
-
settle(id, frame) {
|
|
11378
|
-
const pending = this.pending.get(id);
|
|
11379
|
-
if (!pending) return;
|
|
11380
|
-
this.pending.delete(id);
|
|
11381
|
-
if (frame.error) pending.reject(new Error(frame.error));
|
|
11382
|
-
else pending.resolve(frame.result);
|
|
11383
|
-
}
|
|
11384
|
-
rejectAll(error2) {
|
|
11385
|
-
for (const { reject } of this.pending.values()) reject(error2);
|
|
11386
|
-
this.pending.clear();
|
|
11387
|
-
}
|
|
11388
|
-
};
|
|
11389
11366
|
function defaultDaemonUrl() {
|
|
11390
11367
|
const port = process.env.SOURCEFED_DAEMON_PORT ?? 18787;
|
|
11391
11368
|
return `http://127.0.0.1:${port}`;
|
|
11392
11369
|
}
|
|
11393
|
-
function sleep(ms) {
|
|
11394
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
11395
|
-
}
|
|
11396
11370
|
async function withTimeout(promise, ms, message) {
|
|
11397
11371
|
let timer;
|
|
11398
11372
|
try {
|
|
@@ -11725,164 +11699,225 @@ function parseDaemonFrame(line) {
|
|
|
11725
11699
|
return void 0;
|
|
11726
11700
|
}
|
|
11727
11701
|
}
|
|
11702
|
+
var DaemonEventStream = class {
|
|
11703
|
+
constructor(url2, headers, onEvents, acknowledge, onClose) {
|
|
11704
|
+
this.url = url2;
|
|
11705
|
+
this.headers = headers;
|
|
11706
|
+
this.onEvents = onEvents;
|
|
11707
|
+
this.acknowledge = acknowledge;
|
|
11708
|
+
this.onClose = onClose;
|
|
11709
|
+
}
|
|
11710
|
+
controller = new AbortController();
|
|
11711
|
+
subscribed = Promise.withResolvers();
|
|
11712
|
+
stream;
|
|
11713
|
+
delivering = Promise.resolve();
|
|
11714
|
+
closing;
|
|
11715
|
+
ready = false;
|
|
11716
|
+
failedDelivery = false;
|
|
11717
|
+
async start(signal) {
|
|
11718
|
+
const abort = () => {
|
|
11719
|
+
void this.close();
|
|
11720
|
+
};
|
|
11721
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
11722
|
+
const setup = withTimeout(this.subscribed.promise, 15e3, `sourcefed event stream did not subscribe at ${this.url}`);
|
|
11723
|
+
if (signal?.aborted) abort();
|
|
11724
|
+
const running = this.run();
|
|
11725
|
+
void running.finally(() => signal?.removeEventListener("abort", abort));
|
|
11726
|
+
try {
|
|
11727
|
+
await setup;
|
|
11728
|
+
} catch (error2) {
|
|
11729
|
+
await this.close();
|
|
11730
|
+
throw error2;
|
|
11731
|
+
}
|
|
11732
|
+
}
|
|
11733
|
+
close() {
|
|
11734
|
+
if (!this.closing) {
|
|
11735
|
+
this.subscribed.reject(new Error("sourcefed event stream closed"));
|
|
11736
|
+
if (!this.ready) this.controller.abort();
|
|
11737
|
+
this.closing = this.drain();
|
|
11738
|
+
}
|
|
11739
|
+
return this.closing;
|
|
11740
|
+
}
|
|
11741
|
+
async drain() {
|
|
11742
|
+
try {
|
|
11743
|
+
await withTimeout(this.delivering, 15e3, "sourcefed event delivery did not drain");
|
|
11744
|
+
} catch (error2) {
|
|
11745
|
+
console.error(`[sourcefed] closing event stream: ${String(error2)}`);
|
|
11746
|
+
} finally {
|
|
11747
|
+
this.controller.abort();
|
|
11748
|
+
this.stream?.abort();
|
|
11749
|
+
this.onClose();
|
|
11750
|
+
}
|
|
11751
|
+
}
|
|
11752
|
+
async run() {
|
|
11753
|
+
let consecutiveFailures = 0;
|
|
11754
|
+
while (!this.controller.signal.aborted) {
|
|
11755
|
+
this.failedDelivery = false;
|
|
11756
|
+
try {
|
|
11757
|
+
await this.read();
|
|
11758
|
+
consecutiveFailures = 0;
|
|
11759
|
+
} catch (error2) {
|
|
11760
|
+
if (!this.controller.signal.aborted && !this.failedDelivery && ++consecutiveFailures === 1) {
|
|
11761
|
+
console.error(`[sourcefed] event stream ended: ${String(error2)}`);
|
|
11762
|
+
}
|
|
11763
|
+
}
|
|
11764
|
+
await this.waitForDelivery();
|
|
11765
|
+
if (!this.controller.signal.aborted) await pause(500, this.controller.signal);
|
|
11766
|
+
}
|
|
11767
|
+
}
|
|
11768
|
+
async read() {
|
|
11769
|
+
const controller = new AbortController();
|
|
11770
|
+
const abort = () => controller.abort();
|
|
11771
|
+
this.stream = controller;
|
|
11772
|
+
this.controller.signal.addEventListener("abort", abort, { once: true });
|
|
11773
|
+
let reader;
|
|
11774
|
+
try {
|
|
11775
|
+
this.controller.signal.throwIfAborted();
|
|
11776
|
+
const response = await fetch(this.url, { signal: controller.signal, headers: this.headers });
|
|
11777
|
+
if (!response.ok || !response.body) {
|
|
11778
|
+
await response.body?.cancel();
|
|
11779
|
+
throw new Error(`event stream failed: ${response.status}`);
|
|
11780
|
+
}
|
|
11781
|
+
reader = response.body.getReader();
|
|
11782
|
+
const decoder = new TextDecoder();
|
|
11783
|
+
let buffer = "";
|
|
11784
|
+
while (!controller.signal.aborted) {
|
|
11785
|
+
const { done, value } = await reader.read();
|
|
11786
|
+
if (done) return;
|
|
11787
|
+
buffer += decoder.decode(value, { stream: true });
|
|
11788
|
+
const frames = buffer.split("\n\n");
|
|
11789
|
+
buffer = frames.pop() ?? "";
|
|
11790
|
+
for (const chunk of frames) await this.frame(chunk);
|
|
11791
|
+
}
|
|
11792
|
+
} finally {
|
|
11793
|
+
await reader?.cancel().catch(() => void 0);
|
|
11794
|
+
reader?.releaseLock();
|
|
11795
|
+
this.controller.signal.removeEventListener("abort", abort);
|
|
11796
|
+
if (this.stream === controller) this.stream = void 0;
|
|
11797
|
+
}
|
|
11798
|
+
}
|
|
11799
|
+
async frame(chunk) {
|
|
11800
|
+
if (this.closing || this.controller.signal.aborted) return;
|
|
11801
|
+
for (const line of chunk.split("\n")) {
|
|
11802
|
+
if (!line.startsWith("data: ")) continue;
|
|
11803
|
+
const frame = parseDaemonFrame(line.slice(6));
|
|
11804
|
+
if (!frame || !("type" in frame)) continue;
|
|
11805
|
+
if (frame.type === "subscribed") {
|
|
11806
|
+
this.ready = true;
|
|
11807
|
+
this.subscribed.resolve();
|
|
11808
|
+
}
|
|
11809
|
+
if (frame.type === "event" && frame.events.length > 0) {
|
|
11810
|
+
this.deliver(frame.events);
|
|
11811
|
+
await this.waitForDelivery();
|
|
11812
|
+
}
|
|
11813
|
+
}
|
|
11814
|
+
}
|
|
11815
|
+
deliver(events2) {
|
|
11816
|
+
this.delivering = this.delivering.then(async () => {
|
|
11817
|
+
if (this.failedDelivery || this.controller.signal.aborted) return;
|
|
11818
|
+
try {
|
|
11819
|
+
await this.onEvents(events2);
|
|
11820
|
+
await this.acknowledge(events2, this.controller.signal);
|
|
11821
|
+
} catch (error2) {
|
|
11822
|
+
if (!this.controller.signal.aborted) console.error(`[sourcefed] event delivery failed: ${String(error2)}`);
|
|
11823
|
+
this.failedDelivery = true;
|
|
11824
|
+
this.stream?.abort();
|
|
11825
|
+
}
|
|
11826
|
+
});
|
|
11827
|
+
}
|
|
11828
|
+
async waitForDelivery() {
|
|
11829
|
+
if (this.controller.signal.aborted) return;
|
|
11830
|
+
const stopped = Promise.withResolvers();
|
|
11831
|
+
const abort = () => stopped.resolve();
|
|
11832
|
+
this.controller.signal.addEventListener("abort", abort, { once: true });
|
|
11833
|
+
try {
|
|
11834
|
+
await Promise.race([this.delivering, stopped.promise]);
|
|
11835
|
+
} finally {
|
|
11836
|
+
this.controller.signal.removeEventListener("abort", abort);
|
|
11837
|
+
}
|
|
11838
|
+
}
|
|
11839
|
+
};
|
|
11840
|
+
function pause(ms, signal) {
|
|
11841
|
+
return new Promise((resolve) => {
|
|
11842
|
+
const finish = () => {
|
|
11843
|
+
clearTimeout(timer);
|
|
11844
|
+
signal.removeEventListener("abort", finish);
|
|
11845
|
+
resolve();
|
|
11846
|
+
};
|
|
11847
|
+
const timer = setTimeout(finish, ms);
|
|
11848
|
+
signal.addEventListener("abort", finish, { once: true });
|
|
11849
|
+
if (signal.aborted) finish();
|
|
11850
|
+
});
|
|
11851
|
+
}
|
|
11728
11852
|
async function connectDaemonClient(options) {
|
|
11729
11853
|
const url2 = options.url ?? process.env.SOURCEFED_DAEMON_URL ?? defaultDaemonUrl();
|
|
11730
11854
|
return new HttpDaemonClient(url2, options.token ?? process.env.SOURCEFED_DAEMON_TOKEN);
|
|
11731
11855
|
}
|
|
11732
11856
|
var HttpDaemonClient = class {
|
|
11733
|
-
baseURL;
|
|
11734
|
-
token;
|
|
11735
|
-
router = new RequestRouter();
|
|
11736
|
-
listeners = /* @__PURE__ */ new Map();
|
|
11737
|
-
streams = /* @__PURE__ */ new Set();
|
|
11738
11857
|
constructor(baseURL, token) {
|
|
11739
|
-
this.baseURL = baseURL.replace(/\/+$/, "");
|
|
11740
11858
|
this.token = token;
|
|
11859
|
+
this.baseURL = baseURL.replace(/\/+$/, "");
|
|
11741
11860
|
}
|
|
11861
|
+
baseURL;
|
|
11862
|
+
streams = /* @__PURE__ */ new Set();
|
|
11863
|
+
lifetime = new AbortController();
|
|
11864
|
+
cursor = 0;
|
|
11865
|
+
closing;
|
|
11742
11866
|
headers() {
|
|
11743
11867
|
return this.token ? { authorization: `Bearer ${this.token}` } : {};
|
|
11744
11868
|
}
|
|
11745
|
-
async request(method, params) {
|
|
11746
|
-
|
|
11747
|
-
|
|
11869
|
+
async request(method, params, signal = this.lifetime.signal) {
|
|
11870
|
+
if (this.closing && signal === this.lifetime.signal) throw new Error("daemon closed");
|
|
11871
|
+
signal.throwIfAborted();
|
|
11872
|
+
const response = await fetch(`${this.baseURL}/rpc`, {
|
|
11873
|
+
method: "POST",
|
|
11874
|
+
headers: { "content-type": "application/json", ...this.headers() },
|
|
11875
|
+
body: JSON.stringify({ id: ++this.cursor, method, params }),
|
|
11876
|
+
signal: AbortSignal.any([signal, this.lifetime.signal, AbortSignal.timeout(15e3)])
|
|
11877
|
+
});
|
|
11878
|
+
const frame = await response.json();
|
|
11879
|
+
if (!response.ok || frame.error) throw new Error(frame.error ?? `daemon request failed: ${response.status}`);
|
|
11880
|
+
return frame.result;
|
|
11881
|
+
}
|
|
11882
|
+
async subscribe(target, onEvents, options) {
|
|
11883
|
+
if (this.closing) throw new Error("daemon closed");
|
|
11884
|
+
this.lifetime.signal.throwIfAborted();
|
|
11885
|
+
const stream = new DaemonEventStream(
|
|
11886
|
+
`${this.baseURL}/events?target=${encodeTarget(target)}`,
|
|
11887
|
+
this.headers(),
|
|
11888
|
+
onEvents,
|
|
11889
|
+
(events2, signal) => this.acknowledge(target, events2, signal),
|
|
11890
|
+
() => this.streams.delete(stream)
|
|
11891
|
+
);
|
|
11892
|
+
this.streams.add(stream);
|
|
11748
11893
|
try {
|
|
11749
|
-
|
|
11750
|
-
|
|
11751
|
-
headers: { "content-type": "application/json", ...this.headers() },
|
|
11752
|
-
body: JSON.stringify({ id, method, params })
|
|
11753
|
-
});
|
|
11754
|
-
const frame = await response.json();
|
|
11755
|
-
if (!response.ok || frame.error) throw new Error(frame.error ?? `daemon request failed: ${response.status}`);
|
|
11756
|
-
this.router.settle(id, { result: frame.result });
|
|
11894
|
+
await stream.start(options?.signal);
|
|
11895
|
+
return { close: () => stream.close() };
|
|
11757
11896
|
} catch (error2) {
|
|
11758
|
-
|
|
11897
|
+
await stream.close();
|
|
11898
|
+
throw error2;
|
|
11759
11899
|
}
|
|
11760
|
-
return promise;
|
|
11761
11900
|
}
|
|
11762
|
-
async
|
|
11763
|
-
|
|
11764
|
-
|
|
11765
|
-
if (!callbacks) {
|
|
11766
|
-
callbacks = /* @__PURE__ */ new Set();
|
|
11767
|
-
this.listeners.set(key, callbacks);
|
|
11768
|
-
}
|
|
11769
|
-
callbacks.add(onEvents);
|
|
11770
|
-
const controller = new AbortController();
|
|
11771
|
-
this.streams.add(controller);
|
|
11772
|
-
const url2 = `${this.baseURL}/events?target=${encodeTarget(target)}`;
|
|
11773
|
-
let markSubscribed;
|
|
11774
|
-
const subscribed = new Promise((resolve) => {
|
|
11775
|
-
markSubscribed = () => resolve();
|
|
11776
|
-
});
|
|
11777
|
-
let delivering = Promise.resolve();
|
|
11778
|
-
let activeStream;
|
|
11779
|
-
let retryStream = false;
|
|
11780
|
-
const deliver = (events2) => {
|
|
11781
|
-
if (!callbacks?.has(onEvents) || events2.length === 0) return Promise.resolve();
|
|
11782
|
-
delivering = delivering.then(async () => {
|
|
11783
|
-
try {
|
|
11784
|
-
await onEvents(events2);
|
|
11785
|
-
} catch (error2) {
|
|
11786
|
-
console.error(`[sourcefed] event delivery failed: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
11787
|
-
retryStream = true;
|
|
11788
|
-
activeStream?.abort();
|
|
11789
|
-
return;
|
|
11790
|
-
}
|
|
11791
|
-
await acknowledge(events2);
|
|
11792
|
-
}).catch((error2) => {
|
|
11793
|
-
console.error(`[sourcefed] event delivery failed: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
11794
|
-
});
|
|
11795
|
-
return delivering;
|
|
11796
|
-
};
|
|
11797
|
-
const acknowledge = async (events2) => {
|
|
11798
|
-
let attempt = 0;
|
|
11799
|
-
while (!controller.signal.aborted && callbacks?.has(onEvents)) {
|
|
11800
|
-
try {
|
|
11801
|
-
await this.request("monitor.ack", { target, eventIDs: events2.map((event) => event.id) });
|
|
11802
|
-
return;
|
|
11803
|
-
} catch (error2) {
|
|
11804
|
-
attempt += 1;
|
|
11805
|
-
if (attempt === 3) {
|
|
11806
|
-
console.error(`[sourcefed] event acknowledgement still failing; retrying without repeating delivery: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
11807
|
-
}
|
|
11808
|
-
await sleep(Math.min(250 * 2 ** (attempt - 1), 4e3));
|
|
11809
|
-
}
|
|
11810
|
-
}
|
|
11811
|
-
};
|
|
11812
|
-
const runStream = async () => {
|
|
11813
|
-
const streamController = new AbortController();
|
|
11814
|
-
const closeStream = () => streamController.abort();
|
|
11815
|
-
activeStream = streamController;
|
|
11816
|
-
controller.signal.addEventListener("abort", closeStream, { once: true });
|
|
11901
|
+
async acknowledge(target, events2, signal) {
|
|
11902
|
+
let attempt = 0;
|
|
11903
|
+
while (!signal.aborted) {
|
|
11817
11904
|
try {
|
|
11818
|
-
|
|
11819
|
-
|
|
11820
|
-
const reader = response.body.getReader();
|
|
11821
|
-
const decoder = new TextDecoder();
|
|
11822
|
-
let buffer = "";
|
|
11823
|
-
while (true) {
|
|
11824
|
-
const { done, value } = await reader.read();
|
|
11825
|
-
if (done) break;
|
|
11826
|
-
buffer += decoder.decode(value, { stream: true });
|
|
11827
|
-
const frames = buffer.split("\n\n");
|
|
11828
|
-
buffer = frames.pop() ?? "";
|
|
11829
|
-
for (const chunk of frames) {
|
|
11830
|
-
for (const line of chunk.split("\n")) {
|
|
11831
|
-
if (!line.startsWith("data: ")) continue;
|
|
11832
|
-
const frame = parseDaemonFrame(line.slice(6));
|
|
11833
|
-
if (!frame || !("type" in frame)) continue;
|
|
11834
|
-
if (frame.type === "subscribed") markSubscribed();
|
|
11835
|
-
if (frame.type === "event") void deliver(frame.events);
|
|
11836
|
-
}
|
|
11837
|
-
}
|
|
11838
|
-
}
|
|
11839
|
-
consecutiveFailures = 0;
|
|
11905
|
+
await this.request("monitor.ack", { target, eventIDs: events2.map((event) => event.id) }, signal);
|
|
11906
|
+
return;
|
|
11840
11907
|
} catch (error2) {
|
|
11841
|
-
if (
|
|
11842
|
-
|
|
11843
|
-
if (consecutiveFailures === 1) {
|
|
11844
|
-
console.error(`[sourcefed] event stream ended: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
11845
|
-
}
|
|
11908
|
+
if (++attempt === 3) {
|
|
11909
|
+
console.error(`[sourcefed] event acknowledgement still failing; retrying without repeating delivery: ${String(error2)}`);
|
|
11846
11910
|
}
|
|
11847
|
-
|
|
11848
|
-
controller.signal.removeEventListener("abort", closeStream);
|
|
11849
|
-
if (activeStream === streamController) activeStream = void 0;
|
|
11850
|
-
retryStream = false;
|
|
11911
|
+
await pause(Math.min(250 * 2 ** Math.min(attempt - 1, 4), 4e3), signal);
|
|
11851
11912
|
}
|
|
11852
|
-
};
|
|
11853
|
-
let consecutiveFailures = 0;
|
|
11854
|
-
void (async () => {
|
|
11855
|
-
while (!controller.signal.aborted && callbacks?.has(onEvents)) {
|
|
11856
|
-
await runStream();
|
|
11857
|
-
if (controller.signal.aborted) break;
|
|
11858
|
-
await sleep(500);
|
|
11859
|
-
}
|
|
11860
|
-
})();
|
|
11861
|
-
try {
|
|
11862
|
-
await withTimeout(subscribed, 15e3, `sourcefed event stream did not subscribe at ${url2}`);
|
|
11863
|
-
} catch (error2) {
|
|
11864
|
-
const callbacks2 = this.listeners.get(key);
|
|
11865
|
-
callbacks2?.delete(onEvents);
|
|
11866
|
-
if (callbacks2 && callbacks2.size === 0) this.listeners.delete(key);
|
|
11867
|
-
controller.abort();
|
|
11868
|
-
this.streams.delete(controller);
|
|
11869
|
-
throw error2;
|
|
11870
11913
|
}
|
|
11871
|
-
return {
|
|
11872
|
-
close: async () => {
|
|
11873
|
-
const callbacks2 = this.listeners.get(key);
|
|
11874
|
-
callbacks2?.delete(onEvents);
|
|
11875
|
-
if (callbacks2 && callbacks2.size === 0) this.listeners.delete(key);
|
|
11876
|
-
controller.abort();
|
|
11877
|
-
this.streams.delete(controller);
|
|
11878
|
-
}
|
|
11879
|
-
};
|
|
11880
11914
|
}
|
|
11881
|
-
|
|
11882
|
-
|
|
11883
|
-
|
|
11884
|
-
|
|
11885
|
-
|
|
11915
|
+
close() {
|
|
11916
|
+
this.closing ??= Promise.all([...this.streams].map((stream) => stream.close())).then(() => {
|
|
11917
|
+
this.lifetime.abort();
|
|
11918
|
+
this.streams.clear();
|
|
11919
|
+
});
|
|
11920
|
+
return this.closing;
|
|
11886
11921
|
}
|
|
11887
11922
|
};
|
|
11888
11923
|
async function dispatchDaemonRequest(daemon, method, params) {
|
|
@@ -22324,7 +22359,7 @@ var REQUEST_STATE_ONLY_LEG_PACING_MS = 250;
|
|
|
22324
22359
|
function inputRequiredRoundsExceededMessage(method, maxRounds) {
|
|
22325
22360
|
return `Multi-round-trip request '${method}' still required input after ${maxRounds} rounds (inputRequired.maxRounds)`;
|
|
22326
22361
|
}
|
|
22327
|
-
function
|
|
22362
|
+
function sleep(ms, signal) {
|
|
22328
22363
|
return new Promise((resolve, reject) => {
|
|
22329
22364
|
if (signal?.aborted) {
|
|
22330
22365
|
reject(signal.reason instanceof SdkError ? signal.reason : new SdkError(SdkErrorCode.RequestTimeout, String(signal.reason)));
|
|
@@ -31059,7 +31094,7 @@ var LegacyInputRequiredShim = class {
|
|
|
31059
31094
|
} finally {
|
|
31060
31095
|
roundAbort.dispose();
|
|
31061
31096
|
}
|
|
31062
|
-
} else await
|
|
31097
|
+
} else await sleep(REQUEST_STATE_ONLY_LEG_PACING_MS, outerSignal);
|
|
31063
31098
|
let ctxNext = {
|
|
31064
31099
|
...ctx,
|
|
31065
31100
|
mcpReq: {
|
|
@@ -44192,9 +44227,7 @@ async function runMonitor(argv) {
|
|
|
44192
44227
|
|
|
44193
44228
|
// packages/cli/src/utils/setup.ts
|
|
44194
44229
|
import { execFile } from "node:child_process";
|
|
44195
|
-
import {
|
|
44196
|
-
import os8 from "node:os";
|
|
44197
|
-
import path8 from "node:path";
|
|
44230
|
+
import { readFileSync } from "node:fs";
|
|
44198
44231
|
import { fileURLToPath } from "node:url";
|
|
44199
44232
|
function setupSpec() {
|
|
44200
44233
|
const manifest = JSON.parse(readFileSync(fileURLToPath(new URL("../package.json", import.meta.url)), "utf8"));
|
|
@@ -44211,59 +44244,19 @@ async function setupHost(name, args, spec) {
|
|
|
44211
44244
|
const code = error2 && typeof error2 === "object" && "code" in error2 ? String(error2.code) : "";
|
|
44212
44245
|
if (code === "ENOENT") {
|
|
44213
44246
|
console.error(`[sourcefed] ${name} is not on PATH \u2014 install it manually:`);
|
|
44214
|
-
console.error(name === "opencode" ? ` add "${spec}" to the plugins array in ~/.config/opencode/opencode.jsonc
|
|
44247
|
+
console.error(name === "opencode" ? ` add "${spec}" to the plugins array in ~/.config/opencode/opencode.jsonc` : ` run: pi install ${spec}`);
|
|
44215
44248
|
return false;
|
|
44216
44249
|
}
|
|
44217
44250
|
throw error2;
|
|
44218
44251
|
}
|
|
44219
44252
|
}
|
|
44220
|
-
function configureOpenCodeCliPlugin(spec) {
|
|
44221
|
-
const file = openCodeCliConfigPath();
|
|
44222
|
-
const config2 = readOpenCodeCliConfig(file);
|
|
44223
|
-
const plugins = config2.plugins;
|
|
44224
|
-
if (plugins === void 0) {
|
|
44225
|
-
config2.plugins = [spec];
|
|
44226
|
-
} else if (!Array.isArray(plugins)) {
|
|
44227
|
-
throw new Error(`OpenCode CLI config has a non-array plugins setting: ${file}`);
|
|
44228
|
-
} else if (!plugins.some((plugin) => isPluginEntry(plugin, spec))) {
|
|
44229
|
-
config2.plugins = [...plugins, spec];
|
|
44230
|
-
} else {
|
|
44231
|
-
return;
|
|
44232
|
-
}
|
|
44233
|
-
mkdirSync(path8.dirname(file), { recursive: true });
|
|
44234
|
-
writeFileSync(file, `${JSON.stringify(config2, null, 2)}
|
|
44235
|
-
`);
|
|
44236
|
-
}
|
|
44237
|
-
function openCodeCliConfigPath() {
|
|
44238
|
-
const configHome = process.env.XDG_CONFIG_HOME ?? path8.join(os8.homedir(), ".config");
|
|
44239
|
-
return path8.join(configHome, "opencode", "cli.json");
|
|
44240
|
-
}
|
|
44241
|
-
function readOpenCodeCliConfig(file) {
|
|
44242
|
-
try {
|
|
44243
|
-
const value = JSON.parse(readFileSync(file, "utf8"));
|
|
44244
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
44245
|
-
throw new Error(`OpenCode CLI config must contain a JSON object: ${file}`);
|
|
44246
|
-
}
|
|
44247
|
-
return value;
|
|
44248
|
-
} catch (error2) {
|
|
44249
|
-
if (error2 instanceof Error && "code" in error2 && error2.code === "ENOENT") return {};
|
|
44250
|
-
if (error2 instanceof SyntaxError) throw new Error(`OpenCode CLI config is not valid JSON: ${file}`);
|
|
44251
|
-
throw error2;
|
|
44252
|
-
}
|
|
44253
|
-
}
|
|
44254
|
-
function isPluginEntry(value, spec) {
|
|
44255
|
-
if (value === spec) return true;
|
|
44256
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
44257
|
-
return "package" in value && value.package === spec;
|
|
44258
|
-
}
|
|
44259
44253
|
|
|
44260
44254
|
// packages/cli/src/commands/setup.ts
|
|
44261
44255
|
async function runSetup(args) {
|
|
44262
44256
|
const spec = setupSpec();
|
|
44263
44257
|
const requested = args[0] ?? "all";
|
|
44264
44258
|
if (requested === "opencode" || requested === "all") {
|
|
44265
|
-
|
|
44266
|
-
if (installed) configureOpenCodeCliPlugin(spec);
|
|
44259
|
+
await setupHost("opencode", ["plugin", "add", spec], spec);
|
|
44267
44260
|
}
|
|
44268
44261
|
if (requested === "pi" || requested === "all") {
|
|
44269
44262
|
await setupHost("pi", ["install", `npm:${spec}`], `npm:${spec}`);
|
|
@@ -44272,12 +44265,12 @@ async function runSetup(args) {
|
|
|
44272
44265
|
|
|
44273
44266
|
// packages/cli/src/skills/command.ts
|
|
44274
44267
|
import { readFile as readFile7, readdir as readdir2, stat as stat2 } from "node:fs/promises";
|
|
44275
|
-
import
|
|
44268
|
+
import path9 from "node:path";
|
|
44276
44269
|
|
|
44277
44270
|
// packages/cli/src/skills/discovery.ts
|
|
44278
44271
|
import { statSync } from "node:fs";
|
|
44279
44272
|
import { readdir, readFile as readFile6, stat } from "node:fs/promises";
|
|
44280
|
-
import
|
|
44273
|
+
import path8 from "node:path";
|
|
44281
44274
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
44282
44275
|
|
|
44283
44276
|
// packages/cli/src/skills/frontmatter.ts
|
|
@@ -44325,7 +44318,7 @@ async function skillsDirs() {
|
|
|
44325
44318
|
}
|
|
44326
44319
|
const directories = [];
|
|
44327
44320
|
for (const name of SKILL_DIRS) {
|
|
44328
|
-
const candidate =
|
|
44321
|
+
const candidate = path8.join(skillRoot(), name);
|
|
44329
44322
|
try {
|
|
44330
44323
|
if ((await stat(candidate)).isDirectory()) directories.push(candidate);
|
|
44331
44324
|
} catch {
|
|
@@ -44337,7 +44330,7 @@ async function discoverSkills() {
|
|
|
44337
44330
|
const skills = [];
|
|
44338
44331
|
for (const dir of await skillsDirs()) {
|
|
44339
44332
|
for (const entry of await readdir(dir)) {
|
|
44340
|
-
const skillDir =
|
|
44333
|
+
const skillDir = path8.join(dir, entry);
|
|
44341
44334
|
let entryStat;
|
|
44342
44335
|
try {
|
|
44343
44336
|
entryStat = await stat(skillDir);
|
|
@@ -44345,7 +44338,7 @@ async function discoverSkills() {
|
|
|
44345
44338
|
continue;
|
|
44346
44339
|
}
|
|
44347
44340
|
if (!entryStat.isDirectory()) continue;
|
|
44348
|
-
const skillFile =
|
|
44341
|
+
const skillFile = path8.join(skillDir, "SKILL.md");
|
|
44349
44342
|
try {
|
|
44350
44343
|
const content = await readFile6(skillFile, "utf8");
|
|
44351
44344
|
const parsed = parseFrontmatter(content);
|
|
@@ -44358,15 +44351,15 @@ async function discoverSkills() {
|
|
|
44358
44351
|
return skills;
|
|
44359
44352
|
}
|
|
44360
44353
|
function skillRoot() {
|
|
44361
|
-
let dir =
|
|
44354
|
+
let dir = path8.dirname(fileURLToPath2(import.meta.url));
|
|
44362
44355
|
for (let depth = 0; depth < 6; depth++) {
|
|
44363
|
-
const marker =
|
|
44356
|
+
const marker = path8.join(dir, "data");
|
|
44364
44357
|
if (statSync(marker, { throwIfNoEntry: false })?.isDirectory()) return dir;
|
|
44365
|
-
const parent =
|
|
44358
|
+
const parent = path8.dirname(dir);
|
|
44366
44359
|
if (parent === dir) break;
|
|
44367
44360
|
dir = parent;
|
|
44368
44361
|
}
|
|
44369
|
-
return
|
|
44362
|
+
return path8.dirname(fileURLToPath2(import.meta.url));
|
|
44370
44363
|
}
|
|
44371
44364
|
|
|
44372
44365
|
// packages/cli/src/skills/command.ts
|
|
@@ -44413,7 +44406,7 @@ async function runGet(args) {
|
|
|
44413
44406
|
output += `# ${skill.name}
|
|
44414
44407
|
|
|
44415
44408
|
`;
|
|
44416
|
-
output += await readFile7(
|
|
44409
|
+
output += await readFile7(path9.join(skill.dir, "SKILL.md"), "utf8");
|
|
44417
44410
|
output += "\n";
|
|
44418
44411
|
if (full) output += await supplementaryFiles(skill.dir);
|
|
44419
44412
|
}
|
|
@@ -44436,7 +44429,7 @@ async function runPath(name) {
|
|
|
44436
44429
|
async function supplementaryFiles(skillDir) {
|
|
44437
44430
|
let output = "";
|
|
44438
44431
|
for (const subdirName of ["references", "templates"]) {
|
|
44439
|
-
const subdir =
|
|
44432
|
+
const subdir = path9.join(skillDir, subdirName);
|
|
44440
44433
|
try {
|
|
44441
44434
|
if (!(await stat2(subdir)).isDirectory()) continue;
|
|
44442
44435
|
} catch {
|
|
@@ -44444,7 +44437,7 @@ async function supplementaryFiles(skillDir) {
|
|
|
44444
44437
|
}
|
|
44445
44438
|
const entries = (await readdir2(subdir)).sort();
|
|
44446
44439
|
for (const entry of entries) {
|
|
44447
|
-
const filePath =
|
|
44440
|
+
const filePath = path9.join(subdir, entry);
|
|
44448
44441
|
try {
|
|
44449
44442
|
if (!(await stat2(filePath)).isFile()) continue;
|
|
44450
44443
|
} catch {
|