devchain-cli 0.24.0 → 0.24.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -4
- package/dist/build-info.json +2 -2
- package/dist/cli.js +66 -11
- package/dist/host-install/devchain-host-bootstrap.tgz +0 -0
- package/dist/host-install/pins.json +31 -2
- package/dist/lib/exclusive-run.js +51 -3
- package/dist/lib/git-owner.js +284 -0
- package/dist/lib/host-install.js +19 -151
- package/dist/lib/local-api.js +175 -0
- package/dist/server/common/config/env.config.d.ts +3 -0
- package/dist/server/common/config/env.config.js +1 -0
- package/dist/server/common/config/env.config.js.map +1 -1
- package/dist/server/common/config/host-image.json +3 -3
- package/dist/server/common/constants/syncthing-markers.d.ts +1 -0
- package/dist/server/common/constants/syncthing-markers.js +6 -1
- package/dist/server/common/constants/syncthing-markers.js.map +1 -1
- package/dist/server/common/filesystem/vm-home-path.d.ts +11 -0
- package/dist/server/common/filesystem/vm-home-path.js +48 -0
- package/dist/server/common/filesystem/vm-home-path.js.map +1 -0
- package/dist/server/common/process-ids-env.d.ts +1 -0
- package/dist/server/common/process-ids-env.js +13 -0
- package/dist/server/common/process-ids-env.js.map +1 -0
- package/dist/server/common/test/api-test-app.d.ts +12 -0
- package/dist/server/common/test/api-test-app.js +76 -0
- package/dist/server/common/test/api-test-app.js.map +1 -0
- package/dist/server/common/test/app-bootstrap.helper.js +8 -1
- package/dist/server/common/test/app-bootstrap.helper.js.map +1 -1
- package/dist/server/common/test/fake-bootstrap.server.js +3 -2
- package/dist/server/common/test/fake-bootstrap.server.js.map +1 -1
- package/dist/server/common/test/fake-docker-engine.server.d.ts +24 -6
- package/dist/server/common/test/fake-docker-engine.server.js +123 -25
- package/dist/server/common/test/fake-docker-engine.server.js.map +1 -1
- package/dist/server/common/test/fake-proxmox.server.js +4 -4
- package/dist/server/common/test/fake-ssh.server.js +6 -6
- package/dist/server/common/test/fake-ssh.server.js.map +1 -1
- package/dist/server/common/test/test-database.helper.d.ts +6 -0
- package/dist/server/common/test/test-database.helper.js +29 -0
- package/dist/server/common/test/test-database.helper.js.map +1 -0
- package/dist/server/modules/cloud-tunnel/services/mobile-chat-rpc.service.d.ts +1 -0
- package/dist/server/modules/cloud-tunnel/services/mobile-chat-rpc.service.js +9 -3
- package/dist/server/modules/cloud-tunnel/services/mobile-chat-rpc.service.js.map +1 -1
- package/dist/server/modules/cloud-tunnel/services/mobile-transcript-projection.d.ts +6 -0
- package/dist/server/modules/cloud-tunnel/services/mobile-transcript-projection.js +88 -0
- package/dist/server/modules/cloud-tunnel/services/mobile-transcript-projection.js.map +1 -0
- package/dist/server/modules/cloud-tunnel/services/tunnel-event-forwarder.service.js +7 -1
- package/dist/server/modules/cloud-tunnel/services/tunnel-event-forwarder.service.js.map +1 -1
- package/dist/server/modules/core/controllers/docker-archive.d.ts +9 -2
- package/dist/server/modules/core/controllers/docker-archive.js +22 -6
- package/dist/server/modules/core/controllers/docker-archive.js.map +1 -1
- package/dist/server/modules/core/controllers/docker-engine.client.d.ts +2 -1
- package/dist/server/modules/core/controllers/docker-engine.client.js +57 -4
- package/dist/server/modules/core/controllers/docker-engine.client.js.map +1 -1
- package/dist/server/modules/core/controllers/docker-image-metadata.d.ts +248 -0
- package/dist/server/modules/core/controllers/docker-image-metadata.js +161 -0
- package/dist/server/modules/core/controllers/docker-image-metadata.js.map +1 -0
- package/dist/server/modules/core/controllers/docker-settings.d.ts +13 -2
- package/dist/server/modules/core/controllers/docker-settings.js +49 -11
- package/dist/server/modules/core/controllers/docker-settings.js.map +1 -1
- package/dist/server/modules/core/controllers/host-user-identity.d.ts +34 -0
- package/dist/server/modules/core/controllers/host-user-identity.js +23 -0
- package/dist/server/modules/core/controllers/host-user-identity.js.map +1 -0
- package/dist/server/modules/core/controllers/runtime.controller.d.ts +11 -4
- package/dist/server/modules/core/controllers/runtime.controller.js +2 -0
- package/dist/server/modules/core/controllers/runtime.controller.js.map +1 -1
- package/dist/server/modules/file-sync/build-exclusion-suggestions.d.ts +15 -0
- package/dist/server/modules/file-sync/build-exclusion-suggestions.js +402 -0
- package/dist/server/modules/file-sync/build-exclusion-suggestions.js.map +1 -0
- package/dist/server/modules/file-sync/file-sync-auto-fix.dto.d.ts +102 -0
- package/dist/server/modules/file-sync/file-sync-auto-fix.dto.js +22 -0
- package/dist/server/modules/file-sync/file-sync-auto-fix.dto.js.map +1 -0
- package/dist/server/modules/file-sync/file-sync-auto-fix.store.d.ts +12 -0
- package/dist/server/modules/file-sync/file-sync-auto-fix.store.js +73 -0
- package/dist/server/modules/file-sync/file-sync-auto-fix.store.js.map +1 -0
- package/dist/server/modules/file-sync/file-sync-conflicts.d.ts +3 -0
- package/dist/server/modules/file-sync/file-sync-conflicts.js +191 -0
- package/dist/server/modules/file-sync/file-sync-conflicts.js.map +1 -0
- package/dist/server/modules/file-sync/file-sync-ignores.store.d.ts +5 -1
- package/dist/server/modules/file-sync/file-sync-ignores.store.js +39 -8
- package/dist/server/modules/file-sync/file-sync-ignores.store.js.map +1 -1
- package/dist/server/modules/file-sync/file-sync.controller.d.ts +1 -3
- package/dist/server/modules/file-sync/file-sync.controller.js +5 -14
- package/dist/server/modules/file-sync/file-sync.controller.js.map +1 -1
- package/dist/server/modules/file-sync/file-sync.dto.d.ts +220 -1
- package/dist/server/modules/file-sync/file-sync.dto.js +70 -4
- package/dist/server/modules/file-sync/file-sync.dto.js.map +1 -1
- package/dist/server/modules/file-sync/file-sync.module.js +16 -1
- package/dist/server/modules/file-sync/file-sync.module.js.map +1 -1
- package/dist/server/modules/file-sync/file-sync.service.d.ts +20 -5
- package/dist/server/modules/file-sync/file-sync.service.js +173 -37
- package/dist/server/modules/file-sync/file-sync.service.js.map +1 -1
- package/dist/server/modules/file-sync/git-guard.dto.d.ts +61 -0
- package/dist/server/modules/file-sync/git-guard.dto.js +26 -0
- package/dist/server/modules/file-sync/git-guard.dto.js.map +1 -0
- package/dist/server/modules/file-sync/home-git-guard.service.d.ts +4 -2
- package/dist/server/modules/file-sync/home-git-guard.service.js +50 -25
- package/dist/server/modules/file-sync/home-git-guard.service.js.map +1 -1
- package/dist/server/modules/file-sync/host-git-guard.controller.d.ts +10 -0
- package/dist/server/modules/file-sync/host-git-guard.controller.js +64 -0
- package/dist/server/modules/file-sync/host-git-guard.controller.js.map +1 -0
- package/dist/server/modules/file-sync/host-git-index.controller.d.ts +9 -0
- package/dist/server/modules/file-sync/host-git-index.controller.js +67 -0
- package/dist/server/modules/file-sync/host-git-index.controller.js.map +1 -0
- package/dist/server/modules/file-sync/host-sync.controller.d.ts +15 -2
- package/dist/server/modules/file-sync/host-sync.controller.js +122 -14
- package/dist/server/modules/file-sync/host-sync.controller.js.map +1 -1
- package/dist/server/modules/file-sync/ignore-pattern-matcher.d.ts +30 -0
- package/dist/server/modules/file-sync/ignore-pattern-matcher.js +183 -0
- package/dist/server/modules/file-sync/ignore-pattern-matcher.js.map +1 -0
- package/dist/server/modules/file-sync/project-repository.d.ts +2 -0
- package/dist/server/modules/file-sync/project-repository.js +20 -0
- package/dist/server/modules/file-sync/project-repository.js.map +1 -0
- package/dist/server/modules/file-sync/sync-chown.dto.d.ts +99 -0
- package/dist/server/modules/file-sync/sync-chown.dto.js +46 -0
- package/dist/server/modules/file-sync/sync-chown.dto.js.map +1 -0
- package/dist/server/modules/file-sync/sync-chown.service.d.ts +12 -0
- package/dist/server/modules/file-sync/sync-chown.service.js +230 -0
- package/dist/server/modules/file-sync/sync-chown.service.js.map +1 -0
- package/dist/server/modules/file-sync/sync-path-inspection.dto.d.ts +626 -0
- package/dist/server/modules/file-sync/sync-path-inspection.dto.js +108 -0
- package/dist/server/modules/file-sync/sync-path-inspection.dto.js.map +1 -0
- package/dist/server/modules/file-sync/sync-path-inspector.d.ts +12 -0
- package/dist/server/modules/file-sync/sync-path-inspector.js +413 -0
- package/dist/server/modules/file-sync/sync-path-inspector.js.map +1 -0
- package/dist/server/modules/file-sync/syncthing-rest.client.d.ts +1 -1
- package/dist/server/modules/file-sync/syncthing-rest.client.js +9 -4
- package/dist/server/modules/file-sync/syncthing-rest.client.js.map +1 -1
- package/dist/server/modules/file-sync/testing/fake-file-sync.service.d.ts +28 -5
- package/dist/server/modules/file-sync/testing/fake-file-sync.service.js +68 -5
- package/dist/server/modules/file-sync/testing/fake-file-sync.service.js.map +1 -1
- package/dist/server/modules/file-sync/translate-git-ignore-rule.d.ts +3 -0
- package/dist/server/modules/file-sync/translate-git-ignore-rule.js +30 -0
- package/dist/server/modules/file-sync/translate-git-ignore-rule.js.map +1 -0
- package/dist/server/modules/hooks/dtos/hook-event.dto.d.ts +86 -0
- package/dist/server/modules/hooks/dtos/hook-event.dto.js +15 -1
- package/dist/server/modules/hooks/dtos/hook-event.dto.js.map +1 -1
- package/dist/server/modules/hooks/services/hooks-config.service.js +29 -0
- package/dist/server/modules/hooks/services/hooks-config.service.js.map +1 -1
- package/dist/server/modules/hooks/services/hooks.service.d.ts +5 -1
- package/dist/server/modules/hooks/services/hooks.service.js +27 -5
- package/dist/server/modules/hooks/services/hooks.service.js.map +1 -1
- package/dist/server/modules/hooks/services/pending-ask-user-question.service.d.ts +2 -2
- package/dist/server/modules/hooks/services/pending-ask-user-question.service.js +9 -12
- package/dist/server/modules/hooks/services/pending-ask-user-question.service.js.map +1 -1
- package/dist/server/modules/mcp/services/handlers/skill-tools.js +2 -2
- package/dist/server/modules/mcp/services/handlers/skill-tools.js.map +1 -1
- package/dist/server/modules/metrics/services/metrics.service.js +1 -1
- package/dist/server/modules/metrics/services/metrics.service.js.map +1 -1
- package/dist/server/modules/providers/adapters/claude.adapter.d.ts +3 -1
- package/dist/server/modules/providers/adapters/claude.adapter.js +4 -1
- package/dist/server/modules/providers/adapters/claude.adapter.js.map +1 -1
- package/dist/server/modules/remotes/connect-choices.controller.d.ts +9 -0
- package/dist/server/modules/remotes/connect-choices.controller.js +54 -0
- package/dist/server/modules/remotes/connect-choices.controller.js.map +1 -0
- package/dist/server/modules/remotes/connect-choices.dto.d.ts +52 -0
- package/dist/server/modules/remotes/connect-choices.dto.js +19 -0
- package/dist/server/modules/remotes/connect-choices.dto.js.map +1 -0
- package/dist/server/modules/remotes/connect-choices.store.d.ts +12 -0
- package/dist/server/modules/remotes/connect-choices.store.js +95 -0
- package/dist/server/modules/remotes/connect-choices.store.js.map +1 -0
- package/dist/server/modules/remotes/controllers/remotes.controller.d.ts +3 -0
- package/dist/server/modules/remotes/controllers/remotes.controller.js +9 -1
- package/dist/server/modules/remotes/controllers/remotes.controller.js.map +1 -1
- package/dist/server/modules/remotes/docker/docker-copy-back.d.ts +1 -0
- package/dist/server/modules/remotes/docker/docker-copy-back.js +70 -31
- package/dist/server/modules/remotes/docker/docker-copy-back.js.map +1 -1
- package/dist/server/modules/remotes/docker/docker-handoff.d.ts +5 -3
- package/dist/server/modules/remotes/docker/docker-handoff.js +221 -53
- package/dist/server/modules/remotes/docker/docker-handoff.js.map +1 -1
- package/dist/server/modules/remotes/docker/docker-handoff.store.d.ts +5 -0
- package/dist/server/modules/remotes/docker/docker-handoff.store.js.map +1 -1
- package/dist/server/modules/remotes/docker/docker-plan-fit.d.ts +4 -1
- package/dist/server/modules/remotes/docker/docker-plan-fit.js +19 -6
- package/dist/server/modules/remotes/docker/docker-plan-fit.js.map +1 -1
- package/dist/server/modules/remotes/docker/docker-plan-policy.d.ts +6 -2
- package/dist/server/modules/remotes/docker/docker-plan-policy.js +191 -38
- package/dist/server/modules/remotes/docker/docker-plan-policy.js.map +1 -1
- package/dist/server/modules/remotes/docker/docker-plan-source.service.d.ts +55 -6
- package/dist/server/modules/remotes/docker/docker-plan-source.service.js +284 -52
- package/dist/server/modules/remotes/docker/docker-plan-source.service.js.map +1 -1
- package/dist/server/modules/remotes/docker/docker-plan.controller.d.ts +2 -1
- package/dist/server/modules/remotes/docker/docker-plan.controller.js +15 -1
- package/dist/server/modules/remotes/docker/docker-plan.controller.js.map +1 -1
- package/dist/server/modules/remotes/docker/docker-plan.dto.d.ts +47 -1
- package/dist/server/modules/remotes/docker/docker-plan.dto.js +1 -0
- package/dist/server/modules/remotes/docker/docker-plan.dto.js.map +1 -1
- package/dist/server/modules/remotes/docker/docker-plan.service.d.ts +15 -6
- package/dist/server/modules/remotes/docker/docker-plan.service.js +83 -20
- package/dist/server/modules/remotes/docker/docker-plan.service.js.map +1 -1
- package/dist/server/modules/remotes/docker/docker-project-compose.d.ts +7 -0
- package/dist/server/modules/remotes/docker/docker-project-compose.js +30 -0
- package/dist/server/modules/remotes/docker/docker-project-compose.js.map +1 -0
- package/dist/server/modules/remotes/dtos/remote.dto.d.ts +2 -0
- package/dist/server/modules/remotes/dtos/remote.dto.js.map +1 -1
- package/dist/server/modules/remotes/git-owner.store.d.ts +13 -0
- package/dist/server/modules/remotes/git-owner.store.js +69 -0
- package/dist/server/modules/remotes/git-owner.store.js.map +1 -0
- package/dist/server/modules/remotes/host/host-docker.controller.d.ts +14 -1
- package/dist/server/modules/remotes/host/host-docker.controller.js +28 -9
- package/dist/server/modules/remotes/host/host-docker.controller.js.map +1 -1
- package/dist/server/modules/remotes/host/host-docker.dto.d.ts +640 -3
- package/dist/server/modules/remotes/host/host-docker.dto.js +66 -9
- package/dist/server/modules/remotes/host/host-docker.dto.js.map +1 -1
- package/dist/server/modules/remotes/host/host-docker.service.d.ts +18 -6
- package/dist/server/modules/remotes/host/host-docker.service.js +184 -81
- package/dist/server/modules/remotes/host/host-docker.service.js.map +1 -1
- package/dist/server/modules/remotes/host/host-ipv4-routes.d.ts +4 -0
- package/dist/server/modules/remotes/host/host-ipv4-routes.js +43 -0
- package/dist/server/modules/remotes/host/host-ipv4-routes.js.map +1 -0
- package/dist/server/modules/remotes/host-image.d.ts +1 -1
- package/dist/server/modules/remotes/host-image.js +1 -1
- package/dist/server/modules/remotes/host-install/host-install-block.d.ts +1 -0
- package/dist/server/modules/remotes/host-install/host-install-block.js +76 -2
- package/dist/server/modules/remotes/host-install/host-install-block.js.map +1 -1
- package/dist/server/modules/remotes/host-install/host-install.service.d.ts +0 -1
- package/dist/server/modules/remotes/host-install/host-install.service.js +9 -26
- package/dist/server/modules/remotes/host-install/host-install.service.js.map +1 -1
- package/dist/server/modules/remotes/operations/attach.operation.d.ts +5 -1
- package/dist/server/modules/remotes/operations/attach.operation.js +41 -5
- package/dist/server/modules/remotes/operations/attach.operation.js.map +1 -1
- package/dist/server/modules/remotes/operations/claim.operation.d.ts +1 -0
- package/dist/server/modules/remotes/operations/claim.operation.js +6 -1
- package/dist/server/modules/remotes/operations/claim.operation.js.map +1 -1
- package/dist/server/modules/remotes/operations/detach.operation.d.ts +4 -1
- package/dist/server/modules/remotes/operations/detach.operation.js +10 -2
- package/dist/server/modules/remotes/operations/detach.operation.js.map +1 -1
- package/dist/server/modules/remotes/operations/docker-import-inventory.store.d.ts +10 -0
- package/dist/server/modules/remotes/operations/docker-import-inventory.store.js +17 -0
- package/dist/server/modules/remotes/operations/docker-import-inventory.store.js.map +1 -1
- package/dist/server/modules/remotes/operations/file-sync-handoff.d.ts +30 -2
- package/dist/server/modules/remotes/operations/file-sync-handoff.js +498 -57
- package/dist/server/modules/remotes/operations/file-sync-handoff.js.map +1 -1
- package/dist/server/modules/remotes/operations/force-sync.operation.d.ts +39 -0
- package/dist/server/modules/remotes/operations/force-sync.operation.js +177 -0
- package/dist/server/modules/remotes/operations/force-sync.operation.js.map +1 -0
- package/dist/server/modules/remotes/operations/git-owner.dto.d.ts +83 -0
- package/dist/server/modules/remotes/operations/git-owner.dto.js +25 -0
- package/dist/server/modules/remotes/operations/git-owner.dto.js.map +1 -0
- package/dist/server/modules/remotes/operations/git-owner.operation.d.ts +35 -0
- package/dist/server/modules/remotes/operations/git-owner.operation.js +216 -0
- package/dist/server/modules/remotes/operations/git-owner.operation.js.map +1 -0
- package/dist/server/modules/remotes/operations/remote-host.client.d.ts +72 -8
- package/dist/server/modules/remotes/operations/remote-host.client.js +162 -28
- package/dist/server/modules/remotes/operations/remote-host.client.js.map +1 -1
- package/dist/server/modules/remotes/operations/remote-operation.dto.d.ts +19 -0
- package/dist/server/modules/remotes/operations/remote-operation.dto.js +5 -1
- package/dist/server/modules/remotes/operations/remote-operation.dto.js.map +1 -1
- package/dist/server/modules/remotes/operations/remote-operation.runner.d.ts +3 -1
- package/dist/server/modules/remotes/operations/remote-operation.runner.js +59 -21
- package/dist/server/modules/remotes/operations/remote-operation.runner.js.map +1 -1
- package/dist/server/modules/remotes/operations/remote-operation.types.d.ts +4 -1
- package/dist/server/modules/remotes/operations/remote-operation.types.js +4 -2
- package/dist/server/modules/remotes/operations/remote-operation.types.js.map +1 -1
- package/dist/server/modules/remotes/operations/remote-operations.controller.d.ts +5 -0
- package/dist/server/modules/remotes/operations/remote-operations.controller.js +56 -0
- package/dist/server/modules/remotes/operations/remote-operations.controller.js.map +1 -1
- package/dist/server/modules/remotes/operations/remote-operations.service.d.ts +16 -1
- package/dist/server/modules/remotes/operations/remote-operations.service.js +155 -5
- package/dist/server/modules/remotes/operations/remote-operations.service.js.map +1 -1
- package/dist/server/modules/remotes/operations/update-logins.operation.d.ts +1 -3
- package/dist/server/modules/remotes/operations/update-logins.operation.js +3 -18
- package/dist/server/modules/remotes/operations/update-logins.operation.js.map +1 -1
- package/dist/server/modules/remotes/ports/remote-health.port.d.ts +2 -0
- package/dist/server/modules/remotes/ports/remote-health.port.js.map +1 -1
- package/dist/server/modules/remotes/remotes.module.js +18 -0
- package/dist/server/modules/remotes/remotes.module.js.map +1 -1
- package/dist/server/modules/remotes/replica/__fixtures__/replica-seed.d.ts +2 -2
- package/dist/server/modules/remotes/replica/__fixtures__/replica-seed.js +2 -13
- package/dist/server/modules/remotes/replica/__fixtures__/replica-seed.js.map +1 -1
- package/dist/server/modules/remotes/services/remote-health.service.js +5 -0
- package/dist/server/modules/remotes/services/remote-health.service.js.map +1 -1
- package/dist/server/modules/remotes/sync/file-sync-failures.service.d.ts +18 -0
- package/dist/server/modules/remotes/sync/file-sync-failures.service.js +157 -0
- package/dist/server/modules/remotes/sync/file-sync-failures.service.js.map +1 -0
- package/dist/server/modules/remotes/sync/file-sync-pattern-preview.service.d.ts +14 -0
- package/dist/server/modules/remotes/sync/file-sync-pattern-preview.service.js +99 -0
- package/dist/server/modules/remotes/sync/file-sync-pattern-preview.service.js.map +1 -0
- package/dist/server/modules/remotes/sync/file-sync-suggestions.service.d.ts +15 -0
- package/dist/server/modules/remotes/sync/file-sync-suggestions.service.js +90 -0
- package/dist/server/modules/remotes/sync/file-sync-suggestions.service.js.map +1 -0
- package/dist/server/modules/remotes/sync/project-file-sync.controller.d.ts +29 -0
- package/dist/server/modules/remotes/sync/project-file-sync.controller.js +160 -0
- package/dist/server/modules/remotes/sync/project-file-sync.controller.js.map +1 -0
- package/dist/server/modules/remotes/sync/remote-file-sync.dto.d.ts +72 -0
- package/dist/server/modules/remotes/sync/remote-file-sync.dto.js +16 -0
- package/dist/server/modules/remotes/sync/remote-file-sync.dto.js.map +1 -0
- package/dist/server/modules/remotes/sync/remote-file-sync.service.d.ts +32 -1
- package/dist/server/modules/remotes/sync/remote-file-sync.service.js +499 -38
- package/dist/server/modules/remotes/sync/remote-file-sync.service.js.map +1 -1
- package/dist/server/modules/remotes/sync/remote-live-sync.service.d.ts +2 -0
- package/dist/server/modules/remotes/sync/remote-live-sync.service.js +26 -12
- package/dist/server/modules/remotes/sync/remote-live-sync.service.js.map +1 -1
- package/dist/server/modules/remotes/vm-user-identity.d.ts +29 -0
- package/dist/server/modules/remotes/vm-user-identity.js +45 -0
- package/dist/server/modules/remotes/vm-user-identity.js.map +1 -0
- package/dist/server/modules/runtime-context-capture/codex-plugin-profile-materializer.service.js +5 -1
- package/dist/server/modules/runtime-context-capture/codex-plugin-profile-materializer.service.js.map +1 -1
- package/dist/server/modules/session-reader/adapters/claude-session-reader.adapter.d.ts +5 -0
- package/dist/server/modules/session-reader/adapters/claude-session-reader.adapter.js +9 -0
- package/dist/server/modules/session-reader/adapters/claude-session-reader.adapter.js.map +1 -1
- package/dist/server/modules/session-reader/adapters/session-reader-adapter.interface.d.ts +1 -0
- package/dist/server/modules/session-reader/adapters/utils/coalesce-turns.js +1 -0
- package/dist/server/modules/session-reader/adapters/utils/coalesce-turns.js.map +1 -1
- package/dist/server/modules/session-reader/builders/semantic-step-extractor.js +1 -1
- package/dist/server/modules/session-reader/builders/semantic-step-extractor.js.map +1 -1
- package/dist/server/modules/session-reader/controllers/session-reader.controller.js +1 -1
- package/dist/server/modules/session-reader/controllers/session-reader.controller.js.map +1 -1
- package/dist/server/modules/session-reader/data/pricing.json +89 -12
- package/dist/server/modules/session-reader/dtos/unified-message.types.d.ts +1 -0
- package/dist/server/modules/session-reader/parsers/claude-jsonl.parser.d.ts +3 -0
- package/dist/server/modules/session-reader/parsers/claude-jsonl.parser.js +10 -1
- package/dist/server/modules/session-reader/parsers/claude-jsonl.parser.js.map +1 -1
- package/dist/server/modules/session-reader/parsers/claude-turn-evidence.d.ts +11 -0
- package/dist/server/modules/session-reader/parsers/claude-turn-evidence.js +50 -0
- package/dist/server/modules/session-reader/parsers/claude-turn-evidence.js.map +1 -0
- package/dist/server/modules/session-reader/parsers/codex-jsonl.parser.js +8 -2
- package/dist/server/modules/session-reader/parsers/codex-jsonl.parser.js.map +1 -1
- package/dist/server/modules/session-reader/services/bounded-anchor-proof.d.ts +7 -0
- package/dist/server/modules/session-reader/services/bounded-anchor-proof.js +31 -2
- package/dist/server/modules/session-reader/services/bounded-anchor-proof.js.map +1 -1
- package/dist/server/modules/session-reader/services/session-cache.service.d.ts +8 -2
- package/dist/server/modules/session-reader/services/session-cache.service.js +80 -21
- package/dist/server/modules/session-reader/services/session-cache.service.js.map +1 -1
- package/dist/server/modules/session-reader/services/session-reader.service.d.ts +4 -0
- package/dist/server/modules/session-reader/services/session-reader.service.js +40 -8
- package/dist/server/modules/session-reader/services/session-reader.service.js.map +1 -1
- package/dist/server/modules/session-reader/services/transcript-cursor.d.ts +16 -4
- package/dist/server/modules/session-reader/services/transcript-cursor.js +65 -6
- package/dist/server/modules/session-reader/services/transcript-cursor.js.map +1 -1
- package/dist/server/modules/session-reader/services/transcript-serialization.js +2 -1
- package/dist/server/modules/session-reader/services/transcript-serialization.js.map +1 -1
- package/dist/server/modules/session-reader/services/transcript-turn-state.d.ts +4 -0
- package/dist/server/modules/session-reader/services/transcript-turn-state.js +20 -0
- package/dist/server/modules/session-reader/services/transcript-turn-state.js.map +1 -0
- package/dist/server/modules/session-reader/services/transcript-watcher.service.d.ts +4 -1
- package/dist/server/modules/session-reader/services/transcript-watcher.service.js +43 -18
- package/dist/server/modules/session-reader/services/transcript-watcher.service.js.map +1 -1
- package/dist/server/modules/sessions/services/provider-launch-config/provider-launch-config.service.js +5 -0
- package/dist/server/modules/sessions/services/provider-launch-config/provider-launch-config.service.js.map +1 -1
- package/dist/server/modules/sessions/services/session-runtime/__test-utils__/pipeline-harness.d.ts +36 -17
- package/dist/server/modules/sessions/services/session-runtime/__test-utils__/pipeline-harness.js +26 -9
- package/dist/server/modules/sessions/services/session-runtime/__test-utils__/pipeline-harness.js.map +1 -1
- package/dist/server/modules/sessions/services/session-runtime/ensure-mcp-readiness.d.ts +19 -0
- package/dist/server/modules/sessions/services/session-runtime/ensure-mcp-readiness.js +26 -0
- package/dist/server/modules/sessions/services/session-runtime/ensure-mcp-readiness.js.map +1 -0
- package/dist/server/modules/sessions/services/session-runtime/session-launch-pipeline.service.js +10 -18
- package/dist/server/modules/sessions/services/session-runtime/session-launch-pipeline.service.js.map +1 -1
- package/dist/server/modules/sessions/services/session-runtime/session-restore-pipeline.service.d.ts +5 -1
- package/dist/server/modules/sessions/services/session-runtime/session-restore-pipeline.service.js +20 -2
- package/dist/server/modules/sessions/services/session-runtime/session-restore-pipeline.service.js.map +1 -1
- package/dist/server/modules/settings/local/delegates/skills-settings.delegate.d.ts +6 -0
- package/dist/server/modules/settings/local/delegates/skills-settings.delegate.js +26 -0
- package/dist/server/modules/settings/local/delegates/skills-settings.delegate.js.map +1 -1
- package/dist/server/modules/settings/services/settings.service.d.ts +3 -1
- package/dist/server/modules/settings/services/settings.service.js +6 -0
- package/dist/server/modules/settings/services/settings.service.js.map +1 -1
- package/dist/server/modules/skills/adapters/anthropic-skill-source.adapter.js +5 -5
- package/dist/server/modules/skills/adapters/anthropic-skill-source.adapter.js.map +1 -1
- package/dist/server/modules/skills/adapters/github-directory-skill-source.adapter.js +5 -5
- package/dist/server/modules/skills/adapters/github-directory-skill-source.adapter.js.map +1 -1
- package/dist/server/modules/skills/adapters/github-skill-source.base.js +4 -3
- package/dist/server/modules/skills/adapters/github-skill-source.base.js.map +1 -1
- package/dist/server/modules/skills/adapters/local-skill-source.adapter.js +5 -5
- package/dist/server/modules/skills/adapters/local-skill-source.adapter.js.map +1 -1
- package/dist/server/modules/skills/adapters/microsoft-skill-source.adapter.js +5 -5
- package/dist/server/modules/skills/adapters/microsoft-skill-source.adapter.js.map +1 -1
- package/dist/server/modules/skills/adapters/openai-skill-source.adapter.js +5 -5
- package/dist/server/modules/skills/adapters/openai-skill-source.adapter.js.map +1 -1
- package/dist/server/modules/skills/adapters/skill-source.adapter.d.ts +5 -0
- package/dist/server/modules/skills/adapters/skill-sync-temp-cleanup.d.ts +5 -0
- package/dist/server/modules/skills/adapters/skill-sync-temp-cleanup.js +75 -0
- package/dist/server/modules/skills/adapters/skill-sync-temp-cleanup.js.map +1 -0
- package/dist/server/modules/skills/adapters/trailofbits-skill-source.adapter.js +5 -5
- package/dist/server/modules/skills/adapters/trailofbits-skill-source.adapter.js.map +1 -1
- package/dist/server/modules/skills/adapters/vercel-skill-source.adapter.js +5 -5
- package/dist/server/modules/skills/adapters/vercel-skill-source.adapter.js.map +1 -1
- package/dist/server/modules/skills/controllers/skills.controller.js +2 -2
- package/dist/server/modules/skills/controllers/skills.controller.js.map +1 -1
- package/dist/server/modules/skills/services/skill-source-lifecycle.service.d.ts +3 -3
- package/dist/server/modules/skills/services/skill-source-lifecycle.service.js +9 -4
- package/dist/server/modules/skills/services/skill-source-lifecycle.service.js.map +1 -1
- package/dist/server/modules/skills/services/skill-sync.service.d.ts +3 -3
- package/dist/server/modules/skills/services/skill-sync.service.js +32 -6
- package/dist/server/modules/skills/services/skill-sync.service.js.map +1 -1
- package/dist/server/modules/skills/services/skill-sync.types.d.ts +3 -0
- package/dist/server/modules/storage/db/schema.d.ts +2 -2
- package/dist/server/modules/storage/db/schema.js +2 -0
- package/dist/server/modules/storage/db/schema.js.map +1 -1
- package/dist/server/modules/storage/models/domain.models.d.ts +1 -1
- package/dist/server/modules/storage/models/domain.models.js +2 -0
- package/dist/server/modules/storage/models/domain.models.js.map +1 -1
- package/dist/server/modules/teams/storage/teams.store.d.ts +1 -0
- package/dist/server/modules/teams/storage/teams.store.js +19 -3
- package/dist/server/modules/teams/storage/teams.store.js.map +1 -1
- package/dist/server/modules/terminal/gateways/terminal.gateway.d.ts +3 -1
- package/dist/server/modules/terminal/gateways/terminal.gateway.js +9 -4
- package/dist/server/modules/terminal/gateways/terminal.gateway.js.map +1 -1
- package/dist/server/modules/terminal/services/session-turn-signals.d.ts +18 -0
- package/dist/server/modules/terminal/services/session-turn-signals.js +6 -0
- package/dist/server/modules/terminal/services/session-turn-signals.js.map +1 -0
- package/dist/server/modules/terminal/services/terminal-activity.service.d.ts +32 -5
- package/dist/server/modules/terminal/services/terminal-activity.service.js +322 -40
- package/dist/server/modules/terminal/services/terminal-activity.service.js.map +1 -1
- package/dist/server/modules/terminal/services/terminal-io/lifecycle.js +15 -3
- package/dist/server/modules/terminal/services/terminal-io/lifecycle.js.map +1 -1
- package/dist/server/modules/terminal/terminal.module.js +2 -0
- package/dist/server/modules/terminal/terminal.module.js.map +1 -1
- package/dist/server/modules/terminal/utils/ansi-sanitizer.d.ts +0 -1
- package/dist/server/modules/terminal/utils/ansi-sanitizer.js +0 -4
- package/dist/server/modules/terminal/utils/ansi-sanitizer.js.map +1 -1
- package/dist/server/templates/teams-dev.json +14 -14
- package/dist/server/test-setup-node.js +4 -3
- package/dist/server/test-setup-node.js.map +1 -1
- package/dist/server/test-setup.js +7 -0
- package/dist/server/test-setup.js.map +1 -1
- package/dist/server/tsconfig.tsbuildinfo +1 -1
- package/dist/server/ui/assets/{ExternalRichEditor--kNXs-Eb.js → ExternalRichEditor-CIZPhssf.js} +24 -24
- package/dist/server/ui/assets/ReviewDetailPage-winyLSQ7.js +6 -0
- package/dist/server/ui/assets/ReviewsPage-BYKBReMp.js +6 -0
- package/dist/server/ui/assets/index-CiDJX6Hn.js +1191 -0
- package/dist/server/ui/assets/index-f1WOAqXB.css +32 -0
- package/dist/server/ui/assets/useReviewSubscription-v3Cto0y4.js +69 -0
- package/dist/server/ui/index.html +2 -2
- package/dist/templates/teams-dev.json +14 -14
- package/package.json +15 -1
- package/dist/server/modules/reviews/utils/notification-formatter.d.ts +0 -12
- package/dist/server/modules/reviews/utils/notification-formatter.js +0 -60
- package/dist/server/modules/reviews/utils/notification-formatter.js.map +0 -1
- package/dist/server/ui/assets/ReviewDetailPage-DMgP5fKn.js +0 -6
- package/dist/server/ui/assets/ReviewsPage-CkyFUJr6.js +0 -6
- package/dist/server/ui/assets/index-CVUaAlP4.css +0 -32
- package/dist/server/ui/assets/index-CqRufKpA.js +0 -994
- package/dist/server/ui/assets/useReviewSubscription-CU70CzwG.js +0 -69
package/README.md
CHANGED
|
@@ -49,9 +49,7 @@ DevChain opens in your browser:
|
|
|
49
49
|
|
|
50
50
|
## Remote VMs
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
<a href="https://devchain.cc/features/remote-vms.mp4"><img src=".github/assets/remote-vms-poster.jpg" alt="Remote VMs: watch the 42-second demo" width="100%"></a>
|
|
54
|
-
</p>
|
|
52
|
+
https://github.com/user-attachments/assets/5ec85c19-f407-43bc-bb44-4da7f899702f
|
|
55
53
|
|
|
56
54
|
Move a project to your own VM and keep working from the same app. The agents keep running when your laptop sleeps, and the mobile app can tell you when the work is done.
|
|
57
55
|
|
|
@@ -61,7 +59,6 @@ Move a project to your own VM and keep working from the same app. The agents kee
|
|
|
61
59
|
|
|
62
60
|
Before you start:
|
|
63
61
|
|
|
64
|
-
- Use a LAN or VPN between your PC and the VM. Your PC reaches every VM with an API key, over TLS pinned to the VM's own certificate ([details](https://devchain.cc/releases/0.24.0/#secure-connection-to-every-vm)).
|
|
65
62
|
- Install [Syncthing v2](https://syncthing.net) on your PC. DevChain installs it on the VM.
|
|
66
63
|
- For your own VM, use a dedicated headless VM: Ubuntu 22.04+ or Debian 12+, amd64, and at least 4 GiB of RAM.
|
|
67
64
|
- To follow a VM's projects in the mobile app, sign the VM in to DevChain Cloud from the **Cloud** page.
|
package/dist/build-info.json
CHANGED
package/dist/cli.js
CHANGED
|
@@ -16,6 +16,8 @@ const { spawn, execSync, execFileSync } = require('child_process');
|
|
|
16
16
|
const { pathToFileURL } = require('url');
|
|
17
17
|
const { InteractiveCLI } = require('./lib/interactive-cli');
|
|
18
18
|
const { runHostInstallCommand } = require('./lib/host-install');
|
|
19
|
+
const { runGitOwnerCommand } = require('./lib/git-owner');
|
|
20
|
+
const { getLocalApiBaseUrl } = require('./lib/local-api');
|
|
19
21
|
const { runHostApiKeyReset } = require('./lib/host-api-key');
|
|
20
22
|
const { QUEUE_NAME, runExclusive } = require('./lib/exclusive-run');
|
|
21
23
|
const readline = require('readline');
|
|
@@ -347,6 +349,30 @@ async function ensureProvidersInDb(baseUrl, detected, log) {
|
|
|
347
349
|
|
|
348
350
|
async function validateMcpForProviders(baseUrl, cli, opts, log, projectPath) {
|
|
349
351
|
try {
|
|
352
|
+
// The ensure endpoint matches projectPath exactly against a stored project
|
|
353
|
+
// root, and a folder that is not a registered project can never be
|
|
354
|
+
// registered there — MCP is registered when a session launches or restores.
|
|
355
|
+
let effectiveProjectPath = projectPath;
|
|
356
|
+
if (projectPath) {
|
|
357
|
+
try {
|
|
358
|
+
const byPathRes = await fetchWithTimeout(
|
|
359
|
+
`${baseUrl}/api/projects/by-path?path=${encodeURIComponent(projectPath)}`,
|
|
360
|
+
{},
|
|
361
|
+
2500,
|
|
362
|
+
);
|
|
363
|
+
if (byPathRes.ok) {
|
|
364
|
+
const project = await byPathRes.json();
|
|
365
|
+
// The stored rootPath avoids trailing-slash or normalization mismatches.
|
|
366
|
+
effectiveProjectPath = project?.rootPath ?? projectPath;
|
|
367
|
+
} else if (byPathRes.status === 404) {
|
|
368
|
+
log('info', 'Startup folder is not a registered project; skipping MCP validation (MCP is registered when a session launches)', { startupPath: projectPath });
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
} catch {
|
|
372
|
+
// Lookup failed (network/timeout): proceed with the raw path as before.
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
350
376
|
// Fetch all providers
|
|
351
377
|
const res = await fetch(`${baseUrl}/api/providers`);
|
|
352
378
|
if (!res.ok) {
|
|
@@ -374,7 +400,7 @@ async function validateMcpForProviders(baseUrl, cli, opts, log, projectPath) {
|
|
|
374
400
|
const results = [];
|
|
375
401
|
for (const provider of providers) {
|
|
376
402
|
try {
|
|
377
|
-
const body =
|
|
403
|
+
const body = effectiveProjectPath ? JSON.stringify({ projectPath: effectiveProjectPath }) : JSON.stringify({});
|
|
378
404
|
const ensureRes = await fetch(`${baseUrl}/api/providers/${provider.id}/mcp/ensure`, {
|
|
379
405
|
method: 'POST',
|
|
380
406
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -1388,6 +1414,34 @@ async function main(argv) {
|
|
|
1388
1414
|
});
|
|
1389
1415
|
});
|
|
1390
1416
|
|
|
1417
|
+
const git = program.command('git').description('Move Git control between this PC and the VM');
|
|
1418
|
+
for (const name of ['status', 'take', 'return']) {
|
|
1419
|
+
const command = git
|
|
1420
|
+
.command(name)
|
|
1421
|
+
.description(
|
|
1422
|
+
{
|
|
1423
|
+
status: 'Show Git control and any unfinished switch',
|
|
1424
|
+
take: 'Move Git control to this PC',
|
|
1425
|
+
return: 'Move Git control back to the VM',
|
|
1426
|
+
}[name],
|
|
1427
|
+
)
|
|
1428
|
+
.option('--project <path>', 'Project folder (defaults to the current folder)');
|
|
1429
|
+
if (name === 'take') {
|
|
1430
|
+
command.option('--force', "Stop this project's agent sessions on the VM before the switch");
|
|
1431
|
+
}
|
|
1432
|
+
command.action(async (options) => {
|
|
1433
|
+
process.exitCode = await runGitOwnerCommand(name, options, {
|
|
1434
|
+
getMachineRole,
|
|
1435
|
+
getLocalApiBaseUrl: () =>
|
|
1436
|
+
getLocalApiBaseUrl({
|
|
1437
|
+
readPidFile,
|
|
1438
|
+
isProcessRunning,
|
|
1439
|
+
resolveSharedModuleSpecifier,
|
|
1440
|
+
}),
|
|
1441
|
+
});
|
|
1442
|
+
});
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1391
1445
|
const host = program.command('host').description('Manage DevChain hosts');
|
|
1392
1446
|
|
|
1393
1447
|
host
|
|
@@ -1400,7 +1454,10 @@ async function main(argv) {
|
|
|
1400
1454
|
.option('--passphrase-stdin', 'Read the SSH key passphrase from one line of stdin')
|
|
1401
1455
|
.option('--sudo-password-stdin', 'Read the optional sudo password from one line of stdin')
|
|
1402
1456
|
.option('--projects <project-ids...>', 'Project ids to include in the disk estimate')
|
|
1403
|
-
.option(
|
|
1457
|
+
.option(
|
|
1458
|
+
'--no-docker',
|
|
1459
|
+
'Do not install Docker Engine and Compose on the VM (installed by default)',
|
|
1460
|
+
)
|
|
1404
1461
|
.option(
|
|
1405
1462
|
'--provider-auth <provider=choice>',
|
|
1406
1463
|
'Provider login choice: skip, generate, or reuse:<entry-id> (repeatable)',
|
|
@@ -1408,15 +1465,12 @@ async function main(argv) {
|
|
|
1408
1465
|
)
|
|
1409
1466
|
.action(async (options) => {
|
|
1410
1467
|
const exitCode = await runHostInstallCommand(options, {
|
|
1411
|
-
getLocalApiBaseUrl:
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
port: pidData.port,
|
|
1418
|
-
});
|
|
1419
|
-
},
|
|
1468
|
+
getLocalApiBaseUrl: () =>
|
|
1469
|
+
getLocalApiBaseUrl({
|
|
1470
|
+
readPidFile,
|
|
1471
|
+
isProcessRunning,
|
|
1472
|
+
resolveSharedModuleSpecifier,
|
|
1473
|
+
}),
|
|
1420
1474
|
});
|
|
1421
1475
|
process.exitCode = exitCode;
|
|
1422
1476
|
});
|
|
@@ -1509,6 +1563,7 @@ module.exports = {
|
|
|
1509
1563
|
main,
|
|
1510
1564
|
__test__: {
|
|
1511
1565
|
waitForHealth,
|
|
1566
|
+
validateMcpForProviders,
|
|
1512
1567
|
runHostPreflightChecks,
|
|
1513
1568
|
getDevUiConfig,
|
|
1514
1569
|
getPreferredDevApiPort,
|
|
Binary file
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"bootstrap": {
|
|
6
6
|
"package": "devchain-host-bootstrap",
|
|
7
7
|
"version": "0.1.0",
|
|
8
|
-
"sha256": "
|
|
8
|
+
"sha256": "647a36e15832c854515835132b80892fffebe4fb0957938541135b0481a39040"
|
|
9
9
|
},
|
|
10
10
|
"aptPackages": [
|
|
11
11
|
"qemu-guest-agent",
|
|
@@ -17,6 +17,10 @@
|
|
|
17
17
|
"build-essential",
|
|
18
18
|
"python3",
|
|
19
19
|
"jq",
|
|
20
|
+
"openssl",
|
|
21
|
+
"procps"
|
|
22
|
+
],
|
|
23
|
+
"toolPackages": [
|
|
20
24
|
"ripgrep",
|
|
21
25
|
"python-is-python3",
|
|
22
26
|
"python3-pip",
|
|
@@ -26,6 +30,31 @@
|
|
|
26
30
|
"bsdextrautils",
|
|
27
31
|
"rsync",
|
|
28
32
|
"unzip",
|
|
29
|
-
"
|
|
33
|
+
"screen",
|
|
34
|
+
"psmisc",
|
|
35
|
+
"time",
|
|
36
|
+
"lsof",
|
|
37
|
+
"strace",
|
|
38
|
+
"htop",
|
|
39
|
+
"less",
|
|
40
|
+
"nano",
|
|
41
|
+
"vim-tiny",
|
|
42
|
+
"tree",
|
|
43
|
+
"zip",
|
|
44
|
+
"net-tools",
|
|
45
|
+
"iputils-ping",
|
|
46
|
+
"inetutils-telnet",
|
|
47
|
+
"netcat-openbsd",
|
|
48
|
+
"bind9-dnsutils",
|
|
49
|
+
"traceroute",
|
|
50
|
+
"mtr-tiny",
|
|
51
|
+
"tcpdump",
|
|
52
|
+
"socat",
|
|
53
|
+
"fd-find",
|
|
54
|
+
"universal-ctags",
|
|
55
|
+
"gawk",
|
|
56
|
+
"shellcheck",
|
|
57
|
+
"cloc",
|
|
58
|
+
"git-lfs"
|
|
30
59
|
]
|
|
31
60
|
}
|
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
const fs = require("node:fs");
|
|
2
|
-
const { spawn } = require("node:child_process");
|
|
2
|
+
const { spawn, spawnSync } = require("node:child_process");
|
|
3
3
|
const { randomBytes } = require("node:crypto");
|
|
4
4
|
const { homedir, constants } = require("node:os");
|
|
5
|
-
const { join, resolve } = require("node:path");
|
|
5
|
+
const { delimiter, join, resolve } = require("node:path");
|
|
6
6
|
|
|
7
7
|
const QUEUE_NAME = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
8
8
|
const SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"];
|
|
9
|
+
// systemd-run execs the command in place: pid, process group, stdio and exit
|
|
10
|
+
// code stay the same. systemd 258 and later expand $VAR in the arguments
|
|
11
|
+
// unless told not to.
|
|
12
|
+
const SCOPE_ARGS = [
|
|
13
|
+
"--user",
|
|
14
|
+
"--scope",
|
|
15
|
+
"--quiet",
|
|
16
|
+
"--collect",
|
|
17
|
+
"--expand-environment=no",
|
|
18
|
+
"--",
|
|
19
|
+
];
|
|
20
|
+
let scopeAvailable;
|
|
9
21
|
|
|
10
22
|
function isPid(value) {
|
|
11
23
|
return Number.isInteger(value) && value > 0;
|
|
@@ -150,13 +162,49 @@ function formatWait(ms) {
|
|
|
150
162
|
return `${Math.floor(seconds / 60)}m ${seconds % 60}s`;
|
|
151
163
|
}
|
|
152
164
|
|
|
165
|
+
function findExecutable(command, env) {
|
|
166
|
+
const candidates = command.includes("/")
|
|
167
|
+
? [resolve(command)]
|
|
168
|
+
: (env.PATH || "")
|
|
169
|
+
.split(delimiter)
|
|
170
|
+
.filter(Boolean)
|
|
171
|
+
.map((dir) => join(dir, command));
|
|
172
|
+
return candidates.find((file) => {
|
|
173
|
+
try {
|
|
174
|
+
fs.accessSync(file, fs.constants.X_OK);
|
|
175
|
+
return fs.statSync(file).isFile();
|
|
176
|
+
} catch {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// In a user scope of its own, a command that systemd-oomd kills does not take
|
|
183
|
+
// the caller's scope down with it, e.g. an agent's tmux pane.
|
|
184
|
+
function scopedSpawnArgs(command, args, env) {
|
|
185
|
+
if (process.platform !== "linux") return [command, args];
|
|
186
|
+
const executable = findExecutable(command, env);
|
|
187
|
+
// An unknown command spawns directly, so its start error still names it.
|
|
188
|
+
if (!executable) return [command, args];
|
|
189
|
+
scopeAvailable ??=
|
|
190
|
+
spawnSync("systemd-run", [...SCOPE_ARGS, "true"], {
|
|
191
|
+
env,
|
|
192
|
+
stdio: "ignore",
|
|
193
|
+
timeout: 5000,
|
|
194
|
+
}).status === 0;
|
|
195
|
+
return scopeAvailable
|
|
196
|
+
? ["systemd-run", [...SCOPE_ARGS, executable, ...args]]
|
|
197
|
+
: [command, args];
|
|
198
|
+
}
|
|
199
|
+
|
|
153
200
|
async function spawnAndForward(
|
|
154
201
|
{ command, args, env, pollMs, name },
|
|
155
202
|
state,
|
|
156
203
|
onSpawn,
|
|
157
204
|
) {
|
|
158
205
|
if (state.signal) return signalCode(state.signal);
|
|
159
|
-
const
|
|
206
|
+
const [file, argv] = scopedSpawnArgs(command, args, env);
|
|
207
|
+
const child = spawn(file, argv, { env, stdio: "inherit", detached: true });
|
|
160
208
|
state.pgid = child.pid || null;
|
|
161
209
|
const result = new Promise((done) => {
|
|
162
210
|
child.once("error", (error) => {
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
const { dirname, resolve } = require("node:path");
|
|
2
|
+
const {
|
|
3
|
+
LocalApiHttpError,
|
|
4
|
+
POLL_INTERVAL_MS,
|
|
5
|
+
getOperation,
|
|
6
|
+
printOperationSteps,
|
|
7
|
+
requestJson,
|
|
8
|
+
writeLine,
|
|
9
|
+
} = require("./local-api");
|
|
10
|
+
|
|
11
|
+
// The server checks the VM before it starts a switch; each check can take 15 seconds.
|
|
12
|
+
const START_TIMEOUT_MS = 120_000;
|
|
13
|
+
|
|
14
|
+
class GitCommandRefusedError extends Error {}
|
|
15
|
+
|
|
16
|
+
async function findProject(fetchImpl, baseUrl, path) {
|
|
17
|
+
let candidate = resolve(path);
|
|
18
|
+
for (;;) {
|
|
19
|
+
try {
|
|
20
|
+
const project = await requestJson(
|
|
21
|
+
fetchImpl,
|
|
22
|
+
baseUrl,
|
|
23
|
+
`/api/projects/by-path?path=${encodeURIComponent(candidate)}`,
|
|
24
|
+
);
|
|
25
|
+
if (!project || typeof project.id !== "string") {
|
|
26
|
+
throw new Error("DevChain returned an invalid project.");
|
|
27
|
+
}
|
|
28
|
+
return project;
|
|
29
|
+
} catch (error) {
|
|
30
|
+
if (!(error instanceof LocalApiHttpError) || error.status !== 404)
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
const parent = dirname(candidate);
|
|
34
|
+
if (parent === candidate) {
|
|
35
|
+
throw new GitCommandRefusedError(
|
|
36
|
+
`No registered project contains ${resolve(path)}.`,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
candidate = parent;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function recoveryCommand(owner, force, projectPath) {
|
|
44
|
+
const command =
|
|
45
|
+
owner === "home"
|
|
46
|
+
? `devchain git take${force ? " --force" : ""}`
|
|
47
|
+
: "devchain git return";
|
|
48
|
+
return projectPath
|
|
49
|
+
? `${command} --project '${projectPath.replace(/'/g, "'\\''")}'`
|
|
50
|
+
: command;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function ownerMessage(owner, remoteName, already = false) {
|
|
54
|
+
const side = owner === "home" ? "this PC" : `the VM '${remoteName}'`;
|
|
55
|
+
return `Git for this project is ${already ? "already " : ""}on ${side}.`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function printStatus(status, stdout, projectPath) {
|
|
59
|
+
writeLine(
|
|
60
|
+
stdout,
|
|
61
|
+
status.connected
|
|
62
|
+
? ownerMessage(status.owner, status.remoteName)
|
|
63
|
+
: "This project is not connected to a VM.",
|
|
64
|
+
);
|
|
65
|
+
if (!status.open) return;
|
|
66
|
+
const open = status.open;
|
|
67
|
+
writeLine(stdout, `Git switch ${open.operationId}: ${open.state}.`);
|
|
68
|
+
writeLine(
|
|
69
|
+
stdout,
|
|
70
|
+
`Target: ${open.owner === "home" ? "this PC" : `the VM '${status.remoteName}'`}.`,
|
|
71
|
+
);
|
|
72
|
+
if (open.step) writeLine(stdout, `Step: ${open.step}.`);
|
|
73
|
+
if (open.error)
|
|
74
|
+
writeLine(
|
|
75
|
+
stdout,
|
|
76
|
+
`Error: ${open.error.message}${open.error.code ? ` (${open.error.code})` : ""}`,
|
|
77
|
+
);
|
|
78
|
+
writeLine(
|
|
79
|
+
stdout,
|
|
80
|
+
`To finish the switch, run \`${recoveryCommand(open.owner, open.force, projectPath)}\`.`,
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function printDetails(operation, seen, stderr) {
|
|
85
|
+
const details = operation.details ?? {};
|
|
86
|
+
const emit = (line) => {
|
|
87
|
+
if (seen.has(line)) return;
|
|
88
|
+
seen.add(line);
|
|
89
|
+
writeLine(stderr, line);
|
|
90
|
+
};
|
|
91
|
+
const unknownAgents = details.unknownAgents ?? [];
|
|
92
|
+
if (unknownAgents.length > 0)
|
|
93
|
+
emit(
|
|
94
|
+
"These agents on the VM have an unknown state. They do not block the switch:",
|
|
95
|
+
);
|
|
96
|
+
for (const agent of unknownAgents) {
|
|
97
|
+
emit(` - ${agent.agentName} (state unknown)`);
|
|
98
|
+
}
|
|
99
|
+
for (const warning of [details.guardWarning, details.vmGuardWarning]) {
|
|
100
|
+
if (warning) emit(`WARNING: ${warning}`);
|
|
101
|
+
}
|
|
102
|
+
for (const [field, side] of [
|
|
103
|
+
["pcGuardRemove", "PC"],
|
|
104
|
+
["vmGuardRemove", "VM"],
|
|
105
|
+
]) {
|
|
106
|
+
const result = details[field];
|
|
107
|
+
if (!result) continue;
|
|
108
|
+
if (result.warning) emit(`WARNING: ${result.warning}`);
|
|
109
|
+
if (result.indexRefreshed !== true)
|
|
110
|
+
emit(`WARNING: The ${side} Git index was not rebuilt.`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function printBusyAgents(error, remoteName, context, projectPath) {
|
|
115
|
+
const agents = error.details?.agents ?? [];
|
|
116
|
+
writeLine(
|
|
117
|
+
context.stderr,
|
|
118
|
+
`Git stays on the VM '${remoteName}': ${agents.length} ${agents.length === 1 ? "agent is" : "agents are"} working in this project.`,
|
|
119
|
+
);
|
|
120
|
+
for (const agent of agents) {
|
|
121
|
+
const elapsed = context.wallNow() - Date.parse(agent.since);
|
|
122
|
+
const minutes = Number.isFinite(elapsed)
|
|
123
|
+
? Math.max(0, Math.floor(elapsed / 60_000))
|
|
124
|
+
: null;
|
|
125
|
+
const duration =
|
|
126
|
+
minutes === null
|
|
127
|
+
? "time unknown"
|
|
128
|
+
: minutes < 1
|
|
129
|
+
? "less than 1 min"
|
|
130
|
+
: `${minutes} min`;
|
|
131
|
+
const state =
|
|
132
|
+
agent.state === "busy" ? `busy for ${duration}` : `starting, ${duration}`;
|
|
133
|
+
writeLine(context.stderr, ` - ${agent.agentName} (${state})`);
|
|
134
|
+
}
|
|
135
|
+
writeLine(
|
|
136
|
+
context.stderr,
|
|
137
|
+
`Wait until they finish, then run \`${recoveryCommand("home", false, projectPath)}\` again.`,
|
|
138
|
+
);
|
|
139
|
+
writeLine(
|
|
140
|
+
context.stderr,
|
|
141
|
+
`To stop this project's agent sessions on the VM now, run \`${recoveryCommand("home", true, projectPath)}\`.`,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
async function runGitOwnerCommand(command, options = {}, dependencies = {}) {
|
|
146
|
+
const stdout = dependencies.stdout ?? process.stdout;
|
|
147
|
+
const stderr = dependencies.stderr ?? process.stderr;
|
|
148
|
+
const fetchImpl = dependencies.fetch ?? globalThis.fetch;
|
|
149
|
+
const context = {
|
|
150
|
+
stdout: stderr,
|
|
151
|
+
stderr,
|
|
152
|
+
secrets: [],
|
|
153
|
+
now: dependencies.now ?? (() => performance.now()),
|
|
154
|
+
wallNow: dependencies.wallNow ?? Date.now,
|
|
155
|
+
sleep:
|
|
156
|
+
dependencies.sleep ??
|
|
157
|
+
((ms) => new Promise((done) => setTimeout(done, ms))),
|
|
158
|
+
};
|
|
159
|
+
let status;
|
|
160
|
+
try {
|
|
161
|
+
if (dependencies.getMachineRole?.() === "remote VM") {
|
|
162
|
+
throw new GitCommandRefusedError(
|
|
163
|
+
"Run this command on the PC that connected this project.",
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
if (
|
|
167
|
+
!["status", "take", "return"].includes(command) ||
|
|
168
|
+
(command !== "take" && options.force)
|
|
169
|
+
) {
|
|
170
|
+
throw new GitCommandRefusedError(
|
|
171
|
+
"Use devchain git status, take [--force], or return.",
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
const baseUrl = await dependencies.getLocalApiBaseUrl?.();
|
|
175
|
+
if (!baseUrl) {
|
|
176
|
+
writeLine(stderr, "Start DevChain first (devchain start).");
|
|
177
|
+
return 1;
|
|
178
|
+
}
|
|
179
|
+
const project = await findProject(
|
|
180
|
+
fetchImpl,
|
|
181
|
+
baseUrl,
|
|
182
|
+
options.project ?? dependencies.cwd ?? process.cwd(),
|
|
183
|
+
);
|
|
184
|
+
status = await requestJson(
|
|
185
|
+
fetchImpl,
|
|
186
|
+
baseUrl,
|
|
187
|
+
`/api/remotes/git-owner?projectId=${encodeURIComponent(project.id)}`,
|
|
188
|
+
);
|
|
189
|
+
if (command === "status") {
|
|
190
|
+
printStatus(status, stdout, options.project);
|
|
191
|
+
return 0;
|
|
192
|
+
}
|
|
193
|
+
if (!status.connected || !status.remoteId) {
|
|
194
|
+
throw new GitCommandRefusedError(
|
|
195
|
+
"This project is not connected to a VM.",
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
const owner = command === "take" ? "home" : "vm";
|
|
199
|
+
let operation = await requestJson(
|
|
200
|
+
fetchImpl,
|
|
201
|
+
baseUrl,
|
|
202
|
+
`/api/remotes/${encodeURIComponent(status.remoteId)}/git-owner`,
|
|
203
|
+
{
|
|
204
|
+
method: "POST",
|
|
205
|
+
body: { projectId: project.id, owner, force: options.force === true },
|
|
206
|
+
timeoutMs: START_TIMEOUT_MS,
|
|
207
|
+
},
|
|
208
|
+
);
|
|
209
|
+
if (operation?.changed === false) {
|
|
210
|
+
if (operation.cancelledOperationId) {
|
|
211
|
+
writeLine(
|
|
212
|
+
stdout,
|
|
213
|
+
`Cancelled the failed switch ${operation.cancelledOperationId}.`,
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
writeLine(stdout, ownerMessage(operation.owner, status.remoteName, true));
|
|
217
|
+
return 0;
|
|
218
|
+
}
|
|
219
|
+
const steps = new Map();
|
|
220
|
+
const details = new Set();
|
|
221
|
+
let announced = false;
|
|
222
|
+
for (;;) {
|
|
223
|
+
if (
|
|
224
|
+
!operation ||
|
|
225
|
+
typeof operation.id !== "string" ||
|
|
226
|
+
!Array.isArray(operation.steps) ||
|
|
227
|
+
!["running", "failed", "done", "cancelled"].includes(operation.state)
|
|
228
|
+
) {
|
|
229
|
+
throw new Error("DevChain returned an invalid Git switch operation.");
|
|
230
|
+
}
|
|
231
|
+
const target = operation.details?.owner ?? owner;
|
|
232
|
+
const repeat = recoveryCommand(
|
|
233
|
+
target,
|
|
234
|
+
operation.details?.force === true,
|
|
235
|
+
options.project,
|
|
236
|
+
);
|
|
237
|
+
context.recoveryHint = `Run \`${repeat}\` again to follow or retry operation ${operation.id}.`;
|
|
238
|
+
if (!announced) {
|
|
239
|
+
writeLine(stderr, `Git switch started (operation ${operation.id}).`);
|
|
240
|
+
announced = true;
|
|
241
|
+
}
|
|
242
|
+
printOperationSteps(operation, steps, context);
|
|
243
|
+
printDetails(operation, details, stderr);
|
|
244
|
+
if (operation.state === "done") {
|
|
245
|
+
writeLine(stdout, ownerMessage(target, status.remoteName));
|
|
246
|
+
return 0;
|
|
247
|
+
}
|
|
248
|
+
if (operation.state === "failed" || operation.state === "cancelled") {
|
|
249
|
+
const failed = operation.steps.find((step) => step.state === "failed");
|
|
250
|
+
writeLine(
|
|
251
|
+
stderr,
|
|
252
|
+
failed?.error?.message ?? `Git switch ${operation.state}.`,
|
|
253
|
+
);
|
|
254
|
+
writeLine(stderr, context.recoveryHint);
|
|
255
|
+
return 1;
|
|
256
|
+
}
|
|
257
|
+
await context.sleep(POLL_INTERVAL_MS);
|
|
258
|
+
operation = await getOperation(fetchImpl, baseUrl, operation.id, context);
|
|
259
|
+
}
|
|
260
|
+
} catch (error) {
|
|
261
|
+
const code = error.details?.code ?? error.code;
|
|
262
|
+
if (code === "GIT_TAKE_AGENTS_BUSY") {
|
|
263
|
+
printBusyAgents(error, status?.remoteName, context, options.project);
|
|
264
|
+
return 2;
|
|
265
|
+
}
|
|
266
|
+
writeLine(stderr, error.message ?? "Git command failed.");
|
|
267
|
+
if (
|
|
268
|
+
code === "REMOTE_OPERATION_CANCEL_FAILED" ||
|
|
269
|
+
(error instanceof LocalApiHttpError && error.status >= 500)
|
|
270
|
+
) {
|
|
271
|
+
writeLine(stderr, "Run the same command again.");
|
|
272
|
+
return 1;
|
|
273
|
+
}
|
|
274
|
+
if (
|
|
275
|
+
error instanceof GitCommandRefusedError ||
|
|
276
|
+
(error instanceof LocalApiHttpError &&
|
|
277
|
+
[400, 403, 404, 409, 422].includes(error.status))
|
|
278
|
+
)
|
|
279
|
+
return 2;
|
|
280
|
+
return 1;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
module.exports = { runGitOwnerCommand };
|