runwork 0.15.0 → 0.15.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/dist/index.js +19272 -116
- package/package.json +4 -4
- package/dist/__tests__/curl-parser.test.d.ts +0 -1
- package/dist/__tests__/curl-parser.test.js +0 -250
- package/dist/__tests__/install-scripts.test.d.ts +0 -1
- package/dist/__tests__/install-scripts.test.js +0 -280
- package/dist/__tests__/types-manager.test.d.ts +0 -1
- package/dist/__tests__/types-manager.test.js +0 -89
- package/dist/agents/__tests__/chatgpt-registry.test.d.ts +0 -1
- package/dist/agents/__tests__/chatgpt-registry.test.js +0 -61
- package/dist/agents/__tests__/claude-code-managed-block.test.d.ts +0 -1
- package/dist/agents/__tests__/claude-code-managed-block.test.js +0 -97
- package/dist/agents/__tests__/claude-code-plugin.test.d.ts +0 -1
- package/dist/agents/__tests__/claude-code-plugin.test.js +0 -47
- package/dist/agents/__tests__/claude-code-stats.test.d.ts +0 -1
- package/dist/agents/__tests__/claude-code-stats.test.js +0 -390
- package/dist/agents/__tests__/claude-desktop-memory.test.d.ts +0 -1
- package/dist/agents/__tests__/claude-desktop-memory.test.js +0 -154
- package/dist/agents/__tests__/claude-desktop-plugin-tree.test.d.ts +0 -1
- package/dist/agents/__tests__/claude-desktop-plugin-tree.test.js +0 -161
- package/dist/agents/__tests__/claude-desktop-plugin.test.d.ts +0 -1
- package/dist/agents/__tests__/claude-desktop-plugin.test.js +0 -117
- package/dist/agents/__tests__/claude-desktop-rpm.test.d.ts +0 -1
- package/dist/agents/__tests__/claude-desktop-rpm.test.js +0 -126
- package/dist/agents/__tests__/claude-desktop-stats.test.d.ts +0 -1
- package/dist/agents/__tests__/claude-desktop-stats.test.js +0 -280
- package/dist/agents/__tests__/codex-instructions.test.d.ts +0 -1
- package/dist/agents/__tests__/codex-instructions.test.js +0 -57
- package/dist/agents/__tests__/codex-minimum-permissions.test.d.ts +0 -1
- package/dist/agents/__tests__/codex-minimum-permissions.test.js +0 -82
- package/dist/agents/__tests__/codex-stats.test.d.ts +0 -1
- package/dist/agents/__tests__/codex-stats.test.js +0 -370
- package/dist/agents/__tests__/cursor-merge.test.d.ts +0 -1
- package/dist/agents/__tests__/cursor-merge.test.js +0 -66
- package/dist/agents/__tests__/cursor-stats.test.d.ts +0 -1
- package/dist/agents/__tests__/cursor-stats.test.js +0 -183
- package/dist/agents/__tests__/defaults-merge.test.d.ts +0 -1
- package/dist/agents/__tests__/defaults-merge.test.js +0 -268
- package/dist/agents/__tests__/detection.test.d.ts +0 -1
- package/dist/agents/__tests__/detection.test.js +0 -89
- package/dist/agents/__tests__/graceful-degradation.test.d.ts +0 -1
- package/dist/agents/__tests__/graceful-degradation.test.js +0 -129
- package/dist/agents/__tests__/instruction-hint.test.d.ts +0 -1
- package/dist/agents/__tests__/instruction-hint.test.js +0 -69
- package/dist/agents/__tests__/intro-skill.test.d.ts +0 -1
- package/dist/agents/__tests__/intro-skill.test.js +0 -193
- package/dist/agents/__tests__/schema-validation.test.d.ts +0 -1
- package/dist/agents/__tests__/schema-validation.test.js +0 -212
- package/dist/agents/__tests__/skill-slug.test.d.ts +0 -1
- package/dist/agents/__tests__/skill-slug.test.js +0 -77
- package/dist/agents/claude-code.d.ts +0 -53
- package/dist/agents/claude-code.js +0 -754
- package/dist/agents/claude-desktop-plugin-tree.d.ts +0 -59
- package/dist/agents/claude-desktop-plugin-tree.js +0 -143
- package/dist/agents/claude-desktop.d.ts +0 -47
- package/dist/agents/claude-desktop.js +0 -684
- package/dist/agents/cline.d.ts +0 -15
- package/dist/agents/cline.js +0 -130
- package/dist/agents/codex.d.ts +0 -44
- package/dist/agents/codex.js +0 -453
- package/dist/agents/conversation-skills.d.ts +0 -18
- package/dist/agents/conversation-skills.js +0 -229
- package/dist/agents/cursor.d.ts +0 -48
- package/dist/agents/cursor.js +0 -324
- package/dist/agents/default-config.d.ts +0 -30
- package/dist/agents/default-config.js +0 -67
- package/dist/agents/defaults-merge.d.ts +0 -72
- package/dist/agents/defaults-merge.js +0 -131
- package/dist/agents/detect.d.ts +0 -4
- package/dist/agents/detect.js +0 -67
- package/dist/agents/detection.d.ts +0 -18
- package/dist/agents/detection.js +0 -94
- package/dist/agents/gemini.d.ts +0 -15
- package/dist/agents/gemini.js +0 -122
- package/dist/agents/generic-adapter.d.ts +0 -25
- package/dist/agents/generic-adapter.js +0 -151
- package/dist/agents/intro-skill.d.ts +0 -45
- package/dist/agents/intro-skill.js +0 -447
- package/dist/agents/registry-data.d.ts +0 -192
- package/dist/agents/registry-data.js +0 -669
- package/dist/agents/registry.d.ts +0 -13
- package/dist/agents/registry.js +0 -36
- package/dist/agents/runtime-detection.d.ts +0 -82
- package/dist/agents/runtime-detection.js +0 -271
- package/dist/agents/session-start-hook.d.ts +0 -37
- package/dist/agents/session-start-hook.js +0 -159
- package/dist/agents/types.d.ts +0 -171
- package/dist/agents/types.js +0 -75
- package/dist/agents/utils/instruction-hint.d.ts +0 -21
- package/dist/agents/utils/instruction-hint.js +0 -108
- package/dist/agents/utils/json-config.d.ts +0 -19
- package/dist/agents/utils/json-config.js +0 -69
- package/dist/agents/utils/toml-config.d.ts +0 -8
- package/dist/agents/utils/toml-config.js +0 -27
- package/dist/agents/windsurf.d.ts +0 -14
- package/dist/agents/windsurf.js +0 -102
- package/dist/api/__tests__/client.test.d.ts +0 -1
- package/dist/api/__tests__/client.test.js +0 -272
- package/dist/api/client.d.ts +0 -326
- package/dist/api/client.js +0 -427
- package/dist/auth/__tests__/login-flow.test.d.ts +0 -1
- package/dist/auth/__tests__/login-flow.test.js +0 -101
- package/dist/auth/__tests__/store.test.d.ts +0 -1
- package/dist/auth/__tests__/store.test.js +0 -132
- package/dist/auth/login-flow.d.ts +0 -26
- package/dist/auth/login-flow.js +0 -137
- package/dist/auth/store.d.ts +0 -5
- package/dist/auth/store.js +0 -62
- package/dist/commands/__tests__/clone-args.test.d.ts +0 -1
- package/dist/commands/__tests__/clone-args.test.js +0 -51
- package/dist/commands/__tests__/clone-source-result.test.d.ts +0 -1
- package/dist/commands/__tests__/clone-source-result.test.js +0 -45
- package/dist/commands/__tests__/info-merge.test.d.ts +0 -1
- package/dist/commands/__tests__/info-merge.test.js +0 -55
- package/dist/commands/__tests__/mcp-entries.test.d.ts +0 -1
- package/dist/commands/__tests__/mcp-entries.test.js +0 -48
- package/dist/commands/__tests__/setup-persona.test.d.ts +0 -1
- package/dist/commands/__tests__/setup-persona.test.js +0 -31
- package/dist/commands/__tests__/setup.test.d.ts +0 -1
- package/dist/commands/__tests__/setup.test.js +0 -81
- package/dist/commands/__tests__/sync-redetect.test.d.ts +0 -1
- package/dist/commands/__tests__/sync-redetect.test.js +0 -96
- package/dist/commands/__tests__/sync-telemetry.test.d.ts +0 -1
- package/dist/commands/__tests__/sync-telemetry.test.js +0 -281
- package/dist/commands/__tests__/upgrade.test.d.ts +0 -1
- package/dist/commands/__tests__/upgrade.test.js +0 -157
- package/dist/commands/agents.d.ts +0 -2
- package/dist/commands/agents.js +0 -160
- package/dist/commands/api-keys.d.ts +0 -2
- package/dist/commands/api-keys.js +0 -95
- package/dist/commands/apps.d.ts +0 -2
- package/dist/commands/apps.js +0 -82
- package/dist/commands/build-plugin.d.ts +0 -2
- package/dist/commands/build-plugin.js +0 -135
- package/dist/commands/clone.d.ts +0 -60
- package/dist/commands/clone.js +0 -271
- package/dist/commands/components.d.ts +0 -2
- package/dist/commands/components.js +0 -43
- package/dist/commands/deploy.d.ts +0 -2
- package/dist/commands/deploy.js +0 -279
- package/dist/commands/dev.d.ts +0 -11
- package/dist/commands/dev.js +0 -1011
- package/dist/commands/doctor.d.ts +0 -2
- package/dist/commands/doctor.js +0 -230
- package/dist/commands/endpoints.d.ts +0 -2
- package/dist/commands/endpoints.js +0 -189
- package/dist/commands/entities.d.ts +0 -2
- package/dist/commands/entities.js +0 -198
- package/dist/commands/files.d.ts +0 -2
- package/dist/commands/files.js +0 -193
- package/dist/commands/inbox.d.ts +0 -11
- package/dist/commands/inbox.js +0 -60
- package/dist/commands/info.d.ts +0 -178
- package/dist/commands/info.js +0 -455
- package/dist/commands/init.d.ts +0 -21
- package/dist/commands/init.js +0 -185
- package/dist/commands/integrations.d.ts +0 -2
- package/dist/commands/integrations.js +0 -233
- package/dist/commands/login.d.ts +0 -2
- package/dist/commands/login.js +0 -44
- package/dist/commands/logout.d.ts +0 -2
- package/dist/commands/logout.js +0 -13
- package/dist/commands/logs.d.ts +0 -2
- package/dist/commands/logs.js +0 -232
- package/dist/commands/mcp-entries.d.ts +0 -13
- package/dist/commands/mcp-entries.js +0 -26
- package/dist/commands/mcp.d.ts +0 -2
- package/dist/commands/mcp.js +0 -245
- package/dist/commands/open.d.ts +0 -2
- package/dist/commands/open.js +0 -53
- package/dist/commands/resume.d.ts +0 -2
- package/dist/commands/resume.js +0 -289
- package/dist/commands/save-convo.d.ts +0 -8
- package/dist/commands/save-convo.js +0 -20
- package/dist/commands/schedules.d.ts +0 -2
- package/dist/commands/schedules.js +0 -221
- package/dist/commands/setup.d.ts +0 -27
- package/dist/commands/setup.js +0 -177
- package/dist/commands/share-convo.d.ts +0 -24
- package/dist/commands/share-convo.js +0 -167
- package/dist/commands/skills.d.ts +0 -2
- package/dist/commands/skills.js +0 -352
- package/dist/commands/sync-telemetry.d.ts +0 -33
- package/dist/commands/sync-telemetry.js +0 -186
- package/dist/commands/sync.d.ts +0 -37
- package/dist/commands/sync.js +0 -702
- package/dist/commands/uninstall.d.ts +0 -2
- package/dist/commands/uninstall.js +0 -145
- package/dist/commands/upgrade.d.ts +0 -14
- package/dist/commands/upgrade.js +0 -217
- package/dist/commands/validate.d.ts +0 -2
- package/dist/commands/validate.js +0 -89
- package/dist/commands/welcome.d.ts +0 -1
- package/dist/commands/welcome.js +0 -86
- package/dist/commands/workflows.d.ts +0 -2
- package/dist/commands/workflows.js +0 -187
- package/dist/deploy/__tests__/deploy-state.test.d.ts +0 -1
- package/dist/deploy/__tests__/deploy-state.test.js +0 -80
- package/dist/deploy/__tests__/deploy-status.test.d.ts +0 -1
- package/dist/deploy/__tests__/deploy-status.test.js +0 -41
- package/dist/deploy/__tests__/detach-args.test.d.ts +0 -1
- package/dist/deploy/__tests__/detach-args.test.js +0 -30
- package/dist/deploy/deploy-state.d.ts +0 -36
- package/dist/deploy/deploy-state.js +0 -63
- package/dist/deploy/deploy-status.d.ts +0 -21
- package/dist/deploy/deploy-status.js +0 -36
- package/dist/deploy/detach.d.ts +0 -32
- package/dist/deploy/detach.js +0 -71
- package/dist/dev/__tests__/attach.test.d.ts +0 -1
- package/dist/dev/__tests__/attach.test.js +0 -296
- package/dist/dev/__tests__/detach.test.d.ts +0 -1
- package/dist/dev/__tests__/detach.test.js +0 -404
- package/dist/dev/__tests__/preview-url-poller.test.d.ts +0 -1
- package/dist/dev/__tests__/preview-url-poller.test.js +0 -149
- package/dist/dev/__tests__/session.test.d.ts +0 -1
- package/dist/dev/__tests__/session.test.js +0 -446
- package/dist/dev/__tests__/startup-sync.test.d.ts +0 -1
- package/dist/dev/__tests__/startup-sync.test.js +0 -32
- package/dist/dev/__tests__/stop.test.d.ts +0 -1
- package/dist/dev/__tests__/stop.test.js +0 -172
- package/dist/dev/attach.d.ts +0 -120
- package/dist/dev/attach.js +0 -269
- package/dist/dev/detach.d.ts +0 -187
- package/dist/dev/detach.js +0 -292
- package/dist/dev/preview-url-poller.d.ts +0 -35
- package/dist/dev/preview-url-poller.js +0 -50
- package/dist/dev/session.d.ts +0 -175
- package/dist/dev/session.js +0 -258
- package/dist/dev/startup-sync.d.ts +0 -23
- package/dist/dev/startup-sync.js +0 -14
- package/dist/dev/stop.d.ts +0 -52
- package/dist/dev/stop.js +0 -101
- package/dist/devtools/registry-data.d.ts +0 -46
- package/dist/devtools/registry-data.js +0 -40
- package/dist/generated/bundled-types.d.ts +0 -1
- package/dist/generated/bundled-types.js +0 -46
- package/dist/generated/version.d.ts +0 -1
- package/dist/generated/version.js +0 -2
- package/dist/git/__tests__/auto-commit.test.d.ts +0 -1
- package/dist/git/__tests__/auto-commit.test.js +0 -431
- package/dist/git/__tests__/classify-sync-error.test.d.ts +0 -1
- package/dist/git/__tests__/classify-sync-error.test.js +0 -57
- package/dist/git/__tests__/credential-helper-e2e.test.d.ts +0 -21
- package/dist/git/__tests__/credential-helper-e2e.test.js +0 -195
- package/dist/git/__tests__/credentials.test.d.ts +0 -1
- package/dist/git/__tests__/credentials.test.js +0 -141
- package/dist/git/__tests__/deploy-guard.test.d.ts +0 -1
- package/dist/git/__tests__/deploy-guard.test.js +0 -61
- package/dist/git/__tests__/ensure-git-credential-helper.test.d.ts +0 -1
- package/dist/git/__tests__/ensure-git-credential-helper.test.js +0 -133
- package/dist/git/__tests__/ensure-runwork-remote.test.d.ts +0 -1
- package/dist/git/__tests__/ensure-runwork-remote.test.js +0 -109
- package/dist/git/__tests__/identity.test.d.ts +0 -1
- package/dist/git/__tests__/identity.test.js +0 -146
- package/dist/git/__tests__/manifest.test.d.ts +0 -1
- package/dist/git/__tests__/manifest.test.js +0 -446
- package/dist/git/__tests__/preflight-resolution.test.d.ts +0 -1
- package/dist/git/__tests__/preflight-resolution.test.js +0 -366
- package/dist/git/__tests__/preflight.test.d.ts +0 -1
- package/dist/git/__tests__/preflight.test.js +0 -36
- package/dist/git/__tests__/repo-config.test.d.ts +0 -1
- package/dist/git/__tests__/repo-config.test.js +0 -26
- package/dist/git/__tests__/sync.test.d.ts +0 -1
- package/dist/git/__tests__/sync.test.js +0 -405
- package/dist/git/auto-commit.d.ts +0 -35
- package/dist/git/auto-commit.js +0 -293
- package/dist/git/classify-sync-error.d.ts +0 -21
- package/dist/git/classify-sync-error.js +0 -111
- package/dist/git/credentials.d.ts +0 -75
- package/dist/git/credentials.js +0 -164
- package/dist/git/critical-files.d.ts +0 -20
- package/dist/git/critical-files.js +0 -68
- package/dist/git/deploy-guard.d.ts +0 -53
- package/dist/git/deploy-guard.js +0 -78
- package/dist/git/identity.d.ts +0 -44
- package/dist/git/identity.js +0 -133
- package/dist/git/preflight.d.ts +0 -57
- package/dist/git/preflight.js +0 -276
- package/dist/git/remote.d.ts +0 -37
- package/dist/git/remote.js +0 -75
- package/dist/git/repo-config.d.ts +0 -8
- package/dist/git/repo-config.js +0 -29
- package/dist/git/sync.d.ts +0 -15
- package/dist/git/sync.js +0 -159
- package/dist/health/__tests__/checks.test.d.ts +0 -1
- package/dist/health/__tests__/checks.test.js +0 -357
- package/dist/health/__tests__/cli-distribution-checks.test.d.ts +0 -1
- package/dist/health/__tests__/cli-distribution-checks.test.js +0 -196
- package/dist/health/__tests__/fix.test.d.ts +0 -1
- package/dist/health/__tests__/fix.test.js +0 -72
- package/dist/health/__tests__/runner-filter.test.d.ts +0 -1
- package/dist/health/__tests__/runner-filter.test.js +0 -61
- package/dist/health/checks.d.ts +0 -42
- package/dist/health/checks.js +0 -636
- package/dist/health/fix.d.ts +0 -22
- package/dist/health/fix.js +0 -62
- package/dist/health/runner.d.ts +0 -8
- package/dist/health/runner.js +0 -47
- package/dist/health/types.d.ts +0 -12
- package/dist/health/types.js +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/logs/__tests__/tailer-format.test.d.ts +0 -1
- package/dist/logs/__tests__/tailer-format.test.js +0 -43
- package/dist/logs/tailer.d.ts +0 -17
- package/dist/logs/tailer.js +0 -217
- package/dist/sync/__tests__/change-detect.test.d.ts +0 -1
- package/dist/sync/__tests__/change-detect.test.js +0 -123
- package/dist/sync/__tests__/hash.test.d.ts +0 -1
- package/dist/sync/__tests__/hash.test.js +0 -18
- package/dist/sync/change-detect.d.ts +0 -19
- package/dist/sync/change-detect.js +0 -136
- package/dist/sync/conflict-ui.d.ts +0 -5
- package/dist/sync/conflict-ui.js +0 -78
- package/dist/sync/executor.d.ts +0 -23
- package/dist/sync/executor.js +0 -102
- package/dist/sync/hash.d.ts +0 -1
- package/dist/sync/hash.js +0 -4
- package/dist/sync/types.d.ts +0 -24
- package/dist/sync/types.js +0 -1
- package/dist/template/manifest.d.ts +0 -17
- package/dist/template/manifest.js +0 -145
- package/dist/tools/types.d.ts +0 -52
- package/dist/tools/types.js +0 -8
- package/dist/types-manager.d.ts +0 -1
- package/dist/types-manager.js +0 -35
- package/dist/types.d.ts +0 -349
- package/dist/types.js +0 -1
- package/dist/ui/__tests__/banner.test.d.ts +0 -1
- package/dist/ui/__tests__/banner.test.js +0 -98
- package/dist/ui/__tests__/colors.test.d.ts +0 -1
- package/dist/ui/__tests__/colors.test.js +0 -22
- package/dist/ui/__tests__/keyboard.test.d.ts +0 -1
- package/dist/ui/__tests__/keyboard.test.js +0 -34
- package/dist/ui/__tests__/status-line.test.d.ts +0 -1
- package/dist/ui/__tests__/status-line.test.js +0 -54
- package/dist/ui/banner.d.ts +0 -29
- package/dist/ui/banner.js +0 -153
- package/dist/ui/colors.d.ts +0 -4
- package/dist/ui/colors.js +0 -7
- package/dist/ui/keyboard.d.ts +0 -12
- package/dist/ui/keyboard.js +0 -61
- package/dist/ui/status-line.d.ts +0 -6
- package/dist/ui/status-line.js +0 -53
- package/dist/utils/__tests__/format-error.test.d.ts +0 -1
- package/dist/utils/__tests__/format-error.test.js +0 -43
- package/dist/utils/__tests__/help-json.test.d.ts +0 -1
- package/dist/utils/__tests__/help-json.test.js +0 -39
- package/dist/utils/__tests__/http.test.d.ts +0 -1
- package/dist/utils/__tests__/http.test.js +0 -381
- package/dist/utils/__tests__/ignore-matcher.test.d.ts +0 -1
- package/dist/utils/__tests__/ignore-matcher.test.js +0 -205
- package/dist/utils/__tests__/output.test.d.ts +0 -1
- package/dist/utils/__tests__/output.test.js +0 -38
- package/dist/utils/__tests__/prompt.test.d.ts +0 -1
- package/dist/utils/__tests__/prompt.test.js +0 -27
- package/dist/utils/__tests__/resolve.test.d.ts +0 -1
- package/dist/utils/__tests__/resolve.test.js +0 -95
- package/dist/utils/__tests__/sqlite.test.d.ts +0 -1
- package/dist/utils/__tests__/sqlite.test.js +0 -89
- package/dist/utils/agent-guidance.d.ts +0 -47
- package/dist/utils/agent-guidance.js +0 -128
- package/dist/utils/app-info.d.ts +0 -70
- package/dist/utils/app-info.js +0 -167
- package/dist/utils/curl-parser.d.ts +0 -12
- package/dist/utils/curl-parser.js +0 -162
- package/dist/utils/data-input.d.ts +0 -1
- package/dist/utils/data-input.js +0 -38
- package/dist/utils/format-error.d.ts +0 -10
- package/dist/utils/format-error.js +0 -38
- package/dist/utils/fs.d.ts +0 -5
- package/dist/utils/fs.js +0 -23
- package/dist/utils/help-json.d.ts +0 -70
- package/dist/utils/help-json.js +0 -88
- package/dist/utils/http.d.ts +0 -46
- package/dist/utils/http.js +0 -421
- package/dist/utils/ignore-matcher.d.ts +0 -47
- package/dist/utils/ignore-matcher.js +0 -132
- package/dist/utils/output.d.ts +0 -17
- package/dist/utils/output.js +0 -27
- package/dist/utils/prompt.d.ts +0 -5
- package/dist/utils/prompt.js +0 -42
- package/dist/utils/resolve.d.ts +0 -12
- package/dist/utils/resolve.js +0 -52
- package/dist/utils/setup-state.d.ts +0 -3
- package/dist/utils/setup-state.js +0 -19
- package/dist/utils/sqlite-adapter.d.ts +0 -48
- package/dist/utils/sqlite-adapter.js +0 -147
- package/dist/utils/sqlite.d.ts +0 -14
- package/dist/utils/sqlite.js +0 -14
- package/dist/utils/subprocess.d.ts +0 -19
- package/dist/utils/subprocess.js +0 -27
- package/dist/utils/which.d.ts +0 -14
- package/dist/utils/which.js +0 -47
- package/dist/utils/zip.d.ts +0 -7
- package/dist/utils/zip.js +0 -42
- package/dist/validate/__tests__/validate.test.d.ts +0 -1
- package/dist/validate/__tests__/validate.test.js +0 -42
- package/dist/validate/freshness.d.ts +0 -28
- package/dist/validate/freshness.js +0 -48
- package/dist/validate/preview.d.ts +0 -21
- package/dist/validate/preview.js +0 -39
- package/dist/workspace/resolve.d.ts +0 -19
- package/dist/workspace/resolve.js +0 -100
package/dist/git/auto-commit.js
DELETED
|
@@ -1,293 +0,0 @@
|
|
|
1
|
-
import { execFileSync } from '../utils/subprocess.js';
|
|
2
|
-
import { readFileSync } from 'fs';
|
|
3
|
-
import { watch } from 'chokidar';
|
|
4
|
-
import { join, relative } from 'path';
|
|
5
|
-
import { dim, cyan, yellow } from '../ui/colors.js';
|
|
6
|
-
import { buildIgnoreSets, defaultIgnoreSets, isPathIgnored, isRelPathIgnored } from '../utils/ignore-matcher.js';
|
|
7
|
-
let watcher = null;
|
|
8
|
-
let fastSyncTimer = null;
|
|
9
|
-
let gitTimer = null;
|
|
10
|
-
let gitPushing = false;
|
|
11
|
-
let gitPendingAfterPush = false;
|
|
12
|
-
let activeCallbacks;
|
|
13
|
-
// Files awaiting fast sync: path -> 'changed' | 'deleted'
|
|
14
|
-
const pendingFastSync = new Map();
|
|
15
|
-
// Track files the user actually touched during this session (for git)
|
|
16
|
-
const changedFiles = new Set();
|
|
17
|
-
// Binary extensions to skip in fast sync (git handles them fine)
|
|
18
|
-
const BINARY_EXTENSIONS = new Set([
|
|
19
|
-
'.png', '.jpg', '.jpeg', '.gif', '.ico', '.webp', '.avif', '.svg',
|
|
20
|
-
'.woff', '.woff2', '.ttf', '.eot', '.otf',
|
|
21
|
-
'.mp3', '.mp4', '.webm', '.ogg', '.wav',
|
|
22
|
-
'.zip', '.tar', '.gz', '.br',
|
|
23
|
-
'.pdf', '.wasm',
|
|
24
|
-
]);
|
|
25
|
-
const STATIC_IGNORE_SETS = defaultIgnoreSets();
|
|
26
|
-
/**
|
|
27
|
-
* Basename-level ignore predicate using the static defaults only.
|
|
28
|
-
* Exposed for unit testing of the static defaults; the runtime watcher uses
|
|
29
|
-
* a richer matcher built from `.gitignore` (see watchAndAutoCommit).
|
|
30
|
-
*/
|
|
31
|
-
export function isIgnored(filePath) {
|
|
32
|
-
return isPathIgnored(filePath, STATIC_IGNORE_SETS);
|
|
33
|
-
}
|
|
34
|
-
export async function watchAndAutoCommit(directory, client, appId, callbacks) {
|
|
35
|
-
activeCallbacks = callbacks;
|
|
36
|
-
// Build a project-scoped ignore matcher that includes simple patterns from
|
|
37
|
-
// the project's .gitignore in addition to the static defaults. Without
|
|
38
|
-
// this the watcher tries to descend into large gitignored caches such as
|
|
39
|
-
// `.bun-cache/` or `dist/` and bogs the CLI down on startup.
|
|
40
|
-
const ignoreSets = buildIgnoreSets(directory);
|
|
41
|
-
watcher = watch(directory, {
|
|
42
|
-
ignored: (p) => isPathIgnored(p, ignoreSets),
|
|
43
|
-
persistent: true,
|
|
44
|
-
ignoreInitial: true,
|
|
45
|
-
awaitWriteFinish: {
|
|
46
|
-
stabilityThreshold: 300,
|
|
47
|
-
pollInterval: 100,
|
|
48
|
-
},
|
|
49
|
-
});
|
|
50
|
-
const onFileChange = (filePath) => {
|
|
51
|
-
const rel = relative(directory, filePath);
|
|
52
|
-
if (changedFiles.size === 0) {
|
|
53
|
-
console.log(` ${dim('Changed:')} ${cyan(rel)}`);
|
|
54
|
-
}
|
|
55
|
-
else {
|
|
56
|
-
console.log(` ${dim('Changed:')} ${cyan(rel)} ${dim(`(+${changedFiles.size} pending)`)}`);
|
|
57
|
-
}
|
|
58
|
-
changedFiles.add(rel);
|
|
59
|
-
pendingFastSync.set(rel, 'changed');
|
|
60
|
-
activeCallbacks?.onFileChange?.(rel, changedFiles.size);
|
|
61
|
-
scheduleFastSync(directory, client, appId);
|
|
62
|
-
scheduleGitCommit();
|
|
63
|
-
};
|
|
64
|
-
const onFileUnlink = (filePath) => {
|
|
65
|
-
const rel = relative(directory, filePath);
|
|
66
|
-
console.log(` ${dim('Deleted:')} ${cyan(rel)}`);
|
|
67
|
-
changedFiles.add(rel);
|
|
68
|
-
pendingFastSync.set(rel, 'deleted');
|
|
69
|
-
scheduleFastSync(directory, client, appId);
|
|
70
|
-
scheduleGitCommit();
|
|
71
|
-
};
|
|
72
|
-
watcher.on('add', onFileChange);
|
|
73
|
-
watcher.on('change', onFileChange);
|
|
74
|
-
watcher.on('unlink', onFileUnlink);
|
|
75
|
-
}
|
|
76
|
-
// ========================================
|
|
77
|
-
// FAST SYNC PATH (200ms debounce)
|
|
78
|
-
// ========================================
|
|
79
|
-
function scheduleFastSync(directory, client, appId) {
|
|
80
|
-
if (fastSyncTimer)
|
|
81
|
-
clearTimeout(fastSyncTimer);
|
|
82
|
-
fastSyncTimer = setTimeout(() => {
|
|
83
|
-
executeFastSync(directory, client, appId);
|
|
84
|
-
}, 200);
|
|
85
|
-
}
|
|
86
|
-
async function executeFastSync(directory, client, appId) {
|
|
87
|
-
if (pendingFastSync.size === 0)
|
|
88
|
-
return;
|
|
89
|
-
// Snapshot and clear
|
|
90
|
-
const snapshot = new Map(pendingFastSync);
|
|
91
|
-
pendingFastSync.clear();
|
|
92
|
-
const files = [];
|
|
93
|
-
const deletedFiles = [];
|
|
94
|
-
for (const [filePath, action] of snapshot) {
|
|
95
|
-
if (action === 'deleted') {
|
|
96
|
-
deletedFiles.push(filePath);
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
// Skip binary files in fast sync — git path handles them
|
|
100
|
-
const ext = filePath.lastIndexOf('.') >= 0 ? filePath.slice(filePath.lastIndexOf('.')) : '';
|
|
101
|
-
if (BINARY_EXTENSIONS.has(ext.toLowerCase()))
|
|
102
|
-
continue;
|
|
103
|
-
try {
|
|
104
|
-
const contents = readFileSync(join(directory, filePath), 'utf-8');
|
|
105
|
-
files.push({ filePath, fileContents: contents });
|
|
106
|
-
}
|
|
107
|
-
catch {
|
|
108
|
-
// File may have been deleted between detection and read
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
if (files.length === 0 && deletedFiles.length === 0)
|
|
113
|
-
return;
|
|
114
|
-
const total = files.length + deletedFiles.length;
|
|
115
|
-
try {
|
|
116
|
-
await client.syncFiles(appId, files, deletedFiles.length > 0 ? deletedFiles : undefined);
|
|
117
|
-
console.log(dim(` Synced ${total} file(s) to preview.`));
|
|
118
|
-
activeCallbacks?.onFastSync?.(total);
|
|
119
|
-
}
|
|
120
|
-
catch (error) {
|
|
121
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
122
|
-
console.warn(yellow(` Fast sync failed (git will handle it): ${message}`));
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
// ========================================
|
|
126
|
-
// GIT PATH (2s debounce)
|
|
127
|
-
// ========================================
|
|
128
|
-
/**
|
|
129
|
-
* Stage and commit the current working tree in a single shot, staging exactly
|
|
130
|
-
* what the dev watcher would: tracked modifications/deletions (`git add -u`)
|
|
131
|
-
* plus untracked files that the CLI ignore matcher does NOT exclude.
|
|
132
|
-
*
|
|
133
|
-
* It deliberately does NOT use `git add -A`. A blanket add honors only
|
|
134
|
-
* `.gitignore`, which in the runwork-app template excludes `.env.*` but not a
|
|
135
|
-
* bare `.env` (vibe-apps write both `.dev.vars` and `.env` locally) — so
|
|
136
|
-
* `git add -A` would commit and push local secrets. The CLI ignore matcher
|
|
137
|
-
* (the same one the dev watcher uses) excludes `.env`, `.dev.vars`,
|
|
138
|
-
* `.bun-cache`, `.runwork`, and `*.log`, keeping deploy's staging in parity
|
|
139
|
-
* with dev.
|
|
140
|
-
*
|
|
141
|
-
* Used by `runwork deploy`, which must commit pending working-tree changes
|
|
142
|
-
* even when no dev session ever ran.
|
|
143
|
-
*
|
|
144
|
-
* Returns the number of files committed (0 when nothing was staged).
|
|
145
|
-
*/
|
|
146
|
-
export function commitWorkingTree(cwd, message) {
|
|
147
|
-
// Tracked modifications and deletions.
|
|
148
|
-
execFileSync('git', ['add', '-u'], { cwd, stdio: 'pipe' });
|
|
149
|
-
// Untracked files that git itself doesn't ignore (.gitignore), further
|
|
150
|
-
// filtered through the CLI ignore matcher to match the dev watcher exactly.
|
|
151
|
-
const ignoreSets = buildIgnoreSets(cwd);
|
|
152
|
-
const untracked = execFileSync('git', ['-c', 'core.quotePath=false', 'ls-files', '--others', '--exclude-standard'], { cwd, encoding: 'utf-8' }).trim();
|
|
153
|
-
if (untracked) {
|
|
154
|
-
const toAdd = untracked
|
|
155
|
-
.split('\n')
|
|
156
|
-
.filter(Boolean)
|
|
157
|
-
.filter((p) => !isRelPathIgnored(p, ignoreSets));
|
|
158
|
-
const BATCH_SIZE = 50;
|
|
159
|
-
for (let i = 0; i < toAdd.length; i += BATCH_SIZE) {
|
|
160
|
-
const batch = toAdd.slice(i, i + BATCH_SIZE);
|
|
161
|
-
if (batch.length === 0)
|
|
162
|
-
continue;
|
|
163
|
-
try {
|
|
164
|
-
execFileSync('git', ['add', '--', ...batch], { cwd, stdio: 'pipe' });
|
|
165
|
-
}
|
|
166
|
-
catch {
|
|
167
|
-
// A file may have vanished between listing and staging.
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
return commitStaged(cwd, message);
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Commit whatever is currently staged. Shared by the deploy one-shot path
|
|
175
|
-
* (after `git add -A`) and the dev watcher path (after a selective add) so
|
|
176
|
-
* the "is anything staged? then commit" logic lives in one place.
|
|
177
|
-
*
|
|
178
|
-
* Returns the number of files committed (0 when nothing was staged).
|
|
179
|
-
*/
|
|
180
|
-
function commitStaged(cwd, message) {
|
|
181
|
-
// An empty staging area means there is nothing to commit.
|
|
182
|
-
const staged = execFileSync('git', ['-c', 'core.quotePath=false', 'diff', '--cached', '--name-only'], { cwd, encoding: 'utf-8' });
|
|
183
|
-
if (!staged.trim()) {
|
|
184
|
-
return { committed: false, fileCount: 0 };
|
|
185
|
-
}
|
|
186
|
-
const stagedFiles = staged.trim().split('\n').filter(Boolean);
|
|
187
|
-
execFileSync('git', ['commit', '-m', message], { cwd, stdio: 'pipe' });
|
|
188
|
-
return { committed: true, fileCount: stagedFiles.length };
|
|
189
|
-
}
|
|
190
|
-
function scheduleGitCommit() {
|
|
191
|
-
if (gitPushing) {
|
|
192
|
-
gitPendingAfterPush = true;
|
|
193
|
-
return;
|
|
194
|
-
}
|
|
195
|
-
if (gitTimer)
|
|
196
|
-
clearTimeout(gitTimer);
|
|
197
|
-
gitTimer = setTimeout(() => {
|
|
198
|
-
commitAndPush();
|
|
199
|
-
}, 2000);
|
|
200
|
-
}
|
|
201
|
-
function commitAndPush() {
|
|
202
|
-
try {
|
|
203
|
-
if (changedFiles.size === 0)
|
|
204
|
-
return;
|
|
205
|
-
gitPushing = true;
|
|
206
|
-
// Stage only files the user actually touched + already-tracked modified files
|
|
207
|
-
execFileSync('git', ['add', '-u'], { stdio: 'pipe' });
|
|
208
|
-
// Also stage specific files the user created/modified this session
|
|
209
|
-
const filesToAdd = Array.from(changedFiles);
|
|
210
|
-
changedFiles.clear();
|
|
211
|
-
if (filesToAdd.length > 0) {
|
|
212
|
-
const BATCH_SIZE = 50;
|
|
213
|
-
for (let i = 0; i < filesToAdd.length; i += BATCH_SIZE) {
|
|
214
|
-
const batch = filesToAdd.slice(i, i + BATCH_SIZE);
|
|
215
|
-
try {
|
|
216
|
-
execFileSync('git', ['add', '--', ...batch], { stdio: 'pipe' });
|
|
217
|
-
}
|
|
218
|
-
catch {
|
|
219
|
-
// Some files may have been deleted between detection and staging
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
// Commit whatever ended up staged (shared with the deploy path).
|
|
224
|
-
const timestamp = new Date().toISOString().replace('T', ' ').slice(0, 19);
|
|
225
|
-
const { committed, fileCount } = commitStaged(process.cwd(), `dev: updated ${timestamp}`);
|
|
226
|
-
if (!committed)
|
|
227
|
-
return;
|
|
228
|
-
// Pull --rebase to integrate any remote changes, then push
|
|
229
|
-
try {
|
|
230
|
-
execFileSync('git', ['pull', '--rebase', 'runwork', 'main'], { stdio: 'pipe' });
|
|
231
|
-
}
|
|
232
|
-
catch {
|
|
233
|
-
try {
|
|
234
|
-
execFileSync('git', ['rebase', '--abort'], { stdio: 'pipe' });
|
|
235
|
-
}
|
|
236
|
-
catch { /* no rebase in progress */ }
|
|
237
|
-
// Rebase fails when histories diverged (e.g. template update). Fall back to merge.
|
|
238
|
-
try {
|
|
239
|
-
execFileSync('git', ['merge', 'runwork/main', '--allow-unrelated-histories', '--no-edit'], { stdio: 'pipe' });
|
|
240
|
-
}
|
|
241
|
-
catch {
|
|
242
|
-
try {
|
|
243
|
-
execFileSync('git', ['merge', '--abort'], { stdio: 'pipe' });
|
|
244
|
-
}
|
|
245
|
-
catch { /* no merge in progress */ }
|
|
246
|
-
console.warn(yellow('Auto-sync: could not reconcile with the remote (conflicting changes). Your work is committed locally and safe.'));
|
|
247
|
-
console.warn(dim(' Resolve it by running: git fetch runwork && git rebase runwork/main'));
|
|
248
|
-
console.warn(dim(' Fix any conflicts (git status), then restart `runwork dev` to resume auto-sync.'));
|
|
249
|
-
return;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
// Push the current HEAD to the remote's `main` branch regardless of
|
|
253
|
-
// what the local branch is named. This way `git init` defaults of
|
|
254
|
-
// `master` (older Git) or any other custom branch name still sync
|
|
255
|
-
// cleanly to runwork's `main`. Without `HEAD:main`, `git push runwork
|
|
256
|
-
// main` fails with "src refspec main does not match any" when the
|
|
257
|
-
// local branch isn't called `main`.
|
|
258
|
-
try {
|
|
259
|
-
execFileSync('git', ['rev-parse', '--abbrev-ref', '@{u}'], { stdio: 'pipe' });
|
|
260
|
-
execFileSync('git', ['push', 'runwork', 'HEAD:main'], { stdio: 'pipe' });
|
|
261
|
-
}
|
|
262
|
-
catch {
|
|
263
|
-
execFileSync('git', ['push', '-u', 'runwork', 'HEAD:main'], { stdio: 'pipe' });
|
|
264
|
-
}
|
|
265
|
-
console.log(dim(` Pushed ${fileCount} file(s) to git.`));
|
|
266
|
-
activeCallbacks?.onGitPush?.(fileCount);
|
|
267
|
-
}
|
|
268
|
-
catch (error) {
|
|
269
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
270
|
-
console.warn(yellow(`Auto-sync failed: ${message}`));
|
|
271
|
-
}
|
|
272
|
-
finally {
|
|
273
|
-
gitPushing = false;
|
|
274
|
-
if (gitPendingAfterPush) {
|
|
275
|
-
gitPendingAfterPush = false;
|
|
276
|
-
scheduleGitCommit();
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
export async function stopAutoCommit() {
|
|
281
|
-
if (fastSyncTimer) {
|
|
282
|
-
clearTimeout(fastSyncTimer);
|
|
283
|
-
fastSyncTimer = null;
|
|
284
|
-
}
|
|
285
|
-
if (gitTimer) {
|
|
286
|
-
clearTimeout(gitTimer);
|
|
287
|
-
gitTimer = null;
|
|
288
|
-
}
|
|
289
|
-
if (watcher) {
|
|
290
|
-
await watcher.close();
|
|
291
|
-
watcher = null;
|
|
292
|
-
}
|
|
293
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Classify a git sync failure from the raw stderr that `syncWithRemote`
|
|
3
|
-
* captures, so `runwork dev`/`deploy` can show an accurate cause and fix
|
|
4
|
-
* instead of the old catch-all "the sandbox session expired or the network
|
|
5
|
-
* connection was interrupted" (which pointed users away from the real
|
|
6
|
-
* problem, e.g. a missing `runwork` remote -- see friction log #3).
|
|
7
|
-
*/
|
|
8
|
-
export type SyncErrorReason = 'no-remote' | 'auth' | 'network' | 'conflict' | 'unknown';
|
|
9
|
-
export interface SyncErrorDiagnosis {
|
|
10
|
-
reason: SyncErrorReason;
|
|
11
|
-
/** One-line summary suitable for an `error.message` field. */
|
|
12
|
-
message: string;
|
|
13
|
-
/** Plain explanation of the likely cause. */
|
|
14
|
-
diagnosis: string;
|
|
15
|
-
/** Actionable next steps, most-likely-fix first. */
|
|
16
|
-
suggestions: string[];
|
|
17
|
-
}
|
|
18
|
-
/** Map raw git stderr (or the stash-conflict sentinel) to a coarse reason. */
|
|
19
|
-
export declare function classifySyncError(raw: string | undefined): SyncErrorReason;
|
|
20
|
-
/** Build a full, user-facing diagnosis from the raw git stderr. */
|
|
21
|
-
export declare function diagnoseSyncError(raw: string | undefined): SyncErrorDiagnosis;
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The sentinel `syncWithRemote` returns when a stash pop conflicts after an
|
|
3
|
-
* otherwise-successful fetch/rebase. Routed through the classifier so the
|
|
4
|
-
* diagnosis stays in one place.
|
|
5
|
-
*/
|
|
6
|
-
const STASH_CONFLICT = 'stash-conflict';
|
|
7
|
-
/** Map raw git stderr (or the stash-conflict sentinel) to a coarse reason. */
|
|
8
|
-
export function classifySyncError(raw) {
|
|
9
|
-
if (!raw)
|
|
10
|
-
return 'unknown';
|
|
11
|
-
const s = raw.toLowerCase();
|
|
12
|
-
if (raw === STASH_CONFLICT)
|
|
13
|
-
return 'conflict';
|
|
14
|
-
// Missing/!misnamed remote. A plain `git clone` names the remote `origin`,
|
|
15
|
-
// so `git fetch runwork` fails with this before auth ever matters.
|
|
16
|
-
if (s.includes('does not appear to be a git repository') ||
|
|
17
|
-
s.includes("'runwork' does not appear") ||
|
|
18
|
-
s.includes('no such remote') ||
|
|
19
|
-
(s.includes('remote') && s.includes('not found'))) {
|
|
20
|
-
return 'no-remote';
|
|
21
|
-
}
|
|
22
|
-
// Authentication / authorization.
|
|
23
|
-
if (s.includes('authentication failed') ||
|
|
24
|
-
s.includes('could not read username') ||
|
|
25
|
-
s.includes('could not read password') ||
|
|
26
|
-
s.includes('terminal prompts disabled') ||
|
|
27
|
-
s.includes('permission denied') ||
|
|
28
|
-
s.includes('error: 403') ||
|
|
29
|
-
s.includes('error: 401') ||
|
|
30
|
-
s.includes('http basic: access denied') ||
|
|
31
|
-
s.includes('invalid username or password')) {
|
|
32
|
-
return 'auth';
|
|
33
|
-
}
|
|
34
|
-
// Network / connectivity.
|
|
35
|
-
if (s.includes('could not resolve host') ||
|
|
36
|
-
s.includes('failed to connect') ||
|
|
37
|
-
s.includes("couldn't connect to server") ||
|
|
38
|
-
s.includes('connection timed out') ||
|
|
39
|
-
s.includes('operation timed out') ||
|
|
40
|
-
s.includes('network is unreachable') ||
|
|
41
|
-
s.includes('temporary failure in name resolution')) {
|
|
42
|
-
return 'network';
|
|
43
|
-
}
|
|
44
|
-
// Merge/rebase conflicts.
|
|
45
|
-
if (s.includes('conflict') ||
|
|
46
|
-
s.includes('needs merge') ||
|
|
47
|
-
s.includes('automatic merge failed') ||
|
|
48
|
-
s.includes('patch failed')) {
|
|
49
|
-
return 'conflict';
|
|
50
|
-
}
|
|
51
|
-
return 'unknown';
|
|
52
|
-
}
|
|
53
|
-
/** Build a full, user-facing diagnosis from the raw git stderr. */
|
|
54
|
-
export function diagnoseSyncError(raw) {
|
|
55
|
-
const reason = classifySyncError(raw);
|
|
56
|
-
switch (reason) {
|
|
57
|
-
case 'no-remote':
|
|
58
|
-
return {
|
|
59
|
-
reason,
|
|
60
|
-
message: "git remote 'runwork' is missing or misconfigured",
|
|
61
|
-
diagnosis: "The sync targets a remote named 'runwork', but it doesn't exist in this repository (a plain `git clone` names the remote 'origin').",
|
|
62
|
-
suggestions: [
|
|
63
|
-
'Run `runwork doctor --fix` to add/repair the runwork remote',
|
|
64
|
-
'Or add it manually: `git remote add runwork <app git URL>`',
|
|
65
|
-
],
|
|
66
|
-
};
|
|
67
|
-
case 'auth':
|
|
68
|
-
return {
|
|
69
|
-
reason,
|
|
70
|
-
message: 'git could not authenticate to the runwork remote',
|
|
71
|
-
diagnosis: 'The runwork git credential helper is not registered (or the stored credentials were rejected), so git could not authenticate.',
|
|
72
|
-
suggestions: [
|
|
73
|
-
'Run `runwork doctor --fix` to register the git credential helper',
|
|
74
|
-
'If it persists, re-authenticate with `runwork login`',
|
|
75
|
-
],
|
|
76
|
-
};
|
|
77
|
-
case 'network':
|
|
78
|
-
return {
|
|
79
|
-
reason,
|
|
80
|
-
message: 'network error while syncing with the runwork remote',
|
|
81
|
-
diagnosis: 'git could not reach the runwork host. This is usually a connectivity or DNS issue.',
|
|
82
|
-
suggestions: [
|
|
83
|
-
'Check your network connection',
|
|
84
|
-
'Confirm outbound access to runwork.ai, then run `runwork dev` again',
|
|
85
|
-
],
|
|
86
|
-
};
|
|
87
|
-
case 'conflict':
|
|
88
|
-
return {
|
|
89
|
-
reason,
|
|
90
|
-
message: raw === STASH_CONFLICT
|
|
91
|
-
? 'merge conflicts after restoring local changes'
|
|
92
|
-
: 'merge conflicts while syncing with the remote',
|
|
93
|
-
diagnosis: 'Local changes could not be automatically merged with the remote state; the conflict needs manual resolution.',
|
|
94
|
-
suggestions: [
|
|
95
|
-
'Resolve the conflicts in the affected files (`git status` lists them)',
|
|
96
|
-
'Run `git add` on resolved files, then `git commit`',
|
|
97
|
-
'Run `runwork dev` again after resolving',
|
|
98
|
-
],
|
|
99
|
-
};
|
|
100
|
-
default:
|
|
101
|
-
return {
|
|
102
|
-
reason,
|
|
103
|
-
message: raw || 'file sync failed',
|
|
104
|
-
diagnosis: 'Could not sync files to the sandbox.',
|
|
105
|
-
suggestions: [
|
|
106
|
-
'Run `runwork doctor` to diagnose environment issues',
|
|
107
|
-
'Run `runwork dev` again to start a fresh session',
|
|
108
|
-
],
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
}
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Build the value we hand to `git config credential.<origin>.helper`.
|
|
3
|
-
*
|
|
4
|
-
* Git invokes credential helpers via its bash shell (Git Bash on Windows,
|
|
5
|
-
* /bin/sh elsewhere). A leading `!` tells git to treat the value as a raw
|
|
6
|
-
* shell command. We embed the absolute path of the *currently running*
|
|
7
|
-
* runwork binary so the helper invocation never depends on PATH at the
|
|
8
|
-
* moment git happens to call it -- which used to be a real failure mode
|
|
9
|
-
* on Windows when runwork.exe sits in `~/.runwork/bin` and that directory
|
|
10
|
-
* isn't picked up by git's bash subshell.
|
|
11
|
-
*
|
|
12
|
-
* The path is wrapped in quotes (handles spaces in install paths) and on
|
|
13
|
-
* Windows we normalise backslashes to forward slashes -- bash on Windows
|
|
14
|
-
* accepts both, but forward slashes avoid escaping issues in the .gitconfig
|
|
15
|
-
* file itself.
|
|
16
|
-
*/
|
|
17
|
-
export declare function buildHelperValue(execPath: string): string;
|
|
18
|
-
/**
|
|
19
|
-
* Configure git to use the runwork credential helper for our remote.
|
|
20
|
-
* Called by `runwork login` and `runwork init`.
|
|
21
|
-
*/
|
|
22
|
-
export declare function configureGitCredentials(remoteUrl: string): Promise<void>;
|
|
23
|
-
/**
|
|
24
|
-
* Result of looking up the git credential helper registered for a given
|
|
25
|
-
* origin in the user's global git config. Shared by `runwork doctor`
|
|
26
|
-
* (reporting) and the lazy-ensure path (clone/dev/deploy) so the detection
|
|
27
|
-
* logic never drifts between the two.
|
|
28
|
-
*/
|
|
29
|
-
export type CredentialHelperLookup = {
|
|
30
|
-
status: 'none';
|
|
31
|
-
} | {
|
|
32
|
-
status: 'unscoped';
|
|
33
|
-
otherCount: number;
|
|
34
|
-
} | {
|
|
35
|
-
status: 'registered';
|
|
36
|
-
value: string;
|
|
37
|
-
};
|
|
38
|
-
/**
|
|
39
|
-
* Read the git credential helper (if any) registered for `origin` in the
|
|
40
|
-
* global git config. Mirrors the scoped lookup `runwork doctor` performs: an
|
|
41
|
-
* entry only counts when its scope matches the user's baseUrl origin, so a
|
|
42
|
-
* stale staging origin from a previous login doesn't mask a missing entry.
|
|
43
|
-
*/
|
|
44
|
-
export declare function lookupCredentialHelper(origin: string): CredentialHelperLookup;
|
|
45
|
-
/**
|
|
46
|
-
* Inspect the binary a credential-helper value points at. Only absolute-path
|
|
47
|
-
* helper values (`!"/abs/path" git-credential-helper`) can be validated on
|
|
48
|
-
* disk; PATH-relative entries are trusted to resolve at git-invocation time
|
|
49
|
-
* (reported `ok` with a null path). Shared so the doctor check and the
|
|
50
|
-
* lazy-ensure path agree on what "stale" means.
|
|
51
|
-
*/
|
|
52
|
-
export declare function helperBinaryStatus(value: string): {
|
|
53
|
-
ok: boolean;
|
|
54
|
-
path: string | null;
|
|
55
|
-
};
|
|
56
|
-
/**
|
|
57
|
-
* Idempotently make sure the runwork git credential helper is registered for
|
|
58
|
-
* the given baseUrl's origin -- registering it when absent, or repairing it
|
|
59
|
-
* when it points at a binary that no longer exists (e.g. after the CLI moved
|
|
60
|
-
* on upgrade). This is the bridge that lets headless auth paths -- the
|
|
61
|
-
* `get_cli_setup` MCP tool or a hand-written `~/.runwork/.credentials` --
|
|
62
|
-
* work with git without a separate `runwork login`. Safe (and cheap) to call
|
|
63
|
-
* before every git operation in clone/dev/deploy.
|
|
64
|
-
*/
|
|
65
|
-
export declare function ensureGitCredentialHelper(baseUrl: string): Promise<void>;
|
|
66
|
-
/**
|
|
67
|
-
* Remove the git credential helper configuration for our remote.
|
|
68
|
-
*/
|
|
69
|
-
export declare function removeGitCredentials(baseUrl: string): Promise<void>;
|
|
70
|
-
/**
|
|
71
|
-
* Git credential helper protocol handler.
|
|
72
|
-
* Git calls: runwork git-credential-helper get
|
|
73
|
-
* We read stdin for host/protocol, write username/password to stdout.
|
|
74
|
-
*/
|
|
75
|
-
export declare function handleGitCredentialRequest(action: string): Promise<void>;
|
package/dist/git/credentials.js
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
import { existsSync } from 'fs';
|
|
2
|
-
import { execFileSync } from '../utils/subprocess.js';
|
|
3
|
-
import { getCredentials } from '../auth/store.js';
|
|
4
|
-
/**
|
|
5
|
-
* Build the value we hand to `git config credential.<origin>.helper`.
|
|
6
|
-
*
|
|
7
|
-
* Git invokes credential helpers via its bash shell (Git Bash on Windows,
|
|
8
|
-
* /bin/sh elsewhere). A leading `!` tells git to treat the value as a raw
|
|
9
|
-
* shell command. We embed the absolute path of the *currently running*
|
|
10
|
-
* runwork binary so the helper invocation never depends on PATH at the
|
|
11
|
-
* moment git happens to call it -- which used to be a real failure mode
|
|
12
|
-
* on Windows when runwork.exe sits in `~/.runwork/bin` and that directory
|
|
13
|
-
* isn't picked up by git's bash subshell.
|
|
14
|
-
*
|
|
15
|
-
* The path is wrapped in quotes (handles spaces in install paths) and on
|
|
16
|
-
* Windows we normalise backslashes to forward slashes -- bash on Windows
|
|
17
|
-
* accepts both, but forward slashes avoid escaping issues in the .gitconfig
|
|
18
|
-
* file itself.
|
|
19
|
-
*/
|
|
20
|
-
export function buildHelperValue(execPath) {
|
|
21
|
-
const normalised = execPath.replace(/\\/g, '/');
|
|
22
|
-
return `!"${normalised}" git-credential-helper`;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Configure git to use the runwork credential helper for our remote.
|
|
26
|
-
* Called by `runwork login` and `runwork init`.
|
|
27
|
-
*/
|
|
28
|
-
export async function configureGitCredentials(remoteUrl) {
|
|
29
|
-
const origin = new URL(remoteUrl).origin;
|
|
30
|
-
const helperValue = buildHelperValue(process.execPath);
|
|
31
|
-
try {
|
|
32
|
-
execFileSync('git', [
|
|
33
|
-
'config', '--global',
|
|
34
|
-
`credential.${origin}.helper`,
|
|
35
|
-
helperValue,
|
|
36
|
-
], { stdio: 'pipe' });
|
|
37
|
-
}
|
|
38
|
-
catch (err) {
|
|
39
|
-
const code = err?.code;
|
|
40
|
-
if (code === 'ENOENT') {
|
|
41
|
-
console.warn('Note: git is not installed. Skipping git credential helper setup.');
|
|
42
|
-
console.warn('Install git before running `runwork init`, `clone`, `dev`, or `deploy`.');
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
throw err;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Read the git credential helper (if any) registered for `origin` in the
|
|
50
|
-
* global git config. Mirrors the scoped lookup `runwork doctor` performs: an
|
|
51
|
-
* entry only counts when its scope matches the user's baseUrl origin, so a
|
|
52
|
-
* stale staging origin from a previous login doesn't mask a missing entry.
|
|
53
|
-
*/
|
|
54
|
-
export function lookupCredentialHelper(origin) {
|
|
55
|
-
// `--get-regexp` exits 1 (printing nothing) when no entry matches, which
|
|
56
|
-
// surfaces here as a thrown error -- a normal "not registered" signal.
|
|
57
|
-
let helperConfig;
|
|
58
|
-
try {
|
|
59
|
-
const buf = execFileSync('git', ['config', '--global', '--get-regexp', 'credential\\..*runwork.*\\.helper'], { stdio: ['ignore', 'pipe', 'ignore'] });
|
|
60
|
-
helperConfig = buf.toString();
|
|
61
|
-
}
|
|
62
|
-
catch {
|
|
63
|
-
return { status: 'none' };
|
|
64
|
-
}
|
|
65
|
-
const lines = helperConfig.split(/\r?\n/).map(l => l.trim()).filter(Boolean);
|
|
66
|
-
const escapedOrigin = origin.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
67
|
-
const scopedRegex = new RegExp(`^credential\\.${escapedOrigin}\\.helper\\s+(.+)$`);
|
|
68
|
-
const matchedLine = lines.find(line => scopedRegex.test(line));
|
|
69
|
-
if (!matchedLine) {
|
|
70
|
-
return { status: 'unscoped', otherCount: lines.length };
|
|
71
|
-
}
|
|
72
|
-
return { status: 'registered', value: scopedRegex.exec(matchedLine)?.[1] ?? '' };
|
|
73
|
-
}
|
|
74
|
-
/**
|
|
75
|
-
* Inspect the binary a credential-helper value points at. Only absolute-path
|
|
76
|
-
* helper values (`!"/abs/path" git-credential-helper`) can be validated on
|
|
77
|
-
* disk; PATH-relative entries are trusted to resolve at git-invocation time
|
|
78
|
-
* (reported `ok` with a null path). Shared so the doctor check and the
|
|
79
|
-
* lazy-ensure path agree on what "stale" means.
|
|
80
|
-
*/
|
|
81
|
-
export function helperBinaryStatus(value) {
|
|
82
|
-
const absoluteHelperRegex = /^!"?(\/|[A-Za-z]:[\\/])/;
|
|
83
|
-
if (!absoluteHelperRegex.test(value))
|
|
84
|
-
return { ok: true, path: null };
|
|
85
|
-
const pathMatch = value.match(/^!"([^"]+)"|^!(\S+)/);
|
|
86
|
-
const helperPath = pathMatch?.[1] ?? pathMatch?.[2] ?? '';
|
|
87
|
-
if (!helperPath)
|
|
88
|
-
return { ok: true, path: null };
|
|
89
|
-
return { ok: existsSync(helperPath), path: helperPath };
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Idempotently make sure the runwork git credential helper is registered for
|
|
93
|
-
* the given baseUrl's origin -- registering it when absent, or repairing it
|
|
94
|
-
* when it points at a binary that no longer exists (e.g. after the CLI moved
|
|
95
|
-
* on upgrade). This is the bridge that lets headless auth paths -- the
|
|
96
|
-
* `get_cli_setup` MCP tool or a hand-written `~/.runwork/.credentials` --
|
|
97
|
-
* work with git without a separate `runwork login`. Safe (and cheap) to call
|
|
98
|
-
* before every git operation in clone/dev/deploy.
|
|
99
|
-
*/
|
|
100
|
-
export async function ensureGitCredentialHelper(baseUrl) {
|
|
101
|
-
let origin;
|
|
102
|
-
try {
|
|
103
|
-
origin = new URL(baseUrl).origin;
|
|
104
|
-
}
|
|
105
|
-
catch {
|
|
106
|
-
return; // Unparseable baseUrl -- nothing actionable.
|
|
107
|
-
}
|
|
108
|
-
const lookup = lookupCredentialHelper(origin);
|
|
109
|
-
if (lookup.status === 'registered' && helperBinaryStatus(lookup.value).ok) {
|
|
110
|
-
return; // Already registered and valid -- no-op.
|
|
111
|
-
}
|
|
112
|
-
await configureGitCredentials(baseUrl);
|
|
113
|
-
}
|
|
114
|
-
/**
|
|
115
|
-
* Remove the git credential helper configuration for our remote.
|
|
116
|
-
*/
|
|
117
|
-
export async function removeGitCredentials(baseUrl) {
|
|
118
|
-
const origin = new URL(baseUrl).origin;
|
|
119
|
-
try {
|
|
120
|
-
execFileSync('git', [
|
|
121
|
-
'config', '--global', '--unset',
|
|
122
|
-
`credential.${origin}.helper`,
|
|
123
|
-
], { stdio: 'pipe' });
|
|
124
|
-
}
|
|
125
|
-
catch {
|
|
126
|
-
// Ignore errors if the config key doesn't exist
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Git credential helper protocol handler.
|
|
131
|
-
* Git calls: runwork git-credential-helper get
|
|
132
|
-
* We read stdin for host/protocol, write username/password to stdout.
|
|
133
|
-
*/
|
|
134
|
-
export async function handleGitCredentialRequest(action) {
|
|
135
|
-
if (action !== 'get') {
|
|
136
|
-
return; // Only 'get' needs handling. 'store' and 'erase' are no-ops.
|
|
137
|
-
}
|
|
138
|
-
const input = await readStdin();
|
|
139
|
-
const lines = input.trim().split('\n');
|
|
140
|
-
const params = {};
|
|
141
|
-
for (const line of lines) {
|
|
142
|
-
const [key, value] = line.split('=', 2);
|
|
143
|
-
if (key && value)
|
|
144
|
-
params[key] = value;
|
|
145
|
-
}
|
|
146
|
-
const creds = getCredentials();
|
|
147
|
-
if (!creds) {
|
|
148
|
-
process.exit(1);
|
|
149
|
-
}
|
|
150
|
-
process.stdout.write(`protocol=${params.protocol || 'https'}\n`);
|
|
151
|
-
process.stdout.write(`host=${params.host}\n`);
|
|
152
|
-
process.stdout.write(`username=runwork\n`);
|
|
153
|
-
process.stdout.write(`password=${creds.apiKey}\n`);
|
|
154
|
-
}
|
|
155
|
-
function readStdin() {
|
|
156
|
-
return new Promise((resolve) => {
|
|
157
|
-
let data = '';
|
|
158
|
-
process.stdin.setEncoding('utf8');
|
|
159
|
-
process.stdin.on('data', (chunk) => { data += chunk; });
|
|
160
|
-
process.stdin.on('end', () => resolve(data));
|
|
161
|
-
if (process.stdin.readableEnded)
|
|
162
|
-
resolve(data);
|
|
163
|
-
});
|
|
164
|
-
}
|