pi-daddy 0.27.3 → 0.27.4

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/CHANGELOG.md CHANGED
@@ -12,6 +12,13 @@ the record of how the package got here and are worth keeping; they are not worth
12
12
  > the record of how the package arrived at what it does, and because the reasoning behind each one is
13
13
  > usually the clearest statement of why the current behaviour is what it is.
14
14
 
15
+ ## 0.27.4 — independent Herdr delegation names (2026-09-17)
16
+
17
+ - Generate a fresh execution suffix instead of a process-local counter, preventing parallel Pi parents
18
+ and extension reloads from reusing globally reserved Herdr agent names.
19
+ - Keep readable tab labels and valid agent names within Herdr's 32-character limit.
20
+ - Regression coverage exercises parallel processes and fresh module instances; grant and cleanup behavior is unchanged.
21
+
15
22
  ## 0.27.3 — visible completed delegation history (2026-09-15)
16
23
 
17
24
  - Show how many completed roots and children the compact ledger dashboard hides.
@@ -1,37 +1,3 @@
1
- /**
2
- * Naming a herdr agent: the grammar herdr enforces, and uniqueness it does not.
3
- *
4
- * Split out of `src/run-herdr.ts` at the 400-line ceiling, and a real seam: both rules below come from **herdr's
5
- * own validation and lifecycle**, not from anything this package decides. Two shipping defects lived here, and
6
- * both were invisible to every test because the unit fake accepts whatever name it is handed and the integration
7
- * suite never reaches a real herdr spawn. They surfaced from two real spawns against the live daemon.
8
- */
9
- /**
10
- * Make a herdr agent name that is **valid** and cannot collide with a live one.
11
- *
12
- * **Validity is a separate, PRE-EXISTING defect, and it is the more serious half.** Callers build a name as
13
- * `${definition}-${childId}`, and a ledger child id is hierarchical — `d0.1`, `d0.1.2` (ADR-0008/F8). Those dots
14
- * are **not in herdr's grammar**, so `agent start review-d0.1 …` is rejected with `invalid_agent_name`. Every
15
- * `delegate({agent})` on the herdr path has therefore failed at `agent start` since the executor was written.
16
- *
17
- * Nothing could see it. The unit fake accepts any name it is handed, and the integration suite never reaches a
18
- * real herdr spawn — so both were green while the feature could not work. It surfaced only by running two real
19
- * spawns against the live daemon, which is the argument for doing that at all.
20
- *
21
- * **Measured, and a shipping defect without it.** herdr binds an agent name to its **tab**, and only closing
22
- * the tab frees the name: a second `agent start` with a name still held returns
23
- * `agent_name_taken: agent <name> is already used; … tab_id=…`. `herdr agent stop` does not exist (see
24
- * `cleanup`), so nothing else releases it.
25
- *
26
- * Callers build a name from the definition and the ledger child id — and for a plain blocking `delegate` that
27
- * id is **constant** (`d0.1`, index 0 of the session), so every delegation in a session asked for the same
28
- * name. That was harmless while the pane closed at the end of each call. Once ADR-0032 kept panes alive to
29
- * `agent_settled`, the **first** delegation of a turn worked and every later one failed with
30
- * `agent_name_taken`, on the executor ADR-0031 had just made the default.
31
- *
32
- * Uniquified HERE rather than at the call site, so no caller can forget: the constraint belongs to herdr, and
33
- * this module is the only thing that talks to herdr. The suffix is a counter rather than a random token so a
34
- * pane label stays readable and reproducible within a run.
35
- */
1
+ /** Valid Herdr identity independent of process counters, parent labels and reloads. */
36
2
  export declare function uniqueAgentName(base: string): string;
37
3
  //# sourceMappingURL=herdr-name.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"herdr-name.d.ts","sourceRoot":"","sources":["../src/herdr-name.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAaH;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAapD"}
1
+ {"version":3,"file":"herdr-name.d.ts","sourceRoot":"","sources":["../src/herdr-name.ts"],"names":[],"mappings":"AASA,uFAAuF;AACvF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAUpD"}
@@ -1,59 +1,20 @@
1
1
  /**
2
- * Naming a herdr agent: the grammar herdr enforces, and uniqueness it does not.
3
- *
4
- * Split out of `src/run-herdr.ts` at the 400-line ceiling, and a real seam: both rules below come from **herdr's
5
- * own validation and lifecycle**, not from anything this package decides. Two shipping defects lived here, and
6
- * both were invisible to every test because the unit fake accepts whatever name it is handed and the integration
7
- * suite never reaches a real herdr spawn. They surfaced from two real spawns against the live daemon.
8
- */
9
- /** Monotonic within this process. See `uniqueAgentName`. */
10
- let spawnSeq = 0;
11
- /**
12
- * herdr's agent-name grammar, measured from its own rejection message.
13
- *
14
- * `agent name must start with a lowercase letter and contain only lowercase letters, digits, '-' or '_'
15
- * (1-32 characters)`.
2
+ * Herdr reserves agent names across all parents until their tabs close.
3
+ * A counter alone is process-local: parallel parents and module reloads repeat it.
4
+ * Keep the readable base separate from a fresh, 80-bit execution suffix.
16
5
  */
6
+ import { randomBytes } from "node:crypto";
17
7
  const AGENT_NAME_MAX = 32;
18
- /**
19
- * Make a herdr agent name that is **valid** and cannot collide with a live one.
20
- *
21
- * **Validity is a separate, PRE-EXISTING defect, and it is the more serious half.** Callers build a name as
22
- * `${definition}-${childId}`, and a ledger child id is hierarchical — `d0.1`, `d0.1.2` (ADR-0008/F8). Those dots
23
- * are **not in herdr's grammar**, so `agent start review-d0.1 …` is rejected with `invalid_agent_name`. Every
24
- * `delegate({agent})` on the herdr path has therefore failed at `agent start` since the executor was written.
25
- *
26
- * Nothing could see it. The unit fake accepts any name it is handed, and the integration suite never reaches a
27
- * real herdr spawn — so both were green while the feature could not work. It surfaced only by running two real
28
- * spawns against the live daemon, which is the argument for doing that at all.
29
- *
30
- * **Measured, and a shipping defect without it.** herdr binds an agent name to its **tab**, and only closing
31
- * the tab frees the name: a second `agent start` with a name still held returns
32
- * `agent_name_taken: agent <name> is already used; … tab_id=…`. `herdr agent stop` does not exist (see
33
- * `cleanup`), so nothing else releases it.
34
- *
35
- * Callers build a name from the definition and the ledger child id — and for a plain blocking `delegate` that
36
- * id is **constant** (`d0.1`, index 0 of the session), so every delegation in a session asked for the same
37
- * name. That was harmless while the pane closed at the end of each call. Once ADR-0032 kept panes alive to
38
- * `agent_settled`, the **first** delegation of a turn worked and every later one failed with
39
- * `agent_name_taken`, on the executor ADR-0031 had just made the default.
40
- *
41
- * Uniquified HERE rather than at the call site, so no caller can forget: the constraint belongs to herdr, and
42
- * this module is the only thing that talks to herdr. The suffix is a counter rather than a random token so a
43
- * pane label stays readable and reproducible within a run.
44
- */
8
+ /** Valid Herdr identity independent of process counters, parent labels and reloads. */
45
9
  export function uniqueAgentName(base) {
46
- spawnSeq += 1;
47
- const suffix = `-${spawnSeq}`;
10
+ const suffix = "-" + randomBytes(10).toString("hex");
48
11
  const cleaned = base
49
12
  .toLowerCase()
50
- .replace(/[^a-z0-9_-]+/g, "-") // dots from a child id, and anything else outside the grammar
13
+ .replace(/[^a-z0-9_-]+/g, "-")
51
14
  .replace(/-{2,}/g, "-")
52
- .replace(/^[^a-z]+/, ""); // must START with a lowercase letter, so a leading digit or dash goes
53
- // Truncated so the whole name fits, and trimmed of a trailing separator so the join stays readable. The
54
- // fallback covers a base that sanitises to nothing at all (a definition named entirely in non-Latin script).
15
+ .replace(/^[^a-z]+/, "");
55
16
  const room = AGENT_NAME_MAX - suffix.length;
56
17
  const head = cleaned.slice(0, room).replace(/[-_]+$/, "") || "agent";
57
- return `${head}${suffix}`;
18
+ return head + suffix;
58
19
  }
59
20
  //# sourceMappingURL=herdr-name.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"herdr-name.js","sourceRoot":"","sources":["../src/herdr-name.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,4DAA4D;AAC5D,IAAI,QAAQ,GAAG,CAAC,CAAC;AAEjB;;;;;GAKG;AACH,MAAM,cAAc,GAAG,EAAE,CAAC;AAE1B;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,QAAQ,IAAI,CAAC,CAAC;IACd,MAAM,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;IAC9B,MAAM,OAAO,GAAG,IAAI;SACjB,WAAW,EAAE;SACb,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC,8DAA8D;SAC5F,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC;SACtB,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,CAAC,sEAAsE;IAClG,wGAAwG;IACxG,6GAA6G;IAC7G,MAAM,IAAI,GAAG,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC;IAC5C,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,OAAO,CAAC;IACrE,OAAO,GAAG,IAAI,GAAG,MAAM,EAAE,CAAC;AAC5B,CAAC"}
1
+ {"version":3,"file":"herdr-name.js","sourceRoot":"","sources":["../src/herdr-name.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,cAAc,GAAG,EAAE,CAAC;AAE1B,uFAAuF;AACvF,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,MAAM,MAAM,GAAG,GAAG,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACrD,MAAM,OAAO,GAAG,IAAI;SACjB,WAAW,EAAE;SACb,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC;SAC7B,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC;SACtB,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC3B,MAAM,IAAI,GAAG,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC;IAC5C,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,OAAO,CAAC;IACrE,OAAO,IAAI,GAAG,MAAM,CAAC;AACvB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-daddy",
3
- "version": "0.27.3",
3
+ "version": "0.27.4",
4
4
  "description": "Capability governance for pi sub-agents: spawn Agent Skills (SKILL.md) definitions whose allowed-tools becomes a grant that can only narrow going down a delegation tree, enforced by pi's own --tools allowlist, with an append-only ledger.",
5
5
  "keywords": [
6
6
  "pi-package",
package/src/herdr-name.ts CHANGED
@@ -1,61 +1,21 @@
1
1
  /**
2
- * Naming a herdr agent: the grammar herdr enforces, and uniqueness it does not.
3
- *
4
- * Split out of `src/run-herdr.ts` at the 400-line ceiling, and a real seam: both rules below come from **herdr's
5
- * own validation and lifecycle**, not from anything this package decides. Two shipping defects lived here, and
6
- * both were invisible to every test because the unit fake accepts whatever name it is handed and the integration
7
- * suite never reaches a real herdr spawn. They surfaced from two real spawns against the live daemon.
2
+ * Herdr reserves agent names across all parents until their tabs close.
3
+ * A counter alone is process-local: parallel parents and module reloads repeat it.
4
+ * Keep the readable base separate from a fresh, 80-bit execution suffix.
8
5
  */
6
+ import { randomBytes } from "node:crypto";
9
7
 
10
- /** Monotonic within this process. See `uniqueAgentName`. */
11
- let spawnSeq = 0;
12
-
13
- /**
14
- * herdr's agent-name grammar, measured from its own rejection message.
15
- *
16
- * `agent name must start with a lowercase letter and contain only lowercase letters, digits, '-' or '_'
17
- * (1-32 characters)`.
18
- */
19
8
  const AGENT_NAME_MAX = 32;
20
9
 
21
- /**
22
- * Make a herdr agent name that is **valid** and cannot collide with a live one.
23
- *
24
- * **Validity is a separate, PRE-EXISTING defect, and it is the more serious half.** Callers build a name as
25
- * `${definition}-${childId}`, and a ledger child id is hierarchical — `d0.1`, `d0.1.2` (ADR-0008/F8). Those dots
26
- * are **not in herdr's grammar**, so `agent start review-d0.1 …` is rejected with `invalid_agent_name`. Every
27
- * `delegate({agent})` on the herdr path has therefore failed at `agent start` since the executor was written.
28
- *
29
- * Nothing could see it. The unit fake accepts any name it is handed, and the integration suite never reaches a
30
- * real herdr spawn — so both were green while the feature could not work. It surfaced only by running two real
31
- * spawns against the live daemon, which is the argument for doing that at all.
32
- *
33
- * **Measured, and a shipping defect without it.** herdr binds an agent name to its **tab**, and only closing
34
- * the tab frees the name: a second `agent start` with a name still held returns
35
- * `agent_name_taken: agent <name> is already used; … tab_id=…`. `herdr agent stop` does not exist (see
36
- * `cleanup`), so nothing else releases it.
37
- *
38
- * Callers build a name from the definition and the ledger child id — and for a plain blocking `delegate` that
39
- * id is **constant** (`d0.1`, index 0 of the session), so every delegation in a session asked for the same
40
- * name. That was harmless while the pane closed at the end of each call. Once ADR-0032 kept panes alive to
41
- * `agent_settled`, the **first** delegation of a turn worked and every later one failed with
42
- * `agent_name_taken`, on the executor ADR-0031 had just made the default.
43
- *
44
- * Uniquified HERE rather than at the call site, so no caller can forget: the constraint belongs to herdr, and
45
- * this module is the only thing that talks to herdr. The suffix is a counter rather than a random token so a
46
- * pane label stays readable and reproducible within a run.
47
- */
10
+ /** Valid Herdr identity independent of process counters, parent labels and reloads. */
48
11
  export function uniqueAgentName(base: string): string {
49
- spawnSeq += 1;
50
- const suffix = `-${spawnSeq}`;
12
+ const suffix = "-" + randomBytes(10).toString("hex");
51
13
  const cleaned = base
52
14
  .toLowerCase()
53
- .replace(/[^a-z0-9_-]+/g, "-") // dots from a child id, and anything else outside the grammar
15
+ .replace(/[^a-z0-9_-]+/g, "-")
54
16
  .replace(/-{2,}/g, "-")
55
- .replace(/^[^a-z]+/, ""); // must START with a lowercase letter, so a leading digit or dash goes
56
- // Truncated so the whole name fits, and trimmed of a trailing separator so the join stays readable. The
57
- // fallback covers a base that sanitises to nothing at all (a definition named entirely in non-Latin script).
17
+ .replace(/^[^a-z]+/, "");
58
18
  const room = AGENT_NAME_MAX - suffix.length;
59
19
  const head = cleaned.slice(0, room).replace(/[-_]+$/, "") || "agent";
60
- return `${head}${suffix}`;
20
+ return head + suffix;
61
21
  }