@logictan/dsh-config-manager 0.1.60
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/LICENSE +21 -0
- package/README.md +105 -0
- package/cordis.patch.yml +21 -0
- package/lib/adapters/agent-instructions.d.ts +13 -0
- package/lib/adapters/agent-instructions.js +46 -0
- package/lib/adapters/agent-presets.d.ts +13 -0
- package/lib/adapters/agent-presets.js +14 -0
- package/lib/adapters/credentials.d.ts +37 -0
- package/lib/adapters/credentials.js +122 -0
- package/lib/adapters/file-collection.d.ts +15 -0
- package/lib/adapters/file-collection.js +127 -0
- package/lib/adapters/index.d.ts +57 -0
- package/lib/adapters/index.js +55 -0
- package/lib/adapters/link-report.d.ts +16 -0
- package/lib/adapters/link-report.js +47 -0
- package/lib/adapters/mcp.d.ts +28 -0
- package/lib/adapters/mcp.js +178 -0
- package/lib/adapters/plugin-files.d.ts +18 -0
- package/lib/adapters/plugin-files.js +142 -0
- package/lib/adapters/plugins.d.ts +41 -0
- package/lib/adapters/plugins.js +603 -0
- package/lib/adapters/pnpm-workspace.d.ts +26 -0
- package/lib/adapters/pnpm-workspace.js +147 -0
- package/lib/adapters/prompts.d.ts +30 -0
- package/lib/adapters/prompts.js +231 -0
- package/lib/adapters/providers.d.ts +34 -0
- package/lib/adapters/providers.js +155 -0
- package/lib/adapters/self.d.ts +17 -0
- package/lib/adapters/self.js +71 -0
- package/lib/adapters/sessions.d.ts +14 -0
- package/lib/adapters/sessions.js +15 -0
- package/lib/adapters/settings.d.ts +28 -0
- package/lib/adapters/settings.js +165 -0
- package/lib/adapters/skills.d.ts +13 -0
- package/lib/adapters/skills.js +14 -0
- package/lib/adapters/test-helpers.d.ts +125 -0
- package/lib/adapters/test-helpers.js +236 -0
- package/lib/adapters/ui.d.ts +27 -0
- package/lib/adapters/ui.js +89 -0
- package/lib/adapters/workspaces.d.ts +13 -0
- package/lib/adapters/workspaces.js +106 -0
- package/lib/client.d.ts +1026 -0
- package/lib/client.js +10047 -0
- package/lib/core/analyzer.d.ts +99 -0
- package/lib/core/analyzer.js +934 -0
- package/lib/core/backup.d.ts +138 -0
- package/lib/core/backup.js +513 -0
- package/lib/core/boot-rescue.d.ts +146 -0
- package/lib/core/boot-rescue.js +618 -0
- package/lib/core/cache-cleaner.d.ts +31 -0
- package/lib/core/cache-cleaner.js +95 -0
- package/lib/core/config-lifecycle.d.ts +180 -0
- package/lib/core/config-lifecycle.js +481 -0
- package/lib/core/config-snapshot.d.ts +135 -0
- package/lib/core/config-snapshot.js +424 -0
- package/lib/core/config-state.d.ts +70 -0
- package/lib/core/config-state.js +177 -0
- package/lib/core/consult-source.d.ts +58 -0
- package/lib/core/consult-source.js +260 -0
- package/lib/core/crash-report.d.ts +84 -0
- package/lib/core/crash-report.js +317 -0
- package/lib/core/exporter.d.ts +68 -0
- package/lib/core/exporter.js +375 -0
- package/lib/core/ghost-sweep.d.ts +19 -0
- package/lib/core/ghost-sweep.js +52 -0
- package/lib/core/importer.d.ts +60 -0
- package/lib/core/importer.js +29 -0
- package/lib/core/index.d.ts +14 -0
- package/lib/core/index.js +14 -0
- package/lib/core/journal.d.ts +197 -0
- package/lib/core/journal.js +418 -0
- package/lib/core/local-plugin-host.d.ts +35 -0
- package/lib/core/local-plugin-host.js +120 -0
- package/lib/core/local-plugin-pack.d.ts +135 -0
- package/lib/core/local-plugin-pack.js +278 -0
- package/lib/core/messages.d.ts +310 -0
- package/lib/core/messages.js +621 -0
- package/lib/core/migration-consult.d.ts +117 -0
- package/lib/core/migration-consult.js +363 -0
- package/lib/core/migration-history.d.ts +153 -0
- package/lib/core/migration-history.js +411 -0
- package/lib/core/model-tools.d.ts +50 -0
- package/lib/core/model-tools.js +148 -0
- package/lib/core/msg-types.d.ts +8 -0
- package/lib/core/msg-types.js +6 -0
- package/lib/core/phase3-child-crash.d.ts +1 -0
- package/lib/core/phase3-child-crash.js +87 -0
- package/lib/core/phase3-host.d.ts +138 -0
- package/lib/core/phase3-host.js +359 -0
- package/lib/core/phase3-prod-child.d.ts +1 -0
- package/lib/core/phase3-prod-child.js +35 -0
- package/lib/core/phase4-crash-child.d.ts +1 -0
- package/lib/core/phase4-crash-child.js +103 -0
- package/lib/core/plugin-cli.d.ts +150 -0
- package/lib/core/plugin-cli.js +497 -0
- package/lib/core/reconcile.d.ts +120 -0
- package/lib/core/reconcile.js +389 -0
- package/lib/core/recovery-orchestrator.d.ts +94 -0
- package/lib/core/recovery-orchestrator.js +327 -0
- package/lib/core/restore.d.ts +162 -0
- package/lib/core/restore.js +703 -0
- package/lib/core/rollback.d.ts +12 -0
- package/lib/core/rollback.js +145 -0
- package/lib/core/run-registry.d.ts +85 -0
- package/lib/core/run-registry.js +157 -0
- package/lib/core/startup-barrier.d.ts +53 -0
- package/lib/core/startup-barrier.js +77 -0
- package/lib/core/types.d.ts +515 -0
- package/lib/core/types.js +27 -0
- package/lib/core/undo.d.ts +73 -0
- package/lib/core/undo.js +87 -0
- package/lib/core/validator.d.ts +18 -0
- package/lib/core/validator.js +77 -0
- package/lib/core/verify-recovery.d.ts +21 -0
- package/lib/core/verify-recovery.js +256 -0
- package/lib/core/watcher.d.ts +101 -0
- package/lib/core/watcher.js +219 -0
- package/lib/index.d.ts +238 -0
- package/lib/index.js +2764 -0
- package/lib/migrations/index.d.ts +29 -0
- package/lib/migrations/index.js +56 -0
- package/lib/migrations/v1-to-v2.d.ts +9 -0
- package/lib/migrations/v1-to-v2.js +10 -0
- package/lib/profiles/index.d.ts +4 -0
- package/lib/profiles/index.js +5 -0
- package/lib/profiles/profile-manager.d.ts +106 -0
- package/lib/profiles/profile-manager.js +543 -0
- package/lib/schema/config.d.ts +28 -0
- package/lib/schema/config.js +165 -0
- package/lib/schema/index.d.ts +24 -0
- package/lib/schema/index.js +26 -0
- package/lib/schema/manifest.d.ts +28 -0
- package/lib/schema/manifest.js +109 -0
- package/lib/schema/tombstones.d.ts +46 -0
- package/lib/schema/tombstones.js +64 -0
- package/lib/schema/types.d.ts +232 -0
- package/lib/schema/types.js +8 -0
- package/lib/schema/versions.d.ts +27 -0
- package/lib/schema/versions.js +50 -0
- package/lib/security/encryption.d.ts +85 -0
- package/lib/security/encryption.js +279 -0
- package/lib/security/index.d.ts +16 -0
- package/lib/security/index.js +17 -0
- package/lib/security/integrity.d.ts +30 -0
- package/lib/security/integrity.js +78 -0
- package/lib/security/redaction.d.ts +26 -0
- package/lib/security/redaction.js +95 -0
- package/lib/security/secret-scanner.d.ts +86 -0
- package/lib/security/secret-scanner.js +404 -0
- package/lib/security/vault.d.ts +59 -0
- package/lib/security/vault.js +151 -0
- package/lib/security/zip-security.d.ts +27 -0
- package/lib/security/zip-security.js +154 -0
- package/lib/sync/autosync-config.d.ts +39 -0
- package/lib/sync/autosync-config.js +151 -0
- package/lib/sync/autosync-scheduler.d.ts +139 -0
- package/lib/sync/autosync-scheduler.js +564 -0
- package/lib/sync/fs.d.ts +18 -0
- package/lib/sync/fs.js +49 -0
- package/lib/sync/git/git-transport.d.ts +100 -0
- package/lib/sync/git/git-transport.js +437 -0
- package/lib/sync/github-auth.d.ts +131 -0
- package/lib/sync/github-auth.js +264 -0
- package/lib/sync/layout.d.ts +43 -0
- package/lib/sync/layout.js +203 -0
- package/lib/sync/snapshot-json.d.ts +9 -0
- package/lib/sync/snapshot-json.js +107 -0
- package/lib/sync/sync-config.d.ts +81 -0
- package/lib/sync/sync-config.js +281 -0
- package/lib/sync/sync-engine.d.ts +269 -0
- package/lib/sync/sync-engine.js +591 -0
- package/lib/sync/sync-history.d.ts +42 -0
- package/lib/sync/sync-history.js +78 -0
- package/lib/sync/sync-selection.d.ts +29 -0
- package/lib/sync/sync-selection.js +127 -0
- package/lib/sync/sync-session.d.ts +40 -0
- package/lib/sync/sync-session.js +54 -0
- package/lib/sync/sync-state.d.ts +37 -0
- package/lib/sync/sync-state.js +108 -0
- package/lib/sync/transport.d.ts +75 -0
- package/lib/sync/transport.js +55 -0
- package/lib/sync/ui-prefs.d.ts +34 -0
- package/lib/sync/ui-prefs.js +109 -0
- package/lib/sync/webdav/webdav-transport.d.ts +77 -0
- package/lib/sync/webdav/webdav-transport.js +451 -0
- package/lib/ui/errors.d.ts +19 -0
- package/lib/ui/errors.js +81 -0
- package/lib/ui/export-flow.d.ts +82 -0
- package/lib/ui/export-flow.js +98 -0
- package/lib/ui/i18n.d.ts +289 -0
- package/lib/ui/i18n.js +581 -0
- package/lib/ui/migration-consult-view.d.ts +91 -0
- package/lib/ui/migration-consult-view.js +115 -0
- package/lib/ui/progress.d.ts +38 -0
- package/lib/ui/progress.js +87 -0
- package/lib/ui/report.d.ts +23 -0
- package/lib/ui/report.js +153 -0
- package/lib/ui/test-helpers.d.ts +69 -0
- package/lib/ui/test-helpers.js +154 -0
- package/lib/ui/types.d.ts +257 -0
- package/lib/ui/types.js +21 -0
- package/lib/utils/atomic-write.d.ts +88 -0
- package/lib/utils/atomic-write.js +399 -0
- package/lib/utils/env-lock.d.ts +393 -0
- package/lib/utils/env-lock.js +930 -0
- package/lib/utils/hashing.d.ts +17 -0
- package/lib/utils/hashing.js +41 -0
- package/lib/utils/json.d.ts +24 -0
- package/lib/utils/json.js +76 -0
- package/lib/utils/logger.d.ts +39 -0
- package/lib/utils/logger.js +82 -0
- package/lib/utils/paths.d.ts +42 -0
- package/lib/utils/paths.js +189 -0
- package/lib/utils/proxy.d.ts +69 -0
- package/lib/utils/proxy.js +455 -0
- package/lib/utils/recursive-walk.d.ts +24 -0
- package/lib/utils/recursive-walk.js +134 -0
- package/lib/utils/zip.d.ts +54 -0
- package/lib/utils/zip.js +285 -0
- package/package.json +188 -0
- package/src/adapters/agent-instructions.ts +48 -0
- package/src/adapters/agent-presets.ts +14 -0
- package/src/adapters/credentials.test.ts +90 -0
- package/src/adapters/credentials.ts +143 -0
- package/src/adapters/file-collection.ts +137 -0
- package/src/adapters/files.test.ts +353 -0
- package/src/adapters/index.ts +94 -0
- package/src/adapters/link-report.test.ts +65 -0
- package/src/adapters/link-report.ts +61 -0
- package/src/adapters/mcp.test.ts +96 -0
- package/src/adapters/mcp.ts +185 -0
- package/src/adapters/plugin-files.ts +146 -0
- package/src/adapters/plugins.test.ts +326 -0
- package/src/adapters/plugins.ts +615 -0
- package/src/adapters/pnpm-workspace.test.ts +87 -0
- package/src/adapters/pnpm-workspace.ts +150 -0
- package/src/adapters/prompts.test.ts +110 -0
- package/src/adapters/prompts.ts +230 -0
- package/src/adapters/providers.test.ts +126 -0
- package/src/adapters/providers.ts +173 -0
- package/src/adapters/roundtrip.test.ts +190 -0
- package/src/adapters/self.test.ts +92 -0
- package/src/adapters/self.ts +75 -0
- package/src/adapters/sessions.ts +15 -0
- package/src/adapters/settings.test.ts +100 -0
- package/src/adapters/settings.ts +187 -0
- package/src/adapters/skills.ts +14 -0
- package/src/adapters/test-helpers.ts +248 -0
- package/src/adapters/ui.test.ts +57 -0
- package/src/adapters/ui.ts +108 -0
- package/src/adapters/workspaces.test.ts +106 -0
- package/src/adapters/workspaces.ts +109 -0
- package/src/client/ConfigManagerSection.tsx +90 -0
- package/src/client/api.ts +66 -0
- package/src/client/client-types.ts +18 -0
- package/src/client/common/ErrorBanner.tsx +73 -0
- package/src/client/common/Icon.tsx +129 -0
- package/src/client/common/Modal.tsx +173 -0
- package/src/client/common/ToastViewport.tsx +73 -0
- package/src/client/common/toast-store.test.ts +192 -0
- package/src/client/common/toast-store.ts +181 -0
- package/src/client/common/toast-types.ts +7 -0
- package/src/client/common/ui.tsx +342 -0
- package/src/client/config-manager.module.css +2971 -0
- package/src/client/css-modules.d.ts +8 -0
- package/src/client/index.ts +65 -0
- package/src/client/locales.ts +56 -0
- package/src/client/lucide-icons.d.ts +38 -0
- package/src/client/run-store.test.ts +223 -0
- package/src/client/run-store.ts +372 -0
- package/src/client/sync/SyncConfirmView.tsx +379 -0
- package/src/client/sync/SyncHistoryView.test.ts +40 -0
- package/src/client/sync/SyncHistoryView.tsx +220 -0
- package/src/client/sync/SyncSettingsView.tsx +1535 -0
- package/src/client/sync/history-model.test.ts +194 -0
- package/src/client/sync/history-model.ts +195 -0
- package/src/client/sync/sync-api.test.ts +585 -0
- package/src/client/sync/sync-api.ts +543 -0
- package/src/client/sync/sync-locales.ts +416 -0
- package/src/client/sync/sync-push-preview.test.ts +52 -0
- package/src/client/sync/sync-view-v2.test.ts +213 -0
- package/src/client/sync/sync-view.test.ts +487 -0
- package/src/client/sync/sync-view.ts +759 -0
- package/src/core/analyzer.ts +1068 -0
- package/src/core/backup.ts +605 -0
- package/src/core/boot-rescue.test.ts +847 -0
- package/src/core/boot-rescue.ts +737 -0
- package/src/core/cache-cleaner.test.ts +169 -0
- package/src/core/cache-cleaner.ts +121 -0
- package/src/core/config-lifecycle.test.ts +727 -0
- package/src/core/config-lifecycle.ts +573 -0
- package/src/core/config-snapshot.test.ts +369 -0
- package/src/core/config-snapshot.ts +522 -0
- package/src/core/config-state.test.ts +381 -0
- package/src/core/config-state.ts +207 -0
- package/src/core/consult-source.test.ts +199 -0
- package/src/core/consult-source.ts +293 -0
- package/src/core/crash-report.test.ts +380 -0
- package/src/core/crash-report.ts +369 -0
- package/src/core/exporter.ts +417 -0
- package/src/core/ghost-sweep.test.ts +94 -0
- package/src/core/ghost-sweep.ts +67 -0
- package/src/core/importer.ts +83 -0
- package/src/core/index.ts +56 -0
- package/src/core/journal.test.ts +257 -0
- package/src/core/journal.ts +518 -0
- package/src/core/local-plugin-host.ts +152 -0
- package/src/core/local-plugin-pack.test.ts +359 -0
- package/src/core/local-plugin-pack.ts +363 -0
- package/src/core/messages.test.ts +54 -0
- package/src/core/messages.ts +664 -0
- package/src/core/migration-consult.test.ts +315 -0
- package/src/core/migration-consult.ts +494 -0
- package/src/core/migration-history.test.ts +319 -0
- package/src/core/migration-history.ts +484 -0
- package/src/core/model-tools.test.ts +190 -0
- package/src/core/model-tools.ts +208 -0
- package/src/core/msg-types.ts +10 -0
- package/src/core/phase3-child-crash.ts +95 -0
- package/src/core/phase3-host.ts +411 -0
- package/src/core/phase3-p1.test.ts +212 -0
- package/src/core/phase3-p2b-fingerprint.test.ts +189 -0
- package/src/core/phase3-prod-child.ts +36 -0
- package/src/core/phase3-production-integration.test.ts +286 -0
- package/src/core/phase4-crash-child.ts +101 -0
- package/src/core/phase4-crash-injection.test.ts +166 -0
- package/src/core/plugin-cli.fs.test.ts +184 -0
- package/src/core/plugin-cli.test.ts +137 -0
- package/src/core/plugin-cli.ts +563 -0
- package/src/core/reconcile.test.ts +392 -0
- package/src/core/reconcile.ts +498 -0
- package/src/core/recovery-orchestrator.test.ts +145 -0
- package/src/core/recovery-orchestrator.ts +366 -0
- package/src/core/restore-manage.test.ts +94 -0
- package/src/core/restore.ts +849 -0
- package/src/core/rollback.ts +151 -0
- package/src/core/run-progress.test.ts +237 -0
- package/src/core/run-registry.test.ts +232 -0
- package/src/core/run-registry.ts +209 -0
- package/src/core/smoke.test.ts +842 -0
- package/src/core/startup-barrier.ts +99 -0
- package/src/core/types.ts +542 -0
- package/src/core/undo.ts +116 -0
- package/src/core/validator.ts +84 -0
- package/src/core/verify-recovery.ts +265 -0
- package/src/core/watcher.test.ts +326 -0
- package/src/core/watcher.ts +263 -0
- package/src/index.facade.test.ts +265 -0
- package/src/index.sync.test.ts +217 -0
- package/src/index.ts +2975 -0
- package/src/migrations/index.ts +71 -0
- package/src/migrations/v1-to-v2.ts +17 -0
- package/src/profiles/index.ts +8 -0
- package/src/profiles/profile-manager.test.ts +282 -0
- package/src/profiles/profile-manager.ts +630 -0
- package/src/schema/config.ts +165 -0
- package/src/schema/index.ts +71 -0
- package/src/schema/manifest-schema.test.ts +519 -0
- package/src/schema/manifest.ts +124 -0
- package/src/schema/tombstones.test.ts +131 -0
- package/src/schema/tombstones.ts +89 -0
- package/src/schema/types.ts +245 -0
- package/src/schema/versions.ts +55 -0
- package/src/security/encryption.ts +335 -0
- package/src/security/index.ts +16 -0
- package/src/security/integrity.ts +102 -0
- package/src/security/redaction.ts +101 -0
- package/src/security/secret-scanner.ts +445 -0
- package/src/security/security.test.ts +1215 -0
- package/src/security/vault.test.ts +164 -0
- package/src/security/vault.ts +198 -0
- package/src/security/zip-security.ts +180 -0
- package/src/sync/autosync-config.test.ts +147 -0
- package/src/sync/autosync-config.ts +179 -0
- package/src/sync/autosync-scheduler.test.ts +490 -0
- package/src/sync/autosync-scheduler.ts +646 -0
- package/src/sync/fs.ts +48 -0
- package/src/sync/git/git-transport.test.ts +673 -0
- package/src/sync/git/git-transport.ts +491 -0
- package/src/sync/github-auth.test.ts +280 -0
- package/src/sync/github-auth.ts +356 -0
- package/src/sync/layout.test.ts +270 -0
- package/src/sync/layout.ts +222 -0
- package/src/sync/snapshot-json.test.ts +119 -0
- package/src/sync/snapshot-json.ts +128 -0
- package/src/sync/sync-config.test.ts +310 -0
- package/src/sync/sync-config.ts +299 -0
- package/src/sync/sync-engine.test.ts +1074 -0
- package/src/sync/sync-engine.ts +754 -0
- package/src/sync/sync-history.test.ts +116 -0
- package/src/sync/sync-history.ts +120 -0
- package/src/sync/sync-selection.test.ts +186 -0
- package/src/sync/sync-selection.ts +143 -0
- package/src/sync/sync-session.test.ts +143 -0
- package/src/sync/sync-session.ts +77 -0
- package/src/sync/sync-state.test.ts +164 -0
- package/src/sync/sync-state.ts +131 -0
- package/src/sync/transport.test.ts +111 -0
- package/src/sync/transport.ts +118 -0
- package/src/sync/ui-prefs.test.ts +152 -0
- package/src/sync/ui-prefs.ts +135 -0
- package/src/sync/webdav/webdav-transport.test.ts +871 -0
- package/src/sync/webdav/webdav-transport.ts +535 -0
- package/src/ui/errors.test.ts +47 -0
- package/src/ui/errors.ts +100 -0
- package/src/ui/export-flow.test.ts +87 -0
- package/src/ui/export-flow.ts +156 -0
- package/src/ui/i18n.ts +590 -0
- package/src/ui/migration-consult-view.test.ts +151 -0
- package/src/ui/migration-consult-view.ts +178 -0
- package/src/ui/progress.test.ts +47 -0
- package/src/ui/progress.ts +102 -0
- package/src/ui/report.test.ts +101 -0
- package/src/ui/report.ts +146 -0
- package/src/ui/test-helpers.ts +184 -0
- package/src/ui/types.ts +325 -0
- package/src/utils/atomic-write.test.ts +312 -0
- package/src/utils/atomic-write.ts +422 -0
- package/src/utils/env-lock.test.ts +999 -0
- package/src/utils/env-lock.ts +1086 -0
- package/src/utils/hashing.ts +53 -0
- package/src/utils/json.ts +77 -0
- package/src/utils/logger.ts +114 -0
- package/src/utils/paths.ts +176 -0
- package/src/utils/proxy.test.ts +465 -0
- package/src/utils/proxy.ts +493 -0
- package/src/utils/recursive-walk.test.ts +148 -0
- package/src/utils/recursive-walk.ts +145 -0
- package/src/utils/zip.ts +332 -0
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
/** 锁目录相对 dataDir */
|
|
2
|
+
export declare const LOCKS_DIR = "locks";
|
|
3
|
+
/** 所有权记录文件名(immutable) */
|
|
4
|
+
export declare const OWNERSHIP_FILE = "environment.lock";
|
|
5
|
+
/** heartbeat sidecar 前缀 + 文件名模板:environment.heartbeat.<instanceId> */
|
|
6
|
+
export declare const HEARTBEAT_PREFIX = "environment.heartbeat.";
|
|
7
|
+
/** recovery 捕获文件名临时前缀 + 模板:environment.recovering.<recoveryInstanceId> */
|
|
8
|
+
export declare const RECOVERING_PREFIX = "environment.recovering.";
|
|
9
|
+
/** lock schema 版本 */
|
|
10
|
+
export declare const LOCK_SCHEMA_VERSION = 1;
|
|
11
|
+
/** 默认心跳间隔 ms */
|
|
12
|
+
export declare const DEFAULT_HEARTBEAT_INTERVAL_MS = 1000;
|
|
13
|
+
/** 默认 stale 阈值 ms(≥ 10 × heartbeatInterval) */
|
|
14
|
+
export declare const DEFAULT_STALE_AFTER_MS = 10000;
|
|
15
|
+
/** 默认 acquire 等待超时(等待活跃锁释放)ms;0 = 不等待直接返回 */
|
|
16
|
+
export declare const DEFAULT_ACQUIRE_TIMEOUT_MS = 0;
|
|
17
|
+
/** 「心跳长过期」下限 ms(issue #36)。实际阈值 = max(30 × staleAfterMs, 本值)。
|
|
18
|
+
* 用途:Windows/macOS 默认拿不到 OS process identity,Windows 又会复用 PID,于是
|
|
19
|
+
* 「心跳过期 + pid 存活」永远停在 UNKNOWN_STATE,用户只能手工删锁文件(issue #36 实测)。
|
|
20
|
+
* 心跳长过期说明写方早已停摆 → 允许**显式**回收判为残留锁;acquire 侧仍绝不自动摘锁。 */
|
|
21
|
+
export declare const DEFAULT_LONG_EXPIRED_AFTER_MS: number;
|
|
22
|
+
/** 进程身份(可注入探测;OS 可验证的 process creation identity 才用于 PID reuse) */
|
|
23
|
+
export interface ProcessIdentity {
|
|
24
|
+
/** OS 可验证的进程创建身份串(Linux /proc/<pid>/stat starttime、macOS ps、Windows Get-Process);null = 无法可靠取得 */
|
|
25
|
+
osProcessStartIdentity: string | null;
|
|
26
|
+
/** 进程是否存活(best-effort) */
|
|
27
|
+
alive: boolean;
|
|
28
|
+
}
|
|
29
|
+
/** 可注入的进程身份探测门面(默认实现跨平台;测试可注入)。
|
|
30
|
+
* 契约:`alive:false` 只表示 **确证不存在**(ESRCH);探测失败/不确定必须 **抛错**,
|
|
31
|
+
* 由上层归为 UNKNOWN_STATE —— 绝不把失败误报为「确证死亡」(否则会成为误删许可)。 */
|
|
32
|
+
export interface ProcessIdentityProbe {
|
|
33
|
+
/** 探测某 pid 的存活与 OS 身份;确证不存在返回 alive:false;不确定/失败抛错 */
|
|
34
|
+
probe(pid: number): Promise<ProcessIdentity>;
|
|
35
|
+
/** 是否能够可靠取得 OS process creation identity(该平台上实现能力) */
|
|
36
|
+
canGetOsIdentity(): boolean;
|
|
37
|
+
}
|
|
38
|
+
/** 可注入 IO 门面(对齐 Phase 1 AtomicIo;默认包 node:fs/promises) */
|
|
39
|
+
export interface EnvLockIo {
|
|
40
|
+
mkdir(dir: string, opts: {
|
|
41
|
+
recursive: boolean;
|
|
42
|
+
}): Promise<void>;
|
|
43
|
+
/** open;flag 含 'x'(wx/wx+)用于独占创建 */
|
|
44
|
+
open(p: string, flag: string, mode?: number): Promise<EnvLockHandle>;
|
|
45
|
+
rename(src: string, dst: string): Promise<void>;
|
|
46
|
+
unlink(p: string): Promise<void>;
|
|
47
|
+
stat(p: string): Promise<{
|
|
48
|
+
isFile(): boolean;
|
|
49
|
+
} | null>;
|
|
50
|
+
readFileText(p: string): Promise<string>;
|
|
51
|
+
lstat?(p: string): Promise<{
|
|
52
|
+
isSymbolicLink(): boolean;
|
|
53
|
+
} | null>;
|
|
54
|
+
/** 列出目录条目名(诊断;不存在 → 空) */
|
|
55
|
+
listLocksDir?(dir: string): Promise<string[]>;
|
|
56
|
+
}
|
|
57
|
+
export interface EnvLockHandle {
|
|
58
|
+
writeFile(data: Uint8Array): Promise<void>;
|
|
59
|
+
sync(): Promise<void>;
|
|
60
|
+
close(): Promise<void>;
|
|
61
|
+
}
|
|
62
|
+
export type LockState =
|
|
63
|
+
/** 成功获得所有权 */
|
|
64
|
+
'ACQUIRED'
|
|
65
|
+
/** 锁被活跃 owner 持有 */
|
|
66
|
+
| 'LOCKED'
|
|
67
|
+
/** 检测到确定 stale(heartbeat 超时 + 进程确证死亡 或 PID reuse)—— 只报告,不自动删除 */
|
|
68
|
+
| 'STALE_LOCK_DETECTED'
|
|
69
|
+
/** 无法可靠判定(探测失败 / OS identity 缺失)—— 不删除、不 recover、destructive 不执行 */
|
|
70
|
+
| 'UNKNOWN_STATE'
|
|
71
|
+
/** lock 目录 / 文件 IO 错误(非占用) */
|
|
72
|
+
| 'LOCK_IO_ERROR'
|
|
73
|
+
/** 权限错误(EPERM/EACCES 且无法确认 lock 存在) */
|
|
74
|
+
| 'PERMISSION_ERROR';
|
|
75
|
+
/** 所有权记录(immutable):写入后直到 release 不再改名/替换 */
|
|
76
|
+
export interface LockOwnershipRecord {
|
|
77
|
+
schemaVersion: number;
|
|
78
|
+
owner: {
|
|
79
|
+
instanceId: string;
|
|
80
|
+
/** 本实例启动时刻(Date.now(),应用层时间戳;PID reuse 判断不使用它) */
|
|
81
|
+
instanceStartedAt: number;
|
|
82
|
+
pid: number;
|
|
83
|
+
hostname: string;
|
|
84
|
+
/** OS 可验证的进程创建身份(写入方 acquire 时探测自身);可能为 null */
|
|
85
|
+
osProcessStartIdentity: string | null;
|
|
86
|
+
};
|
|
87
|
+
op: string;
|
|
88
|
+
target: string;
|
|
89
|
+
acquiredAt: number;
|
|
90
|
+
lockVersion: string;
|
|
91
|
+
/** 预留 Phase 3 journal id;本阶段恒 null,不实现 */
|
|
92
|
+
journalId: string | null;
|
|
93
|
+
}
|
|
94
|
+
/** heartbeat sidecar 内容(atomicWriteFile 更新;文件名含 instanceId) */
|
|
95
|
+
export interface HeartbeatRecord {
|
|
96
|
+
ownerInstanceId: string;
|
|
97
|
+
heartbeatAt: number;
|
|
98
|
+
seq: number;
|
|
99
|
+
}
|
|
100
|
+
/** 一次 acquire 的返回 */
|
|
101
|
+
export interface AcquireResult {
|
|
102
|
+
state: LockState;
|
|
103
|
+
/** state === 'ACQUIRED' 时非 null */
|
|
104
|
+
token: MutationLockToken | null;
|
|
105
|
+
/** 诊断信息(非敏感):占用方 op/hostname、或错误描述 */
|
|
106
|
+
detail?: string;
|
|
107
|
+
}
|
|
108
|
+
/** operation-scoped lock token:accepted 后只属于当前 mutation 调用链 */
|
|
109
|
+
export interface MutationLockToken {
|
|
110
|
+
/** 本 token 唯一的不可伪造 id */
|
|
111
|
+
readonly tokenId: string;
|
|
112
|
+
/** 所属 manager 身份(防止 foreign token) */
|
|
113
|
+
readonly managerId: string;
|
|
114
|
+
/** owner instanceId(release 校验用) */
|
|
115
|
+
readonly instanceId: string;
|
|
116
|
+
/** acquire 时刻 */
|
|
117
|
+
readonly acquiredAt: number;
|
|
118
|
+
}
|
|
119
|
+
/** nested operation 显式传递的 lock context */
|
|
120
|
+
export interface MutationLockContext {
|
|
121
|
+
readonly token: MutationLockToken;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* core/CLI/ModelTools 依赖的最小锁契约(与具体 EnvironmentLockManager 解耦,便于 mock 测试)。
|
|
125
|
+
* 满足:acquire → 无 token 时获取全局锁;reuseLock → nested 复用(不 reacquire)。
|
|
126
|
+
*/
|
|
127
|
+
export interface MutationLockPort {
|
|
128
|
+
/**
|
|
129
|
+
* 尝试获取 GLOBAL mutation lock。
|
|
130
|
+
* @param parentContext 若提供且有效(validate=true),表示调用链已持锁 → 复用,不 reacquire,恒返回 {state:'ACQUIRED', token: parentContext.token}
|
|
131
|
+
* @returns 未持锁时走完整 acquire;被占 → LOCKED;stale/unknown → 对应状态(不自动删)
|
|
132
|
+
*/
|
|
133
|
+
acquire(opts: {
|
|
134
|
+
op: string;
|
|
135
|
+
target?: string;
|
|
136
|
+
/** nested:若有效父 token → 复用(不 reacquire),否则正常 acquire */
|
|
137
|
+
parentContext?: MutationLockContext;
|
|
138
|
+
}): Promise<AcquireResult>;
|
|
139
|
+
/** 校验 token 是否有效且属于当前持有(nested reuse 判断用) */
|
|
140
|
+
validate(token: unknown): token is MutationLockToken;
|
|
141
|
+
/** release(release 前校验 instanceId;mismatch 抛 EnvironmentLockOwnedByAnotherError) */
|
|
142
|
+
release(token: MutationLockToken): Promise<void>;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* 便捷包装:核心引擎「无父 token → acquire;有有效父 token → reuse(不 reacquire)」。
|
|
146
|
+
* 返回 { token, context, release }:调用方在 finally 中调用 release(仅当本次真正 acquire 才 release)。
|
|
147
|
+
* 若未提供 port(测试/无锁环境)→ 恒成功、不锁定(token=null、release = no-op)。
|
|
148
|
+
*
|
|
149
|
+
* @example
|
|
150
|
+
* const { context, release } = await withMutationLock(ctx.mutationLock, { op: 'import', target })
|
|
151
|
+
* if (!context) throw new Error('环境锁被占用') // token===null 且真正需要锁 → 被挡
|
|
152
|
+
* try { ...mutation...; await rollback(..., { lockContext: context }) } finally { await release() }
|
|
153
|
+
*/
|
|
154
|
+
/**
|
|
155
|
+
* 便捷包装:核心/宿主「无父 token → acquire;有有效父 token → reuse(不 reacquire)」。
|
|
156
|
+
* 返回 { context, release }:
|
|
157
|
+
* - context 非 null = 有锁(或已传入有效父 token 复用);release 仅当**本次真正 acquire**才实际释放;
|
|
158
|
+
* - context null = 锁不可得(被挡)或未配置锁环境。
|
|
159
|
+
* 调用方必须区分:port 未配置(无锁环境)→ context null 且可放行;port 已配置但 context null → 被挡必须拒绝。
|
|
160
|
+
*/
|
|
161
|
+
export declare function withMutationLock(port: MutationLockPort | undefined, opts: {
|
|
162
|
+
op: string;
|
|
163
|
+
target?: string;
|
|
164
|
+
parentContext?: MutationLockContext;
|
|
165
|
+
isBlocked?: () => boolean;
|
|
166
|
+
}): Promise<{
|
|
167
|
+
context: MutationLockContext | null;
|
|
168
|
+
release(): Promise<void>;
|
|
169
|
+
reason?: LockBlockReason;
|
|
170
|
+
detail?: string;
|
|
171
|
+
}>;
|
|
172
|
+
/**
|
|
173
|
+
* 直接执行式的 mutation 守卫:acquire(或复用父 token)→ 执行 → 释放。
|
|
174
|
+
* - port 未配置(无锁环境/测试)→ 直接执行 fn(null),不锁定。
|
|
175
|
+
* - port 已配置但 acquire 失败 → **抛 EnvironmentLockUnavailableError**(destructive 不得执行)。
|
|
176
|
+
* - 复用父 token 时(parentContext 有效)→ 不 reacquire、不释放父 token,fn 收到父 context。
|
|
177
|
+
*/
|
|
178
|
+
export declare function runWithMutationLock<T>(port: MutationLockPort | undefined, opts: {
|
|
179
|
+
op: string;
|
|
180
|
+
target?: string;
|
|
181
|
+
parentContext?: MutationLockContext;
|
|
182
|
+
isBlocked?: () => boolean;
|
|
183
|
+
}, fn: (ctx: MutationLockContext | null) => Promise<T>): Promise<T>;
|
|
184
|
+
/** 判断某 state 是否意味着「未获得锁(被挡)」;ACQUIRED 才放行 destructive */
|
|
185
|
+
export declare function isAcquired(state: LockState): boolean;
|
|
186
|
+
/** 一次 recover 的返回 */
|
|
187
|
+
export interface RecoverResult {
|
|
188
|
+
ok: boolean;
|
|
189
|
+
/** 是否实际移除了 stale inode(ok=true 时为 true) */
|
|
190
|
+
removed: boolean;
|
|
191
|
+
/** 判定:STALE_LOCK_DETECTED / UNKNOWN_STATE(拒绝)/ LOCKED(拒绝,owner healthy)/ LOCK_IO_ERROR / PERMISSION_ERROR */
|
|
192
|
+
state: LockState;
|
|
193
|
+
/** 诊断 */
|
|
194
|
+
detail?: string;
|
|
195
|
+
}
|
|
196
|
+
export interface EnvLockManagerOptions {
|
|
197
|
+
/** dataDir(缺省 ~/.dsh/dsh-config-manager)—— 锁在 <dataDir>/locks */
|
|
198
|
+
dataDir?: string;
|
|
199
|
+
/** 覆盖绝对 locks 目录(测试/CLI 注入) */
|
|
200
|
+
locksDir?: string;
|
|
201
|
+
/** 可注入 io */
|
|
202
|
+
io?: EnvLockIo;
|
|
203
|
+
/** 可注入进程探测 */
|
|
204
|
+
probe?: ProcessIdentityProbe;
|
|
205
|
+
/** 时钟(测试注入) */
|
|
206
|
+
now?: () => number;
|
|
207
|
+
/** 心跳间隔 ms(缺省 1000) */
|
|
208
|
+
heartbeatIntervalMs?: number;
|
|
209
|
+
/** stale 阈值 ms(缺省 10000) */
|
|
210
|
+
staleAfterMs?: number;
|
|
211
|
+
/** acquire 等待活跃锁释放的超时 ms(缺省 0=不等待) */
|
|
212
|
+
acquireTimeoutMs?: number;
|
|
213
|
+
/** 「心跳长过期」阈值 ms(issue #36;缺省 max(30 × staleAfterMs, 30 分钟))。
|
|
214
|
+
* 只影响「pid 存活但进程身份不可验证」这一类锁的**显式**回收与状态分类,不放松自动侧。 */
|
|
215
|
+
longExpiredAfterMs?: number;
|
|
216
|
+
/** 诊断用的当前 operation 描述(写入 ownership.op) */
|
|
217
|
+
op?: string;
|
|
218
|
+
/** 诊断用的 target 描述 */
|
|
219
|
+
target?: string;
|
|
220
|
+
/** 插件版本(写入 ownership.lockVersion) */
|
|
221
|
+
lockVersion?: string;
|
|
222
|
+
/** heartbeat 续期写失败回调(留痕;不中断 mutation) */
|
|
223
|
+
onHeartbeatWriteFailure?: (err: unknown) => void;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* EnvironmentLockManager:跨进程环境锁管理器。
|
|
227
|
+
*
|
|
228
|
+
* 用法:
|
|
229
|
+
* const mgr = new EnvironmentLockManager({ locksDir })
|
|
230
|
+
* const { state, token } = await mgr.acquire({ op: 'import' })
|
|
231
|
+
* if (state !== 'ACQUIRED') throw ... // destructive 必须成功 acquire
|
|
232
|
+
* try { ...mutation... } finally { await mgr.release(token) }
|
|
233
|
+
* // nested rollback:mutation 内 rollback(..., { lockContext: { token } }) → reuse,不 reacquire
|
|
234
|
+
*/
|
|
235
|
+
export declare class EnvironmentLockManager {
|
|
236
|
+
private readonly locksDir;
|
|
237
|
+
private readonly io;
|
|
238
|
+
private readonly probe;
|
|
239
|
+
private readonly now;
|
|
240
|
+
private readonly heartbeatIntervalMs;
|
|
241
|
+
private readonly staleAfterMs;
|
|
242
|
+
private readonly longExpiredAfterMs;
|
|
243
|
+
private readonly acquireTimeoutMs;
|
|
244
|
+
private readonly lockVersion;
|
|
245
|
+
private readonly onHeartbeatWriteFailure;
|
|
246
|
+
/** 诊断用(acquire 时写 ownership.op/target) */
|
|
247
|
+
private readonly defaultOp;
|
|
248
|
+
private readonly defaultTarget;
|
|
249
|
+
/** 本 manager 唯一 id(forever token 校验用) */
|
|
250
|
+
private readonly managerId;
|
|
251
|
+
/** 本 manager 持有的当前活跃 token(单锁单持有者) */
|
|
252
|
+
private activeToken;
|
|
253
|
+
private heartbeatTimer;
|
|
254
|
+
private heartbeatSeq;
|
|
255
|
+
private readonly activeInstanceId;
|
|
256
|
+
private heartbeatDegraded;
|
|
257
|
+
/** 串行化的 heartbeat 写链(**最后一次写**的 promise);release 前用于 drain,见 drainHeartbeat */
|
|
258
|
+
private pendingHeartbeat;
|
|
259
|
+
/** 瞬时错误(EBUSY 等)有界重试计数 */
|
|
260
|
+
private transientRetries;
|
|
261
|
+
private readonly maxTransientRetries;
|
|
262
|
+
/** 有界瞬时重试:EBUSY(Windows sharing violation / 杀软)后小退避重试;超限则返回 false(交由 classify) */
|
|
263
|
+
private tryTransientRetry;
|
|
264
|
+
/** 重置瞬时重试计数(每次 acquire 成功/失败收敛时调用) */
|
|
265
|
+
private resetTransientRetries;
|
|
266
|
+
constructor(opts?: EnvLockManagerOptions);
|
|
267
|
+
get ownershipPath(): string;
|
|
268
|
+
get locksDirectory(): string;
|
|
269
|
+
/** 本 manager 是否当前持有锁(诊断用) */
|
|
270
|
+
get isHolding(): boolean;
|
|
271
|
+
/**
|
|
272
|
+
* 尝试获取 GLOBAL mutation lock。
|
|
273
|
+
* - 成功 → state=ACQUIRED,返回 token(token 只属于当前调用链)。
|
|
274
|
+
* - 被活跃 owner 持有 → LOCKED(可选等待 acquireTimeoutMs 后仍失败)。
|
|
275
|
+
* - 确定 stale → STALE_LOCK_DETECTED(**不自动删除**;destructive 不得执行)。
|
|
276
|
+
* - 其它 → UNKNOWN_STATE / LOCK_IO_ERROR / PERMISSION_ERROR。
|
|
277
|
+
*
|
|
278
|
+
* 所有权用 `open(ownershipPath, 'wx')` 独占创建;**绝不用 atomicWriteFile 获取所有权**。
|
|
279
|
+
*/
|
|
280
|
+
acquire(opts?: {
|
|
281
|
+
op?: string;
|
|
282
|
+
target?: string;
|
|
283
|
+
}): Promise<AcquireResult>;
|
|
284
|
+
/**
|
|
285
|
+
* 校验 token 是否有效且属于当前持有(供 nested operation 判断能否 reuse)。
|
|
286
|
+
* 返回 true = 该 token 授权本调用链 reuse 当前持有。
|
|
287
|
+
*/
|
|
288
|
+
validate(token: unknown): token is MutationLockToken;
|
|
289
|
+
/**
|
|
290
|
+
* 释放锁:release 前**校验 ownership record 的 instanceId === token.instanceId**(以及 manager/tokenId)。
|
|
291
|
+
* 匹配 → 清理 heartbeat + unlink ownership;不匹配 → **不 unlink**,记录 ownership-lost violation。
|
|
292
|
+
*
|
|
293
|
+
* 错误语义(F2 修复):仅当磁盘 ownership 被确认成功删除后才清空 activeToken;unlink 失败/异常时
|
|
294
|
+
* **保留 activeToken**(本调用链仍持有该 inode),允许调用方重试 release,绝不留下"令牌已失效但锁在磁盘上"的卡死态。
|
|
295
|
+
*/
|
|
296
|
+
release(token: MutationLockToken): Promise<void>;
|
|
297
|
+
private startHeartbeat;
|
|
298
|
+
private stopHeartbeat;
|
|
299
|
+
/**
|
|
300
|
+
* 等待**当前在途**的 heartbeat 写完成(release 清理 sidecar 前必须调用)。
|
|
301
|
+
* 为什么必要:writeHeartbeat 走 atomicWriteFile(tmp 写入 → rename),是异步多步操作。
|
|
302
|
+
* 若 release 只 stopHeartbeat + unlink sidecar 而不等待,一个已启动的写会在 unlink 之后才 rename,
|
|
303
|
+
* 于是把刚删掉的 sidecar **重新创建**(或残留 .dshcm.*.tmp)——Windows 上即 after-hook rmSync ENOTEMPTY。
|
|
304
|
+
* 调用点保证:release 先同步 stopHeartbeat() 并置 activeToken=null,故此刻起不会有新的写开始;
|
|
305
|
+
* 因此 drain 之后 cleanupHeartbeat 删除的 sidecar 不会再被复活。
|
|
306
|
+
*/
|
|
307
|
+
private drainHeartbeat;
|
|
308
|
+
/** 串行化并追踪一次 heartbeat 写:chain 保证不会有两个写并发 rename 同一个 sidecar */
|
|
309
|
+
private trackHeartbeat;
|
|
310
|
+
/** 写 heartbeat sidecar(atomicWriteFile 更新 sidecar,不影响 ownership;失败 → degraded,不中断 mutation) */
|
|
311
|
+
private writeHeartbeat;
|
|
312
|
+
/** 删除指定 instanceId 的 heartbeat sidecar(不受 activeToken 状态影响——F1 修复;调用方传自己的 instanceId)。 */
|
|
313
|
+
private cleanupHeartbeat;
|
|
314
|
+
/** 检查 environment.lock 是否确实存在(§8.1 分类用;stat 失败/无法确认 → null) */
|
|
315
|
+
private statLockExists;
|
|
316
|
+
/** ownership 三态读取:missing(缺失)/ corrupt(存在但空或非法)/ ok(有效 owner)。
|
|
317
|
+
* 用于区分「无锁」与「崩溃残留的 0 字节/损坏锁」——后者可被显式 recovery 安全回收(无有效 owner 无从误删)。 */
|
|
318
|
+
private readOwnershipState;
|
|
319
|
+
/** 读取 owner instanceId 的 heartbeat sidecar(无 → null) */
|
|
320
|
+
private readHeartbeat;
|
|
321
|
+
/**
|
|
322
|
+
* 判定锁状态(只分类)。按 Design §6.3 正式状态表:
|
|
323
|
+
* heartbeat fresh → LOCKED
|
|
324
|
+
* heartbeat expired + PID dead → STALE_LOCK_DETECTED
|
|
325
|
+
* heartbeat expired + PID alive + identity 不同 → STALE_LOCK_DETECTED (PID reuse)
|
|
326
|
+
* heartbeat expired + PID alive + identity 相同 → LOCKED (owner alive / heartbeat degraded)
|
|
327
|
+
* probe 无法可靠确定 → UNKNOWN_STATE
|
|
328
|
+
*/
|
|
329
|
+
inspectLockState(): Promise<{
|
|
330
|
+
state: LockState;
|
|
331
|
+
detail?: string;
|
|
332
|
+
}>;
|
|
333
|
+
/**
|
|
334
|
+
* 显式 stale recovery(独立动作;对应 CLI `--recover-stale-lock`)。
|
|
335
|
+
* 只执行:inspect → prove definitely stale → 原子 rename 捕获 → 二次验证 → unlink。
|
|
336
|
+
* **不自动触发**;仅当检测为 STALE_LOCK_DETECTED 才允许 capture。
|
|
337
|
+
* 二次验证失败 → quarantine(保留 recovering 文件,不 rename 回环境锁,不覆盖 successor)。
|
|
338
|
+
*/
|
|
339
|
+
recoverStaleLock(): Promise<RecoverResult>;
|
|
340
|
+
/** recovery 二次验证:重新探测 recorded pid 是否确证死亡(保守——任何不确定性 → 失败)。
|
|
341
|
+
* 与 inspectLockState 同一套语义:alive:false 仅确证死亡 → stale 成立;
|
|
342
|
+
* alive 则需 OS identity 判断是否 reuse;无法确定 → 保守失败(不删除)。 */
|
|
343
|
+
private reProveStale;
|
|
344
|
+
/** 心跳「长过期」判据(issue #36):达到阈值 → 返回可读原因,否则 null。
|
|
345
|
+
* heartbeat sidecar 缺失时返回 null(无从判断过期时长)——只对「确实读过 heartbeat
|
|
346
|
+
* 且它早已停更」的锁放宽,避免把「sidecar 被清掉」误判成残留。 */
|
|
347
|
+
private longExpiredReason;
|
|
348
|
+
/** 列出 locks 目录内容(诊断;不存在 → 空) */
|
|
349
|
+
listLockFiles(): Promise<string[]>;
|
|
350
|
+
}
|
|
351
|
+
/** 当 release/recover 发现 ownership 已不属于本 token(异常恢复/人工修改)时抛出 */
|
|
352
|
+
export declare class EnvironmentLockOwnedByAnotherError extends Error {
|
|
353
|
+
constructor(msg: string);
|
|
354
|
+
}
|
|
355
|
+
/** release 时 IO 失败(unlink/读 ownership)抛出;保留 activeToken 以便调用方重试 release */
|
|
356
|
+
export declare class EnvironmentLockIOError extends Error {
|
|
357
|
+
readonly underlyingCause: unknown;
|
|
358
|
+
constructor(msg: string, underlying?: unknown);
|
|
359
|
+
}
|
|
360
|
+
/** 锁被挡时向用户呈现的分类(用户可读文案据此选择,绝不暴露环境锁/op/路径等内部细节)。 */
|
|
361
|
+
export type LockBlockReason =
|
|
362
|
+
/** 被另一进程/任务活跃持有(LOCKED → 「另一个任务正在运行,请稍后重试」) */
|
|
363
|
+
'locked'
|
|
364
|
+
/** Phase 3 SAFE MODE 注入谓词阻断(isBlocked → 「配置修改已被保护,请先处理恢复事项」) */
|
|
365
|
+
| 'blocked'
|
|
366
|
+
/**
|
|
367
|
+
* 检测到 stale 残留锁(上次进程异常退出,持有者已确证死亡)——**重试不会自愈**,
|
|
368
|
+
* 必须显式回收(GUI「事故恢复」/ CLI `recover-stale-lock`)。见 issue #27。
|
|
369
|
+
*/
|
|
370
|
+
| 'stale'
|
|
371
|
+
/** 锁不可用/IO/权限/UNKNOWN(→ 「操作暂时无法执行,请稍后重试」) */
|
|
372
|
+
| 'unavailable';
|
|
373
|
+
/** 按分类生成用户可读的友好文案(内部诊断不进入此文案;op/reason 作为字段供日志使用)。
|
|
374
|
+
* 导出:后台调度器(自动同步/定时备份)被挡时用同一份文案写日志,避免两处文案漂移。 */
|
|
375
|
+
export declare const LOCK_BLOCK_MESSAGE: Record<LockBlockReason, string>;
|
|
376
|
+
/** 分类的**简短**文案(单行、可用于表格单元格/迁移历史摘要/日志前缀)。
|
|
377
|
+
* 与 LOCK_BLOCK_MESSAGE 同源同分类:长文案给「需要完整指引」的场景(423 响应/告警日志),
|
|
378
|
+
* 短文案给「一行放不下长句」的场景。分开定义避免任一处再自造文案(issue #31 的漂移根因)。 */
|
|
379
|
+
export declare const LOCK_BLOCK_BRIEF: Record<LockBlockReason, string>;
|
|
380
|
+
/** destructive 必须成功获取 Environment Lock;否则抛此错(被另一进程/操作持有,或锁不可用)。
|
|
381
|
+
* 携带 op 与 reason 供内部日志诊断;.message 恒为用户可读的友好文案(不暴露锁/op/路径)。 */
|
|
382
|
+
export declare class EnvironmentLockUnavailableError extends Error {
|
|
383
|
+
readonly reason: LockBlockReason;
|
|
384
|
+
readonly op: string;
|
|
385
|
+
/**
|
|
386
|
+
* 内部诊断(非敏感):占用方 op/hostname 或 stale 判定依据。**只进日志**,
|
|
387
|
+
* 绝不进入 .message(用户文案里不含 op/路径/主机名)。
|
|
388
|
+
*/
|
|
389
|
+
readonly detail: string | undefined;
|
|
390
|
+
constructor(op: string, reason?: LockBlockReason, detail?: string);
|
|
391
|
+
}
|
|
392
|
+
/** 便捷:以 token 授权当前持有(供 nested operation 判断复用)—— 等价于 manager.validate 的纯函数形态 */
|
|
393
|
+
export declare function isTokenValid(manager: EnvironmentLockManager, ctx: MutationLockContext | undefined): ctx is MutationLockContext;
|