my-durable 0.0.1 → 0.0.3
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 +19 -0
- package/bin/md.mjs +88 -0
- package/package.json +2 -4
- package/bin/device.mjs +0 -5
- package/bin/hub.mjs +0 -5
- package/bin/tui.mjs +0 -5
package/README.md
CHANGED
|
@@ -1,10 +1,29 @@
|
|
|
1
1
|
# Durable Pi: The Durable Agent Network
|
|
2
2
|
|
|
3
|
+
> [!NOTE]
|
|
4
|
+
> **This repository (`my-durable`) is a fork of [disler/durable-pi](https://github.com/disler/durable-pi) by [IndyDevDan](https://www.youtube.com/@indydevdan), MIT-licensed — see [LICENSE](LICENSE).** All credit for the original architecture, code and docs belongs to the upstream author; upstream history is preserved in the git log. This fork carries the Durable Agent Network hardening work on top: the Gate A security remediation (SSE CRLF coalescing, fail-closed v0 registry preflight with schema-drift refusal, tunnel/pairing/rotation hardening, FE sanitizer policies), the local verification tooling (`scripts/verify.mjs`), and the `my-durable` npm packaging.
|
|
5
|
+
|
|
3
6
|
> **Proactive agents start working before you sit down. They don't wait for you to work. They work for you, then wait.**
|
|
4
7
|
> Durable pi agents on any machine you own, driven from a web UI, a terminal or one curl.
|
|
5
8
|
|
|
6
9
|
📺 Watch this video to get the full breakdown of this codebase: **[Pi Durable PROACTIVE Agents](https://youtu.be/DNDYYHsypZg)**
|
|
7
10
|
|
|
11
|
+
## Quick start (`md`)
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
npm install -g my-durable
|
|
15
|
+
|
|
16
|
+
md hub # web UI + device tunnel server → http://127.0.0.1:4781
|
|
17
|
+
md device # device daemon (pairs to a hub, serves this machine)
|
|
18
|
+
md tui # terminal admin client
|
|
19
|
+
md --help # commands, flags and environment variables
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`md hub` is the only component that other machines talk to, so it is also the one
|
|
23
|
+
to put behind a TLS proxy or tunnel (it refuses anything that did not arrive over
|
|
24
|
+
HTTPS). Pair a device by opening the hub, pressing **Pair a device**, and entering
|
|
25
|
+
the code — or open the pairing link directly on the machine being added.
|
|
26
|
+
|
|
8
27
|
<p align="center">
|
|
9
28
|
<img src="images/01_durable_agent_network.svg" alt="Three clients (web UI, dpi-tui, curl) reach durable agents on four devices; the clients disconnect and every device keeps checkpointing its run to SQLite" width="850">
|
|
10
29
|
</p>
|
package/bin/md.mjs
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// `md` — one command for the Durable Pi stack.
|
|
3
|
+
// md hub [--port N] [--host H] [--public-host H] web UI + device tunnel server
|
|
4
|
+
// md device device-side daemon
|
|
5
|
+
// md tui terminal admin client
|
|
6
|
+
// Every subcommand runs the TypeScript entry through tsx, so no build step is needed.
|
|
7
|
+
import { access } from "node:fs/promises";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
|
|
10
|
+
/** Subcommand → TypeScript entry, relative to this file. */
|
|
11
|
+
const COMMANDS = {
|
|
12
|
+
hub: "../apps/dpi-playground/apps/dpi-playground-hub/src/main.ts",
|
|
13
|
+
device: "../apps/dpi-backend/src/main.ts",
|
|
14
|
+
tui: "../apps/dpi-tui/src/main.ts",
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const HELP = `md — Durable Pi
|
|
18
|
+
|
|
19
|
+
Usage:
|
|
20
|
+
md hub [--port 4781] [--host 127.0.0.1] [--public-host <host>]
|
|
21
|
+
Web UI + device tunnel server (devices dial this).
|
|
22
|
+
md device
|
|
23
|
+
Device-side daemon (pairs to a hub, serves one machine's agents).
|
|
24
|
+
md tui
|
|
25
|
+
Terminal admin client.
|
|
26
|
+
md help | md --help | md -h
|
|
27
|
+
md version | md --version | md -v
|
|
28
|
+
|
|
29
|
+
Environment (hub): DPI_HOME, DPI_HUB_PORT, DPI_HUB_HOST, DPI_HUB_PUBLIC_HOST,
|
|
30
|
+
DPI_HUB_ORIGIN, DPI_HUB_REQUIRE_TLS
|
|
31
|
+
Environment (device): DPI_HUB_URL, DPI_HOME
|
|
32
|
+
`;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* tsx is a dependency of the published package, but a bare repository checkout has it only
|
|
36
|
+
* inside the per-app node_modules. Try the normal resolution first, then the known local
|
|
37
|
+
* copies, so `md` works in both places without a root install.
|
|
38
|
+
*/
|
|
39
|
+
async function loadTsx() {
|
|
40
|
+
try {
|
|
41
|
+
return await import("tsx/esm/api");
|
|
42
|
+
} catch (error) {
|
|
43
|
+
if (error?.code !== "ERR_MODULE_NOT_FOUND") throw error;
|
|
44
|
+
}
|
|
45
|
+
const candidates = [
|
|
46
|
+
"../apps/dpi-playground/node_modules/tsx/dist/esm/api/index.mjs",
|
|
47
|
+
"../apps/dpi-backend/node_modules/tsx/dist/esm/api/index.mjs",
|
|
48
|
+
"../apps/dpi-sdk/node_modules/tsx/dist/esm/api/index.mjs",
|
|
49
|
+
"../apps/dpi-tui/node_modules/tsx/dist/esm/api/index.mjs",
|
|
50
|
+
];
|
|
51
|
+
for (const relative of candidates) {
|
|
52
|
+
const url = new URL(relative, import.meta.url);
|
|
53
|
+
try {
|
|
54
|
+
await access(fileURLToPath(url));
|
|
55
|
+
return await import(url.href);
|
|
56
|
+
} catch {
|
|
57
|
+
// try the next one
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
throw new Error(
|
|
61
|
+
"md: cannot find tsx. Install the package (npm install -g my-durable) or run npm install in an app directory.",
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const [first, ...rest] = process.argv.slice(2);
|
|
66
|
+
|
|
67
|
+
if (!first || first === "help" || first === "--help" || first === "-h") {
|
|
68
|
+
process.stdout.write(HELP);
|
|
69
|
+
process.exit(0);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (first === "version" || first === "--version" || first === "-v") {
|
|
73
|
+
const { readFileSync } = await import("node:fs");
|
|
74
|
+
const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
|
|
75
|
+
process.stdout.write(`md (my-durable) ${pkg.version}\n`);
|
|
76
|
+
process.exit(0);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (!Object.hasOwn(COMMANDS, first)) {
|
|
80
|
+
process.stderr.write(`md: unknown command '${first}'\n\n${HELP}`);
|
|
81
|
+
process.exit(2);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// The entries parse process.argv.slice(2) themselves: hand them their own args.
|
|
85
|
+
process.argv = [process.argv[0], process.argv[1], ...rest];
|
|
86
|
+
const { register } = await loadTsx();
|
|
87
|
+
register();
|
|
88
|
+
await import(COMMANDS[first]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "my-durable",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "Durable Pi — the durable agent network: hub web UI, device backend daemon, TUI admin and the shared SDK, packaged as one runnable monorepo install",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -15,9 +15,7 @@
|
|
|
15
15
|
"node": ">=22.0.0"
|
|
16
16
|
},
|
|
17
17
|
"bin": {
|
|
18
|
-
"
|
|
19
|
-
"my-durable-device": "bin/device.mjs",
|
|
20
|
-
"my-durable-tui": "bin/tui.mjs"
|
|
18
|
+
"md": "bin/md.mjs"
|
|
21
19
|
},
|
|
22
20
|
"scripts": {
|
|
23
21
|
"hub": "tsx apps/dpi-playground/apps/dpi-playground-hub/src/main.ts",
|
package/bin/device.mjs
DELETED
package/bin/hub.mjs
DELETED