@turri-dev/cli 0.1.4-next.246fd84 → 0.1.4-next.ebd337a
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/dist/ask.js +34 -15
- package/dist/extension.js +3 -2
- package/dist/question-dialog.js +1 -0
- package/dist/regenerate/spec-map-view.js +11 -4
- package/docs/skills-and-gates.md +3 -1
- package/docs/using.md +3 -2
- package/package.json +1 -1
package/dist/ask.js
CHANGED
|
@@ -9,6 +9,9 @@ import { PANEL_KEY } from "./regenerate/job-panel.js";
|
|
|
9
9
|
export const OTHER_OPTION = "Something else…";
|
|
10
10
|
export const CHAT_OPTION = "Chat about this";
|
|
11
11
|
export const DONE_OPTION = "Done — that's all of them";
|
|
12
|
+
/** An option's box in a question of several, ticked and not. */
|
|
13
|
+
export const TICKED = "☑";
|
|
14
|
+
export const UNTICKED = "☐";
|
|
12
15
|
export const DISMISSED = "The user dismissed the question without answering.";
|
|
13
16
|
/** How an answer that is no answer starts: the person chose to talk about the question first. */
|
|
14
17
|
export const CHAT_PREFIX = "The user has not answered this question yet: they chose to talk about it first.";
|
|
@@ -107,32 +110,48 @@ export async function runAsk(asked, io) {
|
|
|
107
110
|
return choice;
|
|
108
111
|
}
|
|
109
112
|
}
|
|
110
|
-
// Pick several:
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
113
|
+
// Pick several: every option a box, ticked and unticked as it is chosen, until they say they are done. What they type
|
|
114
|
+
// is one more box, ticked - and can be unticked too. Something else, Chat about this and Done are no boxes.
|
|
115
|
+
const listed = [...options];
|
|
116
|
+
const ticked = new Set();
|
|
117
|
+
const picked = () => listed.filter((option) => ticked.has(option));
|
|
118
|
+
let at = 0;
|
|
119
|
+
for (;;) {
|
|
120
|
+
const rows = listed.map((option) => `${ticked.has(option) ? TICKED : UNTICKED} ${option}`);
|
|
121
|
+
const choice = await io.select(request.question, [...rows, ...extras, DONE_OPTION], context, at);
|
|
122
|
+
if (choice === undefined || choice === DONE_OPTION)
|
|
119
123
|
break;
|
|
120
124
|
if (choice === OTHER_OPTION) {
|
|
125
|
+
at = listed.length;
|
|
121
126
|
const typed = await typeInstead();
|
|
122
|
-
if (
|
|
123
|
-
|
|
127
|
+
if (typedNothing(typed))
|
|
128
|
+
continue;
|
|
129
|
+
const option = typed.trim();
|
|
130
|
+
if (!listed.includes(option))
|
|
131
|
+
listed.push(option);
|
|
132
|
+
ticked.add(option);
|
|
133
|
+
at = listed.indexOf(option);
|
|
124
134
|
continue;
|
|
125
135
|
}
|
|
126
136
|
if (choice === CHAT_OPTION) {
|
|
137
|
+
at = listed.length + extras.indexOf(CHAT_OPTION);
|
|
127
138
|
const said = await chatAbout();
|
|
128
139
|
if (typedNothing(said))
|
|
129
140
|
continue;
|
|
130
|
-
return chatAnswer(said,
|
|
141
|
+
return chatAnswer(said, picked());
|
|
131
142
|
}
|
|
132
|
-
|
|
133
|
-
|
|
143
|
+
// A row, or - where the answer is typed, on the command line - an option by its text, or one more of their own.
|
|
144
|
+
const row = rows.indexOf(choice);
|
|
145
|
+
const option = row !== -1 ? listed[row] : choice.trim();
|
|
146
|
+
if (!listed.includes(option))
|
|
147
|
+
listed.push(option);
|
|
148
|
+
if (ticked.has(option))
|
|
149
|
+
ticked.delete(option);
|
|
150
|
+
else
|
|
151
|
+
ticked.add(option);
|
|
152
|
+
at = listed.indexOf(option);
|
|
134
153
|
}
|
|
135
|
-
return
|
|
154
|
+
return ticked.size > 0 ? picked().join(", ") : DISMISSED;
|
|
136
155
|
}
|
|
137
156
|
/**
|
|
138
157
|
* While a question is open, what catches ctrl+h on the terminal's input: pi gives an extension's shortcut only the keys
|
package/dist/extension.js
CHANGED
|
@@ -90,11 +90,12 @@ aside) {
|
|
|
90
90
|
// The question, with what the asker gives to read for it - a brief to confirm - above it; what it said of its work
|
|
91
91
|
// before asking is kept in its record, never put in the dialog.
|
|
92
92
|
// A dialog of turri's own: a long brief scrolls above the question, and the options always show (question-dialog.ts).
|
|
93
|
-
const dialog = (question, context, options) => ctx.ui.custom((tui, theme, _keybindings, done) => {
|
|
93
|
+
const dialog = (question, context, options, selected) => ctx.ui.custom((tui, theme, _keybindings, done) => {
|
|
94
94
|
const shown = new QuestionDialog({
|
|
95
95
|
question,
|
|
96
96
|
...(context !== undefined ? { context } : {}),
|
|
97
97
|
...(options !== undefined ? { options } : {}),
|
|
98
|
+
...(selected !== undefined ? { selected } : {}),
|
|
98
99
|
rows: () => tui.terminal.rows,
|
|
99
100
|
style: { accent: (text) => theme.fg("accent", text), muted: (text) => theme.fg("muted", text), bold: (text) => theme.bold(text) },
|
|
100
101
|
done: (answer) => {
|
|
@@ -108,7 +109,7 @@ aside) {
|
|
|
108
109
|
return shown;
|
|
109
110
|
});
|
|
110
111
|
const asking = (asked) => runAsk(asked, {
|
|
111
|
-
select: (title, options, context) => dialog(title, context, options),
|
|
112
|
+
select: (title, options, context, at) => dialog(title, context, options, at),
|
|
112
113
|
input: (title, context) => dialog(title, context),
|
|
113
114
|
});
|
|
114
115
|
const bare = { ...request, said: undefined };
|
package/dist/question-dialog.js
CHANGED
|
@@ -323,13 +323,20 @@ function wrapped(text, width, colour = (line) => line) {
|
|
|
323
323
|
.flatMap((line) => (line === "" ? [""] : wrapTextWithAnsi(line, Math.max(10, width - CONTINUED.length))))
|
|
324
324
|
.map((line) => `${CONTINUED}${colour(line)}`);
|
|
325
325
|
}
|
|
326
|
+
/**
|
|
327
|
+
* Whether a new item is drawn as an addition: only beside code already built - a spec diff that adds it - never when the
|
|
328
|
+
* whole page is new, built for the first time or from scratch, where green would say nothing.
|
|
329
|
+
*/
|
|
330
|
+
function addedToBuilt(item, page) {
|
|
331
|
+
return item.state === "new" && page.items.some((other) => other.state === "built" || other.state === "changed" || other.state === "removed");
|
|
332
|
+
}
|
|
326
333
|
/** All of an item, opened: the rest of its text against the code's, and its acceptance tests. Where it stands is beside its mark. */
|
|
327
|
-
function detailLines(item, width, style) {
|
|
334
|
+
function detailLines(item, width, style, added) {
|
|
328
335
|
const lines = [];
|
|
329
336
|
// The rest of its text - its first line is the row - against the record's, for a change.
|
|
330
337
|
const rest = item.state === "changed" ? lineDiff(item.was ?? "", item.text).slice(1) : item.text.split("\n").slice(1).map((line) => ({ was: line, now: line }));
|
|
331
338
|
for (const line of rest) {
|
|
332
|
-
const drawn = item.state === "removed" ? style.removed(strike(line.now ?? "")) : item.state === "changed" ? diffLine(line, style) :
|
|
339
|
+
const drawn = item.state === "removed" ? style.removed(strike(line.now ?? "")) : item.state === "changed" ? diffLine(line, style) : added ? style.added(line.now ?? "") : highlighted(line.now ?? "", style);
|
|
333
340
|
lines.push(...wrapped(drawn, width));
|
|
334
341
|
}
|
|
335
342
|
if (item.acceptance.length > 0) {
|
|
@@ -476,7 +483,7 @@ export function specMapLines(pages, state, width, style, _jobs = [], now = Date.
|
|
|
476
483
|
? style.removed(strike(first))
|
|
477
484
|
: item.state === "changed" && wasFirst !== first
|
|
478
485
|
? wordDiff(wasFirst, first, style)
|
|
479
|
-
: item
|
|
486
|
+
: addedToBuilt(item, page)
|
|
480
487
|
? style.added(first)
|
|
481
488
|
: highlighted(first, style);
|
|
482
489
|
// Wrapped, never cut short: what follows a `…` is what a person came to read. The lines after the first hang
|
|
@@ -492,7 +499,7 @@ export function specMapLines(pages, state, width, style, _jobs = [], now = Date.
|
|
|
492
499
|
add(line, mark);
|
|
493
500
|
}
|
|
494
501
|
if (state.open.has(row.key)) {
|
|
495
|
-
for (const detail of detailLines(item, width, style))
|
|
502
|
+
for (const detail of detailLines(item, width, style, addedToBuilt(item, page)))
|
|
496
503
|
add(detail, mark);
|
|
497
504
|
return;
|
|
498
505
|
}
|
package/docs/skills-and-gates.md
CHANGED
|
@@ -133,7 +133,9 @@ change the step makes and puts its findings on the executor's next tool result.
|
|
|
133
133
|
- **Interview the user.** `ask_user` puts one question to the person. In the TUI it is a dialog;
|
|
134
134
|
from the CLI the options are numbered. Offering choices is required, not optional - a call with
|
|
135
135
|
neither `options` nor `free_form: true` is refused - and every list carries "Something else…".
|
|
136
|
-
`multi_select: true`
|
|
136
|
+
`multi_select: true` gives every option a box, ticked and unticked as it is chosen - a pick made by mistake is
|
|
137
|
+
undone by choosing it again - until they choose Done; what they type is one more box, ticked. "Something
|
|
138
|
+
else…", "Chat about this" and Done are no boxes. The skill's agent talks in a
|
|
137
139
|
session of its own that the person never sees, so what the person must read to answer - the brief
|
|
138
140
|
to confirm, the plan to approve - it passes as `ask_user`'s `context`, shown above the question in
|
|
139
141
|
the dialog; `brood`, `spawn` and `bud` pass their briefs so. The agents are told to keep it to what can be taken in at
|
package/docs/using.md
CHANGED
|
@@ -63,7 +63,7 @@ where it stopped. A project can have skills of its own, in `.turri/skills/` or `
|
|
|
63
63
|
| `lineage` | a module's lineage: what each regeneration and conformance run changed in it, and what it was regenerated from |
|
|
64
64
|
| `cultivate` | run a gated skill, its steps and review gates enforced |
|
|
65
65
|
| `release`, `activate` | try what is regenerated: release it to `dist/<module>` and activate it on this machine, installing what it needs - see [deploy](deploy.md) |
|
|
66
|
-
| `ask_user` | put a question to you as a dialog to pick from - several at once, "Something else…" to type, or "Chat about this" to talk it over first; Esc in either goes back to the options |
|
|
66
|
+
| `ask_user` | put a question to you as a dialog to pick from - several at once, each a box you tick and untick, "Something else…" to type, or "Chat about this" to talk it over first; Esc in either goes back to the options |
|
|
67
67
|
| `web_search`, `web_fetch` | search the web and read a page as text - documentation, an API, an error; `curl` and the like run in its `bash` |
|
|
68
68
|
|
|
69
69
|
What each render does, in order, is in [regenerating the code](regenerating.md).
|
|
@@ -175,7 +175,8 @@ come waits for a free slot, and says so.
|
|
|
175
175
|
|
|
176
176
|
A changed item shows what changed in it: its first line word by word - what is gone struck through in red,
|
|
177
177
|
what is new in green, what is kept highlighted as it reads now - and, under it, only the sub-bullets that changed. A new
|
|
178
|
-
item -
|
|
178
|
+
item beside code already built - one a spec diff adds - is green, all of it, so a new functional spec stands apart
|
|
179
|
+
from one changed; where everything is new, built for the first time or from scratch, nothing is. A spec never built that is taken
|
|
179
180
|
out is simply gone. The top line has a strip of the module's functional specs - built, regenerating, planned,
|
|
180
181
|
waiting - and how many are built, then what is happening: `pulse 3 of 8 regenerating`, or why nothing is -
|
|
181
182
|
`not asked to build - regenerate plans it` (turri was just opened, or nothing has asked for the module: the
|