dorfl 0.3.2 → 0.4.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/dist/cli.d.ts +9 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +108 -0
- package/dist/cli.js.map +1 -1
- package/dist/prd-to-spec.d.ts +3 -52
- package/dist/prd-to-spec.d.ts.map +1 -1
- package/dist/prd-to-spec.js +12 -94
- package/dist/prd-to-spec.js.map +1 -1
- package/dist/resync-protocol.d.ts +73 -0
- package/dist/resync-protocol.d.ts.map +1 -0
- package/dist/resync-protocol.js +114 -0
- package/dist/resync-protocol.js.map +1 -0
- package/dist/skills/setup/SKILL.md +1 -1
- package/package.json +1 -1
- package/src/cli.ts +157 -0
- package/src/prd-to-spec.ts +18 -140
- package/src/resync-protocol.ts +162 -0
package/dist/cli.d.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
|
+
import { type ResyncResult } from './resync-protocol.js';
|
|
3
4
|
import { type InstallSkillsResult } from './install-skills.js';
|
|
5
|
+
/**
|
|
6
|
+
* Human-readable report for the deterministic protocol re-sync half of
|
|
7
|
+
* `dorfl sync`. Groups the docs into changed / unchanged / skipped and names the
|
|
8
|
+
* VERSION file. `dryRun` reframes it as "WOULD" so a preview reads honestly.
|
|
9
|
+
* A SKIPPED doc (unresolvable source) is surfaced LOUDLY — the contract in the
|
|
10
|
+
* target repo is incomplete for that doc.
|
|
11
|
+
*/
|
|
12
|
+
export declare function formatSyncReport(result: ResyncResult, dryRun: boolean): string;
|
|
4
13
|
export declare function buildProgram(): Command;
|
|
5
14
|
/**
|
|
6
15
|
* Human-readable report for `dorfl skills add`. Prints the SOURCE the skills
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAC,OAAO,EAAS,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,OAAO,EAAC,OAAO,EAAS,MAAM,WAAW,CAAC;AAmH1C,OAAO,EAAiB,KAAK,YAAY,EAAC,MAAM,sBAAsB,CAAC;AAuCvE,OAAO,EAAgB,KAAK,mBAAmB,EAAC,MAAM,qBAAqB,CAAC;AA2xB5E;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC/B,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,OAAO,GACb,MAAM,CAoCR;AA6RD,wBAAgB,YAAY,IAAI,OAAO,CAs3GtC;AAaD;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACpC,MAAM,EAAE,mBAAmB,EAC3B,KAAK,EAAE,OAAO,GACZ,MAAM,CAyBR;AA+FD;;;;;GAKG;AACH,wBAAsB,MAAM,CAAC,IAAI,GAAE,MAAM,EAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAQzE"}
|
package/dist/cli.js
CHANGED
|
@@ -46,6 +46,7 @@ import { renderPrompt } from './prompt.js';
|
|
|
46
46
|
import { resolvePromptGuidance } from './config.js';
|
|
47
47
|
import { gc, RETAIN_REASON_TEXT } from './gc.js';
|
|
48
48
|
import { runPrdToSpec, } from './prd-to-spec.js';
|
|
49
|
+
import { resyncProtocol } from './resync-protocol.js';
|
|
49
50
|
import { sweepRemoteMergedBranches } from './reap-branches.js';
|
|
50
51
|
import { sweepOrphanSidecars } from './orphan-sidecar.js';
|
|
51
52
|
import { sweepLedgerDuplicates, formatLedgerSweep } from './ledger-lint.js';
|
|
@@ -512,6 +513,60 @@ function printPrdToSpecReport(result) {
|
|
|
512
513
|
function printLeak(leak) {
|
|
513
514
|
console.error(` [${leak.lens}] ${leak.where}: '${leak.token}' — ${leak.why}`);
|
|
514
515
|
}
|
|
516
|
+
/**
|
|
517
|
+
* A minimal interactive yes/no confirmation (default NO). Prompts on stderr
|
|
518
|
+
* (stdout stays reserved for machine/report output) and reads one line from
|
|
519
|
+
* stdin. Callers only reach this on an interactive (TTY) session — a non-TTY
|
|
520
|
+
* path decides WITHOUT prompting (so a scripted run never hangs). Returns true
|
|
521
|
+
* only for an explicit `y`/`yes`.
|
|
522
|
+
*/
|
|
523
|
+
function confirmYesNo(message) {
|
|
524
|
+
return new Promise((resolvePrompt) => {
|
|
525
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
526
|
+
rl.question(`${message} [y/N] `, (answer) => {
|
|
527
|
+
rl.close();
|
|
528
|
+
const a = answer.trim().toLowerCase();
|
|
529
|
+
resolvePrompt(a === 'y' || a === 'yes');
|
|
530
|
+
});
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* Human-readable report for the deterministic protocol re-sync half of
|
|
535
|
+
* `dorfl sync`. Groups the docs into changed / unchanged / skipped and names the
|
|
536
|
+
* VERSION file. `dryRun` reframes it as "WOULD" so a preview reads honestly.
|
|
537
|
+
* A SKIPPED doc (unresolvable source) is surfaced LOUDLY — the contract in the
|
|
538
|
+
* target repo is incomplete for that doc.
|
|
539
|
+
*/
|
|
540
|
+
export function formatSyncReport(result, dryRun) {
|
|
541
|
+
const lines = [];
|
|
542
|
+
const changed = result.docs.filter((d) => !d.unchanged && !d.skipped);
|
|
543
|
+
const unchanged = result.docs.filter((d) => d.unchanged);
|
|
544
|
+
const skipped = result.docs.filter((d) => d.skipped);
|
|
545
|
+
const verb = dryRun ? 'WOULD sync' : 'Synced';
|
|
546
|
+
lines.push(dryRun
|
|
547
|
+
? '=== dorfl sync (DRY RUN — nothing written) ==='
|
|
548
|
+
: '=== dorfl sync ===');
|
|
549
|
+
lines.push(`Protocol: ${verb} ${result.docs.length} doc(s) — ` +
|
|
550
|
+
`${changed.length} changed, ${unchanged.length} unchanged, ` +
|
|
551
|
+
`${skipped.length} skipped.`);
|
|
552
|
+
for (const d of changed) {
|
|
553
|
+
lines.push(` ~ ${d.dest}`);
|
|
554
|
+
}
|
|
555
|
+
for (const d of skipped) {
|
|
556
|
+
lines.push(` !! ${d.name}: SOURCE could not be resolved — NOT copied ` +
|
|
557
|
+
'(the contract doc is missing in the package).');
|
|
558
|
+
}
|
|
559
|
+
if (changed.length > 0 || skipped.length === result.docs.length) {
|
|
560
|
+
lines.push(`VERSION: ${dryRun ? 'WOULD bump' : 'bumped'} ${result.versionPath}` +
|
|
561
|
+
(skipped.length === result.docs.length
|
|
562
|
+
? ' (no doc synced — no bump)'
|
|
563
|
+
: '.'));
|
|
564
|
+
}
|
|
565
|
+
else {
|
|
566
|
+
lines.push(`VERSION: unchanged (${result.versionPath} — already current).`);
|
|
567
|
+
}
|
|
568
|
+
return lines.join('\n');
|
|
569
|
+
}
|
|
515
570
|
/**
|
|
516
571
|
* Resolve a task-only command's slug argument through the §3a namespace guard
|
|
517
572
|
* (`resolveTaskOnlyArg`): accept bare (= task) + `task:` (explicit alias),
|
|
@@ -2460,6 +2515,59 @@ export function buildProgram() {
|
|
|
2460
2515
|
}
|
|
2461
2516
|
console.log(`Summary: ${result.reaped.length} reaped, ${result.retained.length} retained.`);
|
|
2462
2517
|
});
|
|
2518
|
+
// `dorfl sync`: bring an already-onboarded repo up to the CURRENT protocol.
|
|
2519
|
+
// Always re-syncs `work/protocol/*` + bumps VERSION (the deterministic slice of
|
|
2520
|
+
// `setup`, shared with `prd-to-spec` via `resync-protocol.ts`). `--add-skills`
|
|
2521
|
+
// ADDITIONALLY (re-)installs the packaged skills into the operator's harness
|
|
2522
|
+
// dir(s), NON-INTERACTIVELY (the flag IS the confirmation); without it an
|
|
2523
|
+
// interactive session PROMPTS once and a non-TTY session skips skills.
|
|
2524
|
+
program
|
|
2525
|
+
.command('sync')
|
|
2526
|
+
.helpGroup(HEADLINE_GROUP)
|
|
2527
|
+
.description("Bring THIS repo up to the current dorfl protocol: re-sync work/protocol/* from the package's canonical contract docs and bump work/protocol/VERSION (idempotent — a no-op when already current). This is how a repo that adopted an older protocol picks up the latest. Optionally ALSO (re-)installs the packaged dorfl skills into your own harness: pass --add-skills to do it non-interactively (the flag bypasses the ask), otherwise an interactive run prompts once (a non-TTY run skips skills). Runs IN-PLACE (no git commit/push — the human commits the result).")
|
|
2528
|
+
.option('--repo <dir>', 'the repo working-tree root to sync (default: cwd)')
|
|
2529
|
+
.option('--dry-run', 'REPORT what the protocol re-sync WOULD change, touching nothing (no writes; skills are never installed under --dry-run)')
|
|
2530
|
+
.option('--add-skills', 'ALSO (re-)install the packaged dorfl skills into your own harness dir(s), non-interactively. This flag IS the confirmation — it bypasses the interactive ask.')
|
|
2531
|
+
.option('--local', 'with skills install: scope to <cwd>/.agents/skills/ instead of the global ~/.agents/skills/ default')
|
|
2532
|
+
.option('--json', 'output the raw protocol re-sync result as JSON')
|
|
2533
|
+
.action(async (flags) => {
|
|
2534
|
+
const repoPath = flags.repo ?? process.cwd();
|
|
2535
|
+
const dryRun = flags.dryRun === true;
|
|
2536
|
+
// 1. The deterministic protocol re-sync (always runs).
|
|
2537
|
+
const resync = resyncProtocol(repoPath, {
|
|
2538
|
+
dryRun,
|
|
2539
|
+
sourceCommit: 'dorfl sync',
|
|
2540
|
+
});
|
|
2541
|
+
if (flags.json) {
|
|
2542
|
+
console.log(JSON.stringify(resync, null, 2));
|
|
2543
|
+
}
|
|
2544
|
+
else {
|
|
2545
|
+
console.log(formatSyncReport(resync, dryRun));
|
|
2546
|
+
}
|
|
2547
|
+
// A doc whose source could not be resolved is a broken package — exit
|
|
2548
|
+
// non-zero so a scripted `sync` notices the incomplete contract.
|
|
2549
|
+
const anySkipped = resync.docs.some((d) => d.skipped);
|
|
2550
|
+
// 2. The OPTIONAL skills install. Never under --dry-run (a preview writes
|
|
2551
|
+
// nothing). `--add-skills` authorises it directly (bypasses the ask);
|
|
2552
|
+
// otherwise an interactive TTY prompts once, and a non-TTY skips.
|
|
2553
|
+
if (!dryRun) {
|
|
2554
|
+
let doSkills = flags.addSkills === true;
|
|
2555
|
+
if (!doSkills && process.stdin.isTTY) {
|
|
2556
|
+
const scope = flags.local === true ? 'project-local' : 'global';
|
|
2557
|
+
doSkills = await confirmYesNo(`Also (re-)install the packaged dorfl skills into your ${scope} harness dir(s)?`);
|
|
2558
|
+
}
|
|
2559
|
+
if (doSkills) {
|
|
2560
|
+
const result = installSkills({ global: flags.local !== true });
|
|
2561
|
+
console.log(formatSkillsAddReport(result, flags.local === true));
|
|
2562
|
+
}
|
|
2563
|
+
else if (flags.addSkills !== true && !process.stdin.isTTY) {
|
|
2564
|
+
console.error('>> Skills not installed (non-interactive run; pass --add-skills to install them).');
|
|
2565
|
+
}
|
|
2566
|
+
}
|
|
2567
|
+
if (anySkipped) {
|
|
2568
|
+
process.exit(1);
|
|
2569
|
+
}
|
|
2570
|
+
});
|
|
2463
2571
|
program
|
|
2464
2572
|
.command('prd-to-spec')
|
|
2465
2573
|
.helpGroup(ADVANCED_GROUP)
|