@narumitw/pi-sync 0.54.3 → 0.57.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.
- package/README.md +38 -11
- package/dist/chunks/agent-candidate-3JN6DJKT.ts +26 -0
- package/dist/chunks/agent-plan-QCUJWBP4.ts +99 -0
- package/dist/chunks/agent-plan-QCUJWBP4.ts.map +7 -0
- package/dist/chunks/agent-runner-E2JU2VZ6.ts +182 -0
- package/dist/chunks/agent-runner-E2JU2VZ6.ts.map +7 -0
- package/dist/chunks/agent-store-A3F6IYWZ.ts +152 -0
- package/dist/chunks/agent-store-A3F6IYWZ.ts.map +7 -0
- package/dist/chunks/chunk-5Q5SSKNG.ts +128 -0
- package/dist/chunks/chunk-5Q5SSKNG.ts.map +7 -0
- package/dist/chunks/chunk-5XZOC7FD.ts +215 -0
- package/dist/chunks/chunk-5XZOC7FD.ts.map +7 -0
- package/dist/chunks/{chunk-GC3QOL6J.ts → chunk-AAEEHR7H.ts} +31 -87
- package/dist/chunks/chunk-AAEEHR7H.ts.map +7 -0
- package/dist/chunks/{chunk-R35N4CL3.ts → chunk-B4QZBDBT.ts} +2 -2
- package/dist/chunks/{chunk-KGE47GCZ.ts → chunk-CRKTAPSL.ts} +8 -8
- package/dist/chunks/chunk-DT7M4VQS.ts +69 -0
- package/dist/chunks/chunk-DT7M4VQS.ts.map +7 -0
- package/dist/chunks/chunk-ED3TYIVW.ts +229 -0
- package/dist/chunks/chunk-ED3TYIVW.ts.map +7 -0
- package/dist/chunks/{chunk-HMXUKU43.ts → chunk-EUMINX7L.ts} +6 -6
- package/dist/chunks/chunk-FQOSHGJ7.ts +215 -0
- package/dist/chunks/chunk-FQOSHGJ7.ts.map +7 -0
- package/dist/chunks/chunk-GNH73BJ5.ts +153 -0
- package/dist/chunks/chunk-GNH73BJ5.ts.map +7 -0
- package/dist/chunks/{chunk-YTHQEW35.ts → chunk-GP5DU62N.ts} +8 -9
- package/dist/chunks/chunk-GP5DU62N.ts.map +7 -0
- package/dist/chunks/{chunk-AAZDBIBJ.ts → chunk-GSNPASKB.ts} +2 -2
- package/dist/chunks/{chunk-E6ONFG57.ts → chunk-IWZH5KYS.ts} +11 -8
- package/dist/chunks/chunk-IWZH5KYS.ts.map +7 -0
- package/dist/chunks/{chunk-CAGJOKB7.ts → chunk-JJTARUSO.ts} +15 -14
- package/dist/chunks/chunk-JJTARUSO.ts.map +7 -0
- package/dist/chunks/{chunk-ITFR6NNQ.ts → chunk-NLWS55B6.ts} +2 -1
- package/dist/chunks/{chunk-ITFR6NNQ.ts.map → chunk-NLWS55B6.ts.map} +2 -2
- package/dist/chunks/{chunk-2FETCGGT.ts → chunk-OEWQVWLC.ts} +4 -4
- package/dist/chunks/{chunk-35GM6XKM.ts → chunk-OTZRCKYP.ts} +128 -382
- package/dist/chunks/chunk-OTZRCKYP.ts.map +7 -0
- package/dist/chunks/{chunk-XU2VXGQV.ts → chunk-OWBAZA6J.ts} +14 -8
- package/dist/chunks/chunk-OWBAZA6J.ts.map +7 -0
- package/dist/chunks/chunk-PRUEIIK7.ts +24 -0
- package/dist/chunks/chunk-PRUEIIK7.ts.map +7 -0
- package/dist/chunks/chunk-QGK445K7.ts +21 -0
- package/dist/chunks/chunk-QGK445K7.ts.map +7 -0
- package/dist/chunks/{chunk-KATKRR3D.ts → chunk-QO333NM4.ts} +32 -11
- package/dist/chunks/chunk-QO333NM4.ts.map +7 -0
- package/dist/chunks/{chunk-I4JYVFUS.ts → chunk-QSHMOL3I.ts} +21 -22
- package/dist/chunks/chunk-QSHMOL3I.ts.map +7 -0
- package/dist/chunks/chunk-S2FMH5FT.ts +97 -0
- package/dist/chunks/chunk-S2FMH5FT.ts.map +7 -0
- package/dist/chunks/{chunk-BVVP33U5.ts → chunk-SWRVXVFD.ts} +12 -9
- package/dist/chunks/chunk-SWRVXVFD.ts.map +7 -0
- package/dist/chunks/{chunk-ZX2Q6THB.ts → chunk-UBV24CG4.ts} +4 -5
- package/dist/chunks/chunk-UBV24CG4.ts.map +7 -0
- package/dist/chunks/chunk-UOHR7LRO.ts +70 -0
- package/dist/chunks/chunk-UOHR7LRO.ts.map +7 -0
- package/dist/chunks/{chunk-VCL7TZYW.ts → chunk-UPNVIUBN.ts} +3 -3
- package/dist/chunks/chunk-VJN7KU4J.ts +350 -0
- package/dist/chunks/chunk-VJN7KU4J.ts.map +7 -0
- package/dist/chunks/chunk-YHT4YTYG.ts +31 -0
- package/dist/chunks/chunk-YHT4YTYG.ts.map +7 -0
- package/dist/chunks/{chunk-A3TFXY4O.ts → chunk-YK52VDXG.ts} +6 -5
- package/dist/chunks/chunk-YK52VDXG.ts.map +7 -0
- package/dist/chunks/config-KGIYTTXQ.ts +37 -0
- package/dist/chunks/{conflict-artifacts-4CZFB7WI.ts → conflict-artifacts-FXFIIBCB.ts} +8 -7
- package/dist/chunks/{conflict-review-ZOTOHL2E.ts → conflict-review-6WIEQLXW.ts} +31 -25
- package/dist/chunks/{conflict-review-ZOTOHL2E.ts.map → conflict-review-6WIEQLXW.ts.map} +1 -1
- package/dist/chunks/continuous-record-LFRVXQBD.ts +30 -0
- package/dist/chunks/continuous-sync-AWAAOXK2.ts +545 -0
- package/dist/chunks/continuous-sync-AWAAOXK2.ts.map +7 -0
- package/dist/chunks/{file-selection-UNHBVVON.ts → file-selection-3JJYOVNR.ts} +5 -5
- package/dist/chunks/{git-backend-FD7AVSK6.ts → git-backend-KYDZ673X.ts} +28 -32
- package/dist/chunks/git-backend-KYDZ673X.ts.map +7 -0
- package/dist/chunks/{manager-result-dispatcher-HVRTPEVK.ts → manager-result-dispatcher-AGBBVDDS.ts} +10 -9
- package/dist/chunks/{manager-ui-ZIN4BUSF.ts → manager-ui-KRAW3NE2.ts} +184 -45
- package/dist/chunks/manager-ui-KRAW3NE2.ts.map +7 -0
- package/dist/chunks/{merge-baseline-store-ICXVTCML.ts → merge-baseline-store-RFCAH7KL.ts} +5 -5
- package/dist/chunks/{remote-selection-ui-H6AEVA3Q.ts → remote-selection-ui-5725JDNC.ts} +9 -8
- package/dist/chunks/remote-selection-ui-5725JDNC.ts.map +7 -0
- package/dist/chunks/{s3-backend-Y4P3O5B5.ts → s3-backend-Y7WSCLJI.ts} +38 -38
- package/dist/chunks/s3-backend-Y7WSCLJI.ts.map +7 -0
- package/dist/chunks/{setup-switch-ZMW5C4M7.ts → setup-switch-E7PHKI6J.ts} +7 -6
- package/dist/chunks/setup-switch-E7PHKI6J.ts.map +7 -0
- package/dist/chunks/{setup-wizard-VW7F3JN4.ts → setup-wizard-65DROCIJ.ts} +14 -13
- package/dist/chunks/setup-wizard-65DROCIJ.ts.map +7 -0
- package/dist/chunks/{sync-inspection-3EMS2J5B.ts → sync-inspection-XFJOAMJD.ts} +8 -8
- package/dist/chunks/sync-inspection-XFJOAMJD.ts.map +7 -0
- package/dist/chunks/{sync-operations-2CWST333.ts → sync-operations-HDUDT5PD.ts} +62 -63
- package/dist/chunks/sync-operations-HDUDT5PD.ts.map +7 -0
- package/dist/chunks/{webdav-backend-TBILVEQK.ts → webdav-backend-6K26F6LT.ts} +39 -48
- package/dist/chunks/webdav-backend-6K26F6LT.ts.map +7 -0
- package/dist/index.ts +165 -85
- package/dist/index.ts.map +3 -3
- package/docs/agent-mode-verification.md +99 -0
- package/docs/continuous-sync-verification.md +87 -0
- package/docs/settings.md +32 -247
- package/package.json +11 -5
- package/skills/configure-pi-sync/SKILL.md +54 -0
- package/skills/configure-pi-sync/references/configuration.md +650 -0
- package/src/backends/git/git-backend.ts +1 -4
- package/src/backends/git/git-runner.ts +1 -5
- package/src/backends/s3/s3-backend.ts +3 -25
- package/src/backends/s3/s3-client.ts +14 -2
- package/src/backends/snapshot-pointer.ts +27 -0
- package/src/backends/webdav/webdav-backend.ts +3 -29
- package/src/backends/webdav/webdav-client.ts +11 -7
- package/src/commands/command-execution.ts +5 -2
- package/src/commands/command-handler.ts +15 -3
- package/src/commands/command-types.ts +6 -0
- package/src/commands/command.ts +1 -0
- package/src/settings/config.ts +7 -0
- package/src/settings/settings-store.ts +0 -34
- package/src/settings/settings-types.ts +8 -0
- package/src/settings/settings-validation.ts +1 -1
- package/src/snapshot/snapshot-codec.ts +1 -5
- package/src/state/lock.ts +13 -10
- package/src/state/merge-baseline-store.ts +2 -2
- package/src/state/state-directory.ts +8 -1
- package/src/sync/agent-candidate.ts +251 -0
- package/src/sync/agent-plan.ts +87 -0
- package/src/sync/agent-policy.ts +13 -0
- package/src/sync/agent-request.ts +17 -0
- package/src/sync/agent-runner.ts +188 -0
- package/src/sync/agent-store.ts +151 -0
- package/src/sync/agent-sync.ts +91 -0
- package/src/sync/automatic-sync.ts +2 -1
- package/src/sync/continuous-errors.ts +85 -0
- package/src/sync/continuous-lease.ts +221 -0
- package/src/sync/continuous-record.ts +179 -0
- package/src/sync/continuous-storage.ts +55 -0
- package/src/sync/continuous-sync.ts +516 -0
- package/src/sync/continuous-watch.ts +59 -0
- package/src/sync/merged-sync.ts +70 -12
- package/src/sync/remote-snapshot.ts +2 -3
- package/src/sync/settings-merge.ts +19 -3
- package/src/sync/setup-switch.ts +1 -5
- package/src/sync/startup-check.ts +15 -11
- package/src/sync/sync-inspection.ts +8 -1
- package/src/sync/sync-mutations.ts +6 -17
- package/src/sync/sync-queries.ts +5 -0
- package/src/sync/text-merge.ts +3 -3
- package/src/sync-extension.ts +75 -19
- package/src/ui/agent-mode-setting.ts +91 -0
- package/src/ui/manager-state.ts +2 -0
- package/src/ui/remote-selection-ui.ts +5 -5
- package/src/ui/settings-ui.ts +83 -1
- package/src/ui/setup/s3-credentials-ui.ts +1 -5
- package/src/ui/setup/setup-name-ui.ts +2 -5
- package/src/ui/setup/setup-switcher.ts +2 -0
- package/src/ui/sync-setups-ui.ts +3 -5
- package/dist/chunks/chunk-26PMXY7E.ts +0 -362
- package/dist/chunks/chunk-26PMXY7E.ts.map +0 -7
- package/dist/chunks/chunk-35GM6XKM.ts.map +0 -7
- package/dist/chunks/chunk-A3TFXY4O.ts.map +0 -7
- package/dist/chunks/chunk-BVVP33U5.ts.map +0 -7
- package/dist/chunks/chunk-CAGJOKB7.ts.map +0 -7
- package/dist/chunks/chunk-E6ONFG57.ts.map +0 -7
- package/dist/chunks/chunk-GC3QOL6J.ts.map +0 -7
- package/dist/chunks/chunk-I4JYVFUS.ts.map +0 -7
- package/dist/chunks/chunk-KATKRR3D.ts.map +0 -7
- package/dist/chunks/chunk-XU2VXGQV.ts.map +0 -7
- package/dist/chunks/chunk-YTHQEW35.ts.map +0 -7
- package/dist/chunks/chunk-ZX2Q6THB.ts.map +0 -7
- package/dist/chunks/git-backend-FD7AVSK6.ts.map +0 -7
- package/dist/chunks/manager-ui-ZIN4BUSF.ts.map +0 -7
- package/dist/chunks/s3-backend-Y4P3O5B5.ts.map +0 -7
- package/dist/chunks/setup-wizard-VW7F3JN4.ts.map +0 -7
- package/dist/chunks/sync-operations-2CWST333.ts.map +0 -7
- package/dist/chunks/webdav-backend-TBILVEQK.ts.map +0 -7
- /package/dist/chunks/{conflict-artifacts-4CZFB7WI.ts.map → agent-candidate-3JN6DJKT.ts.map} +0 -0
- /package/dist/chunks/{chunk-R35N4CL3.ts.map → chunk-B4QZBDBT.ts.map} +0 -0
- /package/dist/chunks/{chunk-KGE47GCZ.ts.map → chunk-CRKTAPSL.ts.map} +0 -0
- /package/dist/chunks/{chunk-HMXUKU43.ts.map → chunk-EUMINX7L.ts.map} +0 -0
- /package/dist/chunks/{chunk-AAZDBIBJ.ts.map → chunk-GSNPASKB.ts.map} +0 -0
- /package/dist/chunks/{chunk-2FETCGGT.ts.map → chunk-OEWQVWLC.ts.map} +0 -0
- /package/dist/chunks/{chunk-VCL7TZYW.ts.map → chunk-UPNVIUBN.ts.map} +0 -0
- /package/dist/chunks/{manager-result-dispatcher-HVRTPEVK.ts.map → config-KGIYTTXQ.ts.map} +0 -0
- /package/dist/chunks/{merge-baseline-store-ICXVTCML.ts.map → conflict-artifacts-FXFIIBCB.ts.map} +0 -0
- /package/dist/chunks/{remote-selection-ui-H6AEVA3Q.ts.map → continuous-record-LFRVXQBD.ts.map} +0 -0
- /package/dist/chunks/{file-selection-UNHBVVON.ts.map → file-selection-3JJYOVNR.ts.map} +0 -0
- /package/dist/chunks/{setup-switch-ZMW5C4M7.ts.map → manager-result-dispatcher-AGBBVDDS.ts.map} +0 -0
- /package/dist/chunks/{sync-inspection-3EMS2J5B.ts.map → merge-baseline-store-RFCAH7KL.ts.map} +0 -0
package/dist/index.ts.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/ui/operation-dialogs.ts", "../src/commands/command-execution.ts", "../src/commands/command-handler.ts", "../src/settings/config-errors.ts", "../src/sync/automatic-sync.ts", "../src/sync/startup-check.ts", "../src/sync/sync-loaders.ts", "../src/sync-extension.ts"],
|
|
4
|
-
"sourcesContent": ["import type { ExtensionContext } from \"@earendil-works/pi-coding-agent\";\n\n/** Track History's Pi-owned selector/confirmation lifetime without inspecting renderer internals. */\nexport function trackOperationDialogs<Context extends ExtensionContext>(\n ctx: Context,\n onDialog?: (active: boolean) => void,\n): Context {\n if (!onDialog) return ctx;\n const runDialog = async <Value>(task: () => Promise<Value>): Promise<Value> => {\n onDialog(true);\n try {\n return await task();\n } finally {\n onDialog(false);\n }\n };\n const ui: ExtensionContext[\"ui\"] = {\n ...ctx.ui,\n select: (...args) => runDialog(() => ctx.ui.select(...args)),\n confirm: (...args) => runDialog(() => ctx.ui.confirm(...args)),\n };\n // Forward live context properties: copying the context would hide session\n // replacement from mutation-owner revalidation after a dialog settles.\n return new Proxy(ctx, {\n get(target, key, receiver) {\n return key === \"ui\" ? ui : Reflect.get(target, key, receiver);\n },\n });\n}\n", "import type { ExtensionCommandContext, ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport { loadConfig, sessionTokenWarnings, syncSessionsWarnings } from \"../settings/config.js\";\nimport { activeLocalConfigPath, createLocalConfigDocument, localConfigPath } from \"../settings/config-file.js\";\nimport { localConfigTemplate, readLocalConfigObject } from \"../settings/settings-store.js\";\nimport type { AnySyncConfig } from \"../settings/settings-types.js\";\nimport { unlock, withLock } from \"../state/lock.js\";\nimport { migrateLegacyStateDirectory, stateDirectoryMigrationNotice } from \"../state/state-directory.js\";\nimport { throwIfAborted } from \"../sync/signals.js\";\nimport { syncErrorGuidance } from \"../sync/sync-error-guidance.js\";\nimport { isSyncDecisionRequiredError, SetupPullRequiresUiError } from \"../sync/sync-errors.js\";\nimport type { SyncLoaders } from \"../sync/sync-loaders.js\";\nimport { RemoteSelectionMismatchError } from \"../sync/sync-policy.js\";\nimport { automaticSyncSummary } from \"../ui/automatic-sync-summary.js\";\nimport type { RunRouteResult } from \"../ui/cancellable-operation.js\";\nimport { trackOperationDialogs } from \"../ui/operation-dialogs.js\";\nimport { startupTransferSummary } from \"../ui/sync-behavior.js\";\nimport { setSyncStatus } from \"../ui/sync-status.js\";\nimport { safeTerminalText } from \"../ui/terminal-text.js\";\nimport { parseOptions, resolveSyncCommand, splitArgs, usage, validateCommandOptions } from \"./command.js\";\nimport type { CommandOptions } from \"./command-types.js\";\n\nexport async function executeRecoveryCommand(\n rawArgs: string,\n ctx: ExtensionContext,\n signal: AbortSignal | undefined,\n loaders: SyncLoaders,\n onCommit?: () => void,\n setup?: string,\n): Promise<RunRouteResult> {\n try {\n const [subcommand, ...rest] = splitArgs(rawArgs);\n if (subcommand !== \"sync\" && subcommand !== \"pull\" && subcommand !== \"push\") {\n throw new Error(`Unsupported sync recovery route: ${subcommand ?? \"missing\"}`);\n }\n const options = parseOptions(rest);\n if (setup !== undefined) options.setup = setup;\n if (signal) options.signal = signal;\n if (onCommit) options.onCommit = onCommit;\n options.reload = false;\n options.auto = false;\n validateCommandOptions(subcommand, options);\n const operations = await loaders.operations();\n throwIfAborted(options.signal);\n if (subcommand === \"push\") {\n const outcome = await withLock(\"push\", () => operations.push(ctx, options));\n return { kind: \"completed\", ...(outcome ? { outcome } : {}) };\n }\n if (subcommand === \"pull\") {\n const outcome = await withLock(\"pull\", () => operations.pull(ctx, options));\n return { kind: \"completed\", ...(outcome ? { outcome } : {}) };\n }\n await withLock(\"sync\", () => operations.syncBoth(ctx, options));\n return { kind: \"completed\" };\n } catch (error) {\n if (signal?.aborted) return { kind: \"failed\" };\n setSyncStatus(ctx, undefined);\n if (error instanceof RemoteSelectionMismatchError) {\n return { kind: \"remote-selection-required\", decision: error.decision };\n }\n if (isSyncDecisionRequiredError(error)) {\n return { kind: \"decision-required\", decision: error.decision };\n }\n ctx.ui.notify(syncErrorGuidance(error), \"error\");\n return { kind: \"failed\" };\n }\n}\n\nexport async function executeCommand(\n rawArgs: string,\n ctx: ExtensionCommandContext,\n signal: AbortSignal | undefined,\n loaders: SyncLoaders,\n onCommit?: () => void,\n setup?: string,\n onDialog?: (active: boolean) => void,\n): Promise<RunRouteResult> {\n ctx = trackOperationDialogs(ctx, onDialog);\n try {\n const command = await resolveSyncCommand(rawArgs, ctx);\n if (signal?.aborted || !command) return { kind: \"completed\" };\n const { subcommand, rest } = command;\n const options = parseOptions(rest);\n if (setup !== undefined) options.setup = setup;\n if (signal) options.signal = signal;\n if (onCommit) options.onCommit = onCommit;\n validateCommandOptions(subcommand, options);\n\n switch (subcommand) {\n case \"help\":\n ctx.ui.notify(usage(), \"info\");\n return { kind: \"completed\" };\n case \"use\": {\n const { useSyncSetup } = await loaders.setupSwitch();\n throwIfAborted(options.signal);\n await useSyncSetup(\n ctx,\n options.args[0] ?? \"\",\n async (selectedSetup) => {\n const operations = await loaders.operations();\n throwIfAborted(options.signal);\n return withLock(\"pull\", () => operations.pull(ctx, { ...options, setup: selectedSetup }));\n },\n undefined,\n options.signal,\n );\n return { kind: \"completed\" };\n }\n case \"init\":\n await initConfig(ctx, signal);\n return { kind: \"completed\" };\n case \"config\":\n await showConfig(ctx, options);\n return { kind: \"completed\" };\n case \"files\": {\n const { showFileSelection } = await import(\"../ui/file-selection.js\");\n throwIfAborted(options.signal);\n await showFileSelection(ctx, options.setup, options.signal);\n return { kind: \"completed\" };\n }\n case \"status\": {\n const operations = await loaders.operations();\n throwIfAborted(options.signal);\n await operations.status(ctx, options);\n return { kind: \"completed\" };\n }\n case \"diff\": {\n const operations = await loaders.operations();\n throwIfAborted(options.signal);\n await operations.diff(ctx, options);\n return { kind: \"completed\" };\n }\n case \"conflicts\": {\n const { showConflicts } = await import(\"../sync/conflict-review.js\");\n throwIfAborted(options.signal);\n await withLock(\"sync\", () => showConflicts(ctx, options));\n return { kind: \"completed\" };\n }\n case \"doctor\": {\n const operations = await loaders.operations();\n throwIfAborted(options.signal);\n await operations.doctor(ctx, options);\n return { kind: \"completed\" };\n }\n case \"push\": {\n const operations = await loaders.operations();\n throwIfAborted(options.signal);\n const outcome = await withLock(\"push\", () => operations.push(ctx, options));\n return { kind: \"completed\", ...(outcome ? { outcome } : {}) };\n }\n case \"pull\": {\n const operations = await loaders.operations();\n throwIfAborted(options.signal);\n const outcome = await withLock(\"pull\", () => operations.pull(ctx, options));\n return { kind: \"completed\", ...(outcome ? { outcome } : {}) };\n }\n case \"sync\": {\n const operations = await loaders.operations();\n throwIfAborted(options.signal);\n await withLock(\"sync\", () => operations.syncBoth(ctx, options));\n return { kind: \"completed\" };\n }\n case \"history\": {\n const operations = await loaders.operations();\n throwIfAborted(options.signal);\n await operations.history(ctx, options);\n return { kind: \"completed\" };\n }\n case \"rollback\": {\n const operations = await loaders.operations();\n throwIfAborted(options.signal);\n await withLock(\"rollback\", () => operations.rollback(ctx, options));\n return { kind: \"completed\" };\n }\n case \"migrate-state\":\n await migrateStateDirectory(ctx, options);\n return { kind: \"completed\" };\n case \"unlock\":\n await unlock(ctx, options);\n return { kind: \"completed\" };\n default:\n ctx.ui.notify(`Unknown /sync command: ${subcommand}\\n\\n${usage()}`, \"warning\");\n return { kind: \"failed\" };\n }\n } catch (error) {\n if (signal?.aborted) return { kind: \"failed\" };\n setSyncStatus(ctx, undefined);\n if (error instanceof SetupPullRequiresUiError) throw error;\n if (error instanceof RemoteSelectionMismatchError) {\n return { kind: \"remote-selection-required\", decision: error.decision };\n }\n if (isSyncDecisionRequiredError(error)) {\n return { kind: \"decision-required\", decision: error.decision };\n }\n ctx.ui.notify(syncErrorGuidance(error), \"error\");\n return { kind: \"failed\" };\n }\n}\n\nasync function migrateStateDirectory(ctx: ExtensionCommandContext, options: CommandOptions) {\n const notice = stateDirectoryMigrationNotice();\n if (!notice) {\n ctx.ui.notify(\"pi-sync already uses the canonical pi-sync/ state directory.\", \"info\");\n return;\n }\n if (\n !options.yes &&\n !(await ctx.ui.confirm(\n \"Migrate pi-sync state directory\",\n \"Confirm that every other Pi process is closed. pi-sync will atomically rename .pisync/ to pi-sync/ without merging or deleting either root.\",\n { signal: options.signal },\n ))\n ) {\n ctx.ui.notify(\"pi-sync state migration cancelled.\", \"info\");\n return;\n }\n throwIfAborted(options.signal);\n const result = await migrateLegacyStateDirectory();\n throwIfAborted(options.signal);\n if (result.status === \"ready\") {\n ctx.ui.notify(\"pi-sync already uses the canonical pi-sync/ state directory.\", \"info\");\n return;\n }\n ctx.ui.notify(result.message, result.status === \"migrated\" ? \"info\" : \"warning\");\n}\n\nasync function initConfig(ctx: ExtensionCommandContext, signal?: AbortSignal) {\n const configPath = localConfigPath();\n if (await readLocalConfigObject()) {\n ctx.ui.notify(`Config already exists: ${await activeLocalConfigPath()}`, \"info\");\n return;\n }\n\n if (ctx.mode === \"tui\") {\n const { showSetupWizard } = await import(\"../ui/setup/setup-wizard.js\");\n throwIfAborted(signal);\n await showSetupWizard(ctx, signal);\n return;\n }\n await createLocalConfigDocument(localConfigTemplate());\n ctx.ui.notify(`Created ${configPath}. Add a storage connection and sync setup before syncing.`, \"info\");\n}\n\nasync function showConfig(ctx: ExtensionCommandContext, options: CommandOptions) {\n const config = await loadConfig(options.setup);\n const warnings = [\n ...(config.backend.type === \"s3\" ? sessionTokenWarnings(config.backend.profile) : []),\n ...syncSessionsWarnings(config),\n ];\n const storageLines = configStorageLines(config);\n ctx.ui.notify(\n [\n \"pi-sync config:\",\n `sync setup: ${config.setupName}`,\n `storage connection: ${config.connectionName}`,\n ...storageLines,\n `storage path: ${config.storagePath}`,\n `automatic sync: ${automaticSyncSummary(config.automatic)}`,\n `settings field merge: ${config.mergeSettings ? \"On (experimental)\" : \"Off\"}`,\n `machine-local settings.json fields: ${(config.localFields ?? []).map(safeTerminalText).join(\", \") || \"none\"}`,\n `startup transfer: ${startupTransferSummary(config)}`,\n `included content: ${config.include.join(\", \") || \"none\"}`,\n `sessions: ${config.include.includes(\"sessions\") ? \"included\" : \"not included\"}`,\n `settings file: ${localConfigPath()}`,\n ...warnings,\n ].join(\"\\n\"),\n warnings.length > 0 ? \"warning\" : \"info\",\n );\n}\n\nfunction configStorageLines(config: AnySyncConfig) {\n switch (config.backend.type) {\n case \"git\":\n return [\n \"kind: git\",\n `remote: ${displayGitRemote(config.backend.profile.remote)}`,\n \"authentication: existing Git/SSH credentials (not stored)\",\n `branch: ${config.backend.destination.branch}`,\n ];\n case \"webdav\":\n return [\n \"kind: webdav\",\n `url: ${displayWebDavUrl(config.backend.profile.url, config.backend.profile.username)}`,\n \"username: configured (value hidden)\",\n \"password: configured\",\n ];\n case \"s3\":\n return [\n \"kind: s3\",\n `endpoint: ${config.backend.profile.endpoint}`,\n `bucket: ${config.backend.destination.bucket}`,\n `region: ${config.backend.profile.region}`,\n \"access key id: configured\",\n \"secret access key: configured\",\n `session token: ${config.backend.profile.sessionToken ? \"configured\" : \"not configured\"}`,\n ];\n }\n}\n\nfunction displayGitRemote(value: string | undefined) {\n if (!value) return \"missing\";\n try {\n const url = new URL(value);\n url.username = \"\";\n url.password = \"\";\n url.search = \"\";\n url.hash = \"\";\n return url.toString();\n } catch {\n return value.replace(/^(?:[^@\\s]+@)?(?<host>[^:]+):.+$/u, \"$<host>:\u2026\");\n }\n}\n\nfunction displayWebDavUrl(value: string | undefined, username: string | undefined) {\n if (!value) return \"missing\";\n try {\n const url = new URL(value);\n url.username = \"\";\n url.password = \"\";\n url.search = \"\";\n url.hash = \"\";\n return username ? `${url.origin}/\u2026` : `${url.origin}${url.pathname}`;\n } catch {\n return \"invalid (value hidden)\";\n }\n}\n", "import type { ExtensionCommandContext, ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport { loadConfig } from \"../settings/config.js\";\nimport { readStateForConfig, syncStateFingerprint } from \"../state/sync-state-store.js\";\nimport { combineSignals } from \"../sync/signals.js\";\nimport { errorMessage } from \"../sync/sync-errors.js\";\nimport type { SyncLoaders } from \"../sync/sync-loaders.js\";\nimport { formatRemoteSelectionMismatch } from \"../sync/sync-policy.js\";\nimport type { RunRouteResult } from \"../ui/cancellable-operation.js\";\nimport {\n observationMatchesConfig,\n type SyncAttentionController,\n type SyncAttentionOrigin,\n syncAttentionMatchesConfig,\n} from \"../ui/sync-attention.js\";\nimport { setSyncStatus } from \"../ui/sync-status.js\";\nimport { parseOptions, splitArgs } from \"./command.js\";\nimport { executeCommand, executeRecoveryCommand } from \"./command-execution.js\";\n\nexport async function handleCommand(\n rawArgs: string,\n ctx: ExtensionCommandContext,\n sessionSignal: AbortSignal,\n loaders: SyncLoaders,\n attention: SyncAttentionController,\n) {\n await reconcileObservation(attention, sessionSignal);\n if (sessionSignal.aborted) return;\n const run = (\n route: string,\n signal?: AbortSignal,\n onCommit?: () => void,\n target?: string,\n onDialog?: (active: boolean) => void,\n ) =>\n executeCommand(\n route,\n ctx,\n combineSignals(sessionSignal, signal),\n loaders,\n observationCommitCallback(attention, sessionSignal, onCommit),\n target,\n onDialog,\n );\n if (!rawArgs.trim()) {\n try {\n const { showSyncManager } = await import(\"../ui/manager-ui.js\");\n if (sessionSignal.aborted) return;\n await showSyncManager(ctx, run, sessionSignal, {\n getAttention: () => attention.current(),\n getObservation: () => attention.observation(),\n onObservationInvalidated: () => attention.clearObservation(),\n onSelectionResolved: (expected) => {\n if (attention.current() === expected) attention.clear(ctx);\n },\n });\n } catch (error) {\n if (sessionSignal.aborted) return;\n setSyncStatus(ctx, undefined);\n ctx.ui.notify(errorMessage(error), \"error\");\n }\n await reconcileObservation(attention, sessionSignal);\n if (!sessionSignal.aborted) await attention.publish(ctx, sessionSignal);\n return;\n }\n const result = await run(rawArgs);\n if (result.kind === \"decision-required\") {\n ctx.ui.notify(result.decision.directMessage, \"error\");\n } else if (result.kind === \"remote-selection-required\") {\n const origin = directSelectionOrigin(rawArgs);\n if (origin) attention.set(result.decision, origin);\n const deterministic = splitArgs(rawArgs).some((arg) => arg === \"--yes\" || arg === \"-y\");\n if (origin && ctx.mode === \"tui\" && !deterministic) {\n await resolveSelectionAttention(ctx, attention, sessionSignal, loaders);\n } else {\n ctx.ui.notify(\n formatRemoteSelectionMismatch(\n result.decision.setupName,\n result.decision.localInclude,\n result.decision.remoteInclude,\n ),\n \"error\",\n );\n }\n }\n await clearAttentionAfterCompletedOperation(rawArgs, result, ctx, attention, sessionSignal);\n await reconcileSelectionAttention(ctx, attention, sessionSignal);\n await reconcileObservation(attention, sessionSignal);\n if (!sessionSignal.aborted) await attention.publish(ctx, sessionSignal);\n}\n\nfunction observationCommitCallback(\n attention: SyncAttentionController,\n sessionSignal: AbortSignal,\n onCommit?: () => void,\n) {\n const observed = attention.observation();\n return () => {\n // Opening or cancelling a review changes nothing. A commit may change data\n // even if later publication/baseline cleanup fails; never restore old hints.\n if (!sessionSignal.aborted && attention.observation() === observed) attention.clearObservation();\n onCommit?.();\n };\n}\n\nasync function reconcileObservation(attention: SyncAttentionController, signal: AbortSignal) {\n const observed = attention.observation();\n if (!observed || signal.aborted) return;\n try {\n const config = await loadConfig();\n if (signal.aborted || attention.observation() !== observed) return;\n if (!observationMatchesConfig(observed, config)) {\n attention.clearObservation();\n return;\n }\n const state = await readStateForConfig(config);\n if (signal.aborted || attention.observation() !== observed) return;\n if (syncStateFingerprint(state) !== observed.inspection.stateIdentity) attention.clearObservation();\n } catch {\n if (!signal.aborted && attention.observation() === observed) attention.clearObservation();\n }\n}\n\nasync function clearAttentionAfterCompletedOperation(\n rawArgs: string,\n result: RunRouteResult,\n ctx: ExtensionContext,\n attention: SyncAttentionController,\n signal: AbortSignal,\n) {\n if (result.kind !== \"completed\" || result.outcome === \"cancelled\" || signal.aborted) return;\n const [command, ...rest] = splitArgs(rawArgs);\n if (command !== \"sync\" && command !== \"pull\" && command !== \"push\") return;\n const current = attention.current();\n if (!current) return;\n try {\n const options = parseOptions(rest);\n const setupName = options.setup ?? (await loadConfig()).setupName;\n if (signal.aborted || attention.current() !== current) return;\n if (current.decision.setupName === setupName) attention.clear(ctx);\n } catch {\n // Attention reconciliation below owns malformed or concurrently changed settings.\n }\n}\n\nasync function reconcileSelectionAttention(\n ctx: ExtensionContext,\n attention: SyncAttentionController,\n signal: AbortSignal,\n) {\n const current = attention.current();\n if (!current || signal.aborted) return;\n try {\n const config = await loadConfig(current.decision.setupName);\n if (signal.aborted || attention.current() !== current) return;\n if (!syncAttentionMatchesConfig(current, config)) attention.clear(ctx);\n } catch {\n if (!signal.aborted && attention.current() === current) attention.clear(ctx);\n }\n}\n\nfunction directSelectionOrigin(rawArgs: string): SyncAttentionOrigin | undefined {\n const command = splitArgs(rawArgs)[0];\n return command === \"sync\" || command === \"pull\" || command === \"push\" ? command : undefined;\n}\n\nexport async function resolveSelectionAttention(\n ctx: ExtensionContext,\n attention: SyncAttentionController,\n signal: AbortSignal,\n loaders: SyncLoaders,\n options: {\n cancelLabel?: string;\n withStateAccess?: <T>(task: () => Promise<T>) => Promise<T>;\n } = {},\n) {\n const current = attention.current();\n if (!current || signal.aborted) return;\n const { dispatchManagerResult } = await import(\"../ui/manager-result-dispatcher.js\");\n if (signal.aborted || attention.current() !== current) return;\n await dispatchManagerResult(\n ctx,\n { kind: \"remote-selection-required\", decision: current.decision },\n current.origin,\n (route, actionSignal, onCommit, target) => {\n const execute = () =>\n executeRecoveryCommand(\n route,\n ctx,\n combineSignals(signal, actionSignal),\n loaders,\n observationCommitCallback(attention, signal, onCommit),\n target,\n );\n return options.withStateAccess ? options.withStateAccess(execute) : execute();\n },\n signal,\n {\n cancelLabel: options.cancelLabel,\n withStateAccess: options.withStateAccess,\n onSelectionResolved: () => {\n if (attention.current() === current) attention.clear(ctx);\n },\n },\n );\n}\n", "export function isMissingConfigError(error: unknown) {\n return (\n error instanceof Error &&\n (error.message.startsWith(\"Missing pi-sync settings.\") || error.message === \"No sync setups are configured.\")\n );\n}\n", "import type { ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport { setSyncSetupCompletions } from \"../commands/command.js\";\nimport type { CommandOptions } from \"../commands/command-types.js\";\nimport { loadConfig, loadPartialConfig } from \"../settings/config.js\";\nimport { isMissingConfigError } from \"../settings/config-errors.js\";\nimport { consumeLocalConfigMigrationNotice } from \"../settings/config-file.js\";\nimport { readLocalConfigObject } from \"../settings/settings-store.js\";\nimport { sessionDirFromContext, snapshotOptionsForContext } from \"../snapshot/session-paths.js\";\nimport { recoverSnapshotTransactionsOnStartup } from \"../snapshot/snapshot-transaction.js\";\nimport { withLock } from \"../state/lock.js\";\nimport { stateDirectoryMigrationNotice } from \"../state/state-directory.js\";\nimport { ensureStateDir, readStateForConfig } from \"../state/sync-state-store.js\";\nimport { configureSyncStatus, setSyncStatus } from \"../ui/sync-status.js\";\nimport { safeTerminalText } from \"../ui/terminal-text.js\";\nimport { throwIfAborted } from \"./signals.js\";\nimport { createStartupTimings } from \"./startup-timings.js\";\nimport { errorMessage } from \"./sync-errors.js\";\nimport type { SyncLoaders } from \"./sync-loaders.js\";\nimport { captureMutationOwner } from \"./sync-local.js\";\n\nconst AUTO_SYNC_OPTIONS: CommandOptions = {\n yes: true,\n force: false,\n stale: false,\n silent: true,\n reload: false,\n auto: true,\n args: [],\n};\n\nexport async function startSession(ctx: ExtensionContext, signal: AbortSignal) {\n const timings = createStartupTimings();\n let debug = false;\n let outcome: \"completed\" | \"stopped\" = \"stopped\";\n try {\n throwIfAborted(signal);\n const stateNotice = stateDirectoryMigrationNotice();\n if (stateNotice && ctx.hasUI) ctx.ui.notify(stateNotice, \"warning\");\n // Recovery can restore managed files: finish it before Pi accepts user edits.\n // Unlike remote inspection, it must never be detached behind startup.\n const validateMutation = captureMutationOwner(ctx, signal);\n const currentFile = ctx.sessionManager.getSessionFile?.();\n await timings.measure(\"transaction recovery\", () =>\n recoverSnapshotTransactionsOnStartup({\n signal,\n sessionDir: sessionDirFromContext(ctx),\n protectedTargets: currentFile ? [currentFile] : [],\n validateMutation,\n }),\n );\n throwIfAborted(signal);\n try {\n const settings = await timings.measure(\"settings read\", () => readLocalConfigObject());\n throwIfAborted(signal);\n debug = settings?.debug ?? false;\n const names = settings ? Object.keys(settings.syncSetups).sort((left, right) => left.localeCompare(right)) : [];\n setSyncSetupCompletions(names);\n configureSyncStatus(ctx, settings?.showStatus ?? true);\n } catch {\n if (signal.aborted) return;\n setSyncSetupCompletions([]);\n }\n const migrationNotice = consumeLocalConfigMigrationNotice();\n if (migrationNotice && ctx.hasUI) ctx.ui.notify(migrationNotice, \"warning\");\n throwIfAborted(signal);\n if (!ctx.hasUI) return;\n try {\n const config = await timings.measure(\"config resolution\", () => loadConfig());\n throwIfAborted(signal);\n configureSyncStatus(ctx, config.showStatus);\n outcome = \"completed\";\n return config.automatic || config.automaticTransfer ? config : undefined;\n } catch (error) {\n throwIfAborted(signal);\n if (!isMissingConfigError(error)) {\n ctx.ui.notify(`pi-sync startup check skipped: ${safeTerminalText(errorMessage(error))}`, \"warning\");\n }\n }\n } finally {\n timings.publish(ctx, debug, signal, \"local initialization\", outcome);\n }\n}\n\nexport async function autoPushSessions(ctx: ExtensionContext, signal: AbortSignal, loaders: SyncLoaders) {\n try {\n const partial = await loadPartialConfig();\n throwIfAborted(signal);\n if (!partial.automatic) return;\n if (!partial.include.includes(\"sessions\")) return;\n await ensureStateDir();\n throwIfAborted(signal);\n const config = await loadConfig();\n throwIfAborted(signal);\n if (!config.include.includes(\"sessions\")) return;\n const [operations, snapshotModule, syncStateModule] = await Promise.all([\n loaders.operations(),\n loaders.snapshot(),\n loaders.syncState(),\n ]);\n throwIfAborted(signal);\n await withLock(\"auto-session-push\", async () => {\n throwIfAborted(signal);\n const state = await readStateForConfig(config);\n throwIfAborted(signal);\n const local = await snapshotModule.createSnapshot(config.snapshotIdentity, {\n ...snapshotOptionsForContext(ctx, config),\n signal,\n });\n throwIfAborted(signal);\n if (!syncStateModule.hasLocalChanges(local, state, config)) return;\n await operations.push(ctx, { ...AUTO_SYNC_OPTIONS, signal }, { config, state, local });\n });\n } catch (error) {\n if (signal.aborted || isMissingConfigError(error)) return;\n setSyncStatus(ctx, undefined);\n ctx.ui.notify(`pi-sync session push skipped: ${errorMessage(error)}`, \"warning\");\n }\n}\n", "import type { ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport { loadConfigForCheck, syncCheckConfigFingerprint } from \"../settings/config.js\";\nimport { isMissingConfigError } from \"../settings/config-errors.js\";\nimport type { AnySyncConfig } from \"../settings/settings-types.js\";\nimport { snapshotOptionsForContext } from \"../snapshot/session-paths.js\";\nimport { withLock } from \"../state/lock.js\";\nimport { withStateDirectoryAccess } from \"../state/state-directory.js\";\nimport { readStateForConfig, syncStateFingerprint } from \"../state/sync-state-store.js\";\nimport type { SyncAttentionController } from \"../ui/sync-attention.js\";\nimport { setSyncStatus } from \"../ui/sync-status.js\";\nimport { safeTerminalText } from \"../ui/terminal-text.js\";\nimport { combineSignals, throwIfAborted } from \"./signals.js\";\nimport { createStartupTimings } from \"./startup-timings.js\";\nimport { errorMessage } from \"./sync-errors.js\";\nimport type { SyncLoaders } from \"./sync-loaders.js\";\n\n/** One owned task per extension session, never keyed by the shared headless UI. */\nexport function createStartupCheck(loaders: SyncLoaders, attention: SyncAttentionController, timeoutMs = 30_000) {\n let active:\n | {\n controller: AbortController;\n promise: Promise<void>;\n owner: ExtensionContext[\"sessionManager\"];\n transfer: boolean;\n }\n | undefined;\n\n let pending: { ctx: ExtensionContext; signal: AbortSignal; config: AnySyncConfig } | undefined;\n\n const controllerApi = {\n async interrupt(ctx: ExtensionContext) {\n const task = active;\n if (!task?.transfer || task.owner !== ctx.sessionManager) return;\n task.controller.abort(new DOMException(\"Agent became busy\", \"AbortError\"));\n await task.promise;\n },\n settled(ctx: ExtensionContext) {\n const queued = pending;\n if (!queued || queued.ctx.sessionManager !== ctx.sessionManager || queued.signal.aborted || !ctx.isIdle()) return;\n pending = undefined;\n controllerApi.start(ctx, queued.signal, queued.config);\n },\n start(ctx: ExtensionContext, sessionSignal: AbortSignal, initialConfig?: AnySyncConfig) {\n if (!ctx.hasUI || sessionSignal.aborted) return;\n if (initialConfig?.automaticTransfer && !ctx.isIdle()) {\n pending = { ctx, signal: sessionSignal, config: initialConfig };\n return;\n }\n if (active) throw new Error(\"Previous startup check has not been drained.\");\n const timings = createStartupTimings();\n const controller = new AbortController();\n const signal = combineSignals(sessionSignal, controller.signal);\n const task = {\n controller,\n owner: ctx.sessionManager,\n promise: Promise.resolve(),\n transfer: Boolean(initialConfig?.automaticTransfer),\n };\n active = task;\n const isCurrent = () => !sessionSignal.aborted && active === task && task.owner === ctx.sessionManager;\n const timer = setTimeout(\n () => controller.abort(new DOMException(\"Startup check timed out\", \"TimeoutError\")),\n timeoutMs,\n );\n let config: AnySyncConfig | undefined;\n let checking = false;\n let stopped = false;\n // Handle every detached rejection here; Pi's awaited event runner cannot catch it.\n task.promise = Promise.resolve()\n .then(async () => {\n try {\n throwIfAborted(signal);\n config = initialConfig ?? (await loadConfigForCheck());\n task.transfer = Boolean(config.automaticTransfer);\n throwIfAborted(signal);\n if (!config.automatic && !config.automaticTransfer) return;\n const captured = config;\n const identity = syncCheckConfigFingerprint(captured);\n checking = true;\n setSyncStatus(ctx, \"sync ...\");\n const { inspectSync } = await timings.measure(\"inspection import\", () => loaders.inspection());\n throwIfAborted(signal);\n const currentConfig = await loadConfigForCheck();\n throwIfAborted(signal);\n if (syncCheckConfigFingerprint(currentConfig) !== identity) return;\n // Lock order: state migration guard \u2192 sync operation \u2192 backend cache.\n // Read heads may write only private cache data. Never call doctor/syncBoth.\n const inspection = await timings.measure(\"inspection and guards\", () =>\n withStateDirectoryAccess(() => {\n throwIfAborted(signal);\n return withLock(\"startup-check\", () => {\n throwIfAborted(signal);\n return inspectSync(captured, snapshotOptionsForContext(ctx, captured), signal, undefined, timings);\n });\n }),\n );\n throwIfAborted(signal);\n const latest = await loadConfigForCheck();\n throwIfAborted(signal);\n if (syncCheckConfigFingerprint(latest) !== identity) return;\n const state = await withStateDirectoryAccess(() => readStateForConfig(latest));\n throwIfAborted(signal);\n if (syncStateFingerprint(state) !== inspection.stateIdentity || !isCurrent()) return;\n attention.observe({\n setupName: captured.setupName,\n configIdentity: identity,\n checkedAt: new Date().toISOString(),\n inspection,\n automaticTransfer: captured.automaticTransfer,\n });\n if (\n captured.automaticTransfer &&\n !inspection.firstSync &&\n inspection.head &&\n inspection.selectionState?.kind === \"same\"\n ) {\n const operations = await timings.measure(\"operations import\", () => loaders.operations());\n throwIfAborted(signal);\n if (!isCurrent()) return;\n if (!ctx.isIdle()) {\n pending = { ctx, signal: sessionSignal, config: captured };\n return;\n }\n await timings.measure(\"automatic transfer\", () =>\n withStateDirectoryAccess(() =>\n withLock(\"startup-transfer\", () =>\n operations.syncBoth(ctx, {\n args: [],\n yes: true,\n force: false,\n stale: false,\n silent: true,\n reload: false,\n auto: true,\n signal,\n startupTimings: timings,\n onCommit: () => attention.clearObservation(),\n }),\n ),\n ),\n );\n throwIfAborted(signal);\n if (!isCurrent()) return;\n attention.clearObservation();\n return;\n }\n attention.observe({\n setupName: captured.setupName,\n configIdentity: identity,\n checkedAt: new Date().toISOString(),\n inspection,\n automaticTransfer: captured.automaticTransfer,\n });\n if (ctx.mode === \"rpc\") attention.notifyObservation(ctx);\n } catch (error) {\n stopped = true;\n if (!isCurrent() || sessionSignal.aborted || isMissingConfigError(error)) return;\n if (signal.aborted && controller.signal.reason?.name !== \"TimeoutError\") return;\n // A settings edit invalidates failures as well as successful observations.\n if (config) {\n const latest = await loadConfigForCheck().catch(() => undefined);\n if (!isCurrent() || (signal.aborted && controller.signal.reason?.name !== \"TimeoutError\")) return;\n if (!latest || syncCheckConfigFingerprint(latest) !== syncCheckConfigFingerprint(config)) return;\n }\n ctx.ui.notify(\n config?.automaticTransfer\n ? `pi-sync automatic transfer stopped: ${safeTerminalText(errorMessage(error))}. Run /sync to review or reconcile retained recovery evidence. No resources were reloaded.`\n : `pi-sync startup check skipped: ${safeTerminalText(errorMessage(error))}. Run /sync status to retry. No startup transfer was performed.`,\n \"warning\",\n );\n } finally {\n clearTimeout(timer);\n if (isCurrent() && checking) {\n if (!signal.aborted || controller.signal.reason?.name === \"TimeoutError\") {\n const latest = await loadConfigForCheck().catch(() => undefined);\n if (isCurrent()) {\n if (signal.aborted && controller.signal.reason?.name !== \"TimeoutError\")\n setSyncStatus(ctx, undefined);\n else if (\n config &&\n latest &&\n syncCheckConfigFingerprint(latest) === syncCheckConfigFingerprint(config)\n )\n await attention.publish(ctx, sessionSignal);\n else attention.reset(ctx);\n }\n } else setSyncStatus(ctx, undefined);\n }\n if (isCurrent()) {\n timings.publish(\n ctx,\n config?.debug ?? false,\n sessionSignal,\n \"background startup\",\n signal.aborted || stopped ? \"stopped\" : \"completed\",\n );\n }\n if (active === task) active = undefined;\n }\n })\n .catch(() => {\n // UI teardown can itself throw. No unhandled rejection or retained timer.\n clearTimeout(timer);\n if (active === task) active = undefined;\n });\n },\n async stop() {\n pending = undefined;\n const task = active;\n if (!task) return;\n task.controller.abort(new DOMException(\"Startup check cancelled\", \"AbortError\"));\n // Drain the actual work, including child/ref cleanup, before foreground guards.\n await task.promise;\n },\n };\n return controllerApi;\n}\n", "type SetupSwitchModule = Pick<typeof import(\"./setup-switch.js\"), \"useSyncSetup\">;\ntype SnapshotModule = Pick<typeof import(\"../snapshot/snapshot.js\"), \"createSnapshot\">;\ntype SyncStateModule = Pick<typeof import(\"./sync-state.js\"), \"hasLocalChanges\">;\ntype SyncOperations = typeof import(\"./sync-operations.js\");\n\ntype SyncInspectionModule = Pick<typeof import(\"./sync-inspection.js\"), \"inspectSync\">;\n\nexport interface SyncDependencies {\n loadSyncInspection(): Promise<SyncInspectionModule>;\n loadSetupSwitch(): Promise<SetupSwitchModule>;\n loadSnapshot(): Promise<SnapshotModule>;\n loadSyncState(): Promise<SyncStateModule>;\n loadSyncOperations(): Promise<SyncOperations>;\n}\n\nexport interface SyncLoaders {\n inspection(): Promise<SyncInspectionModule>;\n setupSwitch(): Promise<SetupSwitchModule>;\n snapshot(): Promise<SnapshotModule>;\n syncState(): Promise<SyncStateModule>;\n operations(): Promise<SyncOperations>;\n}\n\nexport function createSyncLoaders(dependencies: Partial<SyncDependencies>): SyncLoaders {\n const loaders: SyncLoaders = {\n inspection: cachedModuleLoader(dependencies.loadSyncInspection ?? (() => import(\"./sync-inspection.js\"))),\n setupSwitch: cachedModuleLoader(dependencies.loadSetupSwitch ?? (() => import(\"./setup-switch.js\"))),\n snapshot: cachedModuleLoader(dependencies.loadSnapshot ?? (() => import(\"../snapshot/snapshot.js\"))),\n syncState: cachedModuleLoader(dependencies.loadSyncState ?? (() => import(\"./sync-state.js\"))),\n operations: cachedModuleLoader(dependencies.loadSyncOperations ?? (() => import(\"./sync-operations.js\"))),\n };\n return loaders;\n}\n\nfunction cachedModuleLoader<Module>(load: () => Promise<Module>): () => Promise<Module> {\n let pending: Promise<Module> | undefined;\n return () => {\n if (!pending) {\n pending = load().catch((error) => {\n pending = undefined;\n throw error;\n });\n }\n return pending;\n };\n}\n", "import type { ExtensionAPI } from \"@earendil-works/pi-coding-agent\";\nimport { completeSyncArguments, splitArgs } from \"./commands/command.js\";\nimport { handleCommand } from \"./commands/command-handler.js\";\nimport type { AnySyncConfig } from \"./settings/settings-types.js\";\nimport { withStateDirectoryAccess } from \"./state/state-directory.js\";\nimport { autoPushSessions, startSession } from \"./sync/automatic-sync.js\";\nimport { combineSignals } from \"./sync/signals.js\";\nimport { createStartupCheck } from \"./sync/startup-check.js\";\nimport { errorMessage } from \"./sync/sync-errors.js\";\nimport { createSyncLoaders, type SyncDependencies } from \"./sync/sync-loaders.js\";\nimport { createSyncAttentionController } from \"./ui/sync-attention.js\";\nimport { setSyncStatus } from \"./ui/sync-status.js\";\nimport { safeTerminalText } from \"./ui/terminal-text.js\";\n\nexport default function sync(pi: ExtensionAPI, dependencies: Partial<SyncDependencies> = {}) {\n const loaders = createSyncLoaders(dependencies);\n const attention = createSyncAttentionController();\n const check = createStartupCheck(loaders, attention);\n let sessionAbort = new AbortController();\n let shutdownAbort: AbortController | undefined;\n let initialization = Promise.resolve<AnySyncConfig | false | undefined>(undefined);\n\n pi.registerCommand(\"sync\", {\n description: \"Sync Pi settings through Git, WebDAV, R2, or S3-compatible storage\",\n getArgumentCompletions: completeSyncArguments,\n handler: async (args, ctx) => {\n if (!ctx.hasUI) {\n throw new Error(\"/sync requires TUI or RPC mode so results and safety prompts are observable.\");\n }\n const signal = sessionAbort.signal;\n const ready = await initialization;\n if (signal.aborted) return;\n await check.stop();\n if (signal.aborted) return;\n const command = splitArgs(args)[0];\n if (ready === false && command !== \"help\" && command !== \"unlock\" && command !== \"migrate-state\") {\n ctx.ui.notify(\n \"pi-sync recovery required. Repair the startup error, then /reload before syncing. Use /sync help for recovery guidance.\",\n \"error\",\n );\n return;\n }\n const run = () => handleCommand(args, ctx, signal, loaders, attention);\n // Drain background cache/child cleanup before entering any foreground guard.\n // Help must remain reachable when the state roots themselves need repair.\n if (command === \"migrate-state\" || command === \"help\") await run();\n else await withStateDirectoryAccess(run);\n },\n });\n\n pi.on(\"session_start\", async (_event, ctx) => {\n shutdownAbort?.abort(new DOMException(\"Session replaced\", \"AbortError\"));\n shutdownAbort = undefined;\n sessionAbort.abort(new DOMException(\"Session replaced\", \"AbortError\"));\n sessionAbort = new AbortController();\n const signal = sessionAbort.signal;\n attention.reset(ctx);\n const previous = initialization;\n initialization = (async () => {\n await previous;\n if (signal.aborted) return false;\n await check.stop();\n if (signal.aborted) return false;\n try {\n const config = await withStateDirectoryAccess(() => startSession(ctx, signal));\n return signal.aborted ? false : config;\n } catch (error) {\n if (!signal.aborted && ctx.hasUI) {\n ctx.ui.notify(`pi-sync recovery required: ${safeTerminalText(errorMessage(error))}`, \"error\");\n }\n return false;\n }\n })();\n const ready = await initialization;\n if (ready && !signal.aborted) check.start(ctx, signal, ready);\n });\n\n pi.on(\"agent_start\", async (_event, ctx) => {\n await check.interrupt(ctx);\n });\n\n pi.on(\"agent_settled\", (_event, ctx) => {\n if (!sessionAbort.signal.aborted) check.settled(ctx);\n });\n\n pi.on(\"session_shutdown\", async (event, ctx) => {\n sessionAbort.abort(new DOMException(\"Session shut down\", \"AbortError\"));\n attention.reset(ctx);\n shutdownAbort?.abort(new DOMException(\"Session shut down again\", \"AbortError\"));\n const controller = new AbortController();\n shutdownAbort = controller;\n const signal = combineSignals(controller.signal, AbortSignal.timeout(30_000));\n const reason = typeof event === \"object\" && event ? (event as { reason?: string }).reason : undefined;\n try {\n const ready = await initialization;\n if (signal.aborted) return;\n await check.stop();\n if (signal.aborted) return;\n if (ready !== false && reason !== \"reload\") {\n await withStateDirectoryAccess(async () => {\n if (signal.aborted) return;\n await autoPushSessions(ctx, signal, loaders);\n });\n }\n } catch (error) {\n if (!signal.aborted) {\n ctx.ui.notify(`pi-sync session push skipped: ${errorMessage(error)}`, \"warning\");\n }\n } finally {\n if (shutdownAbort === controller) shutdownAbort = undefined;\n }\n if (signal.aborted) return;\n setSyncStatus(ctx, undefined);\n });\n}\n\nexport type { SyncDependencies } from \"./sync/sync-loaders.js\";\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
4
|
+
"sourcesContent": ["import type { ExtensionContext } from \"@earendil-works/pi-coding-agent\";\n\n/** Track History's Pi-owned selector/confirmation lifetime without inspecting renderer internals. */\nexport function trackOperationDialogs<Context extends ExtensionContext>(\n ctx: Context,\n onDialog?: (active: boolean) => void,\n): Context {\n if (!onDialog) return ctx;\n const runDialog = async <Value>(task: () => Promise<Value>): Promise<Value> => {\n onDialog(true);\n try {\n return await task();\n } finally {\n onDialog(false);\n }\n };\n const ui: ExtensionContext[\"ui\"] = {\n ...ctx.ui,\n select: (...args) => runDialog(() => ctx.ui.select(...args)),\n confirm: (...args) => runDialog(() => ctx.ui.confirm(...args)),\n };\n // Forward live context properties: copying the context would hide session\n // replacement from mutation-owner revalidation after a dialog settles.\n return new Proxy(ctx, {\n get(target, key, receiver) {\n return key === \"ui\" ? ui : Reflect.get(target, key, receiver);\n },\n });\n}\n", "import type { ExtensionCommandContext, ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport { loadConfig, sessionTokenWarnings, syncSessionsWarnings } from \"../settings/config.js\";\nimport { activeLocalConfigPath, createLocalConfigDocument, localConfigPath } from \"../settings/config-file.js\";\nimport { localConfigTemplate, readLocalConfigObject } from \"../settings/settings-store.js\";\nimport type { AnySyncConfig } from \"../settings/settings-types.js\";\nimport { unlock, withLock } from \"../state/lock.js\";\nimport { migrateLegacyStateDirectory, stateDirectoryMigrationNotice } from \"../state/state-directory.js\";\nimport { withAgentSyncLock } from \"../sync/agent-sync.js\";\nimport { throwIfAborted } from \"../sync/signals.js\";\nimport { syncErrorGuidance } from \"../sync/sync-error-guidance.js\";\nimport { isSyncDecisionRequiredError, SetupPullRequiresUiError } from \"../sync/sync-errors.js\";\nimport type { SyncLoaders } from \"../sync/sync-loaders.js\";\nimport { RemoteSelectionMismatchError } from \"../sync/sync-policy.js\";\nimport { automaticSyncSummary } from \"../ui/automatic-sync-summary.js\";\nimport type { RunRouteResult } from \"../ui/cancellable-operation.js\";\nimport { trackOperationDialogs } from \"../ui/operation-dialogs.js\";\nimport { startupTransferSummary } from \"../ui/sync-behavior.js\";\nimport { setSyncStatus } from \"../ui/sync-status.js\";\nimport { safeTerminalText } from \"../ui/terminal-text.js\";\nimport { parseOptions, resolveSyncCommand, splitArgs, usage, validateCommandOptions } from \"./command.js\";\nimport type { CommandOptions } from \"./command-types.js\";\n\nexport async function executeRecoveryCommand(\n rawArgs: string,\n ctx: ExtensionContext,\n signal: AbortSignal | undefined,\n loaders: SyncLoaders,\n onCommit?: () => void,\n setup?: string,\n): Promise<RunRouteResult> {\n try {\n const [subcommand, ...rest] = splitArgs(rawArgs);\n if (subcommand !== \"sync\" && subcommand !== \"pull\" && subcommand !== \"push\") {\n throw new Error(`Unsupported sync recovery route: ${subcommand ?? \"missing\"}`);\n }\n const options = parseOptions(rest);\n if (setup !== undefined) options.setup = setup;\n if (signal) options.signal = signal;\n if (onCommit) options.onCommit = onCommit;\n options.reload = false;\n options.auto = false;\n validateCommandOptions(subcommand, options);\n const operations = await loaders.operations();\n throwIfAborted(options.signal);\n if (subcommand === \"push\") {\n const outcome = await withLock(\"push\", () => operations.push(ctx, options));\n return { kind: \"completed\", ...(outcome ? { outcome } : {}) };\n }\n if (subcommand === \"pull\") {\n const outcome = await withLock(\"pull\", () => operations.pull(ctx, options));\n return { kind: \"completed\", ...(outcome ? { outcome } : {}) };\n }\n await withAgentSyncLock(ctx, options, (current) => operations.syncBoth(ctx, current));\n return { kind: \"completed\" };\n } catch (error) {\n if (signal?.aborted) return { kind: \"failed\" };\n setSyncStatus(ctx, undefined);\n if (error instanceof RemoteSelectionMismatchError) {\n return { kind: \"remote-selection-required\", decision: error.decision };\n }\n if (isSyncDecisionRequiredError(error)) {\n return { kind: \"decision-required\", decision: error.decision };\n }\n ctx.ui.notify(syncErrorGuidance(error), \"error\");\n return { kind: \"failed\" };\n }\n}\n\nexport async function executeCommand(\n rawArgs: string,\n ctx: ExtensionCommandContext,\n signal: AbortSignal | undefined,\n loaders: SyncLoaders,\n onCommit?: () => void,\n setup?: string,\n onDialog?: (active: boolean) => void,\n): Promise<RunRouteResult> {\n ctx = trackOperationDialogs(ctx, onDialog);\n try {\n const command = await resolveSyncCommand(rawArgs, ctx);\n if (signal?.aborted || !command) return { kind: \"completed\" };\n const { subcommand, rest } = command;\n const options = parseOptions(rest);\n if (setup !== undefined) options.setup = setup;\n if (signal) options.signal = signal;\n if (onCommit) options.onCommit = onCommit;\n validateCommandOptions(subcommand, options);\n\n switch (subcommand) {\n case \"help\":\n ctx.ui.notify(usage(), \"info\");\n return { kind: \"completed\" };\n case \"use\": {\n const { useSyncSetup } = await loaders.setupSwitch();\n throwIfAborted(options.signal);\n await useSyncSetup(\n ctx,\n options.args[0] ?? \"\",\n async (selectedSetup) => {\n const operations = await loaders.operations();\n throwIfAborted(options.signal);\n return withLock(\"pull\", () => operations.pull(ctx, { ...options, setup: selectedSetup }));\n },\n undefined,\n options.signal,\n );\n return { kind: \"completed\" };\n }\n case \"init\":\n await initConfig(ctx, signal);\n return { kind: \"completed\" };\n case \"config\":\n await showConfig(ctx, options);\n return { kind: \"completed\" };\n case \"files\": {\n const { showFileSelection } = await import(\"../ui/file-selection.js\");\n throwIfAborted(options.signal);\n await showFileSelection(ctx, options.setup, options.signal);\n return { kind: \"completed\" };\n }\n case \"status\": {\n const operations = await loaders.operations();\n throwIfAborted(options.signal);\n await operations.status(ctx, options);\n return { kind: \"completed\" };\n }\n case \"diff\": {\n const operations = await loaders.operations();\n throwIfAborted(options.signal);\n await operations.diff(ctx, options);\n return { kind: \"completed\" };\n }\n case \"conflicts\": {\n const { showConflicts } = await import(\"../sync/conflict-review.js\");\n throwIfAborted(options.signal);\n await withLock(\"sync\", () => showConflicts(ctx, options));\n return { kind: \"completed\" };\n }\n case \"doctor\": {\n const operations = await loaders.operations();\n throwIfAborted(options.signal);\n await operations.doctor(ctx, options);\n return { kind: \"completed\" };\n }\n case \"push\": {\n const operations = await loaders.operations();\n throwIfAborted(options.signal);\n const outcome = await withLock(\"push\", () => operations.push(ctx, options));\n return { kind: \"completed\", ...(outcome ? { outcome } : {}) };\n }\n case \"pull\": {\n const operations = await loaders.operations();\n throwIfAborted(options.signal);\n const outcome = await withLock(\"pull\", () => operations.pull(ctx, options));\n return { kind: \"completed\", ...(outcome ? { outcome } : {}) };\n }\n case \"sync\": {\n const operations = await loaders.operations();\n throwIfAborted(options.signal);\n await withAgentSyncLock(ctx, options, (current) => operations.syncBoth(ctx, current));\n return { kind: \"completed\" };\n }\n case \"history\": {\n const operations = await loaders.operations();\n throwIfAborted(options.signal);\n await operations.history(ctx, options);\n return { kind: \"completed\" };\n }\n case \"rollback\": {\n const operations = await loaders.operations();\n throwIfAborted(options.signal);\n await withLock(\"rollback\", () => operations.rollback(ctx, options));\n return { kind: \"completed\" };\n }\n case \"migrate-state\":\n await migrateStateDirectory(ctx, options);\n return { kind: \"completed\" };\n case \"unlock\":\n await unlock(ctx, options);\n return { kind: \"completed\" };\n default:\n ctx.ui.notify(`Unknown /sync command: ${subcommand}\\n\\n${usage()}`, \"warning\");\n return { kind: \"failed\" };\n }\n } catch (error) {\n if (signal?.aborted) return { kind: \"failed\" };\n setSyncStatus(ctx, undefined);\n if (error instanceof SetupPullRequiresUiError) throw error;\n if (error instanceof RemoteSelectionMismatchError) {\n return { kind: \"remote-selection-required\", decision: error.decision };\n }\n if (isSyncDecisionRequiredError(error)) {\n return { kind: \"decision-required\", decision: error.decision };\n }\n ctx.ui.notify(syncErrorGuidance(error), \"error\");\n return { kind: \"failed\" };\n }\n}\n\nasync function migrateStateDirectory(ctx: ExtensionCommandContext, options: CommandOptions) {\n const notice = stateDirectoryMigrationNotice();\n if (!notice) {\n ctx.ui.notify(\"pi-sync already uses the canonical pi-sync/ state directory.\", \"info\");\n return;\n }\n if (\n !options.yes &&\n !(await ctx.ui.confirm(\n \"Migrate pi-sync state directory\",\n \"Confirm that every other Pi process is closed. pi-sync will atomically rename .pisync/ to pi-sync/ without merging or deleting either root.\",\n { signal: options.signal },\n ))\n ) {\n ctx.ui.notify(\"pi-sync state migration cancelled.\", \"info\");\n return;\n }\n throwIfAborted(options.signal);\n const result = await migrateLegacyStateDirectory();\n throwIfAborted(options.signal);\n if (result.status === \"ready\") {\n ctx.ui.notify(\"pi-sync already uses the canonical pi-sync/ state directory.\", \"info\");\n return;\n }\n ctx.ui.notify(result.message, result.status === \"migrated\" ? \"info\" : \"warning\");\n}\n\nasync function initConfig(ctx: ExtensionCommandContext, signal?: AbortSignal) {\n const configPath = localConfigPath();\n if (await readLocalConfigObject()) {\n ctx.ui.notify(`Config already exists: ${await activeLocalConfigPath()}`, \"info\");\n return;\n }\n\n if (ctx.mode === \"tui\") {\n const { showSetupWizard } = await import(\"../ui/setup/setup-wizard.js\");\n throwIfAborted(signal);\n await showSetupWizard(ctx, signal);\n return;\n }\n await createLocalConfigDocument(localConfigTemplate());\n ctx.ui.notify(`Created ${configPath}. Add a storage connection and sync setup before syncing.`, \"info\");\n}\n\nasync function showConfig(ctx: ExtensionCommandContext, options: CommandOptions) {\n const config = await loadConfig(options.setup);\n const warnings = [\n ...(config.backend.type === \"s3\" ? sessionTokenWarnings(config.backend.profile) : []),\n ...syncSessionsWarnings(config),\n ];\n const storageLines = configStorageLines(config);\n ctx.ui.notify(\n [\n \"pi-sync config:\",\n `sync setup: ${config.setupName}`,\n `storage connection: ${config.connectionName}`,\n ...storageLines,\n `storage path: ${config.storagePath}`,\n `automatic sync: ${automaticSyncSummary(config.automatic)}`,\n `settings field merge: ${config.mergeSettings ? \"On (experimental)\" : \"Off\"}`,\n `machine-local settings.json fields: ${(config.localFields ?? []).map(safeTerminalText).join(\", \") || \"none\"}`,\n `startup transfer: ${startupTransferSummary(config)}`,\n `agent mode: ${config.agentMode ? \"On (experimental)\" : \"Off\"}`,\n `continuous sync: ${config.continuous ? (config.agentMode ? \"On (experimental)\" : \"paused; Agent mode is Off\") : \"Off\"}`,\n `included content: ${config.include.join(\", \") || \"none\"}`,\n `sessions: ${config.include.includes(\"sessions\") ? \"included\" : \"not included\"}`,\n `settings file: ${localConfigPath()}`,\n ...warnings,\n ].join(\"\\n\"),\n warnings.length > 0 ? \"warning\" : \"info\",\n );\n}\n\nfunction configStorageLines(config: AnySyncConfig) {\n switch (config.backend.type) {\n case \"git\":\n return [\n \"kind: git\",\n `remote: ${displayGitRemote(config.backend.profile.remote)}`,\n \"authentication: existing Git/SSH credentials (not stored)\",\n `branch: ${config.backend.destination.branch}`,\n ];\n case \"webdav\":\n return [\n \"kind: webdav\",\n `url: ${displayWebDavUrl(config.backend.profile.url, config.backend.profile.username)}`,\n \"username: configured (value hidden)\",\n \"password: configured\",\n ];\n case \"s3\":\n return [\n \"kind: s3\",\n `endpoint: ${config.backend.profile.endpoint}`,\n `bucket: ${config.backend.destination.bucket}`,\n `region: ${config.backend.profile.region}`,\n \"access key id: configured\",\n \"secret access key: configured\",\n `session token: ${config.backend.profile.sessionToken ? \"configured\" : \"not configured\"}`,\n ];\n }\n}\n\nfunction displayGitRemote(value: string | undefined) {\n if (!value) return \"missing\";\n try {\n const url = new URL(value);\n url.username = \"\";\n url.password = \"\";\n url.search = \"\";\n url.hash = \"\";\n return url.toString();\n } catch {\n return value.replace(/^(?:[^@\\s]+@)?(?<host>[^:]+):.+$/u, \"$<host>:\u2026\");\n }\n}\n\nfunction displayWebDavUrl(value: string | undefined, username: string | undefined) {\n if (!value) return \"missing\";\n try {\n const url = new URL(value);\n url.username = \"\";\n url.password = \"\";\n url.search = \"\";\n url.hash = \"\";\n return username ? `${url.origin}/\u2026` : `${url.origin}${url.pathname}`;\n } catch {\n return \"invalid (value hidden)\";\n }\n}\n", "import type { ExtensionCommandContext, ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport { loadConfig } from \"../settings/config.js\";\nimport { readStateForConfig, syncStateFingerprint } from \"../state/sync-state-store.js\";\nimport { combineSignals } from \"../sync/signals.js\";\nimport { errorMessage } from \"../sync/sync-errors.js\";\nimport type { SyncLoaders } from \"../sync/sync-loaders.js\";\nimport { formatRemoteSelectionMismatch } from \"../sync/sync-policy.js\";\nimport type { RunRouteResult } from \"../ui/cancellable-operation.js\";\nimport {\n observationMatchesConfig,\n type SyncAttentionController,\n type SyncAttentionOrigin,\n syncAttentionMatchesConfig,\n} from \"../ui/sync-attention.js\";\nimport { setSyncStatus } from \"../ui/sync-status.js\";\nimport { parseOptions, splitArgs, validateCommandOptions } from \"./command.js\";\nimport { executeCommand, executeRecoveryCommand } from \"./command-execution.js\";\n\nexport async function handleCommand(\n rawArgs: string,\n ctx: ExtensionCommandContext,\n sessionSignal: AbortSignal,\n loaders: SyncLoaders,\n attention: SyncAttentionController,\n onExplicitSync?: (setup?: string) => void,\n) {\n await reconcileObservation(attention, sessionSignal);\n if (sessionSignal.aborted) return;\n const run = (\n route: string,\n signal?: AbortSignal,\n onCommit?: () => void,\n target?: string,\n onDialog?: (active: boolean) => void,\n ) => {\n const [command, ...args] = splitArgs(route);\n if (command === \"sync\") {\n try {\n const options = parseOptions(args);\n validateCommandOptions(\"sync\", options);\n onExplicitSync?.(target ?? options.setup);\n } catch {\n /* Invalid routes do not request an automatic retry. */\n }\n }\n return executeCommand(\n route,\n ctx,\n combineSignals(sessionSignal, signal),\n loaders,\n observationCommitCallback(attention, sessionSignal, onCommit),\n target,\n onDialog,\n );\n };\n if (!rawArgs.trim()) {\n try {\n const { showSyncManager } = await import(\"../ui/manager-ui.js\");\n if (sessionSignal.aborted) return;\n await showSyncManager(ctx, run, sessionSignal, {\n getAttention: () => attention.current(),\n getObservation: () => attention.observation(),\n onObservationInvalidated: () => attention.clearObservation(),\n onSelectionResolved: (expected) => {\n if (attention.current() === expected) attention.clear(ctx);\n },\n });\n } catch (error) {\n if (sessionSignal.aborted) return;\n setSyncStatus(ctx, undefined);\n ctx.ui.notify(errorMessage(error), \"error\");\n }\n await reconcileObservation(attention, sessionSignal);\n if (!sessionSignal.aborted) await attention.publish(ctx, sessionSignal);\n return;\n }\n const result = await run(rawArgs);\n if (result.kind === \"decision-required\") {\n ctx.ui.notify(result.decision.directMessage, \"error\");\n } else if (result.kind === \"remote-selection-required\") {\n const origin = directSelectionOrigin(rawArgs);\n if (origin) attention.set(result.decision, origin);\n const deterministic = splitArgs(rawArgs).some((arg) => arg === \"--yes\" || arg === \"-y\");\n if (origin && ctx.mode === \"tui\" && !deterministic) {\n await resolveSelectionAttention(ctx, attention, sessionSignal, loaders);\n } else {\n ctx.ui.notify(\n formatRemoteSelectionMismatch(\n result.decision.setupName,\n result.decision.localInclude,\n result.decision.remoteInclude,\n ),\n \"error\",\n );\n }\n }\n await clearAttentionAfterCompletedOperation(rawArgs, result, ctx, attention, sessionSignal);\n await reconcileSelectionAttention(ctx, attention, sessionSignal);\n await reconcileObservation(attention, sessionSignal);\n if (!sessionSignal.aborted) await attention.publish(ctx, sessionSignal);\n}\n\nfunction observationCommitCallback(\n attention: SyncAttentionController,\n sessionSignal: AbortSignal,\n onCommit?: () => void,\n) {\n const observed = attention.observation();\n return () => {\n // Opening or cancelling a review changes nothing. A commit may change data\n // even if later publication/baseline cleanup fails; never restore old hints.\n if (!sessionSignal.aborted && attention.observation() === observed) attention.clearObservation();\n onCommit?.();\n };\n}\n\nasync function reconcileObservation(attention: SyncAttentionController, signal: AbortSignal) {\n const observed = attention.observation();\n if (!observed || signal.aborted) return;\n try {\n const config = await loadConfig();\n if (signal.aborted || attention.observation() !== observed) return;\n if (!observationMatchesConfig(observed, config)) {\n attention.clearObservation();\n return;\n }\n const state = await readStateForConfig(config);\n if (signal.aborted || attention.observation() !== observed) return;\n if (syncStateFingerprint(state) !== observed.inspection.stateIdentity) attention.clearObservation();\n } catch {\n if (!signal.aborted && attention.observation() === observed) attention.clearObservation();\n }\n}\n\nasync function clearAttentionAfterCompletedOperation(\n rawArgs: string,\n result: RunRouteResult,\n ctx: ExtensionContext,\n attention: SyncAttentionController,\n signal: AbortSignal,\n) {\n if (result.kind !== \"completed\" || result.outcome === \"cancelled\" || signal.aborted) return;\n const [command, ...rest] = splitArgs(rawArgs);\n if (command !== \"sync\" && command !== \"pull\" && command !== \"push\") return;\n const current = attention.current();\n if (!current) return;\n try {\n const options = parseOptions(rest);\n const setupName = options.setup ?? (await loadConfig()).setupName;\n if (signal.aborted || attention.current() !== current) return;\n if (current.decision.setupName === setupName) attention.clear(ctx);\n } catch {\n // Attention reconciliation below owns malformed or concurrently changed settings.\n }\n}\n\nasync function reconcileSelectionAttention(\n ctx: ExtensionContext,\n attention: SyncAttentionController,\n signal: AbortSignal,\n) {\n const current = attention.current();\n if (!current || signal.aborted) return;\n try {\n const config = await loadConfig(current.decision.setupName);\n if (signal.aborted || attention.current() !== current) return;\n if (!syncAttentionMatchesConfig(current, config)) attention.clear(ctx);\n } catch {\n if (!signal.aborted && attention.current() === current) attention.clear(ctx);\n }\n}\n\nfunction directSelectionOrigin(rawArgs: string): SyncAttentionOrigin | undefined {\n const command = splitArgs(rawArgs)[0];\n return command === \"sync\" || command === \"pull\" || command === \"push\" ? command : undefined;\n}\n\nexport async function resolveSelectionAttention(\n ctx: ExtensionContext,\n attention: SyncAttentionController,\n signal: AbortSignal,\n loaders: SyncLoaders,\n options: {\n cancelLabel?: string;\n withStateAccess?: <T>(task: () => Promise<T>) => Promise<T>;\n } = {},\n) {\n const current = attention.current();\n if (!current || signal.aborted) return;\n const { dispatchManagerResult } = await import(\"../ui/manager-result-dispatcher.js\");\n if (signal.aborted || attention.current() !== current) return;\n await dispatchManagerResult(\n ctx,\n { kind: \"remote-selection-required\", decision: current.decision },\n current.origin,\n (route, actionSignal, onCommit, target) => {\n const execute = () =>\n executeRecoveryCommand(\n route,\n ctx,\n combineSignals(signal, actionSignal),\n loaders,\n observationCommitCallback(attention, signal, onCommit),\n target,\n );\n return options.withStateAccess ? options.withStateAccess(execute) : execute();\n },\n signal,\n {\n cancelLabel: options.cancelLabel,\n withStateAccess: options.withStateAccess,\n onSelectionResolved: () => {\n if (attention.current() === current) attention.clear(ctx);\n },\n },\n );\n}\n", "export function isMissingConfigError(error: unknown) {\n return (\n error instanceof Error &&\n (error.message.startsWith(\"Missing pi-sync settings.\") || error.message === \"No sync setups are configured.\")\n );\n}\n", "import type { ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport { setSyncSetupCompletions } from \"../commands/command.js\";\nimport type { CommandOptions } from \"../commands/command-types.js\";\nimport { loadConfig, loadPartialConfig } from \"../settings/config.js\";\nimport { isMissingConfigError } from \"../settings/config-errors.js\";\nimport { consumeLocalConfigMigrationNotice } from \"../settings/config-file.js\";\nimport { readLocalConfigObject } from \"../settings/settings-store.js\";\nimport { sessionDirFromContext, snapshotOptionsForContext } from \"../snapshot/session-paths.js\";\nimport { recoverSnapshotTransactionsOnStartup } from \"../snapshot/snapshot-transaction.js\";\nimport { withLock } from \"../state/lock.js\";\nimport { stateDirectoryMigrationNotice } from \"../state/state-directory.js\";\nimport { ensureStateDir, readStateForConfig } from \"../state/sync-state-store.js\";\nimport { configureSyncStatus, setSyncStatus } from \"../ui/sync-status.js\";\nimport { safeTerminalText } from \"../ui/terminal-text.js\";\nimport { startupTransferEnabled } from \"./agent-policy.js\";\nimport { throwIfAborted } from \"./signals.js\";\nimport { createStartupTimings } from \"./startup-timings.js\";\nimport { errorMessage } from \"./sync-errors.js\";\nimport type { SyncLoaders } from \"./sync-loaders.js\";\nimport { captureMutationOwner } from \"./sync-local.js\";\n\nconst AUTO_SYNC_OPTIONS: CommandOptions = {\n yes: true,\n force: false,\n stale: false,\n silent: true,\n reload: false,\n auto: true,\n args: [],\n};\n\nexport async function startSession(ctx: ExtensionContext, signal: AbortSignal) {\n const timings = createStartupTimings();\n let debug = false;\n let outcome: \"completed\" | \"stopped\" = \"stopped\";\n try {\n throwIfAborted(signal);\n const stateNotice = stateDirectoryMigrationNotice();\n if (stateNotice && ctx.hasUI) ctx.ui.notify(stateNotice, \"warning\");\n // Recovery can restore managed files: finish it before Pi accepts user edits.\n // Unlike remote inspection, it must never be detached behind startup.\n const validateMutation = captureMutationOwner(ctx, signal);\n const currentFile = ctx.sessionManager.getSessionFile?.();\n await timings.measure(\"transaction recovery\", () =>\n recoverSnapshotTransactionsOnStartup({\n signal,\n sessionDir: sessionDirFromContext(ctx),\n protectedTargets: currentFile ? [currentFile] : [],\n validateMutation,\n }),\n );\n throwIfAborted(signal);\n try {\n const settings = await timings.measure(\"settings read\", () => readLocalConfigObject());\n throwIfAborted(signal);\n debug = settings?.debug ?? false;\n const names = settings ? Object.keys(settings.syncSetups).sort((left, right) => left.localeCompare(right)) : [];\n setSyncSetupCompletions(names);\n configureSyncStatus(ctx, settings?.showStatus ?? true);\n } catch {\n if (signal.aborted) return;\n setSyncSetupCompletions([]);\n }\n const migrationNotice = consumeLocalConfigMigrationNotice();\n if (migrationNotice && ctx.hasUI) ctx.ui.notify(migrationNotice, \"warning\");\n throwIfAborted(signal);\n if (!ctx.hasUI) return;\n try {\n const config = await timings.measure(\"config resolution\", () => loadConfig());\n throwIfAborted(signal);\n configureSyncStatus(ctx, config.showStatus);\n outcome = \"completed\";\n return config.automatic || startupTransferEnabled(config) ? config : undefined;\n } catch (error) {\n throwIfAborted(signal);\n if (!isMissingConfigError(error)) {\n ctx.ui.notify(`pi-sync startup check skipped: ${safeTerminalText(errorMessage(error))}`, \"warning\");\n }\n }\n } finally {\n timings.publish(ctx, debug, signal, \"local initialization\", outcome);\n }\n}\n\nexport async function autoPushSessions(ctx: ExtensionContext, signal: AbortSignal, loaders: SyncLoaders) {\n try {\n const partial = await loadPartialConfig();\n throwIfAborted(signal);\n if (!partial.automatic) return;\n if (!partial.include.includes(\"sessions\")) return;\n await ensureStateDir();\n throwIfAborted(signal);\n const config = await loadConfig();\n throwIfAborted(signal);\n if (!config.include.includes(\"sessions\")) return;\n const [operations, snapshotModule, syncStateModule] = await Promise.all([\n loaders.operations(),\n loaders.snapshot(),\n loaders.syncState(),\n ]);\n throwIfAborted(signal);\n await withLock(\"auto-session-push\", async () => {\n throwIfAborted(signal);\n const state = await readStateForConfig(config);\n throwIfAborted(signal);\n const local = await snapshotModule.createSnapshot(config.snapshotIdentity, {\n ...snapshotOptionsForContext(ctx, config),\n signal,\n });\n throwIfAborted(signal);\n if (!syncStateModule.hasLocalChanges(local, state, config)) return;\n await operations.push(ctx, { ...AUTO_SYNC_OPTIONS, signal }, { config, state, local });\n });\n } catch (error) {\n if (signal.aborted || isMissingConfigError(error)) return;\n setSyncStatus(ctx, undefined);\n ctx.ui.notify(`pi-sync session push skipped: ${errorMessage(error)}`, \"warning\");\n }\n}\n", "import type { ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport { loadConfigForCheck, syncCheckConfigFingerprint } from \"../settings/config.js\";\nimport { isMissingConfigError } from \"../settings/config-errors.js\";\nimport type { AnySyncConfig } from \"../settings/settings-types.js\";\nimport { snapshotOptionsForContext } from \"../snapshot/session-paths.js\";\nimport { withLock } from \"../state/lock.js\";\nimport { withStateDirectoryAccess } from \"../state/state-directory.js\";\nimport { readStateForConfig, syncStateFingerprint } from \"../state/sync-state-store.js\";\nimport type { SyncAttentionController } from \"../ui/sync-attention.js\";\nimport { setSyncStatus } from \"../ui/sync-status.js\";\nimport { safeTerminalText } from \"../ui/terminal-text.js\";\nimport { startupTransferEnabled } from \"./agent-policy.js\";\nimport { withAgentSyncLock } from \"./agent-sync.js\";\nimport { combineSignals, throwIfAborted } from \"./signals.js\";\nimport { createStartupTimings } from \"./startup-timings.js\";\nimport { errorMessage } from \"./sync-errors.js\";\nimport type { SyncLoaders } from \"./sync-loaders.js\";\n\n/** One owned task per extension session, never keyed by the shared headless UI. */\nexport function createStartupCheck(loaders: SyncLoaders, attention: SyncAttentionController, timeoutMs = 30_000) {\n let active:\n | {\n controller: AbortController;\n promise: Promise<void>;\n owner: ExtensionContext[\"sessionManager\"];\n transfer: boolean;\n }\n | undefined;\n\n let pending: { ctx: ExtensionContext; signal: AbortSignal; config: AnySyncConfig } | undefined;\n\n const controllerApi = {\n async interrupt(ctx: ExtensionContext) {\n const task = active;\n if (!task?.transfer || task.owner !== ctx.sessionManager) return;\n task.controller.abort(new DOMException(\"Agent became busy\", \"AbortError\"));\n await task.promise;\n },\n settled(ctx: ExtensionContext) {\n const queued = pending;\n if (!queued || queued.ctx.sessionManager !== ctx.sessionManager || queued.signal.aborted || !ctx.isIdle()) return;\n pending = undefined;\n controllerApi.start(ctx, queued.signal, queued.config);\n },\n start(ctx: ExtensionContext, sessionSignal: AbortSignal, initialConfig?: AnySyncConfig) {\n if (!ctx.hasUI || sessionSignal.aborted) return;\n if (initialConfig && startupTransferEnabled(initialConfig) && !ctx.isIdle()) {\n pending = { ctx, signal: sessionSignal, config: initialConfig };\n return;\n }\n if (active) throw new Error(\"Previous startup check has not been drained.\");\n const timings = createStartupTimings();\n const controller = new AbortController();\n const signal = combineSignals(sessionSignal, controller.signal);\n const task = {\n controller,\n owner: ctx.sessionManager,\n promise: Promise.resolve(),\n transfer: Boolean(initialConfig && startupTransferEnabled(initialConfig)),\n };\n active = task;\n const isCurrent = () => !sessionSignal.aborted && active === task && task.owner === ctx.sessionManager;\n const timer = setTimeout(\n () => controller.abort(new DOMException(\"Startup check timed out\", \"TimeoutError\")),\n timeoutMs,\n );\n let config: AnySyncConfig | undefined;\n let checking = false;\n let stopped = false;\n // Handle every detached rejection here; Pi's awaited event runner cannot catch it.\n task.promise = Promise.resolve()\n .then(async () => {\n try {\n throwIfAborted(signal);\n config = initialConfig ?? (await loadConfigForCheck());\n task.transfer = startupTransferEnabled(config);\n throwIfAborted(signal);\n if (!config.automatic && !startupTransferEnabled(config)) return;\n const captured = config;\n const identity = syncCheckConfigFingerprint(captured);\n checking = true;\n setSyncStatus(ctx, \"sync ...\");\n const { inspectSync } = await timings.measure(\"inspection import\", () => loaders.inspection());\n throwIfAborted(signal);\n const currentConfig = await loadConfigForCheck();\n throwIfAborted(signal);\n if (syncCheckConfigFingerprint(currentConfig) !== identity) return;\n // Lock order: state migration guard \u2192 sync operation \u2192 backend cache.\n // Read heads may write only private cache data. Never call doctor/syncBoth.\n const inspection = await timings.measure(\"inspection and guards\", () =>\n withStateDirectoryAccess(() => {\n throwIfAborted(signal);\n return withLock(\"startup-check\", () => {\n throwIfAborted(signal);\n return inspectSync(captured, snapshotOptionsForContext(ctx, captured), signal, undefined, timings);\n });\n }),\n );\n throwIfAborted(signal);\n const latest = await loadConfigForCheck();\n throwIfAborted(signal);\n if (syncCheckConfigFingerprint(latest) !== identity) return;\n const state = await withStateDirectoryAccess(() => readStateForConfig(latest));\n throwIfAborted(signal);\n if (syncStateFingerprint(state) !== inspection.stateIdentity || !isCurrent()) return;\n attention.observe({\n setupName: captured.setupName,\n configIdentity: identity,\n checkedAt: new Date().toISOString(),\n inspection,\n automaticTransfer: startupTransferEnabled(captured),\n });\n if (\n startupTransferEnabled(captured) &&\n !inspection.firstSync &&\n inspection.head &&\n inspection.selectionState?.kind === \"same\"\n ) {\n const operations = await timings.measure(\"operations import\", () => loaders.operations());\n throwIfAborted(signal);\n if (!isCurrent()) return;\n if (!ctx.isIdle()) {\n pending = { ctx, signal: sessionSignal, config: captured };\n return;\n }\n await timings.measure(\"automatic transfer\", () =>\n withStateDirectoryAccess(() =>\n withAgentSyncLock(\n ctx,\n {\n args: [],\n yes: true,\n force: false,\n stale: false,\n silent: true,\n reload: false,\n auto: true,\n signal,\n startupTimings: timings,\n onCommit: () => attention.clearObservation(),\n },\n (options) => operations.syncBoth(ctx, options),\n ),\n ),\n );\n throwIfAborted(signal);\n if (!isCurrent()) return;\n attention.clearObservation();\n return;\n }\n attention.observe({\n setupName: captured.setupName,\n configIdentity: identity,\n checkedAt: new Date().toISOString(),\n inspection,\n automaticTransfer: startupTransferEnabled(captured),\n });\n if (ctx.mode === \"rpc\") attention.notifyObservation(ctx);\n } catch (error) {\n stopped = true;\n if (!isCurrent() || sessionSignal.aborted || isMissingConfigError(error)) return;\n if (signal.aborted && controller.signal.reason?.name !== \"TimeoutError\") return;\n // A settings edit invalidates failures as well as successful observations.\n if (config) {\n const latest = await loadConfigForCheck().catch(() => undefined);\n if (!isCurrent() || (signal.aborted && controller.signal.reason?.name !== \"TimeoutError\")) return;\n if (!latest || syncCheckConfigFingerprint(latest) !== syncCheckConfigFingerprint(config)) return;\n }\n ctx.ui.notify(\n config && startupTransferEnabled(config)\n ? `pi-sync automatic transfer stopped: ${safeTerminalText(errorMessage(error))}. Run /sync to review or reconcile retained recovery evidence. No resources were reloaded.`\n : `pi-sync startup check skipped: ${safeTerminalText(errorMessage(error))}. Run /sync status to retry. No startup transfer was performed.`,\n \"warning\",\n );\n } finally {\n clearTimeout(timer);\n if (isCurrent() && checking) {\n if (!signal.aborted || controller.signal.reason?.name === \"TimeoutError\") {\n const latest = await loadConfigForCheck().catch(() => undefined);\n if (isCurrent()) {\n if (signal.aborted && controller.signal.reason?.name !== \"TimeoutError\")\n setSyncStatus(ctx, undefined);\n else if (\n config &&\n latest &&\n syncCheckConfigFingerprint(latest) === syncCheckConfigFingerprint(config)\n )\n await attention.publish(ctx, sessionSignal);\n else attention.reset(ctx);\n }\n } else setSyncStatus(ctx, undefined);\n }\n if (isCurrent()) {\n timings.publish(\n ctx,\n config?.debug ?? false,\n sessionSignal,\n \"background startup\",\n signal.aborted || stopped ? \"stopped\" : \"completed\",\n );\n }\n if (active === task) active = undefined;\n }\n })\n .catch(() => {\n // UI teardown can itself throw. No unhandled rejection or retained timer.\n clearTimeout(timer);\n if (active === task) active = undefined;\n });\n },\n async stop() {\n pending = undefined;\n const task = active;\n if (!task) return;\n task.controller.abort(new DOMException(\"Startup check cancelled\", \"AbortError\"));\n // Drain the actual work, including child/ref cleanup, before foreground guards.\n await task.promise;\n },\n };\n return controllerApi;\n}\n", "type SetupSwitchModule = Pick<typeof import(\"./setup-switch.js\"), \"useSyncSetup\">;\ntype SnapshotModule = Pick<typeof import(\"../snapshot/snapshot.js\"), \"createSnapshot\">;\ntype SyncStateModule = Pick<typeof import(\"./sync-state.js\"), \"hasLocalChanges\">;\ntype SyncOperations = typeof import(\"./sync-operations.js\");\n\ntype SyncInspectionModule = Pick<typeof import(\"./sync-inspection.js\"), \"inspectSync\">;\n\nexport interface SyncDependencies {\n loadSyncInspection(): Promise<SyncInspectionModule>;\n loadSetupSwitch(): Promise<SetupSwitchModule>;\n loadSnapshot(): Promise<SnapshotModule>;\n loadSyncState(): Promise<SyncStateModule>;\n loadSyncOperations(): Promise<SyncOperations>;\n}\n\nexport interface SyncLoaders {\n inspection(): Promise<SyncInspectionModule>;\n setupSwitch(): Promise<SetupSwitchModule>;\n snapshot(): Promise<SnapshotModule>;\n syncState(): Promise<SyncStateModule>;\n operations(): Promise<SyncOperations>;\n}\n\nexport function createSyncLoaders(dependencies: Partial<SyncDependencies>): SyncLoaders {\n const loaders: SyncLoaders = {\n inspection: cachedModuleLoader(dependencies.loadSyncInspection ?? (() => import(\"./sync-inspection.js\"))),\n setupSwitch: cachedModuleLoader(dependencies.loadSetupSwitch ?? (() => import(\"./setup-switch.js\"))),\n snapshot: cachedModuleLoader(dependencies.loadSnapshot ?? (() => import(\"../snapshot/snapshot.js\"))),\n syncState: cachedModuleLoader(dependencies.loadSyncState ?? (() => import(\"./sync-state.js\"))),\n operations: cachedModuleLoader(dependencies.loadSyncOperations ?? (() => import(\"./sync-operations.js\"))),\n };\n return loaders;\n}\n\nfunction cachedModuleLoader<Module>(load: () => Promise<Module>): () => Promise<Module> {\n let pending: Promise<Module> | undefined;\n return () => {\n if (!pending) {\n pending = load().catch((error) => {\n pending = undefined;\n throw error;\n });\n }\n return pending;\n };\n}\n", "import type { ExtensionAPI, ExtensionContext } from \"@earendil-works/pi-coding-agent\";\nimport { completeSyncArguments, splitArgs } from \"./commands/command.js\";\nimport { handleCommand } from \"./commands/command-handler.js\";\nimport type { AnySyncConfig } from \"./settings/settings-types.js\";\nimport { withStateDirectoryAccess } from \"./state/state-directory.js\";\nimport { autoPushSessions, startSession } from \"./sync/automatic-sync.js\";\nimport { combineSignals } from \"./sync/signals.js\";\nimport { createStartupCheck } from \"./sync/startup-check.js\";\nimport { errorMessage } from \"./sync/sync-errors.js\";\nimport { createSyncLoaders, type SyncDependencies } from \"./sync/sync-loaders.js\";\nimport { createSyncAttentionController } from \"./ui/sync-attention.js\";\nimport { setSyncStatus } from \"./ui/sync-status.js\";\nimport { safeTerminalText } from \"./ui/terminal-text.js\";\n\nexport default function sync(pi: ExtensionAPI, dependencies: Partial<SyncDependencies> = {}) {\n const loaders = createSyncLoaders(dependencies);\n const attention = createSyncAttentionController();\n const check = createStartupCheck(loaders, attention);\n let sessionAbort = new AbortController();\n let shutdownAbort: AbortController | undefined;\n let initialization = Promise.resolve<AnySyncConfig | false | undefined>(undefined);\n let continuous: ReturnType<typeof import(\"./sync/continuous-sync.js\")[\"createContinuousSync\"]> | undefined;\n let owner: ExtensionContext[\"sessionManager\"] | undefined;\n let continuousPossible = false;\n const foreground = new Map<ExtensionContext[\"sessionManager\"], number>();\n async function resumeContinuous(ctx: ExtensionContext, signal: AbortSignal, retry?: { setup?: string }) {\n const isCurrent = () => !signal.aborted && !foreground.has(ctx.sessionManager) && owner === ctx.sessionManager;\n if (!isCurrent() || !ctx.hasUI) return;\n try {\n const { loadConfigForCheck } = await import(\"./settings/config.js\");\n if (!isCurrent()) return;\n const config = await loadConfigForCheck();\n if (!isCurrent()) return;\n continuousPossible = Boolean(config.continuous && config.agentMode);\n if (!continuousPossible) {\n await continuous?.stop(ctx.sessionManager);\n return;\n }\n const { createContinuousSync } = await import(\"./sync/continuous-sync.js\");\n if (!isCurrent()) return;\n continuous ??= createContinuousSync(loaders);\n continuous.start(ctx, signal, Boolean(retry && (retry.setup === undefined || retry.setup === config.setupName)));\n } catch {\n /* Existing initialization/command paths report settings errors. */\n }\n }\n\n pi.registerCommand(\"sync\", {\n description: \"Sync Pi settings through Git, WebDAV, R2, or S3-compatible storage\",\n getArgumentCompletions: completeSyncArguments,\n handler: async (args, ctx) => {\n if (!ctx.hasUI) {\n throw new Error(\"/sync requires TUI or RPC mode so results and safety prompts are observable.\");\n }\n const signal = sessionAbort.signal;\n const manager = ctx.sessionManager;\n const command = splitArgs(args)[0];\n let retry: { setup?: string } | undefined;\n let mayResume = false;\n foreground.set(manager, (foreground.get(manager) ?? 0) + 1);\n try {\n const ready = await initialization;\n mayResume = ready !== false;\n if (signal.aborted) return;\n await continuous?.stop(manager);\n if (signal.aborted) return;\n await check.stop();\n if (signal.aborted) return;\n if (ready === false && command !== \"help\" && command !== \"unlock\" && command !== \"migrate-state\") {\n ctx.ui.notify(\n \"pi-sync recovery required. Repair the startup error, then /reload before syncing. Use /sync help for recovery guidance.\",\n \"error\",\n );\n return;\n }\n const run = () =>\n handleCommand(args, ctx, signal, loaders, attention, (setup) => {\n retry = { setup };\n });\n // Drain background children before foreground guards. Help remains reachable during repair.\n if (command === \"migrate-state\" || command === \"help\") await run();\n else await withStateDirectoryAccess(run);\n } finally {\n const count = (foreground.get(manager) ?? 1) - 1;\n if (count) foreground.set(manager, count);\n else foreground.delete(manager);\n if (mayResume) await resumeContinuous(ctx, signal, retry);\n }\n },\n });\n\n pi.on(\"session_start\", async (_event, ctx) => {\n shutdownAbort?.abort(new DOMException(\"Session replaced\", \"AbortError\"));\n shutdownAbort = undefined;\n sessionAbort.abort(new DOMException(\"Session replaced\", \"AbortError\"));\n sessionAbort = new AbortController();\n const signal = sessionAbort.signal;\n owner = ctx.sessionManager;\n continuousPossible = false;\n attention.reset(ctx);\n const previous = initialization;\n initialization = (async () => {\n await previous;\n if (signal.aborted) return false;\n await continuous?.stop();\n if (signal.aborted) return false;\n await check.stop();\n if (signal.aborted) return false;\n try {\n const config = await withStateDirectoryAccess(() => startSession(ctx, signal));\n return signal.aborted ? false : config;\n } catch (error) {\n if (!signal.aborted && ctx.hasUI) {\n ctx.ui.notify(`pi-sync recovery required: ${safeTerminalText(errorMessage(error))}`, \"error\");\n }\n return false;\n }\n })();\n const ready = await initialization;\n if (ready && !signal.aborted) {\n if (ready.continuous && ready.agentMode) await resumeContinuous(ctx, signal);\n else check.start(ctx, signal, ready);\n }\n });\n\n pi.on(\"agent_start\", async (_event, ctx) => {\n await continuous?.stop(ctx.sessionManager);\n await check.interrupt(ctx);\n });\n\n pi.on(\"agent_settled\", async (_event, ctx) => {\n const signal = sessionAbort.signal;\n if (!signal.aborted) {\n check.settled(ctx);\n if (continuousPossible) await resumeContinuous(ctx, signal);\n }\n });\n\n pi.on(\"session_shutdown\", async (event, ctx) => {\n if (continuous && owner && owner !== ctx.sessionManager) return;\n sessionAbort.abort(new DOMException(\"Session shut down\", \"AbortError\"));\n attention.reset(ctx);\n shutdownAbort?.abort(new DOMException(\"Session shut down again\", \"AbortError\"));\n const controller = new AbortController();\n shutdownAbort = controller;\n const signal = combineSignals(controller.signal, AbortSignal.timeout(30_000));\n const reason = typeof event === \"object\" && event ? (event as { reason?: string }).reason : undefined;\n try {\n const ready = await initialization;\n if (signal.aborted) return;\n await continuous?.stop(ctx.sessionManager);\n if (signal.aborted) return;\n await check.stop();\n if (signal.aborted) return;\n if (ready !== false && reason !== \"reload\") {\n await withStateDirectoryAccess(async () => {\n if (signal.aborted) return;\n await autoPushSessions(ctx, signal, loaders);\n });\n }\n } catch (error) {\n if (!signal.aborted) {\n ctx.ui.notify(`pi-sync session push skipped: ${errorMessage(error)}`, \"warning\");\n }\n } finally {\n if (shutdownAbort === controller) shutdownAbort = undefined;\n }\n if (signal.aborted) return;\n setSyncStatus(ctx, undefined);\n });\n}\n\nexport type { SyncDependencies } from \"./sync/sync-loaders.js\";\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["loadConfigForCheck"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Agent mode implementation verification
|
|
2
|
+
|
|
3
|
+
This record describes the experimental implementation and its verification scope. The [settings reference](settings.md#experimental-agent-mode) is authoritative for user behavior, limits, privacy, and recovery.
|
|
4
|
+
|
|
5
|
+
## Boundaries and semantic review
|
|
6
|
+
|
|
7
|
+
- The implementation changes pi-sync only, plus its Changeset and matching bundled-Pi peer declarations in the manifest/lockfile. It does not modify Pi core or depend on another extension.
|
|
8
|
+
- Each agent directory is one replica. The existing operation lock protects pi-sync transfers; the separate resolver claim prevents duplicate local inference without holding that operation lock during provider work.
|
|
9
|
+
- Candidate keys bind accepted ancestors, ordered local/remote evidence, baseline, destination/policies, model identity and contract version. Validation runs before disclosure and again before commit. Cached output crosses the same validation boundary as fresh output.
|
|
10
|
+
- The child SDK session and its Pi-provided credential store are in memory, use an explicit empty resource loader, and have no tools. Provider requests delegate through the initiating context's public Pi model registry. No parent conversation, tool activation, prompt prefix or provider state is rewritten.
|
|
11
|
+
- Model identity is rechecked through the final merged-sync authorization path, including changes after candidate acceptance. Disclosure scanning checks raw base/local/remote strings before JSON escaping.
|
|
12
|
+
- Model-writable text consists only of overlapping hunks. Code assembles unchanged bytes and independent edits. Settings resolution selects complete existing atomic units, including coupled fields; it cannot synthesize unknown fields or replace machine-local values.
|
|
13
|
+
- Unsupported, unsafe, refused, malformed, truncated, oversized, stale and secret-bearing inputs fail closed. Detected local edits are not blindly restored. Explicit partial-sync policy alone permits independent progress around withheld groups.
|
|
14
|
+
- Remote revision checks and the existing publication/apply/baseline journal remain authoritative. A committed but uncertain publication is reconciled without another inference or blind republishing.
|
|
15
|
+
- Cancellation, foreground interruption, repeated shutdown, replacement, claim successor ownership and unrelated-session shutdown were reviewed and tested. Resolver timers, stream subscriptions and SDK sessions are released; UI cancellation clears the owned status without publishing from a stale continuation.
|
|
16
|
+
- Settings use the existing ordered cross-process writer. Consent binds the reviewed setup/connection. Tests cover cancellation, stale consent, invalid files, failed atomic save, retry, unknown-field preservation, Off defaults, schema compatibility and non-default cancellation bindings.
|
|
17
|
+
|
|
18
|
+
Applicable guides: root and package `AGENTS.md`, `docs/extension-conventions.md`, `docs/extension-settings.md`, and `docs/readme-conventions.md`. Review covered the touched-area/MUST checklist, settings read/write ordering, lifecycle ownership, prompt-prefix stability, terminal sanitization, generated import boundaries, package independence and recovery.
|
|
19
|
+
|
|
20
|
+
## Deterministic verification
|
|
21
|
+
|
|
22
|
+
The `test/agent-*.test.ts` suite covers the SDK boundary, eligibility/candidate validation, settings, cross-process claims, merged-sync integration, lifecycle and generated Jiti loading. Each test uses the repository's normal 5,000 ms timeout. Concurrent-process tests wait for child readiness; provider and lifecycle races use explicit callbacks rather than sleeps.
|
|
23
|
+
|
|
24
|
+
The fixtures assert preserved independent edits and whitespace, atomic coupled settings, unknown fields and machine-local values. Refusal and invalid-candidate tests distinguish an unresolved result from successful completion. These are regression checks, not a measured production model-accuracy benchmark.
|
|
25
|
+
|
|
26
|
+
Final local verification passed:
|
|
27
|
+
|
|
28
|
+
| Check | Result |
|
|
29
|
+
| --- | --- |
|
|
30
|
+
| `npm run check` | Builds, Biome, boundaries and all workspace typechecks passed; eight pre-existing informational lint notices remain. |
|
|
31
|
+
| `npm test` | 625 test files passed, one skipped; 9,106 tests passed and two existing tests skipped. |
|
|
32
|
+
| Agent-specific deterministic suite | 126 tests across nine files, included in the full gate. |
|
|
33
|
+
| README heading audit | All 36 active package READMEs retain the required sections. |
|
|
34
|
+
| Package build, Jiti, CLI and pack | Passed as described below. |
|
|
35
|
+
|
|
36
|
+
Repository gates and runtime smokes are also recorded in the change handoff. The full root test suite includes existing backend contracts, session protection, transaction recovery, settings persistence, command modes and confirmation behavior. The README heading audit ignores fenced code and checks the required sections across 36 active packages.
|
|
37
|
+
|
|
38
|
+
Generated-runtime tests reject eager resolver inputs and bundled dependencies, validate every emitted relative import and trigger actual resolution through Pi's Jiti loader against a local conditional WebDAV server. Both direct `/sync sync` and Agent-mode-only startup succeed with Automatic sync and Startup transfer left off. Lifecycle tests cover replacement and reload/shutdown ownership.
|
|
39
|
+
|
|
40
|
+
## PR review regression checks
|
|
41
|
+
|
|
42
|
+
All four findings in PR #1594 were verified against the implementation and fixed:
|
|
43
|
+
|
|
44
|
+
| Finding | Fix and evidence |
|
|
45
|
+
| --- | --- |
|
|
46
|
+
| A committed consent save could be reported as rejected after cancellation. | The atomic writer's success is the commit boundary. The handler retains that result and skips stale UI work. `agent-setting-commit.test.ts` covers enabling/disabling, cancellation, session replacement, notification failure and authoritative Settings reads after save. |
|
|
47
|
+
| Ordinary operation-lock contention could strand a completed resolver claim. | Creation and cleanup share a separate short-lived cross-process claim guard. Only creation takes the operation lock first; cleanup never takes it, so there is no reverse lock order. `agent-store.test.ts` holds another operation lock until cleanup finishes, for both committed and failed transfers. Existing tests cover live/dead processes, partial initialization and successor ownership. |
|
|
48
|
+
| A fixed output budget could exceed a selected model's limit. | The request uses the smaller positive model limit and resolver cap. Pi's unknown-limit value of zero retains the cap; invalid limits stop before disclosure. `agent-runner.test.ts` covers unknown, smaller, equal, larger and invalid limits. The installed Pi registry forwards explicit budgets on ordinary provider requests and caps routed virtual requests. |
|
|
49
|
+
| The new-transfer capability check could block pending journal recovery. | Recovery runs first and never republishes. `agent-recovery.test.ts` covers manual/startup recovery of published, uncertain, apply-only, inactive and already accepted journals on a weak backend. It also proves that newer local edits remain protected and new autonomous transfers remain blocked without model requests or publication. |
|
|
50
|
+
|
|
51
|
+
Review covered every changed settings publication and notification boundary, claim mutation and cleanup path, model-limit branch and journal recovery branch. Consent, settings ordering, private evidence, session ownership, remote revisions and baseline checks remain unchanged. No new setting, dependency, public API or Pi core change was added. The existing Changeset covers these fixes.
|
|
52
|
+
|
|
53
|
+
The final gates include these regressions. The generated Jiti/WebDAV tests still exercise the lazy resolver and both command/startup entry paths. The package RPC load smoke was repeated without provider requests. The earlier live-provider result below was reused; no extra paid request was needed for these control-flow fixes. Platform and live-service limits remain as listed below.
|
|
54
|
+
|
|
55
|
+
## Live provider smoke
|
|
56
|
+
|
|
57
|
+
One explicitly enabled request used `openai-codex/gpt-6.1-sol` with synthetic text only:
|
|
58
|
+
|
|
59
|
+
| Version | Synthetic content |
|
|
60
|
+
| --- | --- |
|
|
61
|
+
| Base | `Use blue.` |
|
|
62
|
+
| Local | `Use green.` |
|
|
63
|
+
| Remote | `Use blue. Keep replies short.` |
|
|
64
|
+
| Accepted result | `Use green. Keep replies short.` |
|
|
65
|
+
|
|
66
|
+
The real SDK runner delegated to Pi-managed authentication, produced a valid candidate, and preserved both tested changes. The request completed in 2,104 ms with 223 reported tokens. For this single case: one attempted completion, one accepted completion, zero refusals and zero observed semantic errors. This is not a statistical reliability claim. No personal files or real remote sync storage were involved.
|
|
67
|
+
|
|
68
|
+
The smoke invoked the emitted runner and candidate parser under `node --input-type=module`, used the selected model from Pi runtime metadata, and applied a 25-second outer signal in addition to the runner's own deadline. No provider retry or second live request was made.
|
|
69
|
+
|
|
70
|
+
## CLI, package and load checks
|
|
71
|
+
|
|
72
|
+
A disposable agent directory loaded the built package with:
|
|
73
|
+
|
|
74
|
+
```sh
|
|
75
|
+
pi --mode rpc --no-session --no-extensions --no-skills --no-context-files -e ./packages/pi-sync
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
A pipe client waited for successful `get_commands`, verified the registered `sync` command, sent `/sync help`, verified its observable notification, then closed stdin for orderly shutdown. The subprocess exited zero without model work. Resolution and reload ownership are additionally covered by the generated-Jiti and lifecycle harnesses; no interactive TUI command was opened.
|
|
79
|
+
|
|
80
|
+
`npm run package:pack -- sync` checks the pack dry run. An actual archive was created with `npm pack --workspace @narumitw/pi-sync --pack-destination <temporary-directory>` and inspected for `dist/index.ts`, lazy resolver chunks, source, documentation and external Pi peers. No credential files, resolver records or `node_modules` were present. No package was published or tagged.
|
|
81
|
+
|
|
82
|
+
Separate-process warm-load samples compared the main-branch package with Agent mode Off after one discarded warmup:
|
|
83
|
+
|
|
84
|
+
| Build | Module import samples (ms) | RPC first-response samples (ms) |
|
|
85
|
+
| --- | --- | --- |
|
|
86
|
+
| Main-branch baseline | 25, 25, 23 | 206, 215, 202 |
|
|
87
|
+
| Agent mode Off | 26, 26, 24 | 209, 210, 204 |
|
|
88
|
+
|
|
89
|
+
Both builds used the same installed Pi/dependencies, disposable agent directories and RPC command-discovery request. These host-specific samples establish no timing threshold or performance improvement. Builder tests separately prove that the resolver stays outside the eager graph.
|
|
90
|
+
|
|
91
|
+
## Remaining limits
|
|
92
|
+
|
|
93
|
+
- JSON parsing, hunk confinement and source selection do not prove semantic correctness. The feature remains default-off and experimental.
|
|
94
|
+
- Operation locks and process-local file queues do not exclude arbitrary cross-process file writers. The implementation does not claim atomic local compare-and-swap or lossless live session synchronization.
|
|
95
|
+
- Session histories, executable code, deletion conflicts, path collisions and missing ancestors are not model-resolved. Initial-source/policy changes retain reviewed flows.
|
|
96
|
+
- Provider disclosure and billing can occur before cancellation; exactly-once billing is not guaranteed. Candidate records are private but retained without automatic pruning.
|
|
97
|
+
- Live evidence covers one provider/model and one synthetic conflict, not all model APIs, proxies, production storage services or network environments. Git/S3 and failure branches have deterministic contract/regression coverage, not new live-service smokes.
|
|
98
|
+
- Windows and Android were not live-tested in this change. Existing platform behavior remains, and new candidate publication uses temporary files plus rename rather than adding a hard-link requirement.
|
|
99
|
+
- `npm install` reported five existing repository audit advisories (three high, two critical). No dependency versions or audit overrides were added; the lockfile change is limited to bundled-Pi peer declarations, with no dependency resolution changes. Dependency remediation is outside this change.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Continuous sync verification
|
|
2
|
+
|
|
3
|
+
This record describes implementation evidence and test scope. The [settings reference](settings.md#experimental-continuous-sync) owns user-facing behavior, limits and recovery.
|
|
4
|
+
|
|
5
|
+
## Boundaries and semantic audit
|
|
6
|
+
|
|
7
|
+
The change is confined to Pi Sync and its Changeset. It adds no dependency, provider, public command, interval setting, environment variable, Pi core change or dependency on another extension. Continuous sync is a separate experimental opt-in; Agent mode alone retains its existing behavior.
|
|
8
|
+
|
|
9
|
+
Applicable guides are root and package `AGENTS.md`, `docs/extension-conventions.md`, `docs/extension-settings.md` and `docs/readme-conventions.md`. The final diff audit covered their touched-area and verification checklists:
|
|
10
|
+
|
|
11
|
+
| Area | Audit and evidence |
|
|
12
|
+
| --- | --- |
|
|
13
|
+
| Lifecycle | No factory-owned watcher or timer. Work is keyed by `sessionManager`. Startup recovery remains an awaited barrier, including after Help. Foreground/agent work, replacement, reload and shutdown abort and drain owned work. Authorization checks also run during active requests when watching is unavailable. Lifecycle and scheduling tests assert released claims, leases, watchers and timers. |
|
|
14
|
+
| Ownership | Atomic guard creation, renewal, stale takeover, malformed records, future clocks, partial publication, replacement and process exit were checked against the installed `proper-lockfile` implementation. Cleanup fences both its asynchronous release and native synchronous exit path by guard identity and owner token. Separate-process tests cover contention, abrupt exit, takeover and successor preservation. |
|
|
15
|
+
| Settings | Existing ordered cross-process atomic writes remain authoritative. Consent binds the setup/connection; tests cover stale review, unknown fields, invalid files, failed save, retry and cancellation after publication. Disabling either prerequisite stops monitoring; saved and effective values remain distinct. |
|
|
16
|
+
| Transfer | Existing operation locks, current-session protection, snapshots, revision checks, conditional publication and journal recovery remain in use. Background ownership is checked before disclosure and mutation. Pending journals are reconciled before capability checks for a new transfer; uncertain publication is not blindly repeated. |
|
|
17
|
+
| Cost and privacy | Reservations sample time under the accounting lock, precede the public registry dispatch boundary and survive restart, crash, state-directory migration and owner handoff. Inconsistent window/candidate counts fail closed. Unknown outcomes consume reservations. Cached candidates cross fresh evidence checks. Private records contain safe metadata and hashes, not raw credentials, provider payloads, reasoning or duplicate conflict text. |
|
|
18
|
+
| Prefix stability | The parent system prompt, ordered tools and conversation prefix are unchanged. The existing isolated, tool-free child contract is unchanged; scheduler timestamps/status do not enter model-visible messages. No intentional parent-prefix transition is added. |
|
|
19
|
+
| UI | Existing Pi/Kit menus and confirmation reviews are reused. Tests cover RPC consent, cancellation and a 40-cell Settings screen with non-default navigation/confirmation/cancellation keys. Added status fields are safe categories, bounded dates and validated PIDs. Print/JSON create no continuous resources. |
|
|
20
|
+
| Packaging | Generated import checks retain the lazy boundary, validate emitted relative paths and keep Pi peers external. Jiti tests exercise command, one-shot startup and continuous resolution. Package-directory RPC and archive checks are described below. |
|
|
21
|
+
|
|
22
|
+
### Lock order and migration
|
|
23
|
+
|
|
24
|
+
Acquisition takes state-directory access, attempts the scheduler lease without waiting, and uses a short operation lock to publish ownership. A standby never waits for election while holding an operation lock.
|
|
25
|
+
|
|
26
|
+
Once elected, an idle owner retains the renewable scheduler lease, not the exclusive legacy migration guard. Each transfer/private-state mutation takes migration access before its operation/backend/cache locks. Idle metadata reads are fenced by the held lease and ownership checks. Inference retains required state access and its resolver claim, but releases the operation lock. Resolver and lease cleanup do not acquire that lock.
|
|
27
|
+
|
|
28
|
+
Migration never waits for a scheduler: a live lease causes a deferred result. A separate-process legacy-state test proves that an idle owner does not block foreground state access. Accounting binds to the canonical agent root, so moving the state directory does not grant new requests. Paused/lost owners remain fenced by guard identity, generation and token checks.
|
|
29
|
+
|
|
30
|
+
### Detection and failure decisions
|
|
31
|
+
|
|
32
|
+
Native watching is a hint, not authority. Missing/replaced paths, unsupported recursive watching and errors retain periodic fallback. Unknown event names are ignored because they can refer to private writes; the periodic scan covers them without a self-trigger loop. Filtering reuses the snapshot deny policy. The normal inspector supplies its existing snapshot fingerprint rather than making a duplicate full scan.
|
|
33
|
+
|
|
34
|
+
S3/WebDAV HTTP status, bounded Retry-After, network cause codes, timeout types and lock error codes provide explicit retry decisions. WebDAV retains a safe category before redaction. Structured synchronous model transport failures are preserved through the SDK boundary. Opaque assistant/Git errors are not guessed from text and remain blocked.
|
|
35
|
+
|
|
36
|
+
Unknown, authentication and storage failures require a relevant configuration change or explicit retry. Malformed local settings/scheduler records have a bounded local repair check, without remote/model work. Unsafe/refused evidence is re-inspected but not repeatedly resolved when unchanged. Partial progress retains unresolved groups as a stable block; restart tests prove that settled evidence causes no further inference, baseline changes or warning repetition.
|
|
37
|
+
|
|
38
|
+
The rolling model window does not prevent read-only checks, conflict-free progress or journal recovery. Full/invalid accounting blocks new requests rather than pruning spent evidence. These are request bounds, not a currency cap or an exactly-once billing guarantee.
|
|
39
|
+
|
|
40
|
+
## Deterministic verification
|
|
41
|
+
|
|
42
|
+
The new `test/continuous-*.test.ts` files cover consent/settings, typed failures, leases and native exit, durable accounting, lifecycle ownership, detection/debounce, fallback, deadlines, restart/backoff, refusal/partial deduplication, journal recovery, explicit retry routing and Status reads. Existing Agent mode, backend, settings, session-protection and recovery tests also pass. Every Vitest test retains the normal 5,000 ms limit. Settings tests check that On and Off saves report the saved state, including consent on enablement and non-default navigation keys.
|
|
43
|
+
|
|
44
|
+
Authorization regression tests also replace settings or the selected model after inspection, both before `syncBoth` reads settings and between its read and `mergeSync` initialization. Sixteen cases cover Continuous sync disablement, Agent mode disablement while Startup transfer stays enabled, credential replacement, and model replacement, with conflict-free and conflicting content. Watcher hints are suppressed and scheduler time does not advance. Each stale cycle must abort without a provider reservation, dispatch, publication, local apply, baseline change, or retained lease/claim. Fresh transfer settings are checked against the cycle's configuration; the periodic guard remains responsible for cancelling active requests.
|
|
45
|
+
|
|
46
|
+
The convergence fixture uses four real child processes across three agent directories and one conditional loopback WebDAV backend. Two processes share one replica and elect one scheduler. Local and remote-only edits converge without manual commands. A server-observed outage recovers automatically, and an idle standby takes over after the owner exits. Child IPC barriers wait for each cycle to finish before advancing simulated time; deadlines start after readiness, not during child import.
|
|
47
|
+
|
|
48
|
+
Final verification:
|
|
49
|
+
|
|
50
|
+
| Check | Result |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| `npm run check` | Builds, Biome, package boundaries and workspace typechecks passed. Existing informational lint notices remain. |
|
|
53
|
+
| `npm test` | 637 files passed, one skipped; 9,206 tests passed, two skipped. |
|
|
54
|
+
| Continuous regression suite | 99 tests across 12 files, included in the full gate; all 16 authorization regression cases failed before the fix and passed afterward. |
|
|
55
|
+
| Generated Jiti/build tests | Command, startup and continuous paths passed against conditional loopback storage. |
|
|
56
|
+
| README heading audit | Required headings/order checked across all 36 active package READMEs. |
|
|
57
|
+
| Package build, RPC and archive | Passed as described below. |
|
|
58
|
+
|
|
59
|
+
## CLI, package and load checks
|
|
60
|
+
|
|
61
|
+
The required package build and dry-run pack use:
|
|
62
|
+
|
|
63
|
+
```sh
|
|
64
|
+
npm --workspace @narumitw/pi-sync run build --if-present
|
|
65
|
+
npm run package:pack -- sync
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
An actual temporary archive is produced with `npm pack --workspace @narumitw/pi-sync --pack-destination <temporary-directory>`. Inspection checks its built entrypoint, lazy chunks, source and installed documentation, and excludes private state, tests and `node_modules`. No package publication, visibility change, tag or release workflow is performed.
|
|
69
|
+
|
|
70
|
+
A disposable agent directory loads the built package through non-interactive RPC with extensions, MCP, skills, templates and context discovery disabled, offline mode, and an explicit `-e ./packages/pi-sync`. The default-Off smoke checks command discovery, manager/Settings navigation, unchanged settings bytes and orderly exit without provider work.
|
|
71
|
+
|
|
72
|
+
`test/continuous-cli-smoke.ts` is a standalone smoke compiled by the test build. It prepares only synthetic text and a loopback conditional backend, waits for CLI readiness, then verifies automatic publication without a manual sync command. The durable provider count remains zero and the lease is absent after orderly exit. It does not open a TUI or contact a production storage/model service.
|
|
73
|
+
|
|
74
|
+
Separate-process load samples compare main commit `76ac610e` with Continuous sync Off, using the same installed dependencies and disposable agent directories after one discarded warmup:
|
|
75
|
+
|
|
76
|
+
| Build | Module import samples (ms) | RPC first-response samples (ms) |
|
|
77
|
+
| --- | --- | --- |
|
|
78
|
+
| Main baseline | 501, 482, 475 | 214, 194, 203 |
|
|
79
|
+
| Continuous sync Off | 503, 490, 494 | 221, 217, 214 |
|
|
80
|
+
|
|
81
|
+
These host-specific samples include cold-process module evaluation. They establish no timing threshold or performance improvement. Generated-graph tests separately prove that the scheduler/resolver remain lazy.
|
|
82
|
+
|
|
83
|
+
## Limits and unverified paths
|
|
84
|
+
|
|
85
|
+
No new live provider request was needed. The earlier Agent mode provider smoke is not evidence for this scheduler, and these fixtures do not measure semantic model accuracy. Production Git/S3/WebDAV services, provider-specific opaque errors, Windows and Android were not live-tested here; deterministic fallback/contract tests do not establish live-platform support.
|
|
86
|
+
|
|
87
|
+
All participating Pi processes must be upgraded before enablement. Older clients do not implement continuous election/accounting. The lease does not exclude arbitrary editors or writers in other processes, and the change adds no atomic local compare-and-swap or lossless live-session guarantee. Unsupported conflicts, uncertain journals and invalid private evidence retain review barriers. Private accounting remains retained and bounded; filling its limit requires repair rather than an automatic reset.
|