pinomad 0.9.1 → 0.11.0
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 +11 -9
- package/dist/{chunk-v414b5pp.js → chunk-44pnts98.js} +2 -2
- package/dist/{chunk-nj5gz6qh.js → chunk-4dcs8sbj.js} +11 -9
- package/dist/{chunk-n8cz7skh.js → chunk-67gq282t.js} +53 -32
- package/dist/{chunk-azarj0f4.js → chunk-6d16c2fv.js} +21 -11
- package/dist/{chunk-cx8jgpdt.js → chunk-9h5vawnm.js} +1040 -79
- package/dist/{chunk-029mmh7d.js → chunk-as6pyf00.js} +3 -3
- package/dist/chunk-b457q0tm.js +70 -0
- package/dist/chunk-etf7ef97.js +55 -0
- package/dist/chunk-greb3dp6.js +22 -0
- package/dist/chunk-gtdpjqa3.js +317 -0
- package/dist/chunk-h5q2y57m.js +20 -0
- package/dist/{chunk-4sepcfpy.js → chunk-jt34g8st.js} +2 -2
- package/dist/chunk-n1m1tjrk.js +214 -0
- package/dist/{chunk-3p1eysm9.js → chunk-ncbqa8jk.js} +5 -4
- package/dist/{chunk-sygeb9qb.js → chunk-pqe7q1s7.js} +1 -1
- package/dist/{chunk-fqgvf8v0.js → chunk-sd5fkxjj.js} +1 -1
- package/dist/{chunk-5gp9svzs.js → chunk-t91zt5f0.js} +4 -53
- package/dist/{chunk-vax4zspw.js → chunk-tj57aqav.js} +3 -3
- package/dist/{chunk-32g3m2h0.js → chunk-vvj9b1gc.js} +29 -24
- package/dist/{chunk-jgd38rna.js → chunk-xqycs43g.js} +171 -171
- package/dist/{chunk-khcpv54k.js → chunk-y127fe1a.js} +59 -4
- package/dist/pinomad.js +18 -12
- package/package.json +1 -1
- package/web/assets/index-BhHrKpoo.js +395 -0
- package/web/index.html +1 -1
- package/dist/chunk-3gcpzpjq.js +0 -16
- package/dist/chunk-n58m5hgh.js +0 -170
- package/web/assets/index-1g60bhv2.js +0 -395
package/README.md
CHANGED
|
@@ -16,21 +16,23 @@ A self-hosted coding agent built on [Pi Durable](https://www.npmjs.com/package/@
|
|
|
16
16
|
|
|
17
17
|
## Quick start
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
1. **Create an account** at [app.pinomad.si](https://app.pinomad.si/) (sign-up is by invite).
|
|
20
|
+
2. **Add your host.** On the machine that should run the agent (macOS or Linux), run the two lines below. `pinomad up` prints a code; enter it on the page it opens, signed in, to add the host to your account. It then runs as a service.
|
|
20
21
|
|
|
21
|
-
```sh
|
|
22
|
-
|
|
23
|
-
pinomad
|
|
24
|
-
|
|
25
|
-
```
|
|
22
|
+
```sh
|
|
23
|
+
curl -fsSL https://pinomad.si/install.sh | sh
|
|
24
|
+
pinomad up
|
|
25
|
+
```
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
Already installed with npm? The script leaves that install alone; run `pinomad upgrade`, then `pinomad up`.
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
3. **Sign in on your other devices** (web, Mac app, iPhone). They pair with your hosts on their own; then connect a model provider under Settings → Providers.
|
|
30
|
+
|
|
31
|
+
To run without an account (one machine, LAN or tailnet, or your own server), see [Without an account](https://pinomad.si/docs/without-account/).
|
|
30
32
|
|
|
31
33
|
## Documentation
|
|
32
34
|
|
|
33
|
-
User docs live on **[pinomad.si/docs](https://pinomad.si/docs/)**: [getting started](https://pinomad.si/docs/) (
|
|
35
|
+
User docs live on **[pinomad.si/docs](https://pinomad.si/docs/)**: [getting started](https://pinomad.si/docs/) (account, adding hosts, devices, push), [your account](https://pinomad.si/docs/official-server/), [without an account](https://pinomad.si/docs/without-account/), and [what the agent can do](https://pinomad.si/docs/features/). Usage, remote access, and the service reference are in Chinese for now: [中文文档](https://pinomad.si/zh/docs/).
|
|
34
36
|
|
|
35
37
|
For contributors (in Chinese):
|
|
36
38
|
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
2
|
RTC_DEFAULT_STUN
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-xqycs43g.js";
|
|
4
4
|
import {
|
|
5
5
|
HOST_SETTING_KEYS,
|
|
6
6
|
cleanHostName,
|
|
7
7
|
isQueueMode,
|
|
8
8
|
isThinkingLevel,
|
|
9
9
|
normalizeHostName
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-pqe7q1s7.js";
|
|
11
11
|
|
|
12
12
|
// apps/host/src/host-value.ts
|
|
13
13
|
function constantValue(value) {
|
|
@@ -3,30 +3,32 @@ import {
|
|
|
3
3
|
assertSecureServerOrigin,
|
|
4
4
|
probeServerAccounts,
|
|
5
5
|
runServerOperation
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-ncbqa8jk.js";
|
|
7
7
|
import {
|
|
8
8
|
loadHostKey,
|
|
9
|
-
loadRelayKey
|
|
9
|
+
loadRelayKey
|
|
10
|
+
} from "./chunk-t91zt5f0.js";
|
|
11
|
+
import {
|
|
10
12
|
readServerConfig,
|
|
11
13
|
removeServerConfig
|
|
12
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-etf7ef97.js";
|
|
13
15
|
import {
|
|
14
16
|
relayHostId
|
|
15
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-y127fe1a.js";
|
|
16
18
|
import {
|
|
17
19
|
argValue,
|
|
18
20
|
restartService,
|
|
19
21
|
serviceManager,
|
|
20
22
|
withoutRelayArgs
|
|
21
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-vvj9b1gc.js";
|
|
24
|
+
import"./chunk-jt34g8st.js";
|
|
22
25
|
import"./chunk-kzbzacz9.js";
|
|
23
|
-
import"./chunk-
|
|
24
|
-
import"./chunk-
|
|
25
|
-
import"./chunk-jgd38rna.js";
|
|
26
|
-
import"./chunk-sygeb9qb.js";
|
|
26
|
+
import"./chunk-xqycs43g.js";
|
|
27
|
+
import"./chunk-pqe7q1s7.js";
|
|
27
28
|
import {
|
|
28
29
|
DEFAULT_DATA_DIR
|
|
29
30
|
} from "./chunk-ngf1zatm.js";
|
|
31
|
+
import"./chunk-sd5fkxjj.js";
|
|
30
32
|
import"./chunk-df32avw6.js";
|
|
31
33
|
|
|
32
34
|
// apps/host/src/cli/leave.ts
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
serveWebClient
|
|
4
|
-
} from "./chunk-wb10efyq.js";
|
|
5
2
|
import {
|
|
6
3
|
Published,
|
|
7
4
|
constantValue,
|
|
8
5
|
openHostSettings,
|
|
9
6
|
sameList,
|
|
10
7
|
settingsDefaults
|
|
11
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-44pnts98.js";
|
|
12
9
|
import {
|
|
13
10
|
DevicesDoc,
|
|
14
11
|
RevocationsDoc,
|
|
@@ -16,21 +13,22 @@ import {
|
|
|
16
13
|
ensureDevices,
|
|
17
14
|
loadHostKey,
|
|
18
15
|
loadRelayKey,
|
|
16
|
+
pairingOffers
|
|
17
|
+
} from "./chunk-t91zt5f0.js";
|
|
18
|
+
import {
|
|
19
19
|
normalizeOrigin,
|
|
20
|
-
pairingOffers,
|
|
21
20
|
readServerBinding,
|
|
22
21
|
readServerConfig,
|
|
23
22
|
resolveRelayOrigin
|
|
24
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-etf7ef97.js";
|
|
24
|
+
import {
|
|
25
|
+
serveWebClient
|
|
26
|
+
} from "./chunk-wb10efyq.js";
|
|
25
27
|
import {
|
|
26
28
|
relayHostId,
|
|
27
29
|
relayWsBase,
|
|
28
30
|
startRelayLink
|
|
29
|
-
} from "./chunk-
|
|
30
|
-
import {
|
|
31
|
-
packagedVersion,
|
|
32
|
-
webRoot
|
|
33
|
-
} from "./chunk-fqgvf8v0.js";
|
|
31
|
+
} from "./chunk-y127fe1a.js";
|
|
34
32
|
import {
|
|
35
33
|
ATTACHMENT_TTL_MS,
|
|
36
34
|
INVALID_FRAME_CLOSE_CODE,
|
|
@@ -56,7 +54,7 @@ import {
|
|
|
56
54
|
rtcCandidateType,
|
|
57
55
|
sdpCandidates,
|
|
58
56
|
withRtcCandidates
|
|
59
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-xqycs43g.js";
|
|
60
58
|
import {
|
|
61
59
|
ENDPOINT_SET_SCHEMA_VERSION,
|
|
62
60
|
MAX_HOST_ENDPOINT_URL_LENGTH,
|
|
@@ -72,10 +70,14 @@ import {
|
|
|
72
70
|
parseEndpointSet,
|
|
73
71
|
respondIK,
|
|
74
72
|
toBase64Url
|
|
75
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-pqe7q1s7.js";
|
|
76
74
|
import {
|
|
77
75
|
DEFAULT_DATA_DIR
|
|
78
76
|
} from "./chunk-ngf1zatm.js";
|
|
77
|
+
import {
|
|
78
|
+
packagedVersion,
|
|
79
|
+
webRoot
|
|
80
|
+
} from "./chunk-sd5fkxjj.js";
|
|
79
81
|
import {
|
|
80
82
|
__require
|
|
81
83
|
} from "./chunk-df32avw6.js";
|
|
@@ -3355,6 +3357,14 @@ async function startGateway(options) {
|
|
|
3355
3357
|
};
|
|
3356
3358
|
let remote;
|
|
3357
3359
|
let relay;
|
|
3360
|
+
const closeDevice = (publicKey) => {
|
|
3361
|
+
for (const connection of [...connections]) {
|
|
3362
|
+
if (connection.devicePublicKey === publicKey) {
|
|
3363
|
+
connection.closeConnection(UNAUTHORIZED_CLOSE_CODE, "device revoked");
|
|
3364
|
+
}
|
|
3365
|
+
}
|
|
3366
|
+
rtc?.closeDevice(publicKey);
|
|
3367
|
+
};
|
|
3358
3368
|
const currentAdvertisement = () => {
|
|
3359
3369
|
const advertiseUrl = remote?.advertiseUrl;
|
|
3360
3370
|
const endpoints = remoteEndpointCandidates({
|
|
@@ -3381,14 +3391,7 @@ async function startGateway(options) {
|
|
|
3381
3391
|
rtc?.closeOwner(self);
|
|
3382
3392
|
self.dispose();
|
|
3383
3393
|
},
|
|
3384
|
-
closeDevice
|
|
3385
|
-
for (const connection2 of [...connections]) {
|
|
3386
|
-
if (connection2.devicePublicKey === publicKey) {
|
|
3387
|
-
connection2.closeConnection(UNAUTHORIZED_CLOSE_CODE, "device revoked");
|
|
3388
|
-
}
|
|
3389
|
-
}
|
|
3390
|
-
rtc?.closeDevice(publicKey);
|
|
3391
|
-
},
|
|
3394
|
+
closeDevice,
|
|
3392
3395
|
rtcOffer: (owner, key, attempt, sdp) => {
|
|
3393
3396
|
if (rtc === undefined)
|
|
3394
3397
|
throw new Error("WebRTC is not available on this host");
|
|
@@ -3462,7 +3465,8 @@ async function startGateway(options) {
|
|
|
3462
3465
|
acceptAccountDevices: () => options.settings.value.acceptAccountDevices,
|
|
3463
3466
|
serverBinding: async () => await readServerBinding(options.dataDir).catch(() => {
|
|
3464
3467
|
return;
|
|
3465
|
-
})
|
|
3468
|
+
}),
|
|
3469
|
+
accountAdmitted: (requestId, publicKey) => relay?.reportAdmitted(requestId, publicKey)
|
|
3466
3470
|
};
|
|
3467
3471
|
const secure = options.secure;
|
|
3468
3472
|
const handshakeHandlers = {
|
|
@@ -3515,6 +3519,16 @@ async function startGateway(options) {
|
|
|
3515
3519
|
});
|
|
3516
3520
|
if (secure?.relay !== undefined) {
|
|
3517
3521
|
const relayOrigin = secure.relay.origin;
|
|
3522
|
+
const currentBinding = async () => {
|
|
3523
|
+
const config = await readServerConfig(options.dataDir).catch(() => {
|
|
3524
|
+
return;
|
|
3525
|
+
});
|
|
3526
|
+
if (config?.binding === undefined)
|
|
3527
|
+
return { refused: "not_joined" };
|
|
3528
|
+
if (normalizeOrigin(config.origin) !== normalizeOrigin(relayOrigin))
|
|
3529
|
+
return { refused: "rebinding" };
|
|
3530
|
+
return { binding: config.binding };
|
|
3531
|
+
};
|
|
3518
3532
|
let link;
|
|
3519
3533
|
link = startRelayLink({
|
|
3520
3534
|
origin: relayOrigin,
|
|
@@ -3527,17 +3541,12 @@ async function startGateway(options) {
|
|
|
3527
3541
|
},
|
|
3528
3542
|
subscribe: (listener) => options.settings.subscribe((settings) => listener(settings.hostName))
|
|
3529
3543
|
},
|
|
3530
|
-
accountOffer: async () => {
|
|
3544
|
+
accountOffer: async (requestId) => {
|
|
3531
3545
|
if (!options.settings.value.acceptAccountDevices)
|
|
3532
3546
|
return { ok: false, reason: "disabled" };
|
|
3533
|
-
const
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
if (config?.binding === undefined)
|
|
3537
|
-
return { ok: false, reason: "not_joined" };
|
|
3538
|
-
if (normalizeOrigin(config.origin) !== normalizeOrigin(relayOrigin)) {
|
|
3539
|
-
return { ok: false, reason: "rebinding" };
|
|
3540
|
-
}
|
|
3547
|
+
const bound = await currentBinding();
|
|
3548
|
+
if ("refused" in bound)
|
|
3549
|
+
return { ok: false, reason: bound.refused };
|
|
3541
3550
|
let endpointSet;
|
|
3542
3551
|
try {
|
|
3543
3552
|
const current = checkedEndpointSet(currentAdvertisement().endpoints);
|
|
@@ -3545,9 +3554,18 @@ async function startGateway(options) {
|
|
|
3545
3554
|
} catch {
|
|
3546
3555
|
return { ok: false, reason: "invalid_endpoint" };
|
|
3547
3556
|
}
|
|
3548
|
-
const { secret, expiresAt } = secure.offers.createAccount(
|
|
3557
|
+
const { secret, expiresAt } = secure.offers.createAccount(bound.binding, requestId);
|
|
3549
3558
|
return { ok: true, secret, expiresAt, ...endpointSet === undefined ? {} : { endpointSet } };
|
|
3550
3559
|
},
|
|
3560
|
+
deviceReports: {
|
|
3561
|
+
revoke: async (publicKey) => {
|
|
3562
|
+
const bound = await currentBinding();
|
|
3563
|
+
if ("refused" in bound)
|
|
3564
|
+
throw new Error(`revocation refused: ${bound.refused}`);
|
|
3565
|
+
await revokeDevice(options.harness, publicKey, context3);
|
|
3566
|
+
closeDevice(publicKey);
|
|
3567
|
+
}
|
|
3568
|
+
},
|
|
3551
3569
|
onStateChange: (state) => {
|
|
3552
3570
|
if (state.status === "registered") {
|
|
3553
3571
|
const push = state.push === undefined ? "undeclared" : state.push.length === 0 ? "none" : state.push.join(",");
|
|
@@ -3817,6 +3835,9 @@ function secureHandshake(carrier, secure, policy, handlers) {
|
|
|
3817
3835
|
carrier.close(UNAUTHORIZED_CLOSE_CODE, "unauthorized");
|
|
3818
3836
|
return;
|
|
3819
3837
|
}
|
|
3838
|
+
if (decision.outcome === "admitted" && decision.requestId !== undefined) {
|
|
3839
|
+
policy.accountAdmitted(decision.requestId, deviceKey);
|
|
3840
|
+
}
|
|
3820
3841
|
const { message, result: result2 } = responder.writeMessage2(encodeHostHello({ v: 1 }));
|
|
3821
3842
|
return {
|
|
3822
3843
|
result: result2,
|
|
@@ -2,30 +2,38 @@
|
|
|
2
2
|
import {
|
|
3
3
|
restartService,
|
|
4
4
|
serviceManager
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-vvj9b1gc.js";
|
|
6
|
+
import"./chunk-jt34g8st.js";
|
|
6
7
|
import"./chunk-kzbzacz9.js";
|
|
8
|
+
import"./chunk-xqycs43g.js";
|
|
9
|
+
import"./chunk-pqe7q1s7.js";
|
|
10
|
+
import {
|
|
11
|
+
hostAddressOptions
|
|
12
|
+
} from "./chunk-ngf1zatm.js";
|
|
7
13
|
import {
|
|
8
14
|
globalPrefixOf,
|
|
9
15
|
packageDir,
|
|
10
16
|
packagedVersion
|
|
11
|
-
} from "./chunk-
|
|
12
|
-
import"./chunk-4sepcfpy.js";
|
|
13
|
-
import"./chunk-jgd38rna.js";
|
|
14
|
-
import"./chunk-sygeb9qb.js";
|
|
15
|
-
import {
|
|
16
|
-
hostAddressOptions
|
|
17
|
-
} from "./chunk-ngf1zatm.js";
|
|
17
|
+
} from "./chunk-sd5fkxjj.js";
|
|
18
18
|
import"./chunk-df32avw6.js";
|
|
19
19
|
|
|
20
20
|
// apps/host/src/cli/upgrade.ts
|
|
21
21
|
import { execFile, spawn } from "node:child_process";
|
|
22
|
+
import { existsSync } from "node:fs";
|
|
23
|
+
import { dirname, join } from "node:path";
|
|
22
24
|
import { fileURLToPath } from "node:url";
|
|
23
25
|
import { parseArgs, promisify } from "node:util";
|
|
24
26
|
var exec = promisify(execFile);
|
|
25
27
|
var repoRoot = fileURLToPath(new URL("../../../../", import.meta.url));
|
|
26
|
-
var step = (command, args) => new Promise((resolve) => {
|
|
27
|
-
|
|
28
|
+
var step = (command, args, binDir) => new Promise((resolve) => {
|
|
29
|
+
const env = binDir === undefined ? process.env : { ...process.env, PATH: `${binDir}:${process.env.PATH ?? ""}` };
|
|
30
|
+
spawn(command, [...args], { cwd: repoRoot, env, stdio: "inherit" }).once("exit", (code) => resolve(code ?? 1));
|
|
28
31
|
});
|
|
32
|
+
function npmBeside(execPath) {
|
|
33
|
+
const binDir = dirname(execPath);
|
|
34
|
+
const cli = join(binDir, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js");
|
|
35
|
+
return existsSync(cli) ? { command: execPath, args: [cli], binDir } : { command: "npm", args: [] };
|
|
36
|
+
}
|
|
29
37
|
var serviceInstalled = () => Promise.resolve().then(() => serviceManager().state()).then((state) => state.installed, () => false);
|
|
30
38
|
async function main(argv, deps = {}) {
|
|
31
39
|
const { values } = parseArgs({
|
|
@@ -60,7 +68,8 @@ async function main(argv, deps = {}) {
|
|
|
60
68
|
process.exitCode = 1;
|
|
61
69
|
return;
|
|
62
70
|
}
|
|
63
|
-
const
|
|
71
|
+
const npm = npmBeside(process.execPath);
|
|
72
|
+
const code = await runStep(npm.command, [...npm.args, "install", "-g", "--prefix", prefix, "pinomad@latest"], npm.binDir);
|
|
64
73
|
if (code !== 0) {
|
|
65
74
|
process.exitCode = code;
|
|
66
75
|
return;
|
|
@@ -75,5 +84,6 @@ async function main(argv, deps = {}) {
|
|
|
75
84
|
}
|
|
76
85
|
if (false) {}
|
|
77
86
|
export {
|
|
87
|
+
npmBeside,
|
|
78
88
|
main
|
|
79
89
|
};
|