paperlint 10.0.0 → 10.1.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.
Files changed (54) hide show
  1. package/CONTRIBUTING.md +16 -4
  2. package/dist/eslint-rules/js-needs-reason.d.ts +55 -0
  3. package/dist/eslint-rules/js-needs-reason.d.ts.map +1 -0
  4. package/dist/eslint-rules/js-needs-reason.js +35 -0
  5. package/dist/eslint-rules/js-needs-reason.js.map +1 -0
  6. package/dist/package-dirs.d.ts +6 -0
  7. package/dist/package-dirs.d.ts.map +1 -1
  8. package/dist/package-dirs.js +6 -0
  9. package/dist/package-dirs.js.map +1 -1
  10. package/dist/skills/label-agent-runs/scripts/labels-commands.d.ts +13 -0
  11. package/dist/skills/label-agent-runs/scripts/labels.d.ts +2 -0
  12. package/dist/skills/run-agent-grid/scripts/grid-guard-commands.d.ts +20 -0
  13. package/dist/skills/run-agent-grid/scripts/grid-guard.d.ts +2 -0
  14. package/docs/skills.md +2 -0
  15. package/docs/testing.md +13 -0
  16. package/eslint-rules/js-needs-reason.test.ts +141 -0
  17. package/eslint-rules/js-needs-reason.ts +77 -0
  18. package/eslint.config.mjs +22 -2
  19. package/lib/skill-trigger-cases.test.ts +211 -0
  20. package/package.json +8 -4
  21. package/scripts/coverage-config.test.ts +5 -3
  22. package/skills/build-benchmark/SKILL.md +4 -1
  23. package/skills/build-benchmark/SKILL.md.spec.ts +3 -0
  24. package/skills/build-label-page/SKILL.md +3 -1
  25. package/skills/build-label-page/SKILL.md.spec.ts +2 -0
  26. package/skills/label-agent-runs/SKILL.md +103 -0
  27. package/skills/label-agent-runs/SKILL.md.spec.ts +106 -0
  28. package/skills/label-agent-runs/label-agent-runs.eval.ts +55 -0
  29. package/skills/label-agent-runs/label-agent-runs.harness.ts +123 -0
  30. package/skills/label-agent-runs/references/formats.md +64 -0
  31. package/skills/label-agent-runs/scripts/labels-commands.js +13 -0
  32. package/skills/label-agent-runs/scripts/labels-commands.ts +13 -0
  33. package/skills/label-agent-runs/scripts/labels.js +396 -0
  34. package/skills/label-agent-runs/scripts/labels.test.ts +538 -0
  35. package/skills/label-agent-runs/scripts/labels.ts +501 -0
  36. package/skills/paper-pipeline/SKILL.md +8 -1
  37. package/skills/paper-pipeline/SKILL.md.spec.ts +7 -0
  38. package/skills/run-agent-grid/SKILL.md +181 -0
  39. package/skills/run-agent-grid/SKILL.md.spec.ts +184 -0
  40. package/skills/run-agent-grid/references/failure-catalog.md +36 -0
  41. package/skills/run-agent-grid/references/registry-and-ledger.md +142 -0
  42. package/skills/run-agent-grid/run-agent-grid.eval.ts +59 -0
  43. package/skills/run-agent-grid/run-agent-grid.harness.ts +115 -0
  44. package/skills/run-agent-grid/scripts/grid-guard-commands.js +18 -0
  45. package/skills/run-agent-grid/scripts/grid-guard-commands.ts +21 -0
  46. package/skills/run-agent-grid/scripts/grid-guard.js +700 -0
  47. package/skills/run-agent-grid/scripts/grid-guard.test.ts +1090 -0
  48. package/skills/run-agent-grid/scripts/grid-guard.ts +869 -0
  49. package/src/package-dirs.ts +8 -0
  50. package/tsconfig.base.json +22 -0
  51. package/tsconfig.json +6 -24
  52. package/tsconfig.pkg.json +3 -1
  53. package/tsconfig.skills.json +14 -0
  54. package/tsconfig.src.json +12 -0
@@ -0,0 +1,115 @@
1
+ /**
2
+ * run-agent-grid — the agent-facing tier. Does an agent that loads this skill get a guard it can
3
+ * actually call, at the path the skill names, with the result the skill promises?
4
+ *
5
+ * Runs the REAL `claude` CLI against a SCRIPTED MOCK MODEL (`runHarnessTest`): $0, no API key.
6
+ * The script: activate the skill, then — through the Bash tool, as an agent following §5 would —
7
+ * take the lock on a working-copy root, have a second driver refused while the first holds it,
8
+ * and release it. The commands use the skill directory as `${CLAUDE_SKILL_DIR}` resolves for a
9
+ * consumer: the skill's link under `.claude/skills/`, and the COMPILED `grid-guard.js` there,
10
+ * which is what runs from `node_modules` (`npm run build` makes it; `npm run check` builds first).
11
+ *
12
+ * Also, without the CLI: the shared per-skill checks (`checkSkill`). Whether the skill names only
13
+ * subcommands the guard has is not tested here: the spec interpolates them from
14
+ * `scripts/grid-guard-commands.ts`, so a wrong one fails `tsc`.
15
+ *
16
+ * What it does NOT prove: that a real model follows the order of the gates. That is a
17
+ * probabilistic question for `run-agent-grid.eval.ts` and a real grid.
18
+ */
19
+ import { spawnSync } from "node:child_process";
20
+ import { join } from "node:path";
21
+ import { runHarnessTest, skip, type ToolCall } from "vigiles";
22
+ import { createChecker } from "../../lib/check.ts";
23
+ import { checkSkill } from "../../lib/skill-checks.mjs";
24
+ import { observeAgentCli } from "#lib/agent-cli-version";
25
+ import { claudeDir } from "#src/package-dirs";
26
+ import { COMMANDS } from "./scripts/grid-guard-commands.ts";
27
+
28
+ const check = createChecker();
29
+
30
+ await checkSkill("run-agent-grid");
31
+
32
+ // ── Through the real CLI: the lock, as the skill tells an agent to take it ────────────────
33
+ const SKILL_LINK = join(claudeDir(), "skills", "run-agent-grid");
34
+ const cli = observeAgentCli({ spawnSync });
35
+ if (!cli.present) skip(`run-agent-grid effects: ${cli.note}`);
36
+
37
+ const g = `node ${SKILL_LINK}/scripts/grid-guard.js`;
38
+ // The holder's pid is this harness: alive for the whole run, so the second driver must be refused.
39
+ // `--attached`: a Bash call of an agent session is not a detached driver, and this run is short —
40
+ // the detachment refusal itself is pinned in `scripts/grid-guard.test.ts`.
41
+ const LOCK = `${g} ${COMMANDS.lock} wc --owner driver-a --pid ${String(process.pid)} --attached`;
42
+ const r = await runHarnessTest({
43
+ pluginDir: claudeDir(),
44
+ // bubblewrap is absent here; the code loaded is this repository's own `.claude`.
45
+ sandbox: false,
46
+ transcript: true,
47
+ timeoutMs: 180_000,
48
+ prompt:
49
+ "we are about to start the paid grid — take the lock on the working copy",
50
+ allowedTools: ["Skill", "Bash"],
51
+ files: { "README.md": "grid working directory\n" },
52
+ model: [
53
+ { tool: "Skill", input: { skill: "run-agent-grid" } },
54
+ { tool: "Bash", input: { command: LOCK } },
55
+ {
56
+ tool: "Bash",
57
+ input: {
58
+ command: `${g} ${COMMANDS.lock} wc --owner driver-b --attached`,
59
+ },
60
+ },
61
+ {
62
+ tool: "Bash",
63
+ input: { command: `${g} ${COMMANDS.release} wc --owner driver-a` },
64
+ },
65
+ { text: "done" },
66
+ ],
67
+ });
68
+
69
+ /** Did this call run, with this error flag, and print what `re` matches? */
70
+ const ran = (c: ToolCall | undefined, isError: boolean, re: RegExp): boolean =>
71
+ c !== undefined && c.isError === isError && re.test(c.resultText);
72
+ const shown = (c: ToolCall | undefined): string =>
73
+ c ? c.resultText.slice(0, 300) : "never called";
74
+
75
+ try {
76
+ const activation = r.toolCalls.find((c) => c.name === "Skill");
77
+ check(
78
+ "the skill activated",
79
+ activation !== undefined && !activation.isError,
80
+ shown(activation),
81
+ );
82
+ const reached = r.modelRequests
83
+ .map((q) => [q.system, ...q.messages.map((m) => m.text)].join("\n"))
84
+ .join("\n");
85
+ check(
86
+ "the skill body reached the model",
87
+ reached.includes(
88
+ "The order — each gate is passed before the next phase starts",
89
+ ),
90
+ `${String(r.modelRequests.length)} requests`,
91
+ );
92
+ const bash = r.toolCalls.filter((c) => c.name === "Bash");
93
+ const [take, second, give] = bash;
94
+ check("three Bash calls ran", bash.length === 3, String(bash.length));
95
+ check(
96
+ "the first driver takes the lock",
97
+ ran(take, false, /locked \S+wc\.lock for driver-a/),
98
+ shown(take),
99
+ );
100
+ check(
101
+ "a second driver is refused while the first lives",
102
+ ran(second, true, /wc\.lock is held by driver-a/),
103
+ shown(second),
104
+ );
105
+ check(
106
+ "the owner releases it",
107
+ ran(give, false, /released \S+wc\.lock/),
108
+ shown(give),
109
+ );
110
+ console.log(
111
+ `✓ run-agent-grid [effects]: skill activated; lock taken, second driver refused, released.\n CLI: ${cli.note}`,
112
+ );
113
+ } finally {
114
+ r.cleanup();
115
+ }
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The subcommands of `grid-guard`, by name. One table, read twice: the dispatcher in
3
+ * `grid-guard.ts` is keyed by these names (a missing or extra entry is a type error there), and
4
+ * `SKILL.md.spec.ts` interpolates them into every command it instructs (a name that is not here
5
+ * is a type error there). So the skill cannot instruct a subcommand the script does not have.
6
+ *
7
+ * A module of its own, with no side effects: the spec imports it at compile time, and importing
8
+ * `grid-guard.ts` itself would run the command line.
9
+ */
10
+ export const COMMANDS = {
11
+ lock: "lock",
12
+ release: "release",
13
+ gate: "gate",
14
+ overlap: "overlap",
15
+ envProbe: "env-probe",
16
+ scanKeys: "scan-keys",
17
+ precommit: "precommit",
18
+ };
@@ -0,0 +1,21 @@
1
+ /**
2
+ * The subcommands of `grid-guard`, by name. One table, read twice: the dispatcher in
3
+ * `grid-guard.ts` is keyed by these names (a missing or extra entry is a type error there), and
4
+ * `SKILL.md.spec.ts` interpolates them into every command it instructs (a name that is not here
5
+ * is a type error there). So the skill cannot instruct a subcommand the script does not have.
6
+ *
7
+ * A module of its own, with no side effects: the spec imports it at compile time, and importing
8
+ * `grid-guard.ts` itself would run the command line.
9
+ */
10
+ export const COMMANDS = {
11
+ lock: "lock",
12
+ release: "release",
13
+ gate: "gate",
14
+ overlap: "overlap",
15
+ envProbe: "env-probe",
16
+ scanKeys: "scan-keys",
17
+ precommit: "precommit",
18
+ } as const;
19
+
20
+ /** A subcommand's name as typed on the command line. */
21
+ export type CommandName = (typeof COMMANDS)[keyof typeof COMMANDS];