@linzumi/cli 1.0.91 → 1.0.93

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linzumi/cli",
3
- "version": "1.0.91",
3
+ "version": "1.0.93",
4
4
  "description": "Linzumi CLI \u2014 point a Codex agent at the real code on your laptop, with your team watching and steering from shared threads.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,160 @@
1
+ // Spec: kandan/plans/2026-07-10-compute-nodes-rescript-commander-zero-ts-program.md (M2.5 + M2.6)
2
+ // Relationship: Builds the TS-impl differential entry
3
+ // (src/differentialCommanderEntry.ts) into a single runnable bundle at
4
+ // .differential/impl-ts.mjs, mirroring the published dist/index.js build
5
+ // configuration (same platform/target/format/externals/banner) so the
6
+ // differential harness exercises the SAME bundling reality the shipped CLI
7
+ // has - this is the M3 packaging seam's dist/impl-ts precursor: the M3
8
+ // chooser design ships dist/impl-ts/ + dist/impl-res/ side by side, and the
9
+ // M2.5 differential runner's impl parameter selects between them (impl-res
10
+ // fails honestly until M3 cluster 1 lands).
11
+ //
12
+ // M2.6 mutation mode (`--mutation <name>`): applies ONE seeded behavior
13
+ // delta from scripts/differentialMutations.mjs as a build-time source patch
14
+ // and emits .differential/impl-ts.mutant-<name>.mjs instead. The harness's
15
+ // anti-false-green mutation check builds each mutant and asserts the
16
+ // differential suite goes RED on it. Every patch anchor must match the
17
+ // current source EXACTLY ONCE - zero or multiple matches fail the build
18
+ // loudly, so a commander refactor can never silently no-op a mutation.
19
+ //
20
+ // Unminified deliberately: the bundle is a local test artifact
21
+ // (.differential/ is gitignored, never published), and readable output makes
22
+ // differential findings debuggable.
23
+ import { copyFile, mkdir, readFile } from 'node:fs/promises';
24
+ import { dirname, join } from 'node:path';
25
+ import { fileURLToPath } from 'node:url';
26
+ import { build } from 'esbuild';
27
+ import { differentialMutations } from './differentialMutations.mjs';
28
+
29
+ const packageRoot = dirname(dirname(fileURLToPath(import.meta.url)));
30
+
31
+ function parseArgs(argv) {
32
+ if (argv.length === 0) {
33
+ return { mutation: undefined };
34
+ }
35
+ if (argv[0] === '--mutation' && argv.length === 2) {
36
+ const mutation = differentialMutations.find(
37
+ (entry) => entry.name === argv[1]
38
+ );
39
+ if (mutation === undefined) {
40
+ const known = differentialMutations.map((entry) => entry.name);
41
+ throw new Error(
42
+ `unknown differential mutation ${JSON.stringify(argv[1])}; known mutations: ${known.join(', ')}`
43
+ );
44
+ }
45
+ return { mutation };
46
+ }
47
+ throw new Error(
48
+ 'usage: node scripts/build-differential-entry.mjs [--mutation <name>]'
49
+ );
50
+ }
51
+
52
+ const { mutation } = parseArgs(process.argv.slice(2));
53
+
54
+ // Count non-overlapping occurrences of `needle` in `haystack`. An empty
55
+ // needle is a registry authoring error, refused loudly (indexOf('') matches
56
+ // at every position, which would both loop forever here and make the
57
+ // exactly-once rule meaningless); the harness registry conformance pins the
58
+ // same rule at rest (Greptile finding on #3115).
59
+ function occurrences(haystack, needle) {
60
+ if (needle.length === 0) {
61
+ throw new Error('mutation patch `find` must be a non-empty string');
62
+ }
63
+ let count = 0;
64
+ let from = 0;
65
+ for (;;) {
66
+ const at = haystack.indexOf(needle, from);
67
+ if (at === -1) {
68
+ return count;
69
+ }
70
+ count += 1;
71
+ from = at + needle.length;
72
+ }
73
+ }
74
+
75
+ // esbuild onLoad plugin: apply the mutation's patches to their target
76
+ // sources, enforcing the exactly-once anchor rule per patch. Also asserts
77
+ // every patch was actually loaded by the bundle (a patched-but-unbundled
78
+ // file would be a silent no-op mutation).
79
+ function mutationPlugin(activeMutation) {
80
+ const patchesByFile = new Map();
81
+ for (const patch of activeMutation.patches) {
82
+ const absolute = join(packageRoot, patch.file);
83
+ const existing = patchesByFile.get(absolute) ?? [];
84
+ existing.push(patch);
85
+ patchesByFile.set(absolute, existing);
86
+ }
87
+ const applied = new Set();
88
+
89
+ return {
90
+ plugin: {
91
+ name: 'differential-mutation',
92
+ setup(pluginBuild) {
93
+ pluginBuild.onLoad({ filter: /\.ts$/ }, async (args) => {
94
+ const patches = patchesByFile.get(args.path);
95
+ if (patches === undefined) {
96
+ return undefined;
97
+ }
98
+ let contents = await readFile(args.path, 'utf8');
99
+ for (const patch of patches) {
100
+ const found = occurrences(contents, patch.find);
101
+ if (found !== 1) {
102
+ throw new Error(
103
+ `mutation ${activeMutation.name}: anchor in ${patch.file} matched ${found} times (must match exactly once); the commander source moved - re-anchor the patch in scripts/differentialMutations.mjs`
104
+ );
105
+ }
106
+ contents = contents.replace(patch.find, patch.replace);
107
+ applied.add(`${patch.file}:${patch.find.slice(0, 40)}`);
108
+ }
109
+ return { contents, loader: 'ts' };
110
+ });
111
+ },
112
+ },
113
+ assertAllApplied() {
114
+ const expected = activeMutation.patches.length;
115
+ if (applied.size !== expected) {
116
+ throw new Error(
117
+ `mutation ${activeMutation.name}: only ${applied.size} of ${expected} patches were loaded into the bundle - a patched file is not part of the differential entry`
118
+ );
119
+ }
120
+ },
121
+ };
122
+ }
123
+
124
+ // Renamed banner import: unlike the minified dist build, this bundle keeps
125
+ // source-level identifiers, and the commander sources themselves import
126
+ // createRequire - the published banner's bare name would collide.
127
+ const banner = {
128
+ js: "import { createRequire as __differentialCreateRequire } from 'node:module';\nconst require = __differentialCreateRequire(import.meta.url);",
129
+ };
130
+
131
+ const outfile =
132
+ mutation === undefined
133
+ ? join(packageRoot, '.differential/impl-ts.mjs')
134
+ : join(packageRoot, `.differential/impl-ts.mutant-${mutation.name}.mjs`);
135
+
136
+ const mutationHooks = mutation === undefined ? undefined : mutationPlugin(mutation);
137
+
138
+ await build({
139
+ entryPoints: [join(packageRoot, 'src/differentialCommanderEntry.ts')],
140
+ bundle: true,
141
+ platform: 'node',
142
+ target: 'node20',
143
+ format: 'esm',
144
+ outfile,
145
+ minify: false,
146
+ sourcemap: false,
147
+ legalComments: 'none',
148
+ external: ['ws', 'undici', 'blessed', '@anthropic-ai/claude-agent-sdk'],
149
+ banner,
150
+ plugins: mutationHooks === undefined ? [] : [mutationHooks.plugin],
151
+ });
152
+
153
+ mutationHooks?.assertAllApplied();
154
+
155
+ // The runtime resolves assets/ relative to the bundle (same as dist/).
156
+ await mkdir(join(packageRoot, '.differential/assets'), { recursive: true });
157
+ await copyFile(
158
+ join(packageRoot, 'src/assets/linzumi-logo.svg'),
159
+ join(packageRoot, '.differential/assets/linzumi-logo.svg')
160
+ );
@@ -0,0 +1,113 @@
1
+ // Spec: kandan/plans/2026-07-10-compute-nodes-rescript-commander-zero-ts-program.md (M2.6)
2
+ // Relationship: The maintained seeded-mutation set for the differential
3
+ // harness's anti-false-green mutation check. Each entry is a deliberate
4
+ // behavior delta patched into the TS commander AT BUILD TIME
5
+ // (scripts/build-differential-entry.mjs --mutation <name>); the harness's
6
+ // MutationCheckConformance then asserts the differential suite goes RED on
7
+ // the mutant (transcript diff for the shape/ordering classes, a named
8
+ // ported-invariant violation for the invariant class). A seeded delta the
9
+ // suite stays green on means the gate is lying - that conformance leg fails.
10
+ //
11
+ // This registry is the SINGLE source (derive, don't duplicate): the build
12
+ // script applies `patches`, and the harness conformance imports this exact
13
+ // module to drive and pin the set (closed classes, one mutation per class).
14
+ //
15
+ // MAINTENANCE RULES:
16
+ // - The set stays small (one mutation per class below) - every entry is a
17
+ // permanent CI cost, so each must earn its place by proving a DISTINCT
18
+ // sensitivity class of the differential canonical transcript.
19
+ // - `find` strings must match the current source EXACTLY ONCE; the build
20
+ // fails loudly on zero or multiple matches, so a refactor can never
21
+ // silently no-op a mutation (the anchor rot the exactly-once rule
22
+ // exists for).
23
+ // - Mutations must never remove an event a differential scenario AWAITS
24
+ // (the choreography synchronizes on milestones; deleting one turns a
25
+ // fast red into a slow timeout red).
26
+ // - No current-version literals (the commander-harness package rule).
27
+ //
28
+ // Classes (the M2.6 task's closed vocabulary):
29
+ // - transcript-shape: an event the commander silently stops emitting must
30
+ // change the canonical transcript bytes.
31
+ // - invariant: a behavior delta violating a ported ordering invariant
32
+ // must surface as that invariant's named violation.
33
+ // - ordering: a pure reorder of the commander's own send order (same
34
+ // event multiset) must change the canonical transcript bytes.
35
+
36
+ export const differentialMutations = [
37
+ {
38
+ name: 'message-state-processing-drop',
39
+ class: 'transcript-shape',
40
+ scenario: 'harness-session-rebuild',
41
+ proves:
42
+ 'a silently dropped message-state publish (the msg-state ladder silent-drop class: the user-visible "processing / starting turn" paint never reaches the server) changes the canonical transcript - the differential diff can see a suppressed notification type',
43
+ patches: [
44
+ {
45
+ file: 'src/channelSession.ts',
46
+ find: ` await publishQueuedMessageState(
47
+ args,
48
+ state,
49
+ next,
50
+ {
51
+ status: 'processing',
52
+ reason: 'starting turn',
53
+ },
54
+ 'sent'
55
+ );`,
56
+ replace: ` // [seeded differential mutation: message-state-processing-drop] the
57
+ // starting-turn processing paint is silently dropped.`,
58
+ },
59
+ ],
60
+ },
61
+ {
62
+ name: 'join-roster-drop',
63
+ class: 'invariant',
64
+ expectInvariant: 'I319',
65
+ scenario: 'full-join-surfaces',
66
+ proves:
67
+ 'a commander that silently drops the join-reply roster (the Commander-boots-into-empty-onboarding regression class the compute-nodes program exists to kill) under-delivers the display page and goes red as an I319 violation, not just a byte diff',
68
+ patches: [
69
+ {
70
+ file: 'src/runner.ts',
71
+ find: ` seedDashboardRosterFromReply(joinResponse, 'join');`,
72
+ replace: ` // [seeded differential mutation: join-roster-drop] the join-reply
73
+ // roster seed is silently dropped.`,
74
+ },
75
+ ],
76
+ },
77
+ {
78
+ name: 'handshake-initialized-reorder',
79
+ class: 'ordering',
80
+ scenario: 'harness-clean-turn',
81
+ proves:
82
+ 'a pure reorder of the commander\'s own send order (the codex app-server handshake: `initialized` notified BEFORE the `initialize` request instead of after its result) changes the canonical transcript even though the event multiset is identical - per-party send order is preserved evidence, not normalized away',
83
+ patches: [
84
+ {
85
+ file: 'src/codexAppServer.ts',
86
+ // The early frame below is byte-for-byte the wire shape of the
87
+ // pristine `initialized` literal in codexAppServer.ts, so this
88
+ // mutation stays a PURE reorder. Drift teeth (Greptile finding on
89
+ // #3115): if the real notification ever gains fields, the early
90
+ // frame's content diverges and MutationCheckConformance's
91
+ // ordering-class assertion (equal sorted-line multiset) goes red
92
+ // until this patch is re-synced - the payload cannot silently rot.
93
+ find: ` const response = await sendRequest(websocket, pending, {
94
+ jsonrpc: '2.0',
95
+ id: 'initialize',
96
+ method: 'initialize',`,
97
+ replace: ` // [seeded differential mutation: handshake-initialized-reorder] the
98
+ // initialized notification jumps AHEAD of the initialize request.
99
+ websocket.send(JSON.stringify({ jsonrpc: '2.0', method: 'initialized' }));
100
+ const response = await sendRequest(websocket, pending, {
101
+ jsonrpc: '2.0',
102
+ id: 'initialize',
103
+ method: 'initialize',`,
104
+ },
105
+ {
106
+ file: 'src/codexAppServer.ts',
107
+ find: ` websocket.send(JSON.stringify(initialized));`,
108
+ replace: ` // [seeded differential mutation: handshake-initialized-reorder] the
109
+ // post-result send is suppressed (it already went out early above).`,
110
+ },
111
+ ],
112
+ },
113
+ ];