@turri-dev/cli 0.1.27-next.763d091 → 0.1.28-next.d5f2680
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 +6 -6
- package/dist/advisor-chat.d.ts +63 -0
- package/dist/advisor-chat.js +290 -0
- package/dist/background-skills.d.ts +53 -0
- package/dist/background-skills.js +121 -0
- package/dist/bedrock-region.d.ts +66 -0
- package/dist/bedrock-region.js +144 -0
- package/dist/btw.d.ts +1 -1
- package/dist/btw.js +1 -1
- package/dist/change-plain-cli.js +20 -13
- package/dist/chat-idle.d.ts +7 -0
- package/dist/chat-idle.js +20 -0
- package/dist/chats.d.ts +10 -0
- package/dist/chats.js +23 -0
- package/dist/cli-options.d.ts +1 -2
- package/dist/cli-options.js +2 -7
- package/dist/cli.js +11 -3
- package/dist/config-command.d.ts +14 -0
- package/dist/config-command.js +35 -15
- package/dist/config-edit.d.ts +3 -3
- package/dist/config-edit.js +16 -12
- package/dist/config.d.ts +54 -34
- package/dist/config.js +40 -44
- package/dist/conform-cli.js +12 -10
- package/dist/conformance-switch.d.ts +34 -0
- package/dist/conformance-switch.js +108 -0
- package/dist/cultivate-cli.js +15 -5
- package/dist/drift-cli.js +2 -0
- package/dist/extension.d.ts +15 -0
- package/dist/extension.js +260 -83
- package/dist/host-session.d.ts +26 -0
- package/dist/host-session.js +30 -2
- package/dist/host.d.ts +5 -2
- package/dist/host.js +7 -1
- package/dist/init-config.d.ts +1 -1
- package/dist/init-config.js +20 -11
- package/dist/loop-cli.d.ts +3 -3
- package/dist/loop-cli.js +13 -16
- package/dist/loop-tools.js +18 -10
- package/dist/model-check.d.ts +8 -3
- package/dist/model-check.js +13 -8
- package/dist/new-project.js +12 -8
- package/dist/{validate-cli.js → parse-cli.js} +11 -5
- package/dist/parse-tool.d.ts +9 -0
- package/dist/parse-tool.js +33 -0
- package/dist/pi-launch.js +1 -1
- package/dist/plain/check.d.ts +53 -6
- package/dist/plain/check.js +217 -24
- package/dist/plain/concepts.d.ts +8 -0
- package/dist/plain/concepts.js +66 -23
- package/dist/plain/cycles.d.ts +21 -0
- package/dist/plain/cycles.js +190 -0
- package/dist/plain/errors.d.ts +4 -0
- package/dist/plain/errors.js +7 -0
- package/dist/plain/files.d.ts +18 -1
- package/dist/plain/files.js +39 -2
- package/dist/plain/graph.d.ts +33 -4
- package/dist/plain/graph.js +60 -12
- package/dist/plain/highlight.d.ts +3 -2
- package/dist/plain/highlight.js +4 -3
- package/dist/plain/index.d.ts +8 -5
- package/dist/plain/index.js +8 -5
- package/dist/plain/liquid.js +1 -6
- package/dist/plain/markdown.d.ts +32 -3
- package/dist/plain/markdown.js +146 -24
- package/dist/plain/module-concepts.js +2 -2
- package/dist/plain/parser.d.ts +83 -28
- package/dist/plain/parser.js +381 -260
- package/dist/plain/plain.tmLanguage.json +29 -3
- package/dist/plain/project.d.ts +48 -0
- package/dist/plain/project.js +155 -0
- package/dist/plain/spec.d.ts +90 -28
- package/dist/plain/spec.js +107 -133
- package/dist/plain/test-plain-file.d.ts +59 -0
- package/dist/plain/test-plain-file.js +232 -0
- package/dist/regenerate/activity.d.ts +20 -9
- package/dist/regenerate/activity.js +11 -4
- package/dist/regenerate/advisor-records.d.ts +93 -0
- package/dist/regenerate/advisor-records.js +110 -0
- package/dist/regenerate/advisor-runs.d.ts +87 -0
- package/dist/regenerate/advisor-runs.js +327 -0
- package/dist/regenerate/base-folder.d.ts +68 -0
- package/dist/regenerate/base-folder.js +168 -0
- package/dist/regenerate/cases.d.ts +9 -6
- package/dist/regenerate/cases.js +71 -15
- package/dist/regenerate/change-view.d.ts +8 -3
- package/dist/regenerate/change-view.js +71 -22
- package/dist/regenerate/chunk-plan.d.ts +36 -15
- package/dist/regenerate/chunk-plan.js +165 -59
- package/dist/regenerate/conform.d.ts +3 -0
- package/dist/regenerate/conform.js +6 -5
- package/dist/regenerate/conformance-agents.d.ts +18 -39
- package/dist/regenerate/conformance-agents.js +60 -88
- package/dist/regenerate/conformance.d.ts +23 -20
- package/dist/regenerate/conformance.js +118 -121
- package/dist/regenerate/diff-view.d.ts +1 -1
- package/dist/regenerate/diff-view.js +20 -4
- package/dist/regenerate/drift.d.ts +47 -15
- package/dist/regenerate/drift.js +101 -30
- package/dist/regenerate/jobs.d.ts +2 -2
- package/dist/regenerate/jobs.js +1 -1
- package/dist/regenerate/ledger.d.ts +19 -0
- package/dist/regenerate/loop.d.ts +61 -49
- package/dist/regenerate/loop.js +473 -340
- package/dist/regenerate/paths.d.ts +4 -0
- package/dist/regenerate/paths.js +7 -1
- package/dist/regenerate/plain-palette.js +2 -0
- package/dist/regenerate/prompt.d.ts +57 -19
- package/dist/regenerate/prompt.js +157 -122
- package/dist/regenerate/records.d.ts +43 -12
- package/dist/regenerate/records.js +102 -88
- package/dist/regenerate/regenerate.js +29 -11
- package/dist/regenerate/regression.d.ts +4 -4
- package/dist/regenerate/regression.js +14 -10
- package/dist/regenerate/renames.d.ts +42 -0
- package/dist/regenerate/renames.js +185 -0
- package/dist/regenerate/requires.d.ts +1 -1
- package/dist/regenerate/requires.js +10 -3
- package/dist/regenerate/resources.d.ts +5 -3
- package/dist/regenerate/resources.js +4 -4
- package/dist/regenerate/scripts-being-written.d.ts +19 -0
- package/dist/regenerate/scripts-being-written.js +30 -0
- package/dist/regenerate/spec-map-view.d.ts +2 -2
- package/dist/regenerate/spec-map-view.js +46 -15
- package/dist/regenerate/spec-map.d.ts +27 -5
- package/dist/regenerate/spec-map.js +92 -60
- package/dist/regenerate/spec-steps.d.ts +48 -5
- package/dist/regenerate/spec-steps.js +213 -28
- package/dist/regenerate/state.d.ts +4 -3
- package/dist/regenerate/stop-report.d.ts +1 -1
- package/dist/regenerate/stop-report.js +10 -10
- package/dist/regenerate/test-advisor.d.ts +101 -0
- package/dist/regenerate/test-advisor.js +379 -0
- package/dist/regenerate/test-kinds.d.ts +69 -31
- package/dist/regenerate/test-kinds.js +109 -80
- package/dist/regenerate/test-scripts.d.ts +2 -0
- package/dist/regenerate/test-scripts.js +4 -0
- package/dist/regenerate/testing-steps.d.ts +41 -0
- package/dist/regenerate/testing-steps.js +110 -0
- package/dist/regenerate/testing.d.ts +1 -1
- package/dist/regenerate/testing.js +5 -4
- package/dist/regenerate/unit-review.d.ts +1 -1
- package/dist/regenerate/unit-review.js +3 -3
- package/dist/regenerate-cli.js +11 -12
- package/dist/release-agent.js +4 -0
- package/dist/release-cli.js +2 -0
- package/dist/release-tools.js +2 -0
- package/dist/run-report.d.ts +2 -2
- package/dist/run-report.js +4 -3
- package/dist/self-invocation.d.ts +1 -1
- package/dist/self-invocation.js +1 -1
- package/dist/sentinel.js +1 -1
- package/dist/setup.d.ts +10 -0
- package/dist/setup.js +52 -4
- package/dist/skill.d.ts +10 -0
- package/dist/skill.js +6 -0
- package/dist/skills.js +3 -1
- package/dist/spec-tools.js +21 -31
- package/dist/test-plain-files.d.ts +41 -0
- package/dist/test-plain-files.js +177 -0
- package/docs/README.md +3 -1
- package/docs/authoring-plain.md +46 -13
- package/docs/chats.md +3 -1
- package/docs/config.md +20 -15
- package/docs/deploy.md +1 -1
- package/docs/development.md +2 -1
- package/docs/headless.md +15 -18
- package/docs/hosting.md +28 -12
- package/docs/installation.md +1 -0
- package/docs/parser.md +88 -27
- package/docs/regenerating.md +89 -54
- package/docs/sentinel.md +1 -1
- package/docs/skills-and-gates.md +3 -1
- package/docs/test-advisor.md +110 -0
- package/docs/theming.md +1 -1
- package/docs/using.md +17 -15
- package/genome/rules/bullet-continuation.md +8 -8
- package/genome/rules/concise-specs-examples.md +111 -80
- package/genome/rules/concise-specs-integration-examples.md +56 -41
- package/genome/rules/concise-specs.md +17 -16
- package/genome/rules/definitions.md +5 -5
- package/genome/rules/examples/integration-embedded-testing/run_conformance_tests_java.sh +1 -1
- package/genome/rules/func-specs.md +69 -74
- package/genome/rules/impl-reqs.md +4 -4
- package/genome/rules/integration-embedded-testing.md +20 -20
- package/genome/rules/integration-embedded.md +31 -31
- package/genome/rules/integration-standalone.md +9 -9
- package/genome/rules/integrations.md +18 -18
- package/genome/rules/linked-resources.md +19 -16
- package/genome/rules/module-structure.md +21 -14
- package/genome/rules/project-model.md +18 -17
- package/genome/rules/required-concepts.md +1 -1
- package/genome/rules/requires-modules.md +6 -5
- package/genome/rules/semantic-ids.md +49 -0
- package/genome/rules/stdlib.md +4 -5
- package/genome/rules/test-plain-files.md +130 -0
- package/genome/rules/test-reqs.md +8 -8
- package/genome/rules/turri-regeneration.md +24 -8
- package/genome/skills/analyze-2-func-specs/SKILL.md +36 -21
- package/genome/skills/analyze-func-specs/SKILL.md +46 -32
- package/genome/skills/break-down-func-spec/SKILL.md +91 -67
- package/genome/skills/consolidate-concepts/SKILL.md +10 -10
- package/genome/skills/convert-old-syntax/SKILL.md +68 -0
- package/genome/skills/convert-old-syntax/references/rubric.md +11 -0
- package/genome/skills/debug-specs/SKILL.md +62 -56
- package/genome/skills/implement-conformance-testing-script/SKILL.md +19 -15
- package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_java.sh +2 -2
- package/genome/skills/implement-conformance-testing-script/assets/run_conformance_tests_python.sh +2 -2
- package/genome/skills/implement-unit-testing-script/SKILL.md +14 -10
- package/genome/skills/refactor-module/SKILL.md +35 -35
- package/genome/skills/resolve-section-ownership/SKILL.md +9 -9
- package/genome/skills/resolve-spec-conflict/SKILL.md +35 -29
- package/package.json +7 -6
- package/dist/regenerate/choose-conformance.d.ts +0 -32
- package/dist/regenerate/choose-conformance.js +0 -117
- /package/dist/{validate-cli.d.ts → parse-cli.d.ts} +0 -0
package/dist/regenerate/cases.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { scenarioLabel } from "./test-kinds.js";
|
|
1
2
|
/**
|
|
2
3
|
* What a job's agents are told to do, by its cases - see docs/regenerating.md. A job's functional specs each fall in
|
|
3
4
|
* one case - fresh, added, changed (patched), regenerated again, taken out - or, with none touched, the job is
|
|
@@ -5,12 +6,18 @@
|
|
|
5
6
|
* functional specs of that case; their reviewers, what to hold each to. A job holding several cases gets a section
|
|
6
7
|
* for each.
|
|
7
8
|
*/
|
|
8
|
-
/** Functional specs, each by its
|
|
9
|
-
const named = (specs) => specs.map((spec) =>
|
|
10
|
-
/**
|
|
11
|
-
|
|
9
|
+
/** Functional specs, each by its func-id - with the module it belongs to, a func-id being unique in its module only - and its first line. */
|
|
10
|
+
const named = (specs) => specs.map((spec) => `${spec.module !== undefined ? `\`${spec.module}:${spec.funcId}\`` : `\`${spec.funcId}\``} (${spec.text})`).join("; ");
|
|
11
|
+
/**
|
|
12
|
+
* What the coding agent does, case by case. `fromBase`: the codebase started from a base folder - nothing is built from
|
|
13
|
+
* the specification, but the folder is not empty, and a project in it is built on, never set up anew.
|
|
14
|
+
*/
|
|
15
|
+
export function codeCasesBlock(cases, fromBase = false) {
|
|
12
16
|
const lines = [];
|
|
13
|
-
if (cases.fresh) {
|
|
17
|
+
if (cases.fresh && fromBase) {
|
|
18
|
+
lines.push("- Nothing is built from the specification yet, and the codebase holds what the base folder had. Where that is a", " project - a layout, a dependency manifest, unit tests - build on it: add to them, never set them up anew. Where it", " is files alone, set the project up around them - its layout, its dependency manifest, and its unit tests where", " the unit testing script runs them. Then build what follows, with its unit tests.");
|
|
19
|
+
}
|
|
20
|
+
else if (cases.fresh) {
|
|
14
21
|
lines.push("- Nothing is built yet: set the project up first - its layout, its dependency manifest, and its unit tests", " where the unit testing script runs them - then build what follows, with its unit tests.");
|
|
15
22
|
}
|
|
16
23
|
if (cases.add.length > 0)
|
|
@@ -53,31 +60,80 @@ export function codeReviewCasesBlock(cases) {
|
|
|
53
60
|
...(cases.delete.length > 0 ? [`- Taken out: ${named(cases.delete)} - its code and the tests only it had removed, and nothing else.`] : []),
|
|
54
61
|
];
|
|
55
62
|
}
|
|
56
|
-
/**
|
|
57
|
-
|
|
63
|
+
/** Scenarios, each by the label its tests carry. */
|
|
64
|
+
const labelled = (spec, scenarios, module) => scenarios.map((scenario) => `"${scenarioLabel(scenario.kind, scenario.id, spec.module ?? module, spec.funcId)}"`).join("; ");
|
|
65
|
+
/** Why a functional spec's code moved under its unchanged scenarios, in a few words. */
|
|
66
|
+
const CODE_CHANGED = {
|
|
67
|
+
text: "its text, or a file it links, changed",
|
|
68
|
+
again: "it was regenerated again",
|
|
69
|
+
concept: "a concept it uses changed",
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* What the conformance agent does with each functional spec, scenario by scenario - each scenario named by the label its
|
|
73
|
+
* tests carry - and, where the code moved under unchanged scenarios, what to do with their tests.
|
|
74
|
+
*/
|
|
75
|
+
function scenarioCasesLines(specs, module) {
|
|
76
|
+
const lines = ["What this job does to the tests, scenario by scenario - each named by the label its tests carry:"];
|
|
77
|
+
for (const spec of specs) {
|
|
78
|
+
lines.push(`- \`${spec.module ?? module}:${spec.funcId}\` (${spec.text}):`);
|
|
79
|
+
if (spec.added.length > 0)
|
|
80
|
+
lines.push(` - added - write a test for each: ${labelled(spec, spec.added, module)}.`);
|
|
81
|
+
if (spec.changed.length > 0)
|
|
82
|
+
lines.push(` - changed - rewrite its tests to the scenario as it reads now: ${labelled(spec, spec.changed, module)}.`);
|
|
83
|
+
if (spec.removed.length > 0)
|
|
84
|
+
lines.push(` - removed - delete every test labelled with it, and its label, and nothing else: ${labelled(spec, spec.removed, module)}.`);
|
|
85
|
+
if (spec.unchanged.length > 0) {
|
|
86
|
+
lines.push(spec.codeChanged !== undefined
|
|
87
|
+
? ` - unchanged, but its code changed - ${CODE_CHANGED[spec.codeChanged]} - run their tests on the new code: ${labelled(spec, spec.unchanged, module)}.`
|
|
88
|
+
: ` - unchanged - leave their tests exactly as they are: ${labelled(spec, spec.unchanged, module)}.`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (specs.some((spec) => spec.codeChanged !== undefined)) {
|
|
92
|
+
lines.push("- Where the code changed under unchanged scenarios: their tests were written against the code it replaced. Run them", " against the new code. Those that pass are tests of the new code too - conformance tests are black box - and are", " not rewritten. Fix what fails against its scenario, read with the functional spec's text: what a failing test checks", " that the scenario says stays checked, the test changed only as the new code needs it reached; what it checks that", " the scenario and the specification leave open - a path, a field, a message, a format the old code chose - is the", " new code's choice now: rewrite that check to what the new code does, or take it out. No test may hold the new code", " to what only the old code did.");
|
|
93
|
+
}
|
|
94
|
+
lines.push("- The tests of every other functional spec stay as they are.");
|
|
95
|
+
return lines;
|
|
96
|
+
}
|
|
97
|
+
/** What the conformance agent does, case by case - scenario by scenario, when the job has them. */
|
|
98
|
+
export function conformanceCasesBlock(cases, module = "") {
|
|
58
99
|
const lines = [];
|
|
59
100
|
if (cases.fresh) {
|
|
60
101
|
lines.push("- There are no conformance tests yet: set the tests folder up first - the tests' own build and layout, so the", " conformance testing script, which brings the tests together with the code, runs them - then write what follows.");
|
|
61
102
|
}
|
|
103
|
+
if (cases.scenarios !== undefined && cases.scenarios.length > 0)
|
|
104
|
+
return [...lines, ...scenarioCasesLines(cases.scenarios, module)];
|
|
62
105
|
if (cases.add.length > 0)
|
|
63
|
-
lines.push(`- New - write its
|
|
106
|
+
lines.push(`- New - write a test for each of its scenarios: ${named(cases.add)}.`);
|
|
64
107
|
if (cases.patch.length > 0) {
|
|
65
|
-
lines.push(`- Changed - its text, its
|
|
108
|
+
lines.push(`- Changed - its text, its scenarios, or a concept it uses: ${named(cases.patch)}.`, " Its conformance tests exist: bring them in line with its scenarios as they are now - a test for each, a", " scenario taken out losing its tests. The tests of everything else stay as they are.");
|
|
66
109
|
}
|
|
67
110
|
if (cases.again.length > 0) {
|
|
68
|
-
lines.push(`- Regenerated again - its code was built anew, and its conformance tests were written against the code it replaced: ${named(cases.again)}.`, " Its text did not change, but the code did
|
|
111
|
+
lines.push(`- Regenerated again - its code was built anew, and its conformance tests were written against the code it replaced: ${named(cases.again)}.`, " Its text did not change, but the code did. Run its tests against the new code. Those that pass are tests of the", " new code too - conformance tests are black box - and are not rewritten. Fix what fails against the", " specification: what a failing test checks that the specification says stays checked, the test changed only as", " the new code needs it reached; what it checks that the specification leaves open - a path, a field, a message,", " a format the old code chose and the specification never names - is the new code's choice now: rewrite that", " check to what the new code does, or take it out. No test may hold the new code to what only the old code did.", " The tests of everything else stay as they are.");
|
|
69
112
|
}
|
|
70
113
|
if (cases.delete.length > 0)
|
|
71
|
-
lines.push(`- Taken out - remove its conformance tests: ${named(cases.delete)}.`);
|
|
114
|
+
lines.push(`- Taken out, or its scenarios all taken out - remove its conformance tests: ${named(cases.delete)}.`);
|
|
72
115
|
if (cases.mechanical) {
|
|
73
116
|
lines.push("- No functional spec is touched: the change is to the test reqs, or to definitions or implementation reqs alone.", " Adapt the existing tests to it. Write no new tests. A test may change only mechanically - how it is built,", " started or reaches the software - never what it asserts. Every test must still pass.");
|
|
74
117
|
}
|
|
75
118
|
return lines;
|
|
76
119
|
}
|
|
77
|
-
/** What the conformance test reviewer holds the tests to, when the job is mechanical
|
|
78
|
-
export function conformanceReviewCasesBlock(cases) {
|
|
79
|
-
if (!cases.mechanical)
|
|
80
|
-
|
|
120
|
+
/** What the conformance test reviewer holds the tests to: scenario by scenario - or, when the job is mechanical, in place of its checks. */
|
|
121
|
+
export function conformanceReviewCasesBlock(cases, module = "") {
|
|
122
|
+
if (!cases.mechanical) {
|
|
123
|
+
if (cases.scenarios === undefined || cases.scenarios.length === 0)
|
|
124
|
+
return [];
|
|
125
|
+
const all = (pick) => cases.scenarios.flatMap((spec) => (pick(spec).length > 0 ? [labelled(spec, pick(spec), module)] : [])).join("; ");
|
|
126
|
+
const kept = all((spec) => (spec.codeChanged === undefined ? spec.unchanged : []));
|
|
127
|
+
const rerun = all((spec) => (spec.codeChanged !== undefined ? spec.unchanged : []));
|
|
128
|
+
const removed = all((spec) => spec.removed);
|
|
129
|
+
return [
|
|
130
|
+
"What this job does to the tests, scenario by scenario - hold it to that:",
|
|
131
|
+
...(kept !== "" ? [`- Unchanged - their tests come out exactly as they were, not rewritten or reworded: ${kept}.`] : []),
|
|
132
|
+
...(rerun !== "" ? [`- Unchanged, the code changed under them - a test changed only where it failed on the new code, and only to what its scenario says: ${rerun}.`] : []),
|
|
133
|
+
...(removed !== "" ? [`- Removed - no test labelled with them is left: ${removed}.`] : []),
|
|
134
|
+
"",
|
|
135
|
+
];
|
|
136
|
+
}
|
|
81
137
|
return [
|
|
82
138
|
"This work touches no functional spec - only the test reqs, or definitions or implementation reqs alone. Review",
|
|
83
139
|
"only that the tests follow them, and that no test was removed or weakened: an assertion loosened or taken out, a",
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
import type { DiffWhere } from "./diff-view.ts";
|
|
2
|
-
import { type SpecChange } from "./spec-steps.ts";
|
|
2
|
+
import { type SpecChange, type TestPlainPath } from "./spec-steps.ts";
|
|
3
3
|
/**
|
|
4
4
|
* `changes` as a diff of `file` - the module's .plain file, which the diff names - section by section: a removed
|
|
5
5
|
* item's lines taken out, an added one's put in, a changed one's both. A change to what a linked file holds
|
|
6
6
|
* follows, as the step's own diff has it.
|
|
7
7
|
*/
|
|
8
|
-
export declare function changeDiff(changes: SpecChange[], file: string): string;
|
|
8
|
+
export declare function changeDiff(changes: SpecChange[], file: string, testPlain?: TestPlainView): string;
|
|
9
|
+
/** For a conformance job: the module, and where its functional specs' test plain files are, as the panels name them. */
|
|
10
|
+
export interface TestPlainView {
|
|
11
|
+
module: string;
|
|
12
|
+
pathOf: TestPlainPath;
|
|
13
|
+
}
|
|
9
14
|
/**
|
|
10
15
|
* `changeDiff`, each section's items in the order they are written - by file, then by line - rather than in the
|
|
11
16
|
* order the spec is read in, which puts a concept after those it uses: placed by `locate`, as the panels place it.
|
|
12
17
|
*/
|
|
13
|
-
export declare function changeDiffInFiles(changes: SpecChange[], file: string, locate: (diff: string) => DiffWhere): {
|
|
18
|
+
export declare function changeDiffInFiles(changes: SpecChange[], file: string, locate: (diff: string) => DiffWhere, testPlain?: TestPlainView): {
|
|
14
19
|
diff: string;
|
|
15
20
|
where: DiffWhere;
|
|
16
21
|
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { resourceDiff } from "./spec-steps.js";
|
|
1
|
+
import { DEFINITIONS, FUNCTIONAL_REQUIREMENTS, NON_FUNCTIONAL_REQUIREMENTS, REQUIRED_FUNCTIONAL_SPECS, TEST_REQUIREMENTS } from "../plain/spec.js";
|
|
2
|
+
import { diffFileTexts, resourceDiff, testPlainFileText } from "./spec-steps.js";
|
|
3
3
|
/**
|
|
4
4
|
* A job's change as its agent is given it, for the panels: the same items `describeSpecChange` writes into
|
|
5
5
|
* `<spec change>` - what the job's functional specs use, from the module's own file and from the files it
|
|
6
6
|
* imports and requires alike - laid out as a diff the panels already show (`diff-view.ts`). Each section is
|
|
7
|
-
* a block under its header, each item as its file writes it -
|
|
8
|
-
*
|
|
7
|
+
* a block under its header, each item as its file writes it - a functional spec under its `# <func-id>` heading -
|
|
8
|
+
* so placed in the .plain files (`locateDiffLines`) every line is shown in the file it is written
|
|
9
9
|
* in, with its line there: split by file and by block. A text diff of the module's file would show other
|
|
10
10
|
* things - the lines around a change, the items no job takes yet - and leave out what an import adds.
|
|
11
11
|
*/
|
|
@@ -13,7 +13,7 @@ import { resourceDiff } from "./spec-steps.js";
|
|
|
13
13
|
const ORDER = [DEFINITIONS, NON_FUNCTIONAL_REQUIREMENTS, TEST_REQUIREMENTS, REQUIRED_FUNCTIONAL_SPECS, FUNCTIONAL_REQUIREMENTS];
|
|
14
14
|
/** A section's header as a .plain file writes it: a required module's functional specs are under its own `***functional specs***`. */
|
|
15
15
|
const heading = (section) => `***${section === REQUIRED_FUNCTIONAL_SPECS ? FUNCTIONAL_REQUIREMENTS : section}***`;
|
|
16
|
-
/** An item's lines as a .plain file writes them:
|
|
16
|
+
/** An item's lines as a .plain file writes them: a functional spec's `# <func-id>` heading over its text, anything else its text. */
|
|
17
17
|
function itemLines(serialized) {
|
|
18
18
|
if (serialized === undefined)
|
|
19
19
|
return [];
|
|
@@ -26,31 +26,24 @@ function itemLines(serialized) {
|
|
|
26
26
|
}
|
|
27
27
|
if (typeof item === "string")
|
|
28
28
|
return item.split("\n");
|
|
29
|
-
const {
|
|
29
|
+
const { id, markdown } = (item ?? {});
|
|
30
30
|
const lines = (markdown ?? JSON.stringify(item)).split("\n");
|
|
31
|
-
|
|
32
|
-
lines.push("", " ***acceptance tests***", "");
|
|
33
|
-
for (const test of tests) {
|
|
34
|
-
const text = typeof test === "string" ? test : (test.markdown ?? JSON.stringify(test));
|
|
35
|
-
lines.push(...text.split("\n").map((line) => ` ${line}`));
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
return lines;
|
|
31
|
+
return id !== undefined ? [`# ${id}`, ...lines] : lines;
|
|
39
32
|
}
|
|
40
33
|
/**
|
|
41
34
|
* `changes` as a diff of `file` - the module's .plain file, which the diff names - section by section: a removed
|
|
42
35
|
* item's lines taken out, an added one's put in, a changed one's both. A change to what a linked file holds
|
|
43
36
|
* follows, as the step's own diff has it.
|
|
44
37
|
*/
|
|
45
|
-
export function changeDiff(changes, file) {
|
|
46
|
-
return laidOut(changes, file).diff;
|
|
38
|
+
export function changeDiff(changes, file, testPlain) {
|
|
39
|
+
return laidOut(changes, file, false, testPlain).diff;
|
|
47
40
|
}
|
|
48
41
|
/**
|
|
49
42
|
* `changeDiff`, each section's items in the order they are written - by file, then by line - rather than in the
|
|
50
43
|
* order the spec is read in, which puts a concept after those it uses: placed by `locate`, as the panels place it.
|
|
51
44
|
*/
|
|
52
|
-
export function changeDiffInFiles(changes, file, locate) {
|
|
53
|
-
const first = laidOut(changes, file);
|
|
45
|
+
export function changeDiffInFiles(changes, file, locate, testPlain) {
|
|
46
|
+
const first = laidOut(changes, file, false, testPlain);
|
|
54
47
|
const where = locate(first.diff);
|
|
55
48
|
const placeOf = (change) => {
|
|
56
49
|
const at = where[first.starts.get(change) ?? -1];
|
|
@@ -65,11 +58,14 @@ export function changeDiffInFiles(changes, file, locate) {
|
|
|
65
58
|
return a.position - b.position;
|
|
66
59
|
return x.file === y.file ? x.line - y.line : (x.file === file ? -1 : y.file === file ? 1 : x.file.localeCompare(y.file));
|
|
67
60
|
});
|
|
68
|
-
const diff = laidOut(ordered, file, true).diff;
|
|
61
|
+
const diff = laidOut(ordered, file, true, testPlain).diff;
|
|
69
62
|
return { diff, where: locate(diff) };
|
|
70
63
|
}
|
|
71
|
-
/**
|
|
72
|
-
|
|
64
|
+
/**
|
|
65
|
+
* The diff, and the line each change starts on in it. `asGiven`: each section's items in the order given. `testPlain`: a
|
|
66
|
+
* conformance job's - a functional spec whose scenarios changed has its test plain file's diff after the module's.
|
|
67
|
+
*/
|
|
68
|
+
function laidOut(changes, file, asGiven = false, testPlain) {
|
|
73
69
|
const starts = new Map();
|
|
74
70
|
const sections = [...new Set(changes.map((change) => change.section))].sort((a, b) => (ORDER.indexOf(a) === -1 ? ORDER.length : ORDER.indexOf(a)) - (ORDER.indexOf(b) === -1 ? ORDER.length : ORDER.indexOf(b)));
|
|
75
71
|
const lines = [`diff --git a/${file} b/${file}`, `--- a/${file}`, `+++ b/${file}`];
|
|
@@ -81,6 +77,9 @@ function laidOut(changes, file, asGiven = false) {
|
|
|
81
77
|
// Where this section's lines start in the diff: after the lines so far, its hunk header and its section header.
|
|
82
78
|
const offset = lines.length + 2;
|
|
83
79
|
for (const change of own) {
|
|
80
|
+
// Only its scenarios changed: they are its test plain file's, whose diff follows - the module's file shows nothing of it.
|
|
81
|
+
if (testPlain !== undefined && scenariosOnly(change))
|
|
82
|
+
continue;
|
|
84
83
|
const before = change.kind === "add" ? [] : itemLines(change.before);
|
|
85
84
|
const after = change.kind === "remove" ? [] : itemLines(change.after);
|
|
86
85
|
// Where it is found: its first line now, or - removed - its first line as it was.
|
|
@@ -96,7 +95,57 @@ function laidOut(changes, file, asGiven = false) {
|
|
|
96
95
|
continue;
|
|
97
96
|
lines.push("@@ @@", ` ${heading(section)}`, ...body);
|
|
98
97
|
}
|
|
99
|
-
|
|
98
|
+
// Nothing of the module's file changed - a conformance job's scenarios alone: no block for it at all.
|
|
99
|
+
const own = lines.length > 3 ? `${lines.join("\n")}\n` : "";
|
|
100
|
+
return { diff: `${own}${testPlain !== undefined ? testPlainDiffs(changes, testPlain) : ""}${resourceDiff(changes, file)}`, starts };
|
|
101
|
+
}
|
|
102
|
+
/** Whether a change to a functional spec is to its scenarios alone: its text, and all else of it, as it was. */
|
|
103
|
+
function scenariosOnly(change) {
|
|
104
|
+
if (change.kind !== "change" || change.before === undefined || change.after === undefined)
|
|
105
|
+
return false;
|
|
106
|
+
const rest = (serialized) => {
|
|
107
|
+
try {
|
|
108
|
+
const { conformance_tests: _conformance, acceptance_tests: _acceptance, ...others } = JSON.parse(serialized);
|
|
109
|
+
return JSON.stringify(others);
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
const [was, now] = [rest(change.before), rest(change.after)];
|
|
116
|
+
return was !== undefined && was === now && change.before !== change.after;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Each test plain file a conformance job's changes touch, as git diffs it: the lines that changed, among the lines around
|
|
120
|
+
* them - a functional spec with no scenarios has no file, so a new one is added whole and one whose scenarios all went is
|
|
121
|
+
* taken out whole.
|
|
122
|
+
*/
|
|
123
|
+
function testPlainDiffs(changes, testPlain) {
|
|
124
|
+
const scenarioCarrier = (line) => {
|
|
125
|
+
if (line === undefined)
|
|
126
|
+
return undefined;
|
|
127
|
+
try {
|
|
128
|
+
const item = JSON.parse(line);
|
|
129
|
+
return item.id !== undefined && (item.conformance_tests !== undefined || item.acceptance_tests !== undefined) ? item : undefined;
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return undefined;
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
return changes
|
|
136
|
+
// A module below's functional specs too: the tip's conformance suite holds the chain's.
|
|
137
|
+
.filter((change) => change.section === FUNCTIONAL_REQUIREMENTS || change.section === REQUIRED_FUNCTIONAL_SPECS)
|
|
138
|
+
.flatMap((change) => {
|
|
139
|
+
const [was, now] = [scenarioCarrier(change.kind === "add" ? undefined : change.before), scenarioCarrier(change.kind === "remove" ? undefined : change.after)];
|
|
140
|
+
const funcId = now?.id ?? was?.id;
|
|
141
|
+
if (funcId === undefined)
|
|
142
|
+
return [];
|
|
143
|
+
const module = now?.module ?? was?.module ?? testPlain.module;
|
|
144
|
+
const fileOf = (carrier) => carrier !== undefined && (carrier.conformance_tests ?? []).length + (carrier.acceptance_tests ?? []).length > 0 ? testPlainFileText(module, carrier) : "";
|
|
145
|
+
const diff = diffFileTexts(fileOf(was), fileOf(now), testPlain.pathOf(funcId, module));
|
|
146
|
+
return diff === "" ? [] : [diff];
|
|
147
|
+
})
|
|
148
|
+
.join("");
|
|
100
149
|
}
|
|
101
150
|
/** The changes a job's agent works from: a code job's leave out the test reqs, which are the conformance job's. */
|
|
102
151
|
export function agentChanges(changes, track) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type MarshalledPlainSource } from "../plain/spec.ts";
|
|
2
2
|
import { type Steering } from "./steer.ts";
|
|
3
|
-
import { type SpecChange, type SpecStep } from "./spec-steps.ts";
|
|
3
|
+
import { type SpecChange, type SpecStep, type TestPlainPath } from "./spec-steps.ts";
|
|
4
4
|
/**
|
|
5
5
|
* The queue's work, cut into jobs of a size worth rendering.
|
|
6
6
|
*
|
|
@@ -18,8 +18,9 @@ import { type SpecChange, type SpecStep } from "./spec-steps.ts";
|
|
|
18
18
|
* 3. Where each new implementation req goes - the group it is about, or the first, when it is about
|
|
19
19
|
* everything - and each new test req: the group whose conformance tests need it first. An agent judges it.
|
|
20
20
|
*
|
|
21
|
-
* Changes to what is built already - an item edited or taken out, a functional spec built changed - go
|
|
22
|
-
*
|
|
21
|
+
* Changes to what is built already - an item edited or taken out, a functional spec built changed - go where the
|
|
22
|
+
* grouping agent places each: with the new work it is about, by default, or first, in a job of their own, when it
|
|
23
|
+
* reshapes what the new work is built on or has nothing to do with it. Every answer is checked; one that does not hold goes back to its agent, twice at most, and then
|
|
23
24
|
* the plan falls back to a functional spec a job. A job past `max-lines-per-pulse` (MAX_LINES_PER_JOB unset) is split. The plan is the queue
|
|
24
25
|
* master's proposal: it reviews it, and may change it, held to the same checks.
|
|
25
26
|
*/
|
|
@@ -47,11 +48,8 @@ export interface PlanInput {
|
|
|
47
48
|
* in one job, as far as the guardrail (`max-lines-per-pulse`) lets.
|
|
48
49
|
*/
|
|
49
50
|
separately?: boolean;
|
|
50
|
-
/**
|
|
51
|
-
|
|
52
|
-
* for 4-6. Never two groups in one job; the functional specs in none are tested together, as before.
|
|
53
|
-
*/
|
|
54
|
-
groups?: string[][];
|
|
51
|
+
/** For the conformance tests: where each functional spec's test plain file is, as a step's ***plain diff names it. */
|
|
52
|
+
testPlainPath?: TestPlainPath;
|
|
55
53
|
/** How big a pulse may be - the config's `max-specs-per-pulse` and `max-lines-per-pulse`; unset, MAX_SPECS_PER_JOB and MAX_LINES_PER_JOB. */
|
|
56
54
|
limits?: PulseLimits;
|
|
57
55
|
}
|
|
@@ -90,9 +88,9 @@ export declare function shortTitle(text: string, chars?: number, words?: number)
|
|
|
90
88
|
export declare const MAX_LINES_PER_JOB = 120;
|
|
91
89
|
/**
|
|
92
90
|
* A functional spec to build, for the grouping: the number the agent answers with, its text, and whether it is built
|
|
93
|
-
* already and regenerated again. `id` and `module` say which it is:
|
|
94
|
-
* regenerates again the functional specs of the modules it is built on too. No module: the codebase's own.
|
|
95
|
-
* number.
|
|
91
|
+
* already and regenerated again. `id` and `module` say which it is: its func-id, unique in its module, and a codebase
|
|
92
|
+
* regenerates again the functional specs of the modules it is built on too. No module: the codebase's own. `place` is
|
|
93
|
+
* where it is among its module's functional specs - the ones next to it there are next to it. No place: its number.
|
|
96
94
|
*/
|
|
97
95
|
export interface NewSpec {
|
|
98
96
|
number: number;
|
|
@@ -100,12 +98,31 @@ export interface NewSpec {
|
|
|
100
98
|
again?: boolean;
|
|
101
99
|
id?: string;
|
|
102
100
|
module?: string;
|
|
101
|
+
place?: number;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* A change to what is built already, for the grouping: the number the agent answers with, whether it is changed, taken
|
|
105
|
+
* out or put in among what is built, what it is - a functional spec, a definition, a req - and its text. `id` and
|
|
106
|
+
* `module` say which functional spec it is.
|
|
107
|
+
*/
|
|
108
|
+
export interface BuiltChange {
|
|
109
|
+
number: number;
|
|
110
|
+
kind: "changed" | "taken out" | "added";
|
|
111
|
+
what: string;
|
|
112
|
+
text: string;
|
|
113
|
+
id?: string;
|
|
114
|
+
module?: string;
|
|
103
115
|
}
|
|
104
116
|
export interface GroupAnswer {
|
|
105
117
|
groups: Array<{
|
|
106
118
|
specs: number[];
|
|
107
119
|
title: string;
|
|
108
120
|
}>;
|
|
121
|
+
/** Where each change to what is built goes: with a group, by its number, or "first" - a pulse of its own, before the new work. */
|
|
122
|
+
built?: Array<{
|
|
123
|
+
change: number;
|
|
124
|
+
to: number | "first";
|
|
125
|
+
}>;
|
|
109
126
|
/** What of the person's wishes it did not follow, and why. */
|
|
110
127
|
notes?: string;
|
|
111
128
|
}
|
|
@@ -161,18 +178,22 @@ export interface TitleAnswer {
|
|
|
161
178
|
* first functional spec's first line; without it, they keep that.
|
|
162
179
|
*/
|
|
163
180
|
export interface ChunkAgents {
|
|
164
|
-
group(specs: NewSpec[], check: (answer: GroupAnswer) => string[], steering?: Steering[], maxSpecs?: number): Promise<GroupAnswer | undefined>;
|
|
181
|
+
group(specs: NewSpec[], check: (answer: GroupAnswer) => string[], steering?: Steering[], maxSpecs?: number, built?: BuiltChange[]): Promise<GroupAnswer | undefined>;
|
|
165
182
|
place(input: PlaceInput, check: (answer: PlaceAnswer) => string[]): Promise<PlaceAnswer | undefined>;
|
|
166
183
|
title?(groups: TitleGroup[], check: (answer: TitleAnswer) => string[], track: "code" | "conformance"): Promise<TitleAnswer | undefined>;
|
|
167
184
|
}
|
|
168
|
-
/**
|
|
169
|
-
|
|
185
|
+
/**
|
|
186
|
+
* What is wrong with a grouping: every new functional spec once, in order, next to each other, none too big - and
|
|
187
|
+
* every change to what is built placed once, with a group or first. A functional spec changed counts in its group: it
|
|
188
|
+
* is built as the new ones are. One taken out builds nothing, and does not.
|
|
189
|
+
*/
|
|
190
|
+
export declare function groupProblems(specs: NewSpec[], answer: GroupAnswer, maxSpecs?: number, built?: BuiltChange[]): string[];
|
|
170
191
|
/** What is wrong with a titling: every group titled once, by its number, none empty, none too long. */
|
|
171
192
|
export declare function titleProblems(groups: TitleGroup[], answer: TitleAnswer): string[];
|
|
172
193
|
/** What is wrong with a placement: every new req once, each where there is such a job. */
|
|
173
194
|
export declare function placeProblems(input: PlaceInput, answer: PlaceAnswer): string[];
|
|
174
195
|
export declare function planChunks(input: PlanInput, agents?: ChunkAgents, notes?: string[]): Promise<DraftJob[]>;
|
|
175
|
-
export declare function groupPrompt(specs: NewSpec[], steering?: Steering[], maxSpecs?: number): string;
|
|
196
|
+
export declare function groupPrompt(specs: NewSpec[], steering?: Steering[], maxSpecs?: number, built?: BuiltChange[]): string;
|
|
176
197
|
export declare function placePrompt(input: PlaceInput): string;
|
|
177
198
|
export declare function titlePrompt(groups: TitleGroup[], track: "code" | "conformance"): string;
|
|
178
199
|
/** The chunking's agents, on a model - fresh for every plan. */
|