@troylar/flightdeck 2.6.1 → 2.8.0
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/CHANGELOG.md +32 -0
- package/README.md +9 -1
- package/bin/flightdeck.js +23 -3
- package/dist/flightdeck.html +1505 -77
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,38 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- Generated by build.py from src/releases.json. Edit that file, not this one. -->
|
|
4
4
|
|
|
5
|
+
## 2.8.0 · Oct 26, 2026
|
|
6
|
+
|
|
7
|
+
Nested processes that know what the child needs.
|
|
8
|
+
|
|
9
|
+
### New
|
|
10
|
+
|
|
11
|
+
- **Pick the process a step runs from a list** (Editor). A Run another process step chooses its process from a list of this folder's checklists, with each one's latest version, and picks Latest or one version to always run. Other ID… still takes a process that isn't here yet. *Where:* Editing a draft, a Run another process step
|
|
12
|
+
- **Say where each of the child's details comes from** (Editor). What the child needs lists every run detail of the checklist it runs. Each one comes from one of this run's details (under another name if you like), a fixed value, or is asked when the child starts. The Markdown gets a pass: line, for example pass: environment=^env, region=us-east-1, notify=?. *Where:* Editing a draft, a Run another process step
|
|
13
|
+
- **Publishing checks what a step passes against the child as it is now** (Checks). A name the child doesn't have, a fixed value of the wrong kind, or a detail that isn't listed stops publishing, read from the folder at that moment. A child published later without a detail a step names is flagged in Folder health, with a way to open the checklist that needs changing. *Where:* Checks, publishing and Folder health
|
|
14
|
+
- **The child's start form opens already filled in** (Runs). Starting a child shows what this run passes and where each value comes from, and asks only what's left, with the roles. A value that doesn't fit keeps the form open with what you typed. If a passed detail changes while you fill it in, nothing starts and it says why. With nothing to ask, the child starts at once, as before. *Where:* The run screen, a Run another process step
|
|
15
|
+
- **Each step says which details it uses and sets** (Editor). A selected step lists the run details it uses (its text, fields, conditions and what it passes) and the ones it sets. *Where:* Editing a draft, the step form
|
|
16
|
+
|
|
17
|
+
### Improved
|
|
18
|
+
|
|
19
|
+
- **Rename keeps what linked steps pass** (Editor). Renaming a detail rewrites this checklist's carry: and pass: lines so each child detail gets the same value. A checklist that runs this one at its latest and passes the old name gets a warning with the fix, and Folder health flags it once this is published. *Where:* Editing a draft, Checklist details
|
|
20
|
+
- **A checklist with a pass: line needs Flightdeck 2.8** (Compatibility). A version with a pass: line, and its runs, open only in Flightdeck 2.8 or later; earlier copies name the version and won't run it. A checklist without one publishes exactly as before and runs in every 2.x copy. *Where:* Publishing and older copies
|
|
21
|
+
|
|
22
|
+
## 2.7.0 · Oct 26, 2026
|
|
23
|
+
|
|
24
|
+
Boxes that know your details.
|
|
25
|
+
|
|
26
|
+
### New
|
|
27
|
+
|
|
28
|
+
- **Type ^ to put a run detail in a step, a gate or a field** (Editor). Typing ^ in a step's text, a gate's approval or a text field lists the checklist's run details, with where each comes from; Enter or a click puts it in. Insert a detail does the same, and Add ^name as a run detail adds one you haven't listed yet. The detail stays where you typed it in the step's text. *Where:* Editing a draft, the step and gate forms
|
|
29
|
+
- **A misspelled detail is marked, with a one-click fix** (Editor). Each ^detail in a box is marked: fine, not a run detail, or maybe not set yet at that step. A misspelled one offers Use ^environment, and one the run may reach before it's set names the step that sets it, with Show that step. *Where:* Editing a draft, under each box
|
|
30
|
+
- **See a box filled in, the way a run will show it** (Editor). In a run: under a box shows it with the values from this checklist's latest run, exactly as the run screen will. *Where:* Editing a draft, under each box that holds a ^detail
|
|
31
|
+
- **Rename a run detail everywhere at once** (Editor). Rename in Checklist details changes the detail in its list, step text, gate approvals, fields, only when and sets, as one Undo step. It says how often each detail is used, and refuses when another checklist receives the detail by that name. *Where:* Editing a draft, Checklist details
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
|
|
35
|
+
- **A caret that isn't a run detail stays as written** (Runs). A field like grep ^ERROR shows ^ERROR in a run, and Checks name it as a tip, with the detail it likely meant. *Where:* The run screen and Checks
|
|
36
|
+
|
|
5
37
|
## 2.6.1 · Oct 25, 2026
|
|
6
38
|
|
|
7
39
|
Documentation that matches the app.
|
package/README.md
CHANGED
|
@@ -111,6 +111,14 @@ You don't have to write Markdown. **New process** on the Processes page asks for
|
|
|
111
111
|
|
|
112
112
|
**The step form** asks a question for each box, with a gray example and why it matters. It shows only the boxes the step's type usually needs, and any that hold a value; the rest are one click away behind **+ add** buttons. The fields every step accepts (a link, how long it takes, a deadline, proof, a time) are under **More about this step**. A choice of five or fewer is a row of buttons. **When it's checked, they record** lists exactly what a run will ask for. In the outline, drag a step or press Alt+Up / Alt+Down to move it, and **Undo** and **Redo** step through changes.
|
|
113
113
|
|
|
114
|
+
**Details in any box.** Type `^` in a step's text, a gate's approval or a text field to pick a run detail, or use **Insert a detail**. A misspelled one is marked with a one-click fix ("Use ^environment"), and a detail that may not be set yet at that step says which step sets it. **In a run:** under the box shows it filled in, with the values from your latest run. A caret that isn't a detail, like `grep ^ERROR`, stays as written. To rename a detail everywhere at once, use **Rename** in Checklist details; a linked step in this checklist keeps passing the same value to its child. If another checklist runs this one at its latest and passes the detail by the old name, Rename says so, and Folder health flags that checklist once this version is published, until it's changed to match.
|
|
115
|
+
|
|
116
|
+
<p align="center"><a href="https://github.com/troylar/flightdeck/blob/main/docs/images/autocomplete-light.png" title="Open in GitHub's image viewer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/troylar/flightdeck/main/docs/images/autocomplete-dark.png"><img src="https://raw.githubusercontent.com/troylar/flightdeck/main/docs/images/autocomplete-light.png" alt="A Jenkins step's parameters box: typing ^en offers ^environment, a text detail asked when a run starts, or adding ^en as a new run detail" width="49%"></picture></a> <a href="https://github.com/troylar/flightdeck/blob/main/docs/images/rename-light.png" title="Open in GitHub's image viewer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/troylar/flightdeck/main/docs/images/rename-dark.png"><img src="https://raw.githubusercontent.com/troylar/flightdeck/main/docs/images/rename-light.png" alt="Checklist details: each run detail with how many places use it and Rename; renaming ^tag to build_tag lists the steps that follow it" width="49%"></picture></a></p>
|
|
117
|
+
|
|
118
|
+
**Run another process.** A step can start another checklist as a linked run. Pick the process from a list, and say where each of its details comes from: one of this run's details (under another name if you like), a fixed value, or asked when it starts. Publishing checks that against the other checklist as it is now. When you start it, its form opens with what's passed already filled in and asks only what's left (2.8).
|
|
119
|
+
|
|
120
|
+
<p align="center"><a href="https://github.com/troylar/flightdeck/blob/main/docs/images/nested-light.png" title="Open in GitHub's image viewer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/troylar/flightdeck/main/docs/images/nested-dark.png"><img src="https://raw.githubusercontent.com/troylar/flightdeck/main/docs/images/nested-light.png" alt="A linked step in the editor: Check in code chosen from a list, Latest when this run starts, and what Check in code needs: branch asked when it starts, commit from this run's ^commit, story from this run's ^ticket" width="38%"></picture></a> <a href="https://github.com/troylar/flightdeck/blob/main/docs/images/child-start-light.png" title="Open in GitHub's image viewer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/troylar/flightdeck/main/docs/images/child-start-dark.png"><img src="https://raw.githubusercontent.com/troylar/flightdeck/main/docs/images/child-start-light.png" alt="Starting the Check in code run: commit and story passed from this run, branch asked, and who's doing what" width="60%"></picture></a></p>
|
|
121
|
+
|
|
114
122
|
**Save draft** saves your work. **Review & publish** goes back to the process page: there you can compare the draft with the last version, write what changed in one line, and choose **Publish vN**. Anything that blocks publishing disables the button; suggestions don't. A save goes through only if the draft is still what you opened; if a teammate changed it meanwhile, nothing is saved and you choose between their version and yours. A shared folder can't lock a file, so edit a draft with one person (or one AI assistant) at a time.
|
|
115
123
|
|
|
116
124
|
<a href="https://github.com/troylar/flightdeck/blob/main/docs/images/edit-light.png" title="Open in GitHub's image viewer"><picture><source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/troylar/flightdeck/main/docs/images/edit-dark.png"><img src="https://raw.githubusercontent.com/troylar/flightdeck/main/docs/images/edit-light.png" alt="Editing a draft as Markdown, with Practice, Save draft and Review & publish in the header: the open corrections with links to their lines, the Markdown on the left, and the Checks and Preview tabs on the right"></picture></a>
|
|
@@ -215,7 +223,7 @@ roles: release-lead, qa, backend
|
|
|
215
223
|
| `## Gate:` · `approves:` | The pause point, and exactly what passing it approves |
|
|
216
224
|
| `### Track: Name @role` | Parallel work inside a phase |
|
|
217
225
|
| `at:` · `due:` · `after:` | A clock time, a deadline, or a due time after the run starts |
|
|
218
|
-
| `{run.process}` · `carry:` · `version:` | Start another process as a linked child run, passing these details, on an exact version if you name one |
|
|
226
|
+
| `{run.process}` · `carry:` · `pass:` · `version:` | Start another process as a linked child run, passing these details (under another name, as a fixed value, or asked when it starts, with `pass:`, 2.8), on an exact version if you name one |
|
|
219
227
|
| `group:` · `tags:` | Where the process sits in your hierarchy, and how to find it |
|
|
220
228
|
| `context: rows:number, due:date` | Typed run details (number, yes-no, date, choice, link), checked as they're typed |
|
|
221
229
|
| `> note` · `` | A note or screenshot, under a step, a phase or a gate |
|
package/bin/flightdeck.js
CHANGED
|
@@ -1500,7 +1500,26 @@ async function draftMain(argv) {
|
|
|
1500
1500
|
try { eng = loadEngine(); dir = folderArg(args[2], 'draft ' + sub); } catch (e) { return draftFail(eng, 'failed', e.message); }
|
|
1501
1501
|
const PF = eng.PF, PP = PF.proposals, U = PF.util, M = PF.map, now = Date.now();
|
|
1502
1502
|
const session = val['--session'] || 's-' + U.randomId(12);
|
|
1503
|
-
|
|
1503
|
+
/* The same checks the app shows, with each linked step's child read from publications/ (2.8), so what a step passes is
|
|
1504
|
+
checked against the child as it is in the folder. */
|
|
1505
|
+
const checksOf = async (t) => {
|
|
1506
|
+
const map = M.parse(t), procs = {}, names = [];
|
|
1507
|
+
M.steps(map).forEach((x) => { const f = x.step.fields || {}; if (x.step.type === 'run.process' && f.process && names.indexOf(f.process) < 0) names.push(f.process); });
|
|
1508
|
+
/* The children are read through a problem ledger of their own, so a child that couldn't be read makes the answer partial. */
|
|
1509
|
+
const L = PF.repo.ledger(readAdapter(dir, { maxBytes: READ_MAX })), rfs = L.fs;
|
|
1510
|
+
for (const n of names) {
|
|
1511
|
+
try {
|
|
1512
|
+
const p = await PF.repo.readProcess(rfs, n);
|
|
1513
|
+
if (p) procs[n] = p;
|
|
1514
|
+
/* A version that read but can't be used is named as READ names one; a failed read the ledger already has. */
|
|
1515
|
+
(p ? p.broken : []).forEach((x) => { if (!x._readFailed) { const k = PF.appjson.pubProblem(x); L.note('publications/' + n + '/' + x.folder + '/', k.kind, k.why); } });
|
|
1516
|
+
} catch (e) { procs[n] = { latest: null, all: [], clashes: [], broken: [], unlisted: 'publications/' + n + '/ couldn\'t be read' }; }
|
|
1517
|
+
}
|
|
1518
|
+
const c = M.check(map, { people: [], types: {}, workflows: {}, processes: [], children: PF.links.childrenFrom(procs) });
|
|
1519
|
+
return { checks: { blockers: c.blockers, suggestions: c.suggestions }, problems: L.problems() };
|
|
1520
|
+
};
|
|
1521
|
+
/* Every problem once: the draft's reads, then the children's. */
|
|
1522
|
+
const merged = (a, b) => { const seen = {}, out = []; a.concat(b).forEach((p) => { const k = p.path + '\u0000' + p.kind; if (!seen[k]) { seen[k] = true; out.push(p); } }); return out; };
|
|
1504
1523
|
try {
|
|
1505
1524
|
if (sub === 'read') {
|
|
1506
1525
|
const s = await draftState(eng, dir, proc, session);
|
|
@@ -1510,8 +1529,9 @@ async function draftMain(argv) {
|
|
|
1510
1529
|
const cf = pending ? { rev: pending.rev, kind: 'proposal', ref: pending.id, text: pending.text }
|
|
1511
1530
|
: s.draft.exists && s.draft.text != null ? { rev: s.draft.rev, kind: 'draft', ref: s.draft.path, text: s.draft.text }
|
|
1512
1531
|
: latest ? { rev: latest.rev, kind: 'version', ref: latest.folder, text: latest.text } : { rev: PP.sha(''), kind: 'none', ref: null, text: '' };
|
|
1532
|
+
const ck = await checksOf(cf.text), problems = merged(s.problems, ck.problems);
|
|
1513
1533
|
const out = draftJson(eng, { process: proc, session, draft: s.draft, openIn: s.presence.openIn, mine: s.mine.map((m) => ({ id: m.id, rev: m.rev, status: m.status, text: m.text })),
|
|
1514
|
-
continueFrom: cf, checks:
|
|
1534
|
+
continueFrom: cf, checks: ck.checks, copies: s.copies, readAt: new Date(now).toISOString(), complete: problems.length === 0, problems });
|
|
1515
1535
|
return { out: JSON.stringify(out, null, 2), code: out.complete ? 0 : EXIT.partial };
|
|
1516
1536
|
}
|
|
1517
1537
|
/* save and propose: the input and every flag are checked before anything is read or written. */
|
|
@@ -1530,7 +1550,7 @@ async function draftMain(argv) {
|
|
|
1530
1550
|
const base = PP.baseFor({ expect: val['--expect'], draft: s.draft, mine: s.mine, versions: s.versions, baseText, afterEarlier: argv.includes('--after-earlier') });
|
|
1531
1551
|
if (base.missing) return draftFail(eng, 'missing-base', 'The text you started from isn\'t the draft, one of this session\'s proposals or a published version any more. Pass the text you read with --base, or read the draft again.');
|
|
1532
1552
|
const operation = PP.newId(now, U.randomId(10)), at = new Date(now).toISOString();
|
|
1533
|
-
const result = { process: proc, session, operation, outcome: null, why: null, link: base.link, rev: PP.sha(text), file: null, ids: PP.ids(base.text, text), checks: checksOf(text), warnings: [], history: null };
|
|
1553
|
+
const result = { process: proc, session, operation, outcome: null, why: null, link: base.link, rev: PP.sha(text), file: null, ids: PP.ids(base.text, text), checks: (await checksOf(text)).checks, warnings: [], history: null };
|
|
1534
1554
|
if (result.ids.removed.length) result.warnings.push('This removes step or phase IDs: ' + result.ids.removed.join(', ') + '. Runs and skills that name them will need a look.');
|
|
1535
1555
|
let why = sub === 'propose' ? 'asked' : s.presence.open ? 'open' : null;
|
|
1536
1556
|
const draftNow = s.draft.exists ? s.draft.text : null, expectText = base.kind === 'none' || base.kind === 'version' ? null : base.text;
|