@turri-dev/cli 0.1.6 → 0.1.7-next.eb57c34

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.
Files changed (140) hide show
  1. package/dist/ask.d.ts +83 -0
  2. package/dist/brand.d.ts +13 -0
  3. package/dist/btw.d.ts +67 -0
  4. package/dist/chat-models.d.ts +22 -0
  5. package/dist/chat-skills.d.ts +17 -0
  6. package/dist/cli-options.d.ts +25 -0
  7. package/dist/cli.d.ts +9 -0
  8. package/dist/config-command.d.ts +26 -0
  9. package/dist/config-edit.d.ts +69 -0
  10. package/dist/config.d.ts +321 -0
  11. package/dist/conform-cli.d.ts +1 -0
  12. package/dist/cultivate-cli.d.ts +1 -0
  13. package/dist/drift-cli.d.ts +1 -0
  14. package/dist/environment.d.ts +39 -0
  15. package/dist/extension.d.ts +147 -0
  16. package/dist/extension.js +36 -10
  17. package/dist/genome.d.ts +62 -0
  18. package/dist/graph.d.ts +52 -0
  19. package/dist/host.d.ts +21 -0
  20. package/dist/host.js +25 -0
  21. package/dist/identity.d.ts +2 -0
  22. package/dist/init-config.d.ts +106 -0
  23. package/dist/jellyfish.d.ts +25 -0
  24. package/dist/judge.d.ts +25 -0
  25. package/dist/lineage-cli.d.ts +1 -0
  26. package/dist/loop-cli.d.ts +34 -0
  27. package/dist/loop-tools.d.ts +80 -0
  28. package/dist/mature-tools.d.ts +53 -0
  29. package/dist/model-check.d.ts +42 -0
  30. package/dist/module-report.d.ts +9 -0
  31. package/dist/pi-launch.d.ts +1 -0
  32. package/dist/pi.d.ts +246 -0
  33. package/dist/picture-row.d.ts +10 -0
  34. package/dist/plain/check.d.ts +23 -0
  35. package/dist/plain/concepts.d.ts +11 -0
  36. package/dist/plain/errors.d.ts +22 -0
  37. package/dist/plain/files.d.ts +12 -0
  38. package/dist/plain/highlight.d.ts +42 -0
  39. package/dist/plain/index.d.ts +15 -0
  40. package/dist/plain/liquid.d.ts +22 -0
  41. package/dist/plain/markdown.d.ts +74 -0
  42. package/dist/plain/parser.d.ts +87 -0
  43. package/dist/plain/spec.d.ts +90 -0
  44. package/dist/plain/stdlib.d.ts +14 -0
  45. package/dist/question-dialog.d.ts +51 -0
  46. package/dist/questioning.d.ts +55 -0
  47. package/dist/quiet.d.ts +34 -0
  48. package/dist/regenerate/activity.d.ts +207 -0
  49. package/dist/regenerate/agent-env.d.ts +44 -0
  50. package/dist/regenerate/agent-shell.d.ts +49 -0
  51. package/dist/regenerate/arbiter.d.ts +68 -0
  52. package/dist/regenerate/audit.d.ts +69 -0
  53. package/dist/regenerate/cases.d.ts +9 -0
  54. package/dist/regenerate/change-view.d.ts +18 -0
  55. package/dist/regenerate/choose-conformance.d.ts +32 -0
  56. package/dist/regenerate/chunk-plan.d.ts +164 -0
  57. package/dist/regenerate/codebase.d.ts +21 -0
  58. package/dist/regenerate/command-check.d.ts +40 -0
  59. package/dist/regenerate/compaction.d.ts +13 -0
  60. package/dist/regenerate/confine.d.ts +62 -0
  61. package/dist/regenerate/conform.d.ts +63 -0
  62. package/dist/regenerate/conformance-agents.d.ts +405 -0
  63. package/dist/regenerate/conformance.d.ts +189 -0
  64. package/dist/regenerate/conversation-writes.d.ts +10 -0
  65. package/dist/regenerate/credentials.d.ts +18 -0
  66. package/dist/regenerate/debug-log.d.ts +54 -0
  67. package/dist/regenerate/debugger.d.ts +31 -0
  68. package/dist/regenerate/delivery.d.ts +6 -0
  69. package/dist/regenerate/diagnose-job.d.ts +2 -0
  70. package/dist/regenerate/diagnose.d.ts +46 -0
  71. package/dist/regenerate/diff-view.d.ts +61 -0
  72. package/dist/regenerate/drift.d.ts +84 -0
  73. package/dist/regenerate/engine.d.ts +52 -0
  74. package/dist/regenerate/environment-error.d.ts +136 -0
  75. package/dist/regenerate/job-log.d.ts +28 -0
  76. package/dist/regenerate/job-panel.d.ts +122 -0
  77. package/dist/regenerate/jobs-tree.d.ts +71 -0
  78. package/dist/regenerate/jobs.d.ts +186 -0
  79. package/dist/regenerate/lanes.d.ts +16 -0
  80. package/dist/regenerate/lineage.d.ts +95 -0
  81. package/dist/regenerate/list-arguments.d.ts +21 -0
  82. package/dist/regenerate/loop.d.ts +392 -0
  83. package/dist/regenerate/masking.d.ts +19 -0
  84. package/dist/regenerate/notes.d.ts +159 -0
  85. package/dist/regenerate/os-sandbox.d.ts +89 -0
  86. package/dist/regenerate/panel-dock.d.ts +23 -0
  87. package/dist/regenerate/paths.d.ts +92 -0
  88. package/dist/regenerate/plain-palette.d.ts +34 -0
  89. package/dist/regenerate/prompt.d.ts +192 -0
  90. package/dist/regenerate/records.d.ts +88 -0
  91. package/dist/regenerate/regenerate.d.ts +108 -0
  92. package/dist/regenerate/regression.d.ts +58 -0
  93. package/dist/regenerate/release.d.ts +123 -0
  94. package/dist/regenerate/requires.d.ts +96 -0
  95. package/dist/regenerate/resources.d.ts +53 -0
  96. package/dist/regenerate/self-check.d.ts +29 -0
  97. package/dist/regenerate/services.d.ts +28 -0
  98. package/dist/regenerate/shell.d.ts +91 -0
  99. package/dist/regenerate/side-panel.d.ts +57 -0
  100. package/dist/regenerate/spec-map-view.d.ts +139 -0
  101. package/dist/regenerate/spec-map.d.ts +138 -0
  102. package/dist/regenerate/spec-steps.d.ts +137 -0
  103. package/dist/regenerate/state.d.ts +20 -0
  104. package/dist/regenerate/steer.d.ts +34 -0
  105. package/dist/regenerate/steering.d.ts +56 -0
  106. package/dist/regenerate/stop-report.d.ts +43 -0
  107. package/dist/regenerate/submit-work.d.ts +42 -0
  108. package/dist/regenerate/test-kinds.d.ts +42 -0
  109. package/dist/regenerate/test-scripts.d.ts +221 -0
  110. package/dist/regenerate/testing.d.ts +141 -0
  111. package/dist/regenerate/transcript-view.d.ts +21 -0
  112. package/dist/regenerate/unit-gate.d.ts +27 -0
  113. package/dist/regenerate/unit-review.d.ts +152 -0
  114. package/dist/regenerate/web.d.ts +61 -0
  115. package/dist/regenerate/workspace.d.ts +12 -0
  116. package/dist/regenerate-cli.d.ts +1 -0
  117. package/dist/release-agent.d.ts +26 -0
  118. package/dist/release-cli.d.ts +1 -0
  119. package/dist/release-tools.d.ts +38 -0
  120. package/dist/resume-line.d.ts +2 -0
  121. package/dist/review/live.d.ts +72 -0
  122. package/dist/rules.d.ts +20 -0
  123. package/dist/run-report.d.ts +88 -0
  124. package/dist/screen-padding.d.ts +28 -0
  125. package/dist/self-invocation.d.ts +25 -0
  126. package/dist/setup.d.ts +43 -0
  127. package/dist/skill-progress.d.ts +46 -0
  128. package/dist/skill.d.ts +98 -0
  129. package/dist/skills.d.ts +30 -0
  130. package/dist/spec-diff-cli.d.ts +1 -0
  131. package/dist/spec-tools.d.ts +36 -0
  132. package/dist/stack.d.ts +58 -0
  133. package/dist/stacks.d.ts +12 -0
  134. package/dist/stdlib.d.ts +27 -0
  135. package/dist/terminal-images.d.ts +2 -0
  136. package/dist/tools.d.ts +101 -0
  137. package/dist/validate-cli.d.ts +1 -0
  138. package/docs/README.md +2 -0
  139. package/docs/hosting.md +52 -0
  140. package/package.json +8 -1
@@ -0,0 +1,123 @@
1
+ import { type ChainEntry } from "./requires.ts";
2
+ /**
3
+ * Deploy: a module's code, as its last commit has it, put out in `dist/<module>` for the person to try.
4
+ *
5
+ * A render works in `plain_modules/<module>/code` while the person asks to try what is there, so what
6
+ * is there is half-written. Its last commit is not: every unit of work starts from one and ends with
7
+ * one, and both are runnable. So the commit is exported - git's own list of what it tracks, and
8
+ * nothing else - which is a copy of the working tree with every unstaged and untracked change put
9
+ * back, without a list of what each stack leaves lying around (`node_modules`, `.venv`, `target`). The
10
+ * working tree itself is never read or touched.
11
+ *
12
+ * What starts it runs here, on the person's machine, unfenced: a server the person opens in their
13
+ * browser, with their toolchains. The agent that releases it installs and runs what it needs itself,
14
+ * as any agent with a shell would - nothing is put to the person - and everything started is the
15
+ * harness's to stop: on a redeploy, on /halt, and when turri exits.
16
+ */
17
+ /**
18
+ * How a module is released - always from its last commit, exported to `dist/<module>` first. `dist`, the default: started
19
+ * from there. `guided`: taken on from there as there is guidance to - the person's, the project's AGENTS.md, a skill -
20
+ * into the host codebase, say.
21
+ */
22
+ export type ReleaseWay = "dist" | "guided";
23
+ export interface Deployment {
24
+ moduleName: string;
25
+ plainFile: string;
26
+ way: ReleaseWay;
27
+ /** `dist/<module>`, in the project: the module's last commit, exported. */
28
+ dir: string;
29
+ /** Guided: the host codebase the guidance takes the code into, and what release runs and starts runs from. */
30
+ hostDir?: string;
31
+ /** Where the module's code is built: `plain_modules/<module>/code`. */
32
+ buildDir: string;
33
+ commit: string;
34
+ /** The commit's subject: what the last unit of work that landed did. */
35
+ subject: string;
36
+ /** When, as git says it: "3 minutes ago". */
37
+ when: string;
38
+ /** Work under way in the module - changes nobody committed yet - left out. */
39
+ unfinished: boolean;
40
+ /** The module the spec's code lives in had nothing committed yet: the nearest one below it that had, instead. */
41
+ instead?: string;
42
+ }
43
+ /**
44
+ * Which module to deploy for a spec: the tip of its codebase - code accumulates up a requires chain, so
45
+ * the top module holds everything below it. Before the tip has anything committed, the nearest module
46
+ * below it that has.
47
+ */
48
+ export declare function deployTarget(plainFile: string, inModule?: string): {
49
+ entry: ChainEntry;
50
+ commit: string;
51
+ instead?: string;
52
+ };
53
+ /**
54
+ * Export the module's code at its last commit into `dist/<module>` - or `into`, `turri regenerate --build-dir` -
55
+ * replacing whatever was there, the harness's own files (what the code is built from, the agents' notes) left out.
56
+ */
57
+ export declare function exportModule(plainFile: string, inModule?: string, into?: string): Deployment;
58
+ /**
59
+ * The host codebase a guided release works in: the git repository the project is in - an embedded project's host -
60
+ * or else `fallback`, where turri runs.
61
+ */
62
+ export declare function hostDirOf(plainFile: string, fallback: string): string;
63
+ /** Where a path is, said from the current directory when it is below it. */
64
+ export declare function shortPath(path: string): string;
65
+ /** What was deployed, in a line or three. */
66
+ export declare function describeDeployment(deployment: Deployment): string;
67
+ export interface DeployedProcess {
68
+ name: string;
69
+ moduleName: string;
70
+ command: string;
71
+ /** Where it runs. */
72
+ dir: string;
73
+ url?: string;
74
+ /** Its output, both streams. */
75
+ log: string;
76
+ pid: number;
77
+ startedAt: number;
78
+ /** Set once it has ended. */
79
+ exited?: {
80
+ code: number | null;
81
+ signal: string | null;
82
+ };
83
+ }
84
+ /** Everything deploy started, running or ended, oldest first. */
85
+ export declare function listDeployed(): DeployedProcess[];
86
+ /** The ones still running. */
87
+ export declare function runningDeployed(moduleName?: string): DeployedProcess[];
88
+ /** Where a project's deployed processes write their output: its scratch, not the code in dist. */
89
+ export declare function deployLogDir(projectDir: string): string;
90
+ /** The end of a log, for when something did not come up. */
91
+ export declare function logTail(log: string, lines?: number, chars?: number): string;
92
+ /** Stop one deployed process, or every one of a module, or every one: politely, then not. Returns the names stopped. */
93
+ export declare function stopDeployed(which?: {
94
+ name?: string;
95
+ moduleName?: string;
96
+ }): Promise<string[]>;
97
+ /** Stop everything at once, without waiting: for when turri itself is going. */
98
+ export declare function stopAllDeployedNow(): void;
99
+ /** How long a server is given to answer at its URL, and to stay up when it has none. */
100
+ export declare const READY_TIMEOUT_MS: number;
101
+ export interface StartResult {
102
+ ok: boolean;
103
+ /** What happened, for the agent and the person. */
104
+ text: string;
105
+ process?: DeployedProcess;
106
+ }
107
+ /**
108
+ * Start something that keeps running - a server, a frontend's dev server - in `dir`, on this machine,
109
+ * in its own process group, its output to a log. One already running under the name is stopped first.
110
+ *
111
+ * With a URL, it is ready once something answers there - any answer - and not when it exits first or
112
+ * nothing answers in time. A port something else holds already is said, with what holds it, and
113
+ * nothing is started: an app moved to a port of the harness's choosing would not be the one the
114
+ * person was told about. With no URL, it only has to still be running a few seconds on.
115
+ */
116
+ export declare function startDeployed(input: {
117
+ name: string;
118
+ command: string;
119
+ dir: string;
120
+ moduleName: string;
121
+ logDir: string;
122
+ url?: string;
123
+ }): Promise<StartResult>;
@@ -0,0 +1,96 @@
1
+ import { type ParseOptions } from "../plain/parser.ts";
2
+ /**
3
+ * `requires` chains.
4
+ *
5
+ * A module that `requires` another is built on top of that module's code: the required
6
+ * module must be finished first, and its codebase is copied into the build before this
7
+ * module starts. So rendering a module means rendering its chain, bottom first, carrying
8
+ * the code forward at each step.
9
+ *
10
+ * What has already been built is not tracked here: each codebase's record says what it is built
11
+ * from - see `records.ts`.
12
+ */
13
+ export interface ChainEntry {
14
+ moduleName: string;
15
+ plainFile: string;
16
+ buildDir: string;
17
+ /** The module whose code is copied in before this one is built. */
18
+ requires: string | null;
19
+ frids: string[];
20
+ }
21
+ /**
22
+ * The chain to build, bottom first.
23
+ *
24
+ * Depth-first, post-order: everything a module requires is listed before the module
25
+ * itself. The parser has already rejected circular requires, and a module reached twice is
26
+ * emitted once.
27
+ */
28
+ export declare function resolveRequiresChain(plainFile: string, templateDirs?: string[], buildRoot?: string,
29
+ /** Accept the named module without functional specs yet. Those it requires must have them. */
30
+ options?: ParseOptions): ChainEntry[];
31
+ /**
32
+ * Whether a .plain file is an import module - one a .plain file imports, or one kept in a `template/` folder - rather than
33
+ * a module of its own. It is no codebase: its reqs and definitions are built in the modules that import it.
34
+ */
35
+ export declare function isImportModule(plainFile: string): boolean;
36
+ /** The modules of their own that import an import module, through any import modules between. */
37
+ export declare function importingModules(plainFile: string): string[];
38
+ /**
39
+ * The codebase a change to `plainFile`'s module lands in: the furthest-built module whose
40
+ * requires chain includes it, with that chain.
41
+ *
42
+ * Code accumulates up a chain, so once modules have been built on top of this one, its own
43
+ * build is only an early snapshot - the living codebase is the one at the tip. A change to
44
+ * this module's spec is made there, where everything built since can be kept working, not
45
+ * in the snapshot, where it would have to be copied up over newer work.
46
+ *
47
+ * Found by reading every .plain file beside this one. Where built descendants sit on
48
+ * different branches there is no single tip, and choosing one is a decision: `inModule`
49
+ * names it, and without it this refuses rather than guesses.
50
+ */
51
+ export declare function findCodebaseTip(plainFile: string, options?: {
52
+ templateDirs?: string[];
53
+ buildRoot?: string;
54
+ inModule?: string;
55
+ allowNoFunctionalities?: boolean;
56
+ }): {
57
+ tip: ChainEntry;
58
+ chain: ChainEntry[];
59
+ };
60
+ /**
61
+ * The chains of the built modules whose requires chain includes `plainFile`'s module, and that no other
62
+ * built module is built on - where its code lives now, one chain per branch. Empty when nothing built is
63
+ * built on it. Found by reading every .plain file beside it.
64
+ */
65
+ export declare function builtTips(plainFile: string, options?: {
66
+ templateDirs?: string[];
67
+ buildRoot?: string;
68
+ }): ChainEntry[][];
69
+ /**
70
+ * Copy a required module's codebase into the build that is about to be created.
71
+ *
72
+ * What the code is built from comes too, converted: what the source module built becomes what
73
+ * the new one inherits, while the new module's own functional specs start empty. Copied as-is, it would claim the source's work as the new
74
+ * module's own. And the conformance tests come, into the new module's tests directory.
75
+ */
76
+ export declare function copyRequiredCode(from: string, to: string, toModule: string,
77
+ /** The module the code comes from: its functional specs are what the new one inherits. */
78
+ fromModule: string): string[];
79
+ /**
80
+ * A module the chain requires now that a module built in it was not built on: one required for
81
+ * the first time - a new module the specs were split into, say - and the built modules above it,
82
+ * whose code was started without it and so has to start again from scratch.
83
+ *
84
+ * A module was built on what its record lists as inherited; one with nothing recorded, on what it
85
+ * was started from, as its history says. A module below it with nothing built was never under it.
86
+ */
87
+ export declare function newlyRequired(chain: ChainEntry[]): {
88
+ modules: string[];
89
+ rebuild: ChainEntry[];
90
+ } | undefined;
91
+ /**
92
+ * Take a module back to nothing - its code, its conformance tests and what they were built from -
93
+ * so it is built again from the start, on the module it now requires. Committed, so the code that
94
+ * was there is in its history.
95
+ */
96
+ export declare function startFromScratch(entry: ChainEntry, why: string): void;
@@ -0,0 +1,53 @@
1
+ import { type ToolDefinition } from "@earendil-works/pi-coding-agent";
2
+ import { type MarshalledPlainSource } from "../plain/spec.ts";
3
+ export interface LoadedResource {
4
+ text: string;
5
+ target: string;
6
+ /** What the agent reads in <linked resources>: the file's text, or - an image - where to find it. */
7
+ content: string;
8
+ /** An image: sent to the agent with its first message, not as text. */
9
+ image?: ResourceImage;
10
+ /** Where the file is: copy_resource copies it whole from here. */
11
+ source?: string;
12
+ /** Its text was cut for the prompt: how long it is whole. */
13
+ cutFrom?: number;
14
+ }
15
+ /** A linked image as a model is sent it. */
16
+ export interface ResourceImage {
17
+ type: "image";
18
+ data: string;
19
+ mimeType: string;
20
+ }
21
+ /** The MIME type of a linked image, by its extension; undefined for any other file. */
22
+ export declare function imageTypeOf(target: string): string | undefined;
23
+ /** A linked image too large to send, or unreadable: the job stops, saying which file and why. */
24
+ export declare class LinkedImageError extends Error {
25
+ }
26
+ /**
27
+ * Load the resources linked from the specifications in scope for one functionality.
28
+ *
29
+ * `collectLinkedResources` stops at the requested FRID, so a resource introduced by a
30
+ * later functionality is not pulled into this prompt.
31
+ */
32
+ export declare function loadLinkedResources(tree: MarshalledPlainSource,
33
+ /** Up to and including this functionality. Null: the whole module. */
34
+ frid: string | null, templateDirs: string[]): LoadedResource[];
35
+ /**
36
+ * A linked resource that is code - a source file, or a build manifest: the specification points at code that lives
37
+ * elsewhere, a host's module the code plugs into, for the code to build on as it says. It is never copied into the
38
+ * codebase, nor recreated there; a resource that is data - a fixture, a schema, a sample - is.
39
+ */
40
+ export declare function isCodeResource(target: string): boolean;
41
+ /** Where in a codebase a linked resource's one copy goes: its path, without the steps up and the leading `./`. */
42
+ export declare function codeCopyOf(target: string): string;
43
+ /**
44
+ * `copy_resource`: a linked resource copied whole into the agent's own folder - at its code-copy path, or where it
45
+ * says - by the harness, byte for byte. The agent's prompt shows a long resource cut short, and the file itself is
46
+ * outside its walls: copied, it reads the whole of it there, and the code or the tests use that one copy.
47
+ */
48
+ export declare function createCopyResourceTool(options: {
49
+ resources: LoadedResource[];
50
+ dir: string;
51
+ }): ToolDefinition;
52
+ /** The images among loaded resources, in the order the prompt numbers them. */
53
+ export declare function resourceImages(resources: LoadedResource[]): ResourceImage[];
@@ -0,0 +1,29 @@
1
+ import { type ToolDefinition } from "@earendil-works/pi-coding-agent";
2
+ /**
3
+ * Tools an agent checks its own work with, before the harness and the reviewer do: the diff the reviewer is shown, and
4
+ * whether a test catches a change to the code. Neither decides anything - the testing scripts, run by the harness, still do.
5
+ */
6
+ /** The work so far, as the reviewer is shown it: a diff of the folder from the commit the job started from. */
7
+ export declare function createMyDiffTool(options: {
8
+ dir: string;
9
+ what: "code" | "tests";
10
+ }): ToolDefinition;
11
+ /** How many times can_it_fail runs in one session, by default: each is a run of the unit testing script. */
12
+ export declare const CAN_IT_FAIL_RUNS = 6;
13
+ /**
14
+ * How long a can_it_fail run may take: three times the last passing run of the unit tests on this code, within 15 and
15
+ * 60 seconds - 60 before one has passed. A bug put in the code often makes it loop or wait for ever: that is found out
16
+ * in a short time, not the whole limit of a test run, and well within the agent's turn.
17
+ */
18
+ export declare function canItFailLimitMs(buildDir: string, script: string): number;
19
+ /**
20
+ * Whether the unit tests catch a change to the code: the change made to a fresh copy - never to the code itself - and
21
+ * the unit testing script run on it. A test that passes whatever the code does tests nothing.
22
+ */
23
+ export declare function createCanItFailTool(options: {
24
+ buildDir: string;
25
+ script: string;
26
+ runs?: number;
27
+ }): ToolDefinition;
28
+ /** When the coding agent checks its own work, by the tools it has: before the unit tests, and before it hands the work in. */
29
+ export declare function selfCheckNote(tools: string[]): string[];
@@ -0,0 +1,28 @@
1
+ import { type ToolDefinition } from "@earendil-works/pi-coding-agent";
2
+ import { type AgentShell } from "./agent-shell.ts";
3
+ /**
4
+ * What an agent starts and keeps running while it works - a server, a worker - to try the software as someone would,
5
+ * from outside: with curl, or what the stack's own client is. Whatever the stack: the agent gives the command that
6
+ * starts it, and how to tell it is up - a port that answers, or a line in its log. It runs on this machine behind the
7
+ * same walls as the agent's own shell - the command check, the module's environment, the OS sandbox, the audit while it
8
+ * starts - in a process group of its own, so it outlives the command that started it; it is stopped - it and everything
9
+ * it started - when the agent asks, when the agent's session ends, and in any case when its pulse ends.
10
+ */
11
+ /** How many services one agent may have running at once. */
12
+ export declare const MAX_SERVICES = 3;
13
+ export interface ServiceTools {
14
+ tools: ToolDefinition[];
15
+ names: string[];
16
+ /** Stop everything still running. Called when the agent's session ends, whatever ended it. */
17
+ stopAll(): Promise<void>;
18
+ }
19
+ /**
20
+ * Start, read and stop services from `dir` - the folder the agent works in - fenced as its role is: what it may read and
21
+ * write (its workdir when not given), or the shell given.
22
+ */
23
+ export declare function createServiceTools(options: {
24
+ dir: string;
25
+ read?: string[];
26
+ write?: string[];
27
+ shell?: AgentShell;
28
+ }): ServiceTools;
@@ -0,0 +1,91 @@
1
+ /**
2
+ * The one way a command runs on this machine - an agent's, a testing script, a service.
3
+ *
4
+ * Each command runs in a process group of its own, so the time limit and a stop end it with everything it started, a
5
+ * server put in the background included. What a command leaves running when it ends - a server for the tests to talk
6
+ * to - is the pulse's: it runs on until the pulse ends (`withPulse`), and is killed then, as everything still running is
7
+ * when turri exits. turri killed outright cannot do that itself, so a watcher - one small shell for each turri - does it
8
+ * within two seconds; and the groups a turri left that nothing killed (the watcher gone too) are swept when turri next
9
+ * starts (`sweepOrphanedGroups`).
10
+ *
11
+ * On Windows there are no process groups: a command's process tree is killed with `taskkill /T /F`, which reaches what
12
+ * is still a child of it - best effort, and nothing watches a turri killed outright.
13
+ */
14
+ export interface RunResult {
15
+ exitCode: number;
16
+ output: string;
17
+ /** Stopped by its time limit, rather than ending on its own. */
18
+ timedOut?: boolean;
19
+ }
20
+ export interface RunOptions {
21
+ /** Where it runs from. */
22
+ cwd: string;
23
+ /** Its time limit: COMMAND_TIMEOUT_MS when not given. */
24
+ timeoutMs?: number;
25
+ /** What the output says when the time limit stops it; the note for a command, by default. */
26
+ timeoutNote?: (timeoutMs: number) => string;
27
+ /** Ends it at once - as the job's own stop signal does, given or not. */
28
+ signal?: AbortSignal;
29
+ /** Its output, as it comes. */
30
+ onData?: (data: Buffer) => void;
31
+ /** Its whole environment: this process's when not given. */
32
+ env?: NodeJS.ProcessEnv;
33
+ /** The command line turned into another that runs it - an OS sandbox around it. */
34
+ wrap?: (argv: string[]) => string[];
35
+ }
36
+ /**
37
+ * How long a command may run before it is stopped - an agent's own, its tests, the harness's runs. Nothing an agent
38
+ * starts may hang a build: a server started in the foreground, a watcher, a prompt waiting for input would otherwise
39
+ * hold the agent's turn, and the job, forever. TURRI_COMMAND_TIMEOUT sets it, in seconds.
40
+ */
41
+ export declare const COMMAND_TIMEOUT_MS: number;
42
+ /** The longest an agent may ask one of its own commands to run for. */
43
+ export declare const MAX_COMMAND_TIMEOUT_MS: number;
44
+ /** What a command that ran out of time leaves in its output, for the agent to act on. */
45
+ export declare function timedOutNote(timeoutMs: number): string;
46
+ /**
47
+ * Whether a pulse other than the current one is at work in `moduleDir` - what changes there is that pulse's, and the
48
+ * audit leaves it.
49
+ */
50
+ export declare function anotherPulseIn(moduleDir: string): boolean;
51
+ /** Where each running turri records its groups, a file named for its process id: for its watcher, and the sweep. */
52
+ export declare function groupRecordsDir(): string;
53
+ /**
54
+ * Run `work` - a pulse - and kill every group it started when it ends, however it ends: what an agent left running in
55
+ * the background is the pulse's, and goes with it. Groups of a pulse running beside it are left alone. `modules`: the
56
+ * module folders it works in - its lanes - which the audit of another pulse's commands leaves to it.
57
+ */
58
+ export declare function withPulse<T>(work: () => Promise<T>, options?: {
59
+ modules?: string[];
60
+ }): Promise<T>;
61
+ /** Kill every group this turri started. Called as it exits; the tests call it between files. */
62
+ export declare function killAllGroups(): void;
63
+ /**
64
+ * Kill the groups turris that are gone left behind - killed outright, their watcher gone too - from their records in
65
+ * `dir`. A running turri's are its own. Returns how many groups were still there to kill.
66
+ */
67
+ export declare function sweepOrphanedGroups(dir?: string): number;
68
+ /**
69
+ * Run `command` with bash on this machine, from `cwd`, in a process group of its own.
70
+ *
71
+ * It has a time limit - COMMAND_TIMEOUT_MS unless given another - and ends at once when it is stopped, by the caller's
72
+ * signal or the job's; either way its whole group is killed. Ended on its own, what it left in the background runs on
73
+ * until its pulse ends.
74
+ */
75
+ export declare function runCommand(command: string, options: RunOptions): Promise<RunResult>;
76
+ /**
77
+ * Start `command` in the background, in a process group of its own, its output to `logFile` - a server an agent starts
78
+ * to try from outside. It is its pulse's: running until stopped (`stopGroup`), and killed when the pulse ends.
79
+ */
80
+ export declare function startInBackground(command: string, options: {
81
+ cwd: string;
82
+ env?: NodeJS.ProcessEnv;
83
+ wrap?: (argv: string[]) => string[];
84
+ logFile: string;
85
+ }): {
86
+ pid: number;
87
+ };
88
+ /** Whether a process is still running. */
89
+ export declare function isRunning(pid: number): boolean;
90
+ /** Stop a group started in the background: asked to end, then - after `graceMs` - made to. */
91
+ export declare function stopGroup(group: number, graceMs?: number): Promise<void>;
@@ -0,0 +1,57 @@
1
+ import { type TuiMouseEvent, type TuiMouseEventResult } from "@earendil-works/pi-tui";
2
+ import type { Job } from "./jobs.ts";
3
+ import { type JobsTreeState } from "./jobs-tree.ts";
4
+ import type { MarkedPage } from "./spec-map.ts";
5
+ import { type SpecMapState } from "./spec-map-view.ts";
6
+ import type { TranscriptStyle } from "./transcript-view.ts";
7
+ /**
8
+ * The side panel: the spec and how far the code has been regenerated, beside the conversation rather than instead of
9
+ * it.
10
+ *
11
+ * Two views. The regeneration (spec-map-view.ts), shown first: every item of the spec with where it stands - built,
12
+ * regenerating, planned, waiting, being taken out - under a row for each module, the one in focus open. And the
13
+ * pulses, as a tree - running, queued, finished, a line per pulse and all of what it builds once opened (see
14
+ * jobs-tree.ts). `p` goes from one to the other, the cursor with it: from an item to the pulse that regenerates it, and
15
+ * back. What the agents said and did is not shown here: it is in each pulse's log (job-log.ts).
16
+ */
17
+ export interface SidePanelOptions {
18
+ /** Every job, oldest first. */
19
+ jobs: () => Job[];
20
+ /** The regeneration's pages. Not given: the pulse list alone. */
21
+ map?: () => MarkedPage[];
22
+ /** Rows the panel may use. */
23
+ rows: () => number;
24
+ style: TranscriptStyle;
25
+ /** Back to the conversation: the panel closes. */
26
+ back: () => void;
27
+ /** Whether something in the conversation waits for the person - a question asked while the panel showed. */
28
+ waiting?: () => boolean;
29
+ /** Close the panel. */
30
+ close: () => void;
31
+ /**
32
+ * A module needs the person - `!`: the panel closes, and the chat takes it up with them - what went wrong, and what
33
+ * to do about it. Not given: the key is not offered.
34
+ */
35
+ discuss?: (page: MarkedPage) => void;
36
+ /** The key that opens and closes it, shown in the footer. */
37
+ key: string;
38
+ /**
39
+ * The panel over the whole screen, or beside the chat - `s` goes from one to the other. Beside it, `esc` gives the
40
+ * keys back to the chat and the panel stays. Not given: the key is not offered.
41
+ */
42
+ dock?: {
43
+ docked(): boolean;
44
+ toggle(): void;
45
+ };
46
+ /** The pulse list's tree - what is open, where the cursor is - kept across openings of the panel. */
47
+ tree?: JobsTreeState;
48
+ /** The regeneration's view - which page, what is open, where the cursor is, which view shows - kept the same way. */
49
+ mapState?: SpecMapState;
50
+ }
51
+ export declare function createSidePanel(options: SidePanelOptions): {
52
+ render(width: number): string[];
53
+ handleInput(data: string): void;
54
+ /** The wheel scrolls the panel wherever the keyboard is. */
55
+ handleMouse(event: TuiMouseEvent): TuiMouseEventResult | undefined;
56
+ invalidate(): void;
57
+ };
@@ -0,0 +1,139 @@
1
+ import type { Job } from "./jobs.ts";
2
+ import { type Mark, type MarkedItem, type MarkedPage } from "./spec-map.ts";
3
+ import type { TranscriptStyle } from "./transcript-view.ts";
4
+ /**
5
+ * The regeneration drawn: a page a module, an item a row - see spec-map.ts for what each mark means.
6
+ *
7
+ * Each item's first line, with its one mark in the gutter - its rung on the ladder; a changed item's changed
8
+ * sub-bullets under it, word by word; an item taken out as a struck-through ghost. Enter opens an item: all of it, its
9
+ * acceptance tests, the pulse that brings it, its conformance tests, and - a definition - the built specs that use it.
10
+ * One module is shown at a time, a tab a module of the chain - ←→ go from one to the next: the module regenerating now, until
11
+ * another tab is chosen, and again once another module starts regenerating. Under its own text, the files it imports, a
12
+ * folded block each. A chain of many modules nested one in another was too deep to read, and too much to draw.
13
+ */
14
+ export interface SpecMapState {
15
+ /** Which view the side panel shows: the map, or the pulse list. */
16
+ view: "map" | "pulses";
17
+ /** The row the cursor is on, and the key of what is there - it stays on the item when rows move. */
18
+ cursor: number;
19
+ cursorKey?: string;
20
+ /** The first line shown. */
21
+ top: number;
22
+ /** The items opened, by key. */
23
+ open: Set<string>;
24
+ /** Import blocks opened by hand, by where they are and file: the rest closed. */
25
+ imports: Map<string, boolean>;
26
+ /** The tab chosen by hand - its .plain file - and the module in focus when it was: another in focus, or it starts regenerating, the view follows that. */
27
+ tab?: {
28
+ file: string;
29
+ focus?: string;
30
+ };
31
+ /** An item to show - in its module and import block, opened for it - and put the cursor on: by .plain file and key. */
32
+ reveal?: {
33
+ file: string;
34
+ key: string;
35
+ };
36
+ }
37
+ export declare function createSpecMapState(): SpecMapState;
38
+ /** A row: a group's heading; an import block; an item. */
39
+ export type MapRow = {
40
+ kind: "group";
41
+ page: MarkedPage;
42
+ key: string;
43
+ label: string;
44
+ depth: number;
45
+ } | {
46
+ kind: "import";
47
+ page: MarkedPage;
48
+ file: string;
49
+ key: string;
50
+ open: boolean;
51
+ depth: number;
52
+ } | {
53
+ kind: "item";
54
+ page: MarkedPage;
55
+ item: MarkedItem;
56
+ key: string;
57
+ };
58
+ /** What a line shows, for the minimap: the mark of the item it belongs to. */
59
+ type LineMark = Mark | "removed" | undefined;
60
+ /**
61
+ * The module in focus: the one regenerating now, else the last the loop looks after - the module asked for, at the top of its
62
+ * chain - else the first.
63
+ */
64
+ export declare function focusOf(pages: MarkedPage[]): MarkedPage | undefined;
65
+ /** The module shown: the tab chosen by hand while the module in focus is as it was then, else the one in focus. */
66
+ export declare function shownPage(pages: MarkedPage[], state: SpecMapState): MarkedPage | undefined;
67
+ /** The tab `by` along from the one shown - the chain's order, the module it is built on to the left - its cursor at its top. */
68
+ export declare function switchTab(pages: MarkedPage[], state: SpecMapState, by: number): void;
69
+ /**
70
+ * The tabs, a module each in the chain's order, the one shown marked - those regenerating spin, those stuck say so - fitted to
71
+ * `width` around the one shown, what does not fit counted at either end.
72
+ */
73
+ export declare function tabBar(pages: MarkedPage[], shown: MarkedPage | undefined, width: number, style: TranscriptStyle, now: number): string;
74
+ /**
75
+ * Where an item stands, as one mark on a ladder every item climbs: planned, working, regenerated, validating, conform - and needs
76
+ * you, off it - named in the legend in the panel's corner. The same mark means the same thing whatever the config says
77
+ * of conformance tests: a functional spec regenerated and not conformed is hollow whether its tests are on, off or not
78
+ * chosen, so changing that changes no mark.
79
+ */
80
+ export declare const LADDER: {
81
+ readonly toRegenerate: "○";
82
+ readonly regenerated: "◇";
83
+ readonly conform: "◆";
84
+ readonly needsYou: "!";
85
+ readonly takenOut: "−";
86
+ };
87
+ /**
88
+ * An item's rung: what its one mark shows. Working is regenerating or taking out alike; validating, its conformance tests
89
+ * being written and run - a spinner of its own colour, the green of the rungs it is between.
90
+ */
91
+ export type Rung = "toRegenerate" | "working" | "regenerated" | "validating" | "conform" | "needsYou" | "takenOut" | "none";
92
+ export declare function rungOf(item: MarkedItem): Rung;
93
+ /** The two columns' headings, over the map - status, and the module's file - and a line of space under them. */
94
+ export declare function columnHeadings(page: MarkedPage, width: number, style: TranscriptStyle): string[];
95
+ /**
96
+ * The legend's lines, for the panel's lower right corner: every rung of the ladder, always - what a mark means never
97
+ * depends on the page - and to take out only where the page has something to take out.
98
+ */
99
+ export declare function legendLines(page: MarkedPage, style: TranscriptStyle): string[];
100
+ /** What the person is needed for, and how: the line under a page's first `!`, and its top line's end. */
101
+ export declare const DISCUSS_KEY = "d";
102
+ /** A line of ***plain highlighted as plyn highlights it: the whole line read, so a span over several words keeps its colour. */
103
+ export declare function highlighted(line: string, style: TranscriptStyle): string;
104
+ /** One line become another, word by word: what is gone struck through in red, what is new in green, the rest as it is. */
105
+ export declare function wordDiff(was: string, now: string, style: TranscriptStyle): string;
106
+ /**
107
+ * An item's text against the code record's, line by line: each line kept, or changed - paired with the line it was -
108
+ * or only on one side. Lines are a functional spec's first line and its sub-bullets.
109
+ */
110
+ export declare function lineDiff(was: string, now: string): Array<{
111
+ was?: string;
112
+ now?: string;
113
+ }>;
114
+ /**
115
+ * The rows of the module shown, top to bottom: its own items, then the files it imports, a block each under their
116
+ * heading, closed until opened. The modules it requires are tabs of their own.
117
+ */
118
+ export declare function specMapRows(pages: MarkedPage[], state: SpecMapState): MapRow[];
119
+ /**
120
+ * A page as lines: each row, the cursor's marked, a section's heading where one starts; where each row starts, for
121
+ * scrolling to it; and each line's mark, for the minimap.
122
+ */
123
+ export declare function specMapLines(pages: MarkedPage[], state: SpecMapState, width: number, style: TranscriptStyle, _jobs?: Job[], now?: number): {
124
+ lines: string[];
125
+ rowStarts: number[];
126
+ rows: MapRow[];
127
+ marks: LineMark[];
128
+ };
129
+ /** The progress strip: the page's functional specs, built, regenerating, planned and waiting, in their colours. */
130
+ export declare function progressStrip(page: MarkedPage, style: TranscriptStyle, cells?: number): string;
131
+ /** A module's row: opened or closed, its file, its strip, how many of its functional specs are built, and its status. */
132
+ /** The map's top line: the page's name, its strip and its count and status. */
133
+ export declare function specMapHeader(page: MarkedPage, width: number, style: TranscriptStyle, waiting?: string): string;
134
+ /**
135
+ * The minimap: a column down the right edge, a cell for each slice of the page - the most pressing mark in it - and
136
+ * the slice shown solid.
137
+ */
138
+ export declare function minimap(marks: LineMark[], height: number, top: number, style: TranscriptStyle): string[];
139
+ export {};