@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
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { readProjectConfig, stacksOf } from "./config.js";
|
|
5
|
+
import { bedrockAwsRegion, bedrockNeedsAwsRegion, bedrockPlaceOf } from "./init-config.js";
|
|
6
|
+
import { modelsInUse } from "./model-check.js";
|
|
7
|
+
/** The variable turri marks its own AWS_REGION with, so the pi it starts - and a reload - tells it from the person's. */
|
|
8
|
+
export const TURRI_AWS_REGION = "TURRI_AWS_REGION";
|
|
9
|
+
/** pi's region when nothing names one. */
|
|
10
|
+
const DEFAULT_REGION = "us-east-1";
|
|
11
|
+
/** Whether a region is in a geography: one of the regions Bedrock serves that geography's inference profiles from. */
|
|
12
|
+
export function regionInGeography(region, geography) {
|
|
13
|
+
const exact = {
|
|
14
|
+
jp: ["ap-northeast-1", "ap-northeast-3"],
|
|
15
|
+
au: ["ap-southeast-2", "ap-southeast-4"],
|
|
16
|
+
in: ["ap-south-1", "ap-south-2"],
|
|
17
|
+
};
|
|
18
|
+
if (exact[geography] !== undefined)
|
|
19
|
+
return exact[geography].includes(region);
|
|
20
|
+
const prefix = { eu: "eu-", apac: "ap-", ca: "ca-", "us-gov": "us-gov-", us: "us-" };
|
|
21
|
+
if (prefix[geography] !== undefined)
|
|
22
|
+
return region.startsWith(prefix[geography]) && (geography !== "us" || !region.startsWith("us-gov-"));
|
|
23
|
+
// global and in-region: any region serves them.
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
/** The region an AWS profile names, from AWS_CONFIG_FILE or ~/.aws/config - undefined when it names none, or the file cannot be read. */
|
|
27
|
+
export function profileRegion(profile, env = process.env) {
|
|
28
|
+
const file = env.AWS_CONFIG_FILE?.trim() || join(homedir(), ".aws", "config");
|
|
29
|
+
if (!existsSync(file))
|
|
30
|
+
return undefined;
|
|
31
|
+
let text;
|
|
32
|
+
try {
|
|
33
|
+
text = readFileSync(file, "utf8");
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
const wanted = profile === "default" ? ["default", "profile default"] : [`profile ${profile}`];
|
|
39
|
+
let inside = false;
|
|
40
|
+
for (const raw of text.split(/\r?\n/)) {
|
|
41
|
+
const line = raw.trim();
|
|
42
|
+
const section = /^\[\s*(.+?)\s*\]$/.exec(line);
|
|
43
|
+
if (section !== null) {
|
|
44
|
+
inside = wanted.includes(section[1].replace(/\s+/g, " "));
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (!inside)
|
|
48
|
+
continue;
|
|
49
|
+
const setting = /^region\s*=\s*(\S+)/.exec(line);
|
|
50
|
+
if (setting !== null)
|
|
51
|
+
return setting[1];
|
|
52
|
+
}
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
/** The Bedrock models a project uses: every model its config names - each stack's too - and those given. */
|
|
56
|
+
function bedrockModels(projectDir, also) {
|
|
57
|
+
const configs = [readProjectConfig(projectDir), ...stacksOf(projectDir).map((stack) => readProjectConfig(projectDir, stack))];
|
|
58
|
+
const specs = [...configs.flatMap((config) => modelsInUse(config).map((used) => used.spec)), ...also];
|
|
59
|
+
return [...new Set(specs.filter((spec) => spec.startsWith("amazon-bedrock/")))];
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* What turri does about the AWS region for a project, from the environment as it is - reading it, setting nothing.
|
|
63
|
+
* `also`: models used besides the config's - named on the command line, chosen in this session.
|
|
64
|
+
*/
|
|
65
|
+
export function bedrockRegionFor(projectDir, options = {}) {
|
|
66
|
+
const env = options.env ?? process.env;
|
|
67
|
+
const models = bedrockModels(projectDir, options.also ?? []);
|
|
68
|
+
// The regions the models need, by region: a model served in global, us or in-region needs none.
|
|
69
|
+
const needed = new Map();
|
|
70
|
+
for (const model of models) {
|
|
71
|
+
const { geography } = bedrockPlaceOf(model);
|
|
72
|
+
if (!bedrockNeedsAwsRegion(geography))
|
|
73
|
+
continue;
|
|
74
|
+
const region = bedrockAwsRegion(geography);
|
|
75
|
+
needed.set(region, { geography, models: [...(needed.get(region)?.models ?? []), model] });
|
|
76
|
+
}
|
|
77
|
+
const conflict = needed.size > 1 ? [...needed].map(([region, { geography, models }]) => ({ region, geography, models })) : undefined;
|
|
78
|
+
const [only] = needed.size === 1 ? [...needed] : [];
|
|
79
|
+
const needs = only !== undefined ? { region: only[0], geography: only[1].geography } : undefined;
|
|
80
|
+
const withConflict = { ...(conflict !== undefined ? { conflict } : {}), ...(needs !== undefined ? { needs } : {}) };
|
|
81
|
+
// The person's region wins, always; turri's own is worked out again.
|
|
82
|
+
const ours = env[TURRI_AWS_REGION];
|
|
83
|
+
const set = env.AWS_REGION?.trim() || env.AWS_DEFAULT_REGION?.trim();
|
|
84
|
+
if (set !== undefined && set !== "" && !(ours !== undefined && env.AWS_REGION === ours))
|
|
85
|
+
return { region: set, source: "set", models, ...withConflict };
|
|
86
|
+
const profile = env.AWS_PROFILE?.trim();
|
|
87
|
+
const fromProfile = profile !== undefined && profile !== "" ? profileRegion(profile, env) : undefined;
|
|
88
|
+
// One region needed: the profile's, when it is in that geography; otherwise turri's.
|
|
89
|
+
if (needs !== undefined) {
|
|
90
|
+
if (fromProfile !== undefined && regionInGeography(fromProfile, needs.geography))
|
|
91
|
+
return { region: fromProfile, source: "profile", models, needs };
|
|
92
|
+
return { region: needs.region, source: "turri", models, needs };
|
|
93
|
+
}
|
|
94
|
+
// None needed, or two: pi goes by the profile, or its default - with two, which is not one of them for every model.
|
|
95
|
+
if (fromProfile !== undefined)
|
|
96
|
+
return { region: fromProfile, source: "profile", models, ...withConflict };
|
|
97
|
+
return { ...(models.length > 0 && conflict === undefined ? { region: DEFAULT_REGION } : {}), source: "default", models, ...withConflict };
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Set AWS_REGION for a project's Bedrock models, as `bedrockRegionFor` says: when they need a region and the person
|
|
101
|
+
* set none. Done again when the models change, it moves or takes back what turri set before, never the person's.
|
|
102
|
+
*/
|
|
103
|
+
export function applyBedrockRegion(projectDir, options = {}) {
|
|
104
|
+
const env = options.env ?? process.env;
|
|
105
|
+
let decided;
|
|
106
|
+
try {
|
|
107
|
+
decided = bedrockRegionFor(projectDir, { ...options, env });
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
// A config that does not read is the model check's to say: nothing is set from it.
|
|
111
|
+
return { source: "default", models: [] };
|
|
112
|
+
}
|
|
113
|
+
if (decided.source === "turri" && decided.region !== undefined) {
|
|
114
|
+
env.AWS_REGION = decided.region;
|
|
115
|
+
env[TURRI_AWS_REGION] = decided.region;
|
|
116
|
+
}
|
|
117
|
+
else if (decided.source !== "set" && env[TURRI_AWS_REGION] !== undefined) {
|
|
118
|
+
// What turri set before is needed no more - or two regions are now: taken back, not guessed.
|
|
119
|
+
if (env.AWS_REGION === env[TURRI_AWS_REGION])
|
|
120
|
+
delete env.AWS_REGION;
|
|
121
|
+
delete env[TURRI_AWS_REGION];
|
|
122
|
+
}
|
|
123
|
+
return decided;
|
|
124
|
+
}
|
|
125
|
+
/** A line on the region, for a model check: what turri set and how to override it - or the conflict it would not guess. */
|
|
126
|
+
export function describeBedrockRegion(decided) {
|
|
127
|
+
if (decided.conflict !== undefined) {
|
|
128
|
+
const needs = decided.conflict.map((each) => `${each.models.join(", ")} need${each.models.length === 1 ? "s" : ""} ${each.region} (${each.geography})`).join("; ");
|
|
129
|
+
return `the Bedrock models need two AWS regions - ${needs} - and one AWS_REGION serves every model: turri set none. Use models of one geography, or global ones.`;
|
|
130
|
+
}
|
|
131
|
+
if (decided.region === undefined)
|
|
132
|
+
return undefined;
|
|
133
|
+
if (decided.source === "turri")
|
|
134
|
+
return `turri calls Bedrock in ${decided.region}, the region the models' geography needs - AWS_REGION, set, overrides it`;
|
|
135
|
+
if (decided.source === "set") {
|
|
136
|
+
const outside = decided.needs !== undefined && !regionInGeography(decided.region, decided.needs.geography);
|
|
137
|
+
return outside
|
|
138
|
+
? `pi calls Bedrock in ${decided.region}, set in AWS_REGION or AWS_DEFAULT_REGION - but the models are served in ${decided.needs.geography}: set it to a region there, ${decided.needs.region}, or unset it and turri sets it`
|
|
139
|
+
: `pi calls Bedrock in ${decided.region}, set in AWS_REGION or AWS_DEFAULT_REGION - the models have to be served there`;
|
|
140
|
+
}
|
|
141
|
+
if (decided.source === "profile")
|
|
142
|
+
return `pi calls Bedrock in ${decided.region}, the AWS profile's region - AWS_REGION, set, overrides it`;
|
|
143
|
+
return `pi calls Bedrock in ${decided.region}, its default - AWS_REGION, set, overrides it`;
|
|
144
|
+
}
|
package/dist/btw.d.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
import type { AskUser, AskUserRequest } from "./ask.ts";
|
|
13
13
|
/** How many tool calls the side agent may make before it is told to answer. */
|
|
14
14
|
export declare const SIDE_CALLS = 20;
|
|
15
|
-
/** "/btw what is a
|
|
15
|
+
/** "/btw what is a func-id?" -> "what is a func-id?"; "/btw" alone -> ""; anything else is not a side question. */
|
|
16
16
|
export declare function sideQuestionOf(text: string): string | undefined;
|
|
17
17
|
/** The skill running now, as the side agent is told of it. */
|
|
18
18
|
export interface SkillRunNow {
|
package/dist/btw.js
CHANGED
|
@@ -19,7 +19,7 @@ export const SIDE_CALLS = 20;
|
|
|
19
19
|
/** How much of a transcript the side agent is shown, from its end. */
|
|
20
20
|
const CONVERSATION_CHARS = 24_000;
|
|
21
21
|
const SKILL_SESSION_CHARS = 16_000;
|
|
22
|
-
/** "/btw what is a
|
|
22
|
+
/** "/btw what is a func-id?" -> "what is a func-id?"; "/btw" alone -> ""; anything else is not a side question. */
|
|
23
23
|
export function sideQuestionOf(text) {
|
|
24
24
|
const match = /^\s*\/btw(?:\s+|$)([\s\S]*)$/i.exec(text);
|
|
25
25
|
return match === null ? undefined : match[1].trim();
|
package/dist/change-plain-cli.js
CHANGED
|
@@ -1,38 +1,45 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
2
|
import { resolve } from "node:path";
|
|
3
|
-
import {
|
|
4
|
-
import { applySpecDiff, revertSpecDiff } from "./regenerate/regenerate.js";
|
|
3
|
+
import { checkTouchedPlain, formatCheckResults } from "./plain/check.js";
|
|
4
|
+
import { applySpecDiff, plainFilesOf, revertSpecDiff } from "./regenerate/regenerate.js";
|
|
5
|
+
import { testPlainFileRefusal } from "./test-plain-files.js";
|
|
5
6
|
import { parseArgs } from "./cli-options.js";
|
|
6
7
|
import { headlessOptions, runLoop } from "./loop-cli.js";
|
|
7
8
|
const USAGE = `usage: turri change-plain <file.plain> <diff-file> [options]
|
|
8
9
|
|
|
9
|
-
Applies a change to ***plain, given as a git diff of the .plain files
|
|
10
|
+
Applies a change to ***plain, given as a git diff of the .plain files - modules and test plain files - and
|
|
11
|
+
builds it: the headless
|
|
10
12
|
counterpart of regenerate, given a diff. The diff is applied first, unless it is already in; then, as
|
|
11
13
|
turri regenerate does, what is left to build is planned into jobs and built.
|
|
12
14
|
|
|
13
|
-
--harness-model <p/id> config.turri.yaml's harness-model for this run: the planner,
|
|
15
|
+
--harness-model <p/id> config.turri.yaml's harness-model for this run: the planner, a diagnosis
|
|
14
16
|
--coding-model <p/id> its coding-model, --model too: the agents that build
|
|
15
17
|
--start-over start over, without asking, a codebase regenerated without a module it now requires
|
|
16
18
|
--judge-model <p/id> its judge-model: the judge and the test review
|
|
17
19
|
--review <true|false> its review: whether the code and its tests are reviewed once they pass
|
|
18
|
-
--conformance-tests <all|chosen|module|false>
|
|
19
|
-
its conformance-tests: which conformance tests are written and run
|
|
20
20
|
--build-dir <dir> as the run ends, export the code there (see turri regenerate --help)
|
|
21
21
|
--report <file.json> write a report of the run there (see turri regenerate --help)`;
|
|
22
|
-
const { positional, options } = parseArgs(process.argv.slice(2), ["--start-over"], USAGE, ["--build-dir", "--report", "--
|
|
23
|
-
const { report, buildDir } = headlessOptions(options
|
|
22
|
+
const { positional, options } = parseArgs(process.argv.slice(2), ["--start-over"], USAGE, ["--build-dir", "--report", "--harness-model", "--judge-model", "--review"]);
|
|
23
|
+
const { report, buildDir } = headlessOptions(options);
|
|
24
24
|
const [plainFile, diffFile] = positional;
|
|
25
25
|
if (plainFile === undefined || diffFile === undefined) {
|
|
26
26
|
console.error(USAGE);
|
|
27
27
|
process.exit(1);
|
|
28
28
|
}
|
|
29
|
+
const refusal = testPlainFileRefusal(plainFile);
|
|
30
|
+
if (refusal !== undefined) {
|
|
31
|
+
console.error(refusal);
|
|
32
|
+
process.exit(1);
|
|
33
|
+
}
|
|
29
34
|
const diff = readFileSync(diffFile, "utf8");
|
|
30
35
|
const cwd = process.cwd();
|
|
31
|
-
applySpecDiff(diff, cwd);
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
const applied = applySpecDiff(diff, cwd);
|
|
37
|
+
// Every file the diff touched is checked - a test plain file as its module - not only the one named.
|
|
38
|
+
const failed = checkTouchedPlain([plainFile, ...plainFilesOf(diff)].map((file) => resolve(cwd, file))).filter((check) => !check.ok);
|
|
39
|
+
if (failed.length > 0) {
|
|
40
|
+
if (applied === "applied")
|
|
41
|
+
revertSpecDiff(diff, cwd);
|
|
42
|
+
console.error(`Nothing was changed: with this diff the ***plain no longer checks.\n${formatCheckResults(failed)}`);
|
|
36
43
|
process.exit(1);
|
|
37
44
|
}
|
|
38
45
|
runLoop({
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import type { ChatLink } from "./chats.ts";
|
|
3
|
+
/**
|
|
4
|
+
* Whether a chat is busy, for what turri tells it of its own accord - a test advisor's verdict, a background skill run's
|
|
5
|
+
* end - and so waits: its agent working, or the person typing - or no session to tell yet. Nothing told so interrupts.
|
|
6
|
+
*/
|
|
7
|
+
export declare function chatBusy(link: ChatLink, context: () => ExtensionContext | undefined): boolean;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether a chat is busy, for what turri tells it of its own accord - a test advisor's verdict, a background skill run's
|
|
3
|
+
* end - and so waits: its agent working, or the person typing - or no session to tell yet. Nothing told so interrupts.
|
|
4
|
+
*/
|
|
5
|
+
export function chatBusy(link, context) {
|
|
6
|
+
const session = link.session();
|
|
7
|
+
if (session === undefined || session.isStreaming || session.isCompacting || session.isRetrying)
|
|
8
|
+
return true;
|
|
9
|
+
const ctx = context();
|
|
10
|
+
try {
|
|
11
|
+
if (ctx !== undefined && (!ctx.isIdle() || ctx.hasPendingMessages()))
|
|
12
|
+
return true;
|
|
13
|
+
if (ctx?.hasUI === true && ctx.ui.getEditorText().trim() !== "")
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
/* a context let go: the session says enough */
|
|
18
|
+
}
|
|
19
|
+
return false;
|
|
20
|
+
}
|
package/dist/chats.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { type SentinelSetting } from "./config.ts";
|
|
|
6
6
|
import type { AskUserIO } from "./ask.ts";
|
|
7
7
|
import type { Job, JobRegistry } from "./regenerate/jobs.ts";
|
|
8
8
|
import type { ToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
9
|
+
import type { AdvisorVerdict } from "./regenerate/advisor-runs.ts";
|
|
9
10
|
import { type ChatRole, type Conclusion, type Notice, type NoticeAnswer, type NoticeInput } from "./notice.ts";
|
|
10
11
|
/**
|
|
11
12
|
* The chats of a turri session.
|
|
@@ -110,12 +111,19 @@ export interface ChatInstance {
|
|
|
110
111
|
concluded(conclusion: Conclusion): void;
|
|
111
112
|
/** The person answered a notice with something to do: the chat's agent started on it. */
|
|
112
113
|
act(task: string): void;
|
|
114
|
+
/**
|
|
115
|
+
* The test advisor's verdict: once the chat is idle - its agent done, nothing typed - a yes starts a turn that writes its
|
|
116
|
+
* scenarios, and a no is a line. Those that arrive meanwhile are delivered together.
|
|
117
|
+
*/
|
|
118
|
+
advised(verdict: AdvisorVerdict): void;
|
|
113
119
|
/** The jobs changed: what it draws of them is drawn again. */
|
|
114
120
|
jobsChanged(): void;
|
|
115
121
|
/** How hard the chat's model thinks now: sub-agents started from it think as hard. */
|
|
116
122
|
thinkingLevel(): string | undefined;
|
|
117
123
|
/** The chat's context, as its tools get it - for its model and its providers. */
|
|
118
124
|
context(): ExtensionContext | undefined;
|
|
125
|
+
/** Conformance tests turned on or off: the chat's tools switched to match - conform and evaluate_tests, or the tool that turns them on. */
|
|
126
|
+
conformanceSwitched?(): void;
|
|
119
127
|
}
|
|
120
128
|
/** A chat's extension, linked to its chat. */
|
|
121
129
|
export interface ChatLink {
|
|
@@ -213,6 +221,8 @@ export interface TurriCore {
|
|
|
213
221
|
notice(input: NoticeInput): Notice | undefined;
|
|
214
222
|
/** The sentinel done with a pulse: told to the chat the person looks at. Undefined: no chat to tell. */
|
|
215
223
|
concluded(conclusion: Conclusion): string | undefined;
|
|
224
|
+
/** The test advisor's verdict, for the chat the person looks at - held until there is one. Undefined: no chat to hand it to yet. */
|
|
225
|
+
advised(verdict: AdvisorVerdict): string | undefined;
|
|
216
226
|
/** The notices put to the person and not yet answered. */
|
|
217
227
|
notices(): Notice[];
|
|
218
228
|
/**
|
package/dist/chats.js
CHANGED
|
@@ -104,6 +104,8 @@ export function createChats(options) {
|
|
|
104
104
|
let consent = "unasked";
|
|
105
105
|
let asking;
|
|
106
106
|
const held = [];
|
|
107
|
+
/** The test advisor's verdicts that came with no chat of the person's to hand them to: handed on as one comes up. */
|
|
108
|
+
const unplaced = [];
|
|
107
109
|
const run = { run: randomUUID().slice(0, 8), pid: process.pid, started: new Date().toISOString(), chats: [] };
|
|
108
110
|
const changed = () => {
|
|
109
111
|
for (const listener of listeners) {
|
|
@@ -357,6 +359,10 @@ export function createChats(options) {
|
|
|
357
359
|
session: () => chat.session,
|
|
358
360
|
live: (instance) => {
|
|
359
361
|
chat.instance = instance;
|
|
362
|
+
// The advisor's verdicts that waited for a chat of the person's.
|
|
363
|
+
if (unplaced.length > 0 && personFacing() !== undefined)
|
|
364
|
+
for (const verdict of unplaced.splice(0))
|
|
365
|
+
core.advised(verdict);
|
|
360
366
|
},
|
|
361
367
|
};
|
|
362
368
|
},
|
|
@@ -456,6 +462,23 @@ export function createChats(options) {
|
|
|
456
462
|
changed();
|
|
457
463
|
return target.id;
|
|
458
464
|
},
|
|
465
|
+
advised(verdict) {
|
|
466
|
+
const target = personFacing();
|
|
467
|
+
if (target?.instance === undefined) {
|
|
468
|
+
unplaced.push(verdict);
|
|
469
|
+
return undefined;
|
|
470
|
+
}
|
|
471
|
+
if (target.id !== shownId)
|
|
472
|
+
target.unread = true;
|
|
473
|
+
try {
|
|
474
|
+
target.instance.advised(verdict);
|
|
475
|
+
}
|
|
476
|
+
catch {
|
|
477
|
+
/* a chat let go as it was told: a yes stays undelivered in the advisor's file, for the next start */
|
|
478
|
+
}
|
|
479
|
+
changed();
|
|
480
|
+
return target.id;
|
|
481
|
+
},
|
|
459
482
|
answer(id, answer) {
|
|
460
483
|
const notice = open.find((candidate) => candidate.id === id);
|
|
461
484
|
if (notice === undefined)
|
package/dist/cli-options.d.ts
CHANGED
|
@@ -15,11 +15,10 @@ export declare function parseArgs(argv: string[], flags: string[], usage: string
|
|
|
15
15
|
export declare function optionValue(options: Record<string, string | undefined>, name: string): string | undefined;
|
|
16
16
|
/**
|
|
17
17
|
* The options that stand for the config's own keys - `--harness-model`, `--coding-model` (`--model`), `--judge-model`
|
|
18
|
-
* and, as asked, `--review
|
|
18
|
+
* and, as asked, `--review` and `--mutation-testing` - read as if config.turri.yaml had them, in their place in the
|
|
19
19
|
* order the config resolves them in (overrideConfig): a run, or doctor, with them is the same as one with them in the
|
|
20
20
|
* file. Exits on a value it cannot read.
|
|
21
21
|
*/
|
|
22
22
|
export declare function configKeyOptions(options: Record<string, string | undefined>, take?: {
|
|
23
|
-
conformance?: boolean;
|
|
24
23
|
review?: boolean;
|
|
25
24
|
}): void;
|
package/dist/cli-options.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { booleanOption,
|
|
1
|
+
import { booleanOption, overrideConfig, splitModelSpec } from "./config.js";
|
|
2
2
|
/**
|
|
3
3
|
* The command line of turri's commands: their words, and the options that stand for the config's own keys - kept apart
|
|
4
4
|
* from the commands that use them, so a light one (doctor) reads them as a regenerate does without loading it.
|
|
@@ -51,7 +51,7 @@ export function optionValue(options, name) {
|
|
|
51
51
|
}
|
|
52
52
|
/**
|
|
53
53
|
* The options that stand for the config's own keys - `--harness-model`, `--coding-model` (`--model`), `--judge-model`
|
|
54
|
-
* and, as asked, `--review
|
|
54
|
+
* and, as asked, `--review` and `--mutation-testing` - read as if config.turri.yaml had them, in their place in the
|
|
55
55
|
* order the config resolves them in (overrideConfig): a run, or doctor, with them is the same as one with them in the
|
|
56
56
|
* file. Exits on a value it cannot read.
|
|
57
57
|
*/
|
|
@@ -63,10 +63,6 @@ export function configKeyOptions(options, take = {}) {
|
|
|
63
63
|
failOption(`--${name} takes true or false, not ${given}`);
|
|
64
64
|
return value;
|
|
65
65
|
};
|
|
66
|
-
const tests = take.conformance === true ? optionValue(options, "conformance-tests") : undefined;
|
|
67
|
-
const setting = tests !== undefined ? conformanceOption(tests) : undefined;
|
|
68
|
-
if (tests !== undefined && setting === undefined)
|
|
69
|
-
failOption(`--conformance-tests takes all, chosen, module or false, not ${tests}`);
|
|
70
66
|
const review = flag("review");
|
|
71
67
|
const mutationTesting = flag("mutation-testing");
|
|
72
68
|
const model = (name, key) => {
|
|
@@ -77,7 +73,6 @@ export function configKeyOptions(options, take = {}) {
|
|
|
77
73
|
...model("harness-model", "harnessModel"),
|
|
78
74
|
...model("model", "codingModel"),
|
|
79
75
|
...model("judge-model", "judgeModel"),
|
|
80
|
-
...(setting !== undefined ? { conformanceTests: setting } : {}),
|
|
81
76
|
...(review !== undefined ? { review } : {}),
|
|
82
77
|
...(mutationTesting !== undefined ? { mutationTesting } : {}),
|
|
83
78
|
});
|
package/dist/cli.js
CHANGED
|
@@ -72,12 +72,12 @@ function chat(args) {
|
|
|
72
72
|
process.exit(result.status ?? 1);
|
|
73
73
|
}
|
|
74
74
|
const COMMANDS = {
|
|
75
|
-
regenerate: { module: "./regenerate-cli.ts", blurb: "regenerate a module and its chain from the spec as it is (with
|
|
75
|
+
regenerate: { module: "./regenerate-cli.ts", blurb: "regenerate a module and its chain from the spec as it is (with module:func-ids: regenerate those again)" },
|
|
76
76
|
glimpse: { module: "./regenerate-cli.ts", blurb: "plan the work and print the first job's prompt, starting nothing", args: ["--dry-run"] },
|
|
77
77
|
drift: { module: "./drift-cli.ts", blurb: "what is left to regenerate: how far the code has drifted from its spec" },
|
|
78
78
|
conform: { module: "./conform-cli.ts", blurb: "write and run a module's conformance tests" },
|
|
79
79
|
"change-plain": { module: "./change-plain-cli.ts", blurb: "apply a change to ***plain, given as a git diff, and regenerate it" },
|
|
80
|
-
|
|
80
|
+
parse: { module: "./parse-cli.ts", blurb: "parse ***plain - its syntax and structure, never its code or tests - regenerating nothing" },
|
|
81
81
|
lineage: { module: "./lineage-cli.ts", blurb: "a module's lineage: what was regenerated into it, and when" },
|
|
82
82
|
ledger: { module: "./ledger-cli.ts", blurb: "what turri did here: the last runs and their pulses, or one pulse, from the ledger" },
|
|
83
83
|
release: { module: "./release-cli.ts", blurb: "release what is regenerated to dist/<module> and activate it on this machine" },
|
|
@@ -147,6 +147,14 @@ if (command === "-v" || command === "--version") {
|
|
|
147
147
|
console.log(versionLine());
|
|
148
148
|
process.exit(0);
|
|
149
149
|
}
|
|
150
|
+
// The AWS region the project's Bedrock models need, set before any model is called - here, and in the pi the chat starts,
|
|
151
|
+
// which inherits it - unless the person set one (bedrock-region.ts). The models named on the command line count too. A
|
|
152
|
+
// command that calls no model is left alone.
|
|
153
|
+
if (!["parse", "drift", "lineage", "ledger", "init-config"].includes(command ?? "")) {
|
|
154
|
+
const { applyBedrockRegion } = await import("./bedrock-region.js");
|
|
155
|
+
const named = argv.flatMap((arg, at) => ["--harness-model", "--coding-model", "--model"].includes(arg) ? [argv[at + 1] ?? ""] : arg.startsWith("--harness-model=") || arg.startsWith("--coding-model=") || arg.startsWith("--model=") ? [arg.slice(arg.indexOf("=") + 1)] : []);
|
|
156
|
+
applyBedrockRegion(process.cwd(), { also: named.filter((model) => model !== "") });
|
|
157
|
+
}
|
|
150
158
|
// turri alone is the conversation, and so is turri with pi's options - `turri -c`, `turri --harness-model <m>`. A word
|
|
151
159
|
// turri does not know is an error below, not a conversation started on it.
|
|
152
160
|
if (command === undefined || command.startsWith("-"))
|
|
@@ -175,7 +183,7 @@ process.argv = [
|
|
|
175
183
|
// A headless run is stopped by a signal - SIGTERM, SIGHUP, Ctrl-C - whatever else listens for it: it exits, and what
|
|
176
184
|
// its agents left running goes with it (shell.ts kills every process group on exit). Left to the libraries' own
|
|
177
185
|
// handlers, one ran on for minutes after it was told to stop, building in the same codebase as the run after it.
|
|
178
|
-
if (!["
|
|
186
|
+
if (!["parse", "drift", "lineage", "ledger"].includes(command)) {
|
|
179
187
|
for (const [signal, code] of [["SIGTERM", 143], ["SIGHUP", 129], ["SIGINT", 130]]) {
|
|
180
188
|
process.on(signal, () => {
|
|
181
189
|
console.error(`\nstopped (${signal})`);
|
package/dist/config-command.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import { type Setting } from "./config-edit.ts";
|
|
2
3
|
/**
|
|
3
4
|
* `/turri-config`: every setting of the project's config.turri.yaml from the chat - `/turri-config` alone lists them,
|
|
4
5
|
* `/turri-config review` asks for review's value, `/turri-config review false` sets it. Each is written into the file
|
|
@@ -23,4 +24,17 @@ export interface TurriConfigOptions {
|
|
|
23
24
|
chatSpec: () => string | undefined;
|
|
24
25
|
live: LiveHooks;
|
|
25
26
|
}
|
|
27
|
+
/** The models pi can reach here, signed in: provider/id - from a chat's context, the model registry the chats use. */
|
|
28
|
+
export declare function reachable(ctx: ExtensionContext | undefined): string[];
|
|
29
|
+
/**
|
|
30
|
+
* Every value /turri-config offers for a setting after what is typed, in its order - "unset" left out, and uncapped: what
|
|
31
|
+
* its completions show, the first of them, and what a host's settings list shows (host-session.ts `settingChoices`).
|
|
32
|
+
* A model setting's are every model pi can reach, signed in - `models` - and after a colon, that model's thinking levels.
|
|
33
|
+
*/
|
|
34
|
+
export declare function settingCandidates(setting: Setting, typed: string, where: {
|
|
35
|
+
cwd: string;
|
|
36
|
+
models: () => string[];
|
|
37
|
+
}): string[];
|
|
38
|
+
/** The ***plain rules there are, by name - what rules-off takes, and its values. */
|
|
39
|
+
export declare function ruleNames(): string[];
|
|
26
40
|
export declare function registerTurriConfig(pi: ExtensionAPI, options: TurriConfigOptions): void;
|
package/dist/config-command.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { applyBedrockRegion } from "./bedrock-region.js";
|
|
1
3
|
import { CONFIG_FILE, LEGACY_CONFIG_FILE, THINKING_LEVELS, usesLegacyConfig } from "./config.js";
|
|
2
4
|
import { currentValue, dotenvFiles, EFFECT_TEXT, overriddenBy, parseValue, pathOptions, readConfigText, settingOf, settings, shownValue, writeSetting, } from "./config-edit.js";
|
|
5
|
+
import { PACKAGE_ROOT } from "./environment.js";
|
|
6
|
+
import { loadRules } from "./rules.js";
|
|
3
7
|
/** The option that unsets a setting, for a setting. */
|
|
4
8
|
const unsetOption = (setting) => `unset - ${setting.unset}`;
|
|
5
9
|
const TYPE_ANOTHER = "type another…";
|
|
6
10
|
const DONE = "done";
|
|
7
11
|
const ROLES_ENTRY = "models.<role> - each agent role's own model, thinking and turn limit…";
|
|
8
|
-
/** The models pi can reach here, signed in: provider/id. */
|
|
9
|
-
function reachable(ctx) {
|
|
12
|
+
/** The models pi can reach here, signed in: provider/id - from a chat's context, the model registry the chats use. */
|
|
13
|
+
export function reachable(ctx) {
|
|
10
14
|
try {
|
|
11
15
|
return (ctx?.modelRegistry.getAvailable() ?? []).map((model) => `${model.provider}/${model.id}`).sort();
|
|
12
16
|
}
|
|
@@ -14,6 +18,31 @@ function reachable(ctx) {
|
|
|
14
18
|
return [];
|
|
15
19
|
}
|
|
16
20
|
}
|
|
21
|
+
/** How many values the terminal's autocomplete shows for a setting: a host reads them whole (`settingCandidates`). */
|
|
22
|
+
const COMPLETIONS_SHOWN = 40;
|
|
23
|
+
/**
|
|
24
|
+
* Every value /turri-config offers for a setting after what is typed, in its order - "unset" left out, and uncapped: what
|
|
25
|
+
* its completions show, the first of them, and what a host's settings list shows (host-session.ts `settingChoices`).
|
|
26
|
+
* A model setting's are every model pi can reach, signed in - `models` - and after a colon, that model's thinking levels.
|
|
27
|
+
*/
|
|
28
|
+
export function settingCandidates(setting, typed, where) {
|
|
29
|
+
const candidates = setting.kind === "boolean"
|
|
30
|
+
? ["true", "false"]
|
|
31
|
+
: setting.kind === "model"
|
|
32
|
+
? typed.includes(":")
|
|
33
|
+
? THINKING_LEVELS.map((level) => `${typed.slice(0, typed.lastIndexOf(":"))}:${level}`)
|
|
34
|
+
: where.models()
|
|
35
|
+
: setting.kind === "path"
|
|
36
|
+
? pathOptions(where.cwd, setting.key)
|
|
37
|
+
: setting.key === "agent-env.files"
|
|
38
|
+
? dotenvFiles(where.cwd)
|
|
39
|
+
: (setting.options ?? []);
|
|
40
|
+
return candidates.filter((candidate) => candidate.startsWith(typed));
|
|
41
|
+
}
|
|
42
|
+
/** The ***plain rules there are, by name - what rules-off takes, and its values. */
|
|
43
|
+
export function ruleNames() {
|
|
44
|
+
return loadRules(join(PACKAGE_ROOT, "genome", "rules")).map((rule) => rule.name);
|
|
45
|
+
}
|
|
17
46
|
/** A setting's line in the list: its key, what it is now - or what it is unset - and what it does. */
|
|
18
47
|
function listLine(setting, text) {
|
|
19
48
|
const value = currentValue(text, setting.key);
|
|
@@ -39,6 +68,9 @@ export function registerTurriConfig(pi, options) {
|
|
|
39
68
|
const adopting = usesLegacyConfig(cwd);
|
|
40
69
|
const text = writeSetting(cwd, setting.key, value);
|
|
41
70
|
const notes = [];
|
|
71
|
+
// A model changed: the AWS region its Bedrock models need is worked out again - set, moved or taken back by turri.
|
|
72
|
+
if (setting.key.endsWith("-model") || setting.key.startsWith("models."))
|
|
73
|
+
applyBedrockRegion(cwd);
|
|
42
74
|
// What turri fixed at its start, changed now.
|
|
43
75
|
if (setting.key === "harness-model" || setting.key === "models.chat") {
|
|
44
76
|
const said = await options.live.chatModel(options.chatSpec(), ctx);
|
|
@@ -83,7 +115,6 @@ export function registerTurriConfig(pi, options) {
|
|
|
83
115
|
case "choice":
|
|
84
116
|
return pick(setting.options ?? [], false);
|
|
85
117
|
case "number":
|
|
86
|
-
case "budget":
|
|
87
118
|
return pick(setting.options ?? []);
|
|
88
119
|
case "path":
|
|
89
120
|
return pick(pathOptions(cwd, setting.key));
|
|
@@ -182,18 +213,7 @@ export function registerTurriConfig(pi, options) {
|
|
|
182
213
|
if (setting === undefined)
|
|
183
214
|
return null;
|
|
184
215
|
const typed = prefix.slice(space + 1).trimStart();
|
|
185
|
-
const
|
|
186
|
-
? ["true", "false"]
|
|
187
|
-
: setting.kind === "model"
|
|
188
|
-
? typed.includes(":")
|
|
189
|
-
? THINKING_LEVELS.map((level) => `${typed.slice(0, typed.lastIndexOf(":"))}:${level}`)
|
|
190
|
-
: reachable(seen)
|
|
191
|
-
: setting.kind === "path"
|
|
192
|
-
? pathOptions(cwd, setting.key)
|
|
193
|
-
: setting.key === "agent-env.files"
|
|
194
|
-
? dotenvFiles(cwd)
|
|
195
|
-
: (setting.options ?? []);
|
|
196
|
-
const items = [...candidates, "unset"].filter((candidate) => candidate.startsWith(typed)).slice(0, 40);
|
|
216
|
+
const items = [...settingCandidates(setting, typed, { cwd, models: () => reachable(seen) }), ...("unset".startsWith(typed) ? ["unset"] : [])].slice(0, COMPLETIONS_SHOWN);
|
|
197
217
|
return items.length === 0 ? null : items.map((candidate) => ({ value: `${setting.key} ${candidate}`, label: candidate }));
|
|
198
218
|
},
|
|
199
219
|
handler: async (args, ctx) => {
|
package/dist/config-edit.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
/** When a change takes effect. Nothing turri reads needs a restart: what is fixed at its start is changed live. */
|
|
8
8
|
export type Effect = "now" | "next-message" | "next-pulse" | "next-plan" | "next-test-run" | "next-landing" | "next-regenerate" | "next-start";
|
|
9
|
-
export type SettingKind = "boolean" | "choice" | "number" | "model" | "list" | "path"
|
|
9
|
+
export type SettingKind = "boolean" | "choice" | "number" | "model" | "list" | "path";
|
|
10
10
|
export interface Setting {
|
|
11
11
|
/** As written in the file - a nested one by its path: `models.coding`, `models.coding.turn-limit`, `agent-env.files`. */
|
|
12
12
|
key: string;
|
|
@@ -16,7 +16,7 @@ export interface Setting {
|
|
|
16
16
|
/** What it is when it is not set. */
|
|
17
17
|
unset: string;
|
|
18
18
|
effect: Effect;
|
|
19
|
-
/** The words it takes (choice), or the values offered first (number,
|
|
19
|
+
/** The words it takes (choice), or the values offered first (number, list). */
|
|
20
20
|
options?: string[];
|
|
21
21
|
/** The least a number may be. */
|
|
22
22
|
min?: number;
|
|
@@ -65,7 +65,7 @@ export declare function overriddenBy(dir: string, text: string, setting: Setting
|
|
|
65
65
|
* file in the old naming when they are what the project is read from - and give back the file as written.
|
|
66
66
|
*/
|
|
67
67
|
export declare function writeSetting(dir: string, key: string, value: unknown): string;
|
|
68
|
-
/** The files a path setting is offered: the testing scripts in the root and test_scripts/,
|
|
68
|
+
/** The files a path setting is offered: the testing scripts in the root and test_scripts/, the .plain files of the folder, or - the test folder - its folders. */
|
|
69
69
|
export declare function pathOptions(dir: string, key: string): string[];
|
|
70
70
|
/** The dotenv files of the project root, for agent-env.files. */
|
|
71
71
|
export declare function dotenvFiles(dir: string): string[];
|