@xhulz/nina 0.50.2 → 0.51.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/README.md +8 -3
- package/bin/nina.mjs +1 -0
- package/package.json +1 -1
- package/releases/0.50.3/core/GAPS.md +125 -0
- package/releases/0.50.3/core/answered.json +53 -0
- package/releases/0.50.3/core/defaults/tree/.claude/agents/architect.md +1 -0
- package/releases/0.50.3/core/defaults/tree/.claude/agents/dba.md +3 -0
- package/releases/0.50.3/core/defaults/tree/.claude/agents/devops.md +1 -0
- package/releases/0.50.3/core/defaults/tree/.claude/agents/implementer.md +1 -0
- package/releases/0.50.3/core/defaults/tree/.claude/agents/integration-tester.md +3 -0
- package/releases/0.50.3/core/defaults/tree/.claude/agents/qa.md +7 -0
- package/releases/0.50.3/core/defaults/tree/.claude/agents/reviewer.md +3 -0
- package/releases/0.50.3/core/defaults/tree/.claude/agents/secops.md +3 -0
- package/releases/0.50.3/core/defaults/tree/.claude/agents/solidity-auditor.md +3 -0
- package/releases/0.50.3/core/defaults/tree/.claude/agents/solidity-dev.md +3 -0
- package/releases/0.50.3/core/tree/.claude/agents/architect.md +129 -0
- package/releases/0.50.3/core/tree/.claude/agents/dba.md +117 -0
- package/releases/0.50.3/core/tree/.claude/agents/devops.md +118 -0
- package/releases/0.50.3/core/tree/.claude/agents/implementer.md +162 -0
- package/releases/0.50.3/core/tree/.claude/agents/integration-tester.md +168 -0
- package/releases/0.50.3/core/tree/.claude/agents/planner.md +132 -0
- package/releases/0.50.3/core/tree/.claude/agents/qa.md +150 -0
- package/releases/0.50.3/core/tree/.claude/agents/reviewer.md +184 -0
- package/releases/0.50.3/core/tree/.claude/agents/secops.md +120 -0
- package/releases/0.50.3/core/tree/.claude/agents/solidity-auditor.md +126 -0
- package/releases/0.50.3/core/tree/.claude/agents/solidity-dev.md +123 -0
- package/releases/0.50.3/core/tree/.claude/agents-overview.md +64 -0
- package/releases/0.50.3/core/tree/.claude/frontend.md +10 -0
- package/releases/0.50.3/core/tree/.claude/graph.md +75 -0
- package/releases/0.50.3/core/tree/.claude/patterns.md +251 -0
- package/releases/0.50.3/core/tree/.claude/pills/README.md +147 -0
- package/releases/0.50.3/core/tree/.claude/pipeline.md +101 -0
- package/releases/0.50.3/core/tree/.claude/retrieval.md +103 -0
- package/releases/0.50.3/core/tree/.claude/router.md +202 -0
- package/releases/0.50.3/core/tree/.claude/templates/integration.md +46 -0
- package/releases/0.50.3/core/tree/CLAUDE.md +164 -0
- package/releases/0.50.3/core/tree/scripts/cost-watch.mjs +25 -0
- package/releases/0.50.3/core/tree/scripts/edit-guard.mjs +24 -0
- package/releases/0.50.3/core/tree/scripts/harness-check.mjs +71 -0
- package/releases/0.50.3/core/tree/scripts/loop-gate.mjs +19 -0
- package/releases/0.50.3/core/vocabulary.json +13 -0
- package/releases/0.50.3/surfaces/blockchain/tree/.claude/agents/architect.md +5 -0
- package/releases/0.50.3/surfaces/blockchain/tree/.claude/agents/devops.md +5 -0
- package/releases/0.50.3/surfaces/blockchain/tree/.claude/agents/reviewer.md +5 -0
- package/releases/0.50.3/surfaces/blockchain/tree/.claude/agents/solidity-auditor.md +18 -0
- package/releases/0.50.3/surfaces/blockchain/tree/.claude/agents/solidity-dev.md +16 -0
- package/releases/0.50.3/surfaces/blockchain/tree/.claude/agents-overview.md +6 -0
- package/releases/0.50.3/surfaces/blockchain/tree/.claude/graph.md +11 -0
- package/releases/0.50.3/surfaces/blockchain/tree/.claude/router.md +6 -0
- package/releases/0.50.3/surfaces/blockchain/tree/CLAUDE.md +12 -0
- package/releases/0.50.3/surfaces/d1/tree/.claude/agents/dba.md +15 -0
- package/releases/0.50.3/surfaces/d1/tree/.claude/agents/devops.md +2 -0
- package/releases/0.50.3/surfaces/d1/tree/.claude/agents/implementer.md +2 -0
- package/releases/0.50.3/surfaces/d1/tree/.claude/patterns.md +8 -0
- package/releases/0.50.3/surfaces/d1/tree/CLAUDE.md +2 -0
- package/releases/0.50.3/surfaces/db/tree/.claude/agents/architect.md +5 -0
- package/releases/0.50.3/surfaces/db/tree/.claude/agents/dba.md +54 -0
- package/releases/0.50.3/surfaces/db/tree/.claude/agents/devops.md +5 -0
- package/releases/0.50.3/surfaces/db/tree/.claude/agents/implementer.md +2 -0
- package/releases/0.50.3/surfaces/db/tree/.claude/agents/integration-tester.md +10 -0
- package/releases/0.50.3/surfaces/db/tree/.claude/agents/planner.md +2 -0
- package/releases/0.50.3/surfaces/db/tree/.claude/agents/reviewer.md +22 -0
- package/releases/0.50.3/surfaces/db/tree/.claude/agents/secops.md +2 -0
- package/releases/0.50.3/surfaces/db/tree/.claude/agents-overview.md +5 -0
- package/releases/0.50.3/surfaces/db/tree/.claude/graph.md +8 -0
- package/releases/0.50.3/surfaces/db/tree/.claude/patterns.md +22 -0
- package/releases/0.50.3/surfaces/db/tree/.claude/pipeline.md +13 -0
- package/releases/0.50.3/surfaces/db/tree/.claude/retrieval.md +5 -0
- package/releases/0.50.3/surfaces/db/tree/.claude/router.md +4 -0
- package/releases/0.50.3/surfaces/db/tree/CLAUDE.md +17 -0
- package/releases/0.50.3/surfaces/drizzle/tree/.claude/agents/dba.md +9 -0
- package/releases/0.50.3/surfaces/drizzle/tree/.claude/agents/devops.md +5 -0
- package/releases/0.50.3/surfaces/drizzle/tree/.claude/agents/implementer.md +2 -0
- package/releases/0.50.3/surfaces/drizzle/tree/.claude/patterns.md +7 -0
- package/releases/0.50.3/surfaces/edge-cf/tree/.claude/agents/architect.md +14 -0
- package/releases/0.50.3/surfaces/edge-cf/tree/.claude/agents/dba.md +2 -0
- package/releases/0.50.3/surfaces/edge-cf/tree/.claude/agents/devops.md +29 -0
- package/releases/0.50.3/surfaces/edge-cf/tree/.claude/agents/implementer.md +14 -0
- package/releases/0.50.3/surfaces/edge-cf/tree/.claude/agents/integration-tester.md +11 -0
- package/releases/0.50.3/surfaces/edge-cf/tree/.claude/agents/qa.md +3 -0
- package/releases/0.50.3/surfaces/edge-cf/tree/.claude/agents/reviewer.md +8 -0
- package/releases/0.50.3/surfaces/edge-cf/tree/.claude/agents/secops.md +8 -0
- package/releases/0.50.3/surfaces/edge-cf/tree/.claude/patterns.md +17 -0
- package/releases/0.50.3/surfaces/edge-cf/tree/.claude/retrieval.md +8 -0
- package/releases/0.50.3/surfaces/edge-cf/tree/CLAUDE.md +27 -0
- package/releases/0.50.3/surfaces/frontend/tree/.claude/agents/architect.md +20 -0
- package/releases/0.50.3/surfaces/frontend/tree/.claude/agents/devops.md +28 -0
- package/releases/0.50.3/surfaces/frontend/tree/.claude/agents/implementer.md +25 -0
- package/releases/0.50.3/surfaces/frontend/tree/.claude/agents/qa.md +17 -0
- package/releases/0.50.3/surfaces/frontend/tree/.claude/agents/reviewer.md +56 -0
- package/releases/0.50.3/surfaces/frontend/tree/.claude/patterns.md +8 -0
- package/releases/0.50.3/surfaces/frontend/tree/.claude/retrieval.md +2 -0
- package/releases/0.50.3/surfaces/frontend/tree/.claude/router.md +14 -0
- package/releases/0.50.3/surfaces/frontend/tree/CLAUDE.md +5 -0
- package/releases/0.50.3/surfaces/integrations/tree/.claude/agents/architect.md +16 -0
- package/releases/0.50.3/surfaces/integrations/tree/.claude/agents/implementer.md +12 -0
- package/releases/0.50.3/surfaces/integrations/tree/.claude/agents/integration-tester.md +20 -0
- package/releases/0.50.3/surfaces/integrations/tree/.claude/agents/planner.md +2 -0
- package/releases/0.50.3/surfaces/integrations/tree/.claude/agents/reviewer.md +21 -0
- package/releases/0.50.3/surfaces/integrations/tree/.claude/agents/secops.md +2 -0
- package/releases/0.50.3/surfaces/integrations/tree/.claude/agents-overview.md +8 -0
- package/releases/0.50.3/surfaces/integrations/tree/.claude/graph.md +10 -0
- package/releases/0.50.3/surfaces/integrations/tree/.claude/patterns.md +38 -0
- package/releases/0.50.3/surfaces/integrations/tree/.claude/pipeline.md +16 -0
- package/releases/0.50.3/surfaces/integrations/tree/.claude/retrieval.md +16 -0
- package/releases/0.50.3/surfaces/integrations/tree/.claude/router.md +6 -0
- package/releases/0.50.3/surfaces/integrations/tree/CLAUDE.md +17 -0
- package/releases/0.50.3/surfaces/money/tree/.claude/agents/architect.md +12 -0
- package/releases/0.50.3/surfaces/money/tree/.claude/agents/dba.md +14 -0
- package/releases/0.50.3/surfaces/money/tree/.claude/agents/implementer.md +11 -0
- package/releases/0.50.3/surfaces/money/tree/.claude/agents/integration-tester.md +3 -0
- package/releases/0.50.3/surfaces/money/tree/.claude/agents/reviewer.md +23 -0
- package/releases/0.50.3/surfaces/money/tree/.claude/agents/secops.md +5 -0
- package/releases/0.50.3/surfaces/money/tree/.claude/agents/solidity-auditor.md +4 -0
- package/releases/0.50.3/surfaces/money/tree/.claude/agents/solidity-dev.md +4 -0
- package/releases/0.50.3/surfaces/money/tree/.claude/graph.md +2 -0
- package/releases/0.50.3/surfaces/money/tree/.claude/patterns.md +49 -0
- package/releases/0.50.3/surfaces/money/tree/.claude/pipeline.md +2 -0
- package/releases/0.50.3/surfaces/money/tree/.claude/retrieval.md +2 -0
- package/releases/0.50.3/surfaces/money/tree/CLAUDE.md +11 -0
- package/releases/0.50.3/surfaces/pii/tree/.claude/agents/dba.md +2 -0
- package/releases/0.50.3/surfaces/pii/tree/.claude/agents/devops.md +8 -0
- package/releases/0.50.3/surfaces/pii/tree/.claude/agents/reviewer.md +8 -0
- package/releases/0.50.3/surfaces/pii/tree/.claude/agents/secops.md +2 -0
- package/releases/0.50.3/surfaces/pii/tree/.claude/agents/solidity-auditor.md +5 -0
- package/releases/0.50.3/surfaces/pii/tree/CLAUDE.md +5 -0
- package/releases/0.50.3/surfaces/prisma/tree/.claude/agents/architect.md +2 -0
- package/releases/0.50.3/surfaces/prisma/tree/.claude/agents/dba.md +42 -0
- package/releases/0.50.3/surfaces/prisma/tree/.claude/agents/devops.md +11 -0
- package/releases/0.50.3/surfaces/prisma/tree/.claude/agents/implementer.md +2 -0
- package/releases/0.50.3/surfaces/prisma/tree/.claude/agents/integration-tester.md +2 -0
- package/releases/0.50.3/surfaces/prisma/tree/.claude/agents/reviewer.md +2 -0
- package/releases/0.50.3/surfaces/prisma/tree/.claude/patterns.md +15 -0
- package/releases/0.50.3/surfaces/prisma/tree/CLAUDE.md +5 -0
- package/releases/0.51.0/core/GAPS.md +125 -0
- package/releases/0.51.0/core/answered.json +68 -0
- package/releases/0.51.0/core/defaults/tree/.claude/agents/architect.md +1 -0
- package/releases/0.51.0/core/defaults/tree/.claude/agents/dba.md +3 -0
- package/releases/0.51.0/core/defaults/tree/.claude/agents/devops.md +1 -0
- package/releases/0.51.0/core/defaults/tree/.claude/agents/implementer.md +1 -0
- package/releases/0.51.0/core/defaults/tree/.claude/agents/integration-tester.md +3 -0
- package/releases/0.51.0/core/defaults/tree/.claude/agents/qa.md +7 -0
- package/releases/0.51.0/core/defaults/tree/.claude/agents/reviewer.md +3 -0
- package/releases/0.51.0/core/defaults/tree/.claude/agents/secops.md +3 -0
- package/releases/0.51.0/core/defaults/tree/.claude/agents/solidity-auditor.md +3 -0
- package/releases/0.51.0/core/defaults/tree/.claude/agents/solidity-dev.md +3 -0
- package/releases/0.51.0/core/tree/.claude/agents/architect.md +129 -0
- package/releases/0.51.0/core/tree/.claude/agents/dba.md +117 -0
- package/releases/0.51.0/core/tree/.claude/agents/devops.md +118 -0
- package/releases/0.51.0/core/tree/.claude/agents/implementer.md +163 -0
- package/releases/0.51.0/core/tree/.claude/agents/integration-tester.md +168 -0
- package/releases/0.51.0/core/tree/.claude/agents/planner.md +132 -0
- package/releases/0.51.0/core/tree/.claude/agents/qa.md +150 -0
- package/releases/0.51.0/core/tree/.claude/agents/reviewer.md +184 -0
- package/releases/0.51.0/core/tree/.claude/agents/secops.md +120 -0
- package/releases/0.51.0/core/tree/.claude/agents/solidity-auditor.md +126 -0
- package/releases/0.51.0/core/tree/.claude/agents/solidity-dev.md +123 -0
- package/releases/0.51.0/core/tree/.claude/agents-overview.md +64 -0
- package/releases/0.51.0/core/tree/.claude/frontend.md +10 -0
- package/releases/0.51.0/core/tree/.claude/graph.md +75 -0
- package/releases/0.51.0/core/tree/.claude/patterns.md +251 -0
- package/releases/0.51.0/core/tree/.claude/pills/README.md +150 -0
- package/releases/0.51.0/core/tree/.claude/pipeline.md +101 -0
- package/releases/0.51.0/core/tree/.claude/retrieval.md +103 -0
- package/releases/0.51.0/core/tree/.claude/router.md +202 -0
- package/releases/0.51.0/core/tree/.claude/templates/integration.md +46 -0
- package/releases/0.51.0/core/tree/CLAUDE.md +164 -0
- package/releases/0.51.0/core/tree/scripts/cost-watch.mjs +25 -0
- package/releases/0.51.0/core/tree/scripts/edit-guard.mjs +24 -0
- package/releases/0.51.0/core/tree/scripts/harness-check.mjs +71 -0
- package/releases/0.51.0/core/tree/scripts/loop-gate.mjs +19 -0
- package/releases/0.51.0/core/vocabulary.json +13 -0
- package/releases/0.51.0/surfaces/blockchain/tree/.claude/agents/architect.md +5 -0
- package/releases/0.51.0/surfaces/blockchain/tree/.claude/agents/devops.md +5 -0
- package/releases/0.51.0/surfaces/blockchain/tree/.claude/agents/reviewer.md +5 -0
- package/releases/0.51.0/surfaces/blockchain/tree/.claude/agents/solidity-auditor.md +18 -0
- package/releases/0.51.0/surfaces/blockchain/tree/.claude/agents/solidity-dev.md +16 -0
- package/releases/0.51.0/surfaces/blockchain/tree/.claude/agents-overview.md +6 -0
- package/releases/0.51.0/surfaces/blockchain/tree/.claude/graph.md +11 -0
- package/releases/0.51.0/surfaces/blockchain/tree/.claude/router.md +6 -0
- package/releases/0.51.0/surfaces/blockchain/tree/CLAUDE.md +12 -0
- package/releases/0.51.0/surfaces/d1/tree/.claude/agents/dba.md +15 -0
- package/releases/0.51.0/surfaces/d1/tree/.claude/agents/devops.md +2 -0
- package/releases/0.51.0/surfaces/d1/tree/.claude/agents/implementer.md +2 -0
- package/releases/0.51.0/surfaces/d1/tree/.claude/patterns.md +8 -0
- package/releases/0.51.0/surfaces/d1/tree/CLAUDE.md +2 -0
- package/releases/0.51.0/surfaces/db/tree/.claude/agents/architect.md +5 -0
- package/releases/0.51.0/surfaces/db/tree/.claude/agents/dba.md +54 -0
- package/releases/0.51.0/surfaces/db/tree/.claude/agents/devops.md +5 -0
- package/releases/0.51.0/surfaces/db/tree/.claude/agents/implementer.md +2 -0
- package/releases/0.51.0/surfaces/db/tree/.claude/agents/integration-tester.md +10 -0
- package/releases/0.51.0/surfaces/db/tree/.claude/agents/planner.md +2 -0
- package/releases/0.51.0/surfaces/db/tree/.claude/agents/reviewer.md +22 -0
- package/releases/0.51.0/surfaces/db/tree/.claude/agents/secops.md +2 -0
- package/releases/0.51.0/surfaces/db/tree/.claude/agents-overview.md +5 -0
- package/releases/0.51.0/surfaces/db/tree/.claude/graph.md +8 -0
- package/releases/0.51.0/surfaces/db/tree/.claude/patterns.md +22 -0
- package/releases/0.51.0/surfaces/db/tree/.claude/pipeline.md +13 -0
- package/releases/0.51.0/surfaces/db/tree/.claude/retrieval.md +5 -0
- package/releases/0.51.0/surfaces/db/tree/.claude/router.md +4 -0
- package/releases/0.51.0/surfaces/db/tree/CLAUDE.md +17 -0
- package/releases/0.51.0/surfaces/drizzle/tree/.claude/agents/dba.md +9 -0
- package/releases/0.51.0/surfaces/drizzle/tree/.claude/agents/devops.md +5 -0
- package/releases/0.51.0/surfaces/drizzle/tree/.claude/agents/implementer.md +2 -0
- package/releases/0.51.0/surfaces/drizzle/tree/.claude/patterns.md +7 -0
- package/releases/0.51.0/surfaces/edge-cf/tree/.claude/agents/architect.md +14 -0
- package/releases/0.51.0/surfaces/edge-cf/tree/.claude/agents/dba.md +2 -0
- package/releases/0.51.0/surfaces/edge-cf/tree/.claude/agents/devops.md +29 -0
- package/releases/0.51.0/surfaces/edge-cf/tree/.claude/agents/implementer.md +14 -0
- package/releases/0.51.0/surfaces/edge-cf/tree/.claude/agents/integration-tester.md +11 -0
- package/releases/0.51.0/surfaces/edge-cf/tree/.claude/agents/qa.md +3 -0
- package/releases/0.51.0/surfaces/edge-cf/tree/.claude/agents/reviewer.md +8 -0
- package/releases/0.51.0/surfaces/edge-cf/tree/.claude/agents/secops.md +8 -0
- package/releases/0.51.0/surfaces/edge-cf/tree/.claude/patterns.md +17 -0
- package/releases/0.51.0/surfaces/edge-cf/tree/.claude/retrieval.md +8 -0
- package/releases/0.51.0/surfaces/edge-cf/tree/CLAUDE.md +27 -0
- package/releases/0.51.0/surfaces/frontend/tree/.claude/agents/architect.md +20 -0
- package/releases/0.51.0/surfaces/frontend/tree/.claude/agents/devops.md +28 -0
- package/releases/0.51.0/surfaces/frontend/tree/.claude/agents/implementer.md +25 -0
- package/releases/0.51.0/surfaces/frontend/tree/.claude/agents/qa.md +17 -0
- package/releases/0.51.0/surfaces/frontend/tree/.claude/agents/reviewer.md +56 -0
- package/releases/0.51.0/surfaces/frontend/tree/.claude/patterns.md +8 -0
- package/releases/0.51.0/surfaces/frontend/tree/.claude/retrieval.md +2 -0
- package/releases/0.51.0/surfaces/frontend/tree/.claude/router.md +14 -0
- package/releases/0.51.0/surfaces/frontend/tree/CLAUDE.md +5 -0
- package/releases/0.51.0/surfaces/integrations/tree/.claude/agents/architect.md +16 -0
- package/releases/0.51.0/surfaces/integrations/tree/.claude/agents/implementer.md +12 -0
- package/releases/0.51.0/surfaces/integrations/tree/.claude/agents/integration-tester.md +20 -0
- package/releases/0.51.0/surfaces/integrations/tree/.claude/agents/planner.md +2 -0
- package/releases/0.51.0/surfaces/integrations/tree/.claude/agents/reviewer.md +21 -0
- package/releases/0.51.0/surfaces/integrations/tree/.claude/agents/secops.md +2 -0
- package/releases/0.51.0/surfaces/integrations/tree/.claude/agents-overview.md +8 -0
- package/releases/0.51.0/surfaces/integrations/tree/.claude/graph.md +10 -0
- package/releases/0.51.0/surfaces/integrations/tree/.claude/patterns.md +38 -0
- package/releases/0.51.0/surfaces/integrations/tree/.claude/pipeline.md +16 -0
- package/releases/0.51.0/surfaces/integrations/tree/.claude/retrieval.md +16 -0
- package/releases/0.51.0/surfaces/integrations/tree/.claude/router.md +6 -0
- package/releases/0.51.0/surfaces/integrations/tree/CLAUDE.md +17 -0
- package/releases/0.51.0/surfaces/money/tree/.claude/agents/architect.md +12 -0
- package/releases/0.51.0/surfaces/money/tree/.claude/agents/dba.md +14 -0
- package/releases/0.51.0/surfaces/money/tree/.claude/agents/implementer.md +11 -0
- package/releases/0.51.0/surfaces/money/tree/.claude/agents/integration-tester.md +3 -0
- package/releases/0.51.0/surfaces/money/tree/.claude/agents/reviewer.md +23 -0
- package/releases/0.51.0/surfaces/money/tree/.claude/agents/secops.md +5 -0
- package/releases/0.51.0/surfaces/money/tree/.claude/agents/solidity-auditor.md +4 -0
- package/releases/0.51.0/surfaces/money/tree/.claude/agents/solidity-dev.md +4 -0
- package/releases/0.51.0/surfaces/money/tree/.claude/graph.md +2 -0
- package/releases/0.51.0/surfaces/money/tree/.claude/patterns.md +49 -0
- package/releases/0.51.0/surfaces/money/tree/.claude/pipeline.md +2 -0
- package/releases/0.51.0/surfaces/money/tree/.claude/retrieval.md +2 -0
- package/releases/0.51.0/surfaces/money/tree/CLAUDE.md +11 -0
- package/releases/0.51.0/surfaces/pii/tree/.claude/agents/dba.md +2 -0
- package/releases/0.51.0/surfaces/pii/tree/.claude/agents/devops.md +8 -0
- package/releases/0.51.0/surfaces/pii/tree/.claude/agents/reviewer.md +8 -0
- package/releases/0.51.0/surfaces/pii/tree/.claude/agents/secops.md +2 -0
- package/releases/0.51.0/surfaces/pii/tree/.claude/agents/solidity-auditor.md +5 -0
- package/releases/0.51.0/surfaces/pii/tree/CLAUDE.md +5 -0
- package/releases/0.51.0/surfaces/prisma/tree/.claude/agents/architect.md +2 -0
- package/releases/0.51.0/surfaces/prisma/tree/.claude/agents/dba.md +42 -0
- package/releases/0.51.0/surfaces/prisma/tree/.claude/agents/devops.md +11 -0
- package/releases/0.51.0/surfaces/prisma/tree/.claude/agents/implementer.md +2 -0
- package/releases/0.51.0/surfaces/prisma/tree/.claude/agents/integration-tester.md +2 -0
- package/releases/0.51.0/surfaces/prisma/tree/.claude/agents/reviewer.md +2 -0
- package/releases/0.51.0/surfaces/prisma/tree/.claude/patterns.md +15 -0
- package/releases/0.51.0/surfaces/prisma/tree/CLAUDE.md +5 -0
- package/src/commands/learn.mjs +302 -48
- package/src/commands/pills.mjs +11 -8
- package/src/commands/upgrade.mjs +1 -1
- package/src/office.html +4 -3
package/src/commands/learn.mjs
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* observe its runs are recorded — the snapshot
|
|
7
7
|
* capture a mistake that will recur is written down — a pill
|
|
8
8
|
* apply the next run reads it — the role's spec tells it to
|
|
9
|
-
* graduate a lesson that keeps recurring becomes a rule — a request to the harness
|
|
9
|
+
* graduate a lesson that keeps recurring becomes a rule — here, or by a request to the harness
|
|
10
10
|
* verify the rule is seen to have helped — the loop-back rate, before and after
|
|
11
11
|
*
|
|
12
12
|
* An audit found every link but the first open. Capture ran at 3% of the rate the router asked
|
|
@@ -23,12 +23,12 @@
|
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
25
|
import { existsSync, readdirSync } from 'node:fs';
|
|
26
|
-
import { mkdir, readFile, readdir, stat, writeFile } from 'node:fs/promises';
|
|
27
|
-
import { join, relative, resolve } from 'node:path';
|
|
26
|
+
import { mkdir, readFile, readdir, rm, stat, writeFile } from 'node:fs/promises';
|
|
27
|
+
import { isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
28
28
|
import { HARNESS, readProfile, slugFor, snapshotsDir } from '../paths.mjs';
|
|
29
29
|
import { localDay, projectRecords } from '../store.mjs';
|
|
30
30
|
import { isLoopBack, runOf } from '../transcripts.mjs';
|
|
31
|
-
import { byVersion, closedGate, layerRootFor } from './compose.mjs';
|
|
31
|
+
import { SLOT, byVersion, closedGate, layerRootFor, noticeOf } from './compose.mjs';
|
|
32
32
|
import { GRADUATION_AT, RETIRED, frontmatter, graduationTarget, list, pillFiles, roleGates, tidyRetired } from './pills.mjs';
|
|
33
33
|
import { decodeProjectDir } from './stats.mjs';
|
|
34
34
|
import { snapshot } from './snapshot.mjs';
|
|
@@ -335,6 +335,8 @@ export function relapsed(known, filed) {
|
|
|
335
335
|
}
|
|
336
336
|
const out = [];
|
|
337
337
|
for (const [pill, request] of newest) {
|
|
338
|
+
// Declined since: the harness left it to the project, which is asked for it as a rule of its own (`undecided`).
|
|
339
|
+
if (newestRecord(filed, pill)?.status === 'declined') continue;
|
|
338
340
|
const shelved = pill.replace(/^\.claude\/pills\//, `.claude/pills/${RETIRED}/`);
|
|
339
341
|
const lesson = known.find((l) => l.rel === pill || l.rel === shelved);
|
|
340
342
|
const then = Number(request.occurrences);
|
|
@@ -346,20 +348,80 @@ export function relapsed(known, filed) {
|
|
|
346
348
|
return out;
|
|
347
349
|
}
|
|
348
350
|
|
|
351
|
+
/** A record's `target` when the lesson became a rule in its own project instead of going to the harness. */
|
|
352
|
+
export const HERE = 'project';
|
|
353
|
+
|
|
354
|
+
/** How far back the harness inbox lists the rules projects made of their own lessons. */
|
|
355
|
+
const MADE_HERE_DAYS = 30;
|
|
356
|
+
|
|
349
357
|
/**
|
|
350
|
-
* Lessons
|
|
351
|
-
*
|
|
352
|
-
* the
|
|
358
|
+
* Lessons owed a graduation, and so a decision only the project can make: where the rule goes. Each is active
|
|
359
|
+
* and either recurred often enough with nothing recorded for it, or was declined by the harness — which leaves
|
|
360
|
+
* the rule to its project — and not made one there yet.
|
|
361
|
+
*
|
|
362
|
+
* The detector used to file every lesson at three as a request to the harness. A convention of one codebase
|
|
363
|
+
* then went the whole way — request, decline, release, upgrade — and came back still a pill: the one step it
|
|
364
|
+
* needed, a rule in its own project, was the one nothing asked for.
|
|
353
365
|
*
|
|
354
366
|
* @param {Awaited<ReturnType<typeof lessons>>} known - The project's pills.
|
|
355
|
-
* @param {
|
|
356
|
-
* @returns {Awaited<ReturnType<typeof lessons>>}
|
|
367
|
+
* @param {Awaited<ReturnType<typeof filedRequests>>} filed - What it has recorded about them.
|
|
368
|
+
* @returns {{lesson: Awaited<ReturnType<typeof lessons>>[number], declined?: Awaited<ReturnType<typeof filedRequests>>[number]}[]}
|
|
357
369
|
*/
|
|
358
|
-
function
|
|
359
|
-
const
|
|
360
|
-
|
|
370
|
+
export function undecided(known, filed) {
|
|
371
|
+
const out = [];
|
|
372
|
+
for (const lesson of known) {
|
|
373
|
+
const last = newestRecord(filed, learnedAt(lesson.rel));
|
|
374
|
+
if (!last && !lesson.retired && lesson.occurrences >= GRADUATION_AT) out.push({ lesson });
|
|
375
|
+
// Retired, only when what was declined reopened it: a rule that did not hold, sent to the harness and declined
|
|
376
|
+
// there, is the project's to make again — otherwise nothing could settle it. One retired by hand after its
|
|
377
|
+
// first request was declined is settled.
|
|
378
|
+
else if (last?.status === 'declined' && (!lesson.retired || last.reopens)) out.push({ lesson, declined: last });
|
|
379
|
+
}
|
|
380
|
+
return out;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/** Where a pill was learned — the path its records name — whether or not it has since been retired. */
|
|
384
|
+
const learnedAt = (rel) => rel.replace(new RegExp(`^\\.claude/pills/${RETIRED}/`), '.claude/pills/');
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* The newest record about one pill: by date, and on one date the one that counted most, since what comes after
|
|
388
|
+
* — a reopening, a rule made again — is written with the count it saw. By the order a directory lists them, a
|
|
389
|
+
* record written the same day read as older.
|
|
390
|
+
*
|
|
391
|
+
* @param {Awaited<ReturnType<typeof filedRequests>>} filed - The project's records.
|
|
392
|
+
* @param {string} pill - Where the pill was learned.
|
|
393
|
+
* @returns {Awaited<ReturnType<typeof filedRequests>>[number]|undefined}
|
|
394
|
+
*/
|
|
395
|
+
function newestRecord(filed, pill) {
|
|
396
|
+
let newest;
|
|
397
|
+
for (const r of filed) {
|
|
398
|
+
if (r.pill !== pill) continue;
|
|
399
|
+
const later = !newest || r.date > newest.date ||
|
|
400
|
+
(r.date === newest.date && (Number(r.occurrences) > Number(newest.occurrences) ||
|
|
401
|
+
(Number(r.occurrences) === Number(newest.occurrences) && generation(r.file) > generation(newest.file))));
|
|
402
|
+
if (later) newest = r;
|
|
403
|
+
}
|
|
404
|
+
return newest;
|
|
361
405
|
}
|
|
362
406
|
|
|
407
|
+
/** Which record of one pill on one day a file name is: the first, `-again`, `-again-2`, … ({@link recordName}). */
|
|
408
|
+
const generation = (file) => {
|
|
409
|
+
const again = /-again(?:-(\d+))?\.md$/.exec(String(file ?? ''));
|
|
410
|
+
return again ? Number(again[1] ?? 1) : 0;
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* Where a graduated lesson's rule went, as a clause: "it became a rule here in …" or "its rule shipped in …".
|
|
415
|
+
*
|
|
416
|
+
* @param {{target: string, rule_in: string, answered_in: string}} request - The record of its graduation.
|
|
417
|
+
* @param {boolean} [layer] - Whether to name the layer a shipped rule went into.
|
|
418
|
+
* @returns {string}
|
|
419
|
+
*/
|
|
420
|
+
const ruleWent = (request, layer = true) =>
|
|
421
|
+
request.target === HERE
|
|
422
|
+
? `it became a rule here in ${request.rule_in}`
|
|
423
|
+
: `its rule shipped in ${request.answered_in || 'a release'}${layer ? ` (${request.rule_in || request.target})` : ''}`;
|
|
424
|
+
|
|
363
425
|
/**
|
|
364
426
|
* Every request this project has written, with its status.
|
|
365
427
|
*
|
|
@@ -381,6 +443,8 @@ export async function filedRequests(target) {
|
|
|
381
443
|
occurrences: fields.occurrences ?? '',
|
|
382
444
|
rule_in: fields.rule_in ?? '',
|
|
383
445
|
answered_in: fields.answered_in ?? '',
|
|
446
|
+
declined: fields.declined ?? '',
|
|
447
|
+
reopens: fields.reopens ?? '',
|
|
384
448
|
});
|
|
385
449
|
}
|
|
386
450
|
return out;
|
|
@@ -409,13 +473,23 @@ async function answerRequest(target, file, answer) {
|
|
|
409
473
|
// A declined lesson is still this project's lesson: the harness said it does not belong in every
|
|
410
474
|
// project, not that it stopped being true in this one. So is one whose rule went into a layer this
|
|
411
475
|
// project does not compose — retiring it there would drop the lesson with nothing in its place.
|
|
412
|
-
|
|
413
|
-
|
|
476
|
+
return { pill: answer.retire ? await retirePill(target, fields.pill) : null };
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* Retires a pill, and moves it out of the way of the agents that open every pill to see which apply.
|
|
481
|
+
*
|
|
482
|
+
* @param {string} target - The project directory.
|
|
483
|
+
* @param {string} rel - The pill, relative to the project.
|
|
484
|
+
* @returns {Promise<string|null>} The pill retired, or null when there is none at that path.
|
|
485
|
+
*/
|
|
486
|
+
async function retirePill(target, rel) {
|
|
487
|
+
if (!rel || !existsSync(join(target, rel))) return null;
|
|
488
|
+
const pill = await readFile(join(target, rel), 'utf8');
|
|
414
489
|
const retired = /^status: .*$/m.test(pill) ? pill.replace(/^status: .*$/m, 'status: retired') : pill.replace(/^---\n/, '---\nstatus: retired\n');
|
|
415
|
-
await writeFile(join(target,
|
|
416
|
-
// And out of the way of the agents that open every pill to see which apply.
|
|
490
|
+
await writeFile(join(target, rel), retired);
|
|
417
491
|
await tidyRetired(target);
|
|
418
|
-
return
|
|
492
|
+
return rel;
|
|
419
493
|
}
|
|
420
494
|
|
|
421
495
|
/**
|
|
@@ -609,18 +683,19 @@ async function fileRequest(target, profile, layerRoot, lesson, { reopens = null,
|
|
|
609
683
|
const date = localDay(new Date().toISOString());
|
|
610
684
|
// Asked about the pill where it was learned, a retired one included: its request names that path.
|
|
611
685
|
const pill = reopens?.pill ?? lesson.rel;
|
|
612
|
-
// The directory separator becomes `__`, so `reviewer/a.b.md` and `reviewer-a/b.md` stay two
|
|
613
|
-
// names — flattening both `/` and `.` to `-` gave them the same one.
|
|
614
|
-
const name = pill.replace(/^\.claude\/pills\//, '').replace(/\.md$/, '').replace(/\//g, '__');
|
|
615
686
|
const dir = join(target, HARNESS, 'requests');
|
|
616
|
-
// Never over a request already written: the same lesson can be sent more than once on one day.
|
|
617
|
-
let file = `${date}-${name}.md`;
|
|
618
|
-
for (let n = 1; existsSync(join(dir, file)); n += 1) file = `${date}-${name}-again${n > 1 ? `-${n}` : ''}.md`;
|
|
619
687
|
await mkdir(dir, { recursive: true });
|
|
620
|
-
const
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
688
|
+
const file = recordName(dir, pill, date);
|
|
689
|
+
// A rule this project made of its own that did not hold goes to the harness, as a rule for the layer its roles
|
|
690
|
+
// live in; one the harness shipped goes back to where it went.
|
|
691
|
+
const mine = reopens?.target === HERE;
|
|
692
|
+
const heading = mine
|
|
693
|
+
? `**A lesson this project made a rule in \`${reopens.rule_in}\` came back ${recurred} time(s) since** — the rule did not hold here, ` +
|
|
694
|
+
`so it goes to the harness, proposed as a rule in \`${target_.layer}\`: ${target_.why}. It reopens ${HARNESS}/requests/${reopens.file}.`
|
|
695
|
+
: reopens
|
|
696
|
+
? `**A lesson that graduated into \`${reopens.rule_in || reopens.target}\` in ${reopens.answered_in || 'a release'} came back ${recurred} time(s) since** — ` +
|
|
697
|
+
`the rule did not hold here. It reopens ${HARNESS}/requests/${reopens.file}.`
|
|
698
|
+
: `**A lesson this project has learned ${lesson.occurrences} time(s), proposed as a rule in \`${target_.layer}\`** — ${target_.why}.`;
|
|
624
699
|
await writeFile(
|
|
625
700
|
join(dir, file),
|
|
626
701
|
[
|
|
@@ -629,7 +704,7 @@ async function fileRequest(target, profile, layerRoot, lesson, { reopens = null,
|
|
|
629
704
|
'status: open',
|
|
630
705
|
`date: ${date}`,
|
|
631
706
|
`core: ${profile.core}`,
|
|
632
|
-
`target: ${reopens
|
|
707
|
+
`target: ${reopens && !mine ? reopens.target || target_.layer : target_.layer}`,
|
|
633
708
|
`pill: ${pill}`,
|
|
634
709
|
`occurrences: ${lesson.occurrences}`,
|
|
635
710
|
...(reopens ? [`reopens: ${reopens.file}`, `rule_in: ${oneLine(reopens.rule_in)}`] : []),
|
|
@@ -649,17 +724,156 @@ async function fileRequest(target, profile, layerRoot, lesson, { reopens = null,
|
|
|
649
724
|
}
|
|
650
725
|
|
|
651
726
|
/**
|
|
652
|
-
*
|
|
653
|
-
*
|
|
727
|
+
* A file name under `.nina/requests/` for a record about one pill, never one already written: the same
|
|
728
|
+
* lesson can be recorded more than once on one day.
|
|
654
729
|
*
|
|
730
|
+
* @param {string} dir - The project's `.nina/requests/`.
|
|
731
|
+
* @param {string} pill - The pill, relative to the project.
|
|
732
|
+
* @param {string} date - Today, as the owner's day.
|
|
733
|
+
* @returns {string}
|
|
734
|
+
*/
|
|
735
|
+
function recordName(dir, pill, date) {
|
|
736
|
+
// The directory separator becomes `__`, so `reviewer/a.b.md` and `reviewer-a/b.md` stay two
|
|
737
|
+
// names — flattening both `/` and `.` to `-` gave them the same one.
|
|
738
|
+
const name = pill.replace(/^\.claude\/pills\//, '').replace(/\.md$/, '').replace(/\//g, '__');
|
|
739
|
+
let file = `${date}-${name}.md`;
|
|
740
|
+
for (let n = 1; existsSync(join(dir, file)); n += 1) file = `${date}-${name}-again${n > 1 ? `-${n}` : ''}.md`;
|
|
741
|
+
return file;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
/**
|
|
745
|
+
* Why a file cannot hold the rule a project makes of its own lesson, or null when it can.
|
|
746
|
+
*
|
|
747
|
+
* The rule goes where the project writes and its agents read. A composed file is neither — the next compose
|
|
748
|
+
* overwrites it, and the edit guard refuses the edit — so its rule goes in the project layer's copy; a pill, a
|
|
749
|
+
* plan or NINA's own records are not where a rule lives.
|
|
750
|
+
*
|
|
751
|
+
* @param {string} target - The project directory.
|
|
752
|
+
* @param {string} file - The file named, as given.
|
|
753
|
+
* @returns {Promise<string|null>}
|
|
754
|
+
*/
|
|
755
|
+
async function notHere(target, file, layerRoot, surfaces) {
|
|
756
|
+
const rel = relative(target, resolve(target, file));
|
|
757
|
+
if (!file || rel === '' || rel === '..' || rel.startsWith(`..${sep}`) || isAbsolute(rel)) return `${file || 'no file'} is not a file inside the project`;
|
|
758
|
+
const path = join(target, rel);
|
|
759
|
+
if (!(await stat(path).catch(() => null))?.isFile()) return `${rel} is not a file — write the rule first, then graduate the lesson into it`;
|
|
760
|
+
const posix = rel.split(sep).join('/');
|
|
761
|
+
const text = await readFile(path, 'utf8');
|
|
762
|
+
if (noticeOf(text)) {
|
|
763
|
+
return `${posix} is composed from the harness, and the next compose overwrites it — write the rule in this project's layer, ` +
|
|
764
|
+
`${HARNESS}/project/tree/${posix} (\`nina where ${posix}\` lists its slots), and name that file`;
|
|
765
|
+
}
|
|
766
|
+
if (posix.startsWith('.claude/pills/')) return `${posix} is a pill — a rule lives where no agent has to remember to apply it`;
|
|
767
|
+
if (posix.startsWith('.claude/plans/')) return `${posix} is a plan, work in progress — the rule outlives it`;
|
|
768
|
+
const layer = `${HARNESS}/project/tree/`;
|
|
769
|
+
if (posix.startsWith(`${HARNESS}/`) && !posix.startsWith(layer)) {
|
|
770
|
+
return `${posix} is NINA's own record — the rule goes in ${layer} or a file the project owns`;
|
|
771
|
+
}
|
|
772
|
+
// A fragment composes only into a slot its core file opens for the project: anywhere else, no agent reads it.
|
|
773
|
+
if (posix.startsWith(layer)) {
|
|
774
|
+
const composed = posix.slice(layer.length);
|
|
775
|
+
const projectSlots = (lines) => new Set(lines.split('\n').map((l) => SLOT.exec(l.trim())?.[1]).filter((s) => s?.startsWith('project.')));
|
|
776
|
+
const core = await readFile(join(layerRoot, 'core', 'tree', composed), 'utf8').catch(() => '');
|
|
777
|
+
const gate = closedGate(core, surfaces);
|
|
778
|
+
if (gate) return `${posix} is a fragment of ${composed}, which this project does not compose without the ${gate} surface — no agent would read the rule`;
|
|
779
|
+
const open = projectSlots(core);
|
|
780
|
+
if (![...projectSlots(text)].some((s) => open.has(s))) {
|
|
781
|
+
return `${posix} fills no project slot of ${composed}, so nothing composes it and no agent would read the rule — \`nina where ${composed}\` lists the slots`;
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
return null;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
/**
|
|
788
|
+
* Records a lesson this project made a rule of its own, and retires its pill.
|
|
789
|
+
*
|
|
790
|
+
* Written beside the requests and closed from the start, so the reader that watches a graduated lesson for
|
|
791
|
+
* coming back — {@link relapsed} — watches this one too, and the harness inbox lists it, where a rule every
|
|
792
|
+
* project needs can still be raised.
|
|
793
|
+
*
|
|
794
|
+
* @param {string} target - The project directory.
|
|
795
|
+
* @param {{core: string}} profile - The project's profile.
|
|
796
|
+
* @param {Awaited<ReturnType<typeof lessons>>[number]} lesson - The lesson.
|
|
797
|
+
* @param {string} rule - The file that now holds the rule, relative to the project.
|
|
798
|
+
* @returns {Promise<string>} The record's file name.
|
|
799
|
+
*/
|
|
800
|
+
async function graduateHere(target, profile, lesson, rule) {
|
|
801
|
+
const date = localDay(new Date().toISOString());
|
|
802
|
+
const dir = join(target, HARNESS, 'requests');
|
|
803
|
+
await mkdir(dir, { recursive: true });
|
|
804
|
+
const pill = learnedAt(lesson.rel);
|
|
805
|
+
const file = recordName(dir, pill, date);
|
|
806
|
+
await writeFile(
|
|
807
|
+
join(dir, file),
|
|
808
|
+
[
|
|
809
|
+
'---',
|
|
810
|
+
'kind: project-rule',
|
|
811
|
+
'status: closed',
|
|
812
|
+
`date: ${date}`,
|
|
813
|
+
`core: ${profile.core}`,
|
|
814
|
+
`target: ${HERE}`,
|
|
815
|
+
`pill: ${pill}`,
|
|
816
|
+
`occurrences: ${lesson.occurrences}`,
|
|
817
|
+
`rule_in: ${rule}`,
|
|
818
|
+
'---',
|
|
819
|
+
'',
|
|
820
|
+
`**A lesson this project has learned ${lesson.occurrences} time(s), made a rule here in \`${rule}\`** — a convention of this codebase.`,
|
|
821
|
+
'',
|
|
822
|
+
`If it comes back ${CAPTURE_AT} more times, the rule did not hold, and \`harness:check\` sends it to the harness.`,
|
|
823
|
+
'',
|
|
824
|
+
lesson.body,
|
|
825
|
+
'',
|
|
826
|
+
].join('\n'),
|
|
827
|
+
{ flag: 'wx' },
|
|
828
|
+
);
|
|
829
|
+
// A record with the pill still active would stop the asking with the lesson nowhere: both, or neither.
|
|
830
|
+
try {
|
|
831
|
+
await retirePill(target, lesson.rel);
|
|
832
|
+
} catch (error) {
|
|
833
|
+
await rm(join(dir, file), { force: true });
|
|
834
|
+
throw error;
|
|
835
|
+
}
|
|
836
|
+
return file;
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
/**
|
|
840
|
+
* `nina learn --graduate <pill>` — sends a lesson to the harness as a request; with `--here <file>`, records
|
|
841
|
+
* that the project made it a rule of its own, in that file, and retires the pill. The detector asks for one or
|
|
842
|
+
* the other once a lesson reaches three occurrences, and either can be done sooner.
|
|
843
|
+
*
|
|
844
|
+
* @param {string|null} here - The file that holds the rule, for a lesson that graduates in its own project.
|
|
655
845
|
* @returns {Promise<number>} Process exit code.
|
|
656
846
|
*/
|
|
657
|
-
async function graduate(target, profile, layerRoot, known, which) {
|
|
847
|
+
async function graduate(target, profile, layerRoot, known, which, here) {
|
|
658
848
|
const lesson = known.find((l) => l.rel === which || l.path === resolve(target, which));
|
|
659
849
|
if (!lesson) {
|
|
660
850
|
console.error(` no pill at ${which} — run \`nina learn\` to list them\n`);
|
|
661
851
|
return 1;
|
|
662
852
|
}
|
|
853
|
+
if (here !== null) {
|
|
854
|
+
// Declined is the one answer from the harness that leaves the rule to the project. A request still open is
|
|
855
|
+
// waiting on it, and a pill retired by any other record has graduated already.
|
|
856
|
+
const last = newestRecord(await filedRequests(target), learnedAt(lesson.rel));
|
|
857
|
+
if (last ? last.status !== 'declined' : lesson.retired) {
|
|
858
|
+
console.error(last ? ` ${lesson.rel} is recorded already, ${last.status}: ${HARNESS}/requests/${last.file}\n` : ` ${lesson.rel} is retired already\n`);
|
|
859
|
+
return 1;
|
|
860
|
+
}
|
|
861
|
+
const why = await notHere(target, here, layerRoot, profile.surfaces ?? []);
|
|
862
|
+
if (why) {
|
|
863
|
+
console.error(` ${why}\n`);
|
|
864
|
+
return 1;
|
|
865
|
+
}
|
|
866
|
+
const rule = relative(target, resolve(target, here)).split(sep).join('/');
|
|
867
|
+
const file = await graduateHere(target, profile, lesson, rule);
|
|
868
|
+
console.log(` made a rule here: ${lesson.rel} → ${rule}`);
|
|
869
|
+
console.log(` recorded in ${HARNESS}/requests/${file}; the pill is retired, under .claude/pills/${RETIRED}/`);
|
|
870
|
+
console.log(
|
|
871
|
+
rule.startsWith(`${HARNESS}/project/tree/`)
|
|
872
|
+
? ' `nina compose` puts it where the agents read it; commit the rule, the record and the pill together\n'
|
|
873
|
+
: ' commit the rule, the record and the pill together\n',
|
|
874
|
+
);
|
|
875
|
+
return 0;
|
|
876
|
+
}
|
|
663
877
|
if (lesson.roles.length === 0) {
|
|
664
878
|
console.error(` ${lesson.rel} names no role in applies_to, so there is no layer to send it to — \`nina pills\` says what to fix\n`);
|
|
665
879
|
return 1;
|
|
@@ -724,7 +938,8 @@ export async function learn(argv, ctx) {
|
|
|
724
938
|
if (argv.includes('--deep')) return deepReport(target, records, known, argv);
|
|
725
939
|
|
|
726
940
|
if (argv.includes('--graduate')) {
|
|
727
|
-
|
|
941
|
+
const here = argv.includes('--here') ? argv[argv.indexOf('--here') + 1] ?? '' : null;
|
|
942
|
+
return graduate(target, profile, resolved.dir, known, argv[argv.indexOf('--graduate') + 1] ?? '', here);
|
|
728
943
|
}
|
|
729
944
|
if (argv.includes('--close')) return close(target, argv[argv.indexOf('--close') + 1] ?? '');
|
|
730
945
|
|
|
@@ -734,7 +949,7 @@ export async function learn(argv, ctx) {
|
|
|
734
949
|
const targets = loops ? new Set([...loops.values()].flatMap((byToken) => [...byToken.values()].flatMap((to) => [...to.keys()]))) : null;
|
|
735
950
|
const late = overdue(records, known, new Date(), days, owners);
|
|
736
951
|
const filed = await filedRequests(target);
|
|
737
|
-
const owed =
|
|
952
|
+
const owed = undecided(known, filed);
|
|
738
953
|
|
|
739
954
|
if (check) {
|
|
740
955
|
// During `nina upgrade --apply`: this is about history, not the move — see upgrade.mjs.
|
|
@@ -751,14 +966,13 @@ export async function learn(argv, ctx) {
|
|
|
751
966
|
} catch (error) {
|
|
752
967
|
exported = `the export to Langfuse could not start — ${error.message}`;
|
|
753
968
|
}
|
|
754
|
-
// A lesson at three occurrences used to be
|
|
755
|
-
//
|
|
756
|
-
//
|
|
757
|
-
//
|
|
758
|
-
//
|
|
969
|
+
// A lesson at three occurrences used to be filed here as a request to the harness, which decided where it
|
|
970
|
+
// went before anyone asked: a convention of one codebase went the whole way and came back still a pill. Where
|
|
971
|
+
// a lesson graduates is the project's judgment, so it is asked for, every turn until it is made (`undecided`).
|
|
972
|
+
// A lesson that came back after it graduated is no judgment — the rule did not hold — and goes to the
|
|
973
|
+
// harness on its own, said once.
|
|
759
974
|
const sent = [];
|
|
760
|
-
|
|
761
|
-
const outgoing = [...owed.map((lesson) => ({ lesson })), ...relapsed(known, filed).filter((r) => r.due).map(({ lesson, request, recurred }) => ({ lesson, reopens: request, recurred }))];
|
|
975
|
+
const outgoing = relapsed(known, filed).filter((r) => r.due).map(({ lesson, request, recurred }) => ({ lesson, reopens: request, recurred }));
|
|
762
976
|
const stuck = outgoing
|
|
763
977
|
.filter((o) => o.lesson.roles.length === 0)
|
|
764
978
|
.map((o) => ({ ...o, why: 'names no role in applies_to, so no layer can take it', fix: 'fix its frontmatter — `nina pills` says what is wrong' }));
|
|
@@ -775,7 +989,7 @@ export async function learn(argv, ctx) {
|
|
|
775
989
|
stuck.push({ ...o, why: `could not be written to ${HARNESS}/requests/ — ${error.message}`, fix: `make it writable, or send it by hand: \`nina learn --graduate ${o.lesson.rel}\`` });
|
|
776
990
|
}
|
|
777
991
|
}
|
|
778
|
-
if (late.length === 0 && sent.length === 0 && due.length === 0 && stuck.length === 0 && !exported) {
|
|
992
|
+
if (late.length === 0 && owed.length === 0 && sent.length === 0 && due.length === 0 && stuck.length === 0 && !exported) {
|
|
779
993
|
console.log('learn: current');
|
|
780
994
|
return 0;
|
|
781
995
|
}
|
|
@@ -788,12 +1002,27 @@ export async function learn(argv, ctx) {
|
|
|
788
1002
|
for (const r of o.recent) console.log(` ${r.ts} ${r.desc || '(no description)'} session ${r.session}`);
|
|
789
1003
|
console.log(' → ask of each whether it would happen again; if so, write the pill, or bump `occurrences` and `last_seen` on the one that already says it');
|
|
790
1004
|
}
|
|
791
|
-
const
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
1005
|
+
for (const { lesson, declined } of owed) {
|
|
1006
|
+
const here = `\`nina learn --graduate ${lesson.rel} --here <file>\``;
|
|
1007
|
+
if (declined) {
|
|
1008
|
+
console.log(` ${lesson.rel} was declined by the harness${declined.answered_in ? ` in ${declined.answered_in}` : ''}: ${declined.declined || 'no reason recorded'}`);
|
|
1009
|
+
console.log(
|
|
1010
|
+
lesson.retired
|
|
1011
|
+
? ` → the rule this project made did not hold: make it again where its agents read it — in its layer under ${HARNESS}/project/tree/, or a file it owns — then ${here}; or, if the reason says a rule already covers it, \`nina learn --close ${declined.file}\``
|
|
1012
|
+
: ` → make it a rule of this project — in its layer under ${HARNESS}/project/tree/, or a file it owns — then ${here}; or, if the reason says a rule already covers it, set the pill's status to retired`,
|
|
1013
|
+
);
|
|
1014
|
+
continue;
|
|
1015
|
+
}
|
|
1016
|
+
console.log(` ${lesson.rel} has recurred ${lesson.occurrences} times — a rule, not a pill. Where it goes is this project's call:`);
|
|
1017
|
+
console.log(` → a convention of this codebase: write the rule in this project's layer under ${HARNESS}/project/tree/ (\`nina where <file>\` lists the slots) or in a file it owns, then ${here}`);
|
|
1018
|
+
console.log(` → a rule any project of this shape needs: \`nina learn --graduate ${lesson.rel}\` sends it to the harness; commit the request with the pill`);
|
|
1019
|
+
}
|
|
1020
|
+
const what = (o) => `${o.lesson.rel} came back ${o.recurred} time(s) after ${ruleWent(o.reopens)}`;
|
|
795
1021
|
for (const s of sent) {
|
|
796
|
-
console.log(
|
|
1022
|
+
console.log(
|
|
1023
|
+
` ${what(s)} — sent to the harness as ${HARNESS}/requests/${s.file}` +
|
|
1024
|
+
(s.reopens.target === HERE ? `, the rule this project made having not held: proposed for ${s.layer}` : ', reopening the rule'),
|
|
1025
|
+
);
|
|
797
1026
|
console.log(' → commit it with the pill; nothing else is owed here. `nina upgrade` to the release that answers it closes it and retires the pill');
|
|
798
1027
|
}
|
|
799
1028
|
for (const o of due) {
|
|
@@ -807,6 +1036,7 @@ export async function learn(argv, ctx) {
|
|
|
807
1036
|
console.log(
|
|
808
1037
|
`learn: ${[
|
|
809
1038
|
late.length && `${late.length} role(s) keep being sent back with nothing written down`,
|
|
1039
|
+
owed.length && `${owed.length} lesson(s) to graduate, here or in the harness`,
|
|
810
1040
|
sent.length && `${sent.length} lesson(s) sent to the harness`,
|
|
811
1041
|
due.length && `${due.length} lesson(s) to send to the harness`,
|
|
812
1042
|
stuck.length && `${stuck.length} lesson(s) cannot be sent`,
|
|
@@ -844,16 +1074,24 @@ export async function learn(argv, ctx) {
|
|
|
844
1074
|
`${use.listed} only listed the directory — measured since ${use.from}. Reading is not obeying; nothing here can see that.`
|
|
845
1075
|
: ' apply not measured yet — runs recorded from now on say whether they read their pills',
|
|
846
1076
|
);
|
|
1077
|
+
const madeHere = filed.filter((r) => r.target === HERE).length;
|
|
847
1078
|
console.log(
|
|
848
1079
|
` graduate ${ready.length} lesson(s) at ${GRADUATION_AT}+ occurrences · ${open.length} request(s) open` +
|
|
1080
|
+
(madeHere ? ` · ${madeHere} made a rule here` : '') +
|
|
849
1081
|
(Math.max(0, ...active.map((l) => l.occurrences)) < 2
|
|
850
1082
|
? ' — no lesson has ever been counted twice; bump `occurrences` when one recurs'
|
|
851
1083
|
: ''),
|
|
852
1084
|
);
|
|
853
|
-
for (const
|
|
1085
|
+
for (const { lesson, declined } of owed) {
|
|
1086
|
+
console.log(
|
|
1087
|
+
declined
|
|
1088
|
+
? ` declined by the harness: ${lesson.rel} — make it a rule here, \`nina learn --graduate ${lesson.rel} --here <file>\``
|
|
1089
|
+
: ` to graduate: ${lesson.rel} — here (\`--graduate ${lesson.rel} --here <file>\`) or in the harness (\`--graduate ${lesson.rel}\`)`,
|
|
1090
|
+
);
|
|
1091
|
+
}
|
|
854
1092
|
for (const r of open) console.log(` open since ${r.date}: ${r.pill} → ${r.target}. \`nina upgrade\` to the release that answers it closes it`);
|
|
855
1093
|
for (const r of relapsed(known, filed)) {
|
|
856
|
-
const shipped = `came back ${r.recurred} time(s) after
|
|
1094
|
+
const shipped = `came back ${r.recurred} time(s) after ${ruleWent(r.request, false)}`;
|
|
857
1095
|
if (r.due) console.log(` ✗ ${r.lesson.rel} ${shipped} — the rule did not hold; \`harness:check\` reopens it`);
|
|
858
1096
|
else console.log(` · ${r.lesson.rel} ${shipped} — watched; it reopens at ${CAPTURE_AT}`);
|
|
859
1097
|
}
|
|
@@ -990,6 +1228,10 @@ async function recordAnswer(argv, ctx, open) {
|
|
|
990
1228
|
export async function requests(argv = [], ctx = { root: '.' }) {
|
|
991
1229
|
const check = argv.includes('--check');
|
|
992
1230
|
const found = [];
|
|
1231
|
+
// What projects made rules of their own lately: theirs to make, and listed so one every project needs can
|
|
1232
|
+
// still be raised into a layer here — a project can misjudge a rule as its own.
|
|
1233
|
+
const since = localDay(new Date(Date.now() - MADE_HERE_DAYS * 86_400_000).toISOString());
|
|
1234
|
+
const madeHere = [];
|
|
993
1235
|
const files = (await readdir(snapshotsDir()).catch(() => [])).filter((f) => f.endsWith('.jsonl'));
|
|
994
1236
|
for (const file of files) {
|
|
995
1237
|
const dir = decodeProjectDir(file.replace(/\.jsonl$/, ''));
|
|
@@ -998,6 +1240,7 @@ export async function requests(argv = [], ctx = { root: '.' }) {
|
|
|
998
1240
|
for (const f of (await readdir(reqDir).catch(() => [])).filter((f) => f.endsWith('.md'))) {
|
|
999
1241
|
const fields = frontmatter(await readFile(join(reqDir, f), 'utf8'));
|
|
1000
1242
|
if (fields?.status === 'open') found.push({ dir, f, id: f.replace(/\.md$/, ''), fields });
|
|
1243
|
+
else if (fields?.target === HERE && String(fields.date ?? '') >= since) madeHere.push({ dir, fields });
|
|
1001
1244
|
}
|
|
1002
1245
|
}
|
|
1003
1246
|
if (argv.includes('--answer') || argv.includes('--decline')) return recordAnswer(argv, ctx, found);
|
|
@@ -1031,8 +1274,18 @@ export async function requests(argv = [], ctx = { root: '.' }) {
|
|
|
1031
1274
|
);
|
|
1032
1275
|
return 1;
|
|
1033
1276
|
}
|
|
1277
|
+
const listMadeHere = () => {
|
|
1278
|
+
if (madeHere.length === 0) return;
|
|
1279
|
+
console.log(` ${madeHere.length} lesson(s) made a rule in their own project in the last ${MADE_HERE_DAYS} days — one every project needs goes into a layer here:\n`);
|
|
1280
|
+
for (const m of madeHere) {
|
|
1281
|
+
console.log(` ${m.fields.date} ${m.fields.pill} → ${m.fields.rule_in}`);
|
|
1282
|
+
console.log(` ${m.dir}`);
|
|
1283
|
+
}
|
|
1284
|
+
console.log('');
|
|
1285
|
+
};
|
|
1034
1286
|
if (found.length === 0) {
|
|
1035
1287
|
console.log(' no open requests — no project has graduated a lesson to the harness\n');
|
|
1288
|
+
listMadeHere();
|
|
1036
1289
|
return 0;
|
|
1037
1290
|
}
|
|
1038
1291
|
console.log(`\n ${found.length} open request(s)\n`);
|
|
@@ -1047,5 +1300,6 @@ export async function requests(argv = [], ctx = { root: '.' }) {
|
|
|
1047
1300
|
console.log(` ${state}`);
|
|
1048
1301
|
}
|
|
1049
1302
|
console.log('');
|
|
1303
|
+
listMadeHere();
|
|
1050
1304
|
return 0;
|
|
1051
1305
|
}
|
package/src/commands/pills.mjs
CHANGED
|
@@ -445,18 +445,21 @@ export async function pills(argv, ctx) {
|
|
|
445
445
|
}
|
|
446
446
|
if (cited > 0) notes.push(`${resolved} of ${cited} citation(s) still resolve`);
|
|
447
447
|
|
|
448
|
-
// A lesson learned three times is not a correction any more; it is a rule nobody wrote down.
|
|
449
|
-
//
|
|
450
|
-
//
|
|
448
|
+
// A lesson learned three times is not a correction any more; it is a rule nobody wrote down. A convention of
|
|
449
|
+
// this codebase becomes one here; one every project of its shape needs goes to the harness as a request, since
|
|
450
|
+
// a project cannot write the harness, and waits — a pill retired before its rule arrives leaves the lesson nowhere.
|
|
451
451
|
for (const c of candidates) {
|
|
452
452
|
const home = gates && c.applies.length > 0 ? graduationTarget(c.applies, gates) : null;
|
|
453
|
-
const
|
|
453
|
+
const pill = `.claude/pills/${c.label}`;
|
|
454
|
+
const asked = requested.get(pill);
|
|
454
455
|
notes.push(
|
|
455
456
|
`${c.label} has recurred ${c.seen} times — that is a rule, not a pill.` +
|
|
456
|
-
(
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
457
|
+
(asked?.status === 'declined'
|
|
458
|
+
? ` The harness declined it on ${asked.date}: make it a rule here, then \`nina learn --graduate ${pill} --here <file>\` retires it.`
|
|
459
|
+
: asked
|
|
460
|
+
? ` It went to the harness as a request on ${asked.date} (${asked.status}); the \`nina upgrade\` to the release that answers it retires this pill.`
|
|
461
|
+
: ` A convention of this codebase becomes a rule here — \`nina learn --graduate ${pill} --here <file>\` retires it;` +
|
|
462
|
+
` one any project of this shape needs goes to the harness with \`nina learn --graduate ${pill}\`${home ? `, and its home there is ${home.layer}, since ${home.why}` : ''}.`),
|
|
460
463
|
);
|
|
461
464
|
}
|
|
462
465
|
|
package/src/commands/upgrade.mjs
CHANGED
|
@@ -618,7 +618,7 @@ export async function upgrade(argv, ctx) {
|
|
|
618
618
|
} else if (a.status === 'closed') {
|
|
619
619
|
console.log(` closed ${HARNESS}/requests/${a.file} — the rule is now in ${a.where}${a.pill ? `; retired ${a.pill}` : ''}`);
|
|
620
620
|
} else {
|
|
621
|
-
console.log(` declined ${HARNESS}/requests/${a.file} — ${a.why}. The pill stays active
|
|
621
|
+
console.log(` declined ${HARNESS}/requests/${a.file} — ${a.why}. The pill stays active until this project makes it a rule of its own.`);
|
|
622
622
|
}
|
|
623
623
|
}
|
|
624
624
|
}
|
package/src/office.html
CHANGED
|
@@ -929,7 +929,7 @@ function drawPerson(p, now) {
|
|
|
929
929
|
|
|
930
930
|
function drawBubble(p) {
|
|
931
931
|
if (!p.bubble) return;
|
|
932
|
-
// Seated, beside the head: above it, the bubble would
|
|
932
|
+
// Seated, beside the head: above it, the bubble would sit on the desk being worked at.
|
|
933
933
|
if (p.pose === 'sit') paint(w, BUBBLE[p.bubble.kind], p.x + 5, p.y - 24, BUBBLE_COLORS);
|
|
934
934
|
else paint(w, BUBBLE[p.bubble.kind], p.x - 4, p.y - 27, BUBBLE_COLORS);
|
|
935
935
|
}
|
|
@@ -1041,9 +1041,10 @@ function drawScreen(now) {
|
|
|
1041
1041
|
text(room.name, x, y, label, C.signText, 'left', (signWidth(room) - 7) * scale, '600', SANS);
|
|
1042
1042
|
}
|
|
1043
1043
|
for (const stage of stages.values()) {
|
|
1044
|
+
// Above the screen, its bottom edge on it: on the desk's front, it covered the head of whoever sat there.
|
|
1044
1045
|
for (const d of stage.desks) {
|
|
1045
|
-
const [x, y] = at(d.dx + 18, d.dy
|
|
1046
|
-
plate(stage.role, x, y, label, '#fff8e8', (DESK_STEP - 4) * scale);
|
|
1046
|
+
const [x, y] = at(d.dx + 18, d.dy - 1);
|
|
1047
|
+
plate(stage.role, x, y - (label + ui(6)) / 2, label, '#fff8e8', (DESK_STEP - 4) * scale);
|
|
1047
1048
|
}
|
|
1048
1049
|
}
|
|
1049
1050
|
{
|