@webinson/peer-core 0.0.0-stage → 0.1.894

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 T3 Tools Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,17 @@
1
- # Temporary Holding Version
1
+ # @webinson/peer-core
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Peer's coordination for coding agents on a computer without the Peer app: the `peer` command.
4
+
5
+ ```sh
6
+ npm i -g @webinson/peer-core # or: npx @webinson/peer-core core status
7
+ peer core login you@company.com # a code is mailed by your Peer Hub
8
+ peer core share ~/code/project # the folder needs a git remote
9
+ peer core connect cursor # Cursor, VS Code, Windsurf, Gemini CLI, OpenCode, Zed, Copilot CLI, Kiro
10
+ peer core hooks install # Claude Code (and Codex with --codex)
11
+ peer core serve --detach # or let the editor start it on demand
12
+ ```
13
+
14
+ `peer core status` says who runs Peer here; `peer core stop` stops Peer Core. The Peer desktop app,
15
+ when it starts, takes coordination over. Any other `peer <command>` goes to the running Peer.
16
+
17
+ Version 0.1.894 of Peer Local (https://github.com/SemanS/peer-app, branch `peer`), based on T3 Code.
@@ -0,0 +1,233 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { $t as runPromise, Cn as tryPromise, I as fail, Mn as void_, f as asVoid, g as catchCause, mn as sync, o as andThen, st as gen, tt as forkChild, va as squash } from "./Effect-DXlc4A9S.mjs";
4
+ import { Bn as await_, O as fromAsyncIterable, lt as runCollect, n as responsePayloads, pt as runForEach, t as discardResponseBody, zn as awaitAll } from "./mcpResponsePayloads-Be_jYC4_.mjs";
5
+ import * as NodeReadline from "node:readline";
6
+ //#region src/mcp/AcpMcpStdioBridge.ts
7
+ /**
8
+ * ACP agents must support stdio MCP servers, while optional http/sse support is
9
+ * unevenly implemented.
10
+ */
11
+ var AcpMcpBridgeError = class extends Error {
12
+ _tag = "AcpMcpBridgeError";
13
+ };
14
+ const bridgeError = (cause) => cause instanceof AcpMcpBridgeError ? cause : new AcpMcpBridgeError(cause instanceof Error ? cause.message : String(cause), { cause });
15
+ const MCP_PROTOCOL_VERSION = "2025-06-18";
16
+ function asEnvelope(value) {
17
+ return typeof value === "object" && value !== null ? value : null;
18
+ }
19
+ function protocolVersionOf(entry) {
20
+ const result = asEnvelope(entry)?.result;
21
+ const version = typeof result === "object" && result !== null ? result.protocolVersion : void 0;
22
+ return typeof version === "string" && version.length > 0 ? version : null;
23
+ }
24
+ /**
25
+ * This is the terminal fallback for ACP agents that accept `mcpServers` in
26
+ * `session/new` but fail to expose those tools to their model. Compliant ACP
27
+ * agents continue to use the stdio bridge above.
28
+ */
29
+ function callAcpMcpTool(options) {
30
+ const fetchImplementation = options.fetchImplementation ?? fetch;
31
+ return gen(function* () {
32
+ let sessionId = null;
33
+ let protocolVersion = null;
34
+ const send = (message) => gen(function* () {
35
+ const response = yield* tryPromise({
36
+ try: () => fetchImplementation(options.endpoint, {
37
+ method: "POST",
38
+ headers: {
39
+ "content-type": "application/json",
40
+ accept: "application/json, text/event-stream",
41
+ authorization: options.authorization,
42
+ ...sessionId === null ? {} : { "mcp-session-id": sessionId },
43
+ ...protocolVersion === null ? {} : { "mcp-protocol-version": protocolVersion }
44
+ },
45
+ body: JSON.stringify(message)
46
+ }),
47
+ catch: bridgeError
48
+ });
49
+ sessionId = response.headers.get("mcp-session-id") ?? sessionId;
50
+ if (!response.ok) {
51
+ yield* discardResponseBody(response);
52
+ return yield* fail(new AcpMcpBridgeError(`T3 Code MCP endpoint responded with HTTP ${response.status}.`));
53
+ }
54
+ const payloads = yield* runCollect(responsePayloads(response, bridgeError));
55
+ for (const payload of payloads) protocolVersion = protocolVersionOf(payload) ?? protocolVersion;
56
+ return payloads;
57
+ });
58
+ const initializeId = "t3-acp-cli-initialize";
59
+ const initializeResponse = (yield* send({
60
+ jsonrpc: "2.0",
61
+ id: initializeId,
62
+ method: "initialize",
63
+ params: {
64
+ protocolVersion: MCP_PROTOCOL_VERSION,
65
+ capabilities: {},
66
+ clientInfo: {
67
+ name: "t3-code-acp-cli",
68
+ version: "0.0.0"
69
+ }
70
+ }
71
+ })).find((entry) => asEnvelope(entry)?.id === initializeId);
72
+ if (initializeResponse === void 0 || asEnvelope(initializeResponse)?.error !== void 0) return yield* fail(new AcpMcpBridgeError("T3 Code MCP endpoint rejected initialization."));
73
+ yield* send({
74
+ jsonrpc: "2.0",
75
+ method: "notifications/initialized"
76
+ });
77
+ const callId = "t3-acp-cli-tool-call";
78
+ const envelope = asEnvelope((yield* send({
79
+ jsonrpc: "2.0",
80
+ id: callId,
81
+ method: "tools/call",
82
+ params: {
83
+ name: options.tool,
84
+ arguments: options.arguments
85
+ }
86
+ })).find((entry) => asEnvelope(entry)?.id === callId));
87
+ if (envelope === null || envelope.error !== void 0) return yield* fail(new AcpMcpBridgeError(`T3 Code MCP tool call failed${envelope?.error === void 0 ? "." : `: ${JSON.stringify(envelope.error)}`}`));
88
+ return envelope.result;
89
+ });
90
+ }
91
+ function runAcpMcpStdioBridge(options) {
92
+ const fetchImplementation = options.fetchImplementation ?? fetch;
93
+ return gen(function* () {
94
+ let sessionId = null;
95
+ let protocolVersion = null;
96
+ const running = /* @__PURE__ */ new Set();
97
+ const writeMessage = (message) => sync(() => {
98
+ options.output.write(`${JSON.stringify(message)}\n`);
99
+ });
100
+ const handleServerPayload = (payload) => gen(function* () {
101
+ for (const entry of Array.isArray(payload) ? payload : [payload]) {
102
+ protocolVersion = protocolVersionOf(entry) ?? protocolVersion;
103
+ yield* writeMessage(entry);
104
+ }
105
+ });
106
+ const respondWithError = (requestId, message, code = -32603) => writeMessage({
107
+ jsonrpc: "2.0",
108
+ id: requestId ?? null,
109
+ error: {
110
+ code,
111
+ message
112
+ }
113
+ });
114
+ const forward = (line, envelope) => gen(function* () {
115
+ const response = yield* tryPromise({
116
+ try: () => fetchImplementation(options.endpoint, {
117
+ method: "POST",
118
+ headers: {
119
+ "content-type": "application/json",
120
+ accept: "application/json, text/event-stream",
121
+ authorization: options.authorization,
122
+ ...sessionId === null ? {} : { "mcp-session-id": sessionId },
123
+ ...protocolVersion === null ? {} : { "mcp-protocol-version": protocolVersion }
124
+ },
125
+ body: line
126
+ }),
127
+ catch: bridgeError
128
+ });
129
+ sessionId = response.headers.get("mcp-session-id") ?? sessionId;
130
+ if (!response.ok) {
131
+ if (envelope.id !== void 0) yield* respondWithError(envelope.id, `T3 Code MCP endpoint responded with HTTP ${response.status}.`);
132
+ return yield* discardResponseBody(response);
133
+ }
134
+ yield* runForEach(responsePayloads(response, bridgeError), handleServerPayload);
135
+ }).pipe(catchCause((cause) => {
136
+ if (envelope.id === void 0) return void_;
137
+ const error = squash(cause);
138
+ return respondWithError(envelope.id, `T3 Code MCP bridge request failed: ${error instanceof Error ? error.message : String(error)}`);
139
+ }));
140
+ let sessionBarrier = void_;
141
+ let sessionBarrierPending = false;
142
+ const launch = (task) => gen(function* () {
143
+ const fiber = yield* forkChild(task);
144
+ running.add(fiber);
145
+ yield* forkChild(await_(fiber).pipe(andThen(sync(() => {
146
+ running.delete(fiber);
147
+ }))));
148
+ });
149
+ const dispatch = (line) => gen(function* () {
150
+ if (line.trim().length === 0) return;
151
+ let parsed;
152
+ try {
153
+ parsed = JSON.parse(line);
154
+ } catch {
155
+ return yield* respondWithError(null, "Parse error", -32700);
156
+ }
157
+ const envelope = asEnvelope(parsed);
158
+ if (envelope === null) return;
159
+ const isResponse = envelope.id !== void 0 && ("result" in envelope || "error" in envelope);
160
+ const isSessionHandshake = envelope.method === "initialize" || envelope.method === "notifications/initialized";
161
+ if (isResponse) return yield* launch(forward(line, envelope));
162
+ if (isSessionHandshake) {
163
+ const fiber = yield* forkChild(sessionBarrier.pipe(andThen(forward(line, envelope))));
164
+ running.add(fiber);
165
+ const barrier = await_(fiber).pipe(asVoid);
166
+ sessionBarrier = barrier;
167
+ sessionBarrierPending = true;
168
+ yield* forkChild(await_(fiber).pipe(andThen(sync(() => {
169
+ running.delete(fiber);
170
+ if (sessionBarrier === barrier) sessionBarrierPending = false;
171
+ }))));
172
+ return;
173
+ }
174
+ const task = sessionBarrierPending ? sessionBarrier.pipe(andThen(forward(line, envelope))) : forward(line, envelope);
175
+ return yield* launch(task);
176
+ });
177
+ const reader = NodeReadline.createInterface({ input: options.input });
178
+ yield* runForEach(fromAsyncIterable(reader, bridgeError), dispatch).pipe(catchCause(() => void_));
179
+ yield* awaitAll(running);
180
+ });
181
+ }
182
+ /**
183
+ * Kept free of heavy imports: these commands run on the ACP first-message
184
+ * critical path.
185
+ */
186
+ async function runAcpMcpCliFastPath(command, args) {
187
+ const endpoint = process.env.T3_ACP_MCP_ENDPOINT;
188
+ const authorization = process.env.T3_ACP_MCP_AUTHORIZATION;
189
+ if (endpoint === void 0 || authorization === void 0) {
190
+ process.stderr.write(`${command} requires T3_ACP_MCP_ENDPOINT and T3_ACP_MCP_AUTHORIZATION.\n`);
191
+ process.exitCode = 2;
192
+ return;
193
+ }
194
+ if (command === "acp-mcp-bridge") {
195
+ await runPromise(runAcpMcpStdioBridge({
196
+ endpoint,
197
+ authorization,
198
+ input: process.stdin,
199
+ output: process.stdout
200
+ }));
201
+ return;
202
+ }
203
+ const [tool, argumentsJson] = args;
204
+ if (tool === void 0 || argumentsJson === void 0) {
205
+ process.stderr.write("acp-mcp-call requires <tool> and <arguments-json>.\n");
206
+ process.exitCode = 2;
207
+ return;
208
+ }
209
+ let parsed;
210
+ try {
211
+ parsed = JSON.parse(argumentsJson);
212
+ } catch {
213
+ process.stderr.write("acp-mcp-call arguments must be valid JSON.\n");
214
+ process.exitCode = 2;
215
+ return;
216
+ }
217
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
218
+ process.stderr.write("acp-mcp-call arguments must be a JSON object.\n");
219
+ process.exitCode = 2;
220
+ return;
221
+ }
222
+ const result = await runPromise(callAcpMcpTool({
223
+ endpoint,
224
+ authorization,
225
+ tool,
226
+ arguments: parsed
227
+ }));
228
+ process.stdout.write(`${JSON.stringify(result)}\n`);
229
+ }
230
+ //#endregion
231
+ export { runAcpMcpStdioBridge as i, callAcpMcpTool as n, runAcpMcpCliFastPath as r, AcpMcpBridgeError as t };
232
+
233
+ //# sourceMappingURL=AcpMcpStdioBridge-ZWAIz2dT.mjs.map
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+
3
+ export { r as runAcpMcpCliFastPath } from "./AcpMcpStdioBridge-ZWAIz2dT.mjs";
@@ -0,0 +1,185 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Ma as currentTimeNanos$1, Oa as clockWith$1, co as monotonicTimeNanos$1, ja as currentTimeMillis$1, ya as ClockRef } from "./Effect-DXlc4A9S.mjs";
4
+ //#region ../../node_modules/.pnpm/effect@4.0.5/node_modules/effect/dist/Clock.js
5
+ /**
6
+ * Context reference for the active time service in the environment.
7
+ *
8
+ * **When to use**
9
+ *
10
+ * Use when you need to access or provide the full time service, including sleep
11
+ * operations, rather than a single timestamp accessor.
12
+ *
13
+ * **Example** (Accessing the Clock service)
14
+ *
15
+ * ```ts import.meta.vitest
16
+ * import { Clock, Effect } from "effect"
17
+ *
18
+ * const testClock: Clock.Clock = {
19
+ * currentTimeMillisUnsafe: () => 1_000,
20
+ * currentTimeMillis: Effect.succeed(1_000),
21
+ * monotonicTimeNanosUnsafe: () => 1_000_000_000n,
22
+ * monotonicTimeNanos: Effect.succeed(1_000_000_000n),
23
+ * currentTimeNanosUnsafe: () => 1_000_000_000n,
24
+ * currentTimeNanos: Effect.succeed(1_000_000_000n),
25
+ * sleep: () => Effect.void
26
+ * }
27
+ *
28
+ * const program = Effect.gen(function*() {
29
+ * const clock = yield* Clock.Clock
30
+ * return clock.currentTimeMillisUnsafe()
31
+ * })
32
+ *
33
+ * await Effect.runPromise(Effect.provideService(program, Clock.Clock, testClock)) // => 1_000
34
+ * ```
35
+ *
36
+ * @see {@link clockWith} for using the current Clock service inside an effect
37
+ * @see {@link currentTimeMillis} for reading the current time in milliseconds
38
+ * @see {@link currentTimeNanos} for reading the current time in nanoseconds
39
+ *
40
+ * @stability stable
41
+ * @category services
42
+ * @since 2.0.0
43
+ */
44
+ const Clock = ClockRef;
45
+ /**
46
+ * Accesses the current Clock service and uses it to run the provided function.
47
+ *
48
+ * **When to use**
49
+ *
50
+ * Use when you need the full Clock service interface to perform multiple time
51
+ * operations or call unsafe variants within a single effect.
52
+ *
53
+ * **Example** (Accessing the current Clock service)
54
+ *
55
+ * ```ts import.meta.vitest
56
+ * import { Clock, Effect } from "effect"
57
+ *
58
+ * const testClock: Clock.Clock = {
59
+ * currentTimeMillisUnsafe: () => 1_000,
60
+ * currentTimeMillis: Effect.succeed(1_000),
61
+ * monotonicTimeNanosUnsafe: () => 1_000_000_000n,
62
+ * monotonicTimeNanos: Effect.succeed(1_000_000_000n),
63
+ * currentTimeNanosUnsafe: () => 1_000_000_000n,
64
+ * currentTimeNanos: Effect.succeed(1_000_000_000n),
65
+ * sleep: () => Effect.void
66
+ * }
67
+ *
68
+ * const program = Clock.clockWith((clock) => Effect.sync(() => clock.currentTimeMillisUnsafe()))
69
+ *
70
+ * await Effect.runPromise(Effect.provideService(program, Clock.Clock, testClock)) // => 1_000
71
+ * ```
72
+ *
73
+ * @see {@link Clock} for the service reference
74
+ * @see {@link currentTimeMillis} for convenience accessor that returns milliseconds
75
+ * @see {@link currentTimeNanos} for convenience accessor that returns nanoseconds
76
+ * @stability stable
77
+ * @category accessors
78
+ * @since 2.0.0
79
+ */
80
+ const clockWith = clockWith$1;
81
+ /**
82
+ * Returns an Effect that succeeds with the current Unix time in milliseconds.
83
+ *
84
+ * **When to use**
85
+ *
86
+ * Use to create wall-clock timestamps from the active `Clock` service with
87
+ * millisecond precision.
88
+ *
89
+ * **Gotchas**
90
+ *
91
+ * The value can move backward or forward when the system wall clock is
92
+ * corrected, so it is not suitable for measuring elapsed time.
93
+ *
94
+ * **Example** (Reading milliseconds)
95
+ *
96
+ * ```ts import.meta.vitest
97
+ * import { Clock, Effect } from "effect"
98
+ *
99
+ * const testClock: Clock.Clock = {
100
+ * currentTimeMillisUnsafe: () => 1_000,
101
+ * currentTimeMillis: Effect.succeed(1_000),
102
+ * monotonicTimeNanosUnsafe: () => 1_000_000_000n,
103
+ * monotonicTimeNanos: Effect.succeed(1_000_000_000n),
104
+ * currentTimeNanosUnsafe: () => 1_000_000_000n,
105
+ * currentTimeNanos: Effect.succeed(1_000_000_000n),
106
+ * sleep: () => Effect.void
107
+ * }
108
+ *
109
+ * await Effect.runPromise(Effect.provideService(Clock.currentTimeMillis, Clock.Clock, testClock)) // => 1_000
110
+ * ```
111
+ *
112
+ * @see {@link currentTimeNanos} for nanosecond precision
113
+ * @see {@link monotonicTimeNanos} for measuring elapsed time
114
+ * @see {@link clockWith} for accessing the full Clock service
115
+ *
116
+ * @stability stable
117
+ * @category accessors
118
+ * @since 2.0.0
119
+ */
120
+ const currentTimeMillis = currentTimeMillis$1;
121
+ /**
122
+ * Returns an Effect that succeeds with the current Unix time in nanoseconds.
123
+ *
124
+ * **When to use**
125
+ *
126
+ * Use to create wall-clock timestamps from the active `Clock` service with
127
+ * nanosecond precision.
128
+ *
129
+ * **Gotchas**
130
+ *
131
+ * The value can move backward or forward when the system wall clock is
132
+ * corrected, so it is not suitable for measuring elapsed time.
133
+ * The live clock allows up to one second of drift from `Date.now()` before
134
+ * re-anchoring.
135
+ *
136
+ * **Example** (Reading nanoseconds)
137
+ *
138
+ * ```ts import.meta.vitest
139
+ * import { Clock, Effect } from "effect"
140
+ *
141
+ * const testClock: Clock.Clock = {
142
+ * currentTimeMillisUnsafe: () => 1_000,
143
+ * currentTimeMillis: Effect.succeed(1_000),
144
+ * monotonicTimeNanosUnsafe: () => 1_000_000_000n,
145
+ * monotonicTimeNanos: Effect.succeed(1_000_000_000n),
146
+ * currentTimeNanosUnsafe: () => 1_000_000_000n,
147
+ * currentTimeNanos: Effect.succeed(1_000_000_000n),
148
+ * sleep: () => Effect.void
149
+ * }
150
+ *
151
+ * await Effect.runPromise(Effect.provideService(Clock.currentTimeNanos, Clock.Clock, testClock)) // => 1_000_000_000n
152
+ * ```
153
+ *
154
+ * @see {@link monotonicTimeNanos} for measuring elapsed time
155
+ *
156
+ * @stability stable
157
+ * @category accessors
158
+ * @since 2.0.0
159
+ */
160
+ const currentTimeNanos = currentTimeNanos$1;
161
+ /**
162
+ * Returns an Effect that succeeds with the current monotonic time in
163
+ * nanoseconds.
164
+ *
165
+ * **When to use**
166
+ *
167
+ * Use to measure elapsed time by subtracting two readings.
168
+ *
169
+ * **Gotchas**
170
+ *
171
+ * The value has an arbitrary origin and is unsuitable for serialization. Use
172
+ * it only to subtract readings produced by the same clock. Whether it advances
173
+ * while the host is suspended depends on the runtime.
174
+ *
175
+ * @see {@link currentTimeNanos} for Unix wall-clock timestamps
176
+ *
177
+ * @stability stable
178
+ * @category accessors
179
+ * @since 4.0.0
180
+ */
181
+ const monotonicTimeNanos = monotonicTimeNanos$1;
182
+ //#endregion
183
+ export { monotonicTimeNanos as a, currentTimeNanos as i, clockWith as n, currentTimeMillis as r, Clock as t };
184
+
185
+ //# sourceMappingURL=Clock-B88OfuDl.mjs.map