@stigmer/cli 3.35.0 → 3.36.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/auth/auth0.d.ts.map +1 -1
- package/auth/auth0.js.map +1 -1
- package/auth/callback-server.d.ts.map +1 -1
- package/auth/callback-server.js.map +1 -1
- package/auth/index.d.ts.map +1 -1
- package/auth/index.js.map +1 -1
- package/auth/login.d.ts.map +1 -1
- package/auth/login.js.map +1 -1
- package/auth/pages.d.ts.map +1 -1
- package/auth/pages.js.map +1 -1
- package/auth/pkce.d.ts.map +1 -1
- package/auth/pkce.js.map +1 -1
- package/auth/token.d.ts.map +1 -1
- package/auth/token.js.map +1 -1
- package/backend.d.ts.map +1 -1
- package/backend.js.map +1 -1
- package/cli/stigmer.d.ts.map +1 -1
- package/cli/stigmer.js.map +1 -1
- package/client/client.d.ts.map +1 -1
- package/client/client.js.map +1 -1
- package/client/index.d.ts.map +1 -1
- package/client/index.js.map +1 -1
- package/commands/agent-exec-flags.d.ts.map +1 -1
- package/commands/agent-exec-flags.js.map +1 -1
- package/commands/apikey/duration.d.ts.map +1 -1
- package/commands/apikey/duration.js.map +1 -1
- package/commands/apikey/index.d.ts.map +1 -1
- package/commands/apikey/index.js.map +1 -1
- package/commands/apply.d.ts.map +1 -1
- package/commands/apply.js.map +1 -1
- package/commands/auth/index.d.ts.map +1 -1
- package/commands/auth/index.js.map +1 -1
- package/commands/auth/login.d.ts.map +1 -1
- package/commands/auth/login.js.map +1 -1
- package/commands/auth/whoami.d.ts.map +1 -1
- package/commands/auth/whoami.js.map +1 -1
- package/commands/bootstrap.d.ts.map +1 -1
- package/commands/bootstrap.js.map +1 -1
- package/commands/completion.d.ts.map +1 -1
- package/commands/completion.js.map +1 -1
- package/commands/config/backend.d.ts.map +1 -1
- package/commands/config/backend.js.map +1 -1
- package/commands/config/context.d.ts.map +1 -1
- package/commands/config/context.js.map +1 -1
- package/commands/config/index.d.ts.map +1 -1
- package/commands/config/index.js.map +1 -1
- package/commands/config/kv.d.ts.map +1 -1
- package/commands/config/kv.js.map +1 -1
- package/commands/connect.d.ts.map +1 -1
- package/commands/connect.js.map +1 -1
- package/commands/delete.d.ts.map +1 -1
- package/commands/delete.js.map +1 -1
- package/commands/diff.d.ts.map +1 -1
- package/commands/diff.js.map +1 -1
- package/commands/down.d.ts.map +1 -1
- package/commands/down.js.map +1 -1
- package/commands/download.d.ts.map +1 -1
- package/commands/download.js.map +1 -1
- package/commands/execution/approve.d.ts.map +1 -1
- package/commands/execution/approve.js.map +1 -1
- package/commands/execution/control.d.ts.map +1 -1
- package/commands/execution/control.js.map +1 -1
- package/commands/execution/index.d.ts.map +1 -1
- package/commands/execution/index.js.map +1 -1
- package/commands/execution/logs.d.ts.map +1 -1
- package/commands/execution/logs.js.map +1 -1
- package/commands/execution/trace.d.ts.map +1 -1
- package/commands/execution/trace.js.map +1 -1
- package/commands/get.d.ts.map +1 -1
- package/commands/get.js.map +1 -1
- package/commands/install.d.ts.map +1 -1
- package/commands/install.js.map +1 -1
- package/commands/internal-daemon.d.ts.map +1 -1
- package/commands/internal-daemon.js.map +1 -1
- package/commands/list.d.ts.map +1 -1
- package/commands/list.js.map +1 -1
- package/commands/logs.d.ts.map +1 -1
- package/commands/logs.js.map +1 -1
- package/commands/marketplace.d.ts.map +1 -1
- package/commands/marketplace.js.map +1 -1
- package/commands/mcp-server.d.ts.map +1 -1
- package/commands/mcp-server.js.map +1 -1
- package/commands/push.d.ts.map +1 -1
- package/commands/push.js.map +1 -1
- package/commands/reset.d.ts.map +1 -1
- package/commands/reset.js.map +1 -1
- package/commands/resume.d.ts.map +1 -1
- package/commands/resume.js.map +1 -1
- package/commands/run.d.ts.map +1 -1
- package/commands/run.js.map +1 -1
- package/commands/schedule.d.ts.map +1 -1
- package/commands/schedule.js.map +1 -1
- package/commands/search.d.ts.map +1 -1
- package/commands/search.js.map +1 -1
- package/commands/setup.d.ts.map +1 -1
- package/commands/setup.js.map +1 -1
- package/commands/share.d.ts.map +1 -1
- package/commands/share.js.map +1 -1
- package/commands/shared.d.ts.map +1 -1
- package/commands/shared.js.map +1 -1
- package/commands/status.d.ts.map +1 -1
- package/commands/status.js.map +1 -1
- package/commands/tag.d.ts.map +1 -1
- package/commands/tag.js.map +1 -1
- package/commands/up.d.ts.map +1 -1
- package/commands/up.js.map +1 -1
- package/commands/usage.d.ts.map +1 -1
- package/commands/usage.js.map +1 -1
- package/commands/validate.d.ts.map +1 -1
- package/commands/validate.js.map +1 -1
- package/commands/version.d.ts.map +1 -1
- package/commands/version.js.map +1 -1
- package/config/config.d.ts.map +1 -1
- package/config/config.js.map +1 -1
- package/config/index.d.ts.map +1 -1
- package/config/index.js.map +1 -1
- package/config/keys.d.ts.map +1 -1
- package/config/keys.js.map +1 -1
- package/config/paths.d.ts.map +1 -1
- package/config/paths.js.map +1 -1
- package/config/resolve.d.ts.map +1 -1
- package/config/resolve.js.map +1 -1
- package/errors/classify.d.ts.map +1 -1
- package/errors/classify.js.map +1 -1
- package/errors/cli-exit-error.d.ts.map +1 -1
- package/errors/cli-exit-error.js.map +1 -1
- package/errors/exit-codes.d.ts.map +1 -1
- package/errors/exit-codes.js.map +1 -1
- package/errors/handle.d.ts.map +1 -1
- package/errors/handle.js.map +1 -1
- package/errors/index.d.ts.map +1 -1
- package/errors/index.js.map +1 -1
- package/errors/usage-error.d.ts.map +1 -1
- package/errors/usage-error.js.map +1 -1
- package/index.d.ts.map +1 -1
- package/index.js.map +1 -1
- package/local/artifact.d.ts.map +1 -1
- package/local/artifact.js.map +1 -1
- package/local/bootstrap.d.ts.map +1 -1
- package/local/bootstrap.js.map +1 -1
- package/local/constants.d.ts.map +1 -1
- package/local/constants.js.map +1 -1
- package/local/daemon/components.d.ts.map +1 -1
- package/local/daemon/components.js.map +1 -1
- package/local/daemon/env.d.ts.map +1 -1
- package/local/daemon/env.js.map +1 -1
- package/local/daemon/host.d.ts.map +1 -1
- package/local/daemon/host.js.map +1 -1
- package/local/daemon/index.d.ts.map +1 -1
- package/local/daemon/index.js.map +1 -1
- package/local/daemon/launch.d.ts.map +1 -1
- package/local/daemon/launch.js.map +1 -1
- package/local/daemon/process.d.ts.map +1 -1
- package/local/daemon/process.js.map +1 -1
- package/local/daemon/supervisor.d.ts.map +1 -1
- package/local/daemon/supervisor.js.map +1 -1
- package/local/daemon/types.d.ts.map +1 -1
- package/local/daemon/types.js.map +1 -1
- package/local/llm-config.d.ts.map +1 -1
- package/local/llm-config.js.map +1 -1
- package/local/logs/tail.d.ts.map +1 -1
- package/local/logs/tail.js.map +1 -1
- package/local/logs/view.d.ts.map +1 -1
- package/local/logs/view.js.map +1 -1
- package/local/net/tcp.d.ts.map +1 -1
- package/local/net/tcp.js.map +1 -1
- package/local/operator-config.d.ts.map +1 -1
- package/local/operator-config.js.map +1 -1
- package/local/paths.d.ts.map +1 -1
- package/local/paths.js.map +1 -1
- package/local/reset.d.ts.map +1 -1
- package/local/reset.js.map +1 -1
- package/local/runtime/index.d.ts.map +1 -1
- package/local/runtime/index.js.map +1 -1
- package/local/runtime/node.d.ts.map +1 -1
- package/local/runtime/node.js.map +1 -1
- package/local/runtime/runner.d.ts.map +1 -1
- package/local/runtime/runner.js.map +1 -1
- package/local/runtime/runtimes-install.d.ts.map +1 -1
- package/local/runtime/runtimes-install.js.map +1 -1
- package/local/runtime/server.d.ts.map +1 -1
- package/local/runtime/server.js.map +1 -1
- package/local/runtime/which.d.ts.map +1 -1
- package/local/runtime/which.js.map +1 -1
- package/local/setup/prompt.d.ts.map +1 -1
- package/local/setup/prompt.js.map +1 -1
- package/local/setup/wizard.d.ts.map +1 -1
- package/local/setup/wizard.js.map +1 -1
- package/local/state/health-state.d.ts.map +1 -1
- package/local/state/health-state.js.map +1 -1
- package/local/state/index.d.ts.map +1 -1
- package/local/state/index.js.map +1 -1
- package/local/state/lock.d.ts.map +1 -1
- package/local/state/lock.js.map +1 -1
- package/local/state/log-rotation.d.ts.map +1 -1
- package/local/state/log-rotation.js.map +1 -1
- package/local/state/pidfile.d.ts.map +1 -1
- package/local/state/pidfile.js.map +1 -1
- package/local/state/proc.d.ts.map +1 -1
- package/local/state/proc.js.map +1 -1
- package/local/state/startup-config.d.ts.map +1 -1
- package/local/state/startup-config.js.map +1 -1
- package/local/status.d.ts.map +1 -1
- package/local/status.js.map +1 -1
- package/local/temporal/download.d.ts.map +1 -1
- package/local/temporal/download.js.map +1 -1
- package/local/temporal/index.d.ts.map +1 -1
- package/local/temporal/index.js.map +1 -1
- package/local/temporal/inspect.d.ts.map +1 -1
- package/local/temporal/inspect.js.map +1 -1
- package/local/temporal/manager.d.ts.map +1 -1
- package/local/temporal/manager.js.map +1 -1
- package/local/temporal/supervisor.d.ts.map +1 -1
- package/local/temporal/supervisor.js.map +1 -1
- package/local/webconsole/index.d.ts.map +1 -1
- package/local/webconsole/index.js.map +1 -1
- package/logger.d.ts.map +1 -1
- package/logger.js.map +1 -1
- package/marketplace/config.d.ts.map +1 -1
- package/marketplace/config.js.map +1 -1
- package/marketplace/github.d.ts.map +1 -1
- package/marketplace/github.js.map +1 -1
- package/marketplace/index.d.ts.map +1 -1
- package/marketplace/index.js.map +1 -1
- package/marketplace/install.d.ts.map +1 -1
- package/marketplace/install.js.map +1 -1
- package/marketplace/materialize.d.ts.map +1 -1
- package/marketplace/materialize.js.map +1 -1
- package/marketplace/official.d.ts.map +1 -1
- package/marketplace/official.js.map +1 -1
- package/marketplace/read.d.ts.map +1 -1
- package/marketplace/read.js.map +1 -1
- package/marketplace/ref.d.ts.map +1 -1
- package/marketplace/ref.js.map +1 -1
- package/marketplace/render.d.ts.map +1 -1
- package/marketplace/render.js.map +1 -1
- package/output/command-result.d.ts.map +1 -1
- package/output/command-result.js.map +1 -1
- package/output/confirm.d.ts.map +1 -1
- package/output/confirm.js.map +1 -1
- package/output/format.d.ts.map +1 -1
- package/output/format.js.map +1 -1
- package/output/index.d.ts.map +1 -1
- package/output/index.js.map +1 -1
- package/output/ndjson.d.ts.map +1 -1
- package/output/ndjson.js.map +1 -1
- package/output/proto.d.ts.map +1 -1
- package/output/proto.js.map +1 -1
- package/output/style.d.ts.map +1 -1
- package/output/style.js.map +1 -1
- package/output/table.d.ts.map +1 -1
- package/output/table.js.map +1 -1
- package/package.json +7 -7
- package/program.d.ts.map +1 -1
- package/program.js.map +1 -1
- package/registry/aliases.d.ts.map +1 -1
- package/registry/aliases.js.map +1 -1
- package/registry/index.d.ts.map +1 -1
- package/registry/index.js.map +1 -1
- package/registry/metadata.d.ts.map +1 -1
- package/registry/metadata.js.map +1 -1
- package/registry/registry.d.ts.map +1 -1
- package/registry/registry.js.map +1 -1
- package/registry/verb-support.d.ts.map +1 -1
- package/registry/verb-support.js.map +1 -1
- package/registry/verbs.d.ts.map +1 -1
- package/registry/verbs.js.map +1 -1
- package/resources/apply/apply.d.ts.map +1 -1
- package/resources/apply/apply.js.map +1 -1
- package/resources/apply/discovery.d.ts.map +1 -1
- package/resources/apply/discovery.js.map +1 -1
- package/resources/apply/handlers.d.ts.map +1 -1
- package/resources/apply/handlers.js.map +1 -1
- package/resources/connect/connect.d.ts.map +1 -1
- package/resources/connect/connect.js.map +1 -1
- package/resources/connect/discover.d.ts.map +1 -1
- package/resources/connect/discover.js.map +1 -1
- package/resources/connect/display.d.ts.map +1 -1
- package/resources/connect/display.js.map +1 -1
- package/resources/connect/oauth.d.ts.map +1 -1
- package/resources/connect/oauth.js.map +1 -1
- package/resources/cursor-pages.d.ts.map +1 -1
- package/resources/cursor-pages.js.map +1 -1
- package/resources/delete.d.ts.map +1 -1
- package/resources/delete.js.map +1 -1
- package/resources/diff.d.ts.map +1 -1
- package/resources/diff.js.map +1 -1
- package/resources/documents.d.ts.map +1 -1
- package/resources/documents.js.map +1 -1
- package/resources/download.d.ts.map +1 -1
- package/resources/download.js.map +1 -1
- package/resources/execution-approve.d.ts.map +1 -1
- package/resources/execution-approve.js.map +1 -1
- package/resources/execution-control.d.ts.map +1 -1
- package/resources/execution-control.js.map +1 -1
- package/resources/execution-format.d.ts.map +1 -1
- package/resources/execution-format.js.map +1 -1
- package/resources/execution-logs.d.ts.map +1 -1
- package/resources/execution-logs.js.map +1 -1
- package/resources/execution-trace.d.ts.map +1 -1
- package/resources/execution-trace.js.map +1 -1
- package/resources/execution.d.ts.map +1 -1
- package/resources/execution.js.map +1 -1
- package/resources/get-bindings.d.ts.map +1 -1
- package/resources/get-bindings.js.map +1 -1
- package/resources/get.d.ts.map +1 -1
- package/resources/get.js.map +1 -1
- package/resources/git.d.ts.map +1 -1
- package/resources/git.js.map +1 -1
- package/resources/ignore/index.d.ts.map +1 -1
- package/resources/ignore/index.js.map +1 -1
- package/resources/ignore/matcher.d.ts.map +1 -1
- package/resources/ignore/matcher.js.map +1 -1
- package/resources/list.d.ts.map +1 -1
- package/resources/list.js.map +1 -1
- package/resources/mcp/placeholder-resolver.d.ts.map +1 -1
- package/resources/mcp/placeholder-resolver.js.map +1 -1
- package/resources/mcp/runtime-env.d.ts.map +1 -1
- package/resources/mcp/runtime-env.js.map +1 -1
- package/resources/picker/ink.d.ts.map +1 -1
- package/resources/picker/ink.js.map +1 -1
- package/resources/picker/tty.d.ts.map +1 -1
- package/resources/picker/tty.js.map +1 -1
- package/resources/plugin.d.ts.map +1 -1
- package/resources/plugin.js.map +1 -1
- package/resources/reference.d.ts.map +1 -1
- package/resources/reference.js.map +1 -1
- package/resources/render.d.ts.map +1 -1
- package/resources/render.js.map +1 -1
- package/resources/run/agent-exec.d.ts.map +1 -1
- package/resources/run/agent-exec.js.map +1 -1
- package/resources/run/attachments.d.ts.map +1 -1
- package/resources/run/attachments.js.map +1 -1
- package/resources/run/create.d.ts.map +1 -1
- package/resources/run/create.js.map +1 -1
- package/resources/run/env.d.ts.map +1 -1
- package/resources/run/env.js.map +1 -1
- package/resources/run/epilogue.d.ts.map +1 -1
- package/resources/run/epilogue.js.map +1 -1
- package/resources/run/header.d.ts.map +1 -1
- package/resources/run/header.js.map +1 -1
- package/resources/run/prepare.d.ts.map +1 -1
- package/resources/run/prepare.js.map +1 -1
- package/resources/run/resolve.d.ts.map +1 -1
- package/resources/run/resolve.js.map +1 -1
- package/resources/run/resume.d.ts.map +1 -1
- package/resources/run/resume.js.map +1 -1
- package/resources/run/stream.d.ts.map +1 -1
- package/resources/run/stream.js.map +1 -1
- package/resources/run/workflow-stream.d.ts.map +1 -1
- package/resources/run/workflow-stream.js.map +1 -1
- package/resources/run/workspace.d.ts.map +1 -1
- package/resources/run/workspace.js.map +1 -1
- package/resources/schedule.d.ts.map +1 -1
- package/resources/schedule.js.map +1 -1
- package/resources/search.d.ts.map +1 -1
- package/resources/search.js.map +1 -1
- package/resources/session.d.ts.map +1 -1
- package/resources/session.js.map +1 -1
- package/resources/share.d.ts.map +1 -1
- package/resources/share.js.map +1 -1
- package/resources/skill.d.ts.map +1 -1
- package/resources/skill.js.map +1 -1
- package/resources/stream/approval-detect.d.ts.map +1 -1
- package/resources/stream/approval-detect.js.map +1 -1
- package/resources/stream/convert.d.ts.map +1 -1
- package/resources/stream/convert.js.map +1 -1
- package/resources/stream/diff.d.ts.map +1 -1
- package/resources/stream/diff.js.map +1 -1
- package/resources/stream/events.d.ts.map +1 -1
- package/resources/stream/events.js.map +1 -1
- package/resources/stream/headless.d.ts.map +1 -1
- package/resources/stream/headless.js.map +1 -1
- package/resources/stream/ink.d.ts.map +1 -1
- package/resources/stream/ink.js.map +1 -1
- package/resources/stream/render-ndjson.d.ts.map +1 -1
- package/resources/stream/render-ndjson.js.map +1 -1
- package/resources/stream/render-plaintext.d.ts.map +1 -1
- package/resources/stream/render-plaintext.js.map +1 -1
- package/resources/stream/snapshot.d.ts.map +1 -1
- package/resources/stream/snapshot.js.map +1 -1
- package/resources/stream/subagent.d.ts.map +1 -1
- package/resources/stream/subagent.js.map +1 -1
- package/resources/stream/submit.d.ts.map +1 -1
- package/resources/stream/submit.js.map +1 -1
- package/resources/stream/todo.d.ts.map +1 -1
- package/resources/stream/todo.js.map +1 -1
- package/resources/stream/tool-state.d.ts.map +1 -1
- package/resources/stream/tool-state.js.map +1 -1
- package/resources/stream/tty.d.ts.map +1 -1
- package/resources/stream/tty.js.map +1 -1
- package/resources/stream/workflow-event-view.d.ts.map +1 -1
- package/resources/stream/workflow-event-view.js.map +1 -1
- package/resources/stream/workflow-render-ndjson.d.ts.map +1 -1
- package/resources/stream/workflow-render-ndjson.js.map +1 -1
- package/resources/stream/workflow-render-plaintext.d.ts.map +1 -1
- package/resources/stream/workflow-render-plaintext.js.map +1 -1
- package/resources/tag.d.ts.map +1 -1
- package/resources/tag.js.map +1 -1
- package/resources/task-configs.d.ts.map +1 -1
- package/resources/task-configs.js.map +1 -1
- package/resources/usage.d.ts.map +1 -1
- package/resources/usage.js.map +1 -1
- package/resources/validate.d.ts.map +1 -1
- package/resources/validate.js.map +1 -1
- package/resources/version.d.ts.map +1 -1
- package/resources/version.js.map +1 -1
- package/runtime.d.ts.map +1 -1
- package/runtime.js.map +1 -1
- package/version.d.ts.map +1 -1
- package/version.js.map +1 -1
- package/src/auth/pkce.test.ts +0 -37
- package/src/auth/token.test.ts +0 -151
- package/src/client/client.test.ts +0 -142
- package/src/commands/apikey/duration.test.ts +0 -23
- package/src/commands/auth/login.test.ts +0 -52
- package/src/commands/auth/whoami.test.ts +0 -96
- package/src/commands/bootstrap.test.ts +0 -178
- package/src/commands/config/backend.test.ts +0 -122
- package/src/commands/config/context.test.ts +0 -171
- package/src/commands/connect.test.ts +0 -113
- package/src/commands/install.test.ts +0 -307
- package/src/commands/marketplace.test.ts +0 -205
- package/src/commands/mcp-server.test.ts +0 -65
- package/src/commands/validate.test.ts +0 -168
- package/src/config/config.test.ts +0 -132
- package/src/config/keys.test.ts +0 -61
- package/src/config/resolve.test.ts +0 -242
- package/src/errors/clierr.test.ts +0 -172
- package/src/local/artifact.test.ts +0 -54
- package/src/local/bootstrap.test.ts +0 -166
- package/src/local/daemon/components.test.ts +0 -148
- package/src/local/daemon/daemon.integration.test.ts +0 -216
- package/src/local/daemon/env.test.ts +0 -108
- package/src/local/daemon/launch.test.ts +0 -136
- package/src/local/daemon/supervisor.test.ts +0 -260
- package/src/local/llm-config.test.ts +0 -66
- package/src/local/logs/tail.test.ts +0 -70
- package/src/local/logs/view.test.ts +0 -46
- package/src/local/operator-config.test.ts +0 -72
- package/src/local/reset.test.ts +0 -53
- package/src/local/runtime/runtime.test.ts +0 -240
- package/src/local/runtime/runtimes-install.test.ts +0 -58
- package/src/local/runtime/server.test.ts +0 -253
- package/src/local/setup/wizard.test.ts +0 -94
- package/src/local/state/state.test.ts +0 -210
- package/src/local/status.test.ts +0 -108
- package/src/local/temporal/download.test.ts +0 -248
- package/src/local/temporal/inspect.test.ts +0 -83
- package/src/local/temporal/manager.test.ts +0 -64
- package/src/local/temporal/supervisor.test.ts +0 -77
- package/src/marketplace/__fixtures__/cursor-marketplace.ts +0 -69
- package/src/marketplace/config.test.ts +0 -254
- package/src/marketplace/github.test.ts +0 -394
- package/src/marketplace/install.test.ts +0 -261
- package/src/marketplace/official.test.ts +0 -107
- package/src/marketplace/read.test.ts +0 -93
- package/src/marketplace/ref.test.ts +0 -179
- package/src/output/command-result.test.ts +0 -73
- package/src/output/confirm.test.ts +0 -43
- package/src/output/format.test.ts +0 -65
- package/src/output/proto.test.ts +0 -72
- package/src/output/table.test.ts +0 -37
- package/src/program.test.ts +0 -62
- package/src/registry/aliases.test.ts +0 -142
- package/src/registry/registry.test.ts +0 -355
- package/src/resources/apply/apply.integration.test.ts +0 -353
- package/src/resources/apply/apply.test.ts +0 -134
- package/src/resources/apply/discovery.integration.test.ts +0 -99
- package/src/resources/connect/__fixtures__/stdio-crash.mjs +0 -6
- package/src/resources/connect/__fixtures__/stdio-server.mjs +0 -48
- package/src/resources/connect/connect.integration.test.ts +0 -383
- package/src/resources/connect/discover.test.ts +0 -84
- package/src/resources/connect/oauth.test.ts +0 -158
- package/src/resources/cursor-pages.test.ts +0 -55
- package/src/resources/diff.integration.test.ts +0 -103
- package/src/resources/diff.test.ts +0 -34
- package/src/resources/documents.test.ts +0 -67
- package/src/resources/execution-approve.test.ts +0 -50
- package/src/resources/execution-format.test.ts +0 -48
- package/src/resources/execution.integration.test.ts +0 -285
- package/src/resources/execution.test.ts +0 -138
- package/src/resources/ignore/ignore.test.ts +0 -62
- package/src/resources/mcp/placeholder-resolver.test.ts +0 -71
- package/src/resources/mcp/runtime-env.test.ts +0 -102
- package/src/resources/mutate-verbs.integration.test.ts +0 -455
- package/src/resources/picker/tty.test.ts +0 -37
- package/src/resources/plugin.test.ts +0 -379
- package/src/resources/push-download.integration.test.ts +0 -175
- package/src/resources/read-completion.integration.test.ts +0 -164
- package/src/resources/read-verbs.integration.test.ts +0 -603
- package/src/resources/reference.test.ts +0 -107
- package/src/resources/run/agent-exec.test.ts +0 -179
- package/src/resources/run/attachments.test.ts +0 -135
- package/src/resources/run/create.test.ts +0 -336
- package/src/resources/run/env.test.ts +0 -131
- package/src/resources/run/header.test.ts +0 -79
- package/src/resources/run/prepare.test.ts +0 -428
- package/src/resources/run/workflow-stream.integration.test.ts +0 -157
- package/src/resources/run/workspace.test.ts +0 -93
- package/src/resources/share.test.ts +0 -523
- package/src/resources/skill.test.ts +0 -364
- package/src/resources/stream/diff.test.ts +0 -338
- package/src/resources/stream/headless.test.ts +0 -119
- package/src/resources/stream/lazy-import.test.ts +0 -63
- package/src/resources/stream/render-ndjson.test.ts +0 -126
- package/src/resources/stream/render-plaintext.test.ts +0 -127
- package/src/resources/stream/snapshot.test.ts +0 -111
- package/src/resources/stream/submit.test.ts +0 -77
- package/src/resources/stream/workflow-event-view.test.ts +0 -116
- package/src/resources/stream/workflow-render.test.ts +0 -81
- package/src/resources/task-configs.test.ts +0 -98
- package/src/resources/usage.test.ts +0 -94
- package/src/resources/validate.test.ts +0 -79
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
import { mkdtempSync, readFileSync, statSync, utimesSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { tmpdir } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import { describe, expect, it } from "vitest";
|
|
5
|
-
import { type HealthState, loadHealthState, writeHealthState } from "./health-state.js";
|
|
6
|
-
import { acquireLock } from "./lock.js";
|
|
7
|
-
import { cleanupOldLogs, rotateLogs } from "./log-rotation.js";
|
|
8
|
-
import { readPidFile, removePidFile, writePidFile } from "./pidfile.js";
|
|
9
|
-
import { isOtherLiveProcess, isProcessAlive } from "./proc.js";
|
|
10
|
-
import { loadStartupConfig, removeStartupConfig, saveStartupConfig, type StartupConfig } from "./startup-config.js";
|
|
11
|
-
|
|
12
|
-
function tempDir(prefix: string): string {
|
|
13
|
-
return mkdtempSync(join(tmpdir(), prefix));
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
// A PID that is exceedingly unlikely to belong to a live process.
|
|
17
|
-
const DEAD_PID = 2 ** 31 - 1;
|
|
18
|
-
|
|
19
|
-
describe("pidfile", () => {
|
|
20
|
-
it("writes, reads, and removes a PID", () => {
|
|
21
|
-
const path = join(tempDir("stigmer-pid-"), "daemon.pid");
|
|
22
|
-
writePidFile(path, 4321);
|
|
23
|
-
expect(readPidFile(path)).toBe(4321);
|
|
24
|
-
removePidFile(path);
|
|
25
|
-
expect(readPidFile(path)).toBeNull();
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
it("returns null for a missing file", () => {
|
|
29
|
-
expect(readPidFile(join(tempDir("stigmer-pid-"), "absent.pid"))).toBeNull();
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it("reads only the first line of a multi-line (Temporal-style) PID file", () => {
|
|
33
|
-
const path = join(tempDir("stigmer-pid-"), "temporal.pid");
|
|
34
|
-
writeFileSync(path, "1234\ntemporal server start-dev\n2026-06-13T00:00:00Z\n");
|
|
35
|
-
expect(readPidFile(path)).toBe(1234);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it("returns null for a non-numeric first line", () => {
|
|
39
|
-
const path = join(tempDir("stigmer-pid-"), "bad.pid");
|
|
40
|
-
writeFileSync(path, "not-a-pid\n");
|
|
41
|
-
expect(readPidFile(path)).toBeNull();
|
|
42
|
-
});
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
describe("isProcessAlive", () => {
|
|
46
|
-
it("is true for the current process and false for a dead PID", () => {
|
|
47
|
-
expect(isProcessAlive(process.pid)).toBe(true);
|
|
48
|
-
expect(isProcessAlive(DEAD_PID)).toBe(false);
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
describe("isOtherLiveProcess", () => {
|
|
53
|
-
// A recorded PID equal to our own is a leftover from a previous life of this
|
|
54
|
-
// PID (a restarted container's fresh PID namespace, a laptop after reboot),
|
|
55
|
-
// never a live peer — the distinction every stale-state reader needs.
|
|
56
|
-
it("is false for the current process, true for its parent, false for a dead PID", () => {
|
|
57
|
-
expect(isOtherLiveProcess(process.pid)).toBe(false);
|
|
58
|
-
expect(isOtherLiveProcess(process.ppid)).toBe(true);
|
|
59
|
-
expect(isOtherLiveProcess(DEAD_PID)).toBe(false);
|
|
60
|
-
expect(isProcessAlive(0)).toBe(false);
|
|
61
|
-
expect(isProcessAlive(-1)).toBe(false);
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
describe("health-state", () => {
|
|
66
|
-
it("round-trips an atomic write/read", () => {
|
|
67
|
-
const path = join(tempDir("stigmer-health-"), "health-state.json");
|
|
68
|
-
const state: HealthState = {
|
|
69
|
-
daemon_pid: 100,
|
|
70
|
-
started_at: "2026-06-13T10:00:00.000Z",
|
|
71
|
-
components: {
|
|
72
|
-
"stigmer-server": { pid: 101, state: "running", started_at: "2026-06-13T10:00:01.000Z", restart_count: 0 },
|
|
73
|
-
runner: { pid: 102, state: "unhealthy", started_at: "2026-06-13T10:00:02.000Z", restart_count: 1, last_error: "boom" },
|
|
74
|
-
},
|
|
75
|
-
};
|
|
76
|
-
writeHealthState(path, state);
|
|
77
|
-
expect(loadHealthState(path)).toEqual(state);
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
it("returns null for a missing or corrupt file", () => {
|
|
81
|
-
const dir = tempDir("stigmer-health-");
|
|
82
|
-
expect(loadHealthState(join(dir, "absent.json"))).toBeNull();
|
|
83
|
-
const corrupt = join(dir, "corrupt.json");
|
|
84
|
-
writeFileSync(corrupt, "{not json");
|
|
85
|
-
expect(loadHealthState(corrupt)).toBeNull();
|
|
86
|
-
});
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
describe("startup-config", () => {
|
|
90
|
-
it("saves, loads, and removes", () => {
|
|
91
|
-
const dir = tempDir("stigmer-startup-");
|
|
92
|
-
const config: StartupConfig = {
|
|
93
|
-
data_dir: dir,
|
|
94
|
-
log_dir: join(dir, "logs"),
|
|
95
|
-
temporal_addr: "127.0.0.1:7233",
|
|
96
|
-
execution_mode: "local",
|
|
97
|
-
sandbox_image: "",
|
|
98
|
-
sandbox_auto_pull: false,
|
|
99
|
-
sandbox_cleanup: true,
|
|
100
|
-
sandbox_ttl: 0,
|
|
101
|
-
stigmer_server_pid: 999,
|
|
102
|
-
server_only: false,
|
|
103
|
-
};
|
|
104
|
-
saveStartupConfig(dir, config);
|
|
105
|
-
expect(loadStartupConfig(dir)).toEqual(config);
|
|
106
|
-
removeStartupConfig(dir);
|
|
107
|
-
expect(loadStartupConfig(dir)).toBeNull();
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it("loads files written by older CLIs carrying since-removed fields (e.g. the llm_* trio)", () => {
|
|
111
|
-
// The lenient-load contract oss#314 leans on: no migration for on-disk
|
|
112
|
-
// files — extra keys simply come along and nothing consumes them.
|
|
113
|
-
const dir = tempDir("stigmer-startup-");
|
|
114
|
-
const legacy = {
|
|
115
|
-
data_dir: dir,
|
|
116
|
-
log_dir: join(dir, "logs"),
|
|
117
|
-
temporal_addr: "127.0.0.1:7233",
|
|
118
|
-
llm_provider: "anthropic",
|
|
119
|
-
llm_model: "claude",
|
|
120
|
-
llm_base_url: "",
|
|
121
|
-
execution_mode: "local",
|
|
122
|
-
sandbox_image: "",
|
|
123
|
-
sandbox_auto_pull: false,
|
|
124
|
-
sandbox_cleanup: true,
|
|
125
|
-
sandbox_ttl: 0,
|
|
126
|
-
stigmer_server_pid: 999,
|
|
127
|
-
server_only: false,
|
|
128
|
-
};
|
|
129
|
-
writeFileSync(join(dir, "startup-config.json"), JSON.stringify(legacy));
|
|
130
|
-
expect(loadStartupConfig(dir)).toMatchObject({ temporal_addr: "127.0.0.1:7233", stigmer_server_pid: 999 });
|
|
131
|
-
});
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
describe("log-rotation", () => {
|
|
135
|
-
it("rotates non-empty logs and leaves empty ones in place", () => {
|
|
136
|
-
const dir = tempDir("stigmer-logs-");
|
|
137
|
-
writeFileSync(join(dir, "daemon.log"), "some output\n");
|
|
138
|
-
writeFileSync(join(dir, "runner.log"), ""); // empty — skipped
|
|
139
|
-
const now = new Date("2026-06-13T14:15:02");
|
|
140
|
-
|
|
141
|
-
const rotated = rotateLogs(dir, { now });
|
|
142
|
-
|
|
143
|
-
expect(rotated).toBe(1);
|
|
144
|
-
expect(() => statSync(join(dir, "daemon.log"))).toThrow(); // renamed away
|
|
145
|
-
expect(statSync(join(dir, "daemon.log.2026-06-13-141502")).size).toBeGreaterThan(0);
|
|
146
|
-
expect(statSync(join(dir, "runner.log")).size).toBe(0); // untouched
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
it("prunes archives older than the retention window but keeps recent ones", () => {
|
|
150
|
-
const dir = tempDir("stigmer-logs-");
|
|
151
|
-
const now = new Date("2026-06-13T00:00:00");
|
|
152
|
-
|
|
153
|
-
const old = join(dir, "daemon.log.2026-05-01-000000");
|
|
154
|
-
const recent = join(dir, "runner.err.2026-06-12-000000");
|
|
155
|
-
writeFileSync(old, "old");
|
|
156
|
-
writeFileSync(recent, "recent");
|
|
157
|
-
const eightDaysAgo = now.getTime() / 1000 - 8 * 86400;
|
|
158
|
-
utimesSync(old, eightDaysAgo, eightDaysAgo);
|
|
159
|
-
|
|
160
|
-
const deleted = cleanupOldLogs(dir, 7, now);
|
|
161
|
-
|
|
162
|
-
expect(deleted).toBe(1);
|
|
163
|
-
expect(() => statSync(old)).toThrow();
|
|
164
|
-
expect(statSync(recent).size).toBeGreaterThan(0);
|
|
165
|
-
});
|
|
166
|
-
});
|
|
167
|
-
|
|
168
|
-
describe("lock", () => {
|
|
169
|
-
it("grants the lock once and refuses a second live acquirer", () => {
|
|
170
|
-
const path = join(tempDir("stigmer-lock-"), "temporal.lock");
|
|
171
|
-
const first = acquireLock(path);
|
|
172
|
-
expect(first).not.toBeNull();
|
|
173
|
-
expect(readFileSync(path, "utf8").trim()).toBe(String(process.pid));
|
|
174
|
-
|
|
175
|
-
// A second acquire while we (a live process) hold it must fail.
|
|
176
|
-
expect(acquireLock(path)).toBeNull();
|
|
177
|
-
|
|
178
|
-
first?.release();
|
|
179
|
-
expect(acquireLock(path)).not.toBeNull();
|
|
180
|
-
});
|
|
181
|
-
|
|
182
|
-
it("reclaims a lock left behind by a dead process", () => {
|
|
183
|
-
const path = join(tempDir("stigmer-lock-"), "temporal.lock");
|
|
184
|
-
writeFileSync(path, `${DEAD_PID}\n`);
|
|
185
|
-
const lock = acquireLock(path);
|
|
186
|
-
expect(lock).not.toBeNull();
|
|
187
|
-
expect(readFileSync(path, "utf8").trim()).toBe(String(process.pid));
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
// The container case: after an unclean stop the lock file on the volume names
|
|
191
|
-
// the PID the daemon had last time — and a fresh PID namespace hands the
|
|
192
|
-
// restarted daemon that same PID. We are not holding a lock we are trying to
|
|
193
|
-
// acquire, so an owner equal to ourselves is stale by construction.
|
|
194
|
-
it("reclaims a lock whose recorded owner is this very process (a previous life of the PID)", () => {
|
|
195
|
-
const path = join(tempDir("stigmer-lock-"), "temporal.lock");
|
|
196
|
-
writeFileSync(path, `${process.pid}\n`);
|
|
197
|
-
const lock = acquireLock(path);
|
|
198
|
-
expect(lock).not.toBeNull();
|
|
199
|
-
lock?.release();
|
|
200
|
-
expect(acquireLock(path)).not.toBeNull();
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
it("release is idempotent and only removes our own lock", () => {
|
|
204
|
-
const path = join(tempDir("stigmer-lock-"), "temporal.lock");
|
|
205
|
-
const lock = acquireLock(path);
|
|
206
|
-
lock?.release();
|
|
207
|
-
lock?.release(); // no throw
|
|
208
|
-
expect(acquireLock(path)).not.toBeNull();
|
|
209
|
-
});
|
|
210
|
-
});
|
package/src/local/status.test.ts
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { mkdirSync, mkdtempSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { tmpdir } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
4
|
-
import { beforeEach, describe, expect, it } from "vitest";
|
|
5
|
-
import { configPath } from "../config/paths.js";
|
|
6
|
-
import { DAEMON_PID_FILE } from "./constants.js";
|
|
7
|
-
import { dataDir } from "./paths.js";
|
|
8
|
-
import type { HealthState } from "./state/health-state.js";
|
|
9
|
-
import { buildStatusResult, formatDuration } from "./status.js";
|
|
10
|
-
|
|
11
|
-
let home: string;
|
|
12
|
-
beforeEach(() => {
|
|
13
|
-
home = mkdtempSync(join(tmpdir(), "stigmer-status-"));
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
const open = async () => true;
|
|
17
|
-
const closed = async () => false;
|
|
18
|
-
|
|
19
|
-
function field(result: Awaited<ReturnType<typeof buildStatusResult>>, section: string, key: string): string | undefined {
|
|
20
|
-
return result.sections.find((s) => s.title === section)?.fields.find((f) => f.key === key)?.value;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function writeHealth(state: HealthState): void {
|
|
24
|
-
mkdirSync(dataDir(home), { recursive: true });
|
|
25
|
-
writeFileSync(join(dataDir(home), DAEMON_PID_FILE), String(process.pid));
|
|
26
|
-
writeFileSync(join(dataDir(home), "health-state.json"), JSON.stringify(state));
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
describe("buildStatusResult", () => {
|
|
30
|
-
it("reports not-running when no daemon and the port is closed", async () => {
|
|
31
|
-
const result = await buildStatusResult(home, closed);
|
|
32
|
-
expect(result.status).toBe("warning");
|
|
33
|
-
expect(result.message).toMatch(/not running/);
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
it("renders components in order, with runner readiness", async () => {
|
|
37
|
-
writeHealth({
|
|
38
|
-
daemon_pid: process.pid,
|
|
39
|
-
started_at: new Date().toISOString(),
|
|
40
|
-
components: {
|
|
41
|
-
temporal: { pid: 10, state: "running", restart_count: 0, started_at: new Date().toISOString() },
|
|
42
|
-
"stigmer-server": { pid: 11, state: "running", restart_count: 0, started_at: new Date().toISOString() },
|
|
43
|
-
runner: { pid: 12, state: "running", restart_count: 1, started_at: new Date().toISOString(), ready: true },
|
|
44
|
-
},
|
|
45
|
-
});
|
|
46
|
-
writeFileSync(configPath(home), "backend:\n type: local\n local:\n llm:\n provider: anthropic\n api_key: sk-x\n");
|
|
47
|
-
|
|
48
|
-
const result = await buildStatusResult(home, open);
|
|
49
|
-
expect(result.status).toBe("success");
|
|
50
|
-
|
|
51
|
-
const titles = result.sections.map((s) => s.title);
|
|
52
|
-
expect(titles.indexOf("Temporal")).toBeLessThan(titles.indexOf("Stigmer Server"));
|
|
53
|
-
expect(titles.indexOf("Stigmer Server")).toBeLessThan(titles.indexOf("Runner"));
|
|
54
|
-
|
|
55
|
-
expect(field(result, "Runner", "Status")).toBe("Running ✓ (polling)");
|
|
56
|
-
expect(field(result, "Runner", "Restarts")).toBe("1");
|
|
57
|
-
expect(field(result, "LLM Configuration", "Provider")).toBe("Anthropic (Cloud)");
|
|
58
|
-
// No model configured: the platform model registry owns the execution
|
|
59
|
-
// default, and status says so instead of asserting a version.
|
|
60
|
-
expect(field(result, "LLM Configuration", "Model")).toBe("Auto (platform default)");
|
|
61
|
-
expect(field(result, "LLM Configuration", "API Key")).toBe("Configured ✓");
|
|
62
|
-
expect(field(result, "Web UI", "Temporal")).toBe("http://localhost:8233");
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it("ignores a stale model key from a pre-oss#314 config — the pin never reached execution, so status must not display it", async () => {
|
|
66
|
-
writeHealth({ daemon_pid: process.pid, started_at: new Date().toISOString(), components: {} });
|
|
67
|
-
writeFileSync(configPath(home), "backend:\n type: local\n local:\n llm:\n provider: anthropic\n model: claude-x\n api_key: sk-x\n");
|
|
68
|
-
|
|
69
|
-
const result = await buildStatusResult(home, open);
|
|
70
|
-
expect(field(result, "LLM Configuration", "Model")).toBe("Auto (platform default)");
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
it("reports a non-anthropic provider as unknown — local execution is Anthropic-only", async () => {
|
|
74
|
-
writeHealth({ daemon_pid: process.pid, started_at: new Date().toISOString(), components: {} });
|
|
75
|
-
writeFileSync(configPath(home), "backend:\n type: local\n local:\n llm:\n provider: ollama\n");
|
|
76
|
-
|
|
77
|
-
const result = await buildStatusResult(home, open);
|
|
78
|
-
expect(field(result, "LLM Configuration", "Provider")).toBe("Unknown (ollama)");
|
|
79
|
-
expect(field(result, "LLM Configuration", "Status")).toBe("Agents will not execute");
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
it("shows runner as starting before the readiness marker", async () => {
|
|
83
|
-
writeHealth({
|
|
84
|
-
daemon_pid: process.pid,
|
|
85
|
-
started_at: new Date().toISOString(),
|
|
86
|
-
components: {
|
|
87
|
-
runner: { pid: 12, state: "running", restart_count: 0, started_at: new Date().toISOString(), ready: false },
|
|
88
|
-
},
|
|
89
|
-
});
|
|
90
|
-
const result = await buildStatusResult(home, open);
|
|
91
|
-
expect(field(result, "Runner", "Status")).toBe("Running ✓ (starting)");
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
it("synthesizes a running server when only the port answers", async () => {
|
|
95
|
-
const result = await buildStatusResult(home, open);
|
|
96
|
-
expect(result.status).toBe("success");
|
|
97
|
-
expect(field(result, "Stigmer Server", "Status")).toBe("Running ✓");
|
|
98
|
-
});
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
describe("formatDuration", () => {
|
|
102
|
-
it("renders coarse human durations", () => {
|
|
103
|
-
expect(formatDuration(5_000)).toBe("5s");
|
|
104
|
-
expect(formatDuration(125_000)).toBe("2m 5s");
|
|
105
|
-
expect(formatDuration(3_700_000)).toBe("1h 1m");
|
|
106
|
-
expect(formatDuration(90_000_000)).toBe("1d 1h");
|
|
107
|
-
});
|
|
108
|
-
});
|
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
// The Temporal CLI download end to end over a scripted `fetch`: asset naming,
|
|
2
|
-
// verification against the release's checksums.txt, extraction, and the retry
|
|
3
|
-
// contract `../artifact.ts` gives every release download. The retry cases pin
|
|
4
|
-
// which failures are transient (a dropped connection before or during the body,
|
|
5
|
-
// a 5xx, a 429) and which are answers (a 404, a bad digest), the backoff, and
|
|
6
|
-
// the error a persistent failure ends in. A recording `sleep` keeps them instant.
|
|
7
|
-
|
|
8
|
-
import { createHash } from "node:crypto";
|
|
9
|
-
import { existsSync, mkdtempSync, readFileSync } from "node:fs";
|
|
10
|
-
import { tmpdir } from "node:os";
|
|
11
|
-
import { join } from "node:path";
|
|
12
|
-
import { gzipSync } from "fflate";
|
|
13
|
-
import { describe, expect, it } from "vitest";
|
|
14
|
-
import { CliExitError } from "../../errors/cli-exit-error.js";
|
|
15
|
-
import {
|
|
16
|
-
TEMPORAL_CHECKSUMS_FILE,
|
|
17
|
-
downloadTemporalCli,
|
|
18
|
-
extractTarEntry,
|
|
19
|
-
temporalArchiveName,
|
|
20
|
-
temporalReleaseAssetUrl,
|
|
21
|
-
} from "./download.js";
|
|
22
|
-
|
|
23
|
-
// Build a minimal ustar archive containing a single regular-file entry. Only
|
|
24
|
-
// the fields the reader uses (name, octal size, type flag) are populated.
|
|
25
|
-
function makeTar(name: string, content: Buffer): Buffer {
|
|
26
|
-
const header = Buffer.alloc(512);
|
|
27
|
-
header.write(name, 0, "utf8");
|
|
28
|
-
header.write(content.length.toString(8).padStart(11, "0"), 124, "ascii");
|
|
29
|
-
header.write("0", 156, "ascii");
|
|
30
|
-
const data = Buffer.alloc(Math.ceil(content.length / 512) * 512);
|
|
31
|
-
content.copy(data);
|
|
32
|
-
const trailer = Buffer.alloc(1024); // two zero blocks end the archive
|
|
33
|
-
return Buffer.concat([header, data, trailer]);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
describe("extractTarEntry", () => {
|
|
37
|
-
it("extracts a named regular file", () => {
|
|
38
|
-
const payload = Buffer.from("#!/bin/sh\necho temporal\n");
|
|
39
|
-
const tar = makeTar("temporal", payload);
|
|
40
|
-
const out = extractTarEntry(new Uint8Array(tar), "temporal");
|
|
41
|
-
expect(out).not.toBeNull();
|
|
42
|
-
expect(Buffer.from(out!).toString("utf8")).toBe(payload.toString("utf8"));
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it("matches by basename for nested entries", () => {
|
|
46
|
-
const payload = Buffer.from("binary-bytes");
|
|
47
|
-
const tar = makeTar("temporal_cli/temporal", payload);
|
|
48
|
-
const out = extractTarEntry(new Uint8Array(tar), "temporal");
|
|
49
|
-
expect(Buffer.from(out!).toString("utf8")).toBe("binary-bytes");
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it("returns null when the entry is absent", () => {
|
|
53
|
-
const tar = makeTar("something-else", Buffer.from("x"));
|
|
54
|
-
expect(extractTarEntry(new Uint8Array(tar), "temporal")).toBeNull();
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
// A release as GitHub serves it: the archive for the requested platform plus a
|
|
59
|
-
// release-wide checksums.txt listing every asset. `fetchImpl` routes by URL so
|
|
60
|
-
// the checksum arm is exercised against a realistic multi-line file.
|
|
61
|
-
function release(version: string, archives: Record<string, Buffer>, checksums: string): typeof fetch {
|
|
62
|
-
return (async (input: string | URL | Request) => {
|
|
63
|
-
const url = String(input);
|
|
64
|
-
const name = url.slice(url.lastIndexOf("/") + 1);
|
|
65
|
-
if (name === TEMPORAL_CHECKSUMS_FILE) {
|
|
66
|
-
return { ok: true, status: 200, text: async () => checksums } as unknown as Response;
|
|
67
|
-
}
|
|
68
|
-
const gz = archives[name];
|
|
69
|
-
if (gz === undefined) return { ok: false, status: 404, arrayBuffer: async () => new ArrayBuffer(0) } as unknown as Response;
|
|
70
|
-
return {
|
|
71
|
-
ok: true,
|
|
72
|
-
status: 200,
|
|
73
|
-
arrayBuffer: async () => gz.buffer.slice(gz.byteOffset, gz.byteOffset + gz.byteLength),
|
|
74
|
-
} as unknown as Response;
|
|
75
|
-
}) as unknown as typeof fetch;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function archiveFor(payload: Buffer): Buffer {
|
|
79
|
-
return Buffer.from(gzipSync(new Uint8Array(makeTar("temporal", payload))));
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function sha256(bytes: Buffer): string {
|
|
83
|
-
return createHash("sha256").update(bytes).digest("hex");
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
describe("downloadTemporalCli", () => {
|
|
87
|
-
const linuxArm = temporalArchiveName("1.5.1", "linux", "arm64");
|
|
88
|
-
const linuxAmd = temporalArchiveName("1.5.1", "linux", "x64");
|
|
89
|
-
|
|
90
|
-
it("names the release assets the way Temporal publishes them", () => {
|
|
91
|
-
expect(linuxArm).toBe("temporal_cli_1.5.1_linux_arm64.tar.gz");
|
|
92
|
-
expect(linuxAmd).toBe("temporal_cli_1.5.1_linux_amd64.tar.gz");
|
|
93
|
-
expect(temporalArchiveName("1.5.1", "darwin", "arm64")).toBe("temporal_cli_1.5.1_darwin_arm64.tar.gz");
|
|
94
|
-
expect(temporalReleaseAssetUrl("1.5.1", TEMPORAL_CHECKSUMS_FILE)).toBe(
|
|
95
|
-
"https://github.com/temporalio/cli/releases/download/v1.5.1/checksums.txt",
|
|
96
|
-
);
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
it("downloads, verifies against the matching checksums.txt line, gunzips, untars, and writes the binary", async () => {
|
|
100
|
-
const arm = archiveFor(Buffer.from("the-arm64-binary"));
|
|
101
|
-
const amd = archiveFor(Buffer.from("the-amd64-binary"));
|
|
102
|
-
// amd64 listed FIRST: a first-token parser would verify arm64 against it.
|
|
103
|
-
const checksums = `${sha256(amd)} ${linuxAmd}\n${sha256(arm)} ${linuxArm}\n`;
|
|
104
|
-
const fetchImpl = release("1.5.1", { [linuxArm]: arm, [linuxAmd]: amd }, checksums);
|
|
105
|
-
|
|
106
|
-
const binPath = join(mkdtempSync(join(tmpdir(), "stigmer-temporal-")), "bin", "temporal");
|
|
107
|
-
await downloadTemporalCli({ version: "1.5.1", binPath, platform: "linux", arch: "arm64", fetchImpl });
|
|
108
|
-
|
|
109
|
-
expect(readFileSync(binPath, "utf8")).toBe("the-arm64-binary");
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it("refuses an archive whose digest does not match its checksums.txt line", async () => {
|
|
113
|
-
const arm = archiveFor(Buffer.from("tampered"));
|
|
114
|
-
const checksums = `${"0".repeat(64)} ${linuxArm}\n`;
|
|
115
|
-
const fetchImpl = release("1.5.1", { [linuxArm]: arm }, checksums);
|
|
116
|
-
|
|
117
|
-
const binPath = join(mkdtempSync(join(tmpdir(), "stigmer-temporal-")), "temporal");
|
|
118
|
-
await expect(
|
|
119
|
-
downloadTemporalCli({ version: "1.5.1", binPath, platform: "linux", arch: "arm64", fetchImpl }),
|
|
120
|
-
).rejects.toThrow(/checksum mismatch/);
|
|
121
|
-
expect(existsSync(binPath)).toBe(false);
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it("refuses an archive the checksums.txt has no entry for", async () => {
|
|
125
|
-
const arm = archiveFor(Buffer.from("unlisted"));
|
|
126
|
-
const checksums = `${sha256(arm)} some_other_asset.tar.gz\n`;
|
|
127
|
-
const fetchImpl = release("1.5.1", { [linuxArm]: arm }, checksums);
|
|
128
|
-
|
|
129
|
-
const binPath = join(mkdtempSync(join(tmpdir(), "stigmer-temporal-")), "temporal");
|
|
130
|
-
await expect(
|
|
131
|
-
downloadTemporalCli({ version: "1.5.1", binPath, platform: "linux", arch: "arm64", fetchImpl }),
|
|
132
|
-
).rejects.toThrow(/checksum mismatch/);
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
it("fails clearly on a non-OK response", async () => {
|
|
136
|
-
const fetchImpl = release("9.9.9", {}, "");
|
|
137
|
-
const binPath = join(mkdtempSync(join(tmpdir(), "stigmer-temporal-")), "temporal");
|
|
138
|
-
await expect(downloadTemporalCli({ version: "9.9.9", binPath, fetchImpl })).rejects.toThrow(/HTTP 404/);
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
type Failure = "reject" | "body" | number;
|
|
143
|
-
|
|
144
|
-
// Wraps a release so requests for one asset fail as scripted before the real
|
|
145
|
-
// release answers: each entry of `failures` is consumed by one request for
|
|
146
|
-
// `asset`. "reject" is a connection that never answers (Node's fetch rejects
|
|
147
|
-
// with the socket error as `cause`), "body" one that drops after the headers,
|
|
148
|
-
// a number an HTTP status. `calls` counts the requests for `asset`.
|
|
149
|
-
function flaky(inner: typeof fetch, asset: string, failures: Failure[]): { fetchImpl: typeof fetch; calls: () => number } {
|
|
150
|
-
let calls = 0;
|
|
151
|
-
const fetchImpl = (async (input: string | URL | Request) => {
|
|
152
|
-
const url = String(input);
|
|
153
|
-
if (!url.endsWith(`/${asset}`)) return inner(input);
|
|
154
|
-
calls += 1;
|
|
155
|
-
const failure = failures[calls - 1];
|
|
156
|
-
if (failure === "reject") throw new TypeError("fetch failed", { cause: new Error("read ECONNRESET") });
|
|
157
|
-
if (failure === "body") {
|
|
158
|
-
return {
|
|
159
|
-
ok: true,
|
|
160
|
-
status: 200,
|
|
161
|
-
arrayBuffer: async () => {
|
|
162
|
-
throw new TypeError("terminated", { cause: new Error("other side closed") });
|
|
163
|
-
},
|
|
164
|
-
} as unknown as Response;
|
|
165
|
-
}
|
|
166
|
-
if (typeof failure === "number") {
|
|
167
|
-
return { ok: false, status: failure, arrayBuffer: async () => new ArrayBuffer(0) } as unknown as Response;
|
|
168
|
-
}
|
|
169
|
-
return inner(input);
|
|
170
|
-
}) as unknown as typeof fetch;
|
|
171
|
-
return { fetchImpl, calls: () => calls };
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
describe("downloadTemporalCli over an unreliable network", () => {
|
|
175
|
-
const linuxArm = temporalArchiveName("1.5.1", "linux", "arm64");
|
|
176
|
-
const arm = archiveFor(Buffer.from("the-arm64-binary"));
|
|
177
|
-
const good = release("1.5.1", { [linuxArm]: arm }, `${sha256(arm)} ${linuxArm}\n`);
|
|
178
|
-
|
|
179
|
-
function install(fetchImpl: typeof fetch): { binPath: string; delays: number[]; run: Promise<void> } {
|
|
180
|
-
const binPath = join(mkdtempSync(join(tmpdir(), "stigmer-temporal-")), "temporal");
|
|
181
|
-
const delays: number[] = [];
|
|
182
|
-
const sleep = async (ms: number): Promise<void> => {
|
|
183
|
-
delays.push(ms);
|
|
184
|
-
};
|
|
185
|
-
const run = downloadTemporalCli({ version: "1.5.1", binPath, platform: "linux", arch: "arm64", fetchImpl, sleep });
|
|
186
|
-
return { binPath, delays, run };
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
it("retries a connection that never answers, then installs the verified binary", async () => {
|
|
190
|
-
const net = flaky(good, linuxArm, ["reject"]);
|
|
191
|
-
const { binPath, delays, run } = install(net.fetchImpl);
|
|
192
|
-
await run;
|
|
193
|
-
expect(readFileSync(binPath, "utf8")).toBe("the-arm64-binary");
|
|
194
|
-
expect(net.calls()).toBe(2);
|
|
195
|
-
expect(delays).toEqual([1000]);
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
it("retries a connection that drops after the headers", async () => {
|
|
199
|
-
const net = flaky(good, linuxArm, ["body"]);
|
|
200
|
-
const { binPath, run } = install(net.fetchImpl);
|
|
201
|
-
await run;
|
|
202
|
-
expect(readFileSync(binPath, "utf8")).toBe("the-arm64-binary");
|
|
203
|
-
expect(net.calls()).toBe(2);
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
it("retries a 5xx and a 429, doubling the wait", async () => {
|
|
207
|
-
const net = flaky(good, linuxArm, [503, 429]);
|
|
208
|
-
const { binPath, delays, run } = install(net.fetchImpl);
|
|
209
|
-
await run;
|
|
210
|
-
expect(readFileSync(binPath, "utf8")).toBe("the-arm64-binary");
|
|
211
|
-
expect(net.calls()).toBe(3);
|
|
212
|
-
expect(delays).toEqual([1000, 2000]);
|
|
213
|
-
});
|
|
214
|
-
|
|
215
|
-
it("retries the checksums.txt fetch the same way", async () => {
|
|
216
|
-
const net = flaky(good, TEMPORAL_CHECKSUMS_FILE, ["reject"]);
|
|
217
|
-
const { binPath, run } = install(net.fetchImpl);
|
|
218
|
-
await run;
|
|
219
|
-
expect(readFileSync(binPath, "utf8")).toBe("the-arm64-binary");
|
|
220
|
-
expect(net.calls()).toBe(2);
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
it("takes a 404 as the answer and does not retry it", async () => {
|
|
224
|
-
const net = flaky(good, linuxArm, [404]);
|
|
225
|
-
const { delays, run } = install(net.fetchImpl);
|
|
226
|
-
await expect(run).rejects.toThrow(/HTTP 404/);
|
|
227
|
-
expect(net.calls()).toBe(1);
|
|
228
|
-
expect(delays).toEqual([]);
|
|
229
|
-
});
|
|
230
|
-
|
|
231
|
-
it("gives up after four attempts, saying what failed and what to do", async () => {
|
|
232
|
-
const net = flaky(good, linuxArm, ["reject", "reject", "reject", "reject"]);
|
|
233
|
-
const { binPath, delays, run } = install(net.fetchImpl);
|
|
234
|
-
const err: unknown = await run.then(
|
|
235
|
-
() => undefined,
|
|
236
|
-
(e: unknown) => e,
|
|
237
|
-
);
|
|
238
|
-
expect(err).toBeInstanceOf(CliExitError);
|
|
239
|
-
const exit = err as CliExitError;
|
|
240
|
-
expect(exit.message).toBe(
|
|
241
|
-
`failed to download Temporal CLI from ${temporalReleaseAssetUrl("1.5.1", linuxArm)} after 4 attempts: fetch failed: read ECONNRESET`,
|
|
242
|
-
);
|
|
243
|
-
expect(exit.hints).toEqual(["check the network connection, then run the command again"]);
|
|
244
|
-
expect(net.calls()).toBe(4);
|
|
245
|
-
expect(delays).toEqual([1000, 2000, 4000]);
|
|
246
|
-
expect(existsSync(binPath)).toBe(false);
|
|
247
|
-
});
|
|
248
|
-
});
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
// Pins the process-identity reader: the kernel's /proc answer comes first, `ps`
|
|
2
|
-
// is the fallback, and neither's absence is mistaken for "not Temporal" when the
|
|
3
|
-
// other can answer. The /proc arm is what keeps a minimal container (no `ps`)
|
|
4
|
-
// from restarting a healthy Temporal every supervisor tick.
|
|
5
|
-
|
|
6
|
-
import { mkdirSync, mkdtempSync, writeFileSync } from "node:fs";
|
|
7
|
-
import { tmpdir } from "node:os";
|
|
8
|
-
import { join } from "node:path";
|
|
9
|
-
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
10
|
-
import { isLikelyTemporal, processCommandLine } from "./inspect.js";
|
|
11
|
-
|
|
12
|
-
function procFixture(entries: Record<number, string[] | "">): string {
|
|
13
|
-
const root = mkdtempSync(join(tmpdir(), "stigmer-proc-"));
|
|
14
|
-
for (const [pid, argv] of Object.entries(entries)) {
|
|
15
|
-
mkdirSync(join(root, pid));
|
|
16
|
-
// /proc/<pid>/cmdline: argv joined by NUL, NUL-terminated; empty for a zombie.
|
|
17
|
-
writeFileSync(join(root, pid, "cmdline"), argv === "" ? "" : `${argv.join("\0")}\0`);
|
|
18
|
-
}
|
|
19
|
-
return root;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// Hide `ps` so the fallback cannot answer; tests that need it restore PATH.
|
|
23
|
-
let savedPath: string | undefined;
|
|
24
|
-
beforeEach(() => {
|
|
25
|
-
savedPath = process.env.PATH;
|
|
26
|
-
});
|
|
27
|
-
afterEach(() => {
|
|
28
|
-
if (savedPath === undefined) delete process.env.PATH;
|
|
29
|
-
else process.env.PATH = savedPath;
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
describe("processCommandLine", () => {
|
|
33
|
-
it("reads argv from <procRoot>/<pid>/cmdline, joining the NUL-separated arguments", () => {
|
|
34
|
-
const root = procFixture({ 42: ["/opt/stigmer/bin/temporal", "server", "start-dev", "--port", "7233"] });
|
|
35
|
-
process.env.PATH = "";
|
|
36
|
-
expect(processCommandLine(42, { procRoot: root })).toBe("/opt/stigmer/bin/temporal server start-dev --port 7233");
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
it("falls back to ps when the pid has no cmdline entry", () => {
|
|
40
|
-
const root = procFixture({});
|
|
41
|
-
// Our own process is the one PID whose command line `ps` can always report.
|
|
42
|
-
const line = processCommandLine(process.pid, { procRoot: root });
|
|
43
|
-
expect(line).not.toBeNull();
|
|
44
|
-
expect(line).toMatch(/node|vitest/);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
it("treats an empty cmdline (a zombie) as unreadable and falls back to ps", () => {
|
|
48
|
-
const root = procFixture({ [process.pid]: "" });
|
|
49
|
-
expect(processCommandLine(process.pid, { procRoot: root })).toMatch(/node|vitest/);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
it("returns null when neither /proc nor ps can answer", () => {
|
|
53
|
-
process.env.PATH = "";
|
|
54
|
-
expect(processCommandLine(process.pid, { procRoot: null })).toBeNull();
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
describe("isLikelyTemporal", () => {
|
|
59
|
-
it("recognises the managed dev server by its binary path", () => {
|
|
60
|
-
const root = procFixture({ 7: ["/home/u/.stigmer/bin/temporal", "server", "start-dev"] });
|
|
61
|
-
process.env.PATH = "";
|
|
62
|
-
expect(isLikelyTemporal(7, "/home/u/.stigmer/bin/temporal", { procRoot: root })).toBe(true);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it("recognises a temporal server started from another path by its subcommand", () => {
|
|
66
|
-
const root = procFixture({ 8: ["/usr/local/bin/temporal", "server", "start-dev"] });
|
|
67
|
-
process.env.PATH = "";
|
|
68
|
-
expect(isLikelyTemporal(8, "/elsewhere/temporal", { procRoot: root })).toBe(true);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
it("rejects an unrelated process that reused the pid", () => {
|
|
72
|
-
const root = procFixture({ 9: ["/usr/bin/node", "/app/main.js"] });
|
|
73
|
-
process.env.PATH = "";
|
|
74
|
-
expect(isLikelyTemporal(9, "/home/u/.stigmer/bin/temporal", { procRoot: root })).toBe(false);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
// The defect the /proc arm fixes: with `ps` gone and no /proc reader, a live
|
|
78
|
-
// Temporal read as "not Temporal" and the supervisor restarted it forever.
|
|
79
|
-
it("is false, not an exception, when no reader can answer", () => {
|
|
80
|
-
process.env.PATH = "";
|
|
81
|
-
expect(isLikelyTemporal(process.pid, "/x/temporal", { procRoot: null })).toBe(false);
|
|
82
|
-
});
|
|
83
|
-
});
|