-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdeploy_stub.go
More file actions
165 lines (151 loc) · 5.57 KB
/
Copy pathdeploy_stub.go
File metadata and controls
165 lines (151 loc) · 5.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
package cmd
// deploy_stub.go — B15-P2 (T9): scope-gap stubs for the missing
// `instant deploy …` surface.
//
// The platform exposes POST /deploy/new (multipart tarball upload + Kaniko
// build) plus GET/DELETE/redeploy/logs sibling endpoints. None of those
// have a CLI binding today — the binary is ~30% of the platform surface
// (BugBash B15 finding), forcing agents to fall back to curl or MCP.
//
// Implementing the full multipart upload + tarball assembly + SSE log
// stream is out of scope for this PR (it requires a multipart client + a
// tar walker the CLI doesn't have yet). What we CAN ship — and what's
// strictly better than the prior "Did you mean: login" — is a clear
// "use this instead" stub on every documented verb:
//
// instant deploy → list-pointer (MCP / dashboard / curl)
// instant deploy new → pointer + the curl invocation
// instant deploy logs → pointer + the curl invocation
// instant deploy redeploy → pointer
// instant deploy delete → pointer
//
// Exit code 1 (ExitGeneric) is returned so an agent script's
// `if ! instant deploy new …` branch fires — silently exiting 0 would
// strand the agent thinking the deploy succeeded.
//
// When the CLI grows real deploy support, every stub here becomes an
// implementation with the same Use/Args shape — no breakage for scripts
// that grep --help today.
import (
"fmt"
"strings"
"github.com/spf13/cobra"
)
var deployCmd = &cobra.Command{
Use: "deploy",
Short: "Deploy an application (CLI surface coming; use MCP or curl today)",
Long: `Deploy commands are not implemented in the CLI yet.
The platform exposes the full deploy API at:
POST /deploy/new (multipart tarball upload + build)
GET /api/v1/deployments
GET /api/v1/deployments/:id
POST /deploy/:id/redeploy
DELETE /deploy/:id
GET /deploy/:id/logs (SSE stream)
Use one of these surfaces today:
1. MCP tools (Claude Code, Cursor, etc.):
create_deploy, list_deployments, get_deployment, redeploy,
delete_deployment
2. Dashboard:
https://instanode.dev/app/deployments
3. curl, with a tarball ready:
curl -X POST https://api.instanode.dev/deploy/new \
-H "Authorization: Bearer $INSTANT_TOKEN" \
-F "name=my-app" \
-F "env=production" \
-F "tarball=@./app.tar.gz"
Track the upcoming native CLI support at:
https://github.com/InstaNode-dev/cli/issues
`,
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
// Print the long help (covers the alternative-surface pointers)
// and exit non-zero so scripts that test exit code don't proceed
// as if a deploy happened.
_ = cmd.Help()
return withExitCode(ExitGeneric,
fmt.Errorf("`instant deploy` is not yet implemented — use MCP, dashboard, or curl (see help text above)"))
},
}
// newDeployStub returns a sub-sub-command that points at the canonical
// alternative for `instant deploy <verb>`. Helps agents that ran
// `instant deploy logs <id>` (and got "Did you mean: login") find the
// real path without checking docs.
func newDeployStub(verb, extra string) *cobra.Command {
short := "Deploy " + verb + " (not yet implemented — use MCP or curl)"
return &cobra.Command{
Use: verb,
Short: short,
Args: cobra.ArbitraryArgs,
RunE: func(cmd *cobra.Command, args []string) error {
_, _ = fmt.Fprintf(cmd.ErrOrStderr(),
"`instant deploy %s` is not yet implemented in the CLI.\n"+
"Use one of:\n"+
" - MCP tool (Claude Code / Cursor: %s)\n"+
" - dashboard (https://instanode.dev/app/deployments)\n"+
" - curl (%s)\n",
verb, mcpAliasFor(verb), curlHintFor(verb, args, extra))
return withExitCode(ExitGeneric,
fmt.Errorf("instant deploy %s: not implemented", verb))
},
}
}
// mcpAliasFor returns the MCP tool name for a given deploy verb so agents
// reading the stub error know exactly which tool to call. Keeping the
// mapping inline (rather than fetching from MCP) keeps this file
// dependency-free.
func mcpAliasFor(verb string) string {
switch verb {
case "new":
return "create_deploy"
case "list":
return "list_deployments"
case "get":
return "get_deployment"
case "logs":
return "get_deployment"
case "redeploy":
return "redeploy"
case "delete":
return "delete_deployment"
}
return "<deploy MCP tools>"
}
// curlHintFor renders a minimal curl invocation for the given deploy verb
// so an agent can copy-paste from the error and proceed.
func curlHintFor(verb string, args []string, _ string) string {
id := "<deploy-id>"
if len(args) > 0 && args[0] != "" {
id = args[0]
}
base := "https://api.instanode.dev"
auth := `-H "Authorization: Bearer $INSTANT_TOKEN"`
switch verb {
case "new":
return fmt.Sprintf(
"curl -X POST %s/deploy/new %s -F name=NAME -F env=production -F tarball=@./app.tar.gz",
base, auth)
case "list":
return fmt.Sprintf("curl %s/api/v1/deployments %s", base, auth)
case "get":
return fmt.Sprintf("curl %s/api/v1/deployments/%s %s", base, id, auth)
case "logs":
return fmt.Sprintf("curl -N %s/deploy/%s/logs %s", base, id, auth)
case "redeploy":
return fmt.Sprintf("curl -X POST %s/deploy/%s/redeploy %s", base, id, auth)
case "delete":
return fmt.Sprintf("curl -X DELETE %s/deploy/%s %s", base, id, auth)
}
return strings.TrimSpace(fmt.Sprintf("curl %s/deploy/... %s", base, auth))
}
func init() {
deployCmd.AddCommand(
newDeployStub("new", ""),
newDeployStub("list", ""),
newDeployStub("get", ""),
newDeployStub("logs", ""),
newDeployStub("redeploy", ""),
newDeployStub("delete", ""),
)
rootCmd.AddCommand(deployCmd)
}