@edgehero/pi-dispatch 0.1.0 → 0.1.1
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/package.json +1 -1
- package/src/cli.mjs +3 -1
- package/src/flow-gate.mjs +5 -4
- package/src/init.mjs +1 -0
- package/src/materialize.mjs +4 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@edgehero/pi-dispatch",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Self-hosted job harness for the pi coding agent: a BullMQ worker that drains the queue, mints scoped forge tokens, and runs one container per job — plus the pi-dispatch CLI (init, up, doctor, service).",
|
|
6
6
|
"keywords": [
|
package/src/cli.mjs
CHANGED
|
@@ -36,7 +36,9 @@ const USAGE = `pi-dispatch — run pi coding-agent flows on your own folders
|
|
|
36
36
|
pi-dispatch resume resume taking jobs
|
|
37
37
|
pi-dispatch status show paused state + job counts
|
|
38
38
|
|
|
39
|
-
Config comes from the environment (see .env.example); flags override it per run
|
|
39
|
+
Config comes from the environment (see .env.example); flags override it per run.
|
|
40
|
+
Prefer being walked through all of this? The operator panel's /dispatch setup does every step
|
|
41
|
+
with a consent per action: pi install npm:@edgehero/pi-dispatch-admin`;
|
|
40
42
|
|
|
41
43
|
export async function main(argv = process.argv.slice(2), env = process.env) {
|
|
42
44
|
const cmd = argv[0];
|
package/src/flow-gate.mjs
CHANGED
|
@@ -30,10 +30,11 @@ const exec = promisify(execFile);
|
|
|
30
30
|
*/
|
|
31
31
|
|
|
32
32
|
// The skill name charset: lowercase kebab/underscore, 1-64 chars, no dots (so no "..") and no
|
|
33
|
-
// slashes.
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
|
|
33
|
+
// slashes. Validating `flow` against it BEFORE building any path is the traversal choke point: a
|
|
34
|
+
// bad name is denied, never interpolated into a git path. Exported as the single source of truth
|
|
35
|
+
// (issue #92): materialize.mjs imports it, and the admin's setup wizard lists a repo's .pi/skills
|
|
36
|
+
// through it — three keep-in-sync copies would drift exactly where a traversal guard cannot.
|
|
37
|
+
export const SKILL_NAME_RE = /^[a-z0-9](?:[a-z0-9_-]{0,62}[a-z0-9])?$/;
|
|
37
38
|
|
|
38
39
|
export async function readFlowGate({ folder, flow, sha, git = defaultGit }) {
|
|
39
40
|
// `sha` is REQUIRED and never defaulted: a missing SHA fails closed rather than resolving HEAD,
|
package/src/init.mjs
CHANGED
package/src/materialize.mjs
CHANGED
|
@@ -2,6 +2,7 @@ import { execFile } from "node:child_process";
|
|
|
2
2
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { dirname, isAbsolute, join, relative } from "node:path";
|
|
4
4
|
import { promisify } from "node:util";
|
|
5
|
+
import { SKILL_NAME_RE } from "./flow-gate.mjs";
|
|
5
6
|
|
|
6
7
|
const exec = promisify(execFile);
|
|
7
8
|
|
|
@@ -29,9 +30,10 @@ const PI_DIR = ".pi";
|
|
|
29
30
|
const APPEND_SYSTEM = `${PI_DIR}/APPEND_SYSTEM.md`;
|
|
30
31
|
// A skill directory name: lowercase kebab/underscore, 1-64 chars, no dots (so no "..") and no
|
|
31
32
|
// slashes. This is what makes a traversal name impossible at the source. Matched against the
|
|
32
|
-
// CAPTURED segment only, never the whole path.
|
|
33
|
+
// CAPTURED segment only, never the whole path. The name charset itself is imported from
|
|
34
|
+
// flow-gate.mjs (the exported single source of truth, issue #92); the path form stays local
|
|
35
|
+
// because only the materialiser walks whole tree paths.
|
|
33
36
|
const SKILL_PATH_RE = /^\.pi\/skills\/([a-z0-9](?:[a-z0-9_-]{0,62}[a-z0-9])?)\/SKILL\.md$/;
|
|
34
|
-
const SKILL_NAME_RE = /^[a-z0-9](?:[a-z0-9_-]{0,62}[a-z0-9])?$/;
|
|
35
37
|
|
|
36
38
|
/**
|
|
37
39
|
* Classify a git tree path into the destination we will WRITE, or null to reject.
|