@rig-c/parts 1.15.0 → 1.16.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/README.md CHANGED
@@ -291,9 +291,13 @@ agent skill.
291
291
  | `loop --frames <dir> --out <file.gif \| file.png> [--palette]` | encode a rendered idle as a looping GIF, lossless APNG, or indexed APNG (`--palette`) |
292
292
  | `build --config --source --full --head --out [--seam] [--project] [--loop] [--lead-in <periods>] [--requirements] [--seam-pairs] [--keep-stills] [--idle-keys ctl\|direct]` | assemble, rig and check in one process, stopping at the first refusal; `--requirements`, `--seam-pairs` and `--keep-stills` are forwarded to check, `--idle-keys` to rig; `--lead-in` (with `--loop`) encodes the loop from the last of n + 1 idle periods played back to back, for a rig whose physics does not end where the render starts it |
293
293
  | `compose --scene <scene.json> --out [--requirements] [--accept]` | bind several characters' green builds into one rig (or, under `--accept`, builds failing only the bars named — for looking, not shipping): every name prefixed `<id>:` under one shared root, each character's offset added at its first-level bones, an optional background plate (its provenance recorded, judged by nothing) drawn first, and the draw order between the characters' slots as the scene file declares it — nothing inferred, nothing scaled; gated through rig-c as `rig` is, then checked ([AUTHORING §7](docs/AUTHORING.md), *Composing several characters*) |
294
+ | `guide <RULE \| §<n> \| §<n>.<m> \| §<n>.<m>.<k>>` | print the one row of [docs/AUTHORING.md](docs/AUTHORING.md) that names a rule (a refusal and the bar it enforces, `CHECK_<LINE>` and `<LINE>`, print together), or one section, `###` subsection or `####` under it, read from the installed file when it runs |
294
295
 
295
296
  `rig-parts --help` has every flag. Exit codes: 0 done, 1 input refused (every
296
297
  reason is a FAIL line), 2 a usage error or a command this version does not implement.
298
+ Every FAIL line ends with `(see rig-parts guide <RULE>)`, the command that prints the
299
+ guide's row for that rule, and each row is anchored on the web as
300
+ `docs/AUTHORING.md#<RULE>`.
297
301
 
298
302
  What 1.0.0 holds stable — these commands and their flags, the config
299
303
  fields, the files a build writes and their spec ids, the environment, and what this
package/cli.ts CHANGED
@@ -20,7 +20,8 @@ import { assembleStage, build, checkStage, ERROR_MAP_FILE, loopStage, readRuns,
20
20
  import { ACCEPTABLE_BARS, DEFAULT_PACK_SHAPE, DEFAULT_PAGE_EDGES, findRigc, PACK_SHAPES, rigcRunnerAt, type PackShape, PAGE_EDGES, type PageEdges, PARTS_HOME_SENTENCE, RIGC_GEOMETRY_VERSION, type RigcRunner, NO_PARTS_SENTENCE, SEAM_MEAN_BAR, SOURCE_SENTENCE, SEAM_PX_BAR, SEAM_PX_LEVEL, SPINEBOY_YARDSTICK, TEXTURE_STRETCH_CEILING } from './src/check.ts';
21
21
  import { ComfyClient, resolveHost, runPainting, runSeeThrough } from './src/comfy/index.ts';
22
22
  import { type CharacterConfig, loadConfig, loadEarlyConfig, loadPaintConfig } from './src/config.ts';
23
- import { PartsError, problemLine } from './src/errors.ts';
23
+ import { failLine, guidePointer, PartsError } from './src/errors.ts';
24
+ import { GUIDE_DOC, type GuideAnswer, guideRule, guideSection } from './src/guide.ts';
24
25
  import { proposeHeadBox } from './src/headbox.ts';
25
26
  import { makeInputs } from './src/inputs.ts';
26
27
  import { idleKeysOf, isIdleKeys } from './src/rig.ts';
@@ -590,6 +591,23 @@ usage:
590
591
  line and ${SCENE_REPORT_FILE} name what was accepted, and the run exits 1.
591
592
  Exit 0 when the check is PASS and nothing was accepted, 1 otherwise.
592
593
 
594
+ rig-parts guide <RULE | §<n> | §<n>.<m> | §<n>.<m>.<k>>
595
+ Print a slice of ${GUIDE_DOC}, the guide this package ships, read
596
+ from the installed file at the moment of the call; nothing is kept
597
+ apart from it. Every FAIL line ends with the command that prints its
598
+ rule's row: "(see rig-parts guide <RULE>)". guide <RULE> prints
599
+ "docs/AUTHORING.md §<addr>, line <N> — under "<heading>"" and the one
600
+ row naming the rule; a refusal and the bar it enforces (CHECK_<LINE>
601
+ and <LINE>) print one after the other, joined by "paired with
602
+ <OTHER>:". A name no row holds is refused on stderr
603
+ (GUIDE_RULE_KNOWN), with the three nearest names the guide holds,
604
+ and nothing printed in their place. guide §<n> prints section n,
605
+ after its subsections' numbers and sizes in KB; §<n>.<m>
606
+ is the m-th ### heading under it and §<n>.<m>.<k> the k-th #### under
607
+ that, counted as the file stands (the headings carry no number), and
608
+ §<n>.<m> lists its ####s as §<n> lists its ###s. Exit 0 printed, 1
609
+ refused, 2 usage.
610
+
593
611
  rig-parts --version
594
612
  rig-parts --help
595
613
 
@@ -598,7 +616,7 @@ ${LATER.length === 0 ? '' : `not implemented in this version (each exits 2):\n${
598
616
 
599
617
  function printRefusal(err: unknown): number {
600
618
  if (err instanceof PartsError) {
601
- for (const p of err.problems) console.log(` FAIL ${problemLine(p)}`);
619
+ for (const p of err.problems) console.log(failLine(p));
602
620
  console.log(`refused: ${err.problems.length} problem(s)`);
603
621
  return EXIT_REFUSED;
604
622
  }
@@ -606,11 +624,28 @@ function printRefusal(err: unknown): number {
606
624
  }
607
625
 
608
626
  function usage(message: string): number {
609
- console.log(` FAIL USAGE: ${message}`);
627
+ console.log(` FAIL USAGE: ${message}${guidePointer('USAGE')}`);
610
628
  console.log('rig-parts --help lists the commands');
611
629
  return EXIT_USAGE;
612
630
  }
613
631
 
632
+ /** `guide`: one argument, a rule name or a section; the slice printed, or the refusal. */
633
+ function cmdGuide(args: string[]): number {
634
+ if (args.length !== 1) return usage(`guide takes one rule name or one §<n> / §<n>.<m> / §<n>.<m>.<k>; got ${args.length} argument(s)`);
635
+ if (args[0].startsWith('-')) return usage(`guide takes no flag; "${args[0]}" is neither a rule name nor §<n> / §<n>.<m>`);
636
+ const path = join(import.meta.dir, GUIDE_DOC);
637
+ if (!existsSync(path)) return printRefusal(new PartsError([{ code: 'GUIDE_FILE_PRESENT', object: path, detail: 'no such file; the guide ships in the package beside cli.ts' }]));
638
+ const text = readFileSync(path, 'utf8');
639
+ const answer: GuideAnswer = args[0].startsWith('§') ? guideSection(text, args[0]) : guideRule(text, args[0]);
640
+ // The shared form: an unknown name or section is one coded FAIL line on stderr, exit 1.
641
+ if ('problem' in answer) {
642
+ console.error(failLine(answer.problem));
643
+ return EXIT_REFUSED;
644
+ }
645
+ for (const l of answer.lines) console.log(l);
646
+ return EXIT_OK;
647
+ }
648
+
614
649
  function fixed(v: number | null): string {
615
650
  return v === null ? '-' : v.toFixed(4);
616
651
  }
@@ -655,7 +690,8 @@ function printLayerTable(set: LayerSet): void {
655
690
  /**
656
691
  * Every flag each command takes: `valued` flags carry a value, `switches` are bare. Each parser reads its row to
657
692
  * decide what it accepts, and {@link notTaken} prints the same row in the unknown-flag refusal, so the refusal
658
- * lists exactly the flags the parser accepts (CL26). `layers` takes one positional path and no flag, so it has no row.
693
+ * lists exactly the flags the parser accepts (CL26). `layers` takes one positional path and `guide` one positional
694
+ * argument, and neither takes a flag, so neither has a row.
659
695
  */
660
696
  const TAKES = {
661
697
  sheet: { valued: ['--source', '--layers', '--out', '--cell', '--cols'], switches: [] },
@@ -1047,7 +1083,7 @@ function cmdCompare(args: string[]): number {
1047
1083
  console.log(`rig-parts compare: left ${left}, right ${right}${map === null ? ', no map' : `, map ${map}`}`);
1048
1084
  for (const l of structureLines(c)) console.log(l);
1049
1085
  const missing = requiredProblems(c, map ?? 'the map');
1050
- for (const p of missing) console.log(` FAIL ${problemLine(p)}`);
1086
+ for (const p of missing) console.log(failLine(p));
1051
1087
  return missing.length > 0 ? EXIT_REFUSED : EXIT_OK;
1052
1088
  } catch (err) {
1053
1089
  return printRefusal(err);
@@ -1398,9 +1434,10 @@ function main(argv: string[]): number | Promise<number> {
1398
1434
  if (command === 'build') return cmdBuild(rest);
1399
1435
  if (command === 'compose') return cmdCompose(rest);
1400
1436
  if (command === 'mesh-draft') return cmdMeshDraft(rest);
1437
+ if (command === 'guide') return cmdGuide(rest);
1401
1438
  const later = LATER.find(([name]) => name === command);
1402
1439
  if (later !== undefined) {
1403
- console.log(` FAIL NOT_IMPLEMENTED: \`rig-parts ${command}\` (${later[1]}) is not implemented in this version, ${version()}`);
1440
+ console.log(` FAIL NOT_IMPLEMENTED: \`rig-parts ${command}\` (${later[1]}) is not implemented in this version, ${version()}${guidePointer('NOT_IMPLEMENTED')}`);
1404
1441
  return EXIT_USAGE;
1405
1442
  }
1406
1443
  return usage(`unknown command "${command}"`);