@gitroll/tacitt-cli 0.4.1 → 0.5.0

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.
Files changed (41) hide show
  1. package/dist/{agent-setup-Cb_spmGb.mjs → agent-setup-BZbgLgHg.mjs} +2 -2
  2. package/dist/agent-setup-worker.mjs +5 -5
  3. package/dist/cli.mjs +37 -10
  4. package/dist/codex-title-worker.mjs +1 -1
  5. package/dist/configured-preview-worker.mjs +5 -5
  6. package/dist/configured-session-worker.mjs +5 -5
  7. package/dist/{frame-waS5FnN5.mjs → frame-DGun31Uc.mjs} +1 -1
  8. package/dist/{heap-eZTo0VYj.mjs → heap-NDnGBXH6.mjs} +6 -6
  9. package/dist/inspection-worker.mjs +4 -4
  10. package/dist/{job-Bi57uRU-.mjs → job-BO0a67HQ.mjs} +383 -8
  11. package/dist/{locate-U3-nkird.mjs → locate-JYtFmKu-.mjs} +120 -3
  12. package/dist/{model-BDrntocp.mjs → model-CmHypB0p.mjs} +1 -1
  13. package/dist/operation-executor.mjs +3 -3
  14. package/dist/preview-worker.mjs +1 -1
  15. package/dist/privacy-validator.mjs +1 -1
  16. package/dist/{query-7uY266qY.mjs → query-BZvNsP1u.mjs} +1272 -265
  17. package/dist/{run-CV6Io7CS.mjs → run-DvRM-NR8.mjs} +4 -4
  18. package/dist/{src-DSDRF7i6.mjs → src-C1SjCDx0.mjs} +65 -4
  19. package/dist/{src-DIuh0LHk.mjs → src-CQeUBG2Y.mjs} +168 -7
  20. package/dist/{src-BESjwh7X.mjs → src-xidy0yF7.mjs} +5 -4
  21. package/dist/store-database-worker.mjs +1 -1
  22. package/dist/web/assets/index-Bbck2aOB.css +1 -0
  23. package/dist/web/assets/index-D0j-mvf1.js +69 -0
  24. package/dist/web/index.html +2 -2
  25. package/package.json +1 -1
  26. package/skills/tacitt/SKILL.md +4 -4
  27. package/skills/tacitt/references/INDEX.md +11 -10
  28. package/skills/tacitt/references/commands.md +13 -0
  29. package/skills/tacitt/references/journey.md +4 -4
  30. package/skills/tacitt/references/remote-workers.md +46 -0
  31. package/skills/tacitt/references/send.md +41 -11
  32. package/skills/tacitt/scripts/INDEX.md +36 -36
  33. package/skills/tacitt/scripts/journey-card-consolidation.mjs +2 -4
  34. package/skills/tacitt/scripts/journey-state.d.mts +30 -0
  35. package/skills/tacitt/scripts/journey-state.mjs +56 -3
  36. package/skills/tacitt/scripts/journey-tasks.d.mts +8 -0
  37. package/skills/tacitt/scripts/journey-tasks.mjs +4 -1
  38. package/skills/tacitt/scripts/privacy-validator.mjs +78 -3
  39. package/skills/tacitt/scripts/review.mjs +36 -5
  40. package/dist/web/assets/index-D5DEG5Ue.css +0 -1
  41. package/dist/web/assets/index-Dh4iG6x2.js +0 -69
@@ -1,5 +1,5 @@
1
- import "./locate-U3-nkird.mjs";
2
- import "./src-DSDRF7i6.mjs";
1
+ import "./locate-JYtFmKu-.mjs";
2
+ import "./src-C1SjCDx0.mjs";
3
3
  import { z } from "zod";
4
4
  import { Worker } from "node:worker_threads";
5
5
  //#region apps/cli/src/agent-setup/index.ts
@@ -1,8 +1,8 @@
1
- import { q as listAgentSetup } from "./src-DIuh0LHk.mjs";
2
- import { rn as workspaceSchema, tn as sessionSchema, yn as createStaticProcessor } from "./locate-U3-nkird.mjs";
3
- import { l as createNativeAdapters, u as createGitNameSeedProvider } from "./src-BESjwh7X.mjs";
4
- import { at as maximumAgentSetupSessions, ci as effectiveTreatmentSchema } from "./src-DSDRF7i6.mjs";
5
- import "./agent-setup-Cb_spmGb.mjs";
1
+ import { J as listAgentSetup } from "./src-CQeUBG2Y.mjs";
2
+ import { Dn as createStaticProcessor, dn as workspaceSchema, ln as sessionSchema } from "./locate-JYtFmKu-.mjs";
3
+ import { l as createNativeAdapters, u as createGitNameSeedProvider } from "./src-xidy0yF7.mjs";
4
+ import { at as maximumAgentSetupSessions, ci as effectiveTreatmentSchema } from "./src-C1SjCDx0.mjs";
5
+ import "./agent-setup-BZbgLgHg.mjs";
6
6
  import { z } from "zod";
7
7
  import { parentPort, workerData } from "node:worker_threads";
8
8
  //#region apps/cli/src/agent-setup/worker.ts
package/dist/cli.mjs CHANGED
@@ -1,9 +1,9 @@
1
1
  #!/usr/bin/env node
2
- import { _ as createExecutionPort, a as readAgentPresence, d as parseOptions, f as businessCommands, g as readStateDump, h as startupFailure, i as invoke, l as createRenderActivity, m as permissionDiagnostic, n as readOperation, o as createRuntime, p as longCommands, r as waitOperation, s as executorEventSchema, t as cancelOperation, u as helpText, v as startHost$1, y as traceStartup } from "./query-7uY266qY.mjs";
3
- import { nt as openPrivateFile, tt as makePrivateDirectory } from "./src-DIuh0LHk.mjs";
4
- import { Gt as safeField, Ht as ApplicationError, Wt as safeCode } from "./locate-U3-nkird.mjs";
5
- import { Zn as reviewTransportBytes, et as readWorkspaceOutcomes, ii as stateSchema, st as resolveFailureLocation } from "./src-DSDRF7i6.mjs";
6
- import { _t as isCoordinationBusy } from "./heap-eZTo0VYj.mjs";
2
+ import { _ as readStateDump, a as readAgentPresence, b as traceStartup, d as helpText, f as parseOptions, g as startupFailure, h as permissionDiagnostic, i as invoke, l as awaitingPassport, m as longCommands, n as readOperation, o as createRuntime, p as businessCommands, r as waitOperation, s as executorEventSchema, t as cancelOperation, u as createRenderActivity, v as createExecutionPort, y as startHost$1 } from "./query-BZvNsP1u.mjs";
3
+ import { nt as makePrivateDirectory, rt as openPrivateFile } from "./src-CQeUBG2Y.mjs";
4
+ import { $t as safeField, Qt as safeCode, Xt as ApplicationError } from "./locate-JYtFmKu-.mjs";
5
+ import { Zn as reviewTransportBytes, et as readWorkspaceOutcomes, ii as stateSchema, st as resolveFailureLocation } from "./src-C1SjCDx0.mjs";
6
+ import { _t as isCoordinationBusy } from "./heap-NDnGBXH6.mjs";
7
7
  import { constants, createReadStream, write } from "node:fs";
8
8
  import { z } from "zod";
9
9
  import { lstat, mkdir, mkdtemp, open, readFile, readdir, realpath, rename, rm, writeFile } from "node:fs/promises";
@@ -140,6 +140,13 @@ function reportOwnershipCheckDeferred() {
140
140
  })}\n`, (_error) => {});
141
141
  } catch {}
142
142
  }
143
+ /**
144
+ * A focused host stops 30 minutes after its journey ended and Passport finished with the last
145
+ * Send, and at most 3 hours after the journey ended (ADR 0233).
146
+ */
147
+ function hostFinished(now, endedAt, settledAt) {
148
+ return now - endedAt >= 108e5 || settledAt !== void 0 && now - settledAt >= 18e5;
149
+ }
143
150
  async function serve(options, journeyId) {
144
151
  let initializing;
145
152
  let shutdownPhase = "application-and-account";
@@ -147,6 +154,7 @@ async function serve(options, journeyId) {
147
154
  let host;
148
155
  let ownerTimer;
149
156
  let finishTimer;
157
+ const hostLife = new AbortController();
150
158
  let observedStore = void 0;
151
159
  const timing = process.env["CI"] ? createHostTimingSampler() : void 0;
152
160
  const timingTimer = process.env["CI"] ? setInterval(() => {
@@ -197,6 +205,7 @@ async function serve(options, journeyId) {
197
205
  }, 5e3);
198
206
  if (ownerTimer) clearInterval(ownerTimer);
199
207
  if (finishTimer) clearInterval(finishTimer);
208
+ hostLife.abort();
200
209
  host?.beginStop();
201
210
  try {
202
211
  await runtime.close();
@@ -286,12 +295,29 @@ async function serve(options, journeyId) {
286
295
  process.on("SIGTERM", onSignal);
287
296
  if (journeyId) {
288
297
  let endedAt;
298
+ let settledAt;
299
+ let following = false;
289
300
  finishTimer = setInterval(() => {
290
- runtime.application.journey?.get({ journeyId }).then((journey) => {
291
- endedAt = journey?.phase === "completed" || journey?.abandonedAt !== void 0 ? endedAt ?? Date.now() : void 0;
292
- if (endedAt !== void 0 && Date.now() - endedAt >= 18e5) scheduleStop();
293
- }).catch(() => {});
294
- }, 6e4);
301
+ if (following) return;
302
+ following = true;
303
+ (async () => {
304
+ const { journey: journeys, journeySend } = runtime.application;
305
+ const journey = await journeys?.get({ journeyId });
306
+ const ended = journey?.phase === "completed" || journey?.abandonedAt !== void 0;
307
+ const send = (await journeys?.get({}))?.journeyId === journeyId ? (await journeySend?.get({ journeyId }))?.send : null;
308
+ const waiting = Boolean(send && awaitingPassport(send));
309
+ const now = Date.now();
310
+ endedAt = ended ? endedAt ?? now : void 0;
311
+ settledAt = ended && !waiting ? settledAt ?? now : void 0;
312
+ if (endedAt !== void 0 && hostFinished(now, endedAt, settledAt)) return scheduleStop();
313
+ if (waiting && send) await journeySend?.advance({
314
+ journeyId,
315
+ sendId: send.id
316
+ }, hostLife.signal);
317
+ })().catch(() => {}).finally(() => {
318
+ following = false;
319
+ });
320
+ }, 15e3);
295
321
  finishTimer.unref();
296
322
  const url = new URL(host.url);
297
323
  url.searchParams.set("view", "skill");
@@ -1135,6 +1161,7 @@ const writeJson = (value) => new Promise((resolve, reject) => {
1135
1161
  /** Procedures the review helper sends; each runs exactly as its own `--input` command would. */
1136
1162
  const streamProcedures = /* @__PURE__ */ new Set([
1137
1163
  "journey.get",
1164
+ "journey.remoteWorkers",
1138
1165
  "journey.prepare",
1139
1166
  "journey.catalog",
1140
1167
  "journey.classificationSessions",
@@ -1,4 +1,4 @@
1
- import { i as errorCode } from "./model-BDrntocp.mjs";
1
+ import { i as errorCode } from "./model-CmHypB0p.mjs";
2
2
  import { a as titleHintLimits, i as encodeTitleError, o as titleInputSchema, t as assertTitleHeap } from "./heap-1FYhGds4.mjs";
3
3
  import { stat } from "node:fs/promises";
4
4
  import { isAbsolute, join } from "node:path";
@@ -1,8 +1,8 @@
1
- import { J as createConfiguredPreviewStream } from "./src-DIuh0LHk.mjs";
2
- import { rn as workspaceSchema, tn as sessionSchema, yn as createStaticProcessor } from "./locate-U3-nkird.mjs";
3
- import { l as createNativeAdapters, u as createGitNameSeedProvider } from "./src-BESjwh7X.mjs";
4
- import { ci as effectiveTreatmentSchema } from "./src-DSDRF7i6.mjs";
5
- import { a as classifyRecord, n as assertPreviewHeap, t as runPreview } from "./run-CV6Io7CS.mjs";
1
+ import { Y as createConfiguredPreviewStream } from "./src-CQeUBG2Y.mjs";
2
+ import { Dn as createStaticProcessor, dn as workspaceSchema, ln as sessionSchema } from "./locate-JYtFmKu-.mjs";
3
+ import { l as createNativeAdapters, u as createGitNameSeedProvider } from "./src-xidy0yF7.mjs";
4
+ import { ci as effectiveTreatmentSchema } from "./src-C1SjCDx0.mjs";
5
+ import { a as classifyRecord, n as assertPreviewHeap, t as runPreview } from "./run-DvRM-NR8.mjs";
6
6
  import { z } from "zod";
7
7
  import { parentPort, workerData } from "node:worker_threads";
8
8
  //#region apps/cli/src/preview/run.ts
@@ -1,8 +1,8 @@
1
- import { $ as safeError, A as runConfiguredSessionJob, R as gitSeedsProvider, m as captureConfiguredSessionJob, u as runConfiguredScanJob } from "./src-DIuh0LHk.mjs";
2
- import { Wt as safeCode, yn as createStaticProcessor } from "./locate-U3-nkird.mjs";
3
- import { l as createNativeAdapters } from "./src-BESjwh7X.mjs";
4
- import "./src-DSDRF7i6.mjs";
5
- import { d as runJourneyBaseJob, i as runJourneyOutputVerifyJob, n as runJourneyOutputJob, r as runJourneyOutputShardJob } from "./job-Bi57uRU-.mjs";
1
+ import { et as safeError, h as captureConfiguredSessionJob, j as runConfiguredSessionJob, u as runConfiguredScanJob, z as gitSeedsProvider } from "./src-CQeUBG2Y.mjs";
2
+ import { Dn as createStaticProcessor, Qt as safeCode } from "./locate-JYtFmKu-.mjs";
3
+ import { l as createNativeAdapters } from "./src-xidy0yF7.mjs";
4
+ import "./src-C1SjCDx0.mjs";
5
+ import { d as runJourneyBaseJob, i as runJourneyOutputVerifyJob, n as runJourneyOutputJob, r as runJourneyOutputShardJob } from "./job-BO0a67HQ.mjs";
6
6
  import { parentPort } from "node:worker_threads";
7
7
  //#region apps/cli/src/configured-session-worker.ts
8
8
  const port = parentPort;
@@ -1,4 +1,4 @@
1
- import { nr as ProcessingError } from "./locate-U3-nkird.mjs";
1
+ import { ur as ProcessingError } from "./locate-JYtFmKu-.mjs";
2
2
  //#region packages/processing/src/compression/frame.ts
3
3
  function createZstdFrameCheck(fail = () => {
4
4
  throw new ProcessingError("PROCESSING_INVALID_RECORD");
@@ -1,6 +1,6 @@
1
- import { b as writePrivateReviewPayload, et as exclusiveLock, it as windowsOwnerOnly, nt as openPrivateFile, rt as restrictToOwner, x as readPrivateReviewPayload } from "./src-DIuh0LHk.mjs";
2
- import { $t as fileIdentitySchema, At as journeyTermSchema, Ht as ApplicationError, It as termTypeSchema, Jt as reviewFamilies, Kn as isStaticCategory, Mt as reviewTermsResultSchema, _ as semanticFindingSchema, b as validateBReview, c as textDigest, d as reviewAlignmentAudit, dt as nativeJourneySchema, ft as journeyGuidanceSchema, g as validateReviewAlignment, gn as createDetectionSummary, gt as journeyWorkSuggestionSchema, ht as journeyDescribeSchema, i as reviewBatchSchema, it as journeyDigestSchema, jt as reviewTermsInputSchema, kt as privacyTermSchema, l as validateReview, m as reviewAlignmentSchema, o as reviewDigest, ot as journeyIdSchema, qn as staticCategories, qt as familySelected, r as reviewBatchChunks, s as reviewSubmitSchema, u as findingReferenceKey, v as bContextEvidence } from "./locate-U3-nkird.mjs";
3
- import { $n as mergeBRepair, $t as journeyResourceSchema, At as validateAttemptAppend, B as validateInspectionBatch, Bt as newJourneyWork, Et as obsoleteJourney, Fn as confirmedHideGroupIds, Ft as applyClassificationProposal, G as validateInspectionFence, Gn as workPrivacyDecisions, Gr as withReadingProgress, Gt as hideFinishSchema, Hn as syncTermGroups, Hr as isReadingComplete, Ht as journeyContextQuerySchema, In as confirmedHideKey, It as classificationCommitSchema, J as validateInspectionQuery, Jn as reviewCandidateResourceSchema, Jt as journeySearchSaveSchema, K as validateInspectionHead, Kr as mergePrivacyTerms, Kt as hidePublishSchema, Mn as bMaskedHits, Nt as journeyBatchReadSchema, Pr as journeySendSchema, Pt as journeyReviewStorageQuerySchema, Qn as bReviewDigest, Qt as journeyResourceQuerySchema, Rn as confirmedHideTerms, Un as retireWorkDescription, Ur as isSelectedWork, Ut as journeyContextSchema, V as validateInspectionBatches, Vn as maskedHitsStale, W as validateInspectionClaim, Wn as workDecisionDigest, Wr as selectedWorks, Wt as hideBeginSchema, X as validateDetectionSummary, Xn as reviewRepairResourceSchema, Xt as journeyPolicyRespondSchema, Y as validateInspectionContribution, Yt as searchScopeDigest, Z as inspectionInputs, Zt as projectPreparationProgress, _ as projectJourneyInventory, _n as journeyCommitResultSchema, _r as preparationSettlementSchema, an as reviewAttemptsResultSchema, ar as scanGitSeedsId, b as bReviewScope, c as reconstructBFields, cn as sessionReconciliationResourceSchema, en as journeyIsolateSchema, fn as sessionReviewQuerySchema, fr as journeyInventoryReadSchema, gn as sessionUsefulnessResourceSchema, gr as preparationBeginSchema, h as semanticGroupKey, hn as sessionUsefulnessInputSchema, ht as candidateSortAvailable, ii as stateSchema, in as reviewAttemptsQuerySchema, ir as scanSessionResourceSchema, jt as journeyGuidance, kr as staticSessionId, kt as attemptBudgetCodePoints, l as reviseGroupMembership, lr as validateScanExclusion, m as hideScopeDigest, mn as sessionReviewStatusSchema, mr as journeyPreparationProgressSchema, nn as sortingApplySchema, nr as scanCanonicalResourceSchema, o as bRereadDigest, pn as sessionReviewResourceSchema, pr as journeyInventorySchema, pt as manualUploadSchema, q as validateInspectionInputs, qt as journeySearchResultSchema, rn as reviewAttemptResourceSchema, s as reconcileBSession, sn as sessionReconcileResultSchema, t as scanBatchContextDigest, tn as journeyPlaceSchema, tr as scanAliasResourceSchema, u as resolveGroupSplit, un as sessionRereadResourceSchema, ut as manualUploadBindingSchema, v as preparationScope, vn as journeyCommitSchema, vr as preparationStartSchema, wn as settleConfirmedHides, wt as settleCorrections, xn as confirmedHideDeltaSchema, xr as applyCardAnswers, yn as journeyEventSchema, yr as validatePreparationFacts, zn as dictionaryHides } from "./src-DSDRF7i6.mjs";
1
+ import { S as readPrivateReviewPayload, at as windowsOwnerOnly, it as restrictToOwner, rt as openPrivateFile, tt as exclusiveLock, x as writePrivateReviewPayload } from "./src-CQeUBG2Y.mjs";
2
+ import { At as journeyTermSchema, It as termTypeSchema, Mt as reviewTermsResultSchema, Xt as ApplicationError, _ as semanticFindingSchema, b as validateBReview, c as textDigest, d as reviewAlignmentAudit, dt as nativeJourneySchema, er as isStaticCategory, ft as journeyGuidanceSchema, g as validateReviewAlignment, gt as journeyWorkSuggestionSchema, ht as journeyDescribeSchema, i as reviewBatchSchema, it as journeyDigestSchema, jt as reviewTermsInputSchema, kt as privacyTermSchema, l as validateReview, m as reviewAlignmentSchema, nn as reviewFamilies, o as reviewDigest, ot as journeyIdSchema, r as reviewBatchChunks, s as reviewSubmitSchema, sn as fileIdentitySchema, tn as familySelected, tr as staticCategories, u as findingReferenceKey, v as bContextEvidence, wn as createDetectionSummary } from "./locate-JYtFmKu-.mjs";
3
+ import { $n as mergeBRepair, $t as journeyResourceSchema, At as validateAttemptAppend, B as validateInspectionBatch, Bt as newJourneyWork, Et as obsoleteJourney, Fn as confirmedHideGroupIds, Ft as applyClassificationProposal, G as validateInspectionFence, Gn as workPrivacyDecisions, Gr as withReadingProgress, Gt as hideFinishSchema, Hn as syncTermGroups, Hr as isReadingComplete, Ht as journeyContextQuerySchema, In as confirmedHideKey, It as classificationCommitSchema, J as validateInspectionQuery, Jn as reviewCandidateResourceSchema, Jt as journeySearchSaveSchema, K as validateInspectionHead, Kr as mergePrivacyTerms, Kt as hidePublishSchema, Mn as bMaskedHits, Nt as journeyBatchReadSchema, Pr as journeySendSchema, Pt as journeyReviewStorageQuerySchema, Qn as bReviewDigest, Qt as journeyResourceQuerySchema, Rn as confirmedHideTerms, Un as retireWorkDescription, Ur as isSelectedWork, Ut as journeyContextSchema, V as validateInspectionBatches, Vn as maskedHitsStale, W as validateInspectionClaim, Wn as workDecisionDigest, Wr as selectedWorks, Wt as hideBeginSchema, X as validateDetectionSummary, Xn as reviewRepairResourceSchema, Xt as journeyPolicyRespondSchema, Y as validateInspectionContribution, Yt as searchScopeDigest, Z as inspectionInputs, Zt as projectPreparationProgress, _ as projectJourneyInventory, _n as journeyCommitResultSchema, _r as preparationSettlementSchema, an as reviewAttemptsResultSchema, ar as scanGitSeedsId, b as bReviewScope, c as reconstructBFields, cn as sessionReconciliationResourceSchema, en as journeyIsolateSchema, fn as sessionReviewQuerySchema, fr as journeyInventoryReadSchema, gn as sessionUsefulnessResourceSchema, gr as preparationBeginSchema, h as semanticGroupKey, hn as sessionUsefulnessInputSchema, ht as candidateSortAvailable, ii as stateSchema, in as reviewAttemptsQuerySchema, ir as scanSessionResourceSchema, jt as journeyGuidance, kr as staticSessionId, kt as attemptBudgetCodePoints, l as reviseGroupMembership, lr as validateScanExclusion, m as hideScopeDigest, mn as sessionReviewStatusSchema, mr as journeyPreparationProgressSchema, nn as sortingApplySchema, nr as scanCanonicalResourceSchema, o as bRereadDigest, pn as sessionReviewResourceSchema, pr as journeyInventorySchema, pt as manualUploadSchema, q as validateInspectionInputs, qt as journeySearchResultSchema, rn as reviewAttemptResourceSchema, s as reconcileBSession, sn as sessionReconcileResultSchema, t as scanBatchContextDigest, tn as journeyPlaceSchema, tr as scanAliasResourceSchema, u as resolveGroupSplit, un as sessionRereadResourceSchema, ut as manualUploadBindingSchema, v as preparationScope, vn as journeyCommitSchema, vr as preparationStartSchema, wn as settleConfirmedHides, wt as settleCorrections, xn as confirmedHideDeltaSchema, xr as applyCardAnswers, yn as journeyEventSchema, yr as validatePreparationFacts, zn as dictionaryHides } from "./src-C1SjCDx0.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";
@@ -415,11 +415,11 @@ function insertCorrectionReport(db, resource) {
415
415
  * A snapshot of an earlier release cannot render, so a new Journey may replace it, but never
416
416
  * one with a Send record or a sent Work: that Send stays for the person to finish.
417
417
  */
418
- /** Passport holds a receipt from one of this Journey's Sends, so a Work may have reached it. */
418
+ /** A receipt or persisted session mutation intent means a Send may have reached Passport. */
419
419
  function reachedPassport(db, journeyId) {
420
420
  return db.prepare("SELECT json FROM journey_sends WHERE journey_id=?").all(journeyId).some((row) => {
421
421
  if (typeof row["json"] !== "string") throw new ApplicationError("CORRUPTED_STATE");
422
- return journeySendSchema.parse(JSON.parse(row["json"])).items.some((item) => item.receipt || item.previousReceipts.length);
422
+ return journeySendSchema.parse(JSON.parse(row["json"])).items.some((item) => item.receipt || item.previousReceipts.length || item.sessionUpload !== void 0 || item.sessionMembership || item.sessionAssembly);
423
423
  });
424
424
  }
425
425
  /** An abandoned Journey gives way to a new one unless one of its Sends reached Passport. */
@@ -4828,7 +4828,7 @@ function commitJourneySend(db, input) {
4828
4828
  ].includes(work.reason));
4829
4829
  const journey = {
4830
4830
  ...current.journey,
4831
- phase: current.journey.phase === "paused" ? "paused" : finished ? "completed" : [
4831
+ phase: current.journey.phase === "paused" || prior?.status === "completed" ? current.journey.phase : finished ? "completed" : [
4832
4832
  "completed",
4833
4833
  "blocked",
4834
4834
  "paused"
@@ -1,7 +1,7 @@
1
- import { Y as createInspectionProcessor } from "./src-DIuh0LHk.mjs";
2
- import { yn as createStaticProcessor } from "./locate-U3-nkird.mjs";
3
- import { l as createNativeAdapters, u as createGitNameSeedProvider } from "./src-BESjwh7X.mjs";
4
- import { H as validateInspectionRequest } from "./src-DSDRF7i6.mjs";
1
+ import { X as createInspectionProcessor } from "./src-CQeUBG2Y.mjs";
2
+ import { Dn as createStaticProcessor } from "./locate-JYtFmKu-.mjs";
3
+ import { l as createNativeAdapters, u as createGitNameSeedProvider } from "./src-xidy0yF7.mjs";
4
+ import { H as validateInspectionRequest } from "./src-C1SjCDx0.mjs";
5
5
  import "./messages-D3m3bhva.mjs";
6
6
  import { z } from "zod";
7
7
  import { parentPort, workerData } from "node:worker_threads";
@@ -1,12 +1,386 @@
1
- import { B as writeLogicalJourneyOutput, C as readConfiguredSearchFields, E as prepareCollectionProduction, R as gitSeedsProvider, U as readConfiguredOutputInfo, d as verifyOutputShard, f as writeOutputShard, k as renderJobDigest, y as writeLogicalJourneyBase } from "./src-DIuh0LHk.mjs";
2
- import { Ht as ApplicationError, Jt as reviewFamilies, zt as filterInventoryByPeriod } from "./locate-U3-nkird.mjs";
3
- import { Ar as staticSessionResourceSchema, Cn as renderedHideValue, Dn as hideKeyId, En as addHideIndexTokens, di as selectFrozenConfiguration, kn as packHideIndex, li as defaultScopedSettings, ui as freezeConfiguration } from "./src-DSDRF7i6.mjs";
1
+ import { A as renderJobDigest, D as prepareCollectionProduction, V as writeLogicalJourneyOutput, W as readConfiguredOutputInfo, at as windowsOwnerOnly, b as writeLogicalJourneyBase, d as verifyOutputShard, f as writeOutputShard, nt as makePrivateDirectory, w as readConfiguredSearchFields, z as gitSeedsProvider } from "./src-CQeUBG2Y.mjs";
2
+ import { Xt as ApplicationError, nn as reviewFamilies, zt as filterInventoryByPeriod } from "./locate-JYtFmKu-.mjs";
3
+ import { Ar as staticSessionResourceSchema, Cn as renderedHideValue, Dn as hideKeyId, En as addHideIndexTokens, di as selectFrozenConfiguration, kn as packHideIndex, li as defaultScopedSettings, ui as freezeConfiguration } from "./src-C1SjCDx0.mjs";
4
4
  import { constants } from "node:fs";
5
- import { link, lstat, open, unlink } from "node:fs/promises";
6
- import { join } from "node:path";
5
+ import { z } from "zod";
6
+ import { copyFile, link, lstat, mkdir, mkdtemp, open, readFile, realpath, rename, rm, unlink, writeFile } from "node:fs/promises";
7
+ import { execFile } from "node:child_process";
8
+ import { dirname, join } from "node:path";
9
+ import { promisify } from "node:util";
7
10
  import { createHash, randomBytes, randomUUID } from "node:crypto";
11
+ import { tmpdir } from "node:os";
12
+ import { quote } from "shell-quote";
13
+ //#region apps/cli/src/remote/model.ts
14
+ function validRemotePath(path, harness) {
15
+ return harness === "codex" ? /^\.codex\/sessions\/\d{4}\/\d{2}\/\d{2}\/rollout-[A-Za-z0-9_.-]+\.jsonl$/u.test(path) : /^\.claude\/projects\/[A-Za-z0-9_-]+\/[A-Za-z0-9_-]+\.jsonl$/u.test(path);
16
+ }
17
+ function insideWindow(start, window) {
18
+ const time = Date.parse(start);
19
+ return Number.isFinite(time) && time >= Date.parse(window.start) && time <= Date.parse(window.end);
20
+ }
21
+ //#endregion
22
+ //#region apps/cli/src/remote/transport.ts
23
+ const execute = promisify(execFile);
24
+ /** Pin every component to the signed-in user's home without following links. */
25
+ const sourceReader = `def source_open(relative):
26
+ parts=relative.split('/')
27
+ if any(part in ('','.', '..') for part in parts): raise RuntimeError('invalid source')
28
+ directory=os.open(os.path.expanduser('~'),os.O_RDONLY|os.O_DIRECTORY|os.O_NOFOLLOW)
29
+ try:
30
+ for part in parts[:-1]:
31
+ child=os.open(part,os.O_RDONLY|os.O_DIRECTORY|os.O_NOFOLLOW,dir_fd=directory)
32
+ os.close(directory)
33
+ directory=child
34
+ descriptor=os.open(parts[-1],os.O_RDONLY|os.O_NOFOLLOW|os.O_NONBLOCK,dir_fd=directory)
35
+ try:
36
+ metadata=os.fstat(descriptor)
37
+ if not stat.S_ISREG(metadata.st_mode) or metadata.st_uid!=os.getuid(): raise RuntimeError('invalid source owner or type')
38
+ return os.fdopen(descriptor,'rb')
39
+ except BaseException:
40
+ os.close(descriptor)
41
+ raise
42
+ finally: os.close(directory)`;
43
+ /** Read only a bounded prefix, ignoring Claude bookkeeping before native session records. */
44
+ const startReader = `def session_start(f,harness):
45
+ prefix=f.read(262145)
46
+ lines=prefix[:262144].split(b'\\n')
47
+ if len(prefix)>262144: lines.pop()
48
+ types=('user','assistant','system','progress','summary','result','queue-operation')
49
+ for line in lines:
50
+ if not line.strip(): continue
51
+ record=json.loads(line)
52
+ if not isinstance(record,dict): continue
53
+ if harness=='codex' and record.get('type')!='session_meta': return None
54
+ if harness=='claude' and record.get('type') not in types: continue
55
+ time=record.get('timestamp')
56
+ if isinstance(time,str):
57
+ try:
58
+ stamp(time)
59
+ return time
60
+ except ValueError: pass
61
+ if harness=='codex': return None
62
+ return None`;
63
+ /** Fixed remote program: bounded first-record metadata only, never directory copying. */
64
+ const listing = `import os,glob,json,datetime,stat
65
+ harness,start,end=INPUT
66
+ home=os.path.expanduser('~')
67
+ def stamp(s):
68
+ return datetime.datetime.fromisoformat(s.replace('Z','+00:00')).timestamp()
69
+ ${startReader}
70
+ ${sourceReader}
71
+ low,high=stamp(start),stamp(end)
72
+ pattern='.codex/sessions/*/*/*/rollout-*.jsonl' if harness=='codex' else '.claude/projects/*/*.jsonl'
73
+ result=[]
74
+ for count,relative in enumerate(glob.iglob(pattern,root_dir=home)):
75
+ if count>=100000: raise RuntimeError('listing limit')
76
+ path=os.path.join(home,relative)
77
+ if os.path.realpath(path)!=path or not stat.S_ISREG(os.stat(path).st_mode): continue
78
+ try:
79
+ with source_open(relative) as f: time=session_start(f,harness)
80
+ if isinstance(time,str) and low<=stamp(time)<=high: result.append({'path':relative,'start':time})
81
+ except (ValueError,KeyError,TypeError,OSError,RuntimeError): continue
82
+ if len(result)>10000: raise RuntimeError('file limit')
83
+ print(json.dumps(result))`;
84
+ function invocation(window, script) {
85
+ const command = quote([
86
+ "python3",
87
+ "-c",
88
+ script
89
+ ]);
90
+ return window.transport === "ssh" ? {
91
+ executable: "ssh",
92
+ args: [
93
+ "-oBatchMode=yes",
94
+ "-oConnectTimeout=10",
95
+ "-oStrictHostKeyChecking=yes",
96
+ "-n",
97
+ ...window.args,
98
+ command
99
+ ]
100
+ } : {
101
+ executable: "gcloud",
102
+ args: [
103
+ "compute",
104
+ "ssh",
105
+ ...window.args,
106
+ "--quiet",
107
+ "--ssh-flag=-oBatchMode=yes",
108
+ "--ssh-flag=-oConnectTimeout=10",
109
+ "--ssh-flag=-oStrictHostKeyChecking=yes",
110
+ "--ssh-flag=-n",
111
+ "--command",
112
+ command
113
+ ]
114
+ };
115
+ }
116
+ async function run(window, script, maxBuffer) {
117
+ const call = invocation(window, script);
118
+ const execution = execute(call.executable, call.args, {
119
+ timeout: 6e4,
120
+ killSignal: "SIGKILL",
121
+ maxBuffer,
122
+ encoding: "buffer",
123
+ env: {
124
+ ...process.env,
125
+ SSH_ASKPASS_REQUIRE: "never",
126
+ CLOUDSDK_CORE_DISABLE_PROMPTS: "1"
127
+ }
128
+ });
129
+ let timer;
130
+ const deadline = new Promise((_resolve, reject) => {
131
+ timer = setTimeout(() => {
132
+ execution.child?.kill("SIGKILL");
133
+ execution.child?.stdin?.destroy();
134
+ execution.child?.stdout?.destroy();
135
+ execution.child?.stderr?.destroy();
136
+ reject(/* @__PURE__ */ new Error("REMOTE_TRANSPORT_TIMEOUT"));
137
+ }, 6e4);
138
+ });
139
+ try {
140
+ return await Promise.race([execution, deadline]);
141
+ } finally {
142
+ clearTimeout(timer);
143
+ }
144
+ }
145
+ function createRemoteTransport() {
146
+ return {
147
+ async list(window) {
148
+ const input = JSON.stringify([
149
+ window.harness,
150
+ window.start,
151
+ window.end
152
+ ]);
153
+ const { stdout } = await run(window, listing.replace("INPUT", input), 4194304);
154
+ const value = JSON.parse(stdout.toString("utf8"));
155
+ if (!Array.isArray(value)) throw new Error("INVALID_REMOTE_LIST");
156
+ const files = [];
157
+ for (const item of value) {
158
+ if (!item || typeof item !== "object" || !("path" in item) || !("start" in item) || typeof item.path !== "string" || typeof item.start !== "string") throw new Error("INVALID_REMOTE_FILE");
159
+ files.push({
160
+ path: item.path,
161
+ start: item.start
162
+ });
163
+ }
164
+ return files;
165
+ },
166
+ async copy(window, file, destination) {
167
+ if (!validRemotePath(file.path, window.harness)) throw new Error("INVALID_REMOTE_PATH");
168
+ const { stdout } = await run(window, `import os,sys,stat,json,datetime
169
+ def stamp(value): return datetime.datetime.fromisoformat(value.replace('Z','+00:00')).timestamp()
170
+ ${startReader}
171
+ ${sourceReader}
172
+ with source_open(${JSON.stringify(file.path)}) as f:
173
+ s=os.fstat(f.fileno())
174
+ if not stat.S_ISREG(s.st_mode) or s.st_size>268435456: raise RuntimeError('source limit')
175
+ time=session_start(f,${JSON.stringify(window.harness)})
176
+ if time is None or not stamp(${JSON.stringify(window.start)})<=stamp(time)<=stamp(${JSON.stringify(window.end)}): raise RuntimeError('source outside window')
177
+ f.seek(0)
178
+ data=f.read(268435457)
179
+ if len(data)>268435456: raise RuntimeError('source limit')
180
+ sys.stdout.buffer.write(data)`, 268435456);
181
+ await writeFile(destination, stdout, {
182
+ flag: "wx",
183
+ mode: 384
184
+ });
185
+ }
186
+ };
187
+ }
188
+ //#endregion
189
+ //#region apps/cli/src/remote/collect.ts
190
+ /** Validate the copied bounded native start records rather than trusting a stale remote listing. */
191
+ async function copiedStart(path, harness) {
192
+ const handle = await open(path, "r");
193
+ try {
194
+ if ((await handle.stat()).size > 268435456) throw new Error("REMOTE_FILE_TOO_LARGE");
195
+ const limit = 262144;
196
+ const buffer = Buffer.alloc(262145);
197
+ const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);
198
+ const lines = buffer.toString("utf8", 0, Math.min(bytesRead, limit)).split("\n");
199
+ if (bytesRead > limit) lines.pop();
200
+ const types = [
201
+ "user",
202
+ "assistant",
203
+ "system",
204
+ "progress",
205
+ "summary",
206
+ "result",
207
+ "queue-operation"
208
+ ];
209
+ for (const line of lines) {
210
+ if (!line.trim()) continue;
211
+ const value = JSON.parse(line);
212
+ if (!value || typeof value !== "object" || !("type" in value)) continue;
213
+ if (harness === "codex" && value.type !== "session_meta") return null;
214
+ if (harness === "claude" && (typeof value.type !== "string" || !types.includes(value.type))) continue;
215
+ if ("timestamp" in value && typeof value.timestamp === "string" && Number.isFinite(Date.parse(value.timestamp))) return value.timestamp;
216
+ if (harness === "codex") return null;
217
+ }
218
+ return null;
219
+ } finally {
220
+ await handle.close();
221
+ }
222
+ }
223
+ /** Only consented hosts are contacted. Every copy is exclusive and normal discovery reads it next. */
224
+ async function collectRemoteWorkers(dispatches, confirmations, home, transport = createRemoteTransport(), reportFailure = () => console.error("REMOTE_WORKER_COLLECTION_FAILED"), roots = {}) {
225
+ const copied = [];
226
+ const failures = /* @__PURE__ */ new Set();
227
+ const seen = /* @__PURE__ */ new Set();
228
+ for (const window of dispatches) {
229
+ if (confirmations[window.host] !== true || failures.has(window.host)) continue;
230
+ let temporary;
231
+ try {
232
+ temporary = await mkdtemp(join(tmpdir(), "tacitt-remote-"));
233
+ const files = await transport.list(window);
234
+ if (files.length > 1e4) throw new Error("REMOTE_LIST_TOO_LARGE");
235
+ for (const file of files) {
236
+ if (!validRemotePath(file.path, window.harness) || !insideWindow(file.start, window)) continue;
237
+ const key = JSON.stringify([window.host, file.path]);
238
+ if (seen.has(key)) continue;
239
+ const staging = join(temporary, "worker.jsonl");
240
+ await transport.copy(window, file, staging);
241
+ const start = await copiedStart(staging, window.harness);
242
+ if (!start || !insideWindow(start, window)) {
243
+ await rm(staging, { force: true });
244
+ continue;
245
+ }
246
+ const hash = createHash("sha256").update(key).digest("hex");
247
+ const date = new Date(start).toISOString().slice(0, 10).split("-");
248
+ const path = window.harness === "codex" ? join(roots.codexHome ?? join(home, ".codex"), "sessions", ...date, `rollout-remote-${hash}.jsonl`) : join(roots.claudeHome ?? join(home, ".claude"), "projects", `remote-${hash.slice(0, 16)}`, `${hash}.jsonl`);
249
+ await mkdir(dirname(path), {
250
+ recursive: true,
251
+ mode: 448
252
+ });
253
+ try {
254
+ await copyFile(staging, path, constants.COPYFILE_EXCL);
255
+ copied.push({
256
+ path,
257
+ sourceSessionId: window.sourceSessionId
258
+ });
259
+ } catch (error) {
260
+ if (!(error instanceof Error) || !("code" in error) || error.code !== "EEXIST") throw error;
261
+ const existing = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
262
+ try {
263
+ if ((await existing.stat()).size <= 268435456) {
264
+ const incoming = await open(staging, "r");
265
+ try {
266
+ const [left, right] = await Promise.all([existing.readFile(), incoming.readFile()]);
267
+ if (left.equals(right)) copied.push({
268
+ path,
269
+ sourceSessionId: window.sourceSessionId
270
+ });
271
+ } finally {
272
+ await incoming.close();
273
+ }
274
+ }
275
+ } finally {
276
+ await existing.close();
277
+ }
278
+ }
279
+ seen.add(key);
280
+ await rm(staging, { force: true });
281
+ }
282
+ } catch (error) {
283
+ failures.add(window.host);
284
+ reportFailure(window.host, error);
285
+ } finally {
286
+ if (temporary) try {
287
+ await rm(temporary, {
288
+ recursive: true,
289
+ force: true
290
+ });
291
+ } catch (error) {
292
+ failures.add(window.host);
293
+ reportFailure(window.host, error);
294
+ }
295
+ }
296
+ }
297
+ return {
298
+ copied,
299
+ failures: [...failures]
300
+ };
301
+ }
302
+ //#endregion
303
+ //#region apps/cli/src/journey/directory.ts
304
+ async function journeyDirectory(stateDir, journeyId) {
305
+ let path = stateDir;
306
+ for (const name of ["journeys", journeyId]) {
307
+ path = join(path, name);
308
+ try {
309
+ await makePrivateDirectory(path);
310
+ } catch (cause) {
311
+ if (!(cause instanceof Error && "code" in cause && cause.code === "EEXIST")) throw cause;
312
+ }
313
+ const stat = await lstat(path, { bigint: true });
314
+ if (!stat.isDirectory() || stat.isSymbolicLink() || await realpath(path) !== path || (process.platform === "win32" ? !await windowsOwnerOnly(path, "directory") : stat.uid !== BigInt(process.getuid?.() ?? -1) || (stat.mode & 63n) !== 0n)) throw new ApplicationError("UNSAFE_STATE_PATH");
315
+ }
316
+ return path;
317
+ }
318
+ //#endregion
319
+ //#region apps/cli/src/remote/state.ts
320
+ const attachment = z.object({
321
+ path: z.string(),
322
+ sourceSessionId: z.string()
323
+ }).strict();
324
+ async function readRemoteState(stateDir, journeyId) {
325
+ const path = join(await journeyDirectory(stateDir, journeyId), "remote-workers.json");
326
+ try {
327
+ const value = JSON.parse(await readFile(path, "utf8"));
328
+ return z.object({
329
+ windows: z.array(z.object({
330
+ host: z.string(),
331
+ harness: z.enum(["codex", "claude"]),
332
+ transport: z.enum(["ssh", "gcloud"]),
333
+ args: z.array(z.string()),
334
+ sourceSessionId: z.string(),
335
+ start: z.string(),
336
+ end: z.string()
337
+ }).strict()),
338
+ decisions: z.record(z.string(), z.boolean()),
339
+ parents: z.record(z.string(), z.string()),
340
+ copied: z.array(attachment),
341
+ failures: z.array(z.string())
342
+ }).strict().parse(value);
343
+ } catch (error) {
344
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") return null;
345
+ throw error;
346
+ }
347
+ }
348
+ async function saveRemoteState(stateDir, journeyId, state) {
349
+ const path = join(await journeyDirectory(stateDir, journeyId), "remote-workers.json");
350
+ const temporary = `${path}.${randomUUID()}`;
351
+ await writeFile(temporary, JSON.stringify(state), {
352
+ mode: 384,
353
+ flag: "wx"
354
+ });
355
+ await rename(temporary, path);
356
+ }
357
+ async function attachRemoteWorkers(inventory, stateDir, journeyId) {
358
+ const state = await readRemoteState(stateDir, journeyId);
359
+ const allowed = new Set(state?.copied.map((copy) => copy.path) ?? []);
360
+ const sessions = inventory.sessions.filter((session) => session.parts.every((part) => !isRemoteImport(part.path) || allowed.has(part.path))).flatMap((session) => {
361
+ const imports = (state?.copied ?? []).filter((copy) => session.parts.some((part) => part.path === copy.path));
362
+ const parent = imports[0]?.sourceSessionId;
363
+ const key = parent ? state?.parents[parent] : void 0;
364
+ const parents = key ? inventory.sessions.filter((candidate) => candidate.sourceKey === key && candidate.parts.every((part) => !isRemoteImport(part.path))) : [];
365
+ const resolved = parents.length === 1 ? parents[0] : void 0;
366
+ if (!resolved || imports.some((copy) => copy.sourceSessionId !== parent)) return session.parts.some((part) => isRemoteImport(part.path)) ? [] : [session];
367
+ return [{
368
+ ...session,
369
+ remoteParentSessionId: resolved.id
370
+ }];
371
+ });
372
+ return {
373
+ ...inventory,
374
+ sessions
375
+ };
376
+ }
377
+ /** Reserved importer names never enter a later Send without that Send's consent receipt. */
378
+ function isRemoteImport(path) {
379
+ return /(?:^|[/\\])rollout-remote-[a-f0-9]{64}\.jsonl$/u.test(path) || /(?:^|[/\\])projects[/\\]remote-[a-f0-9]{16}[/\\][a-f0-9]{64}\.jsonl$/u.test(path);
380
+ }
381
+ //#endregion
8
382
  //#region apps/cli/src/journey/plan.ts
9
- async function prepareSourcePlan(storage, harnesses, journeyId, sensitiveTerms, signal, period = {}) {
383
+ async function prepareSourcePlan(storage, harnesses, journeyId, sensitiveTerms, signal, period = {}, stateDir) {
10
384
  const saved = (await storage.resources({
11
385
  journeyId,
12
386
  kind: "plan"
@@ -14,7 +388,8 @@ async function prepareSourcePlan(storage, harnesses, journeyId, sensitiveTerms,
14
388
  if (saved?.kind === "plan") return saved;
15
389
  const discovered = await harnesses.discover(signal);
16
390
  if (!discovered.complete) throw new ApplicationError("SCOPE_NOT_READY");
17
- const inventory = filterInventoryByPeriod(discovered, period);
391
+ const linked = stateDir ? await attachRemoteWorkers(discovered, stateDir, journeyId) : discovered;
392
+ const inventory = filterInventoryByPeriod(linked, period);
18
393
  if (inventory.sessions.length === 0) throw new ApplicationError("INVALID_SELECTION");
19
394
  const families = reviewFamilies(inventory);
20
395
  const defaults = defaultScopedSettings();
@@ -612,4 +987,4 @@ async function runJourneyOutputJob(job, live, signal, onPath) {
612
987
  };
613
988
  }
614
989
  //#endregion
615
- export { staticBaseProduction as _, writeJourneyOutput as a, mergeHideIndexTokens as c, runJourneyBaseJob as d, writeJourneyBase as f, staticBaseInputs as g, staticSessions as h, runJourneyOutputVerifyJob as i, packRenderHideIndex as l, saveStaticSession as m, runJourneyOutputJob as n, createHideIndexTokens as o, readStaticResult as p, runJourneyOutputShardJob as r, hideIndexTexts as s, journeyOutputJob as t, journeyBaseJob as u, prepareSourcePlan as v, workApproval as y };
990
+ export { journeyDirectory as C, saveRemoteState as S, staticBaseProduction as _, writeJourneyOutput as a, isRemoteImport as b, mergeHideIndexTokens as c, runJourneyBaseJob as d, writeJourneyBase as f, staticBaseInputs as g, staticSessions as h, runJourneyOutputVerifyJob as i, packRenderHideIndex as l, saveStaticSession as m, runJourneyOutputJob as n, createHideIndexTokens as o, readStaticResult as p, runJourneyOutputShardJob as r, hideIndexTexts as s, journeyOutputJob as t, journeyBaseJob as u, prepareSourcePlan as v, collectRemoteWorkers as w, readRemoteState as x, workApproval as y };