@neocompose/cli 0.22.1 → 0.22.2
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,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.22.2] - 2026-08-04
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- Dependency-selected NeoScript preparation narrows source-only bodies by
|
|
8
|
+
recoverable changed-contract identifiers instead of recompiling every body
|
|
9
|
+
without stored IR. Structurally affected owners and source that cannot be
|
|
10
|
+
lexically recovered retain the conservative fallback.
|
|
11
|
+
- Optimized-versus-exhaustive fuzz parity now covers class, enum, value,
|
|
12
|
+
dialogue-node, and dialogue-group edits in addition to member edits.
|
|
13
|
+
- Normal `neo pull` persists a transaction cursor and downloads only records
|
|
14
|
+
changed since the previous sync. Source-neutral deltas update local state
|
|
15
|
+
without rebuilding the complete canonical project source.
|
|
16
|
+
|
|
3
17
|
## [0.22.1] - 2026-08-04
|
|
4
18
|
|
|
5
19
|
### Fixed
|
package/README.md
CHANGED
|
@@ -92,7 +92,10 @@ neo init --project <id> --version <id> --dir neo
|
|
|
92
92
|
|
|
93
93
|
For an existing format-4 workspace, `neo pull --reset` regenerates canonical
|
|
94
94
|
source and managed binaries. Normal `neo pull` performs a stable-ID-aware
|
|
95
|
-
three-way merge
|
|
95
|
+
three-way merge, preserves source placement when possible, and uses a durable
|
|
96
|
+
transaction cursor to fetch only records changed since the previous sync.
|
|
97
|
+
Undo/reset metadata invalidates that cursor and safely falls back to a full
|
|
98
|
+
snapshot.
|
|
96
99
|
|
|
97
100
|
In Unity projects, `neo.json` may use `unityConfigPath` instead of storing
|
|
98
101
|
`projectId` and `versionId`. The referenced `NeoComposeConfig.asset` then owns
|
package/dist/neo.mjs
CHANGED
|
@@ -68316,13 +68316,21 @@ function collectNeoScriptRecompileTargets(args) {
|
|
|
68316
68316
|
}
|
|
68317
68317
|
}
|
|
68318
68318
|
const constructorOwnerById = constructorOwners(args.postDocument);
|
|
68319
|
+
const impactedSourceNames = collectImpactedSourceNames({
|
|
68320
|
+
currentDocument: args.currentDocument,
|
|
68321
|
+
postDocument: args.postDocument,
|
|
68322
|
+
impactedIds,
|
|
68323
|
+
impactedTypeNames,
|
|
68324
|
+
constructedClassIds
|
|
68325
|
+
});
|
|
68319
68326
|
const memberIds = new Set(explicit.memberIds);
|
|
68320
68327
|
for (const member of args.postDocument.members) {
|
|
68321
68328
|
if (recordDependsOnChangedContract(
|
|
68322
68329
|
member,
|
|
68323
68330
|
impactedIds,
|
|
68324
68331
|
impactedTypeNames,
|
|
68325
|
-
constructedClassIds
|
|
68332
|
+
constructedClassIds,
|
|
68333
|
+
impactedSourceNames
|
|
68326
68334
|
)) {
|
|
68327
68335
|
memberIds.add(member.id);
|
|
68328
68336
|
}
|
|
@@ -68333,7 +68341,8 @@ function collectNeoScriptRecompileTargets(args) {
|
|
|
68333
68341
|
explicit.valueIds,
|
|
68334
68342
|
impactedIds,
|
|
68335
68343
|
impactedTypeNames,
|
|
68336
|
-
constructedClassIds
|
|
68344
|
+
constructedClassIds,
|
|
68345
|
+
impactedSourceNames
|
|
68337
68346
|
);
|
|
68338
68347
|
if (impactedIds.size > 0 && postValues.length > 0) {
|
|
68339
68348
|
const ownerByValueId = resolveOwnerMembersForValues(
|
|
@@ -68356,6 +68365,7 @@ function collectNeoScriptRecompileTargets(args) {
|
|
|
68356
68365
|
impactedIds,
|
|
68357
68366
|
impactedTypeNames,
|
|
68358
68367
|
constructedClassIds,
|
|
68368
|
+
impactedSourceNames,
|
|
68359
68369
|
(record3) => constructorOwnerById.get(record3.id) ?? null
|
|
68360
68370
|
),
|
|
68361
68371
|
migrationIds: selectedRecordIds(
|
|
@@ -68363,21 +68373,24 @@ function collectNeoScriptRecompileTargets(args) {
|
|
|
68363
68373
|
explicit.migrationIds,
|
|
68364
68374
|
impactedIds,
|
|
68365
68375
|
impactedTypeNames,
|
|
68366
|
-
constructedClassIds
|
|
68376
|
+
constructedClassIds,
|
|
68377
|
+
impactedSourceNames
|
|
68367
68378
|
),
|
|
68368
68379
|
dialogueNodeIds: selectedRecordIds(
|
|
68369
68380
|
args.postDocument.dialogueNodes ?? [],
|
|
68370
68381
|
explicit.dialogueNodeIds,
|
|
68371
68382
|
impactedIds,
|
|
68372
68383
|
impactedTypeNames,
|
|
68373
|
-
constructedClassIds
|
|
68384
|
+
constructedClassIds,
|
|
68385
|
+
impactedSourceNames
|
|
68374
68386
|
),
|
|
68375
68387
|
dialogueGroupIds: selectedRecordIds(
|
|
68376
68388
|
args.postDocument.dialogueGroups ?? [],
|
|
68377
68389
|
explicit.dialogueGroupIds,
|
|
68378
68390
|
impactedIds,
|
|
68379
68391
|
impactedTypeNames,
|
|
68380
|
-
constructedClassIds
|
|
68392
|
+
constructedClassIds,
|
|
68393
|
+
impactedSourceNames
|
|
68381
68394
|
),
|
|
68382
68395
|
valueIds
|
|
68383
68396
|
};
|
|
@@ -68746,7 +68759,7 @@ function explicitTargetIds(changes) {
|
|
|
68746
68759
|
}
|
|
68747
68760
|
return result;
|
|
68748
68761
|
}
|
|
68749
|
-
function selectedRecordIds(records2, explicitIds, impactedIds, impactedTypeNames, constructedClassIds, ownerId = () => null) {
|
|
68762
|
+
function selectedRecordIds(records2, explicitIds, impactedIds, impactedTypeNames, constructedClassIds, impactedSourceNames, ownerId = () => null) {
|
|
68750
68763
|
const selected2 = new Set(explicitIds);
|
|
68751
68764
|
for (const record3 of records2) {
|
|
68752
68765
|
const owner = ownerId(record3);
|
|
@@ -68754,14 +68767,17 @@ function selectedRecordIds(records2, explicitIds, impactedIds, impactedTypeNames
|
|
|
68754
68767
|
record3,
|
|
68755
68768
|
impactedIds,
|
|
68756
68769
|
impactedTypeNames,
|
|
68757
|
-
constructedClassIds
|
|
68770
|
+
constructedClassIds,
|
|
68771
|
+
impactedSourceNames
|
|
68758
68772
|
)) {
|
|
68759
68773
|
selected2.add(record3.id);
|
|
68760
68774
|
}
|
|
68761
68775
|
}
|
|
68762
68776
|
return selected2;
|
|
68763
68777
|
}
|
|
68764
|
-
function recordDependsOnChangedContract(record3, impactedIds, impactedTypeNames, constructedClassIds) {
|
|
68778
|
+
function recordDependsOnChangedContract(record3, impactedIds, impactedTypeNames, constructedClassIds, impactedSourceNames) {
|
|
68779
|
+
const recordId = isObjectRecord3(record3) ? record3.id : void 0;
|
|
68780
|
+
if (typeof recordId === "string" && impactedIds.has(recordId)) return true;
|
|
68765
68781
|
if (intersects(collectCompilerReferenceIds(record3), impactedIds)) return true;
|
|
68766
68782
|
if (intersects(collectCompilerReferenceNames(record3), impactedTypeNames)) {
|
|
68767
68783
|
return true;
|
|
@@ -68769,7 +68785,109 @@ function recordDependsOnChangedContract(record3, impactedIds, impactedTypeNames,
|
|
|
68769
68785
|
if (intersects(collectConstructedClassIds(record3), constructedClassIds)) {
|
|
68770
68786
|
return true;
|
|
68771
68787
|
}
|
|
68772
|
-
|
|
68788
|
+
if (impactedIds.size === 0 && impactedTypeNames.size === 0) return false;
|
|
68789
|
+
if (!containsAuthoredNeoScriptSource(record3)) return false;
|
|
68790
|
+
if (containsCompiledNeoScriptBody(record3)) return false;
|
|
68791
|
+
if (impactedSourceNames === null) return true;
|
|
68792
|
+
const sourceIdentifiers = collectAuthoredNeoScriptSourceIdentifiers(record3);
|
|
68793
|
+
if (sourceIdentifiers === null) return true;
|
|
68794
|
+
return intersects(sourceIdentifiers, impactedSourceNames);
|
|
68795
|
+
}
|
|
68796
|
+
function collectImpactedSourceNames(args) {
|
|
68797
|
+
const names = new Set(args.impactedTypeNames);
|
|
68798
|
+
let recoveredContract = args.impactedTypeNames.size > 0;
|
|
68799
|
+
const collectDocument = (document) => {
|
|
68800
|
+
const classById = new Map(
|
|
68801
|
+
document.classes.map((schemaClass2) => [schemaClass2.id, schemaClass2])
|
|
68802
|
+
);
|
|
68803
|
+
const ownerByConstructorId = constructorOwners(document);
|
|
68804
|
+
const impactedValueIds = new Set(
|
|
68805
|
+
(document.values ?? []).filter((value) => args.impactedIds.has(value.id)).map((value) => value.id)
|
|
68806
|
+
);
|
|
68807
|
+
const ownerByValueId = resolveOwnerMembersForValues(
|
|
68808
|
+
document,
|
|
68809
|
+
impactedValueIds
|
|
68810
|
+
);
|
|
68811
|
+
for (const owner of ownerByValueId.values()) {
|
|
68812
|
+
recoveredContract = true;
|
|
68813
|
+
collectDeclaredSourceNames(owner, names);
|
|
68814
|
+
const ownerId = Reflect.get(owner, "id");
|
|
68815
|
+
if (typeof ownerId !== "string") continue;
|
|
68816
|
+
for (const classId of classPlacementsForMember(ownerId, document)) {
|
|
68817
|
+
const schemaClass2 = classById.get(classId);
|
|
68818
|
+
if (schemaClass2 !== void 0) {
|
|
68819
|
+
collectDeclaredSourceNames(schemaClass2, names);
|
|
68820
|
+
}
|
|
68821
|
+
}
|
|
68822
|
+
}
|
|
68823
|
+
const records2 = [
|
|
68824
|
+
...document.classes,
|
|
68825
|
+
...document.members,
|
|
68826
|
+
...document.constructors ?? [],
|
|
68827
|
+
...document.enums,
|
|
68828
|
+
...document.interfaces ?? [],
|
|
68829
|
+
...document.values ?? []
|
|
68830
|
+
];
|
|
68831
|
+
for (const record3 of records2) {
|
|
68832
|
+
if (!args.impactedIds.has(record3.id)) continue;
|
|
68833
|
+
recoveredContract = true;
|
|
68834
|
+
collectDeclaredSourceNames(record3, names);
|
|
68835
|
+
const ownerClassId = ownerByConstructorId.get(record3.id);
|
|
68836
|
+
if (ownerClassId === void 0) continue;
|
|
68837
|
+
const owner = classById.get(ownerClassId);
|
|
68838
|
+
if (owner !== void 0) collectDeclaredSourceNames(owner, names);
|
|
68839
|
+
}
|
|
68840
|
+
for (const schemaClass2 of document.classes) {
|
|
68841
|
+
if (!args.constructedClassIds.has(schemaClass2.id)) continue;
|
|
68842
|
+
recoveredContract = true;
|
|
68843
|
+
collectDeclaredSourceNames(schemaClass2, names);
|
|
68844
|
+
}
|
|
68845
|
+
};
|
|
68846
|
+
collectDocument(args.currentDocument);
|
|
68847
|
+
collectDocument(args.postDocument);
|
|
68848
|
+
return recoveredContract ? names : null;
|
|
68849
|
+
}
|
|
68850
|
+
function collectDeclaredSourceNames(value, names) {
|
|
68851
|
+
if (Array.isArray(value)) {
|
|
68852
|
+
for (const child of value) collectDeclaredSourceNames(child, names);
|
|
68853
|
+
return;
|
|
68854
|
+
}
|
|
68855
|
+
if (!isObjectRecord3(value)) return;
|
|
68856
|
+
for (const [field, child] of Object.entries(value)) {
|
|
68857
|
+
if (typeof child === "string" && (field === "name" || field === "sourceName" || field === "sourceFunctionName" || field === "declaredTypeName" || field === "typeName")) {
|
|
68858
|
+
names.add(child);
|
|
68859
|
+
continue;
|
|
68860
|
+
}
|
|
68861
|
+
collectDeclaredSourceNames(child, names);
|
|
68862
|
+
}
|
|
68863
|
+
}
|
|
68864
|
+
function collectAuthoredNeoScriptSourceIdentifiers(value) {
|
|
68865
|
+
const identifiers = /* @__PURE__ */ new Set();
|
|
68866
|
+
let complete2 = true;
|
|
68867
|
+
const collect = (child) => {
|
|
68868
|
+
if (Array.isArray(child)) {
|
|
68869
|
+
for (const entry of child) collect(entry);
|
|
68870
|
+
return;
|
|
68871
|
+
}
|
|
68872
|
+
if (!isObjectRecord3(child)) return;
|
|
68873
|
+
for (const [field, nested] of Object.entries(child)) {
|
|
68874
|
+
if ((field === "code" || field === "setterCode") && typeof nested === "string") {
|
|
68875
|
+
const result = lex(nested);
|
|
68876
|
+
if (result.diagnostics.some(
|
|
68877
|
+
(diagnostic) => diagnostic.severity === "error"
|
|
68878
|
+
)) {
|
|
68879
|
+
complete2 = false;
|
|
68880
|
+
}
|
|
68881
|
+
for (const token of result.tokens) {
|
|
68882
|
+
if (token.kind === "identifier") identifiers.add(token.text);
|
|
68883
|
+
}
|
|
68884
|
+
continue;
|
|
68885
|
+
}
|
|
68886
|
+
collect(nested);
|
|
68887
|
+
}
|
|
68888
|
+
};
|
|
68889
|
+
collect(value);
|
|
68890
|
+
return complete2 ? identifiers : null;
|
|
68773
68891
|
}
|
|
68774
68892
|
function containsAuthoredNeoScriptSource(value) {
|
|
68775
68893
|
if (Array.isArray(value)) {
|
|
@@ -68868,6 +68986,7 @@ var init_neo_script_recompile_scope = __esm({
|
|
|
68868
68986
|
"../src/database/neo-script-recompile-scope.ts"() {
|
|
68869
68987
|
"use strict";
|
|
68870
68988
|
init_canonical_json();
|
|
68989
|
+
init_src();
|
|
68871
68990
|
init_member_kind_enum();
|
|
68872
68991
|
init_inheritance();
|
|
68873
68992
|
init_effective_storage();
|
|
@@ -87199,20 +87318,172 @@ async function fetchProjectDocument(workspace) {
|
|
|
87199
87318
|
});
|
|
87200
87319
|
}
|
|
87201
87320
|
}
|
|
87321
|
+
const revision = readProjectDocumentRevisionMarker2(raw);
|
|
87202
87322
|
return {
|
|
87203
87323
|
records: records2,
|
|
87204
87324
|
heads,
|
|
87205
|
-
raw
|
|
87325
|
+
raw,
|
|
87326
|
+
...revision === null ? {} : { revision }
|
|
87327
|
+
};
|
|
87328
|
+
}
|
|
87329
|
+
async function fetchProjectDocumentSyncMarker(workspace) {
|
|
87330
|
+
const convex = await createConvexClient(workspace);
|
|
87331
|
+
return queryProjectDocumentSyncMarker(workspace, convex);
|
|
87332
|
+
}
|
|
87333
|
+
async function queryProjectDocumentSyncMarker(workspace, convex) {
|
|
87334
|
+
const [revisionValue, signal] = await Promise.all([
|
|
87335
|
+
convex.query(api2.projectDocuments.getDocumentRevision, {
|
|
87336
|
+
projectId: workspace.config.projectId,
|
|
87337
|
+
versionId: workspace.config.versionId
|
|
87338
|
+
}),
|
|
87339
|
+
convex.query(api2.projectExportData.schemaSignal, {
|
|
87340
|
+
projectId: workspace.config.projectId,
|
|
87341
|
+
versionId: workspace.config.versionId
|
|
87342
|
+
})
|
|
87343
|
+
]);
|
|
87344
|
+
if (!isProjectDocumentRevisionMarker(revisionValue)) {
|
|
87345
|
+
throw new Error(
|
|
87346
|
+
"Project document revision query returned an invalid cursor marker."
|
|
87347
|
+
);
|
|
87348
|
+
}
|
|
87349
|
+
return {
|
|
87350
|
+
revision: revisionValue,
|
|
87351
|
+
headTransactionId: signal?.transactionId ?? null,
|
|
87352
|
+
headTransactionHash: signal?.transactionHash ?? null
|
|
87353
|
+
};
|
|
87354
|
+
}
|
|
87355
|
+
async function fetchProjectDocumentDelta(workspace, cursor) {
|
|
87356
|
+
const convex = await createConvexClient(workspace);
|
|
87357
|
+
const marker = await queryProjectDocumentSyncMarker(workspace, convex);
|
|
87358
|
+
if (marker.revision.versionsStamp !== cursor.versionsStamp) {
|
|
87359
|
+
return {
|
|
87360
|
+
fullResync: true,
|
|
87361
|
+
headTransactionHash: marker.headTransactionHash
|
|
87362
|
+
};
|
|
87363
|
+
}
|
|
87364
|
+
if (marker.headTransactionId === marker.revision.latestTransactionId && marker.headTransactionHash === workspace.state.headTransactionHash) {
|
|
87365
|
+
return {
|
|
87366
|
+
fullResync: false,
|
|
87367
|
+
document: projectDocumentFromWorkspaceState(workspace.state, cursor),
|
|
87368
|
+
changedKeys: /* @__PURE__ */ new Set(),
|
|
87369
|
+
cursor,
|
|
87370
|
+
headTransactionHash: marker.headTransactionHash
|
|
87371
|
+
};
|
|
87372
|
+
}
|
|
87373
|
+
const result = await convex.query(api2.projectDocuments.getRecordsSince, {
|
|
87374
|
+
projectId: workspace.config.projectId,
|
|
87375
|
+
versionId: workspace.config.versionId,
|
|
87376
|
+
sinceCreatedAt: cursor.createdAt,
|
|
87377
|
+
seenTransactionIds: [...cursor.transactionIds]
|
|
87378
|
+
});
|
|
87379
|
+
if (result.fullResync) {
|
|
87380
|
+
return {
|
|
87381
|
+
fullResync: true,
|
|
87382
|
+
headTransactionHash: marker.headTransactionHash
|
|
87383
|
+
};
|
|
87384
|
+
}
|
|
87385
|
+
const document = projectDocumentFromWorkspaceState(workspace.state, cursor);
|
|
87386
|
+
const { records: records2, heads } = document;
|
|
87387
|
+
const changedKeys = /* @__PURE__ */ new Set();
|
|
87388
|
+
for (const record3 of result.records) {
|
|
87389
|
+
const key = `${record3.recordKind}:${record3.recordId}`;
|
|
87390
|
+
changedKeys.add(key);
|
|
87391
|
+
if (record3.deleted) {
|
|
87392
|
+
records2.delete(key);
|
|
87393
|
+
heads.set(key, {
|
|
87394
|
+
recordKind: record3.recordKind,
|
|
87395
|
+
recordId: record3.recordId,
|
|
87396
|
+
contentHash: "",
|
|
87397
|
+
deleted: true
|
|
87398
|
+
});
|
|
87399
|
+
continue;
|
|
87400
|
+
}
|
|
87401
|
+
if (record3.contentHash === null) {
|
|
87402
|
+
throw new Error(
|
|
87403
|
+
`Project document delta record "${key}" is live but has no content hash.`
|
|
87404
|
+
);
|
|
87405
|
+
}
|
|
87406
|
+
records2.set(key, {
|
|
87407
|
+
recordKind: record3.recordKind,
|
|
87408
|
+
recordId: record3.recordId,
|
|
87409
|
+
contentHash: record3.contentHash,
|
|
87410
|
+
deleted: false,
|
|
87411
|
+
data: record3.data
|
|
87412
|
+
});
|
|
87413
|
+
heads.set(key, {
|
|
87414
|
+
recordKind: record3.recordKind,
|
|
87415
|
+
recordId: record3.recordId,
|
|
87416
|
+
contentHash: record3.contentHash,
|
|
87417
|
+
deleted: false
|
|
87418
|
+
});
|
|
87419
|
+
}
|
|
87420
|
+
const next = result.cursor ?? cursor;
|
|
87421
|
+
const nextCursor = {
|
|
87422
|
+
createdAt: next.createdAt,
|
|
87423
|
+
transactionIds: [...next.transactionIds],
|
|
87424
|
+
versionsStamp: marker.revision.versionsStamp
|
|
87425
|
+
};
|
|
87426
|
+
return {
|
|
87427
|
+
fullResync: false,
|
|
87428
|
+
document: projectDocumentWithRevision(document, nextCursor),
|
|
87429
|
+
changedKeys,
|
|
87430
|
+
cursor: nextCursor,
|
|
87431
|
+
headTransactionHash: marker.headTransactionHash
|
|
87432
|
+
};
|
|
87433
|
+
}
|
|
87434
|
+
function projectDocumentFromWorkspaceState(state, cursor) {
|
|
87435
|
+
const records2 = serverRecordsFromWorkspaceState(state);
|
|
87436
|
+
const heads = new Map(
|
|
87437
|
+
[...records2].map(([key, record3]) => [
|
|
87438
|
+
key,
|
|
87439
|
+
{
|
|
87440
|
+
recordKind: record3.recordKind,
|
|
87441
|
+
recordId: record3.recordId,
|
|
87442
|
+
contentHash: record3.contentHash,
|
|
87443
|
+
deleted: false
|
|
87444
|
+
}
|
|
87445
|
+
])
|
|
87446
|
+
);
|
|
87447
|
+
return projectDocumentWithRevision({ records: records2, heads, raw: {} }, cursor);
|
|
87448
|
+
}
|
|
87449
|
+
function projectDocumentWithRevision(document, cursor) {
|
|
87450
|
+
return {
|
|
87451
|
+
...document,
|
|
87452
|
+
revision: {
|
|
87453
|
+
latestTransactionId: cursor.transactionIds[cursor.transactionIds.length - 1] ?? null,
|
|
87454
|
+
latestTransactionCreatedAt: cursor.createdAt,
|
|
87455
|
+
versionsStamp: cursor.versionsStamp
|
|
87456
|
+
}
|
|
87206
87457
|
};
|
|
87207
87458
|
}
|
|
87208
|
-
|
|
87459
|
+
function serverRecordsFromWorkspaceState(state) {
|
|
87460
|
+
const records2 = /* @__PURE__ */ new Map();
|
|
87461
|
+
for (const [key, record3] of Object.entries(state.records)) {
|
|
87462
|
+
if (record3.conflictServerHash === null) continue;
|
|
87463
|
+
const conflictServerHash = record3.conflictServerHash;
|
|
87464
|
+
const hasConflictServer = conflictServerHash !== void 0;
|
|
87465
|
+
records2.set(key, {
|
|
87466
|
+
recordKind: record3.recordKind,
|
|
87467
|
+
recordId: record3.recordId,
|
|
87468
|
+
contentHash: hasConflictServer ? conflictServerHash : record3.contentHash,
|
|
87469
|
+
deleted: false,
|
|
87470
|
+
data: hasConflictServer ? record3.conflictServerData : record3.data
|
|
87471
|
+
});
|
|
87472
|
+
}
|
|
87473
|
+
return records2;
|
|
87474
|
+
}
|
|
87475
|
+
var fetchProjectDocumentRawChunked2, readProjectDocumentContentHashHeads2, readProjectDocumentRevisionMarker2, SOURCE_RECORD_KINDS;
|
|
87209
87476
|
var init_document = __esm({
|
|
87210
87477
|
"src/document.ts"() {
|
|
87211
87478
|
"use strict";
|
|
87212
87479
|
init_project_document_read();
|
|
87213
87480
|
init_project2();
|
|
87214
87481
|
init_convex();
|
|
87215
|
-
({
|
|
87482
|
+
({
|
|
87483
|
+
fetchProjectDocumentRawChunked: fetchProjectDocumentRawChunked2,
|
|
87484
|
+
readProjectDocumentContentHashHeads: readProjectDocumentContentHashHeads2,
|
|
87485
|
+
readProjectDocumentRevisionMarker: readProjectDocumentRevisionMarker2
|
|
87486
|
+
} = project_document_read_exports);
|
|
87216
87487
|
SOURCE_RECORD_KINDS = new Set(
|
|
87217
87488
|
Object.values(ProjectRecordKind)
|
|
87218
87489
|
);
|
|
@@ -87899,6 +88170,7 @@ var init_static_value_seed_records = __esm({
|
|
|
87899
88170
|
// src/commands/pull.ts
|
|
87900
88171
|
var pull_exports = {};
|
|
87901
88172
|
__export(pull_exports, {
|
|
88173
|
+
deltaRequiresSourceProjectionV4: () => deltaRequiresSourceProjectionV4,
|
|
87902
88174
|
projectSourcePathsRequiringRewriteV4: () => projectSourcePathsRequiringRewriteV4,
|
|
87903
88175
|
runPull: () => runPull
|
|
87904
88176
|
});
|
|
@@ -87915,6 +88187,15 @@ async function runPull(workspace, options) {
|
|
|
87915
88187
|
await runResetPull(workspace);
|
|
87916
88188
|
return;
|
|
87917
88189
|
}
|
|
88190
|
+
const progress = spinner("Checking local workspace\u2026");
|
|
88191
|
+
try {
|
|
88192
|
+
await runNormalPull(workspace, options, progress);
|
|
88193
|
+
} catch (error) {
|
|
88194
|
+
progress.fail("Pull failed.");
|
|
88195
|
+
throw error;
|
|
88196
|
+
}
|
|
88197
|
+
}
|
|
88198
|
+
async function runNormalPull(workspace, options, progress) {
|
|
87918
88199
|
const destructive = options.force;
|
|
87919
88200
|
const hasBaseline = Object.keys(workspace.state.records).length > 0;
|
|
87920
88201
|
let localByKey = /* @__PURE__ */ new Map();
|
|
@@ -87943,25 +88224,54 @@ ${blockingErrors.map((error) => ` ${error.message}`).join("\n")}`
|
|
|
87943
88224
|
])
|
|
87944
88225
|
);
|
|
87945
88226
|
}
|
|
87946
|
-
|
|
87947
|
-
|
|
87948
|
-
|
|
87949
|
-
|
|
87950
|
-
|
|
87951
|
-
|
|
87952
|
-
|
|
87953
|
-
|
|
87954
|
-
|
|
87955
|
-
|
|
87956
|
-
|
|
87957
|
-
|
|
87958
|
-
|
|
87959
|
-
|
|
88227
|
+
let changedRecordKeys = null;
|
|
88228
|
+
let nextCursor = null;
|
|
88229
|
+
let observedHeadTransactionHash;
|
|
88230
|
+
let document = null;
|
|
88231
|
+
if (!destructive && hasBaseline) {
|
|
88232
|
+
progress.update("Checking remote changes\u2026");
|
|
88233
|
+
const cursor = workspace.state.documentRevisionCursor;
|
|
88234
|
+
if (cursor !== void 0) {
|
|
88235
|
+
const delta = await fetchProjectDocumentDelta(workspace, cursor);
|
|
88236
|
+
observedHeadTransactionHash = delta.headTransactionHash;
|
|
88237
|
+
if (!delta.fullResync) {
|
|
88238
|
+
document = delta.document;
|
|
88239
|
+
changedRecordKeys = delta.changedKeys;
|
|
88240
|
+
nextCursor = delta.cursor;
|
|
88241
|
+
if (delta.changedKeys.size === 0 && !options.regenerateSourceNames) {
|
|
88242
|
+
const cursorChanged = !cursorsEqual(
|
|
88243
|
+
workspace.state.documentRevisionCursor,
|
|
88244
|
+
delta.cursor
|
|
88245
|
+
);
|
|
88246
|
+
const headChanged = workspace.state.headTransactionHash !== delta.headTransactionHash;
|
|
88247
|
+
if (cursorChanged || headChanged) {
|
|
88248
|
+
workspace.state.documentRevisionCursor = mutableCursor(
|
|
88249
|
+
delta.cursor
|
|
88250
|
+
);
|
|
88251
|
+
workspace.state.headTransactionHash = delta.headTransactionHash;
|
|
88252
|
+
writeWorkspaceState(workspace.root, workspace.state);
|
|
88253
|
+
}
|
|
88254
|
+
progress.succeed("Already up to date.");
|
|
88255
|
+
return;
|
|
88256
|
+
}
|
|
88257
|
+
}
|
|
88258
|
+
} else if (!options.regenerateSourceNames && workspace.state.headTransactionHash !== void 0) {
|
|
88259
|
+
const marker = await fetchProjectDocumentSyncMarker(workspace);
|
|
88260
|
+
observedHeadTransactionHash = marker.headTransactionHash;
|
|
88261
|
+
if (marker.headTransactionId === marker.revision.latestTransactionId && marker.headTransactionHash === workspace.state.headTransactionHash) {
|
|
88262
|
+
const seededCursor = cursorFromRevision(marker.revision);
|
|
88263
|
+
workspace.state.documentRevisionCursor = mutableCursor(seededCursor);
|
|
88264
|
+
writeWorkspaceState(workspace.root, workspace.state);
|
|
88265
|
+
progress.succeed("Already up to date.");
|
|
87960
88266
|
return;
|
|
87961
88267
|
}
|
|
87962
88268
|
}
|
|
87963
88269
|
}
|
|
87964
|
-
|
|
88270
|
+
if (document === null) {
|
|
88271
|
+
progress.update("Downloading full project snapshot\u2026");
|
|
88272
|
+
document = await fetchProjectDocument(workspace);
|
|
88273
|
+
nextCursor = document.revision === void 0 ? null : cursorFromRevision(document.revision);
|
|
88274
|
+
}
|
|
87965
88275
|
const plans = /* @__PURE__ */ new Map();
|
|
87966
88276
|
let mergedCount = 0;
|
|
87967
88277
|
let conflictCount = 0;
|
|
@@ -88081,7 +88391,11 @@ ${blockingErrors.map((error) => ` ${error.message}`).join("\n")}`
|
|
|
88081
88391
|
conflictKeys,
|
|
88082
88392
|
localStatus,
|
|
88083
88393
|
destructive,
|
|
88084
|
-
regenerateSourceNames: destructive || options.regenerateSourceNames
|
|
88394
|
+
regenerateSourceNames: destructive || options.regenerateSourceNames,
|
|
88395
|
+
changedRecordKeys,
|
|
88396
|
+
nextCursor,
|
|
88397
|
+
observedHeadTransactionHash,
|
|
88398
|
+
progress
|
|
88085
88399
|
});
|
|
88086
88400
|
}
|
|
88087
88401
|
async function runResetPull(workspace) {
|
|
@@ -88111,10 +88425,17 @@ async function runResetPull(workspace) {
|
|
|
88111
88425
|
projectId: workspace.config.projectId,
|
|
88112
88426
|
versionId: workspace.config.versionId
|
|
88113
88427
|
});
|
|
88114
|
-
workspace.state.headTransactionHash = signal?.transactionHash
|
|
88428
|
+
workspace.state.headTransactionHash = document.revision !== void 0 && signal?.transactionId === document.revision.latestTransactionId ? signal.transactionHash : null;
|
|
88115
88429
|
} catch {
|
|
88116
88430
|
workspace.state.headTransactionHash = null;
|
|
88117
88431
|
}
|
|
88432
|
+
if (document.revision !== void 0) {
|
|
88433
|
+
workspace.state.documentRevisionCursor = mutableCursor(
|
|
88434
|
+
cursorFromRevision(document.revision)
|
|
88435
|
+
);
|
|
88436
|
+
} else {
|
|
88437
|
+
delete workspace.state.documentRevisionCursor;
|
|
88438
|
+
}
|
|
88118
88439
|
writeWorkspaceState(workspace.root, workspace.state);
|
|
88119
88440
|
progress.succeed(
|
|
88120
88441
|
`Pulled ${document.records.size} records \u2014 ${reset.written} file(s) updated \u2014 ${reset.removed} removed.`
|
|
@@ -88134,8 +88455,30 @@ async function finishFormat4Pull(args) {
|
|
|
88134
88455
|
conflictKeys,
|
|
88135
88456
|
localStatus,
|
|
88136
88457
|
destructive,
|
|
88137
|
-
regenerateSourceNames
|
|
88458
|
+
regenerateSourceNames,
|
|
88459
|
+
changedRecordKeys,
|
|
88460
|
+
nextCursor,
|
|
88461
|
+
observedHeadTransactionHash,
|
|
88462
|
+
progress
|
|
88138
88463
|
} = args;
|
|
88464
|
+
if (changedRecordKeys !== null && !regenerateSourceNames && conflictCount === 0 && localStatus !== null && !deltaRequiresSourceProjectionV4({
|
|
88465
|
+
workspace,
|
|
88466
|
+
document,
|
|
88467
|
+
plans,
|
|
88468
|
+
localStatus,
|
|
88469
|
+
changedRecordKeys
|
|
88470
|
+
})) {
|
|
88471
|
+
finishRecordOnlyDeltaPull({
|
|
88472
|
+
workspace,
|
|
88473
|
+
document,
|
|
88474
|
+
changedRecordKeys,
|
|
88475
|
+
nextCursor,
|
|
88476
|
+
observedHeadTransactionHash,
|
|
88477
|
+
progress
|
|
88478
|
+
});
|
|
88479
|
+
return;
|
|
88480
|
+
}
|
|
88481
|
+
progress.update("Regenerating affected Neo sources\u2026");
|
|
88139
88482
|
const plannedLocalRecords = buildEmitRecordSet(document, plans, "emit");
|
|
88140
88483
|
for (const [key, record3] of staticValueSeedEmitRecords(
|
|
88141
88484
|
localStatus,
|
|
@@ -88150,7 +88493,7 @@ async function finishFormat4Pull(args) {
|
|
|
88150
88493
|
)
|
|
88151
88494
|
);
|
|
88152
88495
|
const localResult = emitProjectDocumentFilesV4(localRecords);
|
|
88153
|
-
const serverResult = emitProjectDocumentFilesV4(
|
|
88496
|
+
const serverResult = conflictCount === 0 ? null : emitProjectDocumentFilesV4(
|
|
88154
88497
|
buildEmitRecordSet(document, plans, "server")
|
|
88155
88498
|
);
|
|
88156
88499
|
const binaries = await pullProjectBinariesV4({
|
|
@@ -88164,11 +88507,11 @@ async function finishFormat4Pull(args) {
|
|
|
88164
88507
|
localResult.files.map((file) => [file.path, file])
|
|
88165
88508
|
);
|
|
88166
88509
|
const serverByPath = new Map(
|
|
88167
|
-
serverResult
|
|
88510
|
+
(serverResult?.files ?? []).map((file) => [file.path, file])
|
|
88168
88511
|
);
|
|
88169
88512
|
const conflictPaths = /* @__PURE__ */ new Set();
|
|
88170
88513
|
for (const key of conflictKeys) {
|
|
88171
|
-
const path = localResult.recordFiles.get(key) ?? serverResult
|
|
88514
|
+
const path = localResult.recordFiles.get(key) ?? serverResult?.recordFiles.get(key);
|
|
88172
88515
|
if (path) conflictPaths.add(path);
|
|
88173
88516
|
}
|
|
88174
88517
|
const emittedPaths = /* @__PURE__ */ new Set([
|
|
@@ -88180,7 +88523,7 @@ async function finishFormat4Pull(args) {
|
|
|
88180
88523
|
localStatus,
|
|
88181
88524
|
plans,
|
|
88182
88525
|
localRecordFiles: localResult.recordFiles,
|
|
88183
|
-
serverRecordFiles: serverResult
|
|
88526
|
+
serverRecordFiles: serverResult?.recordFiles ?? /* @__PURE__ */ new Map(),
|
|
88184
88527
|
previousRecords: workspace.state.records,
|
|
88185
88528
|
conflictPaths,
|
|
88186
88529
|
emittedPaths,
|
|
@@ -88230,7 +88573,7 @@ async function finishFormat4Pull(args) {
|
|
|
88230
88573
|
if (baseState) records2[key] = { ...baseState };
|
|
88231
88574
|
continue;
|
|
88232
88575
|
}
|
|
88233
|
-
const file = localResult.recordFiles.get(key) ?? serverResult
|
|
88576
|
+
const file = localResult.recordFiles.get(key) ?? serverResult?.recordFiles.get(key) ?? baseState?.file;
|
|
88234
88577
|
records2[key] = plan.conflicted ? {
|
|
88235
88578
|
recordKind,
|
|
88236
88579
|
recordId,
|
|
@@ -88249,7 +88592,7 @@ async function finishFormat4Pull(args) {
|
|
|
88249
88592
|
}
|
|
88250
88593
|
for (const [key, serverRecord] of document.records) {
|
|
88251
88594
|
if (serverRecord.deleted || records2[key]) continue;
|
|
88252
|
-
const file = localResult.recordFiles.get(key) ?? serverResult
|
|
88595
|
+
const file = localResult.recordFiles.get(key) ?? serverResult?.recordFiles.get(key);
|
|
88253
88596
|
records2[key] = {
|
|
88254
88597
|
recordKind: serverRecord.recordKind,
|
|
88255
88598
|
recordId: serverRecord.recordId,
|
|
@@ -88263,30 +88606,37 @@ async function finishFormat4Pull(args) {
|
|
|
88263
88606
|
if (record3) record3.projectBinary = state;
|
|
88264
88607
|
}
|
|
88265
88608
|
workspace.state.records = records2;
|
|
88266
|
-
|
|
88267
|
-
|
|
88268
|
-
|
|
88269
|
-
|
|
88270
|
-
|
|
88271
|
-
|
|
88272
|
-
|
|
88273
|
-
|
|
88274
|
-
|
|
88609
|
+
if (nextCursor !== null) {
|
|
88610
|
+
workspace.state.documentRevisionCursor = mutableCursor(nextCursor);
|
|
88611
|
+
}
|
|
88612
|
+
if (observedHeadTransactionHash !== void 0) {
|
|
88613
|
+
workspace.state.headTransactionHash = observedHeadTransactionHash;
|
|
88614
|
+
} else {
|
|
88615
|
+
try {
|
|
88616
|
+
const convex = await createConvexClient(workspace);
|
|
88617
|
+
const signal = await convex.query(api2.projectExportData.schemaSignal, {
|
|
88618
|
+
projectId: workspace.config.projectId,
|
|
88619
|
+
versionId: workspace.config.versionId
|
|
88620
|
+
});
|
|
88621
|
+
workspace.state.headTransactionHash = document.revision !== void 0 && signal?.transactionId === document.revision.latestTransactionId ? signal.transactionHash : null;
|
|
88622
|
+
} catch {
|
|
88623
|
+
workspace.state.headTransactionHash = null;
|
|
88624
|
+
}
|
|
88275
88625
|
}
|
|
88276
88626
|
writeWorkspaceState(workspace.root, workspace.state);
|
|
88277
88627
|
if (conflictCount === 0) {
|
|
88278
88628
|
writeProjectSourceAnalysisCacheV4(workspace.root, localResult.analysis);
|
|
88279
|
-
|
|
88280
|
-
|
|
88281
|
-
|
|
88282
|
-
|
|
88283
|
-
|
|
88284
|
-
|
|
88285
|
-
|
|
88286
|
-
);
|
|
88629
|
+
if (localStatus === null || localStatus.changes.length === 0) {
|
|
88630
|
+
writeMaterializedConstructionBuildCacheV1(
|
|
88631
|
+
workspace.root,
|
|
88632
|
+
workspace.state,
|
|
88633
|
+
localResult.materializedConstructors
|
|
88634
|
+
);
|
|
88635
|
+
}
|
|
88287
88636
|
}
|
|
88637
|
+
const pulledRecords = changedRecordKeys === null ? `Pulled ${document.records.size} records` : `Pulled ${changedRecordKeys.size} changed record(s)`;
|
|
88288
88638
|
const summary = [
|
|
88289
|
-
|
|
88639
|
+
pulledRecords,
|
|
88290
88640
|
`${written} file(s) updated`,
|
|
88291
88641
|
`${removed} removed`
|
|
88292
88642
|
];
|
|
@@ -88297,7 +88647,7 @@ async function finishFormat4Pull(args) {
|
|
|
88297
88647
|
if (mergedCount > 0)
|
|
88298
88648
|
summary.push(color.green(`${mergedCount} merged cleanly`));
|
|
88299
88649
|
if (conflictCount > 0) summary.push(color.red(`${conflictCount} CONFLICTED`));
|
|
88300
|
-
|
|
88650
|
+
progress.succeed(`${summary.join(" \u2014 ")}.`);
|
|
88301
88651
|
if (conflictCount > 0) {
|
|
88302
88652
|
warn(
|
|
88303
88653
|
'Conflict markers were written into the affected files. Edit them to the desired final state and push \u2014 the push is the resolution. To keep one side everywhere, use "neo resolve --mine" or "neo resolve --theirs".'
|
|
@@ -88311,6 +88661,98 @@ async function finishFormat4Pull(args) {
|
|
|
88311
88661
|
for (const path of binaries.conflicts) console.log(` ${sym.fail} ${path}`);
|
|
88312
88662
|
}
|
|
88313
88663
|
}
|
|
88664
|
+
function deltaRequiresSourceProjectionV4(args) {
|
|
88665
|
+
const mainLocale = workspaceMainLocale(args.workspace.state.records);
|
|
88666
|
+
for (const key of args.changedRecordKeys) {
|
|
88667
|
+
const previous = args.workspace.state.records[key];
|
|
88668
|
+
const local = args.localStatus.reconstructed.get(key)?.fullData;
|
|
88669
|
+
const plan = args.plans.get(key);
|
|
88670
|
+
const server = args.document.records.get(key);
|
|
88671
|
+
if (server === void 0) {
|
|
88672
|
+
if (previous?.file !== void 0 || local !== void 0) return true;
|
|
88673
|
+
continue;
|
|
88674
|
+
}
|
|
88675
|
+
if (local === void 0 || plan?.emitData === void 0) {
|
|
88676
|
+
if (previous?.file !== void 0 || previous === void 0) return true;
|
|
88677
|
+
continue;
|
|
88678
|
+
}
|
|
88679
|
+
if (!sourceAuthoredRecordsSemanticallyEqual(
|
|
88680
|
+
server.recordKind,
|
|
88681
|
+
plan.emitData,
|
|
88682
|
+
local,
|
|
88683
|
+
mainLocale
|
|
88684
|
+
)) {
|
|
88685
|
+
return true;
|
|
88686
|
+
}
|
|
88687
|
+
}
|
|
88688
|
+
return false;
|
|
88689
|
+
}
|
|
88690
|
+
function finishRecordOnlyDeltaPull(args) {
|
|
88691
|
+
const cachedExpressions = readMaterializedConstructionBuildCacheV1(
|
|
88692
|
+
args.workspace.root,
|
|
88693
|
+
args.workspace.state
|
|
88694
|
+
);
|
|
88695
|
+
const records2 = { ...args.workspace.state.records };
|
|
88696
|
+
for (const key of args.changedRecordKeys) {
|
|
88697
|
+
const server = args.document.records.get(key);
|
|
88698
|
+
if (server === void 0) {
|
|
88699
|
+
delete records2[key];
|
|
88700
|
+
continue;
|
|
88701
|
+
}
|
|
88702
|
+
const previous = records2[key];
|
|
88703
|
+
records2[key] = {
|
|
88704
|
+
recordKind: server.recordKind,
|
|
88705
|
+
recordId: server.recordId,
|
|
88706
|
+
contentHash: server.contentHash,
|
|
88707
|
+
data: server.data,
|
|
88708
|
+
...previous?.file === void 0 ? {} : { file: previous.file },
|
|
88709
|
+
...previous?.projectBinary === void 0 ? {} : { projectBinary: previous.projectBinary }
|
|
88710
|
+
};
|
|
88711
|
+
}
|
|
88712
|
+
args.workspace.state.records = records2;
|
|
88713
|
+
if (args.nextCursor !== null) {
|
|
88714
|
+
args.workspace.state.documentRevisionCursor = mutableCursor(
|
|
88715
|
+
args.nextCursor
|
|
88716
|
+
);
|
|
88717
|
+
}
|
|
88718
|
+
if (args.observedHeadTransactionHash !== void 0) {
|
|
88719
|
+
args.workspace.state.headTransactionHash = args.observedHeadTransactionHash;
|
|
88720
|
+
}
|
|
88721
|
+
writeWorkspaceState(args.workspace.root, args.workspace.state);
|
|
88722
|
+
if (cachedExpressions !== null) {
|
|
88723
|
+
writeMaterializedConstructionBuildCacheV1(
|
|
88724
|
+
args.workspace.root,
|
|
88725
|
+
args.workspace.state,
|
|
88726
|
+
cachedExpressions
|
|
88727
|
+
);
|
|
88728
|
+
}
|
|
88729
|
+
args.progress.succeed(
|
|
88730
|
+
`Pulled ${args.changedRecordKeys.size} changed record(s) \u2014 0 file(s) updated \u2014 0 removed.`
|
|
88731
|
+
);
|
|
88732
|
+
}
|
|
88733
|
+
function cursorFromRevision(revision) {
|
|
88734
|
+
return {
|
|
88735
|
+
createdAt: revision.latestTransactionCreatedAt,
|
|
88736
|
+
transactionIds: revision.latestTransactionId === null ? [] : [revision.latestTransactionId],
|
|
88737
|
+
versionsStamp: revision.versionsStamp
|
|
88738
|
+
};
|
|
88739
|
+
}
|
|
88740
|
+
function mutableCursor(cursor) {
|
|
88741
|
+
return {
|
|
88742
|
+
createdAt: cursor.createdAt,
|
|
88743
|
+
transactionIds: [...cursor.transactionIds],
|
|
88744
|
+
versionsStamp: cursor.versionsStamp
|
|
88745
|
+
};
|
|
88746
|
+
}
|
|
88747
|
+
function cursorsEqual(left, right) {
|
|
88748
|
+
if (left === void 0) return false;
|
|
88749
|
+
if (left.createdAt !== right.createdAt) return false;
|
|
88750
|
+
if (left.versionsStamp !== right.versionsStamp) return false;
|
|
88751
|
+
if (left.transactionIds.length !== right.transactionIds.length) return false;
|
|
88752
|
+
return left.transactionIds.every(
|
|
88753
|
+
(transactionId, index) => transactionId === right.transactionIds[index]
|
|
88754
|
+
);
|
|
88755
|
+
}
|
|
88314
88756
|
function projectSourcePathsRequiringRewriteV4(args) {
|
|
88315
88757
|
if (args.destructive || args.localStatus === null) {
|
|
88316
88758
|
return new Set(args.emittedPaths);
|
package/package.json
CHANGED
|
@@ -78,7 +78,7 @@ wrappers.
|
|
|
78
78
|
The marker near the top of `SKILL.md` must exactly match the package version:
|
|
79
79
|
|
|
80
80
|
```html
|
|
81
|
-
<!-- reviewed-through-cli: 0.22.
|
|
81
|
+
<!-- reviewed-through-cli: 0.22.2 -->
|
|
82
82
|
```
|
|
83
83
|
|
|
84
84
|
The quoted version above is checked too, so this instruction cannot go stale
|
|
@@ -28,7 +28,9 @@ neo push --dry-run --force-recompile
|
|
|
28
28
|
Use `neo pull --regenerate-source-names` to refresh readable naming while
|
|
29
29
|
retaining normal merge behavior. Use `--reset` to regenerate canonical source
|
|
30
30
|
and managed binaries. Use `--force` only to discard local edits for the server
|
|
31
|
-
version.
|
|
31
|
+
version. Normal pulls persist a transaction cursor and fetch only changed
|
|
32
|
+
records; an undo/reset metadata change invalidates the cursor and causes a safe
|
|
33
|
+
full-snapshot fallback.
|
|
32
34
|
|
|
33
35
|
Treat `neo push --dry-run` as a full local commit rehearsal: source emission,
|
|
34
36
|
in-memory pending-ID assignment, transport shapes, hashes, and repeat
|