@turri-dev/cli 0.1.6-next.336dd6e → 0.1.7-next.9aec40e
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/.pi/themes/turri-dark.json +1 -1
- package/README.md +1 -1
- package/dist/ask.d.ts +83 -0
- package/dist/brand.d.ts +13 -0
- package/dist/btw.d.ts +67 -0
- package/dist/chat-models.d.ts +22 -0
- package/dist/chat-skills.d.ts +17 -0
- package/dist/cli-options.d.ts +25 -0
- package/dist/cli.d.ts +9 -0
- package/dist/cli.js +7 -1
- package/dist/config-command.d.ts +26 -0
- package/dist/config-edit.d.ts +69 -0
- package/dist/config.d.ts +321 -0
- package/dist/conform-cli.d.ts +1 -0
- package/dist/cultivate-cli.d.ts +1 -0
- package/dist/drift-cli.d.ts +1 -0
- package/dist/environment.d.ts +39 -0
- package/dist/environment.js +26 -0
- package/dist/extension.d.ts +147 -0
- package/dist/extension.js +36 -10
- package/dist/genome.d.ts +62 -0
- package/dist/graph.d.ts +52 -0
- package/dist/host.d.ts +20 -0
- package/dist/host.js +23 -0
- package/dist/identity.d.ts +2 -0
- package/dist/init-config.d.ts +106 -0
- package/dist/jellyfish.d.ts +25 -0
- package/dist/judge.d.ts +25 -0
- package/dist/lineage-cli.d.ts +1 -0
- package/dist/loop-cli.d.ts +34 -0
- package/dist/loop-tools.d.ts +80 -0
- package/dist/mature-tools.d.ts +53 -0
- package/dist/model-check.d.ts +42 -0
- package/dist/module-report.d.ts +9 -0
- package/dist/pi-launch.d.ts +1 -0
- package/dist/pi.d.ts +246 -0
- package/dist/picture-row.d.ts +10 -0
- package/dist/plain/check.d.ts +23 -0
- package/dist/plain/concepts.d.ts +11 -0
- package/dist/plain/errors.d.ts +22 -0
- package/dist/plain/files.d.ts +12 -0
- package/dist/plain/highlight.d.ts +42 -0
- package/dist/plain/index.d.ts +15 -0
- package/dist/plain/liquid.d.ts +22 -0
- package/dist/plain/markdown.d.ts +74 -0
- package/dist/plain/parser.d.ts +87 -0
- package/dist/plain/spec.d.ts +90 -0
- package/dist/plain/stdlib.d.ts +14 -0
- package/dist/question-dialog.d.ts +51 -0
- package/dist/questioning.d.ts +55 -0
- package/dist/quiet.d.ts +34 -0
- package/dist/regenerate/activity.d.ts +207 -0
- package/dist/regenerate/agent-env.d.ts +44 -0
- package/dist/regenerate/agent-shell.d.ts +49 -0
- package/dist/regenerate/arbiter.d.ts +68 -0
- package/dist/regenerate/audit.d.ts +69 -0
- package/dist/regenerate/cases.d.ts +9 -0
- package/dist/regenerate/change-view.d.ts +18 -0
- package/dist/regenerate/choose-conformance.d.ts +32 -0
- package/dist/regenerate/chunk-plan.d.ts +164 -0
- package/dist/regenerate/codebase.d.ts +21 -0
- package/dist/regenerate/command-check.d.ts +40 -0
- package/dist/regenerate/compaction.d.ts +13 -0
- package/dist/regenerate/confine.d.ts +62 -0
- package/dist/regenerate/conform.d.ts +63 -0
- package/dist/regenerate/conformance-agents.d.ts +405 -0
- package/dist/regenerate/conformance.d.ts +189 -0
- package/dist/regenerate/conversation-writes.d.ts +10 -0
- package/dist/regenerate/credentials.d.ts +18 -0
- package/dist/regenerate/debug-log.d.ts +54 -0
- package/dist/regenerate/debugger.d.ts +31 -0
- package/dist/regenerate/delivery.d.ts +6 -0
- package/dist/regenerate/diagnose-job.d.ts +2 -0
- package/dist/regenerate/diagnose.d.ts +46 -0
- package/dist/regenerate/diff-view.d.ts +61 -0
- package/dist/regenerate/drift.d.ts +84 -0
- package/dist/regenerate/engine.d.ts +52 -0
- package/dist/regenerate/environment-error.d.ts +136 -0
- package/dist/regenerate/job-log.d.ts +28 -0
- package/dist/regenerate/job-panel.d.ts +122 -0
- package/dist/regenerate/jobs-tree.d.ts +71 -0
- package/dist/regenerate/jobs.d.ts +186 -0
- package/dist/regenerate/lanes.d.ts +16 -0
- package/dist/regenerate/lineage.d.ts +95 -0
- package/dist/regenerate/list-arguments.d.ts +21 -0
- package/dist/regenerate/loop.d.ts +392 -0
- package/dist/regenerate/masking.d.ts +19 -0
- package/dist/regenerate/notes.d.ts +159 -0
- package/dist/regenerate/os-sandbox.d.ts +89 -0
- package/dist/regenerate/panel-dock.d.ts +23 -0
- package/dist/regenerate/paths.d.ts +92 -0
- package/dist/regenerate/plain-palette.d.ts +34 -0
- package/dist/regenerate/prompt.d.ts +192 -0
- package/dist/regenerate/records.d.ts +88 -0
- package/dist/regenerate/regenerate.d.ts +108 -0
- package/dist/regenerate/regression.d.ts +58 -0
- package/dist/regenerate/release.d.ts +123 -0
- package/dist/regenerate/requires.d.ts +96 -0
- package/dist/regenerate/resources.d.ts +53 -0
- package/dist/regenerate/self-check.d.ts +29 -0
- package/dist/regenerate/services.d.ts +28 -0
- package/dist/regenerate/shell.d.ts +91 -0
- package/dist/regenerate/side-panel.d.ts +57 -0
- package/dist/regenerate/spec-map-view.d.ts +139 -0
- package/dist/regenerate/spec-map.d.ts +138 -0
- package/dist/regenerate/spec-steps.d.ts +137 -0
- package/dist/regenerate/state.d.ts +20 -0
- package/dist/regenerate/steer.d.ts +34 -0
- package/dist/regenerate/steering.d.ts +56 -0
- package/dist/regenerate/stop-report.d.ts +43 -0
- package/dist/regenerate/submit-work.d.ts +42 -0
- package/dist/regenerate/test-kinds.d.ts +42 -0
- package/dist/regenerate/test-scripts.d.ts +221 -0
- package/dist/regenerate/testing.d.ts +141 -0
- package/dist/regenerate/transcript-view.d.ts +21 -0
- package/dist/regenerate/unit-gate.d.ts +27 -0
- package/dist/regenerate/unit-review.d.ts +152 -0
- package/dist/regenerate/web.d.ts +61 -0
- package/dist/regenerate/workspace.d.ts +12 -0
- package/dist/regenerate-cli.d.ts +1 -0
- package/dist/release-agent.d.ts +26 -0
- package/dist/release-cli.d.ts +1 -0
- package/dist/release-tools.d.ts +38 -0
- package/dist/resume-line.d.ts +2 -0
- package/dist/review/live.d.ts +72 -0
- package/dist/rules.d.ts +20 -0
- package/dist/run-report.d.ts +88 -0
- package/dist/screen-padding.d.ts +28 -0
- package/dist/self-invocation.d.ts +25 -0
- package/dist/setup.d.ts +43 -0
- package/dist/skill-progress.d.ts +46 -0
- package/dist/skill.d.ts +98 -0
- package/dist/skills.d.ts +30 -0
- package/dist/spec-diff-cli.d.ts +1 -0
- package/dist/spec-tools.d.ts +36 -0
- package/dist/stack.d.ts +58 -0
- package/dist/stacks.d.ts +12 -0
- package/dist/stdlib.d.ts +27 -0
- package/dist/terminal-images.d.ts +2 -0
- package/dist/tools.d.ts +101 -0
- package/dist/validate-cli.d.ts +1 -0
- package/docs/README.md +2 -0
- package/docs/hosting.md +51 -0
- package/docs/installation.md +1 -1
- package/docs/theming.md +2 -2
- package/package.json +8 -1
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type ScriptRun } from "./test-scripts.ts";
|
|
2
|
+
export interface DebugInput {
|
|
3
|
+
/** The codebase: what it reads. */
|
|
4
|
+
buildDir: string;
|
|
5
|
+
/** The failing run, as the harness saw it. */
|
|
6
|
+
failure: string;
|
|
7
|
+
/** How many times in a row it has failed this way. */
|
|
8
|
+
times: number;
|
|
9
|
+
/** What the change is meant to do: the spec as the coding agent has it. */
|
|
10
|
+
task: string;
|
|
11
|
+
/** The testing script that decides pass or fail, with its path: how the tests are run, and where. */
|
|
12
|
+
script?: string;
|
|
13
|
+
/** How the failing run ended against its time limit: how long it took, and whether the limit stopped it. */
|
|
14
|
+
run?: Pick<ScriptRun, "exitCode" | "timedOut" | "timeoutMs" | "elapsedMs">;
|
|
15
|
+
label: string;
|
|
16
|
+
model?: string;
|
|
17
|
+
onDelta?: (delta: string) => void;
|
|
18
|
+
}
|
|
19
|
+
export interface Diagnosis {
|
|
20
|
+
rootCause: string;
|
|
21
|
+
fix: string;
|
|
22
|
+
/**
|
|
23
|
+
* The run the time limit stopped hangs on nothing: it was making progress up to the limit and needs more time than a
|
|
24
|
+
* test run may take - which no agent can give it. Taken only of a run the limit stopped.
|
|
25
|
+
*/
|
|
26
|
+
tooSlow?: boolean;
|
|
27
|
+
}
|
|
28
|
+
/** The debugger's account, as the coding agent is given it. */
|
|
29
|
+
export declare function diagnosisText(diagnosis: Diagnosis): string;
|
|
30
|
+
/** Have a fresh agent find why the unit tests keep failing the same way: its root cause and fix, or undefined when it found none. */
|
|
31
|
+
export declare function debugFailure(input: DebugInput): Promise<Diagnosis | undefined>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** What every job that lands code ends with: the person can try it now, by asking. */
|
|
2
|
+
export declare const TRY_IT_LINE = "Want to try it? Just ask me - I'll set it up from what's built so far.";
|
|
3
|
+
/** The same for a command-line run, which has no one to ask: the command that does it. */
|
|
4
|
+
export declare function tryItCommand(plainFile: string): string;
|
|
5
|
+
/** A job's report, ending with how to try what it built when it landed. */
|
|
6
|
+
export declare function withTryItLine(report: string, landed: boolean): string;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Why a job failed twice, and what has to be done about it - worked out by an agent that can read
|
|
3
|
+
* everything the job depended on: the project's specs, code, tests and testing scripts, the job's
|
|
4
|
+
* log and its agents' logs, and turri itself - its source, its skills and its rules. Read only.
|
|
5
|
+
*
|
|
6
|
+
* A job is retried once; failing again, it and every job queued behind it fail, and this is what the
|
|
7
|
+
* person is told: not the last stage it reached, but the cause, and whose it is to fix.
|
|
8
|
+
*/
|
|
9
|
+
export interface Diagnosis {
|
|
10
|
+
whatHappened: string;
|
|
11
|
+
cause: string;
|
|
12
|
+
/** Where the fix belongs: the spec, the environment, the code, or turri itself. */
|
|
13
|
+
whose: "spec" | "environment" | "code" | "harness";
|
|
14
|
+
todo: string[];
|
|
15
|
+
}
|
|
16
|
+
/** How many tool calls the diagnosis may make before it is told to decide. */
|
|
17
|
+
export declare const DIAGNOSIS_CALLS = 40;
|
|
18
|
+
export declare function describeDiagnosis(diagnosis: Diagnosis): string;
|
|
19
|
+
export declare function diagnoseFailure(options: {
|
|
20
|
+
/** The job, as it is listed: its kind and what it was asked to do. */
|
|
21
|
+
job: {
|
|
22
|
+
id: string;
|
|
23
|
+
kind: string;
|
|
24
|
+
summary: string;
|
|
25
|
+
};
|
|
26
|
+
/** What each attempt ended with - its report or its error. */
|
|
27
|
+
failures: string[];
|
|
28
|
+
/** The project: its specs, config, testing scripts and plain_modules. */
|
|
29
|
+
projectDir: string;
|
|
30
|
+
/** turri's own folder: its source, skills, rules and docs. */
|
|
31
|
+
harnessDir: string;
|
|
32
|
+
/** The job's own log, when it has one. */
|
|
33
|
+
jobLog?: string;
|
|
34
|
+
model?: string;
|
|
35
|
+
}): Promise<Diagnosis | undefined>;
|
|
36
|
+
export declare function diagnosisPrompt(options: {
|
|
37
|
+
job: {
|
|
38
|
+
id: string;
|
|
39
|
+
kind: string;
|
|
40
|
+
summary: string;
|
|
41
|
+
};
|
|
42
|
+
failures: string[];
|
|
43
|
+
projectDir: string;
|
|
44
|
+
harnessDir: string;
|
|
45
|
+
jobLog?: string;
|
|
46
|
+
}): string;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { type PlainRole } from "../plain/highlight.ts";
|
|
2
|
+
/**
|
|
3
|
+
* A spec diff as the panels show it: each line's ***plain highlighted as plyn highlights it
|
|
4
|
+
* (`plain/highlight.ts`), an added line on a green band and a removed one on a red, the band the width
|
|
5
|
+
* of the panel - as an editor shows a diff. Each file is named once, quietly, above its hunks - not
|
|
6
|
+
* git's headers - and a hunk header is a quiet rule between hunks.
|
|
7
|
+
*/
|
|
8
|
+
/** How a diff is painted: ***plain's colours, and the fills of added and removed lines (`plain-palette.ts`). */
|
|
9
|
+
export interface DiffPaint {
|
|
10
|
+
/** A piece of ***plain, by what it is. */
|
|
11
|
+
syntax(role: PlainRole, text: string): string;
|
|
12
|
+
/** The +/- in front of an added or removed line. */
|
|
13
|
+
added(text: string): string;
|
|
14
|
+
removed(text: string): string;
|
|
15
|
+
/** A whole added or removed row, padded to the width: its band. */
|
|
16
|
+
addedBand(text: string): string;
|
|
17
|
+
removedBand(text: string): string;
|
|
18
|
+
muted(text: string): string;
|
|
19
|
+
}
|
|
20
|
+
/** Painted with nothing: the text as it is, for where there are no colours. */
|
|
21
|
+
export declare const PLAIN_PAINT: DiffPaint;
|
|
22
|
+
/**
|
|
23
|
+
* Where the lines of a diff are in the .plain files: by a line's place in the diff, the file it is in and its
|
|
24
|
+
* line there. Only lines that are in a file - added and unchanged ones; a removed line is in none now.
|
|
25
|
+
*/
|
|
26
|
+
export type DiffWhere = Record<number, {
|
|
27
|
+
file: string;
|
|
28
|
+
line: number;
|
|
29
|
+
section?: string;
|
|
30
|
+
}>;
|
|
31
|
+
/**
|
|
32
|
+
* Place a spec diff's lines in the .plain files they come from - `files`, the module's and every one it
|
|
33
|
+
* reads, named as they are to be shown. A spec diff is of the spec as read, the files it imports laid into
|
|
34
|
+
* it, so its own line numbers are not the file's: each line is found where it is written, the file a line
|
|
35
|
+
* before it was found in first, from there on, and each place once.
|
|
36
|
+
*/
|
|
37
|
+
export declare function locateDiffLines(diff: string, files: Array<{
|
|
38
|
+
name: string;
|
|
39
|
+
text: string;
|
|
40
|
+
}>): DiffWhere;
|
|
41
|
+
/** A file's part of a spec diff, as the panels show it: its name, what it adds and takes out, and its rows. */
|
|
42
|
+
export interface DiffFile {
|
|
43
|
+
file: string;
|
|
44
|
+
added: number;
|
|
45
|
+
removed: number;
|
|
46
|
+
rows: string[];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* A spec diff, file by file: each file's lines together, however the diff has them - a spec diff is of the
|
|
50
|
+
* spec as read, so what one file holds can come in more than one place - the file being rendered first,
|
|
51
|
+
* the rest by name. Each line is in the file it is placed in (`where`); a line placed nowhere - a removed
|
|
52
|
+
* one, or one written other than it reads - goes with the line placed before it, else the one after it,
|
|
53
|
+
* else the file the diff's own header names. The file being rendered is the one the diff's header names.
|
|
54
|
+
*/
|
|
55
|
+
export declare function diffFiles(diff: string, width: number, paint?: DiffPaint, where?: DiffWhere): DiffFile[];
|
|
56
|
+
/** A file's header: its name, and what it adds and takes out. `open`, with the mark of a group that opens and closes. */
|
|
57
|
+
export declare function fileHeader(file: DiffFile, paint: DiffPaint, open?: boolean): string;
|
|
58
|
+
/** Where a spec diff's lines go that are in none of the spec's files as they are written. */
|
|
59
|
+
export declare const NOT_FOUND = "not found in the spec's files";
|
|
60
|
+
/** The diff's lines, at most `width` wide: every file, each under its header - for a view that opens none and closes none. */
|
|
61
|
+
export declare function diffView(diff: string, width: number, paint?: DiffPaint, where?: DiffWhere): string[];
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { type MarshalledPlainSource } from "../plain/spec.ts";
|
|
2
|
+
import { type Chosen } from "./records.ts";
|
|
3
|
+
import { type SpecChange } from "./spec-steps.ts";
|
|
4
|
+
/**
|
|
5
|
+
* The work, derived from the records - see docs/regenerating.md. Nothing here is stored: what is left
|
|
6
|
+
* to build is the difference between what a record says is built and what the spec says now, worked
|
|
7
|
+
* out again whenever either changes.
|
|
8
|
+
*
|
|
9
|
+
* - Code work: from the code record to the spec as the code sees it.
|
|
10
|
+
* - Conformance work: from the tests record to what the conformance tests are to be written for now -
|
|
11
|
+
* the chosen functional specs the code is built from.
|
|
12
|
+
*
|
|
13
|
+
* A job is a set of those changes. What it tells its agents follows from the functional specs it
|
|
14
|
+
* touches - its cases - and a running job is stopped once the spec no longer wants what it makes.
|
|
15
|
+
*/
|
|
16
|
+
/** Everything left to build in the code: from what the code record says it is built from, to the spec now. */
|
|
17
|
+
export declare function codeWork(record: MarshalledPlainSource | null, spec: MarshalledPlainSource): SpecChange[];
|
|
18
|
+
/** Everything left to do in the conformance tests: from what the tests record says they are written for, to what they are to be now. */
|
|
19
|
+
export declare function conformanceWork(tests: MarshalledPlainSource | null, code: MarshalledPlainSource | null, spec: MarshalledPlainSource, chosen?: Chosen): SpecChange[];
|
|
20
|
+
/**
|
|
21
|
+
* A functional spec a job touches: its number - in the spec after the job, or, taken out, before it - its first line,
|
|
22
|
+
* and the module it belongs to: each module numbers its own from 1, so a number alone can mean two.
|
|
23
|
+
*/
|
|
24
|
+
export interface TouchedSpec {
|
|
25
|
+
frid: string;
|
|
26
|
+
text: string;
|
|
27
|
+
module?: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* What a job does to the functional specs, and so what its agents are told:
|
|
31
|
+
*
|
|
32
|
+
* - fresh: the module requires none and nothing is built - the project is set up first.
|
|
33
|
+
* - add: functional specs that are new.
|
|
34
|
+
* - patch: functional specs changed - their text, their acceptance tests, or a concept they use: a
|
|
35
|
+
* change to what is built, never built again from scratch.
|
|
36
|
+
* - again: functional specs marked to regenerate again (`regenerate` with functionalities named): their code is built, and is regenerated again - rewritten
|
|
37
|
+
* or started over, doing what the spec says now - with what it replaces taken out. A functional spec of a module
|
|
38
|
+
* this one requires, regenerated again here, is one too.
|
|
39
|
+
* - delete: functional specs taken out.
|
|
40
|
+
* - mechanical: none of those - only reqs, or definitions no functional spec uses. Existing tests may
|
|
41
|
+
* change only mechanically, and no new ones are written.
|
|
42
|
+
*
|
|
43
|
+
* A job can hold several of add, patch and delete at once: its prompt has a section for each.
|
|
44
|
+
*/
|
|
45
|
+
export interface JobCases {
|
|
46
|
+
fresh: boolean;
|
|
47
|
+
add: TouchedSpec[];
|
|
48
|
+
patch: TouchedSpec[];
|
|
49
|
+
again: TouchedSpec[];
|
|
50
|
+
delete: TouchedSpec[];
|
|
51
|
+
mechanical: boolean;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Every concept a functional spec uses: those its text names, and those their definitions name in
|
|
55
|
+
* turn, as far as it goes.
|
|
56
|
+
*/
|
|
57
|
+
export declare function conceptsUsed(markdown: string, definitions: Array<{
|
|
58
|
+
markdown: string;
|
|
59
|
+
}>): Set<string>;
|
|
60
|
+
/**
|
|
61
|
+
* The cases of a job: `before` is the tree it starts from - the record, or what the jobs ahead of it
|
|
62
|
+
* leave - and `changes` the changes it makes, found from `before`. `fresh`: the module requires none
|
|
63
|
+
* and nothing is built.
|
|
64
|
+
*
|
|
65
|
+
* A functional spec is patched when its item changed, or when a concept it uses - as the spec after
|
|
66
|
+
* the job defines it, or as it was defined before - is defined anew, changed or taken out by the job.
|
|
67
|
+
* `module`: the module whose codebase it is - its own functional specs are that module's.
|
|
68
|
+
*/
|
|
69
|
+
export declare function casesOf(before: MarshalledPlainSource, changes: SpecChange[], options?: {
|
|
70
|
+
fresh?: boolean;
|
|
71
|
+
module?: string;
|
|
72
|
+
}): JobCases;
|
|
73
|
+
/**
|
|
74
|
+
* Whether a running job may finish: every change it makes is still part of the work as it is now -
|
|
75
|
+
* both measured from the same record, which nothing changes while the job runs. When one is not, the
|
|
76
|
+
* job is making something the spec no longer wants, and it is stopped and rolled back.
|
|
77
|
+
*/
|
|
78
|
+
/**
|
|
79
|
+
* Why a running job is no longer wanted, in a line: the files it links that hold something else now - the commonest
|
|
80
|
+
* cause, a resource edited while the job regenerated from it - else the items whose text changed under it, by section
|
|
81
|
+
* and place.
|
|
82
|
+
*/
|
|
83
|
+
export declare function whyNotWanted(running: SpecChange[], work: SpecChange[]): string;
|
|
84
|
+
export declare function stillWanted(running: SpecChange[], work: SpecChange[]): boolean;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which model the agents of a job run on.
|
|
3
|
+
*
|
|
4
|
+
* By default, whatever the conversation is using. The person can say otherwise - "render spec
|
|
5
|
+
* changes with Gemini Flash" - for one kind of work or for all of it, and that holds for the
|
|
6
|
+
* rest of the session, for jobs started from a tool call and for jobs a skill queues alike. A
|
|
7
|
+
* single tool call can also name a model for itself alone.
|
|
8
|
+
*
|
|
9
|
+
* A name is resolved strictly. pi's own pattern matching picks its best guess and says nothing
|
|
10
|
+
* - "gpt-5" becomes a Bedrock model with no credentials, "flash" a GLM one - and a job on a
|
|
11
|
+
* guessed model is worse than a question. So an exact id is taken as it is, a looser name is
|
|
12
|
+
* taken only when it fits exactly one model that has credentials, and anything else comes back
|
|
13
|
+
* as a short list to ask the person about.
|
|
14
|
+
*/
|
|
15
|
+
/** The part of pi's model registry this needs. */
|
|
16
|
+
export interface ModelCatalog {
|
|
17
|
+
getAll(): ReadonlyArray<CatalogModel>;
|
|
18
|
+
hasConfiguredAuth(model: CatalogModel): boolean;
|
|
19
|
+
}
|
|
20
|
+
export interface CatalogModel {
|
|
21
|
+
provider: string;
|
|
22
|
+
id: string;
|
|
23
|
+
name?: string;
|
|
24
|
+
}
|
|
25
|
+
export type ModelResolution = {
|
|
26
|
+
ok: true;
|
|
27
|
+
model: string;
|
|
28
|
+
name: string;
|
|
29
|
+
} | {
|
|
30
|
+
ok: false;
|
|
31
|
+
message: string;
|
|
32
|
+
candidates: string[];
|
|
33
|
+
};
|
|
34
|
+
/** Resolve what the person called a model to one this machine can run, or say why not. */
|
|
35
|
+
export declare function resolveModel(query: string, catalog: ModelCatalog): ModelResolution;
|
|
36
|
+
/** The resolution as text for the agent: the model, or why not and what to ask. */
|
|
37
|
+
export declare function describeResolution(resolution: ModelResolution): string;
|
|
38
|
+
/** Kinds of work a model can be chosen for. */
|
|
39
|
+
export type RenderWork = "spec_changes" | "functionalities";
|
|
40
|
+
export declare const WORK_LABEL: Record<RenderWork | "all", string>;
|
|
41
|
+
/** The models chosen in this session, by kind of work. Unset: the project's, or the conversation's model. */
|
|
42
|
+
export type ModelChoices = Partial<Record<RenderWork | "all", string>>;
|
|
43
|
+
/** The model a job of this kind runs on: chosen for it, chosen for everything, or the chat's. */
|
|
44
|
+
export declare function modelFor(choices: ModelChoices, work: RenderWork, chat: string | undefined): string | undefined;
|
|
45
|
+
/**
|
|
46
|
+
* Where each kind of work runs now, in a line each: chosen in this session, or the default coding
|
|
47
|
+
* model - from `--coding-model` or config.turri.yaml, said which - or the conversation's.
|
|
48
|
+
*/
|
|
49
|
+
export declare function describeChoices(choices: ModelChoices, chat: string | undefined, project?: {
|
|
50
|
+
model: string;
|
|
51
|
+
from: string;
|
|
52
|
+
}): string;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { type ToolDefinition } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
/**
|
|
3
|
+
* When the machine lacks what the work needs - a toolchain, a system library, a credential - no agent can fix it, and
|
|
4
|
+
* none tries: the pulse stops and is rolled back, the module's later pulses wait, and the person is told what is
|
|
5
|
+
* missing, how to fix it, and how to run it again. Raised two ways: an agent calls `report_environment_error`, which
|
|
6
|
+
* ends its turn - its reason goes to the person as it is; or the harness finds it itself - a testing script that cannot
|
|
7
|
+
* find its toolchain, a credential `agent-env:` names that is not there - and works out at once what to do about it.
|
|
8
|
+
*/
|
|
9
|
+
export declare class EnvironmentError extends Error {
|
|
10
|
+
/** The module whose pulse stopped. */
|
|
11
|
+
readonly moduleName: string;
|
|
12
|
+
/** What the environment lacks. */
|
|
13
|
+
readonly missing: string;
|
|
14
|
+
/** What needs it. */
|
|
15
|
+
readonly neededBy: string;
|
|
16
|
+
/** What showed it: the command, the output. */
|
|
17
|
+
readonly shownBy?: string;
|
|
18
|
+
/** How to fix it, when it is known. */
|
|
19
|
+
fix?: string;
|
|
20
|
+
/** Who found it: an agent, or the harness. */
|
|
21
|
+
readonly source: "agent" | "harness";
|
|
22
|
+
/**
|
|
23
|
+
* Nothing is missing: what the agent could not reach is on this machine, and turri's own sandbox kept it from it - the
|
|
24
|
+
* files it named, and the toolchain folder that holds them, for `toolchains:` to let the agents read.
|
|
25
|
+
*/
|
|
26
|
+
readonly sandbox?: SandboxGap;
|
|
27
|
+
constructor(details: {
|
|
28
|
+
moduleName: string;
|
|
29
|
+
missing: string;
|
|
30
|
+
neededBy: string;
|
|
31
|
+
shownBy?: string;
|
|
32
|
+
fix?: string;
|
|
33
|
+
source: "agent" | "harness";
|
|
34
|
+
sandbox?: SandboxGap;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/** Files on this machine turri's sandbox kept an agent from, and the toolchain folder that holds them. */
|
|
38
|
+
export interface SandboxGap {
|
|
39
|
+
paths: string[];
|
|
40
|
+
folder: string;
|
|
41
|
+
/**
|
|
42
|
+
* What the sandbox refused: reading - a toolchain outside what it lets the agents read, which `toolchains:` fixes - or
|
|
43
|
+
* writing, which no line of config allows: a lock file a build tool takes as it runs, a cache it fills.
|
|
44
|
+
*/
|
|
45
|
+
access: "read" | "write";
|
|
46
|
+
/** The first path is a lock file - `gradle.lock`, `bin/cache/lockfile`, `*.lck`. */
|
|
47
|
+
lock?: boolean;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* What an agent reported the machine lacks, read for what it says of turri's own sandbox: a file it names that is on
|
|
51
|
+
* this machine - outside the project and the system's folders, which the sandbox already lets it read - is not missing,
|
|
52
|
+
* the sandbox hid it. A version manager's Node under ~/.local/share/mise, say, whose npm the agent could not open. Then
|
|
53
|
+
* the stop is the sandbox's, and the fix is a line of config - `toolchains:` - not an install.
|
|
54
|
+
*/
|
|
55
|
+
export declare function sandboxGapOf(text: string, options?: {
|
|
56
|
+
project?: string;
|
|
57
|
+
exists?: (path: string) => boolean;
|
|
58
|
+
platform?: NodeJS.Platform;
|
|
59
|
+
}): SandboxGap | undefined;
|
|
60
|
+
/**
|
|
61
|
+
* What the person is told, in the chat, at the end of `turri regenerate`, and in the job's log. `rerun`: the command that runs
|
|
62
|
+
* the work again, as the pulse knows it - the spec the person ran; without it, the module's own spec by its name.
|
|
63
|
+
*/
|
|
64
|
+
export declare function describeEnvironmentError(error: EnvironmentError, rerun?: string): string;
|
|
65
|
+
/** The name agents know the tool by - their wall text names it. */
|
|
66
|
+
export declare const ENVIRONMENT_ERROR_TOOL = "report_environment_error";
|
|
67
|
+
/** An agent's report that the machine lacks something. */
|
|
68
|
+
export interface EnvironmentReport {
|
|
69
|
+
missing: string;
|
|
70
|
+
neededBy: string;
|
|
71
|
+
shownBy?: string;
|
|
72
|
+
}
|
|
73
|
+
/** Whether a report stands - the pulse stops - or not, and what the agent is told then. */
|
|
74
|
+
export type ReportVerdict = {
|
|
75
|
+
stands: true;
|
|
76
|
+
} | {
|
|
77
|
+
stands: false;
|
|
78
|
+
reply: string;
|
|
79
|
+
};
|
|
80
|
+
/**
|
|
81
|
+
* An agent's report checked against the harness's own run of the testing script - on this machine, outside the agent's
|
|
82
|
+
* sandbox, the run that decides whether the work is done. Its shell runs behind walls the script does not: what fails
|
|
83
|
+
* there may run here. The script passing, the machine has what the work needs: the report does not stand, and the agent
|
|
84
|
+
* goes on. The script not finding its toolchain, it stands. Failing otherwise, the agent is shown the run once - a
|
|
85
|
+
* report made again after it stands.
|
|
86
|
+
*/
|
|
87
|
+
export declare function checkAgainstScript(run: () => Promise<{
|
|
88
|
+
exitCode: number;
|
|
89
|
+
output: string;
|
|
90
|
+
}>, script: string): (report: EnvironmentReport) => Promise<ReportVerdict>;
|
|
91
|
+
/**
|
|
92
|
+
* `report_environment_error`: an agent that finds the machine lacking what the work needs says so, and its turn ends.
|
|
93
|
+
* `record` is told what it reported; whoever asked the turn stops the pulse with it. With `check`, the report is checked
|
|
94
|
+
* first: one that does not stand is not recorded, and the agent is told why and goes on.
|
|
95
|
+
*/
|
|
96
|
+
export declare function environmentErrorTool(record: (report: EnvironmentReport) => void, check?: (report: EnvironmentReport) => Promise<ReportVerdict>): ToolDefinition;
|
|
97
|
+
/**
|
|
98
|
+
* A testing script that cannot find its toolchain: the machine lacks it, and no change to the code or the tests would
|
|
99
|
+
* pass the script - so it is the environment's, found by the harness. `missing` is what the run's output named.
|
|
100
|
+
*/
|
|
101
|
+
export declare function toolchainError(missing: {
|
|
102
|
+
command?: string;
|
|
103
|
+
}, details: {
|
|
104
|
+
moduleName: string;
|
|
105
|
+
script: string;
|
|
106
|
+
kind: "unit" | "conformance";
|
|
107
|
+
}): EnvironmentError;
|
|
108
|
+
/**
|
|
109
|
+
* A testing script the time limit stopped while it was still making progress - judged so by the judge or the debugger,
|
|
110
|
+
* from where its output stops: nothing hangs, the suite needs more time than a test run may take. No agent can give it
|
|
111
|
+
* that, so the pulse stops and the person is told how to.
|
|
112
|
+
*/
|
|
113
|
+
export declare function timeLimitError(run: {
|
|
114
|
+
timeoutMs: number;
|
|
115
|
+
elapsedMs?: number;
|
|
116
|
+
}, details: {
|
|
117
|
+
moduleName: string;
|
|
118
|
+
script: string;
|
|
119
|
+
kind: "unit" | "conformance";
|
|
120
|
+
reason: string;
|
|
121
|
+
}): EnvironmentError;
|
|
122
|
+
/** The harness's run of a testing script, when it could not find its toolchain: the error that stops the pulse. */
|
|
123
|
+
export declare function missingToolchainError(run: {
|
|
124
|
+
exitCode: number;
|
|
125
|
+
output: string;
|
|
126
|
+
}, details: {
|
|
127
|
+
moduleName: string;
|
|
128
|
+
script: string;
|
|
129
|
+
kind: "unit" | "conformance";
|
|
130
|
+
}): EnvironmentError | undefined;
|
|
131
|
+
/**
|
|
132
|
+
* Before a pulse in `moduleDir` starts any agent: a credential `agent-env:` names that is not there stops it - every
|
|
133
|
+
* command that needs it would fail, and no agent may make one up. Nothing when all are there, or the folder is no
|
|
134
|
+
* module's.
|
|
135
|
+
*/
|
|
136
|
+
export declare function missingCredentials(moduleDir: string): EnvironmentError | undefined;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { TranscriptEntry } from "./activity.ts";
|
|
2
|
+
/**
|
|
3
|
+
* A job's whole transcript streamed to a file as it happens: the harness's
|
|
4
|
+
* stages, the functional spec or the diff it builds, and every one of its agents, in order - what it
|
|
5
|
+
* was asked, what it thought and wrote, each tool call and its result, whole, not clipped as the
|
|
6
|
+
* screen clips them - and how the job ended.
|
|
7
|
+
*
|
|
8
|
+
* In `.turri/jobs/` in the project, one file per job, beside the per-agent logs in
|
|
9
|
+
* `.turri/debug/`. Outside `plain_modules`, so no agent reads it. A log that cannot be
|
|
10
|
+
* written is given up on, never allowed to fail the job.
|
|
11
|
+
*/
|
|
12
|
+
export interface JobLog {
|
|
13
|
+
readonly file: string;
|
|
14
|
+
entry(entry: TranscriptEntry): void;
|
|
15
|
+
/** A line about the machinery under the work (activity.ts `reportNote`): which walls are up, what a command had put back. */
|
|
16
|
+
note(line: string): void;
|
|
17
|
+
/** `agents`: a line per agent - its turns, compactions and cost. */
|
|
18
|
+
end(status: string, report: string | undefined, agents?: string[]): void;
|
|
19
|
+
}
|
|
20
|
+
/** The folder a job's log goes in: the project of the first module it writes, from its lanes. */
|
|
21
|
+
export declare function jobLogDir(lanes: string[]): string | undefined;
|
|
22
|
+
export declare function startJobLog(job: {
|
|
23
|
+
id: string;
|
|
24
|
+
kind: string;
|
|
25
|
+
summary: string;
|
|
26
|
+
model?: string;
|
|
27
|
+
diff?: string;
|
|
28
|
+
}, lanes: string[]): JobLog | undefined;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { type Color } from "@earendil-works/pi-tui";
|
|
2
|
+
import { type Job } from "./jobs.ts";
|
|
3
|
+
/**
|
|
4
|
+
* The live panel above the editor while background work runs.
|
|
5
|
+
*
|
|
6
|
+
* One block per running job: what it is and how long it has been going, the stage it is
|
|
7
|
+
* at, what is happening this second, and the last things its agents did. What waits is not
|
|
8
|
+
* in it - the side panel lists the queue. It disappears when nothing is running - the finished
|
|
9
|
+
* job announces itself in the transcript instead.
|
|
10
|
+
*
|
|
11
|
+
* It is drawn as a component rather than handed over as lines, because pi cuts a list of
|
|
12
|
+
* lines off at ten. Instead it sizes itself: compact by default, and the agents' trace in full
|
|
13
|
+
* while tool output is expanded - pi's own ctrl+o, which the person already uses to see more of
|
|
14
|
+
* what the agent did. What finished stays counted either way: the side panel lists it.
|
|
15
|
+
*/
|
|
16
|
+
export declare const JOB_PANEL_KEY = "turri-jobs";
|
|
17
|
+
/**
|
|
18
|
+
* The key that opens the side panel on its jobs, and goes back to it. Not ctrl+j: a terminal without the Kitty keyboard
|
|
19
|
+
* protocol sends ctrl+j as a line feed - what it sends for shift+enter too, and what a dialog reads as enter - so it
|
|
20
|
+
* would answer a question, and take a new line from the editor. ctrl+h is the byte old terminals sent for backspace;
|
|
21
|
+
* every terminal now sends backspace as DEL, which pi never takes for ctrl+h, so it is free - in pi, and in a dialog.
|
|
22
|
+
*/
|
|
23
|
+
export declare const PANEL_KEY = "ctrl+h";
|
|
24
|
+
/**
|
|
25
|
+
* Each key in the line under the panel - ctrl+o, ctrl+h - breathes until it is first pressed: fully there, a little
|
|
26
|
+
* faint, and back, so it reads as something to press, not as text. Once every BREATH_MS, redrawn every BREATH_TICK_MS
|
|
27
|
+
* while the panel shows and a key still breathes, at most BREATH_FADE of the way from the text's colour to the dim one.
|
|
28
|
+
* Pressed once, it stays still for the rest of the process; the other breathes on.
|
|
29
|
+
*/
|
|
30
|
+
export declare const BREATH_MS = 2400;
|
|
31
|
+
/** The keys of the line, by what they do: pressed once, each stops breathing. */
|
|
32
|
+
export type PanelKey = "trace" | "peek";
|
|
33
|
+
/** A key of the line was pressed - ctrl+o, or the side panel opened: it stops breathing. */
|
|
34
|
+
export declare function keyPressed(key: PanelKey): void;
|
|
35
|
+
export declare function breathes(key: PanelKey): boolean;
|
|
36
|
+
/** For tests: every key breathing again. */
|
|
37
|
+
export declare function resetKeysForTests(): void;
|
|
38
|
+
/** How faint a breathing key is at `now`: 0, fully there, at the start of each breath, BREATH_FADE halfway through. */
|
|
39
|
+
export declare function breath(now: number): number;
|
|
40
|
+
export declare function spinner(now: number): string;
|
|
41
|
+
/**
|
|
42
|
+
* What finished, a line a module - its name, then its pulses oldest first - fitted to `width` from the left: the
|
|
43
|
+
* newest that fit, the rest counted as earlier. The side panel lists every one.
|
|
44
|
+
*/
|
|
45
|
+
export declare function finishedLines(finished: Job[], width: number | undefined, marks?: MarkPaint): string[];
|
|
46
|
+
/** A pulse that ran to its end and whose build did not pass - stopped at a gate - is not a success. */
|
|
47
|
+
export declare function didNotPass(job: Job): boolean;
|
|
48
|
+
/** How a finished pulse's mark is coloured: green it passed, red it failed or did not pass, amber it was stopped. */
|
|
49
|
+
export interface MarkPaint {
|
|
50
|
+
success(text: string): string;
|
|
51
|
+
error(text: string): string;
|
|
52
|
+
warning(text: string): string;
|
|
53
|
+
}
|
|
54
|
+
/** A finished pulse's mark, in the colour of how it ended. */
|
|
55
|
+
export declare function finishedMark(job: Job, paint?: MarkPaint): string;
|
|
56
|
+
/** What a pulse cost, as its line says it: " · $0.12", or nothing when the price is not known. */
|
|
57
|
+
export declare function pulseCost(job: Job): string;
|
|
58
|
+
/**
|
|
59
|
+
* One line saying what a spec change does: the files, the lines added and removed, and the
|
|
60
|
+
* first line it adds - usually the concept or the functional spec it is about.
|
|
61
|
+
*/
|
|
62
|
+
/** How a diff is coloured: added lines green, removed lines red. Plain when there is no theme. */
|
|
63
|
+
export interface DiffStyle {
|
|
64
|
+
added(text: string): string;
|
|
65
|
+
removed(text: string): string;
|
|
66
|
+
}
|
|
67
|
+
export declare function summarizeDiff(diff: string, style?: DiffStyle): string;
|
|
68
|
+
/** The lines of a diff worth reading in a panel: the hunks, not the headers. */
|
|
69
|
+
/**
|
|
70
|
+
* A line of the panel wrapped to its width, its continuations under its text: indented as far as it is,
|
|
71
|
+
* and past the rule of a diff box when it is in one.
|
|
72
|
+
*/
|
|
73
|
+
export declare function wrapKeepingIndent(line: string, width: number): string[];
|
|
74
|
+
/** A diff's colours for the +/- alone, when there is nothing to highlight with. */
|
|
75
|
+
export interface PanelOptions {
|
|
76
|
+
/** Everything, rather than the compact view. */
|
|
77
|
+
expanded?: boolean;
|
|
78
|
+
now?: number;
|
|
79
|
+
width?: number;
|
|
80
|
+
/** The lines of help about ctrl+o and the side panel - left out where they do not apply, as in the side panel itself. */
|
|
81
|
+
hints?: boolean;
|
|
82
|
+
/** How the finished pulses' marks are coloured. */
|
|
83
|
+
marks?: MarkPaint;
|
|
84
|
+
/** How each key of the line is painted - breathing until it is pressed, in the TUI. */
|
|
85
|
+
keys?: (key: PanelKey, text: string) => string;
|
|
86
|
+
}
|
|
87
|
+
export declare function jobPanelLines(jobs: Job[], options?: PanelOptions): string[];
|
|
88
|
+
interface Redrawable {
|
|
89
|
+
requestRender(): void;
|
|
90
|
+
}
|
|
91
|
+
/** What of pi's theme the panel paints with: the diff's colours and bands, and ***plain's colours in it. */
|
|
92
|
+
interface PanelTheme {
|
|
93
|
+
fg(color: "toolDiffAdded" | "toolDiffRemoved" | "success" | "error" | "warning", text: string): string;
|
|
94
|
+
/** Whether it is made for a dark or a light surface, and how many colours the terminal has: the diff's palette. */
|
|
95
|
+
appearance?: "dark" | "light";
|
|
96
|
+
getColorMode?(): string;
|
|
97
|
+
/** Each token's concrete colour - what the line of keys breathes between. */
|
|
98
|
+
colors?: Readonly<Record<string, Color>>;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* The keys of the line, painted at `now`'s breath: one not pressed yet in the text's colour mixed toward the dim one, one
|
|
102
|
+
* pressed as it is. Plain where the theme has no colours to mix.
|
|
103
|
+
*/
|
|
104
|
+
export declare function breathing(theme: PanelTheme, now: number): (key: PanelKey, text: string) => string;
|
|
105
|
+
/** The parts of pi's TUI the panel needs: enough to draw, redraw, and ask about ctrl+o. */
|
|
106
|
+
export interface PanelUI {
|
|
107
|
+
setWidget(key: string, content: ((tui: Redrawable, theme: PanelTheme) => {
|
|
108
|
+
render(width: number): string[];
|
|
109
|
+
invalidate(): void;
|
|
110
|
+
}) | undefined, options?: {
|
|
111
|
+
placement?: "aboveEditor" | "belowEditor";
|
|
112
|
+
}): void;
|
|
113
|
+
getToolsExpanded(): boolean;
|
|
114
|
+
}
|
|
115
|
+
export interface JobPanel {
|
|
116
|
+
/** Where to draw. Until this is set there is no UI, and the panel does nothing. */
|
|
117
|
+
attach(ui: PanelUI): void;
|
|
118
|
+
/** Redraw soon, e.g. because a job changed. */
|
|
119
|
+
refresh(): void;
|
|
120
|
+
}
|
|
121
|
+
export declare function createJobPanel(list: () => Job[]): JobPanel;
|
|
122
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { type Job } from "./jobs.ts";
|
|
2
|
+
import type { TranscriptStyle } from "./transcript-view.ts";
|
|
3
|
+
/**
|
|
4
|
+
* The side panel's Jobs view: the queue as a tree, read one job at a time.
|
|
5
|
+
*
|
|
6
|
+
* Three sections - running, queued, finished - each opened and closed on its own, and under them one line per job:
|
|
7
|
+
* its module, its time and its cost. A job opened shows all of what it builds - the diff, or the spec - and, running,
|
|
8
|
+
* what it is doing; finished, what went on in it. So what is planned can be read without every diff on the screen at once.
|
|
9
|
+
*
|
|
10
|
+
* A cursor moves over the sections and the jobs; it stays on its row, whatever moves under it - a job that finishes
|
|
11
|
+
* leaves its row to the one after it. A job opened stays open while it stays where it is: moving to another section
|
|
12
|
+
* it closes, and turns up there collapsed. The state is the conversation's, kept while the panel is closed.
|
|
13
|
+
*/
|
|
14
|
+
export type JobSection = "running" | "queued" | "finished";
|
|
15
|
+
export declare const SECTIONS: JobSection[];
|
|
16
|
+
export interface JobsTreeState {
|
|
17
|
+
/** Which sections are open. */
|
|
18
|
+
open: Record<JobSection, boolean>;
|
|
19
|
+
/** The jobs opened, by id, and the section each was opened in. */
|
|
20
|
+
openJobs: Map<string, JobSection>;
|
|
21
|
+
/** The files of each job's diff opened or closed by hand, by job and file: the rest as they start - the file being rendered open, the others closed. */
|
|
22
|
+
openFiles: Map<string, Map<string, boolean>>;
|
|
23
|
+
/** The row the cursor is on. */
|
|
24
|
+
cursor: number;
|
|
25
|
+
/** The first line shown. */
|
|
26
|
+
top: number;
|
|
27
|
+
}
|
|
28
|
+
export declare function createJobsTreeState(): JobsTreeState;
|
|
29
|
+
export declare function sectionOf(job: Job): JobSection;
|
|
30
|
+
export type TreeRow = {
|
|
31
|
+
kind: "section";
|
|
32
|
+
section: JobSection;
|
|
33
|
+
count: number;
|
|
34
|
+
} | {
|
|
35
|
+
kind: "job";
|
|
36
|
+
section: JobSection;
|
|
37
|
+
job: Job;
|
|
38
|
+
} | {
|
|
39
|
+
kind: "file";
|
|
40
|
+
section: JobSection;
|
|
41
|
+
job: Job;
|
|
42
|
+
file: string;
|
|
43
|
+
first: boolean;
|
|
44
|
+
};
|
|
45
|
+
/** The rows, top to bottom: each section's header, and its jobs when it is open - finished ones newest first. */
|
|
46
|
+
/** The pulse list put on one pulse: its section open, the pulse opened - its stages, its agents, its log - and the cursor on it. */
|
|
47
|
+
export declare function selectJob(jobs: Job[], state: JobsTreeState, id: string): boolean;
|
|
48
|
+
export declare function jobsTreeRows(jobs: Job[], state: JobsTreeState): TreeRow[];
|
|
49
|
+
/** The rows as lines, the cursor's marked, and where each row starts - for scrolling to it. */
|
|
50
|
+
export declare function jobsTreeLines(jobs: Job[], state: JobsTreeState, width: number, style: TranscriptStyle): {
|
|
51
|
+
lines: string[];
|
|
52
|
+
rowStarts: number[];
|
|
53
|
+
rows: TreeRow[];
|
|
54
|
+
};
|
|
55
|
+
/** Keep the cursor's row in sight: scroll only as far as that takes. */
|
|
56
|
+
export declare function keepCursorInView(state: {
|
|
57
|
+
cursor: number;
|
|
58
|
+
top: number;
|
|
59
|
+
}, rowStarts: number[], lineCount: number, height: number): void;
|
|
60
|
+
/** Scroll the view by lines, the cursor coming along to the first row in sight. */
|
|
61
|
+
export declare function scrollTree(state: {
|
|
62
|
+
cursor: number;
|
|
63
|
+
top: number;
|
|
64
|
+
}, by: number, rowStarts: number[], lineCount: number, height: number): void;
|
|
65
|
+
export type TreeAction = {
|
|
66
|
+
kind: "none";
|
|
67
|
+
} | {
|
|
68
|
+
kind: "handled";
|
|
69
|
+
};
|
|
70
|
+
/** A key in the Jobs view, and what it does to the tree. */
|
|
71
|
+
export declare function treeKey(state: JobsTreeState, rows: TreeRow[], key: "up" | "down" | "toggle" | "open" | "close" | "openAll" | "closeAll"): TreeAction;
|