@gitroll/tacitt-cli 0.6.8 → 0.6.10
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/README.md +1 -1
- package/dist/{agent-setup-YlFIJz-h.mjs → agent-setup-LPd8WEsN.mjs} +2 -2
- package/dist/agent-setup-worker.mjs +5 -5
- package/dist/cli.mjs +19 -10
- package/dist/codex-title-worker.mjs +1 -1
- package/dist/configured-preview-worker.mjs +5 -5
- package/dist/configured-session-worker.mjs +5 -5
- package/dist/{frame-Dj5Zs6UW.mjs → frame-ByT1xayJ.mjs} +1 -1
- package/dist/{heap-DsE74_-n.mjs → heap-CM298Yu0.mjs} +8 -6
- package/dist/inspection-worker.mjs +4 -4
- package/dist/{job-CeSf9UCC.mjs → job-BHIwElNF.mjs} +5 -5
- package/dist/{locate-BWkblijS.mjs → locate-Cwv6WH8n.mjs} +25 -2
- package/dist/{model-f_QnDyyb.mjs → model-zvn5GUJ9.mjs} +1 -1
- package/dist/operation-executor.mjs +3 -3
- package/dist/preview-worker.mjs +1 -1
- package/dist/privacy-validator.mjs +1 -1
- package/dist/{query-CaBXQlpF.mjs → query-By41gaKm.mjs} +585 -250
- package/dist/{run-RA_8zZsL.mjs → run-ZQx7p4Rw.mjs} +4 -4
- package/dist/{src-p_uJNjV3.mjs → src-3jvMvSQn.mjs} +3 -3
- package/dist/{src-d7n58sbH.mjs → src-BqtdFVq7.mjs} +683 -341
- package/dist/{src-BBjnljUs.mjs → src-D_DfY--2.mjs} +4 -4
- package/dist/store-database-worker.mjs +1 -1
- package/dist/web/assets/index-B14e6_-z.js +174 -0
- package/dist/web/index.html +1 -1
- package/package.json +1 -1
- package/skills/tacitt/INDEX.md +6 -6
- package/skills/tacitt/SKILL.md +4 -4
- package/skills/tacitt/references/INDEX.md +3 -3
- package/skills/tacitt/references/classification.md +12 -2
- package/skills/tacitt/references/commands.md +60 -13
- package/skills/tacitt/references/journey.md +10 -2
- package/skills/tacitt/references/parallel-review.md +21 -0
- package/skills/tacitt/references/send.md +29 -8
- package/skills/tacitt/scripts/INDEX.md +39 -36
- package/skills/tacitt/scripts/journey-classification-validation.d.mts +13 -0
- package/skills/tacitt/scripts/journey-classification-validation.mjs +38 -0
- package/skills/tacitt/scripts/journey-scan-timing.d.mts +15 -0
- package/skills/tacitt/scripts/journey-scan-timing.mjs +153 -1
- package/skills/tacitt/scripts/journey-state.d.mts +6 -0
- package/skills/tacitt/scripts/journey-state.mjs +24 -1
- package/skills/tacitt/scripts/journey.d.mts +5 -0
- package/skills/tacitt/scripts/journey.mjs +48 -3
- package/skills/tacitt/scripts/privacy-validator.mjs +11 -1
- package/skills/tacitt/scripts/review.mjs +294 -38
- package/LICENSE +0 -11
- package/dist/web/assets/index-B6kJ6XXF.js +0 -174
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { $ as createCleanup, B as parallelismLimits, C as readOriginalSearchFields, F as SessionWorkerError, G as processJourneyMetadataFields, H as privateJourneyDirectory, I as sessionWorkerFailure, K as staticMaskCategory, O as captureLogicalJourneySources, P as createSharedSessionPool, Q as removeNamedTemporarySpools, R as defaultParallelism, T as createCollectionArtifacts, U as readLogicalJourneyFinalMasks, W as readConfiguredOutputInfo, Z as createTemporary, _ as processJourneyMetadata, a as scanReviewFields, at as windowsOwnerOnly, c as readSessionScanRecords, g as readCapturedOriginalRows, i as buildWorkScanBatches, it as restrictToOwner, j as runConfiguredSessionJob, k as capturedJourneyScope, l as scanPreparedSession, m as openConfiguredUpload, n as verifyPreparedSessionSources, nt as makePrivateDirectory, o as createWorkPieces, ot as isWindowsAclFailure, p as configuredSessionUploads, q as readWorkspacePair, r as prepareSessionScans, rt as openPrivateFile, s as readSessionScanFields, st as windowsAclCodes, t as preparedScanConfiguration, v as readStaticSessionMasks, w as readConfiguredSearchFields, y as staticSessionJobs, z as gitSeedsProvider } from "./src-
|
|
2
|
-
import { A as createExecutionPort, C as saveRemoteState, D as createPackagingProgressPort, E as exportDelivery, F as loadDeliveryResults, L as inBackgroundStoreLane, M as withStateMutex, N as createDeliveryService, O as createStore, P as preflight, R as isBackgroundStatusPoll, S as readRemoteState, T as collectRemoteWorkers, _ as staticBaseProduction, a as writeJourneyOutput, b as workApproval, c as mergeHideIndexTokens, f as writeJourneyBase, g as staticBaseInputs, h as staticSessions, l as packRenderHideIndex, m as saveStaticSession, o as createHideIndexTokens, p as readStaticResult, s as hideIndexTexts, t as journeyOutputJob, u as journeyBaseJob, v as readSelectedCaptures, w as journeyDirectory, x as isRemoteImport, y as prepareSourcePlan, z as retrySharingViolation } from "./job-
|
|
3
|
-
import { $t as safeField, Bt as sessionPeriodSchema, Dn as createStaticProcessor, Fn as entityDictionaryVersion, Ft as termTypeInfo, Gt as ownerProfileSchema, Kt as passportAddressSchema, Ot as privacyTermKey, Qt as safeCode, Sn as currentDetectorVersion, T as bLiteralTerms, Un as frameRecords, Wt as mergeOwnerProfile, Xt as ApplicationError, Zt as UnfinishedJourneyError, an as observeSource, ar as admitCustomTerm, c as textDigest, ir as createEntityMatcher, nn as reviewFamilies, or as admitGitName, qt as profileHasChoices, tn as familySelected, ur as ProcessingError, zt as filterInventoryByPeriod } from "./locate-
|
|
4
|
-
import { a as mainTextChunks, c as previewInWorker, i as nearestSortingRepository, l as createNativeAdapters, n as createProjectEvidenceCollector, o as mainTextFields, r as sortingRepositoryId, s as textChunks, t as createHarnesses, u as createGitNameSeedProvider } from "./src-
|
|
5
|
-
import { $ as
|
|
6
|
-
import { _t as isCoordinationBusy } from "./heap-
|
|
7
|
-
import { t as createAgentSetupPort } from "./agent-setup-
|
|
1
|
+
import { $ as createCleanup, B as parallelismLimits, C as readOriginalSearchFields, F as SessionWorkerError, G as processJourneyMetadataFields, H as privateJourneyDirectory, I as sessionWorkerFailure, K as staticMaskCategory, O as captureLogicalJourneySources, P as createSharedSessionPool, Q as removeNamedTemporarySpools, R as defaultParallelism, T as createCollectionArtifacts, U as readLogicalJourneyFinalMasks, W as readConfiguredOutputInfo, Z as createTemporary, _ as processJourneyMetadata, a as scanReviewFields, at as windowsOwnerOnly, c as readSessionScanRecords, g as readCapturedOriginalRows, i as buildWorkScanBatches, it as restrictToOwner, j as runConfiguredSessionJob, k as capturedJourneyScope, l as scanPreparedSession, m as openConfiguredUpload, n as verifyPreparedSessionSources, nt as makePrivateDirectory, o as createWorkPieces, ot as isWindowsAclFailure, p as configuredSessionUploads, q as readWorkspacePair, r as prepareSessionScans, rt as openPrivateFile, s as readSessionScanFields, st as windowsAclCodes, t as preparedScanConfiguration, v as readStaticSessionMasks, w as readConfiguredSearchFields, y as staticSessionJobs, z as gitSeedsProvider } from "./src-3jvMvSQn.mjs";
|
|
2
|
+
import { A as createExecutionPort, C as saveRemoteState, D as createPackagingProgressPort, E as exportDelivery, F as loadDeliveryResults, L as inBackgroundStoreLane, M as withStateMutex, N as createDeliveryService, O as createStore, P as preflight, R as isBackgroundStatusPoll, S as readRemoteState, T as collectRemoteWorkers, _ as staticBaseProduction, a as writeJourneyOutput, b as workApproval, c as mergeHideIndexTokens, f as writeJourneyBase, g as staticBaseInputs, h as staticSessions, l as packRenderHideIndex, m as saveStaticSession, o as createHideIndexTokens, p as readStaticResult, s as hideIndexTexts, t as journeyOutputJob, u as journeyBaseJob, v as readSelectedCaptures, w as journeyDirectory, x as isRemoteImport, y as prepareSourcePlan, z as retrySharingViolation } from "./job-BHIwElNF.mjs";
|
|
3
|
+
import { $t as safeField, Bt as sessionPeriodSchema, Dn as createStaticProcessor, Fn as entityDictionaryVersion, Ft as termTypeInfo, Gt as ownerProfileSchema, Kt as passportAddressSchema, Ot as privacyTermKey, Qt as safeCode, Sn as currentDetectorVersion, T as bLiteralTerms, Un as frameRecords, Wt as mergeOwnerProfile, Xt as ApplicationError, Zt as UnfinishedJourneyError, an as observeSource, ar as admitCustomTerm, c as textDigest, ir as createEntityMatcher, nn as reviewFamilies, or as admitGitName, qt as profileHasChoices, tn as familySelected, ur as ProcessingError, zt as filterInventoryByPeriod } from "./locate-Cwv6WH8n.mjs";
|
|
4
|
+
import { a as mainTextChunks, c as previewInWorker, i as nearestSortingRepository, l as createNativeAdapters, n as createProjectEvidenceCollector, o as mainTextFields, r as sortingRepositoryId, s as textChunks, t as createHarnesses, u as createGitNameSeedProvider } from "./src-D_DfY--2.mjs";
|
|
5
|
+
import { $r as isClassifying, $t as searchScopeDigest, Ar as displayedScopeDigest, At as obsoleteJourney, B as createApplication, Br as staticReviewDigest, Bt as classificationPartition, Ct as sendActionSchema, Dt as sendStartSchema, Et as sendRequestSchema, F as readAccountAvatarUrl, Gr as agentSourcesSchema, H as inspectionStartSchema, Ht as applyClassification, I as storedCredentialSchema, Jn as workDecisionDigest, Jr as sendReceiptSchema, K as inspectionQuerySchema, Kr as journeySendSchema, Ln as bTermMatcher, M as deviceAuthorizationSchema, N as deviceProfileScopeSchema, Nr as assertJourneyPrivacyReady, O as createAccount, P as profileUrlMatchesIdentity, Pr as privacyDecisionDigest, Qr as hasCompleteWorkDescription, St as replaceSensitiveTermsSchema, Tt as sendPrepareSchema, U as validateInspectionBatch, Ut as retireScanGeneration, V as inspectionCancelSchema, Vn as confirmedHideKinds, Vt as classificationWorks, Wn as journeyConfirmedHides, Wr as agentSourceSchema, Wt as newJourneyWork, Xn as workCorrectionBinding, Xr as sendResolutionSchema, Yr as sendReplaceResultSchema, Zr as sendSettingsSchema, Zt as journeySearchResultSchema, _ as changeJourney, _t as manualUploadStartSchema, ai as withReadingProgress, at as appendSensitiveTerms, ci as selectionBatchSchema, cr as scanSessionResourceSchema, di as producerVersion, dr as verifiedScanGitSeeds, dt as validateFailureLocation, ei as isIncludedWork, fr as scanExclusionResourceSchema, ft as manualUploadActionSchema, gt as manualUploadSchema, h as hideScopeDigest, ht as manualUploadPrepareSchema, j as accountProfileSchema, jr as requestedScope, k as renew, kt as currentJourneyAdapters, li as selectionSchema, lr as scanGitSeedsId, lt as artifactFailureDetailSchema, m as activeJourneyTerms, mi as recommendParallelism, mt as manualUploadChoiceSchema, ni as isSelectedWork, nt as settingsQuerySchema, oi as commandSchema, qn as retireWorkDescription, qr as sendArtifactSchema, si as packageCommandSchema, sr as scanPreparationDigest, ti as isReadingComplete, tt as settingsBatchSchema, ur as scanGitSeedsResource, wt as sendChoiceSchema, xt as normalizeSensitiveTerms, yr as emptyPreparationFacts, yt as emptyTermsRevision, zr as hasCurrentStaticReview } from "./src-BqtdFVq7.mjs";
|
|
6
|
+
import { _t as isCoordinationBusy } from "./heap-CM298Yu0.mjs";
|
|
7
|
+
import { t as createAgentSetupPort } from "./agent-setup-LPd8WEsN.mjs";
|
|
8
8
|
import { t as workerMessageSchema } from "./messages-D3m3bhva.mjs";
|
|
9
9
|
import { constants, write } from "node:fs";
|
|
10
10
|
import { z } from "zod";
|
|
@@ -2603,18 +2603,24 @@ function createJourneyPreparation(options) {
|
|
|
2603
2603
|
const scanWorks = scanRequested && state.scope.status === "confirmed" ? state.works : [];
|
|
2604
2604
|
if (scanWorks.length) run = await runWorkers(options.workers);
|
|
2605
2605
|
const frozen = state;
|
|
2606
|
-
const
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2606
|
+
const blockedForRetry = new Set(state.works.filter((work) => work.status === "blocked").map((work) => `${work.id}:${work.inputRevision}`));
|
|
2607
|
+
const deferredForHide = /* @__PURE__ */ new Set();
|
|
2608
|
+
const blockWork = async (work, error) => {
|
|
2609
|
+
const blocked = await changeJourney(storage, journeyId, "snapshot", (before) => {
|
|
2610
|
+
if (before.phase === "paused") throw new ApplicationError("OPERATION_CANCELED");
|
|
2611
|
+
if (before.phase === "sending" || before.phase === "completed") return before;
|
|
2612
|
+
return withReadingProgress({
|
|
2613
|
+
...before,
|
|
2614
|
+
works: before.works.map((item) => item.id === work.id && item.inputRevision === work.inputRevision && !item.blockedCodes.includes("PRIVACY_CHANGE_PENDING") ? {
|
|
2615
|
+
...item,
|
|
2616
|
+
status: "blocked",
|
|
2617
|
+
blockedCodes: blockedCodes(error, safeCode(error))
|
|
2618
|
+
} : item)
|
|
2619
|
+
});
|
|
2620
|
+
}, 100);
|
|
2621
|
+
if (blocked.works.some((item) => item.id === work.id && item.inputRevision === work.inputRevision && item.status === "blocked")) blockedForRetry.add(`${work.id}:${work.inputRevision}`);
|
|
2622
|
+
return blocked;
|
|
2623
|
+
};
|
|
2618
2624
|
const retryLimit = options.retryLimit ?? workRetryDelaysMs.length;
|
|
2619
2625
|
const generation = (work) => `${work.id}:${work.inputRevision}`;
|
|
2620
2626
|
let serialAdmission = Promise.resolve();
|
|
@@ -2638,11 +2644,14 @@ function createJourneyPreparation(options) {
|
|
|
2638
2644
|
await (options.retryDelay ?? waitForWorkRetry)(delay, abort.signal);
|
|
2639
2645
|
abort.signal.throwIfAborted();
|
|
2640
2646
|
let resumed = false;
|
|
2641
|
-
|
|
2647
|
+
let deferred = false;
|
|
2648
|
+
const committed = await changeJourney(storage, journeyId, "snapshot", (before) => {
|
|
2642
2649
|
resumed = false;
|
|
2650
|
+
deferred = false;
|
|
2643
2651
|
const target = before.works.find((item) => item.id === work.id);
|
|
2644
2652
|
if (before.phase === "sending" || before.phase === "completed" || before.phase === "paused" || !target || !isSelectedWork(target) || target.inputRevision !== work.inputRevision || target.status !== "blocked" || target.blockedCodes.includes("PRIVACY_CHANGE_PENDING")) return before;
|
|
2645
2653
|
resumed = !before.pendingHideId;
|
|
2654
|
+
deferred = !resumed;
|
|
2646
2655
|
return withReadingProgress({
|
|
2647
2656
|
...before,
|
|
2648
2657
|
privacy: {
|
|
@@ -2656,6 +2665,7 @@ function createJourneyPreparation(options) {
|
|
|
2656
2665
|
} : item)
|
|
2657
2666
|
});
|
|
2658
2667
|
}, 100);
|
|
2668
|
+
if (deferred && committed.pendingHideId && committed.works.some((item) => generation(item) === generation(work) && item.status === "pending")) deferredForHide.add(generation(work));
|
|
2659
2669
|
return resumed;
|
|
2660
2670
|
};
|
|
2661
2671
|
const readRetries = /* @__PURE__ */ new Map();
|
|
@@ -2693,6 +2703,7 @@ function createJourneyPreparation(options) {
|
|
|
2693
2703
|
"reading",
|
|
2694
2704
|
"review"
|
|
2695
2705
|
].includes(work.status)) return false;
|
|
2706
|
+
blockedForRetry.delete(generation(work));
|
|
2696
2707
|
prepared.add(generation(work));
|
|
2697
2708
|
await prepareClassificationMetadata(storage, latest, work, options.processing, abort.signal, plan);
|
|
2698
2709
|
let failures = collectPreparationFailures(plan.approval.inventory, work.rootSessionIds, {
|
|
@@ -2802,7 +2813,15 @@ function createJourneyPreparation(options) {
|
|
|
2802
2813
|
abort.abort(error);
|
|
2803
2814
|
};
|
|
2804
2815
|
const statics = [];
|
|
2816
|
+
const priorStatics = /* @__PURE__ */ new Map();
|
|
2805
2817
|
const reads = [];
|
|
2818
|
+
const activeReads = /* @__PURE__ */ new Set();
|
|
2819
|
+
const activeStatics = /* @__PURE__ */ new Set();
|
|
2820
|
+
let workSettled = Promise.withResolvers();
|
|
2821
|
+
const notifySettled = () => {
|
|
2822
|
+
workSettled.resolve();
|
|
2823
|
+
workSettled = Promise.withResolvers();
|
|
2824
|
+
};
|
|
2806
2825
|
const pass = async (works) => {
|
|
2807
2826
|
let submittedWorks = 0;
|
|
2808
2827
|
const submitted = Promise.withResolvers();
|
|
@@ -2826,6 +2845,7 @@ function createJourneyPreparation(options) {
|
|
|
2826
2845
|
releaseAdmission.set(planned.id, () => released.resolve());
|
|
2827
2846
|
const onSubmitted = submission();
|
|
2828
2847
|
const read = async () => {
|
|
2848
|
+
await priorStatics.get(planned.id);
|
|
2829
2849
|
if (!run.pool) await previous;
|
|
2830
2850
|
if (fatal) {
|
|
2831
2851
|
onSubmitted();
|
|
@@ -2840,25 +2860,45 @@ function createJourneyPreparation(options) {
|
|
|
2840
2860
|
onSubmitted();
|
|
2841
2861
|
released.resolve();
|
|
2842
2862
|
}
|
|
2843
|
-
|
|
2863
|
+
activeStatics.add(planned.id);
|
|
2864
|
+
const staticResult = retryContention(() => staticWork(planned, passSubmitted), (error) => options.onFailure(error), abort.signal).catch(stop).finally(() => {
|
|
2865
|
+
activeStatics.delete(planned.id);
|
|
2866
|
+
notifySettled();
|
|
2867
|
+
});
|
|
2868
|
+
priorStatics.set(planned.id, staticResult);
|
|
2869
|
+
statics.push(staticResult);
|
|
2844
2870
|
};
|
|
2845
|
-
|
|
2871
|
+
activeReads.add(planned.id);
|
|
2872
|
+
reads.push(read().finally(() => {
|
|
2873
|
+
activeReads.delete(planned.id);
|
|
2874
|
+
notifySettled();
|
|
2875
|
+
}));
|
|
2846
2876
|
}
|
|
2847
2877
|
await Promise.all(admissions);
|
|
2848
2878
|
};
|
|
2849
|
-
/**
|
|
2879
|
+
/** Admit newly grouped and explicitly retried Works until both read and static work drain. */
|
|
2850
2880
|
const later = async () => {
|
|
2851
2881
|
for (;;) {
|
|
2852
2882
|
abort.signal.throwIfAborted();
|
|
2883
|
+
const settled = workSettled.promise;
|
|
2853
2884
|
const latest = await storage.current(journeyId);
|
|
2854
2885
|
if (!latest || latest.phase === "paused" || latest.scope.status !== "confirmed") return [];
|
|
2886
|
+
for (const work of latest.works) if (work.status === "blocked") blockedForRetry.add(generation(work));
|
|
2855
2887
|
const ready = latest.works.filter((work) => isSelectedWork(work) && [
|
|
2856
2888
|
"pending",
|
|
2857
2889
|
"reading",
|
|
2858
2890
|
"review"
|
|
2859
|
-
].includes(work.status) && !
|
|
2860
|
-
if (ready.length || !isClassifying(latest)) return ready;
|
|
2861
|
-
|
|
2891
|
+
].includes(work.status) && !activeReads.has(work.id) && !activeStatics.has(work.id) && !deferredForHide.has(generation(work)) && (!prepared.has(generation(work)) && !hasCurrentStaticReview(latest, work) || work.status === "pending" && blockedForRetry.has(generation(work))));
|
|
2892
|
+
if (ready.length || !isClassifying(latest) && !activeReads.size && !activeStatics.size) return ready;
|
|
2893
|
+
const polling = new AbortController();
|
|
2894
|
+
try {
|
|
2895
|
+
await Promise.race([settled, setTimeout$1(laterWorksPollMs, void 0, { signal: AbortSignal.any([abort.signal, polling.signal]) })]);
|
|
2896
|
+
} catch (error) {
|
|
2897
|
+
abort.signal.throwIfAborted();
|
|
2898
|
+
throw error;
|
|
2899
|
+
} finally {
|
|
2900
|
+
polling.abort();
|
|
2901
|
+
}
|
|
2862
2902
|
}
|
|
2863
2903
|
};
|
|
2864
2904
|
try {
|
|
@@ -2971,7 +3011,16 @@ async function packageBase(storage, state, work, processing, directory, signal,
|
|
|
2971
3011
|
if (after.phase === "paused") throw new ApplicationError("OPERATION_CANCELED");
|
|
2972
3012
|
assertJourneyPrivacyReady(after, true);
|
|
2973
3013
|
}
|
|
2974
|
-
|
|
3014
|
+
try {
|
|
3015
|
+
await assertCurrent();
|
|
3016
|
+
} catch (error) {
|
|
3017
|
+
await Promise.all([
|
|
3018
|
+
base.primary,
|
|
3019
|
+
base.companion,
|
|
3020
|
+
base.maskLedger
|
|
3021
|
+
].map((file) => rm(file.path, { force: true })));
|
|
3022
|
+
throw error;
|
|
3023
|
+
}
|
|
2975
3024
|
try {
|
|
2976
3025
|
await storage.saveResource(base);
|
|
2977
3026
|
return base;
|
|
@@ -3533,7 +3582,7 @@ function assertScope(journey, send) {
|
|
|
3533
3582
|
if (journey.pendingHideId) throw new ApplicationError("SCOPE_NOT_READY");
|
|
3534
3583
|
if (journey.phase === "paused") throw new ApplicationError("OPERATION_CANCELED");
|
|
3535
3584
|
if (scopeDigest(journey) !== send.scopeDigest) throw new ApplicationError("SEND_SCOPE_INVALIDATED");
|
|
3536
|
-
assertJourneyPrivacyReady(journey, true);
|
|
3585
|
+
assertJourneyPrivacyReady(journey, true, { publicChoices: send.status !== "completed" });
|
|
3537
3586
|
for (const item of send.items) {
|
|
3538
3587
|
const work = journey.works.find((value) => value.id === item.workId);
|
|
3539
3588
|
if (!work || work.status !== "ready" || !hasCompleteWorkDescription(work) || !work.accessConfirmed || work.access !== item.access || work.artifact?.revision !== work.revision || work.artifact.sha256 !== item.artifact.sha256 || work.artifact.archiveBytes !== item.artifact.byteLength || work.artifact.bundleId !== item.artifact.bundleId) throw new ApplicationError("SCOPE_NOT_READY");
|
|
@@ -3818,31 +3867,32 @@ function createJourneyRenderer(options) {
|
|
|
3818
3867
|
async function renderScope(journeyId, works, signal) {
|
|
3819
3868
|
const workers = options.workers;
|
|
3820
3869
|
const size = workers ? workers.parallelism ?? renderWorkerCount() : 0;
|
|
3821
|
-
if (!workers || works < 1 || size < 1) {
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
close: async () => void 0
|
|
3826
|
-
};
|
|
3827
|
-
}
|
|
3828
|
-
const retry = renderRetry(signal, Math.min(works, size + 1));
|
|
3829
|
-
const store = retry.store(storage);
|
|
3870
|
+
if (!workers || works < 1 || size < 1) return {
|
|
3871
|
+
render: (workId) => render(journeyId, workId, signal, { retry: renderRetry(signal, Math.max(1, Math.min(16, works))) }),
|
|
3872
|
+
close: async () => void 0
|
|
3873
|
+
};
|
|
3830
3874
|
const pool = createRenderWorkers(workers, size);
|
|
3831
|
-
const session = batchedRenderSession(
|
|
3875
|
+
const session = batchedRenderSession(storage, journeyId);
|
|
3832
3876
|
let plan;
|
|
3833
|
-
const readPlan = () => plan ??= readJourneyPlan(
|
|
3877
|
+
const readPlan = () => plan ??= readJourneyPlan(storage, journeyId).catch((error) => {
|
|
3834
3878
|
plan = void 0;
|
|
3835
3879
|
throw error;
|
|
3836
3880
|
});
|
|
3837
3881
|
return {
|
|
3838
3882
|
concurrency: size + 1,
|
|
3839
|
-
render: (workId) =>
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
|
|
3883
|
+
render: (workId) => {
|
|
3884
|
+
const retry = renderRetry(signal, Math.min(16, works, size + 1));
|
|
3885
|
+
return render(journeyId, workId, signal, {
|
|
3886
|
+
write: pool.write,
|
|
3887
|
+
session: {
|
|
3888
|
+
current: () => retry.run(() => session.current()),
|
|
3889
|
+
commit: (change) => retry.run(() => session.commit(change))
|
|
3890
|
+
},
|
|
3891
|
+
plan: () => retry.run(readPlan),
|
|
3892
|
+
writeBase: pool.writeBase,
|
|
3893
|
+
retry
|
|
3894
|
+
});
|
|
3895
|
+
},
|
|
3846
3896
|
close: pool.close
|
|
3847
3897
|
};
|
|
3848
3898
|
}
|
|
@@ -4642,7 +4692,7 @@ async function resolveChunkSessions(storage, state, works, signal) {
|
|
|
4642
4692
|
* read and applied by the store against the current state, so scan writes in between do not
|
|
4643
4693
|
* refuse it (BL-216).
|
|
4644
4694
|
*/
|
|
4645
|
-
function createClassificationProposal(storage) {
|
|
4695
|
+
function createClassificationProposal(storage, accountAccess) {
|
|
4646
4696
|
return async (input, signal) => {
|
|
4647
4697
|
signal.throwIfAborted();
|
|
4648
4698
|
const state = await storage.current(input.journeyId);
|
|
@@ -4736,9 +4786,14 @@ function createClassificationProposal(storage) {
|
|
|
4736
4786
|
};
|
|
4737
4787
|
const { works } = classificationWorks(state, prepared);
|
|
4738
4788
|
const chunkSessions = await resolveChunkSessions(storage, state, works, signal);
|
|
4789
|
+
const access = late ? await accountAccess?.({
|
|
4790
|
+
...state,
|
|
4791
|
+
works
|
|
4792
|
+
}, signal) : void 0;
|
|
4739
4793
|
return storage.commitClassification({
|
|
4740
4794
|
...prepared,
|
|
4741
|
-
chunkSessions
|
|
4795
|
+
chunkSessions,
|
|
4796
|
+
...access ? { accountAccess: Object.fromEntries(access) } : {}
|
|
4742
4797
|
});
|
|
4743
4798
|
};
|
|
4744
4799
|
}
|
|
@@ -5084,11 +5139,11 @@ function createJourneyClassification(storage, _processing) {
|
|
|
5084
5139
|
//#endregion
|
|
5085
5140
|
//#region apps/cli/src/journey/works/index.ts
|
|
5086
5141
|
/** The journey local port's project catalog and project-type suggestions. */
|
|
5087
|
-
function createJourneyWorks(storage, processing, stateDir) {
|
|
5142
|
+
function createJourneyWorks(storage, processing, stateDir, accountAccess) {
|
|
5088
5143
|
return {
|
|
5089
5144
|
classificationSessions: createClassificationSessions(storage, processing, stateDir),
|
|
5090
5145
|
classificationRead: createClassificationReader(storage, stateDir),
|
|
5091
|
-
classificationSubmit: createClassificationProposal(storage),
|
|
5146
|
+
classificationSubmit: createClassificationProposal(storage, accountAccess),
|
|
5092
5147
|
catalog: createJourneyCatalog(storage, processing, stateDir),
|
|
5093
5148
|
classify: createJourneyClassification(storage, processing)
|
|
5094
5149
|
};
|
|
@@ -5182,6 +5237,46 @@ function protectedSourceText(field, hidden) {
|
|
|
5182
5237
|
}
|
|
5183
5238
|
//#endregion
|
|
5184
5239
|
//#region apps/cli/src/journey/send-package.ts
|
|
5240
|
+
/** Explicit admission refusals must never become automatic packaging retries. */
|
|
5241
|
+
const packagingRefusalCodes = [
|
|
5242
|
+
"ARTIFACT_INVALID_APPROVAL",
|
|
5243
|
+
"ARTIFACT_IDENTITY_MISMATCH",
|
|
5244
|
+
"CONFIRMATION_REQUIRED",
|
|
5245
|
+
"INCOMPLETE_REVIEW",
|
|
5246
|
+
"PRIVACY_CHANGE_PENDING",
|
|
5247
|
+
"PRIVACY_UNCERTAIN",
|
|
5248
|
+
"REVISION_CONFLICT",
|
|
5249
|
+
"SCOPE_NOT_READY",
|
|
5250
|
+
"JOURNEY_OBSOLETE",
|
|
5251
|
+
"UNKNOWN_ITEM",
|
|
5252
|
+
"UNKNOWN_WORKSPACE",
|
|
5253
|
+
"OPERATION_CANCELED"
|
|
5254
|
+
];
|
|
5255
|
+
/**
|
|
5256
|
+
* Deterministic failures a later attempt cannot clear: the refusals above, the source refusals
|
|
5257
|
+
* preparation isolates per root, size limits, a missing source and a full disk. Every other code,
|
|
5258
|
+
* including Windows sharing or antivirus locks, retries until the saved request expires.
|
|
5259
|
+
*/
|
|
5260
|
+
const finalPackagingCodes = [
|
|
5261
|
+
...packagingRefusalCodes,
|
|
5262
|
+
...rootScanRefusals,
|
|
5263
|
+
"ARTIFACT_ARCHIVE_LIMIT",
|
|
5264
|
+
"ARTIFACT_ENTRY_LIMIT",
|
|
5265
|
+
"ARTIFACT_FILESYSTEM_LIMIT",
|
|
5266
|
+
"ARTIFACT_INDEX_LIMIT",
|
|
5267
|
+
"ARTIFACT_METADATA_LIMIT",
|
|
5268
|
+
"ARTIFACT_PART_LIMIT",
|
|
5269
|
+
"ARTIFACT_SOURCE_MISSING",
|
|
5270
|
+
"ARTIFACT_DISK_FULL",
|
|
5271
|
+
"ARTIFACT_INVALID_APPROVAL",
|
|
5272
|
+
"ARTIFACT_INVALID_ARCHIVE",
|
|
5273
|
+
"ARTIFACT_INVALID_MANIFEST",
|
|
5274
|
+
"ARTIFACT_OUTPUT_UNSAFE",
|
|
5275
|
+
"ARTIFACT_PROCESSING_MISMATCH",
|
|
5276
|
+
"ARTIFACT_QUOTA_EXCEEDED",
|
|
5277
|
+
"ARTIFACT_SOURCE_UNSAFE",
|
|
5278
|
+
"ARTIFACT_UNSAFE_REMOTE"
|
|
5279
|
+
];
|
|
5185
5280
|
const packaged = (work) => work.status === "ready" && work.artifact?.revision === work.revision;
|
|
5186
5281
|
/** One host-lifetime packaging batch per advance; persisted artifacts are its progress. */
|
|
5187
5282
|
function createSendPackager(ports) {
|
|
@@ -5200,13 +5295,16 @@ function createSendPackager(ports) {
|
|
|
5200
5295
|
if (!current) throw new ApplicationError("UNKNOWN_ITEM");
|
|
5201
5296
|
}
|
|
5202
5297
|
const ready = (works, id) => works.some((work) => work.id === id && packaged(work));
|
|
5203
|
-
const batch = workIds.filter((id) => !ready(current.works, id))
|
|
5298
|
+
const batch = workIds.filter((id) => !ready(current.works, id));
|
|
5204
5299
|
if (!batch.length) return true;
|
|
5205
5300
|
signal.throwIfAborted();
|
|
5206
5301
|
const result = await ports.render({
|
|
5207
5302
|
journeyId,
|
|
5208
5303
|
workIds: batch
|
|
5209
5304
|
}, signal);
|
|
5305
|
+
const failures = result.renders?.filter((item) => item.status === "failed") ?? [];
|
|
5306
|
+
const failure = failures.find((item) => packagingRefusalCodes.includes(item.code)) ?? failures.find((item) => finalPackagingCodes.includes(item.code)) ?? failures[0];
|
|
5307
|
+
if (failure) throw new ApplicationError(failure.code);
|
|
5210
5308
|
if (batch.some((id) => !ready(result.works, id))) throw new Error("PACKAGING_FAILED");
|
|
5211
5309
|
return false;
|
|
5212
5310
|
};
|
|
@@ -5579,6 +5677,19 @@ async function classifyExit(child, startup, exited, busy) {
|
|
|
5579
5677
|
}
|
|
5580
5678
|
//#endregion
|
|
5581
5679
|
//#region apps/cli/src/send-host.ts
|
|
5680
|
+
/**
|
|
5681
|
+
* The detached focused host (ADR 0227) drives a Send only for the store's current journey, the
|
|
5682
|
+
* check its timer makes, and only while `liveHost` verifies its process identity and URL.
|
|
5683
|
+
* Anything the CLI cannot confirm returns false, so the CLI keeps stepping as before.
|
|
5684
|
+
*/
|
|
5685
|
+
async function focusedHostAlive(stateDir, journeyId, currentJourneyId) {
|
|
5686
|
+
try {
|
|
5687
|
+
if (await currentJourneyId() !== journeyId) return false;
|
|
5688
|
+
return (await liveHost(join(stateDir, "serve"), journeyId)).status === "alive";
|
|
5689
|
+
} catch {
|
|
5690
|
+
return false;
|
|
5691
|
+
}
|
|
5692
|
+
}
|
|
5582
5693
|
const recordSchema = z.object({
|
|
5583
5694
|
hostId: z.uuid(),
|
|
5584
5695
|
pid: z.number().int().positive()
|
|
@@ -6042,49 +6153,72 @@ var SessionContentConflict = class extends ApplicationError {
|
|
|
6042
6153
|
this.contentConflict = contentConflict;
|
|
6043
6154
|
}
|
|
6044
6155
|
};
|
|
6045
|
-
/**
|
|
6156
|
+
/** Collect safe conflicts across the entire pending Send before any session mutation. */
|
|
6046
6157
|
async function sessionAccessBlocked(dependencies, journeyId, items, inventory, signal) {
|
|
6047
6158
|
const sessions = dependencies.artifacts.sessionFacts ?? dependencies.artifacts.sessions;
|
|
6048
|
-
if (!sessions) return
|
|
6159
|
+
if (!sessions) return [];
|
|
6160
|
+
const conflicts = /* @__PURE__ */ new Map();
|
|
6161
|
+
const accountAccesses = /* @__PURE__ */ new Map();
|
|
6162
|
+
function observe(item, access) {
|
|
6163
|
+
const values = accountAccesses.get(item.workId) ?? /* @__PURE__ */ new Set();
|
|
6164
|
+
values.add(access);
|
|
6165
|
+
accountAccesses.set(item.workId, values);
|
|
6166
|
+
}
|
|
6167
|
+
function record(item, sessionKey, rule, account) {
|
|
6168
|
+
if (account) observe(item, account.access);
|
|
6169
|
+
const conflict = {
|
|
6170
|
+
workId: item.workId,
|
|
6171
|
+
sessionKey,
|
|
6172
|
+
requestedAccess: item.access,
|
|
6173
|
+
accountWorkId: account?.logicalWorkId ?? null,
|
|
6174
|
+
accountAccess: account?.access ?? null,
|
|
6175
|
+
rule
|
|
6176
|
+
};
|
|
6177
|
+
conflicts.set(JSON.stringify(conflict), conflict);
|
|
6178
|
+
}
|
|
6049
6179
|
const requestedAccess = /* @__PURE__ */ new Map();
|
|
6050
6180
|
const requestedDigests = /* @__PURE__ */ new Map();
|
|
6051
6181
|
const contentAccess = /* @__PURE__ */ new Map();
|
|
6052
|
-
|
|
6053
|
-
const
|
|
6054
|
-
const
|
|
6055
|
-
|
|
6056
|
-
|
|
6057
|
-
|
|
6058
|
-
|
|
6182
|
+
function claim(claims, identity, key, item, rule) {
|
|
6183
|
+
const previous = claims.get(identity) ?? [];
|
|
6184
|
+
for (const other of previous) {
|
|
6185
|
+
if (other.access === item.access) continue;
|
|
6186
|
+
record(item, key, rule);
|
|
6187
|
+
record(other, key, rule);
|
|
6188
|
+
}
|
|
6189
|
+
if (!previous.some((other) => other.workId === item.workId)) previous.push(item);
|
|
6190
|
+
claims.set(identity, previous);
|
|
6191
|
+
}
|
|
6192
|
+
const claimContent = (key, sha256, item) => claim(contentAccess, JSON.stringify([key, sha256]), key, item, "content-access");
|
|
6059
6193
|
for (const item of items) {
|
|
6060
6194
|
if (item.status === "blocked" || item.sessionAssembly) continue;
|
|
6061
6195
|
const keys = item.sessionMembership?.keys ?? (item.sessionUpload ? [item.sessionUpload.key] : []);
|
|
6062
6196
|
if (!keys.length) continue;
|
|
6063
6197
|
const destination = inventory.works.find((work) => work.logicalWorkId === item.workId);
|
|
6064
6198
|
if (destination?.access === "removed") throw new ApplicationError("WORK_REMOVED");
|
|
6199
|
+
if (destination) observe(item, destination.access);
|
|
6065
6200
|
for (const key of keys) {
|
|
6066
|
-
|
|
6067
|
-
|
|
6068
|
-
|
|
6069
|
-
const source
|
|
6070
|
-
|
|
6071
|
-
|
|
6072
|
-
if (
|
|
6073
|
-
if (destination && destination.access !== item.access && !destination.sessions.some((entry) => entry.key === key && (item.sessionMembership || entry.sha256 === sha256))) return true;
|
|
6201
|
+
claim(requestedAccess, key, key, item, "requested-access");
|
|
6202
|
+
const sources = inventory.works.filter((work) => work.sessions.some((entry) => entry.key === key));
|
|
6203
|
+
for (const source of sources) observe(item, source.access);
|
|
6204
|
+
for (const source of sources) if (source.logicalWorkId !== item.workId && source.access !== item.access) record(item, key, "held-elsewhere", source);
|
|
6205
|
+
const sha256 = item.sessionMembership ? sources[0]?.sessions.find((session) => session.key === key)?.sha256 : item.sessionUpload?.sha256;
|
|
6206
|
+
if (sha256) claimContent(key, sha256, item);
|
|
6207
|
+
if (destination && destination.access !== item.access && !destination.sessions.some((entry) => entry.key === key && (item.sessionMembership || entry.sha256 === sha256))) record(item, key, "destination-access", destination);
|
|
6074
6208
|
}
|
|
6075
6209
|
}
|
|
6076
6210
|
for (const item of items) {
|
|
6077
6211
|
if (item.sessionAssembly || item.sessionMembership || ["completed", "blocked"].includes(item.status)) continue;
|
|
6078
6212
|
const destination = inventory.works.find((work) => work.logicalWorkId === item.workId);
|
|
6079
6213
|
if (destination?.access === "removed") throw new ApplicationError("WORK_REMOVED");
|
|
6214
|
+
if (destination) observe(item, destination.access);
|
|
6080
6215
|
for await (const session of sessions(journeyId, item.artifact, signal)) {
|
|
6081
6216
|
const key = await sessionKeyFor(session);
|
|
6082
6217
|
const { workerIdentity: _, ...original } = session;
|
|
6083
6218
|
const legacyKey = session.workerIdentity ? await sessionKeyFor(original) : key;
|
|
6084
|
-
|
|
6085
|
-
|
|
6086
|
-
|
|
6087
|
-
requestedAccess.set(key, item.access);
|
|
6219
|
+
claimContent(key, session.sha256, item);
|
|
6220
|
+
if (legacyKey !== key) claimContent(legacyKey, session.sha256, item);
|
|
6221
|
+
claim(requestedAccess, key, key, item, "requested-access");
|
|
6088
6222
|
const otherDigest = requestedDigests.get(key);
|
|
6089
6223
|
if (otherDigest !== void 0 && otherDigest.sha256 !== session.sha256) throw new SessionContentConflict({
|
|
6090
6224
|
workIds: [.../* @__PURE__ */ new Set([...otherDigest.workIds, item.workId])],
|
|
@@ -6094,11 +6228,18 @@ async function sessionAccessBlocked(dependencies, journeyId, items, inventory, s
|
|
|
6094
6228
|
sha256: session.sha256,
|
|
6095
6229
|
workIds: [.../* @__PURE__ */ new Set([...otherDigest?.workIds ?? [], item.workId])]
|
|
6096
6230
|
});
|
|
6097
|
-
|
|
6098
|
-
|
|
6231
|
+
for (const work of inventory.works) for (const entry of work.sessions) {
|
|
6232
|
+
if (entry.key !== key && !(entry.key === legacyKey && entry.sha256 === session.sha256)) continue;
|
|
6233
|
+
observe(item, work.access);
|
|
6234
|
+
if (work.logicalWorkId !== item.workId && work.access !== item.access) record(item, entry.key, "held-elsewhere", work);
|
|
6235
|
+
}
|
|
6236
|
+
if (destination && destination.access !== item.access && !destination.sessions.some((entry) => entry.key === key && entry.sha256 === session.sha256)) record(item, key, "destination-access", destination);
|
|
6099
6237
|
}
|
|
6100
6238
|
}
|
|
6101
|
-
return
|
|
6239
|
+
return [...conflicts.values()].map((conflict) => (accountAccesses.get(conflict.workId)?.size ?? 0) > 1 ? {
|
|
6240
|
+
...conflict,
|
|
6241
|
+
accountAccess: "mixed"
|
|
6242
|
+
} : conflict);
|
|
6102
6243
|
}
|
|
6103
6244
|
/** Keep overlapping session ownership serial through membership, including retained members. */
|
|
6104
6245
|
async function sessionIndependentItems(dependencies, journeyId, items, inventory, signal) {
|
|
@@ -6776,8 +6917,8 @@ async function put(context, item, receiptId, upload, connection, signal, guard)
|
|
|
6776
6917
|
await guard();
|
|
6777
6918
|
await context.upload(item.artifact, upload, signal);
|
|
6778
6919
|
const sent = withoutBusy(item);
|
|
6779
|
-
await guard();
|
|
6780
6920
|
try {
|
|
6921
|
+
await guard();
|
|
6781
6922
|
return observe(sent, await connection.complete(receiptId, signal), connection, signal, context.snapshot === true);
|
|
6782
6923
|
} catch (error) {
|
|
6783
6924
|
if (upload.headers !== void 0 && error instanceof JourneyRemoteError && error.code === "bundle_mismatch") return {
|
|
@@ -6907,13 +7048,14 @@ function isCode(error, code) {
|
|
|
6907
7048
|
}
|
|
6908
7049
|
/**
|
|
6909
7050
|
* A step that ended without a definite answer and is safe to repeat: a request timeout or abort
|
|
6910
|
-
* that is not the Send's own cancellation, or a connection failure from `fetch
|
|
7051
|
+
* that is not the Send's own cancellation, or a connection failure from `fetch`: `fetch failed`
|
|
7052
|
+
* before the response, `terminated` when the socket resets while the body is read. The Work keeps
|
|
6911
7053
|
* its state, so the next advance repeats the same idempotent step (ADR 0197).
|
|
6912
7054
|
*/
|
|
6913
7055
|
function isInterrupted(error) {
|
|
6914
7056
|
if (!(error instanceof Error)) return false;
|
|
6915
7057
|
if (error.name === "TimeoutError" || error.name === "AbortError") return true;
|
|
6916
|
-
return error instanceof TypeError && error.message === "fetch failed";
|
|
7058
|
+
return error instanceof TypeError && (error.message === "fetch failed" || error.message === "terminated");
|
|
6917
7059
|
}
|
|
6918
7060
|
const sessionBackoffMs = (attempt) => 1e3 * 2 ** (attempt - 1);
|
|
6919
7061
|
const zeroByteBackoffMs = (count) => [
|
|
@@ -7201,10 +7343,10 @@ function usesSessionSend(dependencies, send) {
|
|
|
7201
7343
|
if (send.items.some((item) => item.sessionUpload !== void 0 || item.sessionMembership || item.sessionAssembly)) return true;
|
|
7202
7344
|
return !send.items.some((item) => item.receipt || item.reservation || item.previousReceipts.length > 0);
|
|
7203
7345
|
}
|
|
7204
|
-
async function saveSend(dependencies, snapshot, next, action) {
|
|
7346
|
+
async function saveSend(dependencies, snapshot, next, action, expectedJourneyRevision = action?.expectedJourneyRevision ?? snapshot.journey.revision) {
|
|
7205
7347
|
return dependencies.storage.commitSend({
|
|
7206
7348
|
journeyId: snapshot.journey.journeyId,
|
|
7207
|
-
expectedJourneyRevision
|
|
7349
|
+
expectedJourneyRevision,
|
|
7208
7350
|
expectedSendRevision: action?.expectedSendRevision ?? (snapshot.send?.id === next.id ? snapshot.send.revision : null),
|
|
7209
7351
|
requestKey: action?.idempotencyKey ?? randomUUID(),
|
|
7210
7352
|
requestHash: hash$1(action ?? next),
|
|
@@ -7231,6 +7373,10 @@ function aggregate(send) {
|
|
|
7231
7373
|
function awaitingPassport(send) {
|
|
7232
7374
|
return send.status === "completed" && send.items.some((item) => !["completed", "blocked"].includes(item.status));
|
|
7233
7375
|
}
|
|
7376
|
+
/** The host continues confirmed uploads and unfinished Passport assessments without a panel. */
|
|
7377
|
+
function hostDrives(send) {
|
|
7378
|
+
return awaitingPassport(send) || send.confirmedAt != null && ["sending", "waiting"].includes(send.status);
|
|
7379
|
+
}
|
|
7234
7380
|
/** Explicit resume retries recoverable items and recaptures a pending sign-in or profile. */
|
|
7235
7381
|
function resumeState(send) {
|
|
7236
7382
|
if (send.status !== "completed" && send.items.length && send.items.every((item) => item.status === "completed") && send.items.some((item) => !item.sessionAssembly)) return {
|
|
@@ -7255,18 +7401,23 @@ function resumeState(send) {
|
|
|
7255
7401
|
...send,
|
|
7256
7402
|
status: "sending",
|
|
7257
7403
|
error: null,
|
|
7258
|
-
items: send.items.map((item) =>
|
|
7259
|
-
|
|
7260
|
-
"
|
|
7261
|
-
|
|
7262
|
-
|
|
7263
|
-
|
|
7264
|
-
|
|
7265
|
-
|
|
7266
|
-
|
|
7267
|
-
|
|
7268
|
-
|
|
7269
|
-
|
|
7404
|
+
items: send.items.map((item) => {
|
|
7405
|
+
const { accessConflict: _previous, accessConflictSessionCount: _count, ...current } = item;
|
|
7406
|
+
return item.status === "blocked" && [
|
|
7407
|
+
"OPERATION_FAILED",
|
|
7408
|
+
"COORDINATION_BUSY",
|
|
7409
|
+
"UPLOAD_FAILED",
|
|
7410
|
+
"SEND_REMOTE_REFUSED",
|
|
7411
|
+
"SESSION_MOVE_ACCESS_REQUIRED",
|
|
7412
|
+
"SESSION_MOVE_ACCESS_HELD",
|
|
7413
|
+
"IDENTITY_UNAVAILABLE",
|
|
7414
|
+
"ACCOUNT_SIGNED_OUT"
|
|
7415
|
+
].includes(item.error ?? "") ? {
|
|
7416
|
+
...current,
|
|
7417
|
+
status: item.receipt ? item.receipt.state === "awaiting_upload" ? "uploading" : "assessing" : "ready",
|
|
7418
|
+
error: null
|
|
7419
|
+
} : item;
|
|
7420
|
+
})
|
|
7270
7421
|
});
|
|
7271
7422
|
return profileRequired && !["blocked", "completed"].includes(next.status) ? {
|
|
7272
7423
|
...next,
|
|
@@ -7307,7 +7458,7 @@ async function writeProfile(connection, chosen, guard, signal, failure, captured
|
|
|
7307
7458
|
await guard();
|
|
7308
7459
|
return captured;
|
|
7309
7460
|
} catch (error) {
|
|
7310
|
-
if (signal.aborted) throw error;
|
|
7461
|
+
if (signal.aborted || safeCode(error) === "COORDINATION_BUSY") throw error;
|
|
7311
7462
|
if (error instanceof JourneyRemoteError && error.status === 409 && addressRefusals[error.code]) return {
|
|
7312
7463
|
status: "blocked",
|
|
7313
7464
|
error: addressRefusals[error.code] ?? null
|
|
@@ -7333,7 +7484,7 @@ async function captureProfile(connection, guard, signal, failure) {
|
|
|
7333
7484
|
parallelCompletes: parallelCompletes ? true : void 0
|
|
7334
7485
|
};
|
|
7335
7486
|
} catch (error) {
|
|
7336
|
-
if (signal.aborted) throw error;
|
|
7487
|
+
if (signal.aborted || safeCode(error) === "COORDINATION_BUSY") throw error;
|
|
7337
7488
|
if (error instanceof JourneyRemoteError && error.status === 401 || error instanceof ApplicationError && error.code === "ACCOUNT_SIGNED_OUT") return {
|
|
7338
7489
|
status: "sign-in",
|
|
7339
7490
|
error: null
|
|
@@ -7454,7 +7605,14 @@ async function advanceItems(host, signal) {
|
|
|
7454
7605
|
});
|
|
7455
7606
|
host.failure("SEND_SCOPE_BUSY", cause);
|
|
7456
7607
|
error = "SEND_SCOPE_BUSY";
|
|
7457
|
-
} else if (isInterrupted(cause) || isTransientRefusal(cause)) {
|
|
7608
|
+
} else if (isInterrupted(cause) || isTransientRefusal(cause) || safeCode(cause) === "COORDINATION_BUSY") {
|
|
7609
|
+
if (safeCode(cause) === "COORDINATION_BUSY") {
|
|
7610
|
+
const current = progressed ?? item;
|
|
7611
|
+
next.set(item.workId, {
|
|
7612
|
+
...current,
|
|
7613
|
+
busyRefusals: (current.busyRefusals ?? 0) + 1
|
|
7614
|
+
});
|
|
7615
|
+
}
|
|
7458
7616
|
host.failure("SEND_INTERRUPTED", cause);
|
|
7459
7617
|
error = "SEND_INTERRUPTED";
|
|
7460
7618
|
} else {
|
|
@@ -7488,7 +7646,7 @@ async function advanceItems(host, signal) {
|
|
|
7488
7646
|
items
|
|
7489
7647
|
}));
|
|
7490
7648
|
} catch (error) {
|
|
7491
|
-
if (!signal.aborted && (isInterrupted(error) || error instanceof Error && isInterrupted(error.cause) || isCode(error, "IDENTITY_UNAVAILABLE"))) {
|
|
7649
|
+
if (!signal.aborted && (isInterrupted(error) || error instanceof Error && isInterrupted(error.cause) || isCode(error, "IDENTITY_UNAVAILABLE") || safeCode(error) === "COORDINATION_BUSY")) {
|
|
7492
7650
|
host.failure("SEND_INTERRUPTED", error);
|
|
7493
7651
|
return send.error === "SEND_INTERRUPTED" ? host.applied() : host.save({
|
|
7494
7652
|
...send,
|
|
@@ -7595,7 +7753,10 @@ async function advanceSend(dependencies, address, signal, chain) {
|
|
|
7595
7753
|
})
|
|
7596
7754
|
});
|
|
7597
7755
|
return blockSend({
|
|
7598
|
-
send:
|
|
7756
|
+
send: safeCode(error) === "SEND_SCOPE_INVALIDATED" ? {
|
|
7757
|
+
...snapshot.send,
|
|
7758
|
+
items: snapshot.send.items.filter((item) => !["SESSION_MOVE_ACCESS_REQUIRED", "SESSION_MOVE_ACCESS_HELD"].includes(item.error ?? ""))
|
|
7759
|
+
} : snapshot.send,
|
|
7599
7760
|
failure: dependencies.failure,
|
|
7600
7761
|
save
|
|
7601
7762
|
}, error, signal);
|
|
@@ -7621,18 +7782,41 @@ async function advanceSend(dependencies, address, signal, chain) {
|
|
|
7621
7782
|
if (!connection.sessions) throw new ApplicationError("INVALID_STATE");
|
|
7622
7783
|
if (!send.items.some((item) => item.status === "uploading" && !item.sessionAssembly && !item.receipt && !item.reservation)) return null;
|
|
7623
7784
|
const inventory = await connection.sessions.inventory(preflightSignal);
|
|
7624
|
-
|
|
7785
|
+
const conflicts = await sessionAccessBlocked(preparation.dependencies, snapshot.journey.journeyId, send.items, inventory, preflightSignal);
|
|
7786
|
+
if (conflicts.length === 0) {
|
|
7625
7787
|
independentItems = await sessionIndependentItems(preparation.dependencies, snapshot.journey.journeyId, send.items, inventory, preflightSignal);
|
|
7626
7788
|
return null;
|
|
7627
7789
|
}
|
|
7628
7790
|
await connection.assertCurrent(preflightSignal);
|
|
7791
|
+
dependencies.failure("SESSION_MOVE_ACCESS_REQUIRED", {
|
|
7792
|
+
code: "SESSION_MOVE_ACCESS_REQUIRED",
|
|
7793
|
+
message: JSON.stringify({
|
|
7794
|
+
conflicts: conflicts.length,
|
|
7795
|
+
works: new Set(conflicts.map((conflict) => conflict.workId)).size,
|
|
7796
|
+
rules: [...new Set(conflicts.map((conflict) => conflict.rule))].sort()
|
|
7797
|
+
})
|
|
7798
|
+
});
|
|
7629
7799
|
return save({
|
|
7630
7800
|
...send,
|
|
7631
7801
|
status: "blocked",
|
|
7632
|
-
items: send.items.map((item) =>
|
|
7633
|
-
|
|
7634
|
-
|
|
7635
|
-
|
|
7802
|
+
items: send.items.map((item) => {
|
|
7803
|
+
if (item.sessionAssembly || item.status === "completed") return item;
|
|
7804
|
+
const { accessConflict: _previous, accessConflictSessionCount: _count, ...current } = item;
|
|
7805
|
+
const itemConflicts = conflicts.filter((entry) => entry.workId === item.workId);
|
|
7806
|
+
const conflict = itemConflicts[0];
|
|
7807
|
+
if (!conflict) return {
|
|
7808
|
+
...current,
|
|
7809
|
+
status: "blocked",
|
|
7810
|
+
error: "SESSION_MOVE_ACCESS_HELD"
|
|
7811
|
+
};
|
|
7812
|
+
const { workId: _, ...accessConflict } = conflict;
|
|
7813
|
+
return {
|
|
7814
|
+
...current,
|
|
7815
|
+
status: "blocked",
|
|
7816
|
+
error: "SESSION_MOVE_ACCESS_REQUIRED",
|
|
7817
|
+
accessConflict,
|
|
7818
|
+
accessConflictSessionCount: new Set(itemConflicts.map((entry) => entry.sessionKey)).size
|
|
7819
|
+
};
|
|
7636
7820
|
})
|
|
7637
7821
|
});
|
|
7638
7822
|
},
|
|
@@ -7653,7 +7837,7 @@ async function advanceSend(dependencies, address, signal, chain) {
|
|
|
7653
7837
|
});
|
|
7654
7838
|
saving = pending.catch(() => void 0);
|
|
7655
7839
|
return pending;
|
|
7656
|
-
}).then((result) => {
|
|
7840
|
+
}).then(({ busyRefusals: _busy, ...result }) => {
|
|
7657
7841
|
fulfilled.add(item.workId);
|
|
7658
7842
|
return result;
|
|
7659
7843
|
})
|
|
@@ -7974,20 +8158,15 @@ function createManualUploader(dependencies) {
|
|
|
7974
8158
|
upload,
|
|
7975
8159
|
status: "applied"
|
|
7976
8160
|
};
|
|
7977
|
-
|
|
8161
|
+
let bindings = [];
|
|
8162
|
+
return advanceItems({
|
|
7978
8163
|
send: upload,
|
|
7979
8164
|
failure: dependencies.failure,
|
|
7980
|
-
save: (next) => save(upload, next)
|
|
7981
|
-
|
|
7982
|
-
|
|
7983
|
-
|
|
7984
|
-
|
|
7985
|
-
} catch (error) {
|
|
7986
|
-
return blockSend(host, error, signal);
|
|
7987
|
-
}
|
|
7988
|
-
return advanceItems({
|
|
7989
|
-
...host,
|
|
7990
|
-
connect: dependencies.auth.connect,
|
|
8165
|
+
save: (next) => save(upload, next),
|
|
8166
|
+
connect: async (connectSignal) => {
|
|
8167
|
+
bindings = await storage.bindings();
|
|
8168
|
+
return dependencies.auth.connect(connectSignal);
|
|
8169
|
+
},
|
|
7991
8170
|
profile: (connection, profileSignal) => captureProfile(connection, guard(upload), profileSignal, dependencies.failure),
|
|
7992
8171
|
context: (item) => ({
|
|
7993
8172
|
active: guard(upload, item),
|
|
@@ -9244,89 +9423,91 @@ const sendRecoveryCodes = [
|
|
|
9244
9423
|
];
|
|
9245
9424
|
//#endregion
|
|
9246
9425
|
//#region apps/cli/src/account/journey/request.ts
|
|
9247
|
-
/** Artifact-independent authorization: packaging progress cannot expand this scope. */
|
|
9248
|
-
function requestedScope(journey) {
|
|
9249
|
-
return hash$1({
|
|
9250
|
-
privacy: privacyDecisionDigest(journey),
|
|
9251
|
-
configurationId: journey.configurationId,
|
|
9252
|
-
confirmedHideRevision: journey.confirmedHideRevision ?? 0,
|
|
9253
|
-
consent: journey.consent,
|
|
9254
|
-
profile: journey.profile,
|
|
9255
|
-
works: journey.works.map((work) => ({
|
|
9256
|
-
id: work.id,
|
|
9257
|
-
inputRevision: work.inputRevision,
|
|
9258
|
-
access: work.access,
|
|
9259
|
-
accessConfirmed: work.accessConfirmed,
|
|
9260
|
-
included: isIncludedWork(work),
|
|
9261
|
-
placement: work.placement,
|
|
9262
|
-
suggestion: work.suggestion
|
|
9263
|
-
}))
|
|
9264
|
-
});
|
|
9265
|
-
}
|
|
9266
9426
|
function requestMatches(send, journey) {
|
|
9267
9427
|
return send.request?.scopeDigest === requestedScope(journey) && !journey.pendingHideId && journey.phase !== "paused" && !journey.abandonedAt;
|
|
9268
9428
|
}
|
|
9269
9429
|
async function requestSend(dependencies, raw, hostId, source) {
|
|
9270
9430
|
const input = sendRequestSchema.parse(raw);
|
|
9271
|
-
|
|
9272
|
-
|
|
9273
|
-
|
|
9274
|
-
|
|
9275
|
-
|
|
9276
|
-
|
|
9277
|
-
|
|
9278
|
-
|
|
9279
|
-
|
|
9280
|
-
state: recorded.send,
|
|
9281
|
-
at: dependencies.now()
|
|
9282
|
-
});
|
|
9283
|
-
if (current.journey.revision !== input.expectedJourneyRevision) return {
|
|
9284
|
-
...current,
|
|
9285
|
-
status: "stale"
|
|
9286
|
-
};
|
|
9287
|
-
assertJourneyPrivacyReady(current.journey);
|
|
9288
|
-
if (current.journey.pendingHideId || current.journey.phase === "paused") throw new ApplicationError("SCOPE_NOT_READY");
|
|
9289
|
-
if (current.send && ([
|
|
9290
|
-
"awaiting-packaging",
|
|
9291
|
-
"sending",
|
|
9292
|
-
"waiting",
|
|
9293
|
-
"sign-in",
|
|
9294
|
-
"review"
|
|
9295
|
-
].includes(current.send.status) || current.send.items.some((item) => item.recoveryReview) || current.send.status === "paused" && current.send.confirmedAt !== null && current.send.scopeDigest === scopeDigest(current.journey))) throw new ApplicationError("INVALID_TRANSITION");
|
|
9296
|
-
if (!hostId) throw new ApplicationError("INVALID_TRANSITION");
|
|
9297
|
-
const included = current.journey.works.filter(isIncludedWork);
|
|
9298
|
-
if (!sameIds$1(input.included.map((work) => work.workId), included.map((work) => work.id)) || !input.included.every((item) => included.some((work) => work.id === item.workId && work.access === item.access && work.accessConfirmed)) || !sameIds$1(input.omittedWorkIds, current.journey.works.filter((work) => !isIncludedWork(work)).map((work) => work.id))) throw new ApplicationError("CONFIRMATION_REQUIRED");
|
|
9299
|
-
const subject = (await dependencies.auth.connect(new AbortController().signal))?.subject ?? null;
|
|
9300
|
-
const at = dependencies.now();
|
|
9301
|
-
return dependencies.storage.commitSend({
|
|
9302
|
-
journeyId: input.journeyId,
|
|
9303
|
-
expectedJourneyRevision: input.expectedJourneyRevision,
|
|
9304
|
-
expectedSendRevision: null,
|
|
9305
|
-
requestKey: input.idempotencyKey,
|
|
9306
|
-
requestHash: hash$1(input),
|
|
9307
|
-
state: {
|
|
9308
|
-
id: input.idempotencyKey,
|
|
9431
|
+
let expectedScope = input.displayedScopeDigest;
|
|
9432
|
+
let binding;
|
|
9433
|
+
let firstSendId = null;
|
|
9434
|
+
for (let attempt = 0;; attempt += 1) {
|
|
9435
|
+
const current = await dependencies.storage.loadSend(input.journeyId);
|
|
9436
|
+
if (!current) throw new ApplicationError("UNKNOWN_ITEM");
|
|
9437
|
+
if (attempt === 0) firstSendId = current.send?.id ?? null;
|
|
9438
|
+
const recorded = current.send?.id === input.idempotencyKey ? current : await dependencies.storage.loadSend(input.journeyId, input.idempotencyKey);
|
|
9439
|
+
if (recorded?.send) return dependencies.storage.commitSend({
|
|
9309
9440
|
journeyId: input.journeyId,
|
|
9310
|
-
|
|
9311
|
-
|
|
9312
|
-
|
|
9313
|
-
|
|
9314
|
-
|
|
9315
|
-
|
|
9316
|
-
|
|
9317
|
-
|
|
9318
|
-
|
|
9319
|
-
|
|
9320
|
-
|
|
9321
|
-
|
|
9322
|
-
|
|
9441
|
+
expectedJourneyRevision: input.expectedJourneyRevision,
|
|
9442
|
+
expectedSendRevision: null,
|
|
9443
|
+
requestKey: input.idempotencyKey,
|
|
9444
|
+
requestHash: hash$1(input),
|
|
9445
|
+
state: recorded.send,
|
|
9446
|
+
at: dependencies.now()
|
|
9447
|
+
});
|
|
9448
|
+
if (attempt > 0 && (current.send?.id ?? null) !== firstSendId) return {
|
|
9449
|
+
...current,
|
|
9450
|
+
status: "stale"
|
|
9451
|
+
};
|
|
9452
|
+
if (expectedScope === void 0) {
|
|
9453
|
+
if (current.journey.revision !== input.expectedJourneyRevision) return {
|
|
9454
|
+
...current,
|
|
9455
|
+
status: "stale"
|
|
9456
|
+
};
|
|
9457
|
+
expectedScope = displayedScopeDigest(current.journey);
|
|
9458
|
+
}
|
|
9459
|
+
if (displayedScopeDigest(current.journey) !== expectedScope) return {
|
|
9460
|
+
...current,
|
|
9461
|
+
status: "stale"
|
|
9462
|
+
};
|
|
9463
|
+
assertJourneyPrivacyReady(current.journey, false, { publicChoices: true });
|
|
9464
|
+
if (current.journey.pendingHideId || current.journey.phase === "paused") throw new ApplicationError("SCOPE_NOT_READY");
|
|
9465
|
+
if (current.send && ([
|
|
9466
|
+
"awaiting-packaging",
|
|
9467
|
+
"sending",
|
|
9468
|
+
"waiting",
|
|
9469
|
+
"sign-in",
|
|
9470
|
+
"review"
|
|
9471
|
+
].includes(current.send.status) || current.send.items.some((item) => item.recoveryReview) || current.send.status === "paused" && current.send.confirmedAt !== null && scopeDigest(current.journey) === current.send.scopeDigest)) throw new ApplicationError("INVALID_TRANSITION");
|
|
9472
|
+
if (!hostId) throw new ApplicationError("INVALID_TRANSITION");
|
|
9473
|
+
const included = current.journey.works.filter(isIncludedWork);
|
|
9474
|
+
if (!sameIds$1(input.included.map((work) => work.workId), included.map((work) => work.id)) || !input.included.every((item) => included.some((work) => work.id === item.workId && work.access === item.access && work.accessConfirmed)) || !sameIds$1(input.omittedWorkIds, current.journey.works.filter((work) => !isIncludedWork(work)).map((work) => work.id))) throw new ApplicationError("CONFIRMATION_REQUIRED");
|
|
9475
|
+
if (!binding) binding = {
|
|
9476
|
+
subject: (await dependencies.auth.connect(new AbortController().signal))?.subject ?? null,
|
|
9477
|
+
at: dependencies.now()
|
|
9478
|
+
};
|
|
9479
|
+
const { subject, at } = binding;
|
|
9480
|
+
const result = await dependencies.storage.commitSend({
|
|
9481
|
+
journeyId: input.journeyId,
|
|
9482
|
+
expectedJourneyRevision: current.journey.revision,
|
|
9483
|
+
expectedSendRevision: null,
|
|
9484
|
+
requestKey: input.idempotencyKey,
|
|
9485
|
+
requestHash: hash$1(input),
|
|
9486
|
+
state: {
|
|
9487
|
+
id: input.idempotencyKey,
|
|
9488
|
+
journeyId: input.journeyId,
|
|
9489
|
+
revision: 0,
|
|
9323
9490
|
scopeDigest: requestedScope(current.journey),
|
|
9324
|
-
|
|
9325
|
-
|
|
9326
|
-
|
|
9327
|
-
|
|
9328
|
-
|
|
9329
|
-
|
|
9491
|
+
subject,
|
|
9492
|
+
confirmedAt: null,
|
|
9493
|
+
status: "awaiting-packaging",
|
|
9494
|
+
items: [],
|
|
9495
|
+
omitted: [],
|
|
9496
|
+
error: null,
|
|
9497
|
+
request: {
|
|
9498
|
+
requestedAt: at,
|
|
9499
|
+
subject,
|
|
9500
|
+
hostId,
|
|
9501
|
+
source,
|
|
9502
|
+
scopeDigest: requestedScope(current.journey),
|
|
9503
|
+
included: input.included,
|
|
9504
|
+
omittedWorkIds: input.omittedWorkIds
|
|
9505
|
+
}
|
|
9506
|
+
},
|
|
9507
|
+
at
|
|
9508
|
+
});
|
|
9509
|
+
if (result.status !== "stale" || attempt === 1) return result;
|
|
9510
|
+
}
|
|
9330
9511
|
}
|
|
9331
9512
|
/**
|
|
9332
9513
|
* Previously sent Works with unchanged access remain part of the displayed authorization. Keep
|
|
@@ -9401,6 +9582,7 @@ function createJourneySender(dependencies, phases = 3, host = {
|
|
|
9401
9582
|
/** The serving host owns a pending request; another process leaves it unchanged. */
|
|
9402
9583
|
const pendingElsewhere = (send) => !host.serving && send?.request !== void 0 && !send.confirmedAt;
|
|
9403
9584
|
const progress = /* @__PURE__ */ new Map();
|
|
9585
|
+
let packagingRetry;
|
|
9404
9586
|
const sessionFacts = createSessionFactsCache();
|
|
9405
9587
|
const running = /* @__PURE__ */ new Map();
|
|
9406
9588
|
const runKey = (address) => `${address.journeyId}:${address.sendId}`;
|
|
@@ -9488,7 +9670,7 @@ function createJourneySender(dependencies, phases = 3, host = {
|
|
|
9488
9670
|
const snapshot = await dependencies.storage.loadSend(input.journeyId);
|
|
9489
9671
|
sessionFacts.retain(input.journeyId, snapshot?.send ?? null);
|
|
9490
9672
|
if (!snapshot) throw new ApplicationError("UNKNOWN_ITEM");
|
|
9491
|
-
if (snapshot.journey.revision !== input.expectedJourneyRevision) return {
|
|
9673
|
+
if (input.displayedScopeDigest ? displayedScopeDigest(snapshot.journey) !== input.displayedScopeDigest : snapshot.journey.revision !== input.expectedJourneyRevision) return {
|
|
9492
9674
|
...snapshot,
|
|
9493
9675
|
status: "stale"
|
|
9494
9676
|
};
|
|
@@ -9500,27 +9682,49 @@ function createJourneySender(dependencies, phases = 3, host = {
|
|
|
9500
9682
|
const pendingError = pending ? await requestError(dependencies, pending, hostId, signal) : null;
|
|
9501
9683
|
if (pending && (pendingError || !requestMatches(pending, snapshot.journey))) return block(snapshot, pending, pendingError ?? "REVISION_CONFLICT");
|
|
9502
9684
|
const draft = await draftSend(snapshot.journey, dependencies, signal);
|
|
9685
|
+
let observed = false;
|
|
9503
9686
|
const recover = snapshot.send && [
|
|
9504
9687
|
"blocked",
|
|
9505
9688
|
"paused",
|
|
9506
9689
|
"completed"
|
|
9507
9690
|
].includes(snapshot.send.status) && snapshot.send.items.some((item) => sendRecoveryCodes.includes(item.error ?? ""));
|
|
9508
|
-
if (recover
|
|
9691
|
+
if (recover || dependencies.artifacts.sessions) {
|
|
9509
9692
|
const connection = await dependencies.auth.connect(signal);
|
|
9510
|
-
if (
|
|
9511
|
-
|
|
9693
|
+
if (connection && draft.subject !== connection.subject) return {
|
|
9694
|
+
...snapshot,
|
|
9695
|
+
status: "stale"
|
|
9696
|
+
};
|
|
9697
|
+
if (recover && !connection) throw new ApplicationError("ACCOUNT_SIGNED_OUT");
|
|
9698
|
+
if (recover && snapshot.send?.subject && snapshot.send.subject !== connection?.subject) throw new ApplicationError("IDENTITY_REJECTED");
|
|
9512
9699
|
const sessions = dependencies.artifacts.sessions;
|
|
9513
|
-
const remote = connection
|
|
9514
|
-
if (sessions && remote) {
|
|
9515
|
-
const inventory = await remote.inventory(signal)
|
|
9516
|
-
|
|
9517
|
-
|
|
9700
|
+
const remote = connection?.sessions;
|
|
9701
|
+
if (sessions && remote && connection) {
|
|
9702
|
+
const inventory = await remote.inventory(signal).catch((error) => {
|
|
9703
|
+
if (signal.aborted || recover) throw error;
|
|
9704
|
+
dependencies.failure("SEND_INTERRUPTED", error);
|
|
9705
|
+
return null;
|
|
9706
|
+
});
|
|
9707
|
+
observed = inventory !== null;
|
|
9708
|
+
try {
|
|
9709
|
+
const conflicts = inventory ? await sessionAccessBlocked(dependencies, input.journeyId, draft.items, inventory, signal) : [];
|
|
9710
|
+
for (const item of draft.items) {
|
|
9711
|
+
const conflict = conflicts.find((entry) => entry.workId === item.workId && entry.accountAccess !== null) ?? conflicts.find((entry) => entry.workId === item.workId);
|
|
9712
|
+
if (conflict) {
|
|
9713
|
+
const { workId: _, ...accessConflict } = conflict;
|
|
9714
|
+
item.accessConflict = accessConflict;
|
|
9715
|
+
}
|
|
9716
|
+
}
|
|
9717
|
+
} catch (error) {
|
|
9718
|
+
if (!(error instanceof SessionContentConflict) && !(error instanceof ApplicationError && error.code === "WORK_REMOVED")) throw error;
|
|
9719
|
+
}
|
|
9720
|
+
for (const item of inventory && recover && snapshot.send ? draft.items : []) {
|
|
9721
|
+
const current = inventory?.works.find((work) => work.logicalWorkId === item.workId);
|
|
9518
9722
|
const assembly = await remote.assembly(item.workId, signal);
|
|
9519
9723
|
const selected = createSessionKeys();
|
|
9520
9724
|
for await (const session of sessions(input.journeyId, item.artifact, signal)) await selected.add(session);
|
|
9521
9725
|
const currentKeys = current?.sessions.map((session) => session.key) ?? [];
|
|
9522
9726
|
item.recoveryReview = {
|
|
9523
|
-
previousSendId: snapshot.send.id,
|
|
9727
|
+
previousSendId: snapshot.send?.id ?? draft.id,
|
|
9524
9728
|
revision: assembly?.revision ?? 0,
|
|
9525
9729
|
currentAccess: current?.access ?? null,
|
|
9526
9730
|
currentKeys,
|
|
@@ -9530,7 +9734,11 @@ function createJourneySender(dependencies, phases = 3, host = {
|
|
|
9530
9734
|
await connection.assertCurrent(signal);
|
|
9531
9735
|
}
|
|
9532
9736
|
}
|
|
9533
|
-
const
|
|
9737
|
+
for (const item of observed ? [] : draft.items) {
|
|
9738
|
+
const previous = snapshot.send?.items.find((entry) => entry.workId === item.workId && entry.access === item.access)?.accessConflict;
|
|
9739
|
+
if (previous && !item.accessConflict) item.accessConflict = previous;
|
|
9740
|
+
}
|
|
9741
|
+
const canReuseExistingSend = !(snapshot.send?.confirmedAt && ["blocked", "paused"].includes(snapshot.send.status)) && !recover && snapshot.send && scopeDigest(snapshot.journey) === snapshot.send.scopeDigest && snapshot.send.subject === draft.subject;
|
|
9534
9742
|
const next = pending ? {
|
|
9535
9743
|
...draft,
|
|
9536
9744
|
id: pending.id,
|
|
@@ -9538,11 +9746,12 @@ function createJourneySender(dependencies, phases = 3, host = {
|
|
|
9538
9746
|
request: pending.request
|
|
9539
9747
|
} : canReuseExistingSend && snapshot.send ? {
|
|
9540
9748
|
...snapshot.send,
|
|
9749
|
+
...snapshot.send.confirmedAt === null ? { items: draft.items } : {},
|
|
9541
9750
|
revision: snapshot.send.revision + 1
|
|
9542
9751
|
} : draft;
|
|
9543
9752
|
const result = await dependencies.storage.commitSend({
|
|
9544
9753
|
journeyId: input.journeyId,
|
|
9545
|
-
expectedJourneyRevision:
|
|
9754
|
+
expectedJourneyRevision: snapshot.journey.revision,
|
|
9546
9755
|
expectedSendRevision: pending?.revision ?? (canReuseExistingSend && snapshot.send ? snapshot.send.revision : null),
|
|
9547
9756
|
requestKey: input.idempotencyKey,
|
|
9548
9757
|
requestHash: hash$1(input),
|
|
@@ -9555,7 +9764,12 @@ function createJourneySender(dependencies, phases = 3, host = {
|
|
|
9555
9764
|
async start(raw, signal) {
|
|
9556
9765
|
const input = sendStartSchema.parse(raw);
|
|
9557
9766
|
const snapshot = await load(input);
|
|
9558
|
-
if (!
|
|
9767
|
+
if (snapshot.send.revision !== input.expectedSendRevision || !input.displayedScopeDigest && snapshot.journey.revision !== input.expectedJourneyRevision) return saveSend(dependencies, snapshot, snapshot.send, input);
|
|
9768
|
+
if (input.displayedScopeDigest && displayedScopeDigest(snapshot.journey) !== input.displayedScopeDigest) return {
|
|
9769
|
+
...snapshot,
|
|
9770
|
+
status: "stale"
|
|
9771
|
+
};
|
|
9772
|
+
const saveStart = (next) => saveSend(dependencies, snapshot, next, input, snapshot.journey.revision);
|
|
9559
9773
|
if (pendingElsewhere(snapshot.send)) return {
|
|
9560
9774
|
...snapshot,
|
|
9561
9775
|
status: "applied"
|
|
@@ -9563,8 +9777,8 @@ function createJourneySender(dependencies, phases = 3, host = {
|
|
|
9563
9777
|
const authorizationError = await requestError(dependencies, snapshot.send, hostId, signal);
|
|
9564
9778
|
if (snapshot.send.request && !snapshot.send.confirmedAt && (authorizationError || !requestMatches(snapshot.send, snapshot.journey))) return block(snapshot, snapshot.send, authorizationError ?? "REVISION_CONFLICT");
|
|
9565
9779
|
assertScope(snapshot.journey, snapshot.send);
|
|
9566
|
-
if (!sameIds$1(input.confirmedWorkIds, snapshot.send.items.map((item) => item.workId)) || !sameIds$1(input.confirmedOmittedWorkIds, snapshot.send.omitted.map((item) => item.workId)) || input.scopeDigest !== snapshot.send.scopeDigest || snapshot.send.items.length === 0) throw new ApplicationError("CONFIRMATION_REQUIRED");
|
|
9567
|
-
if (snapshot.send.confirmedAt !== null) return
|
|
9780
|
+
if (!sameIds$1(input.confirmedWorkIds, snapshot.send.items.map((item) => item.workId)) || !sameIds$1(input.confirmedOmittedWorkIds, snapshot.send.omitted.map((item) => item.workId)) || input.scopeDigest !== snapshot.send.scopeDigest || snapshot.send.items.length === 0 || snapshot.send.items.some((item) => item.accessConflict !== void 0)) throw new ApplicationError("CONFIRMATION_REQUIRED");
|
|
9781
|
+
if (snapshot.send.confirmedAt !== null) return saveStart(snapshot.send);
|
|
9568
9782
|
const connection = await dependencies.auth.connect(signal);
|
|
9569
9783
|
if (snapshot.send.request && (connection?.subject ?? null) !== snapshot.send.request.subject) return saveSend(dependencies, snapshot, {
|
|
9570
9784
|
...snapshot.send,
|
|
@@ -9580,18 +9794,18 @@ function createJourneySender(dependencies, phases = 3, host = {
|
|
|
9580
9794
|
if (connection) try {
|
|
9581
9795
|
profile = await prepareProfile(dependencies, snapshot, connection, signal);
|
|
9582
9796
|
} catch (error) {
|
|
9583
|
-
if (error instanceof ApplicationError && error.code === "REVISION_CONFLICT") return
|
|
9797
|
+
if (error instanceof ApplicationError && error.code === "REVISION_CONFLICT") return saveStart(snapshot.send);
|
|
9584
9798
|
throw error;
|
|
9585
9799
|
}
|
|
9586
9800
|
signal.throwIfAborted();
|
|
9587
9801
|
const finalAuthorizationError = await requestError(dependencies, snapshot.send, hostId, signal);
|
|
9588
9802
|
if (finalAuthorizationError) return block(snapshot, snapshot.send, finalAuthorizationError);
|
|
9589
|
-
return
|
|
9803
|
+
return saveStart({
|
|
9590
9804
|
...snapshot.send,
|
|
9591
9805
|
subject: connection?.subject ?? snapshot.send.subject,
|
|
9592
9806
|
confirmedAt: snapshot.send.request && !connection ? null : dependencies.now(),
|
|
9593
9807
|
...profile
|
|
9594
|
-
}
|
|
9808
|
+
});
|
|
9595
9809
|
},
|
|
9596
9810
|
async respond(raw) {
|
|
9597
9811
|
const input = sendChoiceSchema.parse(raw);
|
|
@@ -9672,6 +9886,10 @@ function createJourneySender(dependencies, phases = 3, host = {
|
|
|
9672
9886
|
...snapshot,
|
|
9673
9887
|
status: "applied"
|
|
9674
9888
|
};
|
|
9889
|
+
if (!host.serving && hostDrives(snapshot.send) && await host.focused?.(address.journeyId)) return {
|
|
9890
|
+
...snapshot,
|
|
9891
|
+
status: "applied"
|
|
9892
|
+
};
|
|
9675
9893
|
const authorizationError = await requestError(dependencies, snapshot.send, hostId, lifetime);
|
|
9676
9894
|
if (authorizationError) return block(snapshot, snapshot.send, authorizationError);
|
|
9677
9895
|
if (snapshot.send.request && !snapshot.send.confirmedAt && ["awaiting-packaging", "prepared"].includes(snapshot.send.status)) {
|
|
@@ -9686,10 +9904,52 @@ function createJourneySender(dependencies, phases = 3, host = {
|
|
|
9686
9904
|
error: "REVISION_CONFLICT"
|
|
9687
9905
|
});
|
|
9688
9906
|
if (snapshot.send.status === "awaiting-packaging") {
|
|
9689
|
-
if (
|
|
9690
|
-
|
|
9907
|
+
if (packagingRetry?.key !== key) packagingRetry = void 0;
|
|
9908
|
+
if (packagingRetry && Date.parse(dependencies.now()) < packagingRetry.after) return {
|
|
9909
|
+
...snapshot,
|
|
9691
9910
|
status: "applied"
|
|
9692
9911
|
};
|
|
9912
|
+
let packaged;
|
|
9913
|
+
try {
|
|
9914
|
+
packaged = await dependencies.package?.(address.journeyId, snapshot.send.request.included.map((item) => item.workId), lifetime, snapshot.send.request.source);
|
|
9915
|
+
} catch (cause) {
|
|
9916
|
+
lifetime.throwIfAborted();
|
|
9917
|
+
const code = cause instanceof ApplicationError ? cause.code : safeCode(cause);
|
|
9918
|
+
if (packagingRefusalCodes.includes(code)) throw cause;
|
|
9919
|
+
dependencies.failure(code, cause);
|
|
9920
|
+
snapshot = await load(address);
|
|
9921
|
+
if (snapshot.send.status !== "awaiting-packaging") return {
|
|
9922
|
+
...snapshot,
|
|
9923
|
+
status: "stale"
|
|
9924
|
+
};
|
|
9925
|
+
const error = await requestError(dependencies, snapshot.send, hostId, lifetime);
|
|
9926
|
+
if (error || !requestMatches(snapshot.send, snapshot.journey)) return block(snapshot, snapshot.send, error ?? "REVISION_CONFLICT");
|
|
9927
|
+
if (finalPackagingCodes.includes(code)) {
|
|
9928
|
+
packagingRetry = void 0;
|
|
9929
|
+
return block(snapshot, snapshot.send, code);
|
|
9930
|
+
}
|
|
9931
|
+
const failures = Math.min((packagingRetry?.failures ?? 0) + 1, 5);
|
|
9932
|
+
packagingRetry = {
|
|
9933
|
+
key,
|
|
9934
|
+
failures,
|
|
9935
|
+
after: Date.parse(dependencies.now()) + Math.min(2e3 * 2 ** (failures - 1), 3e4)
|
|
9936
|
+
};
|
|
9937
|
+
return saveSend(dependencies, snapshot, {
|
|
9938
|
+
...snapshot.send,
|
|
9939
|
+
error: code
|
|
9940
|
+
});
|
|
9941
|
+
}
|
|
9942
|
+
packagingRetry = void 0;
|
|
9943
|
+
if (packaged === false) {
|
|
9944
|
+
snapshot = await load(address);
|
|
9945
|
+
return snapshot.send.error ? saveSend(dependencies, snapshot, {
|
|
9946
|
+
...snapshot.send,
|
|
9947
|
+
error: null
|
|
9948
|
+
}) : {
|
|
9949
|
+
...snapshot,
|
|
9950
|
+
status: "applied"
|
|
9951
|
+
};
|
|
9952
|
+
}
|
|
9693
9953
|
snapshot = await load(address);
|
|
9694
9954
|
if (snapshot.send.status !== "awaiting-packaging") return {
|
|
9695
9955
|
...snapshot,
|
|
@@ -9703,6 +9963,10 @@ function createJourneySender(dependencies, phases = 3, host = {
|
|
|
9703
9963
|
if (prepared.status === "stale" || prepared.send?.status !== "prepared") return prepared;
|
|
9704
9964
|
snapshot = requireSend(prepared);
|
|
9705
9965
|
}
|
|
9966
|
+
if (snapshot.send.items.some((item) => item.accessConflict)) return saveSend(dependencies, snapshot, {
|
|
9967
|
+
...snapshot.send,
|
|
9968
|
+
request: void 0
|
|
9969
|
+
});
|
|
9706
9970
|
if (!requestMatches(snapshot.send, snapshot.journey) || !requestedItemsMatch(snapshot.send, snapshot.journey)) return saveSend(dependencies, snapshot, {
|
|
9707
9971
|
...snapshot.send,
|
|
9708
9972
|
status: "blocked",
|
|
@@ -9740,10 +10004,6 @@ function createJourneySender(dependencies, phases = 3, host = {
|
|
|
9740
10004
|
}
|
|
9741
10005
|
//#endregion
|
|
9742
10006
|
//#region apps/cli/src/account/journey/auth.ts
|
|
9743
|
-
/** An access token this close to expiry is renewed first, so a step never starts on it. */
|
|
9744
|
-
const renewBeforeMs = 12e4;
|
|
9745
|
-
const renewTimeoutMs = 3e4;
|
|
9746
|
-
const renewals = /* @__PURE__ */ new WeakMap();
|
|
9747
10007
|
/** Reuses the existing device sign-in credential; a token is never returned to the panel or Agent. */
|
|
9748
10008
|
function createJourneySendAuth(account, requestFetch) {
|
|
9749
10009
|
/**
|
|
@@ -9770,39 +10030,11 @@ function createJourneySendAuth(account, requestFetch) {
|
|
|
9770
10030
|
return value;
|
|
9771
10031
|
})).credential?.refreshToken) await expire(accessToken);
|
|
9772
10032
|
}
|
|
9773
|
-
function renew(credential) {
|
|
9774
|
-
const running = renewals.get(account);
|
|
9775
|
-
if (running) return running;
|
|
9776
|
-
const renewing = (async () => {
|
|
9777
|
-
try {
|
|
9778
|
-
const token = await account.identity.refresh(credential.refreshToken, AbortSignal.timeout(renewTimeoutMs));
|
|
9779
|
-
if (!token) {
|
|
9780
|
-
await expire(credential.accessToken);
|
|
9781
|
-
return null;
|
|
9782
|
-
}
|
|
9783
|
-
return (await account.credentials.update((value) => {
|
|
9784
|
-
if (value.credential?.refreshToken === credential.refreshToken) value.credential = {
|
|
9785
|
-
...value.credential,
|
|
9786
|
-
accessToken: token.accessToken,
|
|
9787
|
-
refreshToken: token.refreshToken ?? credential.refreshToken,
|
|
9788
|
-
scope: token.scope,
|
|
9789
|
-
issuedAt: account.now(),
|
|
9790
|
-
expiresAt: token.expiresAt
|
|
9791
|
-
};
|
|
9792
|
-
return value;
|
|
9793
|
-
})).credential;
|
|
9794
|
-
} finally {
|
|
9795
|
-
renewals.delete(account);
|
|
9796
|
-
}
|
|
9797
|
-
})();
|
|
9798
|
-
renewals.set(account, renewing);
|
|
9799
|
-
return renewing;
|
|
9800
|
-
}
|
|
9801
10033
|
async function current() {
|
|
9802
10034
|
const credential = (await account.credentials.update((value) => value)).credential;
|
|
9803
10035
|
if (!credential || credential.identityUrl !== account.configuration.identityUrl || credential.clientId !== account.configuration.clientId) return null;
|
|
9804
10036
|
const left = Date.parse(credential.expiresAt) - Date.parse(account.now());
|
|
9805
|
-
if (Number.isFinite(left) && left >
|
|
10037
|
+
if (Number.isFinite(left) && left > 12e4) return credential;
|
|
9806
10038
|
const { refreshToken } = credential;
|
|
9807
10039
|
if (!refreshToken) {
|
|
9808
10040
|
if (Number.isFinite(left) && left > 0) return credential;
|
|
@@ -9810,7 +10042,7 @@ function createJourneySendAuth(account, requestFetch) {
|
|
|
9810
10042
|
return null;
|
|
9811
10043
|
}
|
|
9812
10044
|
try {
|
|
9813
|
-
return await renew({
|
|
10045
|
+
return await renew(account, {
|
|
9814
10046
|
...credential,
|
|
9815
10047
|
refreshToken
|
|
9816
10048
|
});
|
|
@@ -9860,6 +10092,100 @@ function createJourneySendAuth(account, requestFetch) {
|
|
|
9860
10092
|
};
|
|
9861
10093
|
}
|
|
9862
10094
|
//#endregion
|
|
10095
|
+
//#region apps/cli/src/account/journey/account-access.ts
|
|
10096
|
+
/** Current and legacy upload keys of every part of one local session. */
|
|
10097
|
+
async function keysOf(session) {
|
|
10098
|
+
const keys = [];
|
|
10099
|
+
for (const part of session.parts.length ? session.parts : [void 0]) {
|
|
10100
|
+
const native = part?.nativeEvidence?.identity;
|
|
10101
|
+
const identity = {
|
|
10102
|
+
harness: session.harness,
|
|
10103
|
+
nativeSessionId: native?.sessionId ?? session.sourceSessionId,
|
|
10104
|
+
...part?.harnessRelativePath ? { relativePath: part.harnessRelativePath } : {},
|
|
10105
|
+
...session.harness === "claude" && native?.role === "worker" ? { workerIdentity: { agentId: native.agentId } } : {}
|
|
10106
|
+
};
|
|
10107
|
+
const { workerIdentity: _, ...original } = identity;
|
|
10108
|
+
keys.push([await sessionKeyFor(identity), await sessionKeyFor(original)]);
|
|
10109
|
+
}
|
|
10110
|
+
return keys;
|
|
10111
|
+
}
|
|
10112
|
+
/**
|
|
10113
|
+
* Compare frozen identities with the same hashed keys used by session uploads. A Work sends each
|
|
10114
|
+
* root's whole family (`members`, from `reviewFamilies`), so uniform Public is `public-all` only
|
|
10115
|
+
* when every part of every member is held; any key without history keeps it `public` (ADR 0275).
|
|
10116
|
+
*/
|
|
10117
|
+
async function accountAccessForRoots(state, roots, inventory, members) {
|
|
10118
|
+
const sessions = new Map(roots.map((session) => [session.id, session]));
|
|
10119
|
+
const held = /* @__PURE__ */ new Map();
|
|
10120
|
+
for (const work of inventory.works) for (const session of work.sessions) {
|
|
10121
|
+
const access = held.get(session.key) ?? /* @__PURE__ */ new Set();
|
|
10122
|
+
access.add(work.access);
|
|
10123
|
+
held.set(session.key, access);
|
|
10124
|
+
}
|
|
10125
|
+
const result = /* @__PURE__ */ new Map();
|
|
10126
|
+
for (const work of state.works) {
|
|
10127
|
+
const access = /* @__PURE__ */ new Set();
|
|
10128
|
+
let known = 0;
|
|
10129
|
+
let unknown = 0;
|
|
10130
|
+
for (const id of work.rootSessionIds) {
|
|
10131
|
+
const root = sessions.get(id);
|
|
10132
|
+
if (!root) throw new ApplicationError("CORRUPTED_STATE");
|
|
10133
|
+
for (const session of members.get(id) ?? [root]) for (const [key, legacyKey] of await keysOf(session)) {
|
|
10134
|
+
const values = /* @__PURE__ */ new Set([...held.get(key) ?? [], ...held.get(legacyKey) ?? []]);
|
|
10135
|
+
if (!values.size) {
|
|
10136
|
+
unknown++;
|
|
10137
|
+
continue;
|
|
10138
|
+
}
|
|
10139
|
+
known++;
|
|
10140
|
+
for (const value of values) access.add(value);
|
|
10141
|
+
}
|
|
10142
|
+
}
|
|
10143
|
+
if (!known) continue;
|
|
10144
|
+
const uniform = access.size === 1;
|
|
10145
|
+
result.set(work.id, uniform && access.has("private") ? "private" : uniform && access.has("public") ? unknown === 0 ? "public-all" : "public" : "mixed");
|
|
10146
|
+
}
|
|
10147
|
+
return result;
|
|
10148
|
+
}
|
|
10149
|
+
/** Existing authenticated owner ports supply inventory; signed-out scope confirmation stays local. */
|
|
10150
|
+
function createAccountAccess(storage, auth) {
|
|
10151
|
+
return async (state, signal) => {
|
|
10152
|
+
const controller = new AbortController();
|
|
10153
|
+
const boundedSignal = AbortSignal.any([signal, controller.signal]);
|
|
10154
|
+
let timer;
|
|
10155
|
+
let onAbort = () => {};
|
|
10156
|
+
const stopped = new Promise((_resolve, reject) => {
|
|
10157
|
+
onAbort = () => reject(/* @__PURE__ */ new Error("ACCOUNT_ACCESS_CANCELLED"));
|
|
10158
|
+
boundedSignal.addEventListener("abort", onAbort, { once: true });
|
|
10159
|
+
if (boundedSignal.aborted) onAbort();
|
|
10160
|
+
timer = setTimeout(() => controller.abort(), 5e3);
|
|
10161
|
+
});
|
|
10162
|
+
const read = async () => {
|
|
10163
|
+
boundedSignal.throwIfAborted();
|
|
10164
|
+
const connection = await auth.connect(boundedSignal);
|
|
10165
|
+
if (!connection?.sessions) return /* @__PURE__ */ new Map();
|
|
10166
|
+
const plan = (await storage.resources({
|
|
10167
|
+
journeyId: state.journeyId,
|
|
10168
|
+
kind: "plan"
|
|
10169
|
+
}))[0];
|
|
10170
|
+
if (plan?.kind !== "plan") throw new ApplicationError("SCOPE_NOT_READY");
|
|
10171
|
+
const inventory = await connection.sessions.inventory(boundedSignal);
|
|
10172
|
+
const access = await accountAccessForRoots(state, plan.approval.inventory.sessions, inventory, reviewFamilies(plan.approval.inventory).members);
|
|
10173
|
+
await connection.assertCurrent(boundedSignal);
|
|
10174
|
+
return access;
|
|
10175
|
+
};
|
|
10176
|
+
try {
|
|
10177
|
+
return await Promise.race([read(), stopped]);
|
|
10178
|
+
} catch {
|
|
10179
|
+
console.error("ACCOUNT_ACCESS_UNAVAILABLE: using model access");
|
|
10180
|
+
return /* @__PURE__ */ new Map();
|
|
10181
|
+
} finally {
|
|
10182
|
+
clearTimeout(timer);
|
|
10183
|
+
boundedSignal.removeEventListener("abort", onAbort);
|
|
10184
|
+
controller.abort();
|
|
10185
|
+
}
|
|
10186
|
+
};
|
|
10187
|
+
}
|
|
10188
|
+
//#endregion
|
|
9863
10189
|
//#region apps/cli/src/operation/protocol.ts
|
|
9864
10190
|
const sourceExclusionReasonSchema = z.enum([
|
|
9865
10191
|
"guardian-excluded",
|
|
@@ -10455,6 +10781,9 @@ async function readJson(response, where) {
|
|
|
10455
10781
|
}
|
|
10456
10782
|
chunks.push(next.value);
|
|
10457
10783
|
}
|
|
10784
|
+
} catch (error) {
|
|
10785
|
+
if (error instanceof ApplicationError) throw error;
|
|
10786
|
+
throw unavailable(`${where} body read failed`, error);
|
|
10458
10787
|
} finally {
|
|
10459
10788
|
reader.releaseLock();
|
|
10460
10789
|
}
|
|
@@ -11489,6 +11818,8 @@ async function compose(options, callbacks, bundles) {
|
|
|
11489
11818
|
onFatal: fatalStore.fail
|
|
11490
11819
|
});
|
|
11491
11820
|
const account = createAccount(accountPorts);
|
|
11821
|
+
const sendAuth = createJourneySendAuth(accountPorts);
|
|
11822
|
+
const accountAccess = createAccountAccess(journeyStorage, sendAuth);
|
|
11492
11823
|
const application = createApplication({
|
|
11493
11824
|
sessionPeriod: options.sessionPeriod,
|
|
11494
11825
|
journeySender: createJourneySender({
|
|
@@ -11505,7 +11836,7 @@ async function compose(options, callbacks, bundles) {
|
|
|
11505
11836
|
}
|
|
11506
11837
|
}),
|
|
11507
11838
|
artifacts: createJourneySendArtifacts(journeyStorage),
|
|
11508
|
-
auth:
|
|
11839
|
+
auth: sendAuth,
|
|
11509
11840
|
now: () => (/* @__PURE__ */ new Date()).toISOString(),
|
|
11510
11841
|
failure: (code, cause) => diagnostics.onFailure(code, cause),
|
|
11511
11842
|
sessionTransfer: (workId, transfer) => diagnostics.onActivity({
|
|
@@ -11528,18 +11859,22 @@ async function compose(options, callbacks, bundles) {
|
|
|
11528
11859
|
phases: { upload: elapsedMs },
|
|
11529
11860
|
volumes: { bytes }
|
|
11530
11861
|
})
|
|
11531
|
-
}, void 0, sendHost
|
|
11862
|
+
}, void 0, sendHost.serving ? sendHost : {
|
|
11863
|
+
...sendHost,
|
|
11864
|
+
focused: (journeyId) => focusedHostAlive(stateDir, journeyId, async () => (await journeyStorage.current())?.journeyId)
|
|
11865
|
+
}),
|
|
11532
11866
|
manualUploader: createManualUploader({
|
|
11533
11867
|
storage: store.manualUpload,
|
|
11534
11868
|
artifacts: createManualUploadArtifacts({ getDeliverySources: () => application.getDeliverySources() }),
|
|
11535
|
-
auth:
|
|
11869
|
+
auth: sendAuth,
|
|
11536
11870
|
now: () => (/* @__PURE__ */ new Date()).toISOString(),
|
|
11537
11871
|
failure: (code, cause) => diagnostics.onFailure(code, cause)
|
|
11538
11872
|
}),
|
|
11539
11873
|
journeyLocal: {
|
|
11874
|
+
accountAccess,
|
|
11540
11875
|
titles: createJourneyTitles(journeyStorage, processing),
|
|
11541
11876
|
describe: createJourneyDescription(journeyStorage, processing),
|
|
11542
|
-
works: createJourneyWorks(journeyStorage, processing, stateDir),
|
|
11877
|
+
works: createJourneyWorks(journeyStorage, processing, stateDir, accountAccess),
|
|
11543
11878
|
hide: createJourneyHide({
|
|
11544
11879
|
storage: journeyStorage,
|
|
11545
11880
|
execution,
|
|
@@ -12008,4 +12343,4 @@ async function cancelOperation(runtime, id) {
|
|
|
12008
12343
|
return readOperation(runtime, id);
|
|
12009
12344
|
}
|
|
12010
12345
|
//#endregion
|
|
12011
|
-
export {
|
|
12346
|
+
export { longCommands as _, readAgentPresence as a, traceStartup as b, executorRequestSchema as c, serveDetached as d, guardDetachedStartup as f, businessCommands as g, parseOptions as h, invoke as i, awaitingPassport as l, helpText as m, readOperation as n, createRuntime as o, createRenderActivity as p, waitOperation as r, executorEventSchema as s, cancelOperation as t, hostDrives as u, permissionDiagnostic as v, startupFailure as y };
|