@troylar/flightdeck 2.12.0 → 2.12.2
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 +22 -0
- package/README.md +4 -3
- package/bin/flightdeck.js +19 -24
- package/dist/flightdeck.html +189 -43
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
<!-- Generated by build.py from src/releases.json. Edit that file, not this one. -->
|
|
4
4
|
|
|
5
|
+
## 2.12.2 · Nov 2, 2026
|
|
6
|
+
|
|
7
|
+
AGENTS.md says what an assistant's draft checks really cover.
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **AGENTS.md says what draft checks load** (AI assistants). They say what the checks load and what they don't: people, step types, Jira workflows and which checklists are published. AGENTS.md lists flightdeck export. Update with flightdeck install or Settings; Team notes stay as they are. *Where:* Settings › AI assistant files
|
|
12
|
+
|
|
13
|
+
## 2.12.1 · Nov 2, 2026
|
|
14
|
+
|
|
15
|
+
Get your AI assistant started, and let it read all its instructions.
|
|
16
|
+
|
|
17
|
+
### New
|
|
18
|
+
|
|
19
|
+
- **Copy instructions for your assistant** (Settings). One button copies a first prompt for your assistant. It says to read AGENTS.md to the end, says where the skills are, and asks what you want done. Open the team folder itself as the workspace, in Agent mode, then paste it. *Where:* Settings › AI assistant files
|
|
20
|
+
- **Download skills ZIP** (Settings). Download the skills as a ZIP, made from what's already in the app file, with no network and no folder needed. It holds the same files flightdeck skills --to writes. What each skill is for, and what to ask for: docs/skills.md. *Where:* Settings › AI assistant files
|
|
21
|
+
|
|
22
|
+
### Fixed
|
|
23
|
+
|
|
24
|
+
- **AGENTS.md is short enough to be read to the end** (AI assistants). AGENTS.md is under 28 KiB, the safety rules come first, and the long formats moved to .flightdeck/skills/_flightdeck/file-formats.md. Every rule stays. Update it with flightdeck install or Settings; Team notes stay as they are. Keep Team notes to about 4 KiB.
|
|
25
|
+
- **A folder set up by a newer version is left alone** (AI assistants). flightdeck install, Settings and Folder health leave a folder a newer version set up alone, in the same words. An old default an older app left waiting is named, with its path, never merged or counted; it's safe to delete by hand. *Where:* Settings › AI assistant files
|
|
26
|
+
|
|
5
27
|
## 2.12.0 · Nov 1, 2026
|
|
6
28
|
|
|
7
29
|
AI assistant files, from the app.
|
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
## Quick start
|
|
26
26
|
|
|
27
27
|
1. `npx @troylar/flightdeck open` opens the app in your browser (needs Node 18 or later).
|
|
28
|
-
2. No Node? Save [flightdeck.html](https://unpkg.com/@troylar/flightdeck@2.12.
|
|
28
|
+
2. No Node? Save [flightdeck.html](https://unpkg.com/@troylar/flightdeck@2.12.2/dist/flightdeck.html) from the npm package as a file (right-click, **Save link as…**) and open that file in Edge or Chrome.
|
|
29
29
|
3. Choose **Look around the examples** to try it, or **Start your team** to set up your team's folder.
|
|
30
30
|
|
|
31
31
|
<p align="center"><a href="https://github.com/troylar/flightdeck/blob/main/docs/images/run-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/run-dark.png"><img src="https://raw.githubusercontent.com/troylar/flightdeck/main/docs/images/run-light.png" alt="A release in progress on the run screen: 7/15 answered in the header with Details, Screen share, Receipt and More; a strip saying you're recording, with Pause and Hand off and the run's details; Phases with each gate's state; the checklist with Next up pinned at its top; and the selected step, whose text shows the run's tag (Start the production deploy job v2026.10.16), with the values to copy, Record the result, Done, Done differently and Blocked" width="1000"></picture></a></p>
|
|
@@ -373,7 +373,7 @@ Thousands of runs open and refresh without stalling. Long lists show a page at a
|
|
|
373
373
|
|
|
374
374
|
## Skills for your AI assistant
|
|
375
375
|
|
|
376
|
-
**Settings → AI assistant files** in the app (or `flightdeck install` in a terminal) puts these in the team folder's `.flightdeck/skills/`, with an `AGENTS.md` that any assistant reads. They're plain `SKILL.md` files, so any assistant that supports skills can use them. Open the team folder with your assistant
|
|
376
|
+
**Settings → AI assistant files** in the app (or `flightdeck install` in a terminal) puts these in the team folder's `.flightdeck/skills/`, with an `AGENTS.md` that any assistant reads. They're plain `SKILL.md` files, so any assistant that supports skills can use them. Open the team folder itself as the workspace (in Agent mode, for Copilot in VS Code) and start with **Copy instructions for your assistant** on that screen. Then say what you need, or ask for a skill by name. [Skills for your AI assistant](https://github.com/troylar/flightdeck/blob/main/docs/skills.md) lists each one by job, with what to ask for:
|
|
377
377
|
|
|
378
378
|
| Skill | Does |
|
|
379
379
|
|---|---|
|
|
@@ -390,7 +390,7 @@ In `AGENTS.md`, only the part between the `flightdeck:begin` and `flightdeck:end
|
|
|
390
390
|
|
|
391
391
|
### AI assistant files, from the app
|
|
392
392
|
|
|
393
|
-
**Settings → AI assistant files** installs and updates `AGENTS.md` and the skills without a command line. Each file shows where it stands:
|
|
393
|
+
**Settings → AI assistant files** installs and updates `AGENTS.md` and the skills without a command line. **Copy instructions for your assistant** copies the first prompt to paste, and **Download skills ZIP** gives you the skills as a file, with no folder and no network. Each file shows where it stands:
|
|
394
394
|
|
|
395
395
|
| Status | Means |
|
|
396
396
|
|---|---|
|
|
@@ -477,6 +477,7 @@ Flightdeck was called Preflight before 1.9.0. Team folders, runs and published v
|
|
|
477
477
|
|---|---|---|
|
|
478
478
|
| [Checklist format](https://github.com/troylar/flightdeck/blob/main/docs/map-format.md) | Anyone writing checklists, and their AI assistant | Every mark, field and step type, and what stops a checklist from publishing |
|
|
479
479
|
| [Flightdeck and OneDrive](https://github.com/troylar/flightdeck/blob/main/docs/onedrive.md) | Whoever sets up the team folder | What keeps runs safe on a synced folder, and what it can't promise |
|
|
480
|
+
| [Skills for your AI assistant](https://github.com/troylar/flightdeck/blob/main/docs/skills.md) | Anyone working with an AI assistant | Starting one, what to ask for, each skill by job |
|
|
480
481
|
| [Updating Flightdeck](https://github.com/troylar/flightdeck/blob/main/docs/updating.md) | Whoever keeps the team's copy current | A step-by-step update, mixed versions and rolling back |
|
|
481
482
|
| [When something goes wrong](https://github.com/troylar/flightdeck/blob/main/docs/recovery.md) | Anyone who sees a warning | What each problem means and what to do, step by step |
|
|
482
483
|
| [Evidence packs](https://github.com/troylar/flightdeck/blob/main/docs/evidence.md) | Anyone who needs proof of a run | What's in a pack and how to check it |
|
package/bin/flightdeck.js
CHANGED
|
@@ -190,6 +190,14 @@ function classify(t, files, base, force) {
|
|
|
190
190
|
const parts = f.rel.split('/'), now = readInside(t.dir, parts), want = hash(managed(f.key, f.text));
|
|
191
191
|
return { key: f.key, rel: f.rel, baseKey: f.baseKey, parts, text: f.text, now, want, have: now === null ? null : hash(managed(f.key, now)), staged: staged(t, f.rel) };
|
|
192
192
|
});
|
|
193
|
+
/* An old copy an older app left (PF.contract.classifyCopies, the app's own rule, from the texts as read: a byte-order mark
|
|
194
|
+
kept): named, never merged, counted or removed. */
|
|
195
|
+
const K = contractRules();
|
|
196
|
+
items.forEach((i) => {
|
|
197
|
+
const all = i.staged, said = JSON.parse(JSON.stringify(K.classifyCopies({ key: i.key, baseKey: i.baseKey, shipped: i.text, version: t.version, base, active: i.now, copies: all.map((x) => ({ version: x.version, text: x.text })) })));
|
|
198
|
+
i.old = all.filter((x, n) => said[n] === 'old');
|
|
199
|
+
i.staged = all.filter((x, n) => said[n] !== 'old');
|
|
200
|
+
});
|
|
193
201
|
const why = decide(items.map((i) => ({ key: i.key, baseKey: i.baseKey, want: i.want, have: i.have, staged: i.staged.map((x) => ({ version: x.version, hash: hash(managed(i.key, x.text)) })) })), t.record, base, t.version, force);
|
|
194
202
|
return items.map((i, n) => Object.assign(i, why[n], { key: i.key }));
|
|
195
203
|
}
|
|
@@ -234,37 +242,23 @@ function merged(item) {
|
|
|
234
242
|
}
|
|
235
243
|
/* A record written by a newer Flightdeck (flightdeck-installed/2 on, or a must-understand feature): never read for meaning and
|
|
236
244
|
never rewritten. The same verdict as PF.contract.cleanInstalled (test/cli.test.js checks they agree). */
|
|
237
|
-
function installedNewer(r) {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
}
|
|
245
|
+
function installedNewer(r, mine) { return contractRules().recordNewer(r, mine); }
|
|
246
|
+
/* The app's own contract rules (PF.contract), from this package's app file, so a verdict the app, Folder health and this
|
|
247
|
+
command all reach is one function, never a copy. */
|
|
248
|
+
let engineRules = null;
|
|
249
|
+
function contractRules() { return (engineRules = engineRules || loadEngine().PF.contract); }
|
|
243
250
|
/* The folder's record, checked field by field. Anyone can edit it, so a record that isn't exactly what this command writes is
|
|
244
251
|
ignored (and said so), and only entries for files this version installs, with a well-formed hash, are read. */
|
|
245
252
|
function readRecord(t, keys) {
|
|
246
253
|
t.recordText = readInside(t.dir, t.recordAt);
|
|
247
|
-
const r = parseRecord(t.recordText, keys);
|
|
248
|
-
if (r.newer) fail(
|
|
254
|
+
const r = parseRecord(t.recordText, keys, t.version);
|
|
255
|
+
if (r.newer) fail(contractRules().outcomeWords({ state: 'newer', newer: r.newer }, { home: t.home, updates: t.updates, recordAt: t.recordAt.join('/'), version: t.version }).text);
|
|
249
256
|
return r;
|
|
250
257
|
}
|
|
251
258
|
/* The record's text as install reads it: the same as PF.contract.readRecord (test/assistant-files.test.js checks they agree). */
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
let r = null;
|
|
256
|
-
try { r = JSON.parse(text); } catch (e) { /* ignored below */ }
|
|
257
|
-
const newer = installedNewer(r);
|
|
258
|
-
if (newer) return { newer };
|
|
259
|
-
const ok = r && typeof r === 'object' && !Array.isArray(r) && r.format === 'flightdeck-installed/1' && typeof r.version === 'string' && /^(\d+\.\d+\.\d+|dev)$/.test(r.version)
|
|
260
|
-
&& typeof r.at === 'string' && (r.by === 'cli' || r.by === 'app') && r.files && typeof r.files === 'object' && !Array.isArray(r.files)
|
|
261
|
-
&& Object.keys(r.files).every((k) => typeof r.files[k] === 'string' && /^[0-9a-f]{64}$/.test(r.files[k]));
|
|
262
|
-
if (!ok) return Object.assign(none, { ignored: true });
|
|
263
|
-
/* files: what this command may consult; all: every entry, kept as it is for files this command doesn't handle. */
|
|
264
|
-
const files = {};
|
|
265
|
-
keys.forEach((k) => { if (Object.prototype.hasOwnProperty.call(r.files, k)) files[k] = r.files[k]; });
|
|
266
|
-
return { version: r.version, files, all: Object.assign({}, r.files) };
|
|
267
|
-
}
|
|
259
|
+
/* The record's text as install reads it: the app's own PF.contract.readRecord, so the app and this command parse it the same way
|
|
260
|
+
(copied out of the engine's context, so it compares as a plain object here). */
|
|
261
|
+
function parseRecord(text, keys, mine) { return JSON.parse(JSON.stringify(contractRules().readRecord(text === undefined ? null : text, keys, mine))); }
|
|
268
262
|
function stamp(d) { const p = (n) => String(n).padStart(2, '0'); return d.getFullYear() + '-' + p(d.getMonth() + 1) + '-' + p(d.getDate()) + ' ' + p(d.getHours()) + p(d.getMinutes()); }
|
|
269
263
|
function fineStamp(d) { const p = (n, w) => String(n).padStart(w || 2, '0'); return stamp(d).replace(' ', '-') + p(d.getSeconds()) + '-' + p(d.getMilliseconds(), 3); }
|
|
270
264
|
|
|
@@ -417,6 +411,7 @@ const LABEL = { current: 'up to date', update: 'updated', new: 'added', missing:
|
|
|
417
411
|
const CHECK_LABEL = { update: 'update available', new: 'will be added', missing: 'will be added again', merge: 'needs merge', forced: 'will be replaced (--force)', kept: 'kept (your team changed it)' };
|
|
418
412
|
function report(items, check, out) {
|
|
419
413
|
items.filter((i) => i.status !== 'current').forEach((i) => out.push(' ' + (i.changed ? 'changed during install' : (check ? CHECK_LABEL : LABEL)[i.status]).padEnd(28) + i.rel + (i.waiting ? ' (still waiting in updates/' + i.waiting + ')' : '')));
|
|
414
|
+
items.filter((i) => i.old && i.old.length).forEach((i) => out.push(' ' + 'old copy, nothing to merge'.padEnd(28) + i.rel + ' (left in updates/' + i.old.map((x) => x.version).join(', ') + ' by an older Flightdeck; safe to delete by hand)'));
|
|
420
415
|
}
|
|
421
416
|
/* What install says after the file list: an ignored record, and files left alone because they changed while it ran. */
|
|
422
417
|
function notes(t, out) {
|