@gitroll/tacitt-cli 0.6.11 → 0.6.13
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 +4 -0
- package/bin/INDEX.md +6 -4
- package/bin/tacitt.cjs +1 -0
- package/dist/{agent-setup-DdfF3zch.mjs → agent-setup-Doy_AnPY.mjs} +2 -2
- package/dist/agent-setup-worker.mjs +5 -5
- package/dist/cli.mjs +32 -32
- package/dist/codex-title-worker.mjs +2 -2
- package/dist/configured-preview-worker.mjs +5 -5
- package/dist/configured-session-worker.mjs +23 -25
- package/dist/{frame-Bq2zRh-i.mjs → frame-BPbypzmt.mjs} +1 -1
- package/dist/{heap-CV8Eca8V.mjs → heap-DCS_WXIA.mjs} +264 -23
- package/dist/inspection-worker.mjs +4 -4
- package/dist/{job-BKsifhyv.mjs → job--zxwgaPy.mjs} +155 -41
- package/dist/{locate-Cx52Zqxv.mjs → locate-PLEyLYW-.mjs} +292 -236
- package/dist/{model-C1UXkHh9.mjs → model-CyXvsWLz.mjs} +1 -1
- package/dist/operation-executor.mjs +3 -3
- package/dist/preview-worker.mjs +1 -1
- package/dist/privacy-validator.mjs +28 -8
- package/dist/{query-AMZerUh8.mjs → query-BC7MIaWc.mjs} +1914 -759
- package/dist/{run-CaPktPhH.mjs → run-Dod7Vykp.mjs} +6 -6
- package/dist/session-process.mjs +20 -0
- package/dist/{src-DlVbGB32.mjs → src-CP-K2PBv.mjs} +2100 -1649
- package/dist/{src-D1iONla3.mjs → src-CttNuxOn.mjs} +925 -630
- package/dist/{src-wZx_v0Ih.mjs → src-dL6y2mcu.mjs} +180 -30
- package/dist/store-database-worker.mjs +1 -1
- package/dist/web/assets/index-BgDdPL1c.js +172 -0
- package/dist/web/index.html +2 -1
- package/package.json +2 -1
- package/skills/INDEX.md +6 -4
- package/skills/tacitt/INDEX.md +7 -6
- package/skills/tacitt/SKILL.md +7 -7
- package/skills/tacitt/references/INDEX.md +14 -11
- package/skills/tacitt/references/b-method.md +6 -4
- package/skills/tacitt/references/bootstrap.md +18 -4
- package/skills/tacitt/references/classification.md +1 -1
- package/skills/tacitt/references/commands.md +34 -10
- package/skills/tacitt/references/journey.md +7 -7
- package/skills/tacitt/references/parallel-review.md +31 -12
- package/skills/tacitt/references/remote-workers.md +6 -2
- package/skills/tacitt/references/send.md +7 -3
- package/skills/tacitt/scripts/INDEX.md +40 -37
- package/skills/tacitt/scripts/answer.mjs +31 -2
- package/skills/tacitt/scripts/describe.mjs +3 -2
- package/skills/tacitt/scripts/journey-card-consolidation.mjs +1 -1
- package/skills/tacitt/scripts/journey-classification-tasks.mjs +28 -8
- package/skills/tacitt/scripts/journey-classification.mjs +1 -0
- package/skills/tacitt/scripts/journey-panel-host.d.mts +2 -0
- package/skills/tacitt/scripts/journey-panel-host.mjs +25 -2
- package/skills/tacitt/scripts/journey-scan-timing.d.mts +4 -0
- package/skills/tacitt/scripts/journey-scan-timing.mjs +15 -2
- package/skills/tacitt/scripts/journey-state.mjs +11 -0
- package/skills/tacitt/scripts/journey-tasks.mjs +12 -5
- package/skills/tacitt/scripts/journey.mjs +11 -3
- package/skills/tacitt/scripts/privacy-validator.mjs +112 -40
- package/skills/tacitt/scripts/review.d.mts +1 -0
- package/skills/tacitt/scripts/review.mjs +680 -119
- package/dist/web/assets/index-CYl7eDUu.js +0 -172
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { $ as validateDetectionSummary, $t as
|
|
1
|
+
import { C as writePrivateReviewPayload, ct as openPrivateFile, lt as restrictToOwner, ot as exclusiveLock, ut as windowsOwnerOnly, w as readPrivateReviewPayload } from "./src-CP-K2PBv.mjs";
|
|
2
|
+
import { Bt as reviewTermsResultSchema, C as validateBReview, Ft as privacyTermSchema, It as emptyReviewCorrectionResultSchema, Lt as emptyReviewCorrectionSchema, M as semanticFindingSchema, Mn as createDetectionSummary, Rt as journeyTermSchema, St as journeyWorkSuggestionSchema, Wt as termTypeSchema, b as validateReviewAlignment, c as reviewBatchSchema, cr as isStaticCategory, d as reviewSubmitSchema, dt as journeyIdSchema, f as textDigest, gt as nativeJourneySchema, h as reviewAlignmentAudit, hn as fileIdentitySchema, in as ApplicationError, ln as familySelected, lr as staticCategories, lt as journeyDigestSchema, m as findingReferenceKey, p as validateReview, s as reviewBatchChunks, u as reviewDigest, un as reviewFamilies, v as reviewAlignmentSchema, vt as journeyGuidanceSchema, x as bContextEvidence, xt as journeyDescribeSchema, zt as reviewTermsInputSchema } from "./locate-PLEyLYW-.mjs";
|
|
3
|
+
import { $ as validateDetectionSummary, $t as journeyPlaceSchema, At as validateAttemptAppend, Bn as journeySearchSaveSchema, Bt as newJourneyWork, Cn as scanAliasResourceSchema, Dn as scanGitSeedsId, En as scanSessionResourceSchema, Fn as journeyInventoryReadSchema, Ft as classificationCommitSchema, Gr as staticSessionId, Gt as hideFinishSchema, Hn as journeyCommitResultSchema, Hr as mergePrivacyTerms, Ht as journeyContextQuerySchema, In as journeyInventorySchema, Ir as obsoleteJourney, J as validateInspectionFence, Jt as sendOutputQuerySchema, Kn as confirmedHideDeltaSchema, Kt as hidePublishSchema, Ln as journeyPreparationProgressSchema, Lr as sendOwesPassport, Mi as stateSchema, Mt as journeyBatchReadSchema, Nn as projectPreparationProgress, Nt as journeyReviewStorageQuerySchema, Ot as settleCorrections, Pt as applyClassificationProposal, Q as validateInspectionContribution, Qt as journeyIsolateSchema, Rr as sendReachedPassport, Si as bMaskedHits, Sr as assertJourneyPrivacyReady, U as validateInspectionBatch, Un as journeyCommitSchema, Ut as journeyContextSchema, Vn as searchScopeDigest, W as validateInspectionBatches, Wn as journeyEventSchema, Wt as hideBeginSchema, X as validateInspectionInputs, Xr as journeySendSchema, Xt as journeyResourceQuerySchema, Y as validateInspectionHead, Yn as settleConfirmedHides, Yt as sendOutputSchema, Z as validateInspectionQuery, Zt as journeyResourceSchema, an as sessionReconcileResultSchema, bn as bReviewDigest, c as reconstructBFields, ci as isSkippedWork, cn as sessionRereadResourceSchema, cr as preparationSettlementSchema, d as resolveGroupSplit, di as withReadingProgress, dn as sessionReviewResourceSchema, dr as preparationUpdateSchema, en as sortingApplySchema, et as inspectionInputs, fi as confirmedHideGroupIds, fn as sessionReviewStatusSchema, fr as validatePreparationFacts, g as semanticGroupKey, gi as dictionaryHides, gn as reviewCandidateResourceSchema, gt as manualUploadSchema, h as hideScopeDigest, hi as confirmedHideTerms, jn as validateScanExclusion, jt as journeyGuidance, kt as attemptBudgetCodePoints, l as chooseCheapPlacement, li as selectedWorks, lr as preparationStartSchema, mn as sessionUsefulnessResourceSchema, nn as reviewAttemptsQuerySchema, nr as workDecisionDigest, o as bRereadDigest, oi as isReadingComplete, on as sessionReconciliationResourceSchema, or as preparationBeginSchema, pi as confirmedHideKey, pn as sessionUsefulnessInputSchema, pt as manualUploadBindingSchema, q as validateInspectionClaim, qt as journeyPolicyRespondSchema, ri as hasCompleteWorkDescription, rn as reviewAttemptsResultSchema, rr as workPrivacyDecisions, s as reconcileBSession, si as isSelectedWork, sr as preparationPermissionSchema, t as scanBatchContextDigest, ti as sendSessionUploadSchema, tn as reviewAttemptResourceSchema, tr as retireWorkDescription, u as reviseGroupMembership, un as sessionReviewQuerySchema, ur as preparationStateSchema, v as projectJourneyInventory, vi as maskedHitsStale, vn as reviewRepairResourceSchema, vt as candidateSortAvailable, wn as scanCanonicalResourceSchema, wr as reconcileReaderKeeps, x as bReviewScope, xn as mergeBRepair, xr as applyCardAnswers, y as preparationScope, yi as syncTermGroups, zn as journeySearchResultSchema, zt as isolatedWorkId } from "./src-CttNuxOn.mjs";
|
|
4
4
|
import { constants } from "node:fs";
|
|
5
5
|
import { z } from "zod";
|
|
6
6
|
import { copyFile, link, lstat, mkdir, mkdtemp, open, readFile, realpath, rm, unlink } from "node:fs/promises";
|
|
@@ -346,9 +346,26 @@ function readJourney(db, journeyId) {
|
|
|
346
346
|
if (typeof text !== "string") throw new ApplicationError("CORRUPTED_STATE");
|
|
347
347
|
const state = JSON.parse(text);
|
|
348
348
|
if (typeof state === "object" && state !== null && "formatVersion" in state && state.formatVersion !== 10) throw new StoreError("OBSOLETE_SCHEMA", "Stored native Journey state uses an obsolete candidate format and has been preserved.");
|
|
349
|
+
let value = reconcileReaderKeeps(nativeJourneySchema.parse(state));
|
|
350
|
+
if (value.outputVersion !== void 0 && value.outputVersion > 1) throw new StoreError("OBSOLETE_SCHEMA", "This journey requires a newer final writer.");
|
|
351
|
+
if (value.outputVersion !== 1 && value.phase !== "completed" && !obsoleteJourney(value)) value = {
|
|
352
|
+
...value,
|
|
353
|
+
outputVersion: 1,
|
|
354
|
+
phase: value.phase === "ready" ? "review" : value.phase,
|
|
355
|
+
privacy: {
|
|
356
|
+
...value.privacy,
|
|
357
|
+
packageApproval: null
|
|
358
|
+
},
|
|
359
|
+
works: value.works.map((work) => ({
|
|
360
|
+
...work,
|
|
361
|
+
revision: work.revision + 1,
|
|
362
|
+
status: work.status === "ready" ? "review" : work.status,
|
|
363
|
+
artifact: null
|
|
364
|
+
}))
|
|
365
|
+
};
|
|
349
366
|
return {
|
|
350
367
|
text,
|
|
351
|
-
value
|
|
368
|
+
value
|
|
352
369
|
};
|
|
353
370
|
});
|
|
354
371
|
}
|
|
@@ -362,23 +379,29 @@ function insertCorrectionReport(db, resource) {
|
|
|
362
379
|
}
|
|
363
380
|
db.prepare("INSERT INTO journey_resources VALUES(?,?,?,?)").run(resource.journeyId, resource.kind, resource.id, json);
|
|
364
381
|
}
|
|
365
|
-
/**
|
|
366
|
-
* A snapshot of an earlier release cannot render, so a new Journey may replace it, but never
|
|
367
|
-
* one with a Send record or a sent Work: that Send stays for the person to finish.
|
|
368
|
-
*/
|
|
369
|
-
/** A receipt or persisted session mutation intent means a Send may have reached Passport. */
|
|
382
|
+
/** Whether any Send of this Journey may have reached Passport (`sendReachedPassport`). */
|
|
370
383
|
function reachedPassport(db, journeyId) {
|
|
371
384
|
return db.prepare("SELECT json FROM journey_sends WHERE journey_id=?").all(journeyId).some((row) => {
|
|
372
385
|
if (typeof row["json"] !== "string") throw new ApplicationError("CORRUPTED_STATE");
|
|
373
|
-
return journeySendSchema.parse(JSON.parse(row["json"]))
|
|
386
|
+
return sendReachedPassport(journeySendSchema.parse(JSON.parse(row["json"])));
|
|
374
387
|
});
|
|
375
388
|
}
|
|
376
389
|
/** An abandoned Journey gives way to a new one unless one of its Sends reached Passport. */
|
|
377
390
|
function abandoned(db, current) {
|
|
378
391
|
return current.abandonedAt !== void 0 && !reachedPassport(db, current.journeyId);
|
|
379
392
|
}
|
|
393
|
+
/**
|
|
394
|
+
* A snapshot of an earlier release cannot render, so a new Journey replaces it unless its current
|
|
395
|
+
* Send still owes Passport something its next advance sends without the person
|
|
396
|
+
* (`sendOwesPassport`, ADR 0284, owner answer A): sent Works stay on Passport, and the new Journey
|
|
397
|
+
* reads every Work again. Replacement cancels its unfinished Sends.
|
|
398
|
+
*/
|
|
380
399
|
function replaceable(db, current) {
|
|
381
|
-
|
|
400
|
+
if (!obsoleteJourney(current)) return false;
|
|
401
|
+
const row = db.prepare("SELECT json FROM journey_sends JOIN journey_current_send ON journey_sends.id=journey_current_send.send_id WHERE journey_current_send.journey_id=?").get(current.journeyId);
|
|
402
|
+
if (!row) return true;
|
|
403
|
+
if (typeof row["json"] !== "string") throw new ApplicationError("CORRUPTED_STATE");
|
|
404
|
+
return !sendOwesPassport(current, journeySendSchema.parse(JSON.parse(row["json"])));
|
|
382
405
|
}
|
|
383
406
|
/** An addition counts only when one of its findings was assigned to a confirmed Hide category. */
|
|
384
407
|
function joinedHideValues(db, state, delta) {
|
|
@@ -439,6 +462,7 @@ function commitJourney(db, input) {
|
|
|
439
462
|
...input,
|
|
440
463
|
state: {
|
|
441
464
|
...input.state,
|
|
465
|
+
outputVersion: 1,
|
|
442
466
|
privacy: {
|
|
443
467
|
...input.state.privacy,
|
|
444
468
|
rememberedRules
|
|
@@ -453,6 +477,7 @@ function commitJourney(db, input) {
|
|
|
453
477
|
state: current
|
|
454
478
|
};
|
|
455
479
|
}
|
|
480
|
+
if (input.expectedRevision === null && current && replaceable(db, current)) db.prepare("DELETE FROM journey_current_send WHERE journey_id=?").run(current.journeyId);
|
|
456
481
|
if (input.state.journeyId !== input.event.journeyId) throw new ApplicationError("INVALID_ARGUMENTS");
|
|
457
482
|
if (input.closedReader) {
|
|
458
483
|
const hold = input.closedReader;
|
|
@@ -2578,6 +2603,7 @@ function selectTerms(db, query) {
|
|
|
2578
2603
|
if (!source || source["review_ref_json"] === null) throw new ApplicationError("SCOPE_NOT_READY");
|
|
2579
2604
|
}
|
|
2580
2605
|
const work = requireActiveBatch(state, batch.header);
|
|
2606
|
+
if (work.access === "drop") throw new ApplicationError("REVISION_CONFLICT");
|
|
2581
2607
|
if (work.reviewInterruptions?.some((hold) => hold.inputRevision === work.inputRevision && hold.batchIds.includes(unit.batchId)) || db.prepare("SELECT 1 FROM journey_resources WHERE journey_id=? AND kind='closed-reader' AND id=?").get(state.journeyId, unit.batchId + ":" + input.packId)) throw new ApplicationError("REVISION_CONFLICT");
|
|
2582
2608
|
if (batch.header.digest !== unit.batchDigest) throw new ApplicationError("REVISION_CONFLICT");
|
|
2583
2609
|
return batch;
|
|
@@ -2640,6 +2666,10 @@ function finishTerms(db, packet) {
|
|
|
2640
2666
|
count: term.count - previous
|
|
2641
2667
|
})) added++;
|
|
2642
2668
|
}
|
|
2669
|
+
for (const term of packet.located) if (upsertJourneyTerm(db, state.journeyId, {
|
|
2670
|
+
...term,
|
|
2671
|
+
count: 0
|
|
2672
|
+
})) added++;
|
|
2643
2673
|
const groups = syncTermGroups(state, readTermCounts(db, state.journeyId), (key) => findingPreference(db, key));
|
|
2644
2674
|
const reference = {
|
|
2645
2675
|
kind: "term-pack",
|
|
@@ -3853,9 +3883,9 @@ function activeScope(db, input, starting) {
|
|
|
3853
3883
|
if (state.pendingHideId) throw new ApplicationError("SCOPE_NOT_READY");
|
|
3854
3884
|
const work = state.works.find((item) => item.id === input.workId);
|
|
3855
3885
|
if (!work || input.inputRevision !== work.inputRevision || input.snapshotId !== state.snapshotId) throw new ApplicationError("REVISION_CONFLICT");
|
|
3856
|
-
const plan =
|
|
3886
|
+
const { plan, families } = readInventoryFamilies(db, state);
|
|
3857
3887
|
if (!plan.approval.inventory.complete) throw new ApplicationError("CORRUPTED_STATE");
|
|
3858
|
-
return preparationScope(plan.approval.inventory, work);
|
|
3888
|
+
return preparationScope(plan.approval.inventory, work, families);
|
|
3859
3889
|
}
|
|
3860
3890
|
function insert(db, record) {
|
|
3861
3891
|
db.prepare("INSERT INTO journey_resources VALUES(?,?,?,?)").run(record.journeyId, record.kind, record.id, JSON.stringify(record));
|
|
@@ -3926,7 +3956,16 @@ function readJourneyPreparationProgress(db, input) {
|
|
|
3926
3956
|
const state = readFencedJourney(db, input);
|
|
3927
3957
|
if (!state.consent || !state.snapshotId) return null;
|
|
3928
3958
|
const { starts, settlements } = readPreparationReceipts(db, state.journeyId);
|
|
3929
|
-
|
|
3959
|
+
const captures = db.prepare(`SELECT id, json_extract(json,'$.capture.partId') AS partId,
|
|
3960
|
+
json_extract(json,'$.capture.facts.byteLength') AS bytes FROM journey_resources
|
|
3961
|
+
WHERE journey_id=? AND kind='capture'`).all(state.journeyId).map(({ id, partId, bytes }) => {
|
|
3962
|
+
if (id !== partId || typeof partId !== "string" || typeof bytes !== "number" || !Number.isSafeInteger(bytes) || bytes < 0) throw new ApplicationError("CORRUPTED_STATE");
|
|
3963
|
+
return {
|
|
3964
|
+
partId,
|
|
3965
|
+
bytes
|
|
3966
|
+
};
|
|
3967
|
+
});
|
|
3968
|
+
return projectPreparationProgress(state, readInventoryFamilies(db, state).families, captures, starts, settlements);
|
|
3930
3969
|
}
|
|
3931
3970
|
//#endregion
|
|
3932
3971
|
//#region packages/local-host/src/store/journey/hide.ts
|
|
@@ -4732,14 +4771,6 @@ function finishJourneyPlacement(db, packet) {
|
|
|
4732
4771
|
//#endregion
|
|
4733
4772
|
//#region packages/local-host/src/store/journey/isolation.ts
|
|
4734
4773
|
const reason = " – couldn't prepare";
|
|
4735
|
-
/** Stable blocked Work IDs per parent, so later failing roots join one instead of multiplying. */
|
|
4736
|
-
function isolatedWorkId(parentId, ordinal) {
|
|
4737
|
-
const bytes = createHash("sha256").update(`isolated-roots:${parentId}:${ordinal}`).digest().subarray(0, 16);
|
|
4738
|
-
bytes[6] = (bytes[6] ?? 0) & 15 | 64;
|
|
4739
|
-
bytes[8] = (bytes[8] ?? 0) & 63 | 128;
|
|
4740
|
-
const hex = bytes.toString("hex");
|
|
4741
|
-
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
4742
|
-
}
|
|
4743
4774
|
/**
|
|
4744
4775
|
* Moves identified failing roots out of a pending multi-root Work into its visible blocked
|
|
4745
4776
|
* Work, carrying their public-safe codes; the parent returns to pending for the rest.
|
|
@@ -4783,8 +4814,15 @@ function isolateJourneyRoots(db, input) {
|
|
|
4783
4814
|
})),
|
|
4784
4815
|
blocks: /* @__PURE__ */ new Map([[targetId, [...codes]]])
|
|
4785
4816
|
});
|
|
4817
|
+
const classified = !existing && parent.classificationRecommendation && hasCompleteWorkDescription(parent) && !parent.suggestion ? {
|
|
4818
|
+
description: parent.description,
|
|
4819
|
+
classificationRecommendation: parent.classificationRecommendation,
|
|
4820
|
+
reason: parent.classificationRecommendation.reason,
|
|
4821
|
+
projectType: parent.projectType?.origin === "model" ? parent.projectType : null
|
|
4822
|
+
} : {};
|
|
4786
4823
|
const works = next.works.map((work) => work.id === targetId ? {
|
|
4787
4824
|
...work,
|
|
4825
|
+
...classified,
|
|
4788
4826
|
...access
|
|
4789
4827
|
} : work);
|
|
4790
4828
|
return commitJourney(db, commit(input, {
|
|
@@ -4912,9 +4950,197 @@ function finishJourneyDescription(db, packet) {
|
|
|
4912
4950
|
}
|
|
4913
4951
|
//#endregion
|
|
4914
4952
|
//#region packages/local-host/src/store/journey/send.ts
|
|
4953
|
+
/** Run the privacy fence against the store's current immutable row on every request.
|
|
4954
|
+
* Only the approved output and this Work's frozen upload identities cross the worker boundary. */
|
|
4955
|
+
function readSendOutput(db, input) {
|
|
4956
|
+
const { journeyId, workId, revision } = input;
|
|
4957
|
+
const state = readJourney(db, journeyId);
|
|
4958
|
+
if (!state?.consent) throw new ApplicationError("CONFIRMATION_REQUIRED");
|
|
4959
|
+
if (state.phase === "completed" && state.outputVersion !== 1) throw new ApplicationError("SCOPE_NOT_READY");
|
|
4960
|
+
assertJourneyPrivacyReady(state, true);
|
|
4961
|
+
if (state.phase === "paused") throw new ApplicationError("OPERATION_CANCELED");
|
|
4962
|
+
const work = state.works.find((item) => item.id === workId);
|
|
4963
|
+
if (!work?.artifact || work.revision !== revision || work.artifact.revision !== revision) throw new ApplicationError("REVISION_CONFLICT");
|
|
4964
|
+
const [output] = readJourneyResources(db, {
|
|
4965
|
+
journeyId,
|
|
4966
|
+
kind: "output",
|
|
4967
|
+
id: `${workId}:${revision}`
|
|
4968
|
+
});
|
|
4969
|
+
if (output?.kind !== "output" || output.workId !== workId || output.revision !== revision || output.primary.sha256 !== work.artifact.sha256) throw new ApplicationError("ARTIFACT_IDENTITY_MISMATCH");
|
|
4970
|
+
if (!input.sessions) return {
|
|
4971
|
+
output,
|
|
4972
|
+
identities: []
|
|
4973
|
+
};
|
|
4974
|
+
const [base] = readJourneyResources(db, {
|
|
4975
|
+
journeyId,
|
|
4976
|
+
kind: "base",
|
|
4977
|
+
id: `${workId}:${output.finalMaskLedger.inputRevision}`
|
|
4978
|
+
});
|
|
4979
|
+
if (base?.kind !== "base" || base.workId !== workId || base.inputRevision !== output.finalMaskLedger.inputRevision || base.primary.sha256 !== output.finalMaskLedger.basePrimarySha256) throw new ApplicationError("ARTIFACT_IDENTITY_MISMATCH");
|
|
4980
|
+
const plan = readInventoryPlan(db, state);
|
|
4981
|
+
const sessions = new Map(plan.approval.inventory.sessions.map((session) => [session.id, session]));
|
|
4982
|
+
const groups = /* @__PURE__ */ new Map();
|
|
4983
|
+
const identities = base.sessions.map((binding) => {
|
|
4984
|
+
const session = sessions.get(binding.applicationSessionId);
|
|
4985
|
+
const part = session?.parts[0];
|
|
4986
|
+
const lastAt = session?.lastInteractionAt ?? session?.createdAt;
|
|
4987
|
+
if (!session || !part || !lastAt || !Number.isFinite(Date.parse(lastAt))) throw new ApplicationError("ARTIFACT_IDENTITY_MISMATCH");
|
|
4988
|
+
const native = part.nativeEvidence?.identity;
|
|
4989
|
+
if (native?.sessionId?.trim() && native.role !== "unknown" && (native.role !== "worker" || native.agentId?.trim() && session.harness === "claude")) {
|
|
4990
|
+
const key = JSON.stringify([
|
|
4991
|
+
session.harness,
|
|
4992
|
+
native.sessionId,
|
|
4993
|
+
native.role === "worker" ? native.agentId : null
|
|
4994
|
+
]);
|
|
4995
|
+
const group = groups.get(key) ?? [];
|
|
4996
|
+
group.push(binding.archiveSessionId);
|
|
4997
|
+
groups.set(key, group);
|
|
4998
|
+
}
|
|
4999
|
+
const nativeId = part.nativeEvidence?.identity?.sessionId ?? session.sourceSessionId;
|
|
5000
|
+
const path = part.harnessRelativePath ?? "";
|
|
5001
|
+
if (!path && !nativeId?.trim() || isAbsolute(path) || path.includes("\\") || path.split("/").some((segment) => segment === ".." || segment === ".")) throw new ApplicationError("ARTIFACT_IDENTITY_MISMATCH");
|
|
5002
|
+
return {
|
|
5003
|
+
archiveSessionId: binding.archiveSessionId,
|
|
5004
|
+
relativePath: path,
|
|
5005
|
+
lastAt: new Date(lastAt).toISOString()
|
|
5006
|
+
};
|
|
5007
|
+
});
|
|
5008
|
+
const duplicates = [...groups.values()].filter((group) => group.length > 1);
|
|
5009
|
+
if (!duplicates.length) return {
|
|
5010
|
+
output,
|
|
5011
|
+
identities
|
|
5012
|
+
};
|
|
5013
|
+
const duplicateIds = new Set(duplicates.flat());
|
|
5014
|
+
const owners = new Map(base.sessions.map((s) => [s.archiveSessionId, s.applicationSessionId]));
|
|
5015
|
+
const sources = base.sourceBindings.flatMap((binding) => {
|
|
5016
|
+
if (!duplicateIds.has(binding.sessionId) || binding.bundleId !== base.bundleId || owners.get(binding.sessionId) !== binding.applicationSessionId) return [];
|
|
5017
|
+
const part = sessions.get(binding.applicationSessionId)?.parts.find((p) => p.id === binding.sourcePartId);
|
|
5018
|
+
return part ? [{
|
|
5019
|
+
session: binding.sessionId,
|
|
5020
|
+
source: binding.bundleSourceId,
|
|
5021
|
+
part
|
|
5022
|
+
}] : [];
|
|
5023
|
+
});
|
|
5024
|
+
const outputs = state.works.filter(isSelectedWork).flatMap((w) => w.artifact ? [{
|
|
5025
|
+
workId: w.id,
|
|
5026
|
+
revision: w.revision,
|
|
5027
|
+
sha256: w.artifact.sha256,
|
|
5028
|
+
bundleId: w.artifact.bundleId
|
|
5029
|
+
}] : []);
|
|
5030
|
+
const approval = state.privacy.packageApproval;
|
|
5031
|
+
if (!approval) throw new ApplicationError("CONFIRMATION_REQUIRED");
|
|
5032
|
+
return {
|
|
5033
|
+
output,
|
|
5034
|
+
identities,
|
|
5035
|
+
extension: {
|
|
5036
|
+
groups: duplicates,
|
|
5037
|
+
sources,
|
|
5038
|
+
outputs,
|
|
5039
|
+
approval
|
|
5040
|
+
}
|
|
5041
|
+
};
|
|
5042
|
+
}
|
|
5043
|
+
const sendCurrentSchema = z.object({
|
|
5044
|
+
journeyId: journeyIdSchema,
|
|
5045
|
+
sendId: journeyIdSchema,
|
|
5046
|
+
revision: z.number().int().nonnegative()
|
|
5047
|
+
}).strict();
|
|
5048
|
+
function isCurrentSend(db, input) {
|
|
5049
|
+
return !!db.prepare(`SELECT 1 FROM journey_runs r JOIN journey_current_send s ON s.journey_id=r.id
|
|
5050
|
+
JOIN journey_current c ON c.journey_id=r.id AND c.singleton=1
|
|
5051
|
+
WHERE r.id=? AND r.revision=? AND s.send_id=?`).get(input.journeyId, input.revision, input.sendId);
|
|
5052
|
+
}
|
|
5053
|
+
const transferCountSchema = z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
|
|
5054
|
+
const sendTransferSchema = z.object({
|
|
5055
|
+
journeyId: journeyIdSchema,
|
|
5056
|
+
sendId: journeyIdSchema,
|
|
5057
|
+
workId: journeyIdSchema,
|
|
5058
|
+
expectedJourneyRevision: transferCountSchema,
|
|
5059
|
+
expectedSendRevision: transferCountSchema,
|
|
5060
|
+
storedSessions: transferCountSchema.optional(),
|
|
5061
|
+
sessionUpload: sendSessionUploadSchema,
|
|
5062
|
+
requestKey: journeyIdSchema,
|
|
5063
|
+
at: z.iso.datetime()
|
|
5064
|
+
}).strict();
|
|
5065
|
+
const sendTransferResultSchema = z.discriminatedUnion("status", [z.object({
|
|
5066
|
+
status: z.literal("applied"),
|
|
5067
|
+
revision: transferCountSchema,
|
|
5068
|
+
lastEvent: transferCountSchema,
|
|
5069
|
+
sendRevision: transferCountSchema
|
|
5070
|
+
}).strict(), z.object({ status: z.enum(["stale", "replayed"]) }).strict()]);
|
|
5071
|
+
/** Update only transfer fields in the Send document and stamp its Journey revision/event. */
|
|
5072
|
+
function checkpointJourneySendTransfer(db, input) {
|
|
5073
|
+
const requestHash = createHash("sha256").update(JSON.stringify(input)).digest("hex");
|
|
5074
|
+
const receipt = db.prepare("SELECT request_hash,journey_id FROM journey_receipts WHERE request_key=?").get(input.requestKey);
|
|
5075
|
+
if (receipt) {
|
|
5076
|
+
if (receipt["request_hash"] !== requestHash || receipt["journey_id"] !== input.journeyId) throw new ApplicationError("OPERATION_CONFLICT");
|
|
5077
|
+
return { status: "replayed" };
|
|
5078
|
+
}
|
|
5079
|
+
const row = db.prepare(`SELECT r.revision,r.state_json ->> '$.formatVersion' AS formatVersion,
|
|
5080
|
+
r.state_json ->> '$.phase' AS phase,
|
|
5081
|
+
json_type(r.state_json,'$.consent') AS consentType,
|
|
5082
|
+
r.state_json ->> '$.pendingHideId' AS pendingHideId,
|
|
5083
|
+
json_type(r.state_json,'$.abandonedAt') AS abandonedType,s.json
|
|
5084
|
+
FROM journey_runs r
|
|
5085
|
+
JOIN journey_current c ON c.singleton=1 AND c.journey_id=r.id
|
|
5086
|
+
JOIN journey_current_send cs ON cs.journey_id=r.id AND cs.send_id=?
|
|
5087
|
+
JOIN journey_sends s ON s.journey_id=r.id AND s.id=cs.send_id
|
|
5088
|
+
WHERE r.id=?`).get(input.sendId, input.journeyId);
|
|
5089
|
+
if (!row) return { status: "stale" };
|
|
5090
|
+
const revisionValue = row["revision"];
|
|
5091
|
+
if (typeof revisionValue !== "number" || !Number.isSafeInteger(revisionValue) || revisionValue < 0) throw new ApplicationError("CORRUPTED_STATE");
|
|
5092
|
+
if (revisionValue !== input.expectedJourneyRevision) return { status: "stale" };
|
|
5093
|
+
if (row["formatVersion"] !== 10) throw new StoreError("OBSOLETE_SCHEMA", "Stored native Journey state uses an obsolete candidate format and has been preserved.");
|
|
5094
|
+
if (row["consentType"] !== "object") throw new ApplicationError("CONFIRMATION_REQUIRED");
|
|
5095
|
+
if (row["phase"] !== "sending") throw new ApplicationError(row["phase"] === "paused" ? "OPERATION_CANCELED" : "INVALID_TRANSITION");
|
|
5096
|
+
if (row["pendingHideId"] !== null && row["pendingHideId"] !== void 0) throw new ApplicationError("REVISION_CONFLICT");
|
|
5097
|
+
if (row["abandonedType"] !== null && row["abandonedType"] !== void 0) throw new ApplicationError("INVALID_TRANSITION");
|
|
5098
|
+
if (typeof row["json"] !== "string") throw new ApplicationError("CORRUPTED_STATE");
|
|
5099
|
+
const send = journeySendSchema.parse(JSON.parse(row["json"]));
|
|
5100
|
+
if (send.revision !== input.expectedSendRevision) return { status: "stale" };
|
|
5101
|
+
if (!send.subject || !send.confirmedAt) throw new ApplicationError("CONFIRMATION_REQUIRED");
|
|
5102
|
+
if (send.status === "paused") throw new ApplicationError("OPERATION_CANCELED");
|
|
5103
|
+
if (!["sending", "waiting"].includes(send.status)) throw new ApplicationError("INVALID_TRANSITION");
|
|
5104
|
+
const index = send.items.findIndex((item) => item.workId === input.workId);
|
|
5105
|
+
if (index < 0) throw new ApplicationError("INVALID_SELECTION");
|
|
5106
|
+
const item = send.items[index];
|
|
5107
|
+
if (!item) throw new ApplicationError("CORRUPTED_STATE");
|
|
5108
|
+
if (item.status !== "uploading") throw new ApplicationError("INVALID_TRANSITION");
|
|
5109
|
+
const revision = revisionValue + 1;
|
|
5110
|
+
const sendRevision = send.revision + 1;
|
|
5111
|
+
const next = journeySendSchema.parse({
|
|
5112
|
+
...send,
|
|
5113
|
+
revision: sendRevision,
|
|
5114
|
+
items: send.items.map((candidate, candidateIndex) => candidateIndex === index ? {
|
|
5115
|
+
...candidate,
|
|
5116
|
+
sessionUpload: input.sessionUpload,
|
|
5117
|
+
...input.storedSessions === void 0 ? {} : { storedSessions: input.storedSessions }
|
|
5118
|
+
} : candidate)
|
|
5119
|
+
});
|
|
5120
|
+
if (db.prepare("UPDATE journey_sends SET json=? WHERE journey_id=? AND id=?").run(JSON.stringify(next), input.journeyId, input.sendId).changes !== 1) throw new ApplicationError("REVISION_CONFLICT");
|
|
5121
|
+
const inserted = db.prepare("INSERT INTO journey_events(journey_id,event_json) VALUES(?,?)").run(input.journeyId, JSON.stringify({
|
|
5122
|
+
journeyId: input.journeyId,
|
|
5123
|
+
revision,
|
|
5124
|
+
kind: "send",
|
|
5125
|
+
source: "system",
|
|
5126
|
+
at: input.at
|
|
5127
|
+
}));
|
|
5128
|
+
const lastEvent = Number(inserted.lastInsertRowid);
|
|
5129
|
+
if (!Number.isSafeInteger(lastEvent) || lastEvent < 1) throw new ApplicationError("CORRUPTED_STATE");
|
|
5130
|
+
if (db.prepare(`UPDATE journey_runs SET revision=?,state_json=json_set(
|
|
5131
|
+
state_json,'$.revision',?,'$.lastEvent',?) WHERE id=? AND revision=?`).run(revision, revision, lastEvent, input.journeyId, input.expectedJourneyRevision).changes !== 1) throw new ApplicationError("REVISION_CONFLICT");
|
|
5132
|
+
db.prepare("INSERT INTO journey_receipts VALUES(?,?,?,?)").run(input.requestKey, requestHash, input.journeyId, revision);
|
|
5133
|
+
return {
|
|
5134
|
+
status: "applied",
|
|
5135
|
+
revision,
|
|
5136
|
+
lastEvent,
|
|
5137
|
+
sendRevision
|
|
5138
|
+
};
|
|
5139
|
+
}
|
|
4915
5140
|
const sendLoadSchema = z.object({
|
|
4916
5141
|
journeyId: journeyIdSchema,
|
|
4917
|
-
sendId: journeyIdSchema.optional()
|
|
5142
|
+
sendId: journeyIdSchema.optional(),
|
|
5143
|
+
observedRevision: z.number().int().nonnegative().optional()
|
|
4918
5144
|
}).strict();
|
|
4919
5145
|
const sendSnapshotSchema = z.object({
|
|
4920
5146
|
journey: nativeJourneySchema,
|
|
@@ -4935,6 +5161,7 @@ const sendCommitResultSchema = sendSnapshotSchema.extend({ status: z.enum([
|
|
|
4935
5161
|
"stale"
|
|
4936
5162
|
]) });
|
|
4937
5163
|
function loadJourneySend(db, input) {
|
|
5164
|
+
if (input.observedRevision !== void 0 && !input.sendId && db.prepare("SELECT 1 AS same FROM journey_runs WHERE id=? AND revision=?").get(input.journeyId, input.observedRevision)) return null;
|
|
4938
5165
|
const journey = readJourney(db, input.journeyId);
|
|
4939
5166
|
if (!journey) return null;
|
|
4940
5167
|
const row = input.sendId ? db.prepare("SELECT json FROM journey_sends WHERE journey_id=? AND id=?").get(input.journeyId, input.sendId) : db.prepare("SELECT json FROM journey_sends JOIN journey_current_send ON journey_sends.id=journey_current_send.send_id WHERE journey_current_send.journey_id=?").get(input.journeyId);
|
|
@@ -4972,6 +5199,7 @@ function commitJourneySend(db, input) {
|
|
|
4972
5199
|
...input.state,
|
|
4973
5200
|
revision
|
|
4974
5201
|
});
|
|
5202
|
+
if (!prior && obsoleteJourney(current.journey)) throw new ApplicationError("JOURNEY_OBSOLETE");
|
|
4975
5203
|
const skipped = (workId) => current.journey.works.some((work) => work.id === workId && isSkippedWork(work));
|
|
4976
5204
|
const finished = send.status === "completed" && send.omitted.every((work) => [
|
|
4977
5205
|
"drop",
|
|
@@ -7058,6 +7286,9 @@ const operations = {
|
|
|
7058
7286
|
"journey.policy.respond": define(true, policyRespondSchema, respondJourneyPolicy, (value) => journeyCommitResultSchema.parse(value)),
|
|
7059
7287
|
"journey.policy.batches": define(false, policyBatchesSchema, selectPolicyBatches, (value) => z.array(z.uuid()).parse(value)),
|
|
7060
7288
|
"journey.send.load": define(false, sendLoadSchema, loadJourneySend, (value) => sendSnapshotSchema.nullable().parse(value)),
|
|
7289
|
+
"journey.send.current": define(false, sendCurrentSchema, isCurrentSend, (value) => z.boolean().parse(value)),
|
|
7290
|
+
"journey.send.transfer": define(true, sendTransferSchema, checkpointJourneySendTransfer, (value) => sendTransferResultSchema.parse(value)),
|
|
7291
|
+
"journey.send.output": define(false, sendOutputQuerySchema, readSendOutput, (value) => sendOutputSchema.parse(value)),
|
|
7061
7292
|
"journey.send.commit": define(true, sendCommitSchema, commitJourneySend, (value) => sendCommitResultSchema.parse(value)),
|
|
7062
7293
|
"manual.upload.load": define(false, manualUploadLoadSchema, loadManualUpload, (value) => manualUploadSchema.nullable().parse(value)),
|
|
7063
7294
|
"manual.upload.commit": define(true, manualUploadCommitSchema, commitManualUpload, (value) => manualUploadResultSchema.parse(value)),
|
|
@@ -7091,6 +7322,16 @@ const operations = {
|
|
|
7091
7322
|
]),
|
|
7092
7323
|
state: preparationStateSchema
|
|
7093
7324
|
}).strict().parse(value)),
|
|
7325
|
+
"journey.receipt.revision": define(false, z.object({
|
|
7326
|
+
journeyId: z.uuid(),
|
|
7327
|
+
key: z.uuid(),
|
|
7328
|
+
hash: z.string().regex(/^[0-9a-f]{64}$/u)
|
|
7329
|
+
}).strict(), (db, { journeyId, key, hash }) => {
|
|
7330
|
+
const row = db.prepare("SELECT journey_id,request_hash,revision FROM journey_receipts WHERE request_key=?").get(key);
|
|
7331
|
+
if (!row) return null;
|
|
7332
|
+
if (row["journey_id"] !== journeyId || row["request_hash"] !== hash) throw new ApplicationError("OPERATION_CONFLICT");
|
|
7333
|
+
return z.number().int().nonnegative().parse(row["revision"]);
|
|
7334
|
+
}, (value) => z.number().int().nonnegative().nullable().parse(value)),
|
|
7094
7335
|
"journey.current": define(false, z.object({ journeyId: z.uuid().optional() }), (db, input) => readJourney(db, input.journeyId), (value) => nativeJourneySchema.nullable().parse(value)),
|
|
7095
7336
|
"journey.terms.reopen-empty": define(true, emptyReviewCorrectionSchema, reopenEmptyReview, (value) => emptyReviewCorrectionResultSchema.parse(value)),
|
|
7096
7337
|
"journey.terms.select": define(false, termsQuerySchema, selectTerms, (value) => termsSelectionSchema.parse(value)),
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { l as createNativeAdapters, u as createGitNameSeedProvider } from "./src-
|
|
4
|
-
import { G as validateInspectionRequest } from "./src-
|
|
1
|
+
import { et as createInspectionProcessor } from "./src-CP-K2PBv.mjs";
|
|
2
|
+
import { Fn as createStaticProcessor } from "./locate-PLEyLYW-.mjs";
|
|
3
|
+
import { l as createNativeAdapters, u as createGitNameSeedProvider } from "./src-dL6y2mcu.mjs";
|
|
4
|
+
import { G as validateInspectionRequest } from "./src-CttNuxOn.mjs";
|
|
5
5
|
import "./messages-D3m3bhva.mjs";
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
import { parentPort, workerData } from "node:worker_threads";
|