@xhulz/nina 0.38.0 → 0.40.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/package.json +1 -1
- package/releases/0.39.0/core/GAPS.md +125 -0
- package/releases/0.39.0/core/answered.json +32 -0
- package/releases/0.39.0/core/defaults/tree/.claude/agents/architect.md +1 -0
- package/releases/0.39.0/core/defaults/tree/.claude/agents/dba.md +3 -0
- package/releases/0.39.0/core/defaults/tree/.claude/agents/devops.md +1 -0
- package/releases/0.39.0/core/defaults/tree/.claude/agents/implementer.md +1 -0
- package/releases/0.39.0/core/defaults/tree/.claude/agents/integration-tester.md +3 -0
- package/releases/0.39.0/core/defaults/tree/.claude/agents/qa.md +2 -0
- package/releases/0.39.0/core/defaults/tree/.claude/agents/reviewer.md +3 -0
- package/releases/0.39.0/core/defaults/tree/.claude/agents/secops.md +3 -0
- package/releases/0.39.0/core/defaults/tree/.claude/agents/solidity-auditor.md +3 -0
- package/releases/0.39.0/core/defaults/tree/.claude/agents/solidity-dev.md +3 -0
- package/releases/0.39.0/core/tree/.claude/agents/architect.md +127 -0
- package/releases/0.39.0/core/tree/.claude/agents/dba.md +110 -0
- package/releases/0.39.0/core/tree/.claude/agents/devops.md +114 -0
- package/releases/0.39.0/core/tree/.claude/agents/implementer.md +156 -0
- package/releases/0.39.0/core/tree/.claude/agents/integration-tester.md +168 -0
- package/releases/0.39.0/core/tree/.claude/agents/planner.md +132 -0
- package/releases/0.39.0/core/tree/.claude/agents/qa.md +152 -0
- package/releases/0.39.0/core/tree/.claude/agents/reviewer.md +183 -0
- package/releases/0.39.0/core/tree/.claude/agents/secops.md +121 -0
- package/releases/0.39.0/core/tree/.claude/agents/solidity-auditor.md +126 -0
- package/releases/0.39.0/core/tree/.claude/agents/solidity-dev.md +123 -0
- package/releases/0.39.0/core/tree/.claude/agents-overview.md +64 -0
- package/releases/0.39.0/core/tree/.claude/frontend.md +10 -0
- package/releases/0.39.0/core/tree/.claude/graph.md +75 -0
- package/releases/0.39.0/core/tree/.claude/patterns.md +213 -0
- package/releases/0.39.0/core/tree/.claude/pills/README.md +147 -0
- package/releases/0.39.0/core/tree/.claude/pipeline.md +101 -0
- package/releases/0.39.0/core/tree/.claude/retrieval.md +103 -0
- package/releases/0.39.0/core/tree/.claude/router.md +198 -0
- package/releases/0.39.0/core/tree/.claude/templates/integration.md +45 -0
- package/releases/0.39.0/core/tree/CLAUDE.md +163 -0
- package/releases/0.39.0/core/tree/scripts/cost-watch.mjs +18 -0
- package/releases/0.39.0/core/tree/scripts/edit-guard.mjs +24 -0
- package/releases/0.39.0/core/tree/scripts/harness-check.mjs +71 -0
- package/releases/0.39.0/core/tree/scripts/loop-gate.mjs +19 -0
- package/releases/0.39.0/core/vocabulary.json +13 -0
- package/releases/0.39.0/surfaces/blockchain/tree/.claude/agents/architect.md +5 -0
- package/releases/0.39.0/surfaces/blockchain/tree/.claude/agents/devops.md +5 -0
- package/releases/0.39.0/surfaces/blockchain/tree/.claude/agents/reviewer.md +5 -0
- package/releases/0.39.0/surfaces/blockchain/tree/.claude/agents/solidity-auditor.md +18 -0
- package/releases/0.39.0/surfaces/blockchain/tree/.claude/agents/solidity-dev.md +16 -0
- package/releases/0.39.0/surfaces/blockchain/tree/.claude/agents-overview.md +6 -0
- package/releases/0.39.0/surfaces/blockchain/tree/.claude/graph.md +11 -0
- package/releases/0.39.0/surfaces/blockchain/tree/.claude/router.md +6 -0
- package/releases/0.39.0/surfaces/blockchain/tree/CLAUDE.md +12 -0
- package/releases/0.39.0/surfaces/db/tree/.claude/agents/architect.md +5 -0
- package/releases/0.39.0/surfaces/db/tree/.claude/agents/dba.md +50 -0
- package/releases/0.39.0/surfaces/db/tree/.claude/agents/devops.md +5 -0
- package/releases/0.39.0/surfaces/db/tree/.claude/agents/implementer.md +2 -0
- package/releases/0.39.0/surfaces/db/tree/.claude/agents/integration-tester.md +10 -0
- package/releases/0.39.0/surfaces/db/tree/.claude/agents/planner.md +2 -0
- package/releases/0.39.0/surfaces/db/tree/.claude/agents/reviewer.md +22 -0
- package/releases/0.39.0/surfaces/db/tree/.claude/agents/secops.md +2 -0
- package/releases/0.39.0/surfaces/db/tree/.claude/agents-overview.md +5 -0
- package/releases/0.39.0/surfaces/db/tree/.claude/graph.md +8 -0
- package/releases/0.39.0/surfaces/db/tree/.claude/patterns.md +19 -0
- package/releases/0.39.0/surfaces/db/tree/.claude/pipeline.md +13 -0
- package/releases/0.39.0/surfaces/db/tree/.claude/retrieval.md +5 -0
- package/releases/0.39.0/surfaces/db/tree/.claude/router.md +4 -0
- package/releases/0.39.0/surfaces/db/tree/CLAUDE.md +17 -0
- package/releases/0.39.0/surfaces/edge-cf/tree/.claude/agents/architect.md +14 -0
- package/releases/0.39.0/surfaces/edge-cf/tree/.claude/agents/dba.md +2 -0
- package/releases/0.39.0/surfaces/edge-cf/tree/.claude/agents/devops.md +32 -0
- package/releases/0.39.0/surfaces/edge-cf/tree/.claude/agents/implementer.md +14 -0
- package/releases/0.39.0/surfaces/edge-cf/tree/.claude/agents/integration-tester.md +11 -0
- package/releases/0.39.0/surfaces/edge-cf/tree/.claude/agents/qa.md +3 -0
- package/releases/0.39.0/surfaces/edge-cf/tree/.claude/agents/reviewer.md +8 -0
- package/releases/0.39.0/surfaces/edge-cf/tree/.claude/agents/secops.md +8 -0
- package/releases/0.39.0/surfaces/edge-cf/tree/.claude/patterns.md +17 -0
- package/releases/0.39.0/surfaces/edge-cf/tree/.claude/retrieval.md +8 -0
- package/releases/0.39.0/surfaces/edge-cf/tree/CLAUDE.md +27 -0
- package/releases/0.39.0/surfaces/frontend/tree/.claude/agents/architect.md +20 -0
- package/releases/0.39.0/surfaces/frontend/tree/.claude/agents/devops.md +28 -0
- package/releases/0.39.0/surfaces/frontend/tree/.claude/agents/implementer.md +25 -0
- package/releases/0.39.0/surfaces/frontend/tree/.claude/agents/qa.md +17 -0
- package/releases/0.39.0/surfaces/frontend/tree/.claude/agents/reviewer.md +56 -0
- package/releases/0.39.0/surfaces/frontend/tree/.claude/patterns.md +8 -0
- package/releases/0.39.0/surfaces/frontend/tree/.claude/retrieval.md +2 -0
- package/releases/0.39.0/surfaces/frontend/tree/.claude/router.md +14 -0
- package/releases/0.39.0/surfaces/frontend/tree/CLAUDE.md +5 -0
- package/releases/0.39.0/surfaces/integrations/tree/.claude/agents/architect.md +16 -0
- package/releases/0.39.0/surfaces/integrations/tree/.claude/agents/implementer.md +12 -0
- package/releases/0.39.0/surfaces/integrations/tree/.claude/agents/integration-tester.md +20 -0
- package/releases/0.39.0/surfaces/integrations/tree/.claude/agents/planner.md +2 -0
- package/releases/0.39.0/surfaces/integrations/tree/.claude/agents/reviewer.md +21 -0
- package/releases/0.39.0/surfaces/integrations/tree/.claude/agents/secops.md +2 -0
- package/releases/0.39.0/surfaces/integrations/tree/.claude/agents-overview.md +8 -0
- package/releases/0.39.0/surfaces/integrations/tree/.claude/graph.md +10 -0
- package/releases/0.39.0/surfaces/integrations/tree/.claude/patterns.md +38 -0
- package/releases/0.39.0/surfaces/integrations/tree/.claude/pipeline.md +16 -0
- package/releases/0.39.0/surfaces/integrations/tree/.claude/retrieval.md +16 -0
- package/releases/0.39.0/surfaces/integrations/tree/.claude/router.md +6 -0
- package/releases/0.39.0/surfaces/integrations/tree/CLAUDE.md +17 -0
- package/releases/0.39.0/surfaces/money/tree/.claude/agents/architect.md +12 -0
- package/releases/0.39.0/surfaces/money/tree/.claude/agents/dba.md +14 -0
- package/releases/0.39.0/surfaces/money/tree/.claude/agents/implementer.md +11 -0
- package/releases/0.39.0/surfaces/money/tree/.claude/agents/integration-tester.md +3 -0
- package/releases/0.39.0/surfaces/money/tree/.claude/agents/reviewer.md +23 -0
- package/releases/0.39.0/surfaces/money/tree/.claude/agents/secops.md +5 -0
- package/releases/0.39.0/surfaces/money/tree/.claude/agents/solidity-auditor.md +4 -0
- package/releases/0.39.0/surfaces/money/tree/.claude/agents/solidity-dev.md +4 -0
- package/releases/0.39.0/surfaces/money/tree/.claude/graph.md +2 -0
- package/releases/0.39.0/surfaces/money/tree/.claude/patterns.md +49 -0
- package/releases/0.39.0/surfaces/money/tree/.claude/pipeline.md +2 -0
- package/releases/0.39.0/surfaces/money/tree/.claude/retrieval.md +2 -0
- package/releases/0.39.0/surfaces/money/tree/CLAUDE.md +11 -0
- package/releases/0.39.0/surfaces/pii/tree/.claude/agents/dba.md +2 -0
- package/releases/0.39.0/surfaces/pii/tree/.claude/agents/devops.md +8 -0
- package/releases/0.39.0/surfaces/pii/tree/.claude/agents/reviewer.md +8 -0
- package/releases/0.39.0/surfaces/pii/tree/.claude/agents/secops.md +2 -0
- package/releases/0.39.0/surfaces/pii/tree/.claude/agents/solidity-auditor.md +5 -0
- package/releases/0.39.0/surfaces/pii/tree/CLAUDE.md +5 -0
- package/releases/0.39.0/surfaces/prisma/tree/.claude/agents/architect.md +2 -0
- package/releases/0.39.0/surfaces/prisma/tree/.claude/agents/dba.md +39 -0
- package/releases/0.39.0/surfaces/prisma/tree/.claude/agents/devops.md +11 -0
- package/releases/0.39.0/surfaces/prisma/tree/.claude/agents/implementer.md +2 -0
- package/releases/0.39.0/surfaces/prisma/tree/.claude/agents/integration-tester.md +2 -0
- package/releases/0.39.0/surfaces/prisma/tree/.claude/agents/reviewer.md +2 -0
- package/releases/0.39.0/surfaces/prisma/tree/.claude/patterns.md +15 -0
- package/releases/0.39.0/surfaces/prisma/tree/CLAUDE.md +5 -0
- package/releases/0.40.0/core/GAPS.md +125 -0
- package/releases/0.40.0/core/answered.json +32 -0
- package/releases/0.40.0/core/defaults/tree/.claude/agents/architect.md +1 -0
- package/releases/0.40.0/core/defaults/tree/.claude/agents/dba.md +3 -0
- package/releases/0.40.0/core/defaults/tree/.claude/agents/devops.md +1 -0
- package/releases/0.40.0/core/defaults/tree/.claude/agents/implementer.md +1 -0
- package/releases/0.40.0/core/defaults/tree/.claude/agents/integration-tester.md +3 -0
- package/releases/0.40.0/core/defaults/tree/.claude/agents/qa.md +2 -0
- package/releases/0.40.0/core/defaults/tree/.claude/agents/reviewer.md +3 -0
- package/releases/0.40.0/core/defaults/tree/.claude/agents/secops.md +3 -0
- package/releases/0.40.0/core/defaults/tree/.claude/agents/solidity-auditor.md +3 -0
- package/releases/0.40.0/core/defaults/tree/.claude/agents/solidity-dev.md +3 -0
- package/releases/0.40.0/core/tree/.claude/agents/architect.md +127 -0
- package/releases/0.40.0/core/tree/.claude/agents/dba.md +110 -0
- package/releases/0.40.0/core/tree/.claude/agents/devops.md +114 -0
- package/releases/0.40.0/core/tree/.claude/agents/implementer.md +156 -0
- package/releases/0.40.0/core/tree/.claude/agents/integration-tester.md +168 -0
- package/releases/0.40.0/core/tree/.claude/agents/planner.md +132 -0
- package/releases/0.40.0/core/tree/.claude/agents/qa.md +152 -0
- package/releases/0.40.0/core/tree/.claude/agents/reviewer.md +183 -0
- package/releases/0.40.0/core/tree/.claude/agents/secops.md +121 -0
- package/releases/0.40.0/core/tree/.claude/agents/solidity-auditor.md +126 -0
- package/releases/0.40.0/core/tree/.claude/agents/solidity-dev.md +123 -0
- package/releases/0.40.0/core/tree/.claude/agents-overview.md +64 -0
- package/releases/0.40.0/core/tree/.claude/frontend.md +10 -0
- package/releases/0.40.0/core/tree/.claude/graph.md +75 -0
- package/releases/0.40.0/core/tree/.claude/patterns.md +213 -0
- package/releases/0.40.0/core/tree/.claude/pills/README.md +147 -0
- package/releases/0.40.0/core/tree/.claude/pipeline.md +101 -0
- package/releases/0.40.0/core/tree/.claude/retrieval.md +103 -0
- package/releases/0.40.0/core/tree/.claude/router.md +198 -0
- package/releases/0.40.0/core/tree/.claude/templates/integration.md +45 -0
- package/releases/0.40.0/core/tree/CLAUDE.md +163 -0
- package/releases/0.40.0/core/tree/scripts/cost-watch.mjs +25 -0
- package/releases/0.40.0/core/tree/scripts/edit-guard.mjs +24 -0
- package/releases/0.40.0/core/tree/scripts/harness-check.mjs +71 -0
- package/releases/0.40.0/core/tree/scripts/loop-gate.mjs +19 -0
- package/releases/0.40.0/core/vocabulary.json +13 -0
- package/releases/0.40.0/surfaces/blockchain/tree/.claude/agents/architect.md +5 -0
- package/releases/0.40.0/surfaces/blockchain/tree/.claude/agents/devops.md +5 -0
- package/releases/0.40.0/surfaces/blockchain/tree/.claude/agents/reviewer.md +5 -0
- package/releases/0.40.0/surfaces/blockchain/tree/.claude/agents/solidity-auditor.md +18 -0
- package/releases/0.40.0/surfaces/blockchain/tree/.claude/agents/solidity-dev.md +16 -0
- package/releases/0.40.0/surfaces/blockchain/tree/.claude/agents-overview.md +6 -0
- package/releases/0.40.0/surfaces/blockchain/tree/.claude/graph.md +11 -0
- package/releases/0.40.0/surfaces/blockchain/tree/.claude/router.md +6 -0
- package/releases/0.40.0/surfaces/blockchain/tree/CLAUDE.md +12 -0
- package/releases/0.40.0/surfaces/db/tree/.claude/agents/architect.md +5 -0
- package/releases/0.40.0/surfaces/db/tree/.claude/agents/dba.md +50 -0
- package/releases/0.40.0/surfaces/db/tree/.claude/agents/devops.md +5 -0
- package/releases/0.40.0/surfaces/db/tree/.claude/agents/implementer.md +2 -0
- package/releases/0.40.0/surfaces/db/tree/.claude/agents/integration-tester.md +10 -0
- package/releases/0.40.0/surfaces/db/tree/.claude/agents/planner.md +2 -0
- package/releases/0.40.0/surfaces/db/tree/.claude/agents/reviewer.md +22 -0
- package/releases/0.40.0/surfaces/db/tree/.claude/agents/secops.md +2 -0
- package/releases/0.40.0/surfaces/db/tree/.claude/agents-overview.md +5 -0
- package/releases/0.40.0/surfaces/db/tree/.claude/graph.md +8 -0
- package/releases/0.40.0/surfaces/db/tree/.claude/patterns.md +19 -0
- package/releases/0.40.0/surfaces/db/tree/.claude/pipeline.md +13 -0
- package/releases/0.40.0/surfaces/db/tree/.claude/retrieval.md +5 -0
- package/releases/0.40.0/surfaces/db/tree/.claude/router.md +4 -0
- package/releases/0.40.0/surfaces/db/tree/CLAUDE.md +17 -0
- package/releases/0.40.0/surfaces/edge-cf/tree/.claude/agents/architect.md +14 -0
- package/releases/0.40.0/surfaces/edge-cf/tree/.claude/agents/dba.md +2 -0
- package/releases/0.40.0/surfaces/edge-cf/tree/.claude/agents/devops.md +32 -0
- package/releases/0.40.0/surfaces/edge-cf/tree/.claude/agents/implementer.md +14 -0
- package/releases/0.40.0/surfaces/edge-cf/tree/.claude/agents/integration-tester.md +11 -0
- package/releases/0.40.0/surfaces/edge-cf/tree/.claude/agents/qa.md +3 -0
- package/releases/0.40.0/surfaces/edge-cf/tree/.claude/agents/reviewer.md +8 -0
- package/releases/0.40.0/surfaces/edge-cf/tree/.claude/agents/secops.md +8 -0
- package/releases/0.40.0/surfaces/edge-cf/tree/.claude/patterns.md +17 -0
- package/releases/0.40.0/surfaces/edge-cf/tree/.claude/retrieval.md +8 -0
- package/releases/0.40.0/surfaces/edge-cf/tree/CLAUDE.md +27 -0
- package/releases/0.40.0/surfaces/frontend/tree/.claude/agents/architect.md +20 -0
- package/releases/0.40.0/surfaces/frontend/tree/.claude/agents/devops.md +28 -0
- package/releases/0.40.0/surfaces/frontend/tree/.claude/agents/implementer.md +25 -0
- package/releases/0.40.0/surfaces/frontend/tree/.claude/agents/qa.md +17 -0
- package/releases/0.40.0/surfaces/frontend/tree/.claude/agents/reviewer.md +56 -0
- package/releases/0.40.0/surfaces/frontend/tree/.claude/patterns.md +8 -0
- package/releases/0.40.0/surfaces/frontend/tree/.claude/retrieval.md +2 -0
- package/releases/0.40.0/surfaces/frontend/tree/.claude/router.md +14 -0
- package/releases/0.40.0/surfaces/frontend/tree/CLAUDE.md +5 -0
- package/releases/0.40.0/surfaces/integrations/tree/.claude/agents/architect.md +16 -0
- package/releases/0.40.0/surfaces/integrations/tree/.claude/agents/implementer.md +12 -0
- package/releases/0.40.0/surfaces/integrations/tree/.claude/agents/integration-tester.md +20 -0
- package/releases/0.40.0/surfaces/integrations/tree/.claude/agents/planner.md +2 -0
- package/releases/0.40.0/surfaces/integrations/tree/.claude/agents/reviewer.md +21 -0
- package/releases/0.40.0/surfaces/integrations/tree/.claude/agents/secops.md +2 -0
- package/releases/0.40.0/surfaces/integrations/tree/.claude/agents-overview.md +8 -0
- package/releases/0.40.0/surfaces/integrations/tree/.claude/graph.md +10 -0
- package/releases/0.40.0/surfaces/integrations/tree/.claude/patterns.md +38 -0
- package/releases/0.40.0/surfaces/integrations/tree/.claude/pipeline.md +16 -0
- package/releases/0.40.0/surfaces/integrations/tree/.claude/retrieval.md +16 -0
- package/releases/0.40.0/surfaces/integrations/tree/.claude/router.md +6 -0
- package/releases/0.40.0/surfaces/integrations/tree/CLAUDE.md +17 -0
- package/releases/0.40.0/surfaces/money/tree/.claude/agents/architect.md +12 -0
- package/releases/0.40.0/surfaces/money/tree/.claude/agents/dba.md +14 -0
- package/releases/0.40.0/surfaces/money/tree/.claude/agents/implementer.md +11 -0
- package/releases/0.40.0/surfaces/money/tree/.claude/agents/integration-tester.md +3 -0
- package/releases/0.40.0/surfaces/money/tree/.claude/agents/reviewer.md +23 -0
- package/releases/0.40.0/surfaces/money/tree/.claude/agents/secops.md +5 -0
- package/releases/0.40.0/surfaces/money/tree/.claude/agents/solidity-auditor.md +4 -0
- package/releases/0.40.0/surfaces/money/tree/.claude/agents/solidity-dev.md +4 -0
- package/releases/0.40.0/surfaces/money/tree/.claude/graph.md +2 -0
- package/releases/0.40.0/surfaces/money/tree/.claude/patterns.md +49 -0
- package/releases/0.40.0/surfaces/money/tree/.claude/pipeline.md +2 -0
- package/releases/0.40.0/surfaces/money/tree/.claude/retrieval.md +2 -0
- package/releases/0.40.0/surfaces/money/tree/CLAUDE.md +11 -0
- package/releases/0.40.0/surfaces/pii/tree/.claude/agents/dba.md +2 -0
- package/releases/0.40.0/surfaces/pii/tree/.claude/agents/devops.md +8 -0
- package/releases/0.40.0/surfaces/pii/tree/.claude/agents/reviewer.md +8 -0
- package/releases/0.40.0/surfaces/pii/tree/.claude/agents/secops.md +2 -0
- package/releases/0.40.0/surfaces/pii/tree/.claude/agents/solidity-auditor.md +5 -0
- package/releases/0.40.0/surfaces/pii/tree/CLAUDE.md +5 -0
- package/releases/0.40.0/surfaces/prisma/tree/.claude/agents/architect.md +2 -0
- package/releases/0.40.0/surfaces/prisma/tree/.claude/agents/dba.md +39 -0
- package/releases/0.40.0/surfaces/prisma/tree/.claude/agents/devops.md +11 -0
- package/releases/0.40.0/surfaces/prisma/tree/.claude/agents/implementer.md +2 -0
- package/releases/0.40.0/surfaces/prisma/tree/.claude/agents/integration-tester.md +2 -0
- package/releases/0.40.0/surfaces/prisma/tree/.claude/agents/reviewer.md +2 -0
- package/releases/0.40.0/surfaces/prisma/tree/.claude/patterns.md +15 -0
- package/releases/0.40.0/surfaces/prisma/tree/CLAUDE.md +5 -0
- package/src/commands/check.mjs +15 -28
- package/src/commands/compose.mjs +50 -64
- package/src/commands/eval.mjs +1 -1
- package/src/commands/export.mjs +4 -34
- package/src/commands/gate.mjs +4 -11
- package/src/commands/init.mjs +22 -30
- package/src/commands/langfuse.mjs +1 -1
- package/src/commands/learn.mjs +10 -12
- package/src/commands/pills.mjs +5 -5
- package/src/commands/pipeline.mjs +4 -8
- package/src/commands/release.mjs +2 -3
- package/src/commands/runs.mjs +1 -1
- package/src/commands/snapshot.mjs +12 -50
- package/src/commands/stats.mjs +7 -8
- package/src/commands/status.mjs +4 -5
- package/src/commands/upgrade.mjs +9 -12
- package/src/commands/where.mjs +9 -18
- package/src/commands/wire.mjs +8 -19
- package/src/deep.mjs +3 -3
- package/src/gate.mjs +54 -7
- package/src/graph.mjs +1 -1
- package/src/guard.mjs +194 -7
- package/src/langfuse.mjs +9 -8
- package/src/lock.mjs +82 -0
- package/src/paths.mjs +65 -0
- package/src/shell.mjs +3 -3
- package/src/steps.mjs +5 -19
- package/src/store.mjs +2 -2
- package/src/wiring.mjs +20 -7
package/src/commands/check.mjs
CHANGED
|
@@ -9,14 +9,14 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { readFile, readdir } from 'node:fs/promises';
|
|
12
|
-
import {
|
|
12
|
+
import { describeMove, HARNESS, interruptedMove, readProfile, surfacesIn } from '../paths.mjs';
|
|
13
13
|
import { expectedUnfilled } from '../expected.mjs';
|
|
14
14
|
import { parseGraph, validateGraph } from '../graph.mjs';
|
|
15
15
|
import { frontmatterFindings, installedSkills, modelFindings, toolFindings } from '../tools.mjs';
|
|
16
16
|
import { HOOK_SCRIPTS, missingWiring, shippedScripts } from '../wiring.mjs';
|
|
17
17
|
import { existsSync } from 'node:fs';
|
|
18
18
|
import { join, resolve, sep } from 'node:path';
|
|
19
|
-
import {
|
|
19
|
+
import { SLOT, closedGate, defaultedSlots, layerRootFor, noticeOf, readLayerText, stripWhy, walk } from './compose.mjs';
|
|
20
20
|
import { PLACEHOLDER, defaultVocabulary } from '../vocabulary.mjs';
|
|
21
21
|
import { NEEDS } from '../surfaces.mjs';
|
|
22
22
|
|
|
@@ -49,8 +49,7 @@ export async function referencedVocabulary(layerRoot, surfaces, target) {
|
|
|
49
49
|
const found = new Set();
|
|
50
50
|
for (const rel of await walk(coreTree)) {
|
|
51
51
|
const core = await readFile(join(coreTree, rel), 'utf8');
|
|
52
|
-
|
|
53
|
-
if (requires && !surfaces.includes(requires[1])) continue;
|
|
52
|
+
if (closedGate(core, surfaces)) continue;
|
|
54
53
|
const texts = [core];
|
|
55
54
|
for (const s of surfaces) {
|
|
56
55
|
const t = await readFile(join(layerRoot, 'surfaces', s, 'tree', rel), 'utf8').catch(() => null);
|
|
@@ -80,8 +79,7 @@ export async function projectSlots(layerRoot, surfaces) {
|
|
|
80
79
|
const slots = new Set();
|
|
81
80
|
for (const rel of await walk(coreTree)) {
|
|
82
81
|
const core = await readFile(join(coreTree, rel), 'utf8');
|
|
83
|
-
|
|
84
|
-
if (requires && !surfaces.includes(requires[1])) continue;
|
|
82
|
+
if (closedGate(core, surfaces)) continue;
|
|
85
83
|
for (const line of core.split('\n')) {
|
|
86
84
|
const marker = SLOT.exec(line);
|
|
87
85
|
if (marker?.[1].startsWith('project.')) slots.add(`${rel} ${marker[1]}`);
|
|
@@ -142,13 +140,6 @@ export async function owedDocuments(layerRoot, surfaces) {
|
|
|
142
140
|
return owed;
|
|
143
141
|
}
|
|
144
142
|
|
|
145
|
-
/**
|
|
146
|
-
* `nina check`.
|
|
147
|
-
*
|
|
148
|
-
* @param {string[]} argv - Command arguments; `--project <dir>` selects the target.
|
|
149
|
-
* @param {{root: string}} ctx - CLI context; `root` is the NINA install directory.
|
|
150
|
-
* @returns {Promise<number>} Process exit code.
|
|
151
|
-
*/
|
|
152
143
|
/**
|
|
153
144
|
* Composed scripts that nothing in the project runs.
|
|
154
145
|
*
|
|
@@ -191,6 +182,13 @@ export async function unwiredScripts(layerRoot, surfaces, target) {
|
|
|
191
182
|
.sort();
|
|
192
183
|
}
|
|
193
184
|
|
|
185
|
+
/**
|
|
186
|
+
* `nina check`.
|
|
187
|
+
*
|
|
188
|
+
* @param {string[]} argv - Command arguments; `--project <dir>` selects the target.
|
|
189
|
+
* @param {{root: string}} ctx - CLI context; `root` is the NINA install directory.
|
|
190
|
+
* @returns {Promise<number>} Process exit code.
|
|
191
|
+
*/
|
|
194
192
|
export async function check(argv, ctx) {
|
|
195
193
|
const target = resolve(argv.includes('--project') ? argv[argv.indexOf('--project') + 1] : '.');
|
|
196
194
|
// `--detector`: run by every project's harness:check. Inside `nina upgrade --apply` the move measures
|
|
@@ -204,10 +202,9 @@ export async function check(argv, ctx) {
|
|
|
204
202
|
}
|
|
205
203
|
|
|
206
204
|
const expected = expectedUnfilled(argv);
|
|
207
|
-
const
|
|
208
|
-
if (
|
|
209
|
-
|
|
210
|
-
console.error(` no .nina/profile.json under ${target}${hint || ' — run `nina init` first.'}\n`);
|
|
205
|
+
const { profile, error } = readProfile(target);
|
|
206
|
+
if (error) {
|
|
207
|
+
console.error(` ${error}\n`);
|
|
211
208
|
return 1;
|
|
212
209
|
}
|
|
213
210
|
|
|
@@ -216,14 +213,6 @@ export async function check(argv, ctx) {
|
|
|
216
213
|
/** Things that are merely stale — worth saying, not worth failing. */
|
|
217
214
|
const notes = [];
|
|
218
215
|
|
|
219
|
-
let profile;
|
|
220
|
-
try {
|
|
221
|
-
profile = JSON.parse(await readFile(profilePath, 'utf8'));
|
|
222
|
-
} catch (error) {
|
|
223
|
-
console.error(` .nina/profile.json is not valid JSON: ${error.message}\n`);
|
|
224
|
-
return 1;
|
|
225
|
-
}
|
|
226
|
-
|
|
227
216
|
const resolved = layerRootFor(ctx.root, profile.core);
|
|
228
217
|
if (resolved.error) {
|
|
229
218
|
console.error(` ${resolved.error}\n`);
|
|
@@ -235,9 +224,7 @@ export async function check(argv, ctx) {
|
|
|
235
224
|
if (stopped) problems.push(`${describeMove(stopped)} \`nina upgrade --abort\` undoes it`);
|
|
236
225
|
|
|
237
226
|
const surfaces = profile.surfaces ?? [];
|
|
238
|
-
const available = (await
|
|
239
|
-
.filter((e) => e.isDirectory())
|
|
240
|
-
.map((e) => e.name);
|
|
227
|
+
const available = (await surfacesIn(resolved.dir));
|
|
241
228
|
for (const s of surfaces) {
|
|
242
229
|
if (!available.includes(s)) {
|
|
243
230
|
problems.push(`surface "${s}" does not exist in core ${profile.core} — available: ${available.join(', ')}`);
|
package/src/commands/compose.mjs
CHANGED
|
@@ -10,18 +10,20 @@
|
|
|
10
10
|
* placeholder, filled from the profile. A surface the project does not declare has its
|
|
11
11
|
* markers dropped, so a project with no database never reads a word about Prisma.
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
13
|
+
* What keeps this honest is `scripts/compose-test.mjs`: every fixture composed and held to the
|
|
14
|
+
* properties it lists, so no rule is lost on someone's judgement that none was. It began as a
|
|
15
|
+
* recomposition of the project the harness was extracted from, byte for byte; that oracle went
|
|
16
|
+
* when projects began pinning frozen releases.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import { mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises';
|
|
20
|
-
import { HARNESS,
|
|
20
|
+
import { HARNESS, layerRootFor, readProfile } from '../paths.mjs';
|
|
21
21
|
import { expectedUnfilled } from '../expected.mjs';
|
|
22
22
|
import { existsSync, lstatSync, readFileSync } from 'node:fs';
|
|
23
23
|
import { dirname, join, relative, resolve } from 'node:path';
|
|
24
|
-
import { NAME, defaultVocabulary } from '../vocabulary.mjs';
|
|
24
|
+
import { NAME, PLACEHOLDER, defaultVocabulary } from '../vocabulary.mjs';
|
|
25
|
+
|
|
26
|
+
export { layerRootFor };
|
|
25
27
|
|
|
26
28
|
/**
|
|
27
29
|
* Matches a slot marker on its own line, with an optional label.
|
|
@@ -60,6 +62,19 @@ export function stripWhy(text, { keepLines = false } = {}) {
|
|
|
60
62
|
*/
|
|
61
63
|
export const REQUIRES = /^<!-- nina:requires ([a-z-]+) -->\n/;
|
|
62
64
|
|
|
65
|
+
/**
|
|
66
|
+
* The surface a core file is gated on when the project does not declare it — the file is not composed there —
|
|
67
|
+
* or null. Every reader that asks whether a gated file applies asks this.
|
|
68
|
+
*
|
|
69
|
+
* @param {string} text - The core file.
|
|
70
|
+
* @param {string[]} surfaces - What the project declares.
|
|
71
|
+
* @returns {string|null}
|
|
72
|
+
*/
|
|
73
|
+
export function closedGate(text, surfaces) {
|
|
74
|
+
const gate = REQUIRES.exec(text)?.[1] ?? null;
|
|
75
|
+
return gate && !surfaces.includes(gate) ? gate : null;
|
|
76
|
+
}
|
|
77
|
+
|
|
63
78
|
/**
|
|
64
79
|
* A slot inside a line — text before it, and the marker last. Filled with its fragment collapsed
|
|
65
80
|
* to one line; dropped, like any slot, when its surface is not declared.
|
|
@@ -199,33 +214,6 @@ export function stamp(text, rel, slots) {
|
|
|
199
214
|
return `${preamble}${generatedNotice(rel, slots, script)}\n\n${body}`;
|
|
200
215
|
}
|
|
201
216
|
|
|
202
|
-
/**
|
|
203
|
-
* Where a project's layers are read from.
|
|
204
|
-
*
|
|
205
|
-
* A project pins a frozen release, or tracks the working tree with "dev". A pinned release
|
|
206
|
-
* that is missing is an error, never a silent fall back to whatever the harness happens to
|
|
207
|
-
* look like right now: that would compose an unreviewed core into a project that asked for
|
|
208
|
-
* a reviewed one, and nothing downstream would say so.
|
|
209
|
-
*
|
|
210
|
-
* @param {string} root - The NINA install directory.
|
|
211
|
-
* @param {string|undefined} core - The profile's `core` field.
|
|
212
|
-
* @returns {{dir: string}|{error: string}}
|
|
213
|
-
*/
|
|
214
|
-
export function layerRootFor(root, core) {
|
|
215
|
-
if (!core || core === 'dev') {
|
|
216
|
-
// `dev` means "track the layers as they are being worked on", which only exists in a
|
|
217
|
-
// checkout of this repo. An installed package ships frozen releases and nothing else,
|
|
218
|
-
// so say that rather than composing an empty tree and reporting nothing wrong.
|
|
219
|
-
if (!existsSync(join(root, 'core'))) {
|
|
220
|
-
return { error: `profile pins core "dev", which tracks the NINA working tree — ${root} is an installed package and has only releases` };
|
|
221
|
-
}
|
|
222
|
-
return { dir: root };
|
|
223
|
-
}
|
|
224
|
-
const dir = join(root, 'releases', core);
|
|
225
|
-
if (!existsSync(dir)) return { error: `profile pins core ${core}, which is not in ${join(root, 'releases')}` };
|
|
226
|
-
return { dir };
|
|
227
|
-
}
|
|
228
|
-
|
|
229
217
|
/**
|
|
230
218
|
* Orders release names by their numbers rather than as text.
|
|
231
219
|
*
|
|
@@ -376,8 +364,7 @@ export async function composedPaths(layerRoot, surfaces = []) {
|
|
|
376
364
|
const coreTree = join(layerRoot, 'core', 'tree');
|
|
377
365
|
const out = new Set();
|
|
378
366
|
for (const rel of await walk(coreTree)) {
|
|
379
|
-
|
|
380
|
-
if (gate && !surfaces.includes(gate[1])) continue;
|
|
367
|
+
if (closedGate(await readFile(join(coreTree, rel), 'utf8'), surfaces)) continue;
|
|
381
368
|
out.add(rel);
|
|
382
369
|
}
|
|
383
370
|
return out;
|
|
@@ -432,11 +419,8 @@ export async function composeProject(target, ctx, options = {}) {
|
|
|
432
419
|
/** Files composed for a surface this profile no longer declares, moved to {@link REMOVED}. */
|
|
433
420
|
const removed = [];
|
|
434
421
|
|
|
435
|
-
const
|
|
436
|
-
if (
|
|
437
|
-
return { error: `no .nina/profile.json under ${target}${legacyHint(target)}`, written, differ, unfilled: [], skipped };
|
|
438
|
-
}
|
|
439
|
-
const profile = JSON.parse(await readFile(profilePath, 'utf8'));
|
|
422
|
+
const { profile, error } = readProfile(target);
|
|
423
|
+
if (error) return { error, written, differ, unfilled: [], skipped };
|
|
440
424
|
const surfaces = profile.surfaces ?? [];
|
|
441
425
|
|
|
442
426
|
const resolved = layerRootFor(ctx.root, profile.core);
|
|
@@ -479,29 +463,27 @@ export async function composeProject(target, ctx, options = {}) {
|
|
|
479
463
|
let core = await readFile(join(coreTree, rel), 'utf8');
|
|
480
464
|
const dest = join(target, rel);
|
|
481
465
|
|
|
482
|
-
const
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
// Not there.
|
|
495
|
-
}
|
|
496
|
-
if (stale && check) differ.push(`${rel} (present, but no '${requires[1]}' surface)`);
|
|
497
|
-
if (stale && !check) {
|
|
498
|
-
await mkdir(dirname(join(target, REMOVED, rel)), { recursive: true });
|
|
499
|
-
await writeFile(join(target, REMOVED, rel), await readFile(dest));
|
|
500
|
-
await rm(dest);
|
|
501
|
-
removed.push(rel);
|
|
502
|
-
}
|
|
503
|
-
continue;
|
|
466
|
+
const closed = closedGate(core, surfaces);
|
|
467
|
+
core = core.replace(REQUIRES, '');
|
|
468
|
+
if (closed) {
|
|
469
|
+
// The project has no such surface, so the file does not exist for it. One composed for it before the
|
|
470
|
+
// surface left the profile is still dispatched as a stage the graph no longer has, and was reported as
|
|
471
|
+
// drift that no compose cleared: it goes, with a copy kept. A file there with no notice is the project's.
|
|
472
|
+
skipped.push(rel);
|
|
473
|
+
let stale = false;
|
|
474
|
+
try {
|
|
475
|
+
stale = lstatSync(dest).isFile() && noticeOf(await readFile(dest, 'utf8')) !== null;
|
|
476
|
+
} catch {
|
|
477
|
+
// Not there.
|
|
504
478
|
}
|
|
479
|
+
if (stale && check) differ.push(`${rel} (present, but no '${closed}' surface)`);
|
|
480
|
+
if (stale && !check) {
|
|
481
|
+
await mkdir(dirname(join(target, REMOVED, rel)), { recursive: true });
|
|
482
|
+
await writeFile(join(target, REMOVED, rel), await readFile(dest));
|
|
483
|
+
await rm(dest);
|
|
484
|
+
removed.push(rel);
|
|
485
|
+
}
|
|
486
|
+
continue;
|
|
505
487
|
}
|
|
506
488
|
|
|
507
489
|
// History is stripped from each piece before the pieces are joined. Joined first, an opener left
|
|
@@ -558,8 +540,8 @@ export async function composeProject(target, ctx, options = {}) {
|
|
|
558
540
|
let text = out.join('\n');
|
|
559
541
|
if (text.includes('nina:why')) malformed.push(rel);
|
|
560
542
|
for (const [name, value] of Object.entries(profile.vocabulary ?? {})) {
|
|
561
|
-
// `null` means "declared but not filled in yet"
|
|
562
|
-
//
|
|
543
|
+
// `null` means "declared but not filled in yet": it composes as owed, below, and `check` reports it,
|
|
544
|
+
// rather than the rule composing with a hole where a noun should be.
|
|
563
545
|
if (value === null || value === undefined) continue;
|
|
564
546
|
text = text.split(`{{${name}}}`).join(value);
|
|
565
547
|
}
|
|
@@ -574,6 +556,10 @@ export async function composeProject(target, ctx, options = {}) {
|
|
|
574
556
|
for (const [name, why] of Object.entries(profile.deferred ?? {})) {
|
|
575
557
|
if (typeof why === 'string' && why.trim() && NAME.test(name)) text = text.split(`{{${name}}}`).join(`[${name}: not decided yet]`);
|
|
576
558
|
}
|
|
559
|
+
// What is still a placeholder is owed: no default answers it, and the project has not declared it, or has
|
|
560
|
+
// declared it null. Left raw, it reached a stage as `{{TENANT_KEY}}` — once inside a shell block it was told to
|
|
561
|
+
// run — and reads as an editing slip to guess past. Said, it is a noun the stage knows it does not have.
|
|
562
|
+
text = text.replace(PLACEHOLDER, (_, name) => `[${name}: not declared yet]`);
|
|
577
563
|
|
|
578
564
|
// Only what has a comment syntax the notice knows. A layer that one day composes JSON
|
|
579
565
|
// would be corrupted by it rather than marked, so it gets nothing and says nothing.
|
package/src/commands/eval.mjs
CHANGED
|
@@ -225,7 +225,7 @@ export function fixtureDiff(fixture) {
|
|
|
225
225
|
}
|
|
226
226
|
|
|
227
227
|
/** What the judge must answer: a call on every planted defect, with the words it rests on, and on everything else. */
|
|
228
|
-
|
|
228
|
+
const JUDGE_SCHEMA = {
|
|
229
229
|
type: 'object',
|
|
230
230
|
properties: {
|
|
231
231
|
defects: {
|
package/src/commands/export.mjs
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
import { createHash } from 'node:crypto';
|
|
22
22
|
import { existsSync } from 'node:fs';
|
|
23
|
-
import { mkdir,
|
|
23
|
+
import { mkdir, readFile, readdir, rename, writeFile } from 'node:fs/promises';
|
|
24
24
|
import { spawn } from 'node:child_process';
|
|
25
25
|
import { join } from 'node:path';
|
|
26
26
|
import { fileURLToPath } from 'node:url';
|
|
@@ -32,6 +32,7 @@ import { readStoreFile } from '../store.mjs';
|
|
|
32
32
|
import { readConfig, statusPath, targetOf } from './langfuse.mjs';
|
|
33
33
|
import { projectName } from './stats.mjs';
|
|
34
34
|
import { handsToModel } from '../detectors.mjs';
|
|
35
|
+
import { takeLock } from '../lock.mjs';
|
|
35
36
|
|
|
36
37
|
/** The CLI, for the export the detector starts in the background. */
|
|
37
38
|
const BIN = fileURLToPath(new URL('../../bin/nina.mjs', import.meta.url));
|
|
@@ -84,37 +85,6 @@ async function sentOf(slug) {
|
|
|
84
85
|
}
|
|
85
86
|
}
|
|
86
87
|
|
|
87
|
-
/**
|
|
88
|
-
* Holds a project's export for one run. Two at once would each read what was sent before either wrote,
|
|
89
|
-
* and send the same runs twice. A lock left by a run that died is taken over: it names its process.
|
|
90
|
-
*
|
|
91
|
-
* @returns {Promise<(() => Promise<void>)|null>} The release, or null when another export holds it.
|
|
92
|
-
*/
|
|
93
|
-
async function lock(slug) {
|
|
94
|
-
await mkdir(join(exportsDir(), 'langfuse'), { recursive: true });
|
|
95
|
-
const path = join(exportsDir(), 'langfuse', `${slug}.lock`);
|
|
96
|
-
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
97
|
-
try {
|
|
98
|
-
const handle = await open(path, 'wx');
|
|
99
|
-
await handle.writeFile(String(process.pid));
|
|
100
|
-
await handle.close();
|
|
101
|
-
return () => rm(path, { force: true });
|
|
102
|
-
} catch (error) {
|
|
103
|
-
if (error.code !== 'EEXIST') throw error;
|
|
104
|
-
const pid = Number(await readFile(path, 'utf8').catch(() => ''));
|
|
105
|
-
let alive = false;
|
|
106
|
-
try {
|
|
107
|
-
alive = pid > 0 && process.kill(pid, 0);
|
|
108
|
-
} catch (e) {
|
|
109
|
-
alive = e.code === 'EPERM';
|
|
110
|
-
}
|
|
111
|
-
if (alive) return null;
|
|
112
|
-
await rm(path, { force: true });
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
return null;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
88
|
/** Writes it by rename, so an interruption leaves the last whole version. */
|
|
119
89
|
async function keep(slug, sent) {
|
|
120
90
|
await mkdir(join(exportsDir(), 'langfuse'), { recursive: true });
|
|
@@ -203,7 +173,7 @@ export async function exportCommand(argv, ctx = {}) {
|
|
|
203
173
|
if (auto) {
|
|
204
174
|
const setting = config.projects[only ?? ''];
|
|
205
175
|
if (!setting || !target.publicKey || !target.secretKey) return 0;
|
|
206
|
-
const release = await
|
|
176
|
+
const release = await takeLock(join(exportsDir(), 'langfuse', `${only}.lock`));
|
|
207
177
|
if (!release) return 0;
|
|
208
178
|
try {
|
|
209
179
|
const result = await exportProject({ slug: only, name: projectName(only), file: join(snapshotsDir(), `${only}.jsonl`), target, now: ctx.now, since: setting.since, quiet: true, content: contextMode(setting) });
|
|
@@ -236,7 +206,7 @@ export async function exportCommand(argv, ctx = {}) {
|
|
|
236
206
|
let failed = false;
|
|
237
207
|
for (const slug of slugs) {
|
|
238
208
|
const name = projectName(slug);
|
|
239
|
-
const release = dry ? async () => {} : await
|
|
209
|
+
const release = dry ? async () => {} : await takeLock(join(exportsDir(), 'langfuse', `${slug}.lock`));
|
|
240
210
|
if (!release) {
|
|
241
211
|
console.log(` ${name}: ✗ another export of this project is running — nothing sent`);
|
|
242
212
|
failed = true;
|
package/src/commands/gate.mjs
CHANGED
|
@@ -18,7 +18,7 @@ import { spawnSync } from 'node:child_process';
|
|
|
18
18
|
import { existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, realpathSync, rmSync, statSync, writeFileSync } from 'node:fs';
|
|
19
19
|
import { tmpdir } from 'node:os';
|
|
20
20
|
import { join, resolve } from 'node:path';
|
|
21
|
-
import {
|
|
21
|
+
import { readProfile, slugFor } from '../paths.mjs';
|
|
22
22
|
import { GATE, hookCommand, missingWiring, shippedScripts } from '../wiring.mjs';
|
|
23
23
|
import { LEDGER_TAIL, ledgerPath, loadProject, projectGateDir, readLedger, runGate } from '../gate.mjs';
|
|
24
24
|
import { projectRecords } from '../store.mjs';
|
|
@@ -279,16 +279,9 @@ export async function gate(argv, ctx) {
|
|
|
279
279
|
const target = resolve(argv.includes('--project') ? argv[argv.indexOf('--project') + 1] : '.');
|
|
280
280
|
if (argv.includes('--hook')) return runGate({ root: target });
|
|
281
281
|
|
|
282
|
-
const
|
|
283
|
-
if (
|
|
284
|
-
console.error(`
|
|
285
|
-
return 2;
|
|
286
|
-
}
|
|
287
|
-
let profile;
|
|
288
|
-
try {
|
|
289
|
-
profile = JSON.parse(readFileSync(profilePath, 'utf8'));
|
|
290
|
-
} catch (error) {
|
|
291
|
-
console.error(` ${profilePath} is not valid JSON — ${error.message}\n`);
|
|
282
|
+
const { profile, error } = readProfile(target);
|
|
283
|
+
if (error) {
|
|
284
|
+
console.error(` ${error}\n`);
|
|
292
285
|
return 2;
|
|
293
286
|
}
|
|
294
287
|
const resolved = layerRootFor(ctx.root, profile.core);
|
package/src/commands/init.mjs
CHANGED
|
@@ -13,16 +13,16 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import { createInterface } from 'node:readline/promises';
|
|
16
|
-
import { HARNESS } from '../paths.mjs';
|
|
16
|
+
import { HARNESS, readProfile, surfacesIn } from '../paths.mjs';
|
|
17
17
|
import { mkdir, readFile, readdir, writeFile } from 'node:fs/promises';
|
|
18
|
-
import { applyWiring, missingWiring, shippedScripts } from '../wiring.mjs';
|
|
19
|
-
import { existsSync
|
|
18
|
+
import { applyWiring, lacksPackage, missingWiring, shippedScripts } from '../wiring.mjs';
|
|
19
|
+
import { existsSync } from 'node:fs';
|
|
20
20
|
import { join, resolve } from 'node:path';
|
|
21
|
-
import { REQUIRES, SLOT, byVersion,
|
|
21
|
+
import { REQUIRES, SLOT, byVersion, closedGate, composedPaths, composeProject, defaultedSlots, layerRootFor, projectOwned, walk } from './compose.mjs';
|
|
22
22
|
import { owedDocuments } from './check.mjs';
|
|
23
23
|
import { PLACEHOLDER, defaultVocabulary } from '../vocabulary.mjs';
|
|
24
|
-
import { PINK, useColor } from '../banner.mjs';
|
|
25
24
|
import { DETECTABLE, NEEDS } from '../surfaces.mjs';
|
|
25
|
+
import { bold, dim, green, pink } from '../look.mjs';
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* The question each surface answers. Detection can confirm three of them from files; all
|
|
@@ -72,11 +72,10 @@ export function askOrder(available) {
|
|
|
72
72
|
return [...available].sort((a, b) => rank(a) - rank(b) || a.localeCompare(b));
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
/** The interview's colors — the
|
|
76
|
-
const
|
|
77
|
-
const
|
|
78
|
-
const
|
|
79
|
-
const found = (text) => tint('32', text);
|
|
75
|
+
/** The interview's colors — the reports' own, on a terminal that takes color, and plain everywhere else. */
|
|
76
|
+
const strong = (text) => bold(pink(text));
|
|
77
|
+
const faint = dim;
|
|
78
|
+
const found = green;
|
|
80
79
|
|
|
81
80
|
/**
|
|
82
81
|
* What declaring a surface actually adds, counted from the layer rather than described.
|
|
@@ -149,14 +148,13 @@ async function applicableFiles(root, surfaces) {
|
|
|
149
148
|
const out = [];
|
|
150
149
|
for (const rel of (await walk(coreTree)).sort()) {
|
|
151
150
|
const core = await readFile(join(coreTree, rel), 'utf8');
|
|
152
|
-
|
|
153
|
-
if (requires && !surfaces.includes(requires[1])) continue;
|
|
151
|
+
if (closedGate(core, surfaces)) continue;
|
|
154
152
|
const fragments = [];
|
|
155
153
|
for (const s of surfaces) {
|
|
156
154
|
const text = await readFile(join(root, 'surfaces', s, 'tree', rel), 'utf8').catch(() => null);
|
|
157
155
|
if (text !== null) fragments.push(text);
|
|
158
156
|
}
|
|
159
|
-
out.push({ rel, core:
|
|
157
|
+
out.push({ rel, core: core.replace(REQUIRES, ''), fragments });
|
|
160
158
|
}
|
|
161
159
|
return out;
|
|
162
160
|
}
|
|
@@ -270,21 +268,15 @@ export async function init(argv, ctx) {
|
|
|
270
268
|
// itself says to re-run with --force to add one, and doing so used to write a profile from nothing —
|
|
271
269
|
// every vocabulary value and integration gone, and the pin moved to the newest release past every
|
|
272
270
|
// check `upgrade` makes.
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
if (error.code !== 'ENOENT') {
|
|
281
|
-
console.error(
|
|
282
|
-
` ${HARNESS}/profile.json cannot be read (${error.message}). Starting over would write a new one over it and keep ` +
|
|
283
|
-
'nothing it declares — fix it and run this again, or move it aside to start from nothing.\n',
|
|
284
|
-
);
|
|
285
|
-
return 1;
|
|
286
|
-
}
|
|
271
|
+
// None: there is nothing to keep. One that is there but cannot be read still holds the pin and every value
|
|
272
|
+
// the project declared — read as "none", a trailing comma moved the pin to the newest release and wrote every
|
|
273
|
+
// vocabulary value away.
|
|
274
|
+
const read = readProfile(target);
|
|
275
|
+
if (read.error && !read.missing) {
|
|
276
|
+
console.error(` ${read.error}. Starting over would write a new one over it and keep nothing it declares — fix it and run this again, or move it aside to start from nothing.\n`);
|
|
277
|
+
return 1;
|
|
287
278
|
}
|
|
279
|
+
const previous = read.profile ?? null;
|
|
288
280
|
if (previous?.core && arg('--core') && arg('--core') !== previous.core) {
|
|
289
281
|
console.error(` ${target} pins ${previous.core}. A pin moves with \`nina upgrade --to ${arg('--core')}\`, which says what the move costs and rolls it back when it fails.\n`);
|
|
290
282
|
return 1;
|
|
@@ -314,7 +306,7 @@ export async function init(argv, ctx) {
|
|
|
314
306
|
// harness the project is actually going to compose, not whatever the working tree says.
|
|
315
307
|
// In the order the interview asks them, so the TODO, the brief and the hints list them as it did.
|
|
316
308
|
const available = askOrder(
|
|
317
|
-
(await
|
|
309
|
+
(await surfacesIn(resolved.dir)),
|
|
318
310
|
);
|
|
319
311
|
// Only what the pinned core has: a file can reveal a surface a release added after it.
|
|
320
312
|
matched = matched.filter((d) => available.includes(d.surface));
|
|
@@ -441,7 +433,7 @@ export async function init(argv, ctx) {
|
|
|
441
433
|
`## 1. Vocabulary — ${vocabulary.size} entries`,
|
|
442
434
|
'',
|
|
443
435
|
`Every name below appears in a rule the chosen core and surfaces state generically. Fill each one`,
|
|
444
|
-
`in \`.nina/profile.json\`; a \`null\`
|
|
436
|
+
`in \`.nina/profile.json\`; a \`null\` composes as \`[NAME: not declared yet]\` until it is filled.`,
|
|
445
437
|
'',
|
|
446
438
|
...[...vocabulary].sort().map((name) => `- [ ] \`${name}\``),
|
|
447
439
|
...(defaulted.length > 0
|
|
@@ -608,7 +600,7 @@ export async function init(argv, ctx) {
|
|
|
608
600
|
: ` composed: ${composed.written.length} file(s), with holes where .nina/TODO.md §1–§3 go`,
|
|
609
601
|
);
|
|
610
602
|
}
|
|
611
|
-
const uninstalled = unwired
|
|
603
|
+
const uninstalled = lacksPackage(unwired);
|
|
612
604
|
if (uninstalled) {
|
|
613
605
|
console.log(' first: install @xhulz/nina here — until then no hook can load, and nothing tells the model anything');
|
|
614
606
|
}
|
|
@@ -27,7 +27,7 @@ import { exportsDir, slugFor } from '../paths.mjs';
|
|
|
27
27
|
import { projectName } from './stats.mjs';
|
|
28
28
|
|
|
29
29
|
/** Where the keys and the switches live. */
|
|
30
|
-
|
|
30
|
+
const configPath = () => join(exportsDir(), 'langfuse.json');
|
|
31
31
|
|
|
32
32
|
/** What a project sends, in words, by `contextMode`. */
|
|
33
33
|
const LABELS = { full: "with each stage's own context", prompts: "with each stage's prompt and report", none: 'as metadata only' };
|
package/src/commands/learn.mjs
CHANGED
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
import { existsSync, readdirSync } from 'node:fs';
|
|
26
26
|
import { mkdir, readFile, readdir, stat, writeFile } from 'node:fs/promises';
|
|
27
27
|
import { join, relative, resolve } from 'node:path';
|
|
28
|
-
import { HARNESS,
|
|
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 {
|
|
31
|
+
import { byVersion, closedGate, layerRootFor } 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';
|
|
@@ -39,7 +39,7 @@ import { autoExport } from './export.mjs';
|
|
|
39
39
|
import { beforeModel } from '../detectors.mjs';
|
|
40
40
|
|
|
41
41
|
/** Loop-backs from one role, since its newest lesson, that make a lesson overdue. */
|
|
42
|
-
|
|
42
|
+
const CAPTURE_AT = 3;
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
45
|
* How far back a loop-back still counts. Older ones are history nobody remembers well enough to
|
|
@@ -226,7 +226,7 @@ const shift = (date, days) => new Date(Date.parse(`${date}T12:00:00Z`) + days *
|
|
|
226
226
|
* @param {number} n - Out of how many.
|
|
227
227
|
* @returns {[number, number]}
|
|
228
228
|
*/
|
|
229
|
-
|
|
229
|
+
function wilson(k, n) {
|
|
230
230
|
if (n === 0) return [0, 1];
|
|
231
231
|
const z = 1.96;
|
|
232
232
|
const p = k / n;
|
|
@@ -349,7 +349,7 @@ export function relapsed(known, filed) {
|
|
|
349
349
|
* @param {{pill: string}[]} filed - Requests already written, open or closed.
|
|
350
350
|
* @returns {Awaited<ReturnType<typeof lessons>>}
|
|
351
351
|
*/
|
|
352
|
-
|
|
352
|
+
function unfiled(known, filed) {
|
|
353
353
|
const asked = new Set(filed.map((r) => r.pill));
|
|
354
354
|
return known.filter((l) => !l.retired && l.occurrences >= GRADUATION_AT && !asked.has(l.rel));
|
|
355
355
|
}
|
|
@@ -473,8 +473,7 @@ async function missingSurface(layerRoot, layerPath, surfaces) {
|
|
|
473
473
|
const own = /^surfaces\/([^/]+)\/tree\//.exec(layerPath)?.[1];
|
|
474
474
|
if (own && !surfaces.includes(own)) return own;
|
|
475
475
|
const core = await readFile(join(layerRoot, 'core', 'tree', composedPath(layerPath)), 'utf8').catch(() => '');
|
|
476
|
-
|
|
477
|
-
return gate && !surfaces.includes(gate) ? gate : null;
|
|
476
|
+
return closedGate(core, surfaces);
|
|
478
477
|
}
|
|
479
478
|
|
|
480
479
|
/**
|
|
@@ -494,7 +493,7 @@ async function missingSurface(layerRoot, layerPath, surfaces) {
|
|
|
494
493
|
*/
|
|
495
494
|
export async function closeAnswered(target, layerRoot, version) {
|
|
496
495
|
const given = await answers(layerRoot);
|
|
497
|
-
const profile =
|
|
496
|
+
const profile = readProfile(target).profile ?? {};
|
|
498
497
|
const out = [];
|
|
499
498
|
for (const r of (await filedRequests(target)).filter((r) => r.status === 'open' && given[r.id])) {
|
|
500
499
|
const a = given[r.id];
|
|
@@ -685,12 +684,11 @@ export async function learn(argv, ctx) {
|
|
|
685
684
|
const check = argv.includes('--check');
|
|
686
685
|
const days = argv.includes('--days') ? Number(argv[argv.indexOf('--days') + 1]) || CAPTURE_DAYS : CAPTURE_DAYS;
|
|
687
686
|
|
|
688
|
-
const
|
|
689
|
-
if (
|
|
690
|
-
console.error(`
|
|
687
|
+
const { profile, error } = readProfile(target);
|
|
688
|
+
if (error) {
|
|
689
|
+
console.error(` ${error}\n`);
|
|
691
690
|
return check ? 2 : 1;
|
|
692
691
|
}
|
|
693
|
-
const profile = JSON.parse(await readFile(profilePath, 'utf8'));
|
|
694
692
|
const resolved = layerRootFor(ctx.root, profile.core);
|
|
695
693
|
if (resolved.error) {
|
|
696
694
|
console.error(` ${resolved.error}\n`);
|
package/src/commands/pills.mjs
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { mkdir, readFile, readdir, rename } from 'node:fs/promises';
|
|
14
|
-
import { HARNESS } from '../paths.mjs';
|
|
14
|
+
import { HARNESS, readProfile } from '../paths.mjs';
|
|
15
15
|
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
16
16
|
import { spawnSync } from 'node:child_process';
|
|
17
17
|
import { dirname, join, resolve } from 'node:path';
|
|
@@ -124,7 +124,7 @@ export function list(value) {
|
|
|
124
124
|
* @param {string} citation - `path` or `path:line`.
|
|
125
125
|
* @returns {{state: 'ok'|'gone'|'truncated', path: string, line: number|null, lines?: number}}
|
|
126
126
|
*/
|
|
127
|
-
|
|
127
|
+
function resolveCitation(target, citation) {
|
|
128
128
|
const at = /^(.*):(\d+)$/.exec(citation);
|
|
129
129
|
const path = at ? at[1] : citation;
|
|
130
130
|
const line = at ? Number(at[2]) : null;
|
|
@@ -153,7 +153,7 @@ export function resolveCitation(target, citation) {
|
|
|
153
153
|
* @param {string} path - A path inside it.
|
|
154
154
|
* @returns {string | null} `YYYY-MM-DD`, or `null` when git cannot say.
|
|
155
155
|
*/
|
|
156
|
-
|
|
156
|
+
function lastChanged(target, path) {
|
|
157
157
|
const git = spawnSync('git', ['-C', target, 'log', '-1', '--format=%cs', '--', path], { encoding: 'utf8' });
|
|
158
158
|
if (git.status !== 0) return null;
|
|
159
159
|
const when = git.stdout.trim();
|
|
@@ -383,8 +383,8 @@ export async function pills(argv, ctx) {
|
|
|
383
383
|
// of a surface, and composition strips that gate — so it has to come from the layers.
|
|
384
384
|
let gates = null;
|
|
385
385
|
try {
|
|
386
|
-
const profile =
|
|
387
|
-
const layers = layerRootFor(ctx?.root ?? '.', profile
|
|
386
|
+
const { profile } = readProfile(target);
|
|
387
|
+
const layers = layerRootFor(ctx?.root ?? '.', profile?.core);
|
|
388
388
|
if (!layers.error) gates = await roleGates(layers.dir);
|
|
389
389
|
} catch {
|
|
390
390
|
/* without a profile the candidate is still worth naming; only its target is unknown */
|