pi-daddy 0.13.0 → 0.14.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/CHANGELOG.md CHANGED
@@ -12,6 +12,87 @@ 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.14.0 — `pi-daddy init`, and a startup line that names what it will and will not spawn
16
+
17
+ > **Reviewed before release by five independent agents, one hypothesis each. All five found something, and
18
+ > nine defects were fixed here** — including one that executed arbitrary code from the file this feature
19
+ > tells you to commit (R-78), one that overwrote an operator's file and wrote through symlinks (R-79), and
20
+ > one where the startup line blamed your `SKILL.md` files for a misconfigured environment variable (R-81).
21
+ > **ADR-0029 came out of that review**: the generated grant is read-only by default. The reasoning for each
22
+ > is in `docs/03-risks.md` R-78 through R-82.
23
+
24
+ The pi-daddy half of making this package and a package of skills work together out of the box
25
+ (`docs/HANDOFF-principal-pi-skills-integration.md`, items B1/B2/B4; **ADR-0028**). Nothing about grant
26
+ resolution, enforcement, approvals or the ledger changed — this is the part before and around them.
27
+
28
+ - **The generated grant is READ-ONLY by default** (ADR-0029). `init` grants what the copied skills declare
29
+ minus anything that can change your machine — `bash`, `write`, `edit` and the universal capabilities are
30
+ written **commented**, naming the definitions that need them. `init` + `source` gives a working read-only
31
+ setup; widening costs one deliberate uncomment. The reason: `PI_GRANTS_GRANT` is what *bounds* a declared
32
+ ceiling, so generating it from those ceilings would give the bound and the bounded one author, and it
33
+ would not be you.
34
+
35
+ - **`npx pi-daddy init` scaffolds a governed project.** It reads `<cwd>/node_modules` for packages declaring
36
+ skills in their own `package.json` (`"pi": {"skills": [...]}`, pi's convention), copies each declared
37
+ `SKILL.md` into `.pi/skills/`, and writes an annotated `.pi/grants.env`. That replaces, per skill: make a
38
+ directory, copy the body, hand-write frontmatter, choose a capability set with no guidance, and assemble a
39
+ `PI_GRANTS_GRANT` string by hand — seven times for `principal-pi-skills`.
40
+
41
+ **It chooses no ceiling, and that boundary is the whole design.** A skill that declares `allowed-tools` is
42
+ copied byte for byte; one that declares none is copied with a *commented* placeholder and stays
43
+ unspawnable until a human fills it in. The placeholder is deliberately not a working example, so
44
+ uncommenting it unedited fails loudly instead of granting something nobody decided. An existing file is
45
+ **kept**, never overwritten — that edit is the capability decision, and a second `init` run is exactly
46
+ when it would be destroyed. `--force` exists and says what it costs.
47
+
48
+ - **Session start says how many definitions are spawnable, and names the withheld ones.** The line reported
49
+ the grant and never the definitions, so *"governance is working"* and *"did the install fail?"* looked
50
+ identical:
51
+
52
+ ```
53
+ grants: 1 of 7 definitions spawnable — review
54
+ withheld: architect, build, … — need agent:architect, …, which this session does not hold
55
+ ```
56
+
57
+ Classified by the same planner a real spawn comes through (no human is asked, stored approvals count), and
58
+ it speaks even when **nothing** is spawnable — which is the state most worth being told about. It is an
59
+ upper bound: it runs before the tool surface is observed, and `/grants` is the settled answer.
60
+
61
+ - **A worked `principal-pi-skills` example in the README**, replacing the invented one, with every line
62
+ produced by running the commands (`docs/probes/b2-init-principal-pi-skills`).
63
+
64
+ - **Fixed before release: a skill's `allowed-tools` VALUE could execute code from the generated grant file**
65
+ (R-78). `ceilingForDefinition` passes `ext:`/`skill:`/`agent:` entries through as written — correct for
66
+ enforcement, where the catalog refuses what it does not know — so a package declaring
67
+ `allowed-tools: Read,ext:x";touch /tmp/pwned;PI_GRANTS_GRANT="` produced a `.pi/grants.env` that ran the
68
+ payload when sourced: silently, exit 0, with the variable left looking plausible. It survives
69
+ `--ignore-scripts` and travels in the file you commit. Declared ids are whitelisted now, `tool:*`/`agent:*`
70
+ from a package are refused, and the assembled grant is charset-checked before the file is written at all.
71
+
72
+ - **Fixed before release: `init` overwrote an operator's file and wrote through symlinks** (R-79). The
73
+ presence probe was `readFile`, which treats *unreadable* as *absent* — so a permissions-restricted
74
+ `SKILL.md` was replaced and its ceiling **widened**, with no `--force`. And `writeFile` follows symlinks, so
75
+ a dangling link at a target path created the file outside the project while reporting an in-project path.
76
+ Both are one `open(path, "wx")`. `--force` no longer regenerates `.pi/grants.env`, and `pi-daddy init
77
+ --Force` is no longer accepted as a silent no-op.
78
+
79
+ - **Fixed before release: the startup line blamed your files for a session-level refusal** (R-81). A session
80
+ at its depth limit, or with a malformed `PI_GRANTS_MAX_DEPTH`, was told its `SKILL.md` files were written
81
+ wrong — two lines above `/grants` saying "delegation is disabled (maxDepth 0)". A session with no
82
+ `tool:delegate`, which has no delegate tool at all, was told definitions were spawnable.
83
+
84
+ - **Fixed before release: a skill's directory name could write a capability into the generated grant**
85
+ (R-77). A name is interpolated into a comma-separated `PI_GRANTS_GRANT`, into a file the operator sources,
86
+ and into a path. A package shipping a directory called `a,tool:bash` produced
87
+ `PI_GRANTS_GRANT="agent:a,tool:bash,…"` — `tool:bash` in an operator's grant, declared by no definition.
88
+ Names are now whitelisted at discovery and a refusal is printed with its reason.
89
+
90
+ - **Fixed before release: `npx pi-daddy init` printed nothing and exited 0 for every installed copy** (R-73).
91
+ npm installs a bin as a symlink, so `process.argv[1]` is the link and the entry-point guard compared it
92
+ against the real file's URL. Caught by the smoke test, which now runs the installed bin — the same class of
93
+ defect as the `exports` map that worked in the tree and threw for every consumer, and the second time that
94
+ script has caught it.
95
+
15
96
  ## 0.13.0 — the approvals file gets the lock the ledger already had, and two silences end
16
97
 
17
98
  Closing the last items that were open rather than out of scope, then **red-teaming the result**: an
package/README.md CHANGED
@@ -8,7 +8,7 @@ configured.
8
8
  Both qualifiers are load-bearing and are not buried: a child granted `bash` can escape governance entirely
9
9
  (ADR-0012, measured), and the ledger is opt-in. See *What this governs, and what it does not*.
10
10
 
11
- > **0.13.0 is the first published release.** Earlier versions were developed in-repo and never shipped, so
11
+ > **0.13.0 was the first published release.** Earlier versions were developed in-repo and never shipped, so
12
12
  > the breaking changes in the changelog describe how this package arrived at its current behaviour rather
13
13
  > than anything you need to migrate from.
14
14
  >
@@ -300,9 +300,13 @@ as the record of that run and are not a description of this version.
300
300
  PI_GRANTS_GRANT="agent:review,tool:read,tool:grep,tool:find,tool:ls,tool:delegate" \
301
301
  PI_GRANTS_LEDGER=.pi/grants.jsonl \
302
302
  PI_GRANTS_MAX_DEPTH=2 \
303
- pi -e ./extensions/grants.ts
303
+ pi
304
304
  ```
305
305
 
306
+ **Plain `pi`, no `-e`, when you installed this from npm** — the package declares `pi.extensions` and pi
307
+ auto-loads it (verified by execution). `-e ./extensions/grants.ts` is for running from a **clone** of the
308
+ repository, where there is no `node_modules/pi-daddy` for pi to find.
309
+
306
310
  `/grants` shows the session's grant, its depth, the catalog by kind, and an allow/BLOCK verdict per known
307
311
  definition — computed by **the same function a real spawn uses**, so the diagnostic cannot disagree with the
308
312
  enforcer. That is not cosmetic, and it has been got wrong twice. R-28 was a `/grants` that reported "allow"
@@ -327,6 +331,97 @@ digest, each compared against the file on disk (`current` / `CHANGED since`), wh
327
331
  back, so a torn line was indistinguishable from a spawn that never happened. A corrupt line is **evidence**
328
332
  and is left alone rather than repaired. Nothing runs this check automatically.
329
333
 
334
+ ## Worked example: governing `principal-pi-skills`
335
+
336
+ The abstract examples above use invented definitions. This one uses the seven skills people actually have
337
+ installed. Every transcript below is **copied from a run**, not retyped — the run is
338
+ `docs/probes/b2-init-principal-pi-skills` (2026-08-17, `principal-pi-skills@2.3.1`, pi 0.84.1), and where
339
+ this section abridges output it says so.
340
+
341
+ ```bash
342
+ npm install pi-daddy principal-pi-skills
343
+ npx pi-daddy init
344
+ ```
345
+
346
+ ```
347
+ found principal-pi-skills@2.3.1 — 7 skill(s), 0 declaring allowed-tools
348
+ wrote .pi/skills/decide/SKILL.md
349
+ … six more `wrote` lines, one per skill …
350
+ wrote .pi/grants.env
351
+
352
+ 7 skill(s) declare no allowed-tools and cannot be spawned until they do: decide, architect, plan,
353
+ build, review, debug, git-ops. Each copy carries a commented `allowed-tools:` line. pi-daddy does
354
+ not choose ceilings — that decision is what you review and commit, so it is yours to write.
355
+
356
+ Live grant (1 capabilities): tool:delegate
357
+ ```
358
+
359
+ **That is the honest state today, and the zero is the interesting number.** `principal-pi-skills@2.3.1` —
360
+ the published version — declares `allowed-tools` on none of its seven skills, so none of them is spawnable
361
+ and `init` says so rather than inventing capability sets to make its output look better. (It is being fixed
362
+ at the source, in their PR #30; until that ships, this is what `npm install` gives you.) `init` did the
363
+ mechanical work — seven directories, seven copies, the grant file — and left the one decision that has to be
364
+ a human's.
365
+
366
+ You make it, in the file. This is the copy `init` wrote for `decide`, with its commented block elided, and
367
+ the ceiling is the one `principal-pi-skills` PR #30 settled on by re-deriving it from the skill's own body:
368
+
369
+ ```diff
370
+ ---
371
+ name: decide
372
+ description: >
373
+ Use when a decision needs making …
374
+ # pi-daddy: this skill declares no `allowed-tools`, so it CANNOT be spawned as a governed sub-agent —
375
+ … four more comment lines …
376
+ - # allowed-tools: <list the tools this skill needs, e.g. Read, Grep>
377
+ + allowed-tools: read, grep, find, ls
378
+ ---
379
+ ```
380
+
381
+ and in `.pi/grants.env`, whose `PI_GRANTS_GRANT` line `init` wrote as `"tool:delegate"` — you add the rest:
382
+
383
+ ```sh
384
+ export PI_GRANTS_GRANT="agent:decide,tool:read,tool:grep,tool:find,tool:ls,tool:delegate"
385
+ ```
386
+
387
+ ```bash
388
+ source .pi/grants.env && pi
389
+ ```
390
+
391
+ ```
392
+ grants: depth 0/2, holding [agent:decide, tool:read, tool:grep, tool:find, tool:ls, tool:delegate]
393
+ grants: 1 of 7 definitions spawnable — decide
394
+ withheld: architect (needs agent:architect); build (needs agent:build); debug (needs agent:debug);
395
+ git-ops (needs agent:git-ops); plan (needs agent:plan); review (needs agent:review)
396
+ ```
397
+
398
+ The second line is the one worth having. A `decide` sub-agent that **physically cannot write** is a
399
+ different object from one that has been asked not to — and now that is enforced by `--tools` rather than
400
+ requested in prose. The other six are visibly withheld, each naming its own missing capability, which is the
401
+ difference between *governance is working* and *did the install fail?*
402
+
403
+ **`decide` and not `review`, and the reason is worth a sentence.** An earlier version of this section used
404
+ `review` as the read-only example and sourced that to its description saying *"Reports findings; never
405
+ edits"* — **a string that appears nowhere in `principal-pi-skills`**. It was invented for a demo file in
406
+ this repository and then cited back as their evidence. `review`'s real ceiling, settled upstream from its
407
+ body, is `read, grep, find, ls, bash`: it creates a disposable worktree and runs the tests, and denied
408
+ `bash` every verdict it returns is `UNVERIFIED`. The structurally read-only tier is `decide`, `architect`
409
+ and `plan`.
410
+
411
+ **Capabilities that can change your machine are written commented** (ADR-0029). When the seven skills do
412
+ declare their ceilings, `init` puts `tool:read`, `tool:grep` and friends in the live grant and writes
413
+ `tool:bash`, `tool:write` and `tool:edit` — plus the `agent:` ids of the definitions that need them — as
414
+ commented lines naming who asked for what. `init` + `source` gives you a working read-only setup; the wide
415
+ half costs one deliberate uncomment. The reason is that `PI_GRANTS_GRANT` is what *bounds* a declared
416
+ ceiling, so generating it from those same ceilings would give the bound and the bounded one author, and it
417
+ would not be you.
418
+
419
+ Two things this example does **not** claim. pi-daddy governs which **tools**, never which **paths**: a
420
+ `Write(docs/**)` is refused rather than reinterpreted, so *"an architect that may write an ADR but not your
421
+ source"* is not expressible — the honest choice is between a document-producing agent with real write power
422
+ and a read-only one that hands its output back for the parent to write. And the ceilings above are an
423
+ example, not a recommendation: what each skill needs is the skill author's call.
424
+
330
425
  ### The tripwire
331
426
 
332
427
  In a **governed** session the `tool_call` hook refuses third-party spawn tools (`Agent`, `subagent`,
@@ -511,9 +606,11 @@ Subpaths are exported individually (`pi-daddy/resolve`, `/ledger`, `/spawn`, `/d
511
606
  ```bash
512
607
  pi install npm:pi-daddy # as a pi extension
513
608
  npm i pi-daddy # as a library (the resolver, ledger and spawn planner are pure)
609
+ npx pi-daddy init # as a command: scaffold .pi/skills/ and .pi/grants.env from installed
610
+ # skill packages — see the worked example above
514
611
  ```
515
612
 
516
- The package is both. pi loads `extensions/grants.ts` through its own transpiling loader, which reads
613
+ The package is all three. pi loads `extensions/grants.ts` through its own transpiling loader, which reads
517
614
  TypeScript from `node_modules` quite happily; **Node does not** — it refuses to strip types under
518
615
  `node_modules` — so the library entry points are compiled to `dist/`. Until 0.6.0 `exports` pointed at
519
616
  `./src/*.ts`, and every consumer import failed with `ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING` while
@@ -523,10 +620,11 @@ every in-repo test passed. `npm run test:smoke` packs a tarball, installs it int
523
620
  ## Testing
524
621
 
525
622
  ```bash
526
- npm test # 292 unit tests. Fast, pure, no pi, no network.
623
+ npm test # 353 unit tests. Fast, pure, no pi, no network.
527
624
  npm run typecheck # src + extensions + tests + integration tests
528
- npm run test:integration # 23 tests against a REAL pi process. ~32s, no model tokens.
529
- npm run test:smoke # pack, install into a scratch project, import and use it
625
+ npm run test:integration # 28 tests against a REAL pi process. ~40s, no model tokens.
626
+ npm run test:smoke # pack, install into a scratch project, import and use it — and run the
627
+ # installed `pi-daddy init` bin, which is how R-73 was found
530
628
  PI_GRANTS_IT_MODEL=1 npm run test:integration # + 4 end-to-end tests with a real model. ~60s, costs money.
531
629
  ```
532
630
 
@@ -552,7 +650,7 @@ its own author the day after it was added: rather than raise the cap, `delegatio
552
650
 
553
651
  ## Status
554
652
 
555
- **0.13.0 — usable, and honest about scope.** What exists and is verified against real pi: the resolver, the
653
+ **0.14.0 — usable, and honest about scope.** What exists and is verified against real pi: the resolver, the
556
654
  ledger with an integrity reader, the spawn planner, `SKILL.md` definitions with `allowed-tools` as an
557
655
  enforced ceiling, `delegate` and `delegate_all` with a subtree budget, two executors, and human approval for
558
656
  gated capabilities (once / session / always, inheritable down the tree, persisted for `always` and pinned to
package/dist/catalog.d.ts CHANGED
@@ -69,6 +69,15 @@ export declare function buildCatalog(input: {
69
69
  * stale grant referring to an uninstalled package. Silently treating unknown as denied hides that.
70
70
  */
71
71
  export declare function unknownCapabilities(requested: Capability[], catalog: Catalog): Capability[];
72
+ /**
73
+ * The capability an unknown one was most likely meant to be, or null when nothing is close enough.
74
+ *
75
+ * Two sources, in order. A known foreign name wins outright — `Glob` is not a typo for `find`, so no
76
+ * distance metric would ever connect them, and that is exactly the case worth naming. Otherwise the
77
+ * nearest catalog entry within a small edit distance, which catches `raed`/`serach` and stops well short
78
+ * of guessing: the threshold scales with the name's length and never exceeds two.
79
+ */
80
+ export declare function suggestForUnknown(unknown: Capability, catalog: Catalog): Capability | null;
72
81
  /**
73
82
  * Skill name -> absolute path, for `planSpawn`'s `--skill` flags (R-32).
74
83
  *
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEzE,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/D,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,WAAW,GAAG,OAAO,GAAG,WAAW,CAAC;AAE7E,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,UAAU,CAAC;IACvB,IAAI,EAAE,cAAc,CAAC;IACrB,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,OAAO;IACtB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,0CAA0C;IAC1C,GAAG,EAAE,UAAU,EAAE,CAAC;IAClB,MAAM,CAAC,IAAI,EAAE,cAAc,GAAG,UAAU,EAAE,CAAC;IAC3C,GAAG,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC;CACtC;AAED,gFAAgF;AAChF,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,YAAY,EAAE,CAMpE;AAED,+CAA+C;AAC/C,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAE/C;AAED;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CA+BrE;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,YAAY,EAAE,CAM3F;AAED,mFAAmF;AACnF,wBAAgB,WAAW,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,OAAO,CAY5D;AAED,qGAAqG;AACrG,wBAAsB,YAAY,CAAC,KAAK,EAAE;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;CAChC,GAAG,OAAO,CAAC,OAAO,CAAC,CAkBnB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,EAAE,OAAO,GAAG,UAAU,EAAE,CAQ3F;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAO9E"}
1
+ {"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAEzE,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/D,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,WAAW,GAAG,OAAO,GAAG,WAAW,CAAC;AAE7E,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,UAAU,CAAC;IACvB,IAAI,EAAE,cAAc,CAAC;IACrB,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,OAAO;IACtB,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,0CAA0C;IAC1C,GAAG,EAAE,UAAU,EAAE,CAAC;IAClB,MAAM,CAAC,IAAI,EAAE,cAAc,GAAG,UAAU,EAAE,CAAC;IAC3C,GAAG,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC;CACtC;AAED,gFAAgF;AAChF,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,YAAY,EAAE,CAMpE;AAED,+CAA+C;AAC/C,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAE/C;AAED;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,CA+BrE;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,YAAY,EAAE,CAM3F;AAED,mFAAmF;AACnF,wBAAgB,WAAW,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,OAAO,CAY5D;AAED,qGAAqG;AACrG,wBAAsB,YAAY,CAAC,KAAK,EAAE;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;CAChC,GAAG,OAAO,CAAC,OAAO,CAAC,CAkBnB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,UAAU,EAAE,EAAE,OAAO,EAAE,OAAO,GAAG,UAAU,EAAE,CAQ3F;AA6DD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,UAAU,GAAG,IAAI,CAuB1F;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAO9E"}
package/dist/catalog.js CHANGED
@@ -144,6 +144,96 @@ export function unknownCapabilities(requested, catalog) {
144
144
  // unspawnable from any grant. The wildcard is live only at the root without this.
145
145
  return requested.filter((c) => c !== WILDCARD && c !== AGENT_WILDCARD && !catalog.has(c)).sort();
146
146
  }
147
+ /**
148
+ * Tool names that exist in OTHER harnesses' vocabularies, mapped to the pi tool that does the same job.
149
+ *
150
+ * This is a hint for an error message and nothing else. `ceilingForDefinition` deliberately refuses to
151
+ * translate names — lowercasing and no more — because a translation table there would have to decide what
152
+ * `Glob` *means* and would either invent a grant or silently drop one. Naming a likely intent in the
153
+ * refusal costs nothing and keeps that property: the delegation is still refused, and the author still
154
+ * edits the file.
155
+ *
156
+ * Populated from the names an author actually reaches for. `allowed-tools` is an Agent Skills field, so
157
+ * the frontmatter people copy in is usually written against Claude Code's toolset; `Glob` is the one that
158
+ * bit a real consumer (principal-pi-skills, seven definitions), because pi's equivalent is `find`.
159
+ */
160
+ const FOREIGN_TOOL_NAMES = {
161
+ "tool:glob": "tool:find",
162
+ "tool:searchfiles": "tool:find",
163
+ "tool:bashtool": "tool:bash",
164
+ "tool:readfile": "tool:read",
165
+ "tool:writefile": "tool:write",
166
+ "tool:str_replace_editor": "tool:edit",
167
+ "tool:multiedit": "tool:edit",
168
+ };
169
+ /**
170
+ * Optimal string alignment distance — Levenshtein plus adjacent transposition.
171
+ *
172
+ * Transposition counts as ONE edit, not two, because it is the typo people actually make: `raed` for
173
+ * `read` is a single slip of the fingers, and plain Levenshtein scores it 2 — the same as two unrelated
174
+ * substitutions. With the threshold this small, that difference is the whole feature.
175
+ */
176
+ function editDistance(a, b) {
177
+ // Three rows, because a transposition needs the row before last.
178
+ const rows = [
179
+ Array.from({ length: b.length + 1 }, (_, j) => j),
180
+ new Array(b.length + 1).fill(0),
181
+ new Array(b.length + 1).fill(0),
182
+ ];
183
+ let twoBack = rows[2];
184
+ let prev = rows[0];
185
+ let cur = rows[1];
186
+ for (let i = 1; i <= a.length; i++) {
187
+ cur[0] = i;
188
+ for (let j = 1; j <= b.length; j++) {
189
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
190
+ let d = Math.min(prev[j] + 1, cur[j - 1] + 1, prev[j - 1] + cost);
191
+ if (i > 1 && j > 1 && a[i - 1] === b[j - 2] && a[i - 2] === b[j - 1]) {
192
+ d = Math.min(d, twoBack[j - 2] + 1);
193
+ }
194
+ cur[j] = d;
195
+ }
196
+ const spent = twoBack;
197
+ twoBack = prev;
198
+ prev = cur;
199
+ cur = spent;
200
+ }
201
+ return prev[b.length];
202
+ }
203
+ /**
204
+ * The capability an unknown one was most likely meant to be, or null when nothing is close enough.
205
+ *
206
+ * Two sources, in order. A known foreign name wins outright — `Glob` is not a typo for `find`, so no
207
+ * distance metric would ever connect them, and that is exactly the case worth naming. Otherwise the
208
+ * nearest catalog entry within a small edit distance, which catches `raed`/`serach` and stops well short
209
+ * of guessing: the threshold scales with the name's length and never exceeds two.
210
+ */
211
+ export function suggestForUnknown(unknown, catalog) {
212
+ const foreign = FOREIGN_TOOL_NAMES[unknown.toLowerCase()];
213
+ if (foreign && catalog.has(foreign))
214
+ return foreign;
215
+ // Only among capabilities of the same namespace: suggesting `skill:review` for a mistyped tool name
216
+ // would be a worse message than none, because it points the author at the wrong kind of fix.
217
+ const ns = unknown.slice(0, unknown.indexOf(":") + 1);
218
+ if (!ns)
219
+ return null;
220
+ const bare = unknown.slice(ns.length);
221
+ const limit = Math.min(2, Math.floor(bare.length / 3));
222
+ if (limit < 1)
223
+ return null;
224
+ let best = null;
225
+ let bestDistance = limit + 1;
226
+ for (const candidate of catalog.all) {
227
+ if (!candidate.startsWith(ns))
228
+ continue;
229
+ const d = editDistance(bare, candidate.slice(ns.length));
230
+ if (d < bestDistance) {
231
+ bestDistance = d;
232
+ best = candidate;
233
+ }
234
+ }
235
+ return bestDistance <= limit ? best : null;
236
+ }
147
237
  /**
148
238
  * Skill name -> absolute path, for `planSpawn`'s `--skill` flags (R-32).
149
239
  *
@@ -1 +1 @@
1
- {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"catalog.js","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,eAAe,EAAwB,MAAM,kBAAkB,CAAC;AACzE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAmB,MAAM,cAAc,CAAC;AAmB/D,gFAAgF;AAChF,MAAM,UAAU,iBAAiB,CAAC,QAAkB;IAClD,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAS,gBAAgB,CAAC,CAAC;IACnD,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAClD,UAAU,EAAE,QAAQ,IAAI,EAAE;QAC1B,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAE,SAAmB,CAAC,CAAC,CAAE,WAAqB;KACzE,CAAC,CAAC,CAAC;AACN,CAAC;AAED,+CAA+C;AAC/C,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;AACjF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAW;IAC1C,MAAM,KAAK,GAAG,IAAI,GAAG,EAAwB,CAAC;IAC9C,KAAK,MAAM,GAAG,IAAI,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;QACjC,IAAI,KAAe,CAAC;QACpB,IAAI,CAAC;YACH,KAAK,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC;QAAC,MAAM,CAAC;YACP,SAAS,CAAC,8BAA8B;QAC1C,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;YAChC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YAC7B,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC9B,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;oBACvB,MAAM,KAAK,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAc,CAAC,CAAC;oBAC9D,IAAI,KAAK,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;wBACnD,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,SAAS,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;oBAChF,CAAC;gBACH,CAAC;qBAAM,IAAI,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;oBAChC,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;oBACxC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;wBACtB,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,UAAU,EAAE,SAAS,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;oBAClF,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,6FAA6F;gBAC7F,yBAAyB;YAC3B,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;AAC7B,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,WAAyC;IACzE,OAAO,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAC3C,UAAU,EAAE,SAAS,CAAC,CAAC,IAAI,EAAE;QAC7B,IAAI,EAAE,WAAoB;QAC1B,MAAM,EAAE,CAAC,CAAC,MAAM;KACjB,CAAC,CAAC,CAAC;AACN,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,WAAW,CAAC,OAAuB;IACjD,MAAM,OAAO,GAAG,IAAI,GAAG,EAA4B,CAAC;IACpD,KAAK,MAAM,KAAK,IAAI,OAAO;QAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC;YAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IACtG,MAAM,IAAI,GAAG,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC;IAC5F,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IAC3B,OAAO;QACL,OAAO,EAAE,IAAI;QACb,GAAG,EAAE,GAAG;QACR,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC;QAC9E,GAAG,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,CAAC;KAC3C,CAAC;AACJ,CAAC;AAED,qGAAqG;AACrG,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,KAGlC;IACC,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,eAAe,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACrG,OAAO,WAAW,CAAC;QACjB,kGAAkG;QAClG,mGAAmG;QACnG,mGAAmG;QACnG,oGAAoG;QACpG,wCAAwC;QACxC,EAAE;QACF,mGAAmG;QACnG,oGAAoG;QACpG,oGAAoG;QACpG,uFAAuF;QACvF,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,UAAU,EAAE,QAAQ,IAAI,EAAW,EAAE,IAAI,EAAE,SAAkB,EAAE,CAAC,CAAC;QACtG,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,iBAAiB,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACtE,GAAG,MAAM;QACT,GAAG,iBAAiB,CAAC,WAAW,CAAC;KAClC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CAAC,SAAuB,EAAE,OAAgB;IAC3E,qGAAqG;IACrG,wGAAwG;IACxG,yGAAyG;IACzG,iGAAiG;IACjG,qGAAqG;IACrG,kFAAkF;IAClF,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,cAAc,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AACnG,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,kBAAkB,GAAqC;IAC3D,WAAW,EAAE,WAAW;IACxB,kBAAkB,EAAE,WAAW;IAC/B,eAAe,EAAE,WAAW;IAC5B,eAAe,EAAE,WAAW;IAC5B,gBAAgB,EAAE,YAAY;IAC9B,yBAAyB,EAAE,WAAW;IACtC,gBAAgB,EAAE,WAAW;CAC9B,CAAC;AAEF;;;;;;GAMG;AACH,SAAS,YAAY,CAAC,CAAS,EAAE,CAAS;IACxC,iEAAiE;IACjE,MAAM,IAAI,GAAe;QACvB,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QACjD,IAAI,KAAK,CAAS,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACvC,IAAI,KAAK,CAAS,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;KACxC,CAAC;IACF,IAAI,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,IAAI,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACnB,IAAI,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IAElB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACnC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACX,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACnC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC3C,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;YAClE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;gBACrE,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACtC,CAAC;YACD,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACb,CAAC;QACD,MAAM,KAAK,GAAG,OAAO,CAAC;QACtB,OAAO,GAAG,IAAI,CAAC;QACf,IAAI,GAAG,GAAG,CAAC;QACX,GAAG,GAAG,KAAK,CAAC;IACd,CAAC;IACD,OAAO,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AACxB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAmB,EAAE,OAAgB;IACrE,MAAM,OAAO,GAAG,kBAAkB,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC1D,IAAI,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAC;IAEpD,oGAAoG;IACpG,6FAA6F;IAC7F,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IACtD,IAAI,CAAC,EAAE;QAAE,OAAO,IAAI,CAAC;IACrB,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;IACtC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;IACvD,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC;IAE3B,IAAI,IAAI,GAAsB,IAAI,CAAC;IACnC,IAAI,YAAY,GAAG,KAAK,GAAG,CAAC,CAAC;IAC7B,KAAK,MAAM,SAAS,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QACpC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;YAAE,SAAS;QACxC,MAAM,CAAC,GAAG,YAAY,CAAC,IAAI,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;QACzD,IAAI,CAAC,GAAG,YAAY,EAAE,CAAC;YACrB,YAAY,GAAG,CAAC,CAAC;YACjB,IAAI,GAAG,SAAS,CAAC;QACnB,CAAC;IACH,CAAC;IACD,OAAO,YAAY,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAgB;IACpD,MAAM,KAAK,GAA2B,EAAE,CAAC;IACzC,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACpC,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM;YAAE,SAAS;QACtD,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;IAChE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `pi-daddy` — the command line, which today has exactly one subcommand.
4
+ *
5
+ * Thin on purpose: argv in, `discoverSkillPackages` + `planInit` + `applyInit`, report out. Every decision
6
+ * lives in `./init.ts`, `./grant-env.ts` and `./skill-packages.ts` as functions that touch no argv and print
7
+ * nothing, so the scaffolding is testable without running a process — the same split `extensions/grants.ts`
8
+ * was cut along after four wiring bugs in a row lived in the part nothing could test.
9
+ *
10
+ * **`parseArgs` is exported and tested, which it was not** (R-79). This file shipped with zero tests and
11
+ * promptly earned two of them: an entry-point guard that was false for every installed copy (R-73), and an
12
+ * unknown-option check that exempted `argv[0]` whenever `--dir` was absent, so `pi-daddy init --Force`
13
+ * was accepted in silence — the exact failure the check's own comment says it prevents.
14
+ */
15
+ export interface ParsedArgs {
16
+ command: "init" | "help" | "version";
17
+ dir?: string;
18
+ force: boolean;
19
+ /** Non-empty means refuse: argv said something this program does not understand. */
20
+ errors: string[];
21
+ }
22
+ /**
23
+ * Parse argv. Pure, exported, and tested — argv handling is where both of this file's defects lived.
24
+ *
25
+ * Rule 8 throughout: an unrecognised option is refused rather than ignored, and `--dir` refuses a value
26
+ * that looks like a flag, because `init --dir --force` used to scaffold into a directory named `--force`
27
+ * with `force` simultaneously true.
28
+ */
29
+ export declare function parseArgs(argv: string[]): ParsedArgs;
30
+ export declare function main(argv: string[]): Promise<number>;
31
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;GAYG;AAyBH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACrC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,oFAAoF;IACpF,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAoCpD;AA4HD,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA0B1D"}