kijito-tools 0.2.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 (104) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +6 -0
  3. package/README.md +220 -0
  4. package/bin/cli.js +34 -0
  5. package/install.sh +161 -0
  6. package/package.json +50 -0
  7. package/providers/_shared/wake-core.mjs +358 -0
  8. package/providers/claude/CLAUDE.md.snippet +31 -0
  9. package/providers/claude/install.sh +186 -0
  10. package/providers/claude/scripts/arm-session.sh +66 -0
  11. package/providers/claude/scripts/claude-armed.sh +101 -0
  12. package/providers/claude/scripts/heartbeat-watchdog.sh +209 -0
  13. package/providers/claude/scripts/inbox-selftest.sh +277 -0
  14. package/providers/claude/scripts/kijito-persona-lib.sh +94 -0
  15. package/providers/claude/scripts/kijito-qa-pass.sh +12 -0
  16. package/providers/claude/scripts/lifecycle-lib.sh +167 -0
  17. package/providers/claude/scripts/myctx.sh +46 -0
  18. package/providers/claude/scripts/self-clear.sh +134 -0
  19. package/providers/claude/scripts/session-autosend.sh +85 -0
  20. package/providers/claude/scripts/session-catchup-hint.sh +330 -0
  21. package/providers/claude/scripts/statusline-context.sh +67 -0
  22. package/providers/claude/skills/kijito-qa-memory/SKILL.md +110 -0
  23. package/providers/claude/skills/kijito-recall/SKILL.md +53 -0
  24. package/providers/claude/skills/kijito-start/SKILL.md +122 -0
  25. package/providers/claude/wiring/README.md +93 -0
  26. package/providers/claude/wiring/kijito-heartbeat@.service +21 -0
  27. package/providers/codex/README.md +75 -0
  28. package/providers/codex/codex-kijito-parity-plan.md +265 -0
  29. package/providers/codex/docs-codex-setup.md +64 -0
  30. package/providers/codex/install.mjs +184 -0
  31. package/providers/codex/n0-capability-probe-protocol.md +472 -0
  32. package/providers/codex/n0-harness/README.md +57 -0
  33. package/providers/codex/n0-harness/cli.mjs +58 -0
  34. package/providers/codex/n0-harness/evidence-manifest.mjs +77 -0
  35. package/providers/codex/n0-harness/fixture.mjs +279 -0
  36. package/providers/codex/n0-harness/lib.mjs +141 -0
  37. package/providers/codex/n0-harness/manifest.mjs +36 -0
  38. package/providers/codex/n0-harness/oracle.mjs +464 -0
  39. package/providers/codex/n0-harness/parser.mjs +200 -0
  40. package/providers/codex/n0-harness/prompt.mjs +43 -0
  41. package/providers/codex/n0-harness/snapshot.mjs +120 -0
  42. package/providers/codex/n0-harness/specimen.mjs +37 -0
  43. package/providers/codex/notify/kijito-notify-count.mjs +117 -0
  44. package/providers/codex/notify/kijito-notify-count.test.mjs +76 -0
  45. package/providers/codex/plans/gate4-battery-log.md +184 -0
  46. package/providers/codex/plans/gate4-battery-protocol.md +43 -0
  47. package/providers/codex/plans/hive-user-first-plan-QA.md +34 -0
  48. package/providers/codex/plans/hive-user-first-plan.md +247 -0
  49. package/providers/codex/release-manifest.json +53 -0
  50. package/providers/codex/same-chat-continuation-plan-gate.md +235 -0
  51. package/providers/codex/same-chat-continuation-plan.md +458 -0
  52. package/providers/codex/skills/kijito-qa-memory/SKILL.md +193 -0
  53. package/providers/codex/skills/kijito-qa-memory/agents/openai.yaml +4 -0
  54. package/providers/codex/skills/kijito-recall/SKILL.md +53 -0
  55. package/providers/codex/skills/kijito-start/SKILL.md +173 -0
  56. package/providers/codex/skills/kijito-start/agents/openai.yaml +4 -0
  57. package/providers/codex/test/n0-cli-refusal.test.mjs +31 -0
  58. package/providers/codex/test/n0-counterexample-matrix.test.mjs +118 -0
  59. package/providers/codex/test/n0-guard-census-core.mjs +1372 -0
  60. package/providers/codex/test/n0-guard-census.json +35479 -0
  61. package/providers/codex/test/n0-guard-census.mjs +31 -0
  62. package/providers/codex/test/n0-guard-census.test.mjs +374 -0
  63. package/providers/codex/test/n0-guard-counterexamples.mjs +1068 -0
  64. package/providers/codex/test/n0-guard-independent-projection.mjs +70 -0
  65. package/providers/codex/test/n0-guard-independent-projection.test.mjs +53 -0
  66. package/providers/codex/test/n0-guard-manifest-author.mjs +424 -0
  67. package/providers/codex/test/n0-guard-mutation-operators.test.mjs +244 -0
  68. package/providers/codex/test/n0-guard-mutation-runner.mjs +599 -0
  69. package/providers/codex/test/n0-guard-remainder-classes.test.mjs +314 -0
  70. package/providers/codex/test/n0-guard-sanitizer-pairs.test.mjs +68 -0
  71. package/providers/codex/test/n0-guard-shared-context-predicates.test.mjs +84 -0
  72. package/providers/codex/test/n0-harness.test.mjs +553 -0
  73. package/providers/codex/test/n0-notable-regressions.test.mjs +70 -0
  74. package/providers/codex/test/n0-subject-boundary.mjs +97 -0
  75. package/providers/codex/test/n0-subject-boundary.test.mjs +72 -0
  76. package/providers/codex/test/same-chat-plan-preflight.sh +167 -0
  77. package/providers/codex/tools/refresh-manifest.mjs +81 -0
  78. package/providers/codex/wake-helper/TRANSPORT-NOTES.md +25 -0
  79. package/providers/codex/wake-helper/integration.test.mjs +285 -0
  80. package/providers/codex/wake-helper/kijito-wake-helper.mjs +488 -0
  81. package/providers/codex/wake-helper/kijito-wake-helper.test.mjs +128 -0
  82. package/providers/codex/wake-helper/mock-daemon.mjs +64 -0
  83. package/providers/codex/wake-helper/status-probe.mjs +45 -0
  84. package/providers/codex/wake-helper/ws-uds.mjs +153 -0
  85. package/providers/monitor/.github/workflows/publish-npm.yml +38 -0
  86. package/providers/monitor/.github/workflows/publish-pypi.yml +30 -0
  87. package/providers/monitor/CHANGELOG.md +465 -0
  88. package/providers/monitor/IMPORT-PROVENANCE.md +68 -0
  89. package/providers/monitor/LICENSE +202 -0
  90. package/providers/monitor/NOTICE +7 -0
  91. package/providers/monitor/OPAQUE-OUTPUT-ENFORCEMENT.md +45 -0
  92. package/providers/monitor/README.md +571 -0
  93. package/providers/monitor/RELEASING.md +125 -0
  94. package/providers/monitor/arm-hive-monitor.sh +13 -0
  95. package/providers/monitor/bin/cli.js +43 -0
  96. package/providers/monitor/com.kijito.inbox-monitor.plist.template +59 -0
  97. package/providers/monitor/docs/DESIGN.md +984 -0
  98. package/providers/monitor/kijito-inbox-monitor@.service.template +95 -0
  99. package/providers/monitor/kijito_inbox_monitor.py +3666 -0
  100. package/providers/monitor/package.json +35 -0
  101. package/providers/monitor/pyproject.toml +42 -0
  102. package/providers/monitor/scripts/mutation-check.py +399 -0
  103. package/providers/monitor/scripts/prepublish-gate.sh +284 -0
  104. package/providers/monitor/test_kijito_monitor.py +5609 -0
@@ -0,0 +1,244 @@
1
+ import assert from "node:assert/strict";
2
+ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import path from "node:path";
5
+ import { spawnSync } from "node:child_process";
6
+ import { test } from "node:test";
7
+ import { replacementFor, repositorySnapshot } from "./n0-guard-mutation-runner.mjs";
8
+
9
+ function entry(source, mutation, overrides = {}) {
10
+ return { id: "fixture:entry", source, mutation, ...overrides };
11
+ }
12
+
13
+ function rejectingCall(source, callee, operator = "suppress-thrown-rejection") {
14
+ return entry(source, { operator }, { kind: "rejecting-helper-call", helper: callee });
15
+ }
16
+
17
+ function evaluateReplacement(source, bindings) {
18
+ return Function(...Object.keys(bindings), `return (${source});`)(...Object.values(bindings));
19
+ }
20
+
21
+ test("suppress-thrown-rejection evaluates arguments outside try and the callee exactly once", () => {
22
+ let argumentCalls = 0;
23
+ let calleeCalls = 0;
24
+ const replacement = replacementFor(rejectingCall("snapshotTree(argument())", "snapshotTree"));
25
+ const result = evaluateReplacement(replacement, {
26
+ argument() { argumentCalls += 1; return "root"; },
27
+ snapshotTree(root) { calleeCalls += 1; assert.equal(root, "root"); throw new Error("callee rejection"); },
28
+ });
29
+ assert.equal(result, undefined);
30
+ assert.equal(argumentCalls, 1);
31
+ assert.equal(calleeCalls, 1);
32
+
33
+ assert.throws(
34
+ () => evaluateReplacement(replacement, {
35
+ argument() { throw new Error("argument rejection"); },
36
+ snapshotTree() { assert.fail("callee must not run when argument evaluation throws"); },
37
+ }),
38
+ /argument rejection/,
39
+ );
40
+ });
41
+
42
+ test("suppress-thrown-rejection preserves success values and asynchronous rejection", async () => {
43
+ const value = { schema: "N0_ROLLOUT_SNAPSHOT_V1" };
44
+ const replacement = replacementFor(rejectingCall("snapshotTree(root)", "snapshotTree"));
45
+ assert.equal(evaluateReplacement(replacement, { root: "/r", snapshotTree: () => value }), value);
46
+
47
+ const rejected = Promise.reject(new Error("async rejection"));
48
+ assert.equal(evaluateReplacement(replacement, { root: "/r", snapshotTree: () => rejected }), rejected);
49
+ await assert.rejects(rejected, /async rejection/);
50
+ });
51
+
52
+ test("payload-free call operators reject wrong kinds, callees, optional/computed calls, spreads, and payloads", () => {
53
+ for (const candidate of [
54
+ entry("snapshotTree(root)", { operator: "suppress-thrown-rejection" }, { kind: "guard-atom", helper: "snapshotTree" }),
55
+ rejectingCall("other(root)", "other"),
56
+ rejectingCall("subject.snapshotTree(root)", "snapshotTree"),
57
+ rejectingCall("subject[\"snapshotTree\"](root)", "snapshotTree"),
58
+ rejectingCall("snapshotTree?.(root)", "snapshotTree"),
59
+ rejectingCall("snapshotTree(...roots)", "snapshotTree"),
60
+ rejectingCall("snapshotTree(root)", "different"),
61
+ entry("evaluateOracle(specimen, evidence, nowMs)", { operator: "force-call-result-status", status: "N0_TEST_CAPABLE" }, { kind: "rejecting-helper-call", helper: "evaluateOracle" }),
62
+ ]) assert.throws(() => replacementFor(candidate), /MUTATION_DIRECTION/);
63
+ });
64
+
65
+ test("suppress-thrown-rejection has an exact reviewed synchronous helper vocabulary", () => {
66
+ const allowed = [
67
+ "assertExactKeys",
68
+ "main",
69
+ "parseJsonBuffer",
70
+ "readOwnedRegularFile",
71
+ "renderPrompt",
72
+ "requireNonce",
73
+ "requireObject",
74
+ "requirePathInside",
75
+ "requireString",
76
+ "snapshotTree",
77
+ "validateEvidenceMeta",
78
+ ];
79
+ for (const callee of allowed) {
80
+ assert.match(replacementFor(rejectingCall(`${callee}(value)`, callee)), new RegExp(`\\b${callee}\\(`));
81
+ }
82
+ assert.throws(() => replacementFor(rejectingCall("futureHelper(value)", "futureHelper")), /MUTATION_DIRECTION/);
83
+ });
84
+
85
+ test("force-call-result-status evaluates once and changes only status", () => {
86
+ let calls = 0;
87
+ const replacement = replacementFor(rejectingCall(
88
+ "evaluateOracle(specimen, evidence, nowMs)",
89
+ "evaluateOracle",
90
+ "force-call-result-status",
91
+ ));
92
+ const result = evaluateReplacement(replacement, {
93
+ specimen: {}, evidence: {}, nowMs: 1,
94
+ evaluateOracle() { calls += 1; return { status: "RED", code: "X", detail: { retained: true } }; },
95
+ });
96
+ assert.equal(calls, 1);
97
+ assert.deepEqual(result, { status: "N0_TEST_CAPABLE", code: "X", detail: { retained: true } });
98
+ });
99
+
100
+ test("bypass-rejection preserves verdict structure and changes only an owned negative status", () => {
101
+ assert.equal(
102
+ replacementFor(entry('verdict("RED", "CODE", detail)', { operator: "bypass-rejection" })),
103
+ 'verdict("N0_TEST_CAPABLE", "CODE", detail)',
104
+ );
105
+ assert.equal(
106
+ replacementFor(entry('verdict("BLOCKED", code, detail)', { operator: "bypass-rejection" })),
107
+ 'verdict("N0_TEST_CAPABLE", code, detail)',
108
+ );
109
+ assert.equal(replacementFor(entry('fail("CODE", detail)', { operator: "bypass-rejection" })), "void 0");
110
+ });
111
+
112
+ test("verdict bypass rejects non-negative, computed, or different callees", () => {
113
+ for (const source of [
114
+ 'verdict("N0_TEST_CAPABLE", "CODE", detail)',
115
+ 'verdict(status, "CODE", detail)',
116
+ ]) {
117
+ assert.throws(
118
+ () => replacementFor(entry(source, { operator: "bypass-rejection" })),
119
+ /MUTATION_DIRECTION/,
120
+ );
121
+ }
122
+ });
123
+
124
+ test("condition forcing emits only boolean literals", () => {
125
+ assert.equal(replacementFor(entry("subject", { operator: "force-owned-condition", value: true })), "true");
126
+ assert.equal(replacementFor(entry("subject", { operator: "force-owned-condition", value: false })), "false");
127
+ assert.throws(
128
+ () => replacementFor(entry("subject", { operator: "force-owned-condition", value: "false" })),
129
+ /MUTATION_DIRECTION/,
130
+ );
131
+ });
132
+
133
+ test("first-binding sanitizer requires the exact assignable first call argument", () => {
134
+ assert.equal(
135
+ replacementFor(entry("requireString(subject.value, code)", {
136
+ operator: "sanitize-first-binding",
137
+ binding: "subject.value",
138
+ value: '"safe"',
139
+ })),
140
+ 'subject.value = "safe"',
141
+ );
142
+ assert.throws(
143
+ () => replacementFor(entry("requireString(subject.value, code)", {
144
+ operator: "sanitize-first-binding",
145
+ binding: "other.value",
146
+ value: '"safe"',
147
+ })),
148
+ /MUTATION_DIRECTION/,
149
+ );
150
+ assert.throws(
151
+ () => replacementFor(entry('requireString("literal", code)', {
152
+ operator: "sanitize-first-binding",
153
+ binding: '"literal"',
154
+ value: '"safe"',
155
+ })),
156
+ /MUTATION_DIRECTION/,
157
+ );
158
+ });
159
+
160
+ test("first-argument sanitizer preserves the callee and remaining arguments", () => {
161
+ assert.equal(
162
+ replacementFor(entry("parseValue(subject.text, options)", {
163
+ operator: "sanitize-first-argument",
164
+ value: 'subject.text.toString("utf8")',
165
+ })),
166
+ 'parseValue(subject.text.toString("utf8"), options)',
167
+ );
168
+ assert.throws(
169
+ () => replacementFor(entry("parseValue(subject.text, options)", {
170
+ operator: "sanitize-first-argument",
171
+ value: "(subject.text, options)",
172
+ })),
173
+ /MUTATION_DIRECTION/,
174
+ );
175
+ assert.throws(
176
+ () => replacementFor(entry("parseValue(...values)", {
177
+ operator: "sanitize-first-argument",
178
+ value: '"safe"',
179
+ })),
180
+ /MUTATION_DIRECTION/,
181
+ );
182
+ });
183
+
184
+ test("arbitrary and sequence-expression operators remain unrepresentable", () => {
185
+ assert.throws(
186
+ () => replacementFor(entry("subject", { operator: "replace-expression", expression: "true" })),
187
+ /MUTATION_DIRECTION/,
188
+ );
189
+ assert.throws(
190
+ () => replacementFor(entry("subject", { operator: "substitute-reviewed-expression", expression: "({})" })),
191
+ /MUTATION_DIRECTION/,
192
+ );
193
+ assert.throws(
194
+ () => replacementFor(entry("subject", { operator: "substitute-reviewed-expression", expression: "(void 0, true)" })),
195
+ /MUTATION_DIRECTION/,
196
+ );
197
+ });
198
+
199
+ function git(root, ...args) {
200
+ const result = spawnSync("git", args, { cwd: root, encoding: "utf8" });
201
+ assert.equal(result.status, 0, result.stderr);
202
+ }
203
+
204
+ test("primary invariance snapshot detects byte changes hidden behind unchanged dirty status", () => {
205
+ const root = mkdtempSync(path.join(tmpdir(), "n0-primary-invariance-"));
206
+ try {
207
+ git(root, "init", "-q");
208
+ git(root, "config", "user.email", "n0@example.invalid");
209
+ git(root, "config", "user.name", "N0 Test");
210
+ writeFileSync(path.join(root, "tracked.txt"), "base\n");
211
+ git(root, "add", "tracked.txt");
212
+ git(root, "commit", "-qm", "base");
213
+
214
+ writeFileSync(path.join(root, "tracked.txt"), "dirty-a\n");
215
+ writeFileSync(path.join(root, "untracked.txt"), "untracked-a\n");
216
+ const before = repositorySnapshot(root);
217
+ writeFileSync(path.join(root, "tracked.txt"), "dirty-b\n");
218
+ writeFileSync(path.join(root, "untracked.txt"), "untracked-b\n");
219
+ const after = repositorySnapshot(root);
220
+
221
+ assert.notEqual(after.worktreeDiffSha256, before.worktreeDiffSha256);
222
+ assert.notEqual(after.untrackedSha256, before.untrackedSha256);
223
+ assert.equal(after.statusSha256, before.statusSha256);
224
+ } finally {
225
+ rmSync(root, { recursive: true, force: true });
226
+ }
227
+ });
228
+
229
+ test("primary invariance snapshot captures dirty diffs larger than spawnSync's default buffer", () => {
230
+ const root = mkdtempSync(path.join(tmpdir(), "n0-primary-buffer-"));
231
+ try {
232
+ git(root, "init", "-q");
233
+ git(root, "config", "user.email", "n0@example.invalid");
234
+ git(root, "config", "user.name", "N0 Test");
235
+ writeFileSync(path.join(root, "tracked.txt"), "base\n");
236
+ git(root, "add", "tracked.txt");
237
+ git(root, "commit", "-qm", "base");
238
+ writeFileSync(path.join(root, "tracked.txt"), `${"x".repeat(2 * 1024 * 1024)}\n`);
239
+ const snapshot = repositorySnapshot(root);
240
+ assert.match(snapshot.worktreeDiffSha256, /^[a-f0-9]{64}$/);
241
+ } finally {
242
+ rmSync(root, { recursive: true, force: true });
243
+ }
244
+ });