deepline 0.1.110 → 0.1.111
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/dist/cli/index.js +460 -313
- package/dist/cli/index.mjs +367 -219
- package/dist/index.js +2 -2
- package/dist/index.mjs +2 -2
- package/dist/repo/apps/play-runner-workers/src/coordinator-entry.ts +179 -130
- package/dist/repo/apps/play-runner-workers/src/entry.ts +119 -20
- package/dist/repo/sdk/src/release.ts +2 -2
- package/dist/repo/shared_libs/play-runtime/run-ledger.ts +40 -14
- package/dist/repo/shared_libs/play-runtime/scheduler-backend.ts +2 -0
- package/dist/repo/shared_libs/plays/bundling/index.ts +124 -10
- package/package.json +1 -1
|
@@ -720,6 +720,11 @@ export function reducePlayRunLedgerEvent(
|
|
|
720
720
|
);
|
|
721
721
|
case 'step.started': {
|
|
722
722
|
const current = base.stepsById[event.stepId];
|
|
723
|
+
const shouldRefineSyntheticStart =
|
|
724
|
+
current?.startedAt != null &&
|
|
725
|
+
current.completedAt != null &&
|
|
726
|
+
current.startedAt === current.completedAt &&
|
|
727
|
+
occurredAt < current.startedAt;
|
|
723
728
|
const nextStep: PlayRunLedgerStepSnapshot = {
|
|
724
729
|
...(current ?? { stepId: event.stepId, status: 'running' as const }),
|
|
725
730
|
stepId: event.stepId,
|
|
@@ -733,8 +738,10 @@ export function reducePlayRunLedgerEvent(
|
|
|
733
738
|
event.artifactTableNamespace ??
|
|
734
739
|
current?.artifactTableNamespace ??
|
|
735
740
|
null,
|
|
736
|
-
startedAt:
|
|
737
|
-
|
|
741
|
+
startedAt: shouldRefineSyntheticStart
|
|
742
|
+
? occurredAt
|
|
743
|
+
: (current?.startedAt ?? occurredAt),
|
|
744
|
+
updatedAt: Math.max(current?.updatedAt ?? 0, occurredAt),
|
|
738
745
|
};
|
|
739
746
|
return withTiming({
|
|
740
747
|
...base,
|
|
@@ -775,6 +782,25 @@ export function reducePlayRunLedgerEvent(
|
|
|
775
782
|
: event.status === 'running' && inferredStatus === 'completed'
|
|
776
783
|
? 'completed'
|
|
777
784
|
: (event.status ?? current?.status ?? inferredStatus);
|
|
785
|
+
const completedAt =
|
|
786
|
+
current?.completedAt ??
|
|
787
|
+
event.progress.completedAt ??
|
|
788
|
+
(status === 'completed'
|
|
789
|
+
? (event.progress.updatedAt ?? occurredAt)
|
|
790
|
+
: null);
|
|
791
|
+
const shouldRefineSyntheticStart =
|
|
792
|
+
current?.startedAt != null &&
|
|
793
|
+
current.completedAt != null &&
|
|
794
|
+
current.startedAt === current.completedAt &&
|
|
795
|
+
event.progress.startedAt != null &&
|
|
796
|
+
event.progress.startedAt < current.startedAt;
|
|
797
|
+
const startedAt =
|
|
798
|
+
(shouldRefineSyntheticStart ? event.progress.startedAt : null) ??
|
|
799
|
+
current?.startedAt ??
|
|
800
|
+
event.progress.startedAt ??
|
|
801
|
+
(status === 'completed' || status === 'failed'
|
|
802
|
+
? (completedAt ?? event.progress.updatedAt ?? occurredAt)
|
|
803
|
+
: null);
|
|
778
804
|
const nextStep: PlayRunLedgerStepSnapshot = {
|
|
779
805
|
...(current ?? { stepId: event.stepId, status }),
|
|
780
806
|
stepId: event.stepId,
|
|
@@ -785,13 +811,8 @@ export function reducePlayRunLedgerEvent(
|
|
|
785
811
|
progress.artifactTableNamespace ??
|
|
786
812
|
current?.artifactTableNamespace ??
|
|
787
813
|
null,
|
|
788
|
-
startedAt
|
|
789
|
-
completedAt
|
|
790
|
-
current?.completedAt ??
|
|
791
|
-
event.progress.completedAt ??
|
|
792
|
-
(status === 'completed'
|
|
793
|
-
? (event.progress.updatedAt ?? occurredAt)
|
|
794
|
-
: null),
|
|
814
|
+
startedAt,
|
|
815
|
+
completedAt,
|
|
795
816
|
updatedAt: occurredAt,
|
|
796
817
|
progress,
|
|
797
818
|
};
|
|
@@ -826,6 +847,10 @@ export function reducePlayRunLedgerEvent(
|
|
|
826
847
|
: event.type === 'step.failed'
|
|
827
848
|
? 'failed'
|
|
828
849
|
: 'skipped';
|
|
850
|
+
const completedAt =
|
|
851
|
+
status === 'skipped' || preserveFailedStatus
|
|
852
|
+
? (current?.completedAt ?? null)
|
|
853
|
+
: occurredAt;
|
|
829
854
|
const nextStep: PlayRunLedgerStepSnapshot = {
|
|
830
855
|
...(current ?? { stepId: event.stepId, status }),
|
|
831
856
|
stepId: event.stepId,
|
|
@@ -836,11 +861,12 @@ export function reducePlayRunLedgerEvent(
|
|
|
836
861
|
event.artifactTableNamespace ??
|
|
837
862
|
current?.artifactTableNamespace ??
|
|
838
863
|
null,
|
|
839
|
-
startedAt:
|
|
840
|
-
|
|
841
|
-
status === '
|
|
842
|
-
? (
|
|
843
|
-
:
|
|
864
|
+
startedAt:
|
|
865
|
+
current?.startedAt ??
|
|
866
|
+
(status === 'completed' || status === 'failed'
|
|
867
|
+
? (completedAt ?? occurredAt)
|
|
868
|
+
: null),
|
|
869
|
+
completedAt,
|
|
844
870
|
updatedAt: occurredAt,
|
|
845
871
|
progress: current?.progress ?? null,
|
|
846
872
|
};
|
|
@@ -129,6 +129,8 @@ export type PlaySchedulerSubmitInput = {
|
|
|
129
129
|
userId?: string | null;
|
|
130
130
|
source?: 'published' | 'ad_hoc' | 'draft';
|
|
131
131
|
executionProfile?: string | null;
|
|
132
|
+
/** Durable per-workspace active run cap enforced when the run row is projected. */
|
|
133
|
+
activeRunLimit?: number | null;
|
|
132
134
|
/** runner backend to use for executing attempts */
|
|
133
135
|
runtimeBackend: string;
|
|
134
136
|
/** dedup backend for cross-attempt cross-process idempotency */
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
extname,
|
|
9
9
|
isAbsolute,
|
|
10
10
|
join,
|
|
11
|
+
relative,
|
|
11
12
|
resolve,
|
|
12
13
|
} from 'node:path';
|
|
13
14
|
import { builtinModules } from 'node:module';
|
|
@@ -416,6 +417,106 @@ export function extractDefinedPlayName(sourceCode: string): string | null {
|
|
|
416
417
|
return null;
|
|
417
418
|
}
|
|
418
419
|
|
|
420
|
+
function canonicalizeRootPlayNameForWorkersRuntimeHash(
|
|
421
|
+
sourceCode: string,
|
|
422
|
+
): string {
|
|
423
|
+
const source = stripCommentsToSpaces(sourceCode);
|
|
424
|
+
const callPattern =
|
|
425
|
+
/(?:\b[A-Za-z_$][\w$]*\s*\.\s*)?\b(?:definePlay|defineWorkflow)\s*\(/g;
|
|
426
|
+
const match = callPattern.exec(source);
|
|
427
|
+
if (!match) return sourceCode;
|
|
428
|
+
|
|
429
|
+
const openParen = match.index + match[0].length - 1;
|
|
430
|
+
const firstArgStart = openParen + 1;
|
|
431
|
+
const firstNonSpace = source.slice(firstArgStart).search(/\S/);
|
|
432
|
+
if (firstNonSpace < 0) return sourceCode;
|
|
433
|
+
|
|
434
|
+
const argIndex = firstArgStart + firstNonSpace;
|
|
435
|
+
const quote = source[argIndex];
|
|
436
|
+
if (quote === '"' || quote === "'") {
|
|
437
|
+
const literalMatch = source
|
|
438
|
+
.slice(argIndex)
|
|
439
|
+
.match(/^(['"])(?:\\.|(?!\1)[\s\S])*\1/);
|
|
440
|
+
if (!literalMatch) return sourceCode;
|
|
441
|
+
const replacement = `${quote}__deepline_runtime_play_name__${quote}`;
|
|
442
|
+
return `${sourceCode.slice(0, argIndex)}${replacement}${sourceCode.slice(argIndex + literalMatch[0].length)}`;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
if (quote !== '{') return sourceCode;
|
|
446
|
+
const closeBrace = findMatchingBrace(source, argIndex);
|
|
447
|
+
if (closeBrace < 0) return sourceCode;
|
|
448
|
+
const objectSource = source.slice(argIndex + 1, closeBrace);
|
|
449
|
+
const idMatch = objectSource.match(
|
|
450
|
+
/(^|[,{\s])((?:id|['"]id['"])\s*:\s*)(['"])([\s\S]*?)\3/,
|
|
451
|
+
);
|
|
452
|
+
if (!idMatch || idMatch.index === undefined) return sourceCode;
|
|
453
|
+
const idValueStart =
|
|
454
|
+
argIndex +
|
|
455
|
+
1 +
|
|
456
|
+
idMatch.index +
|
|
457
|
+
idMatch[1]!.length +
|
|
458
|
+
idMatch[2]!.length +
|
|
459
|
+
idMatch[3]!.length;
|
|
460
|
+
return `${sourceCode.slice(0, idValueStart)}__deepline_runtime_play_name__${sourceCode.slice(idValueStart + idMatch[4]!.length)}`;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
function workersRuntimeGraphFilePath(input: {
|
|
464
|
+
entryFile: string;
|
|
465
|
+
filePath: string;
|
|
466
|
+
adapter: PlayBundlingAdapter;
|
|
467
|
+
}): string {
|
|
468
|
+
if (input.filePath === input.entryFile) return '<entry>';
|
|
469
|
+
const entryRelative = relative(dirname(input.entryFile), input.filePath);
|
|
470
|
+
if (entryRelative && !entryRelative.startsWith('..')) {
|
|
471
|
+
return entryRelative.replaceAll('\\', '/');
|
|
472
|
+
}
|
|
473
|
+
return `<project>/${relative(input.adapter.projectRoot, input.filePath).replaceAll('\\', '/')}`;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
function buildWorkersRuntimeGraphHash(input: {
|
|
477
|
+
analysis: SourceGraphAnalysis;
|
|
478
|
+
entryFile: string;
|
|
479
|
+
adapter: PlayBundlingAdapter;
|
|
480
|
+
exportName: string;
|
|
481
|
+
}): string {
|
|
482
|
+
const sourceFiles = Object.entries(input.analysis.sourceFiles)
|
|
483
|
+
.map(([filePath, contents]) => ({
|
|
484
|
+
filePath: workersRuntimeGraphFilePath({
|
|
485
|
+
entryFile: input.entryFile,
|
|
486
|
+
filePath,
|
|
487
|
+
adapter: input.adapter,
|
|
488
|
+
}),
|
|
489
|
+
hash: sha256(
|
|
490
|
+
filePath === input.entryFile
|
|
491
|
+
? canonicalizeRootPlayNameForWorkersRuntimeHash(contents)
|
|
492
|
+
: contents,
|
|
493
|
+
),
|
|
494
|
+
}))
|
|
495
|
+
.sort((left, right) => left.filePath.localeCompare(right.filePath));
|
|
496
|
+
|
|
497
|
+
return sha256(
|
|
498
|
+
JSON.stringify({
|
|
499
|
+
entryFile: '<entry>',
|
|
500
|
+
entryExport: input.exportName,
|
|
501
|
+
localFiles: sourceFiles,
|
|
502
|
+
nodeBuiltins: [...input.analysis.importPolicy.nodeBuiltins].sort(),
|
|
503
|
+
packages: input.analysis.importPolicy.packages
|
|
504
|
+
.map(({ name, version }) => ({ name, version }))
|
|
505
|
+
.sort((left, right) => left.name.localeCompare(right.name)),
|
|
506
|
+
importedPlayDependencies: input.analysis.importedPlayDependencies
|
|
507
|
+
.map((dependency) => ({
|
|
508
|
+
filePath: workersRuntimeGraphFilePath({
|
|
509
|
+
entryFile: input.entryFile,
|
|
510
|
+
filePath: dependency.filePath,
|
|
511
|
+
adapter: input.adapter,
|
|
512
|
+
}),
|
|
513
|
+
playName: dependency.playName,
|
|
514
|
+
}))
|
|
515
|
+
.sort((left, right) => left.filePath.localeCompare(right.filePath)),
|
|
516
|
+
}),
|
|
517
|
+
);
|
|
518
|
+
}
|
|
519
|
+
|
|
419
520
|
function readPackageVersionFromPackageJson(
|
|
420
521
|
packageJsonPath: string,
|
|
421
522
|
packageName: string,
|
|
@@ -1488,9 +1589,15 @@ export async function bundlePlayFile(
|
|
|
1488
1589
|
|
|
1489
1590
|
try {
|
|
1490
1591
|
const analysis = await analyzeSourceGraph(absolutePath, adapter);
|
|
1491
|
-
analysis.graphHash =
|
|
1492
|
-
|
|
1493
|
-
|
|
1592
|
+
analysis.graphHash =
|
|
1593
|
+
target === PLAY_ARTIFACT_KINDS.esmWorkers
|
|
1594
|
+
? buildWorkersRuntimeGraphHash({
|
|
1595
|
+
analysis,
|
|
1596
|
+
entryFile: absolutePath,
|
|
1597
|
+
adapter,
|
|
1598
|
+
exportName,
|
|
1599
|
+
})
|
|
1600
|
+
: sha256(`${analysis.graphHash}\nentry-export:${exportName}`);
|
|
1494
1601
|
// For esm_workers builds, the harness source files (entry.ts +
|
|
1495
1602
|
// peer DO/coordinator types it imports) are bundled INTO every play
|
|
1496
1603
|
// artifact. So any harness edit must produce a different graphHash so
|
|
@@ -1537,11 +1644,10 @@ export async function bundlePlayFile(
|
|
|
1537
1644
|
// Cache lookup happens after validation because a bundle cache hit is keyed
|
|
1538
1645
|
// by source and target, while cloud descriptor typecheck results also depend
|
|
1539
1646
|
// on generated tool metadata.
|
|
1540
|
-
const
|
|
1541
|
-
|
|
1542
|
-
target,
|
|
1543
|
-
|
|
1544
|
-
);
|
|
1647
|
+
const canUseArtifactCache = target !== PLAY_ARTIFACT_KINDS.esmWorkers;
|
|
1648
|
+
const cachedArtifact = canUseArtifactCache
|
|
1649
|
+
? await readArtifactCache(analysis.graphHash, target, adapter)
|
|
1650
|
+
: null;
|
|
1545
1651
|
const discoveredFiles =
|
|
1546
1652
|
await adapter.discoverPackagedLocalFiles(absolutePath);
|
|
1547
1653
|
if (cachedArtifact) {
|
|
@@ -1560,7 +1666,13 @@ export async function bundlePlayFile(
|
|
|
1560
1666
|
|
|
1561
1667
|
return {
|
|
1562
1668
|
success: true,
|
|
1563
|
-
artifact: {
|
|
1669
|
+
artifact: {
|
|
1670
|
+
...cachedArtifact,
|
|
1671
|
+
entryFile: absolutePath,
|
|
1672
|
+
sourceHash: analysis.sourceHash,
|
|
1673
|
+
importPolicy: analysis.importPolicy,
|
|
1674
|
+
cacheHit: true,
|
|
1675
|
+
},
|
|
1564
1676
|
sourceCode: analysis.sourceCode,
|
|
1565
1677
|
sourceFiles: analysis.sourceFiles,
|
|
1566
1678
|
filePath: absolutePath,
|
|
@@ -1626,7 +1738,9 @@ export async function bundlePlayFile(
|
|
|
1626
1738
|
cacheHit: false,
|
|
1627
1739
|
};
|
|
1628
1740
|
|
|
1629
|
-
|
|
1741
|
+
if (canUseArtifactCache) {
|
|
1742
|
+
await writeArtifactCache(artifact, adapter);
|
|
1743
|
+
}
|
|
1630
1744
|
|
|
1631
1745
|
return {
|
|
1632
1746
|
success: true,
|