mulmoterminal 8.1.0 → 8.2.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.
Files changed (122) hide show
  1. package/blueprints/adopt/templates/chaff.yml +1 -1
  2. package/blueprints/docs/checks/chaff.sh +1 -1
  3. package/blueprints/docs/skills/workspace/SKILL.md +1 -1
  4. package/blueprints/from-collection/checks/actions.sh +10 -1
  5. package/blueprints/from-collection/skills/actions/SKILL.md +2 -1
  6. package/blueprints/from-collection/skills/actions-cloudflare/SKILL.md +2 -1
  7. package/blueprints/from-collection/skills/actions-firebase/SKILL.md +2 -1
  8. package/blueprints/from-collection/skills/actions-supabase/SKILL.md +2 -1
  9. package/blueprints/style/skills/report/SKILL.md +1 -1
  10. package/common/appActions.ts +1 -0
  11. package/common/blueprint/executorPolicy.ts +19 -3
  12. package/common/blueprint/run.ts +2 -0
  13. package/common/blueprint/stepPrompt.ts +68 -4
  14. package/common/keymap.ts +1 -0
  15. package/dist/assets/{abnfDiagram-O67JEVCF-ClxVnRku.js → abnfDiagram-O67JEVCF-DpKqOyjt.js} +1 -1
  16. package/dist/assets/architecture-7GRP2DOG-tqxhXA_W.js +1 -0
  17. package/dist/assets/{architectureDiagram-NJMV4G6O-DPbRnCKN.js → architectureDiagram-NJMV4G6O-BEf7hi8B.js} +1 -1
  18. package/dist/assets/{blockDiagram-BEXU5L5S-422fI4GC.js → blockDiagram-BEXU5L5S-Bs_qxpCN.js} +1 -1
  19. package/dist/assets/{c4Diagram-YGBWAQC7-htmTlUTG.js → c4Diagram-YGBWAQC7-Cxvi1yMd.js} +1 -1
  20. package/dist/assets/channel-B7Hqexxy.js +1 -0
  21. package/dist/assets/{chunk-3FUC2YCW-BbDEpgy0.js → chunk-3FUC2YCW-CLhlVcbE.js} +1 -1
  22. package/dist/assets/{chunk-5DYCD2WN-D97hkTCQ.js → chunk-5DYCD2WN-tnBh5bTj.js} +1 -1
  23. package/dist/assets/{chunk-742MDFTN-B3Mnh8e7.js → chunk-742MDFTN-BJTRk8eI.js} +1 -1
  24. package/dist/assets/{chunk-7INBJB4K-B5lqXrqb.js → chunk-7INBJB4K-Bg39tnTn.js} +1 -1
  25. package/dist/assets/{chunk-7M6MHVWA-DghPQFUI.js → chunk-7M6MHVWA-Dy7p4wXp.js} +1 -1
  26. package/dist/assets/{chunk-7PRAP22T-BdAaGYkh.js → chunk-7PRAP22T-hw-m893g.js} +1 -1
  27. package/dist/assets/{chunk-GTNCS2PH-DKvFKim8.js → chunk-GTNCS2PH-COevsxgA.js} +1 -1
  28. package/dist/assets/{chunk-GWA4HPMP-RTEdPAf3.js → chunk-GWA4HPMP-GF0g7kkY.js} +1 -1
  29. package/dist/assets/{chunk-MBY4JIJT-x_wqlXNe.js → chunk-MBY4JIJT-CUUZjNcR.js} +1 -1
  30. package/dist/assets/{chunk-NETBCI7D-8Cs1NIno.js → chunk-NETBCI7D-ClVuU0EM.js} +1 -1
  31. package/dist/assets/{chunk-O7XYJQB3-Dz4vrOLX.js → chunk-O7XYJQB3-Gutmfs0i.js} +1 -1
  32. package/dist/assets/{chunk-UA2S7LBM-Dwd6YCa2.js → chunk-UA2S7LBM-jOPSo4_W.js} +1 -1
  33. package/dist/assets/{chunk-WEXAMYUT-rY_Nsr-S.js → chunk-WEXAMYUT-ZT-XWGQ1.js} +1 -1
  34. package/dist/assets/{chunk-Z7XXMR3K-pt-6PBwB.js → chunk-Z7XXMR3K-9viSdvia.js} +1 -1
  35. package/dist/assets/{chunk-ZIGJFQKS-DzYvLxms.js → chunk-ZIGJFQKS-DK3D9aN6.js} +1 -1
  36. package/dist/assets/{classDiagram-v2-NBCMYWYE-DAAHQYjw.js → classDiagram-v2-NBCMYWYE-Cdjo_Ous.js} +1 -1
  37. package/dist/assets/{cynefin-OW5HDTMX-DTPNG3DO.js → cynefin-OW5HDTMX-D-a3gV2N.js} +1 -1
  38. package/dist/assets/{cynefinDiagram-VND7K2PF-BiNAmBAf.js → cynefinDiagram-VND7K2PF-DO5Mg4b5.js} +1 -1
  39. package/dist/assets/{dagre-6A5THRUB-C3aACS4M.js → dagre-6A5THRUB-DDZdk1F_.js} +1 -1
  40. package/dist/assets/{diagram-22UHCM2B-1moWpahw.js → diagram-22UHCM2B-_jTbmIND.js} +1 -1
  41. package/dist/assets/{diagram-3UASUU5V-CgsKz1ze.js → diagram-3UASUU5V-OPNBnJk-.js} +1 -1
  42. package/dist/assets/{diagram-ATOU4E4O-CtIrEsFG.js → diagram-ATOU4E4O-DTibMEtZ.js} +1 -1
  43. package/dist/assets/{diagram-CDSNMT55-BntC2VUx.js → diagram-CDSNMT55-DqnZQTDC.js} +1 -1
  44. package/dist/assets/{diagram-MLGK6HIB-Cdh5tBhw.js → diagram-MLGK6HIB-C8RWNVVB.js} +1 -1
  45. package/dist/assets/{diagram-MPIPVDR6-CQz7IrSH.js → diagram-MPIPVDR6-Bm7W9_aY.js} +1 -1
  46. package/dist/assets/{dist-PySjWJXd.js → dist-Bt6Uoh1p.js} +1 -1
  47. package/dist/assets/{dist-DANd2aqA.js → dist-CCEafgGi.js} +1 -1
  48. package/dist/assets/{dist--0LHNaYl.js → dist-CVg47SZ2.js} +1 -1
  49. package/dist/assets/{dist-DqudlEKF.js → dist-D4AUpaJv.js} +1 -1
  50. package/dist/assets/{dist-CkDbiiOe.js → dist-X9VE8etg.js} +1 -1
  51. package/dist/assets/{ebnfDiagram-ZINNZB2B-CZaPrV3v.js → ebnfDiagram-ZINNZB2B-CcP60K5m.js} +1 -1
  52. package/dist/assets/{elk-276RUBZZ-5V_Op3XR.js → elk-276RUBZZ-DQdydmIq.js} +1 -1
  53. package/dist/assets/{erDiagram-OPXOYQCR-flX7Jn68.js → erDiagram-OPXOYQCR-D3C2QS7R.js} +1 -1
  54. package/dist/assets/eventmodeling-NTZA5JFV-DFoSe9CC.js +1 -0
  55. package/dist/assets/flowDiagram-KWPJA3E3-B5HJ88J1.js +1 -0
  56. package/dist/assets/{ganttDiagram-FUAMR5RP-2KqutibO.js → ganttDiagram-FUAMR5RP-IZaW5VgA.js} +1 -1
  57. package/dist/assets/{gitGraph-4MIJSDKK-DVTDAI2J.js → gitGraph-4MIJSDKK-D3sAiw0g.js} +1 -1
  58. package/dist/assets/{gitGraphDiagram-X574FWY7-Btc5-wfa.js → gitGraphDiagram-X574FWY7-BKQ33CxX.js} +1 -1
  59. package/dist/assets/{index-8Aw0tzeQ.js → index-DjO9W8uQ.js} +310 -310
  60. package/dist/assets/index-ct_vF1PW.css +1 -0
  61. package/dist/assets/{info-A6RAGUB7-BX4xPahk.js → info-A6RAGUB7-CGT6OwbO.js} +1 -1
  62. package/dist/assets/{infoDiagram-VRGFBTTK-ng2eNzlm.js → infoDiagram-VRGFBTTK-f8idGmV5.js} +1 -1
  63. package/dist/assets/{ishikawaDiagram-OU5B5YK6-CnNc1uHK.js → ishikawaDiagram-OU5B5YK6-C3q9XWHW.js} +1 -1
  64. package/dist/assets/{journeyDiagram-ZHPQQLJL-BHr492DG.js → journeyDiagram-ZHPQQLJL-DZeP_NQJ.js} +1 -1
  65. package/dist/assets/{kanban-definition-PNTS6WVX-CD4FdLFL.js → kanban-definition-PNTS6WVX-Be2RPtgv.js} +1 -1
  66. package/dist/assets/{line-DwxnhfoI.js → line--V9C2ujH.js} +1 -1
  67. package/dist/assets/{mermaid-parser.core-DEnlY2ci.js → mermaid-parser.core-CA27Zh_E.js} +3 -3
  68. package/dist/assets/{mermaid.core-B7u-t6P9.js → mermaid.core-oKSvAMmn.js} +4 -4
  69. package/dist/assets/{mindmap-definition-NLK3R4M7-BdIcteCE.js → mindmap-definition-NLK3R4M7-Ds2mxwxS.js} +1 -1
  70. package/dist/assets/{packet-AYTQ26CC-DHisXteY.js → packet-AYTQ26CC-BQS2MXBT.js} +1 -1
  71. package/dist/assets/{pegDiagram-GJSIUBJH-DDOrA3Ua.js → pegDiagram-GJSIUBJH-05ZfyxXE.js} +1 -1
  72. package/dist/assets/{pie-WAS4IAKB-Ba76QqEP.js → pie-WAS4IAKB-BZzyas2W.js} +1 -1
  73. package/dist/assets/{pieDiagram-5QR66LMP-CNlravvW.js → pieDiagram-5QR66LMP-Dbp7Nolp.js} +1 -1
  74. package/dist/assets/{quadrantDiagram-O4NWA36T-B0D-BZQ2.js → quadrantDiagram-O4NWA36T-Cbqaez9d.js} +1 -1
  75. package/dist/assets/{radar-RG4KPBEZ-BCNuh25J.js → radar-RG4KPBEZ-EXcR8Xp9.js} +1 -1
  76. package/dist/assets/{railroad-74A4TZTK-CMJcxNfL.js → railroad-74A4TZTK-CDJiZrju.js} +1 -1
  77. package/dist/assets/railroad-abnf-HS5TGJTU-CjbPm8FI.js +1 -0
  78. package/dist/assets/railroad-ebnf-LZEXJU2U-BLPi2vqK.js +1 -0
  79. package/dist/assets/railroad-peg-WCYAUIDC-Bs_vw0dm.js +1 -0
  80. package/dist/assets/{railroadDiagram-XR7U4H2S-BpB8nxWt.js → railroadDiagram-XR7U4H2S-CsAiR60R.js} +1 -1
  81. package/dist/assets/{requirementDiagram-PLB6GJNP-CsB3aqu0.js → requirementDiagram-PLB6GJNP-CdQreqtO.js} +1 -1
  82. package/dist/assets/{sankeyDiagram-IPEJSGJF-BKGvK8Jv.js → sankeyDiagram-IPEJSGJF-BPGpWJ6l.js} +1 -1
  83. package/dist/assets/{sequenceDiagram-PO4LG4MO-Cr9hkQye.js → sequenceDiagram-PO4LG4MO-CYfCqmWa.js} +1 -1
  84. package/dist/assets/{stateDiagram-v2-GCMORJYK-C7gWKveV.js → stateDiagram-v2-GCMORJYK-BYmaqGf3.js} +1 -1
  85. package/dist/assets/{swimlanes-2SLR337P-iRnomZ6W.js → swimlanes-2SLR337P-D5eV_i9B.js} +1 -1
  86. package/dist/assets/swimlanesDiagram-TC7HE7FX-Bm--zlh6.js +8 -0
  87. package/dist/assets/{timeline-definition-EJHVYXUP-CvM8Zt_H.js → timeline-definition-EJHVYXUP-FCIIPMQE.js} +1 -1
  88. package/dist/assets/{treeView-Q6P3EWNA-B-3825bR.js → treeView-Q6P3EWNA-DjyFz21S.js} +1 -1
  89. package/dist/assets/{treemap-WGGIJYW6-wYDmmCoC.js → treemap-WGGIJYW6-C04a3IWf.js} +1 -1
  90. package/dist/assets/{usecaseDiagram-POWQR4AR-COfhzrb4.js → usecaseDiagram-POWQR4AR-DjWtJ5rd.js} +1 -1
  91. package/dist/assets/{vennDiagram-UO4OBE2U-DQz5w2Ad.js → vennDiagram-UO4OBE2U-CaGYKlrU.js} +1 -1
  92. package/dist/assets/{wardley-WFR3VGLG-D0qPa5yM.js → wardley-WFR3VGLG-lC7L7qz7.js} +1 -1
  93. package/dist/assets/{wardleyDiagram-VNRHLVJA-B0Ffm6Eo.js → wardleyDiagram-VNRHLVJA-BwSYaW09.js} +1 -1
  94. package/dist/assets/{xychartDiagram-PMCCYNJV-mcCWc9NA.js → xychartDiagram-PMCCYNJV-C1KTMmj3.js} +1 -1
  95. package/dist/index.html +2 -2
  96. package/docs/guide/en/v8.2.0.md +85 -0
  97. package/docs/guide/ja/v8.2.0.md +74 -0
  98. package/package.json +8 -8
  99. package/plugins/plugins.json +1 -1
  100. package/server/backends/openPath.ts +1 -1
  101. package/server/backends/presentPathRoot.ts +1 -1
  102. package/server/backends/shapescript.ts +2 -2
  103. package/server/blueprint/executor.ts +68 -12
  104. package/server/infra/host-tools.ts +2 -2
  105. package/server/infra/shapescript-manage-tool.ts +3 -3
  106. package/server/infra/shapescript-render-tool.ts +3 -3
  107. package/server/infra/shapescript-usdz-tool.ts +2 -2
  108. package/server/skills/mulmoterminal-header/SKILL.md +1 -1
  109. package/server/skills/mulmoterminal-keys/SKILL.md +3 -1
  110. package/server/skills/mulmoterminal-shared-app/SKILL.md +13 -4
  111. package/server/skills/mulmoterminal-shared-app/templates/class-seats.md +413 -0
  112. package/server/skills/mulmoterminal-shared-app/templates/meeting-room.md +3 -2
  113. package/server/skills/mulmoterminal-shared-app/templates/schedule-poll.md +424 -0
  114. package/dist/assets/architecture-7GRP2DOG-DbBbO1l3.js +0 -1
  115. package/dist/assets/channel-BAfBdDqJ.js +0 -1
  116. package/dist/assets/eventmodeling-NTZA5JFV-B5Bz1qEf.js +0 -1
  117. package/dist/assets/flowDiagram-KWPJA3E3-CChoJefx.js +0 -1
  118. package/dist/assets/index-BcxXAO6O.css +0 -1
  119. package/dist/assets/railroad-abnf-HS5TGJTU-B2S-Bbzp.js +0 -1
  120. package/dist/assets/railroad-ebnf-LZEXJU2U-DlnwWMr4.js +0 -1
  121. package/dist/assets/railroad-peg-WCYAUIDC-C3FYE35J.js +0 -1
  122. package/dist/assets/swimlanesDiagram-TC7HE7FX-DliugZOm.js +0 -8
@@ -21,7 +21,7 @@ jobs:
21
21
  - uses: actions/setup-node@v7
22
22
  with:
23
23
  node-version: 24
24
- - run: npx -y chaffjs@0.17 {{PATHS}} --sarif chaff.sarif
24
+ - run: npx -y chaffjs@0.18 {{PATHS}} --sarif chaff.sarif
25
25
  continue-on-error: true
26
26
  - uses: github/codeql-action/upload-sarif@1c5b675653bb5c22dbe9b12b556ec555138e09fd # v4.38.1
27
27
  with:
@@ -4,4 +4,4 @@
4
4
  if [ -n "${CHAFF_BIN:-}" ]; then
5
5
  exec sh -c "$CHAFF_BIN \"\$@\"" chaff "$@"
6
6
  fi
7
- exec npx -y chaffjs@0.17 "$@"
7
+ exec npx -y chaffjs@0.18 "$@"
@@ -12,7 +12,7 @@ repository, `.git/info/exclude`) until the person has approved the models.
12
12
  1. `.blueprint/` already exists (the build created it). Everything this build records goes there.
13
13
  2. Run chaff once through the base pack's wrapper, so its first download happens now and not in the
14
14
  middle of a later step: `sh <base pack>/checks/chaff.sh rules --json > /dev/null`. The wrapper runs the
15
- pinned chaff (`npx -y chaffjs@0.17`) unless `CHAFF_BIN` names another. If it fails, show the person the
15
+ pinned chaff (`npx -y chaffjs@0.18`) unless `CHAFF_BIN` names another. If it fails, show the person the
16
16
  error and stop — do not work around it.
17
17
  3. If the folder is a git repository, add `.blueprint/` to `.git/info/exclude`. That keeps the build's
18
18
  working files out of commits without touching `.gitignore`, which belongs to the person.
@@ -44,7 +44,16 @@ const problems = entries.flatMap(({ name, decision }) => {
44
44
  if (decision === "manual" && !inHeading(name)) return [`${name} is left to a person, and README.md has no heading naming it`];
45
45
  return [];
46
46
  });
47
- if (problems.length > 0) { console.error(problems.join("\n")); process.exit(1); }
47
+ // Said with the titles it read and the rule it reads them by, so the one fixing it sees what is missing rather than guessing.
48
+ const untested = entries.some(({ name, decision }) => decision === "feature" && !inTestTitle(name));
49
+ const hint = untested
50
+ ? [
51
+ "",
52
+ `The test titles ${tests} declares, as this check reads them: ${titles.length === 0 ? "(none)" : titles.map((title) => JSON.stringify(title)).join(", ")}.`,
53
+ "Only the title of a test counts: the first argument, written as a plain string, of it(...) or test(...) imported from \"vitest\" in that file. A describe(...) name does not count, so put the whole name in each test title.",
54
+ ]
55
+ : [];
56
+ if (problems.length > 0) { console.error([...problems, ...hint].join("\n")); process.exit(1); }
48
57
  process.stdout.write(String(entries.filter((entry) => entry.decision === "feature").length));
49
58
  ' "$file" "$tests" "$titles")
50
59
  [ "$features" -gt 0 ] || exit 0
@@ -27,7 +27,8 @@ check it against its entry and give it its test here instead of building it a se
27
27
 
28
28
  Tests in `test/actions.test.ts`, one per `feature`, each with the entry's `name` in the title of its `it(…)` / `test(…)`
29
29
  (`it("books.actions.tidy: summarises", …)`) — with `it` / `test` imported from `vitest` in that file (`import { it } from "vitest"`); the check reads titles only from
30
- calls to those imports, so a global `it`, a helper of the same name, a comment or a title built at run time does not count:
30
+ calls to those imports, so a global `it`, a helper of the same name, a comment or a title built at run time does not count, and neither does a `describe(…)` name (`it("tidy")` inside
31
+ `describe("books.actions")` is not titled `books.actions.tidy`: write the whole name in every test's own title):
31
32
  walk the real flow against a temporary database and read back what changed. Never call the network in a test: a model
32
33
  call goes through a client the test replaces with a stand-in, and an ingest reads a fixture file kept under
33
34
  `test/fixtures/`. The tests must pass with no API key set.
@@ -31,7 +31,8 @@ check it against its entry and give it its test here instead of building it a se
31
31
 
32
32
  Tests in `test/actions.test.ts`, one per `feature`, each with the entry's `name` in the title of its `it(…)` / `test(…)`
33
33
  (`it("books.actions.tidy: summarises", …)`) — with `it` / `test` imported from `vitest` in that file (`import { it } from "vitest"`); the check reads titles only from
34
- calls to those imports, so a global `it`, a helper of the same name, a comment or a title built at run time does not count:
34
+ calls to those imports, so a global `it`, a helper of the same name, a comment or a title built at run time does not count, and neither does a `describe(…)` name (`it("tidy")` inside
35
+ `describe("books.actions")` is not titled `books.actions.tidy`: write the whole name in every test's own title):
35
36
  walk the real flow through the Worker on the test D1 and read back what changed. Never call the network in a test: a
36
37
  model call goes through a client the test replaces with a stand-in, and an ingest job takes the fetch it uses as an
37
38
  argument, so the test hands it a fixture instead. The tests must pass with no API key set.
@@ -27,7 +27,8 @@ check it against its entry and give it its test here instead of building it a se
27
27
 
28
28
  Tests in `test/blueprint/actions.spec.ts`, one per `feature`, each with the entry's `name` in the title of its `it(…)` /
29
29
  `test(…)` (`it("books.actions.tidy: summarises", …)`) — with `it` / `test` imported from `vitest` in that file (`import { it } from "vitest"`); the check reads titles only from
30
- calls to those imports, so a global `it`, a helper of the same name, a comment or a title built at run time does not count —
30
+ calls to those imports, so a global `it`, a helper of the same name, a comment or a title built at run time does not count, and neither does a `describe(…)` name (`it("tidy")` inside
31
+ `describe("books.actions")` is not titled `books.actions.tidy`: write the whole name in every test's own title) —
31
32
  against the emulators: do the action as a signed-in user and read back what changed, and check that someone who must not
32
33
  do it is refused. Never call the network in a test: the model call and the fetch go through clients the test replaces
33
34
  with stand-ins.
@@ -30,7 +30,8 @@ check it against its entry and give it its test here instead of building it a se
30
30
 
31
31
  Tests in `test/actions.test.ts`, one per `feature`, each with the entry's `name` in the title of its `it(…)` / `test(…)`
32
32
  (`it("books.actions.tidy: summarises", …)`) — with `it` / `test` imported from `vitest` in that file (`import { it } from "vitest"`); the check reads titles only from
33
- calls to those imports, so a global `it`, a helper of the same name, a comment or a title built at run time does not count:
33
+ calls to those imports, so a global `it`, a helper of the same name, a comment or a title built at run time does not count, and neither does a `describe(…)` name (`it("tidy")` inside
34
+ `describe("books.actions")` is not titled `books.actions.tidy`: write the whole name in every test's own title):
34
35
  walk the real flow against the local stack and read back what changed. Never call the network in a test: a model call
35
36
  goes through a client the test replaces with a stand-in, and an ingest job takes the fetch it uses as an argument, so
36
37
  the test hands it a fixture instead. The tests must pass with no API key set.
@@ -8,7 +8,7 @@ description: "Report what became a machine rule, what went to the guide, and wha
8
8
  Write `.blueprint/style-report.md` for the person, in their language and in plain words:
9
9
 
10
10
  - `## 機械の決まり` / `## Machine rules` — `chaff.yaml`: the genre and language, and each rule you set
11
- with its reason, in one line each. How to run it: `npx -y chaffjs@0.17 <file or folder>`.
11
+ with its reason, in one line each. How to run it: `npx -y chaffjs@0.18 <file or folder>`.
12
12
  - `## 手引き` / `## The guide` — what `STYLE.md` asks for that a machine cannot check.
13
13
  - `## 規約にしなかったこと` / `## Left out` — what the models do that you did not make a rule, and why;
14
14
  any genre chaff lacked; any source that was converted from Word or PDF; counter texts chaff could not see.
@@ -26,6 +26,7 @@ export const APP_ACTIONS = [
26
26
  ...ORDER_ACTIONS,
27
27
  "page-next",
28
28
  "page-prev",
29
+ "terminal-reopen",
29
30
  ] as const satisfies readonly KeymapAction[];
30
31
 
31
32
  // The ones the command palette already has a row for — a screen, a Settings section, the sound /
@@ -5,9 +5,14 @@ import type { PlanStep } from "./plan.js";
5
5
  import { currentStep, type BlueprintState } from "./state.js";
6
6
 
7
7
  // Failed checks one step may have before the build stops for a person. Enough for an agent to read
8
- // its own check output and fix it; small enough that a step it cannot fix does not burn turn after
9
- // turn. Sessions that stopped to ask are not failures and do not count.
10
- export const MAX_FAILED_CHECKS = 3;
8
+ // its own check output and fix it, and then for repair attempts that change approach; small enough that a step it
9
+ // cannot fix does not burn turn after turn. Sessions that stopped to ask are not failures and do not count.
10
+ export const MAX_FAILED_CHECKS = 5;
11
+
12
+ // Failed checks in a row after which an attempt is a repair: doing the same again has not worked, so the attempt is
13
+ // told every failure so far and to find why they all failed before changing anything. A person who cannot fix the
14
+ // step either is the last resort, not the next one.
15
+ export const REPAIR_AFTER = 3;
11
16
 
12
17
  // Rounds one repeating step may run before the build moves on regardless. A list that never empties —
13
18
  // an agent that keeps finding more, or a `repeatWhile` that cannot say no — must not run forever; what
@@ -54,3 +59,14 @@ export function nextAction(inputs: ExecutorInputs): ExecutorAction {
54
59
  if (status === "running") return inputs.sessionActive ? { kind: "wait", stepId: step.id, on: "agent" } : { kind: "spawn", stepId: step.id };
55
60
  return forFailed(step.id, inputs);
56
61
  }
62
+
63
+ /**
64
+ * The step a build stopped at because another build was working in its folder, or null. Only that stop is resumed by
65
+ * itself when the folder frees: every other stop waits for something a person or the agent has to change.
66
+ */
67
+ export function waitsOnBusyFolder(steps: readonly PlanStep[], state: BlueprintState): string | null {
68
+ const step = currentStep(steps, state);
69
+ if (!step) return null;
70
+ const stepState = state.steps[step.id];
71
+ return stepState?.status === "failed" && stepState.lastCheck?.notice?.code === "folder-busy" ? step.id : null;
72
+ }
@@ -21,6 +21,8 @@ export const blueprintRunSchema = z.object({
21
21
  // Checks that failed for a step since a person last retried it; what stops a failing check from
22
22
  // looping forever.
23
23
  failedChecks: z.record(z.string(), z.number().int().nonnegative()).default({}),
24
+ // What each of those failed checks printed, oldest first: a repair attempt is shown them all, to see what keeps failing.
25
+ failureOutputs: z.record(z.string(), z.array(z.string())).default({}),
24
26
  // The session working on the current step, if one is. Its turn ending is what triggers a check.
25
27
  activeSessionId: z.string().nullable().default(null),
26
28
  // `answersAtStart`: how many answers the step had when the session began, so an answer that came
@@ -4,9 +4,12 @@
4
4
  import type { PlanStep } from "./plan.js";
5
5
  import type { StepState } from "./state.js";
6
6
  import { personLanguageLine, type PersonLanguage } from "./personLanguage.js";
7
+ import { REPAIR_AFTER } from "./executorPolicy.js";
7
8
 
8
9
  // Enough of a failing check's output to act on; a build log can run far longer.
9
10
  export const CHECK_OUTPUT_PROMPT_CHARS = 4000;
11
+ // Each earlier failure's output, shorter: what kept failing, not every line of it.
12
+ export const EARLIER_FAILURE_PROMPT_CHARS = 1500;
10
13
  // The person's earlier answers shown to a step, newest kept: a long build with a question every round would otherwise
11
14
  // grow every later prompt without end.
12
15
  export const EARLIER_ANSWERS_PROMPT_CHARS = 6000;
@@ -24,6 +27,11 @@ export interface StepPromptInput {
24
27
  earlierAnswers?: readonly EarlierAnswer[];
25
28
  /** The language the person reads, when the build recorded it. */
26
29
  language?: PersonLanguage | null;
30
+ /** What the step's earlier failed checks printed, oldest first — the attempts before the last one. */
31
+ earlierFailures?: readonly string[];
32
+ /** How many checks in a row have failed, the last included. A run recorded before the history was kept has the
33
+ * count without the outputs, and is a repair all the same. */
34
+ failedAttempts?: number;
27
35
  }
28
36
 
29
37
  /** A question a person answered while an earlier step, or an earlier round of this one, ran — with where it was asked. */
@@ -105,13 +113,69 @@ function roundSection(step: PlanStep, stepState: StepState | undefined): string[
105
113
  ];
106
114
  }
107
115
 
108
- function failureSection(stepState: StepState | undefined): string[] {
116
+ /**
117
+ * The step's check as a shell would run it from the project, with the pack folders written in: a check names them as
118
+ * `$BLUEPRINT_BASE` / `$BLUEPRINT_USECASE` (bare or braced), which only the executor's own run sets.
119
+ */
120
+ export const resolvedCheck = (check: string, packDirs: { base: string; usecase: string }): string =>
121
+ check.replace(/\$\{?BLUEPRINT_(BASE|USECASE)\}?/gu, (_match, which: string) => (which === "BASE" ? packDirs.base : packDirs.usecase));
122
+
123
+ // A check's output does not always say how to fix what it found, and an agent that cannot tell fails the same way
124
+ // until the retries run out and a person — who cannot fix it either — is left with the build. The check itself is
125
+ // the exact rule, so the agent is pointed at it; reading has no side effects, where running some checks would.
126
+ // The earlier failures, and — once enough attempts in a row have failed — the instruction to stop repeating them.
127
+ function repairLines(earlierFailures: readonly string[], failedAttempts: number): string[] {
128
+ const attempts = Math.max(earlierFailures.length + 1, failedAttempts);
129
+ const earlier =
130
+ earlierFailures.length === 0
131
+ ? []
132
+ : [
133
+ "",
134
+ "Earlier attempts failed this check too. What they reported, oldest first:",
135
+ ...earlierFailures.flatMap((output, index) => [`Attempt ${index + 1}:`, "```", tail(output, EARLIER_FAILURE_PROMPT_CHARS), "```"]),
136
+ ];
137
+ const repair =
138
+ attempts >= REPAIR_AFTER
139
+ ? [
140
+ "",
141
+ `This is a repair attempt: ${attempts} attempts in a row have not passed this check, so doing what they did again will not either. Before changing anything, read the check and work out why every attempt still failed — compare what each reported — then fix that cause.`,
142
+ ]
143
+ : [];
144
+ return [...earlier, ...repair];
145
+ }
146
+
147
+ function failureSection(
148
+ step: PlanStep,
149
+ stepState: StepState | undefined,
150
+ packDirs: { base: string; usecase: string },
151
+ earlierFailures: readonly string[],
152
+ failedAttempts: number,
153
+ ): string[] {
109
154
  const check = stepState?.lastCheck;
110
155
  if (!check || check.ok) return [];
111
- return ["", "The previous attempt did not pass its check. Its output:", "```", tail(check.output, CHECK_OUTPUT_PROMPT_CHARS), "```", "Fix what it reports."];
156
+ return [
157
+ ...repairLines(earlierFailures, failedAttempts),
158
+ "",
159
+ "The previous attempt did not pass its check. Its output:",
160
+ "```",
161
+ tail(check.output, CHECK_OUTPUT_PROMPT_CHARS),
162
+ "```",
163
+ "Fix what it reports. When the output does not make plain what would satisfy it, read the check to see exactly what it requires — " +
164
+ `it is \`${resolvedCheck(step.check, packDirs)}\`, and the scripts it names are in the pack folders above — then change the work until it would pass. Never change the check or anything in the pack folders.`,
165
+ ];
112
166
  }
113
167
 
114
- export function stepPrompt({ step, skillFile, packDirs, stepState, askCommand, earlierAnswers: earlier = [], language }: StepPromptInput): string {
168
+ export function stepPrompt({
169
+ step,
170
+ skillFile,
171
+ packDirs,
172
+ stepState,
173
+ askCommand,
174
+ earlierAnswers: earlier = [],
175
+ language,
176
+ earlierFailures = [],
177
+ failedAttempts = 0,
178
+ }: StepPromptInput): string {
115
179
  return [
116
180
  `Blueprint step "${step.id}": ${step.title}.`,
117
181
  step.description,
@@ -129,6 +193,6 @@ export function stepPrompt({ step, skillFile, packDirs, stepState, askCommand, e
129
193
  ...roundSection(step, stepState),
130
194
  ...earlierSection(earlier),
131
195
  ...answeredSection(stepState),
132
- ...failureSection(stepState),
196
+ ...failureSection(step, stepState, packDirs, earlierFailures, failedAttempts),
133
197
  ].join("\n");
134
198
  }
package/common/keymap.ts CHANGED
@@ -24,6 +24,7 @@ export const KEYMAP_ACTIONS = [
24
24
  "terminal-new-here",
25
25
  "terminal-new-adjacent",
26
26
  "terminal-close",
27
+ "terminal-reopen",
27
28
  "terminal-restart",
28
29
  "terminal-move-prev",
29
30
  "terminal-move-next",
@@ -1 +1 @@
1
- import{m as e,t}from"./mermaid-parser.core-DEnlY2ci.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-CllyRBe0.js";import"./chunk-O7XYJQB3-Dz4vrOLX.js";import{n as i,r as a,t as o}from"./chunk-GTNCS2PH-DKvFKim8.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";import"./mermaid.core-B7u-t6P9.js";var c=e().RailroadAbnf.parser.LangiumParser,l=n(e=>{let t=e.alternatives.map(u);return t.length===1?t[0]:{type:`choice`,alternatives:t}},`transformAlternation`),u=n(e=>{let t=e.elements.map(f);return t.length===1?t[0]:{type:`sequence`,elements:t}},`transformConcatenation`),d=n(e=>{if(e.includes(`*`)){let[t,n]=e.split(`*`);return{min:t?parseInt(t,10):0,max:n?parseInt(n,10):1/0}}let t=parseInt(e,10);return{min:t,max:t}},`parseRepeat`),f=n(e=>{let t=p(e.primary);if(!e.repeat)return t;let{min:n,max:r}=d(e.repeat);return n===0&&r===1?{type:`optional`,element:t}:{type:`repetition`,element:t,min:n,max:r}},`transformElement`),p=n(e=>{switch(e.$type){case`AbnfStringLiteral`:return{type:`terminal`,value:e.value};case`AbnfNumVal`:return{type:`terminal`,value:e.value};case`AbnfRuleName`:return{type:`nonterminal`,name:e.name};case`AbnfGroup`:return l(e.element);case`AbnfOptionalGroup`:return{type:`optional`,element:l(e.element)};default:throw Error(`Unsupported ABNF primary node: ${e.$type}`)}},`transformPrimary`),m=n(e=>({name:e.name,definition:l(e.definition)}),`transformRule`),h=n(e=>{s(e,o),e.title&&o.setTitle(e.title),e.rules.map(e=>o.addRule(m(e)))},`populateDb`),g={parser:{parse:n(e=>{o.clear(),r.debug(`[ABNF Parser] Starting Langium parse`);let n=c.parse(e);if(n.lexerErrors.length>0||n.parserErrors.length>0)throw new t(n);let i=n.value;r.debug(`[ABNF Parser] Parsed rules:`,i.rules.length),h(i),r.debug(`[ABNF Parser] Parse complete`)},`parse`),parser:{yy:o}},db:o,renderer:a,styles:i};export{g as diagram};
1
+ import{m as e,t}from"./mermaid-parser.core-CA27Zh_E.js";import{n}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import{m as r}from"./src-CllyRBe0.js";import"./chunk-O7XYJQB3-Gutmfs0i.js";import{n as i,r as a,t as o}from"./chunk-GTNCS2PH-COevsxgA.js";import{t as s}from"./chunk-JWPE2WC7-DVXcaiue.js";import"./mermaid.core-oKSvAMmn.js";var c=e().RailroadAbnf.parser.LangiumParser,l=n(e=>{let t=e.alternatives.map(u);return t.length===1?t[0]:{type:`choice`,alternatives:t}},`transformAlternation`),u=n(e=>{let t=e.elements.map(f);return t.length===1?t[0]:{type:`sequence`,elements:t}},`transformConcatenation`),d=n(e=>{if(e.includes(`*`)){let[t,n]=e.split(`*`);return{min:t?parseInt(t,10):0,max:n?parseInt(n,10):1/0}}let t=parseInt(e,10);return{min:t,max:t}},`parseRepeat`),f=n(e=>{let t=p(e.primary);if(!e.repeat)return t;let{min:n,max:r}=d(e.repeat);return n===0&&r===1?{type:`optional`,element:t}:{type:`repetition`,element:t,min:n,max:r}},`transformElement`),p=n(e=>{switch(e.$type){case`AbnfStringLiteral`:return{type:`terminal`,value:e.value};case`AbnfNumVal`:return{type:`terminal`,value:e.value};case`AbnfRuleName`:return{type:`nonterminal`,name:e.name};case`AbnfGroup`:return l(e.element);case`AbnfOptionalGroup`:return{type:`optional`,element:l(e.element)};default:throw Error(`Unsupported ABNF primary node: ${e.$type}`)}},`transformPrimary`),m=n(e=>({name:e.name,definition:l(e.definition)}),`transformRule`),h=n(e=>{s(e,o),e.title&&o.setTitle(e.title),e.rules.map(e=>o.addRule(m(e)))},`populateDb`),g={parser:{parse:n(e=>{o.clear(),r.debug(`[ABNF Parser] Starting Langium parse`);let n=c.parse(e);if(n.lexerErrors.length>0||n.parserErrors.length>0)throw new t(n);let i=n.value;r.debug(`[ABNF Parser] Parsed rules:`,i.rules.length),h(i),r.debug(`[ABNF Parser] Parse complete`)},`parse`),parser:{yy:o}},db:o,renderer:a,styles:i};export{g as diagram};
@@ -0,0 +1 @@
1
+ import"./chunk-FOHPRMQF-DzxwRta7.js";import{M as e}from"./mermaid-parser.core-CA27Zh_E.js";export{e as createArchitectureServices};