@neocompose/cli 0.24.8 → 0.24.9

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.24.9] - 2026-08-08
4
+
5
+ ### Fixed
6
+
7
+ - Build `neo test` execution documents from the server-prepared candidate and
8
+ compile every remaining authored initializer into evaluator-only IR. Tests
9
+ can now construct classes whose pending idless list rows capture lexical
10
+ selectors without requiring an earlier push.
11
+ - Index constructor-initializer ownership by class and member instead of
12
+ repeatedly scanning the project document. This reduces Neowyn's
13
+ initializer-owner walk from 87.8 ms to 24.9 ms median.
14
+
3
15
  ## [0.24.8] - 2026-08-08
4
16
 
5
17
  ### Fixed
package/dist/neo.mjs CHANGED
@@ -54910,6 +54910,14 @@ function resolveOwnerMembersForValues(document, targetValueIds, additionalRoots,
54910
54910
  const resolved = /* @__PURE__ */ new Map();
54911
54911
  if (targetValueIds.size === 0) return resolved;
54912
54912
  const valuesById = new Map(document.values.map((value) => [value.id, value]));
54913
+ const membersById = new Map(
54914
+ document.members.map((member) => [member.id, member])
54915
+ );
54916
+ const classesById = new Map(
54917
+ document.classes.map((schemaClass2) => [schemaClass2.id, schemaClass2])
54918
+ );
54919
+ const storedSchemaByClassId = /* @__PURE__ */ new Map();
54920
+ const defaultInstanceEnvByClassId = /* @__PURE__ */ new Map();
54913
54921
  const rowsByContainerId = /* @__PURE__ */ new Map();
54914
54922
  for (const value of document.values) {
54915
54923
  if (typeof value.containerId !== "string") continue;
@@ -54933,7 +54941,25 @@ function resolveOwnerMembersForValues(document, targetValueIds, additionalRoots,
54933
54941
  if (typeof memberId !== "string") return /* @__PURE__ */ new Map();
54934
54942
  const classId = declaringClassIdByMemberId.get(memberId);
54935
54943
  if (classId === void 0) return /* @__PURE__ */ new Map();
54936
- return resolveInstanceEnv(classId, void 0, document.classes);
54944
+ return defaultInstanceEnv(classId);
54945
+ }
54946
+ function defaultInstanceEnv(classId) {
54947
+ const cached = defaultInstanceEnvByClassId.get(classId);
54948
+ if (cached !== void 0) return cached;
54949
+ const created = resolveInstanceEnv(classId, void 0, document.classes);
54950
+ defaultInstanceEnvByClassId.set(classId, created);
54951
+ return created;
54952
+ }
54953
+ function storedSchema(classId) {
54954
+ const cached = storedSchemaByClassId.get(classId);
54955
+ if (cached !== void 0) return cached;
54956
+ const created = mergeStoredInstanceSchema(
54957
+ classId,
54958
+ document.classes,
54959
+ document.members
54960
+ );
54961
+ storedSchemaByClassId.set(classId, created);
54962
+ return created;
54937
54963
  }
54938
54964
  function searchRow(member, valueId, rootOwner, env, rootKind) {
54939
54965
  if (targetValueIds.has(valueId) && !resolved.has(valueId)) {
@@ -54972,16 +54998,10 @@ function resolveOwnerMembersForValues(document, targetValueIds, additionalRoots,
54972
54998
  if (isMemberClassBase(member)) {
54973
54999
  if (!isRecordValue(body.value)) return;
54974
55000
  const effectiveClassId = body.classId ?? member.classId;
54975
- const schemaClass2 = document.classes.find(
54976
- (candidate) => candidate.id === effectiveClassId
54977
- );
55001
+ const schemaClass2 = classesById.get(effectiveClassId);
54978
55002
  if (schemaClass2 === void 0) return;
54979
- const merged = mergeStoredInstanceSchema(
54980
- effectiveClassId,
54981
- document.classes,
54982
- document.members
54983
- );
54984
- const env = resolveInstanceEnv(
55003
+ const merged = storedSchema(effectiveClassId);
55004
+ const env = member.classArguments === void 0 || member.classArguments === null ? defaultInstanceEnv(effectiveClassId) : resolveInstanceEnv(
54985
55005
  effectiveClassId,
54986
55006
  member.classArguments,
54987
55007
  document.classes
@@ -54990,9 +55010,7 @@ function resolveOwnerMembersForValues(document, targetValueIds, additionalRoots,
54990
55010
  if (entry.memberId === null) continue;
54991
55011
  const childValueId = body.value[entry.schemaKey];
54992
55012
  if (childValueId === void 0) continue;
54993
- const childMember = document.members.find(
54994
- (candidate) => candidate.id === entry.memberId
54995
- );
55013
+ const childMember = membersById.get(entry.memberId);
54996
55014
  if (childMember === void 0) continue;
54997
55015
  const substituted = trySubstituteMember(childMember, env);
54998
55016
  if (substituted === null) continue;
@@ -55002,9 +55020,7 @@ function resolveOwnerMembersForValues(document, targetValueIds, additionalRoots,
55002
55020
  }
55003
55021
  if (isMemberDictionaryBase(member)) {
55004
55022
  if (!isRecordValue(body.value)) return;
55005
- const entryMemberRecord = document.members.find(
55006
- (candidate) => candidate.id === member.entryMemberId
55007
- );
55023
+ const entryMemberRecord = membersById.get(member.entryMemberId);
55008
55024
  if (entryMemberRecord === void 0) return;
55009
55025
  const entryEnv = overlayStamp(ambientEnv, body.genericBindings);
55010
55026
  const entryMember = trySubstituteMember(entryMemberRecord, entryEnv);
@@ -55015,9 +55031,7 @@ function resolveOwnerMembersForValues(document, targetValueIds, additionalRoots,
55015
55031
  return;
55016
55032
  }
55017
55033
  if (isMemberListBase(member)) {
55018
- const entryMemberRecord = document.members.find(
55019
- (candidate) => candidate.id === member.entryMemberId
55020
- );
55034
+ const entryMemberRecord = membersById.get(member.entryMemberId);
55021
55035
  if (entryMemberRecord === void 0) return;
55022
55036
  const entryEnv = overlayStamp(ambientEnv, body.genericBindings);
55023
55037
  const entryMember = trySubstituteMember(entryMemberRecord, entryEnv);
@@ -63462,21 +63476,17 @@ function initializerEvaluatorLookups(document) {
63462
63476
  });
63463
63477
  return lookups;
63464
63478
  }
63465
- function buildInitializerRootValue(document) {
63479
+ function buildInitializerRootValue(document, lookups) {
63466
63480
  const rootValue = {};
63467
- const memberById = new Map(
63468
- document.members.map((member) => [member.id, member])
63469
- );
63470
- const valueById = new Map(document.values.map((row) => [row.id, row]));
63471
63481
  for (const { root, memberId } of projectRootMembersInDisplayOrder(
63472
63482
  document.project
63473
63483
  )) {
63474
- const member = memberById.get(memberId);
63475
- if (member === void 0 || typeof member.valueId !== "string") {
63484
+ const member = lookups.memberById(memberId);
63485
+ if (member === null || typeof member.valueId !== "string") {
63476
63486
  rootValue[root.key] = null;
63477
63487
  continue;
63478
63488
  }
63479
- rootValue[root.key] = valueById.get(member.valueId)?.value ?? null;
63489
+ rootValue[root.key] = lookups.valueById(member.valueId)?.value ?? null;
63480
63490
  }
63481
63491
  return rootValue;
63482
63492
  }
@@ -63489,6 +63499,7 @@ function evaluateMemberInitializer(args) {
63489
63499
  args.init
63490
63500
  );
63491
63501
  }
63502
+ const databaseVM = initializerEvaluatorLookups(args.document);
63492
63503
  const ctx = {
63493
63504
  vm: {
63494
63505
  project: args.document.project,
@@ -63502,10 +63513,10 @@ function evaluateMemberInitializer(args) {
63502
63513
  interfaces: args.document.interfaces,
63503
63514
  localizedTexts: args.document.localizedTexts,
63504
63515
  localizationConfig: args.document.localizationConfig,
63505
- databaseVM: initializerEvaluatorLookups(args.document)
63516
+ databaseVM
63506
63517
  },
63507
63518
  thisValue: null,
63508
- rootValue: buildInitializerRootValue(args.document),
63519
+ rootValue: buildInitializerRootValue(args.document, databaseVM),
63509
63520
  saveStaticBindings: args.saveStaticBindings,
63510
63521
  sessionStaticBindings: args.sessionStaticBindings,
63511
63522
  ...args.storedConstructionReplay === true ? {
@@ -84137,6 +84148,7 @@ function assertServerPreparationSucceeds(args) {
84137
84148
  prepared
84138
84149
  );
84139
84150
  }
84151
+ return prepared;
84140
84152
  } catch (error) {
84141
84153
  throw locateBodyCompileFailure(error, args.sourceByRecord);
84142
84154
  }
@@ -84354,7 +84366,7 @@ function replayStoredConstructionV4(args) {
84354
84366
  "Construction replay cannot compile document bodies without a compiler project."
84355
84367
  );
84356
84368
  }
84357
- compilePulledProjectDocumentBodiesV4(document, compilationProject);
84369
+ compilePulledProjectDocumentForEvaluationV4(document, compilationProject);
84358
84370
  }
84359
84371
  const root = document.values.find((value) => value.id === args.valueId);
84360
84372
  if (root === void 0) {
@@ -84550,7 +84562,16 @@ function compilePulledValueInitializerBodyV4(document, valueId, compilationProje
84550
84562
  ...compilationProject === void 0 ? {} : { compilationProject }
84551
84563
  });
84552
84564
  }
84553
- function compilePulledProjectDocumentBodiesV4(document, compilationProject) {
84565
+ function compilePulledProjectDocumentForEvaluationV4(document, compilationProject) {
84566
+ const sharedCompilationProject = compilationProject ?? createNeoScriptCompilationProject({
84567
+ project: document.project,
84568
+ projectFiles: document.projectFiles,
84569
+ members: document.members,
84570
+ classes: document.classes,
84571
+ enums: document.enums,
84572
+ interfaces: document.interfaces,
84573
+ constructors: document.constructors ?? []
84574
+ });
84554
84575
  const compileArgs = {
84555
84576
  project: document.project,
84556
84577
  projectFiles: document.projectFiles,
@@ -84559,7 +84580,7 @@ function compilePulledProjectDocumentBodiesV4(document, compilationProject) {
84559
84580
  enums: document.enums,
84560
84581
  interfaces: document.interfaces,
84561
84582
  constructors: document.constructors ?? [],
84562
- compilationProject
84583
+ compilationProject: sharedCompilationProject
84563
84584
  };
84564
84585
  for (const constructor2 of compileArgs.constructors) {
84565
84586
  compileConstructorRecord({ ...compileArgs, constructor: constructor2 });
@@ -84579,6 +84600,20 @@ function compilePulledProjectDocumentBodiesV4(document, compilationProject) {
84579
84600
  thisClass: ownerClassByMemberId.get(member.id) ?? null
84580
84601
  });
84581
84602
  }
84603
+ for (const site of valueInitializerCompilationSites(document).values()) {
84604
+ if (isInitValueContent(site.row) && site.row.init.compiled !== void 0) {
84605
+ continue;
84606
+ }
84607
+ compileValueRowInitializerBody({
84608
+ ...compileArgs,
84609
+ member: site.member,
84610
+ valueRow: site.row,
84611
+ valueId: String(Reflect.get(site.row, "id")),
84612
+ initializerOwnerClass: site.ownerClass,
84613
+ lexicalThisClass: site.lexicalThisClass,
84614
+ storedConstructionReplay: true
84615
+ });
84616
+ }
84582
84617
  }
84583
84618
  function assertPulledConstructorsCompiled(document) {
84584
84619
  const uncompiled = (document.constructors ?? []).find(
@@ -100098,6 +100133,7 @@ async function prepareLocalPushArtifactsV4(workspace, status, onPhase = () => vo
100098
100133
  status.changes,
100099
100134
  localizedTextCreateEnvelopeConfig2(workspace, status.changes)
100100
100135
  );
100136
+ let preparedChanges = null;
100101
100137
  if (options.fullValidation) {
100102
100138
  onPhase("Verifying the complete source round trip\u2026");
100103
100139
  verifyProjectSourceCommitAgainstStateV4({
@@ -100114,7 +100150,7 @@ async function prepareLocalPushArtifactsV4(workspace, status, onPhase = () => vo
100114
100150
  onPhase(
100115
100151
  `Rehearsing server validation for ${transportChanges.length.toLocaleString("en-US")} change(s)\u2026`
100116
100152
  );
100117
- assertServerPreparationSucceeds({
100153
+ preparedChanges = assertServerPreparationSucceeds({
100118
100154
  workspace,
100119
100155
  changes: transportChanges,
100120
100156
  authoredValueSeeds: transportSeeds,
@@ -100129,7 +100165,8 @@ async function prepareLocalPushArtifactsV4(workspace, status, onPhase = () => vo
100129
100165
  transactionOperation,
100130
100166
  transportChanges,
100131
100167
  transportSeeds,
100132
- preparedFiles
100168
+ preparedFiles,
100169
+ preparedChanges
100133
100170
  };
100134
100171
  }
100135
100172
  async function prepareLocalCandidateV4(workspace, options = {}) {
@@ -100203,8 +100240,23 @@ async function prepareLocalCandidateV4(workspace, options = {}) {
100203
100240
  if (typeof baseId === "string") {
100204
100241
  records2.delete(`${change.recordKind}:${baseId}`);
100205
100242
  }
100243
+ }
100244
+ const candidateChanges = preparedLocal?.preparedChanges ?? documentStatus.changes.map((change) => ({
100245
+ recordKind: change.recordKind,
100246
+ recordId: change.recordId,
100247
+ operation: change.kind,
100248
+ nextData: change.nextData
100249
+ }));
100250
+ for (const change of candidateChanges) {
100206
100251
  records2.delete(`${change.recordKind}:${change.recordId}`);
100207
- if (change.nextData === void 0) continue;
100252
+ if (change.operation === "delete" || change.nextData === void 0) {
100253
+ continue;
100254
+ }
100255
+ if (!isObjectRecord2(change.nextData)) {
100256
+ throw new Error(
100257
+ `Prepared ${change.recordKind} record ${JSON.stringify(change.recordId)} has invalid data.`
100258
+ );
100259
+ }
100208
100260
  const nextId = typeof change.nextData.id === "string" ? change.nextData.id : change.recordId;
100209
100261
  records2.set(`${change.recordKind}:${nextId}`, {
100210
100262
  recordKind: change.recordKind,
@@ -100214,9 +100266,11 @@ async function prepareLocalCandidateV4(workspace, options = {}) {
100214
100266
  data: change.nextData
100215
100267
  });
100216
100268
  }
100269
+ const document = readPulledProjectDocumentV4(records2);
100270
+ compilePulledProjectDocumentForEvaluationV4(document);
100217
100271
  return {
100218
100272
  status,
100219
- document: readPulledProjectDocumentV4(records2),
100273
+ document,
100220
100274
  sourceHash,
100221
100275
  preparedLocal
100222
100276
  };
@@ -101670,7 +101724,7 @@ var init_registry2 = __esm({
101670
101724
  PROJECT_SCHEMA_CONTRACT = Object.freeze({
101671
101725
  formatVersion: 3,
101672
101726
  contractVersion: "3.9",
101673
- cliVersion: "0.24.8",
101727
+ cliVersion: "0.24.9",
101674
101728
  projectFileUploadBatchSize: 32,
101675
101729
  documentRecords: {
101676
101730
  member: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@neocompose/cli",
3
- "version": "0.24.8",
3
+ "version": "0.24.9",
4
4
  "description": "Neo Compose native project-source CLI with bidirectional sync.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -9,7 +9,7 @@ description: >-
9
9
  `@neocompose/cli` or `node cli/bin/neo.mjs` in the neo-compose repository.
10
10
  ---
11
11
 
12
- <!-- reviewed-through-cli: 0.24.8 -->
12
+ <!-- reviewed-through-cli: 0.24.9 -->
13
13
 
14
14
  # Neo Compose CLI
15
15
 
@@ -30,6 +30,9 @@ Those are not part of format 4.
30
30
  existed before the task began.
31
31
  4. Run `neo test` after NeoScript changes and `neo dialogue dryrun <ref>` after
32
32
  dialogue changes.
33
+ `neo test` compiles the complete pending candidate, including idless nested
34
+ construction rows, so tests must work before the first push; do not add IDs
35
+ or push merely to obtain compiled initializer bodies.
33
36
  5. Run `neo push --dry-run` before every real push. It performs the full local
34
37
  source emission, ID-assignment, transport-shape, hash, and repeat-verification path,
35
38
  then rehearses the server's preparation phase — schema-commit
@@ -82,7 +82,7 @@ wrappers.
82
82
  The marker near the top of `SKILL.md` must exactly match the package version:
83
83
 
84
84
  ```html
85
- <!-- reviewed-through-cli: 0.24.8 -->
85
+ <!-- reviewed-through-cli: 0.24.9 -->
86
86
  ```
87
87
 
88
88
  The quoted version above is checked too, so this instruction cannot go stale