@ericrisco/rsc 3.0.15 → 3.0.17
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/manifest.json +1 -1
- package/package.json +1 -1
- package/scripts/install-apply.js +51 -4
- package/skills/orient/SKILL.md +10 -0
package/manifest.json
CHANGED
package/package.json
CHANGED
package/scripts/install-apply.js
CHANGED
|
@@ -469,12 +469,24 @@ export function ignoreLocalState(cwd = process.cwd(), target) {
|
|
|
469
469
|
}
|
|
470
470
|
|
|
471
471
|
const add = wanted.filter((w) => !present.has(norm(w)));
|
|
472
|
-
|
|
472
|
+
// Every append used to open a new block with its own header, so a project synced across a dozen
|
|
473
|
+
// versions carried a dozen copies of it. Adjacent rsc blocks are one block: fold them (only our
|
|
474
|
+
// header lines and the blank seams between our blocks go; every entry stays, in order).
|
|
475
|
+
const folded = foldIgnoreBlocks(text);
|
|
476
|
+
if (!add.length) {
|
|
477
|
+
if (folded === text) return null;
|
|
478
|
+
try { writeFileSync(gi, folded); return gi; } catch { return null; }
|
|
479
|
+
}
|
|
473
480
|
|
|
474
|
-
//
|
|
475
|
-
|
|
481
|
+
// Never reorder, never touch a line of theirs. When the file already ends with our block, the new
|
|
482
|
+
// entries join it; otherwise they open one.
|
|
483
|
+
const base = folded === '' || folded.endsWith('\n') ? folded : `${folded}\n`;
|
|
484
|
+
const next = endsWithIgnoreBlock(base)
|
|
485
|
+
? `${base}${add.join('\n')}\n`
|
|
486
|
+
: `${base}${base === '' ? '' : '\n'}${RSC_IGNORE_HEADER}\n${add.join('\n')}\n`;
|
|
476
487
|
try {
|
|
477
|
-
|
|
488
|
+
if (folded === text && next.startsWith(text)) appendFileSync(gi, next.slice(text.length));
|
|
489
|
+
else writeFileSync(gi, next);
|
|
478
490
|
if (target) {
|
|
479
491
|
const statePath = targetPaths(target, undefined, cwd).stateFile;
|
|
480
492
|
const state = readState(statePath);
|
|
@@ -778,6 +790,41 @@ function emptyConfig(file) {
|
|
|
778
790
|
|
|
779
791
|
const RSC_IGNORE_HEADER = '# rsc local state (hooks, seals, logs) and managed skill links — machine-local';
|
|
780
792
|
|
|
793
|
+
// Merge consecutive rsc blocks into the first: drop a repeated header and the blank seam before it
|
|
794
|
+
// when the block above was ours too. A block of the user's in between ends ours, so nothing of
|
|
795
|
+
// theirs is ever moved or absorbed.
|
|
796
|
+
export function foldIgnoreBlocks(text) {
|
|
797
|
+
const out = [];
|
|
798
|
+
let ours = false;
|
|
799
|
+
let afterBlank = false;
|
|
800
|
+
for (const line of text.split('\n')) {
|
|
801
|
+
if (line === RSC_IGNORE_HEADER) {
|
|
802
|
+
if (ours && afterBlank) {
|
|
803
|
+
while (out.length && out[out.length - 1].trim() === '') out.pop();
|
|
804
|
+
afterBlank = false;
|
|
805
|
+
continue;
|
|
806
|
+
}
|
|
807
|
+
ours = true;
|
|
808
|
+
} else if (line.trim() === '') {
|
|
809
|
+
afterBlank = true;
|
|
810
|
+
out.push(line);
|
|
811
|
+
continue;
|
|
812
|
+
} else if (afterBlank) {
|
|
813
|
+
ours = false;
|
|
814
|
+
}
|
|
815
|
+
afterBlank = false;
|
|
816
|
+
out.push(line);
|
|
817
|
+
}
|
|
818
|
+
return out.join('\n');
|
|
819
|
+
}
|
|
820
|
+
|
|
821
|
+
function endsWithIgnoreBlock(text) {
|
|
822
|
+
const lines = text.replace(/\n+$/, '').split('\n');
|
|
823
|
+
let i = lines.length - 1;
|
|
824
|
+
while (i > 0 && lines[i - 1].trim() !== '') i -= 1;
|
|
825
|
+
return lines[i] === RSC_IGNORE_HEADER;
|
|
826
|
+
}
|
|
827
|
+
|
|
781
828
|
// Remove the blocks `ignoreLocalState` appended: the header line, the entries under it up to the
|
|
782
829
|
// next blank line, and the blank seam before it. Lines the user wrote are never part of a block.
|
|
783
830
|
function stripIgnoreBlocks(text) {
|
package/skills/orient/SKILL.md
CHANGED
|
@@ -27,6 +27,16 @@ You own how the harness speaks to the person. Four rules, a register, a ladder,
|
|
|
27
27
|
4. **Short.** Say what the reader needs, then stop. No walls of paragraphs. Rules 3 and 4 meet in one
|
|
28
28
|
place: give the **minimum** context, never the whole story.
|
|
29
29
|
|
|
30
|
+
Three habits make those rules hold (adapted from the `i-have-adhd` skill, ayghri, MIT):
|
|
31
|
+
|
|
32
|
+
- **The answer goes first.** The first line is the answer, the verdict or the action. Context comes
|
|
33
|
+
after, and only if it is needed. A reader who stops after one line must still know the answer.
|
|
34
|
+
- **Five visible items at most.** Group a longer list and show the five that matter now. Keep the
|
|
35
|
+
rest and give it when asked or when it becomes next. Never drop an item that matters.
|
|
36
|
+
- **Check before you send.** Delete a first sentence that only announces what follows. Delete
|
|
37
|
+
closing filler ("hope this helps"); the brújula is the close. Delete a "perhaps" that adds
|
|
38
|
+
nothing, and keep one that carries real doubt.
|
|
39
|
+
|
|
30
40
|
Full rules and examples → `references/orientation-contract.md`.
|
|
31
41
|
|
|
32
42
|
## The register
|