@tarout/cli 0.7.2 → 0.10.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/dist/{api-QVUO7EWV.js → api-YFXACHOB.js} +2 -2
- package/dist/{chunk-Y6TWR3XZ.js → chunk-CZPJYUNC.js} +1 -1
- package/dist/{chunk-DI66W4S5.js → chunk-OPPZGNJX.js} +1 -1
- package/dist/{chunk-K7JK5HIL.js → chunk-WKITMZ4U.js} +6 -0
- package/dist/index.js +426 -138
- package/dist/{prompts-JH6YBHHV.js → prompts-D72VJYWE.js} +2 -2
- package/package.json +1 -1
|
@@ -2,9 +2,9 @@ import {
|
|
|
2
2
|
createApiClient,
|
|
3
3
|
getApiClient,
|
|
4
4
|
resetApiClient
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-CZPJYUNC.js";
|
|
6
6
|
import "./chunk-5DAFGMBH.js";
|
|
7
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-WKITMZ4U.js";
|
|
8
8
|
export {
|
|
9
9
|
createApiClient,
|
|
10
10
|
getApiClient,
|
|
@@ -106,6 +106,11 @@ function success(message) {
|
|
|
106
106
|
console.log(colors.success(`\u2713 ${message}`));
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
|
+
function warn(message) {
|
|
110
|
+
if (!globalOptions.json) {
|
|
111
|
+
console.log(colors.warn(`\u26A0 ${message}`));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
109
114
|
function error(message, suggestions) {
|
|
110
115
|
if (globalOptions.json) {
|
|
111
116
|
outputJson(jsonError("ERROR", message, suggestions));
|
|
@@ -197,6 +202,7 @@ export {
|
|
|
197
202
|
getStatusBadge,
|
|
198
203
|
log,
|
|
199
204
|
success,
|
|
205
|
+
warn,
|
|
200
206
|
error,
|
|
201
207
|
table,
|
|
202
208
|
outputData,
|
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
handleError,
|
|
14
14
|
platformFetch,
|
|
15
15
|
resetApiClient
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-CZPJYUNC.js";
|
|
17
17
|
import {
|
|
18
18
|
clearConfig,
|
|
19
19
|
getApiUrl,
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
password,
|
|
35
35
|
promptOrEmit,
|
|
36
36
|
select
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-OPPZGNJX.js";
|
|
38
38
|
import {
|
|
39
39
|
ExitCode,
|
|
40
40
|
box,
|
|
@@ -52,8 +52,9 @@ import {
|
|
|
52
52
|
setGlobalOptions,
|
|
53
53
|
shouldSkipConfirmation,
|
|
54
54
|
success,
|
|
55
|
-
table
|
|
56
|
-
|
|
55
|
+
table,
|
|
56
|
+
warn
|
|
57
|
+
} from "./chunk-WKITMZ4U.js";
|
|
57
58
|
|
|
58
59
|
// src/index.ts
|
|
59
60
|
import { Command } from "commander";
|
|
@@ -61,7 +62,7 @@ import { Command } from "commander";
|
|
|
61
62
|
// package.json
|
|
62
63
|
var package_default = {
|
|
63
64
|
name: "@tarout/cli",
|
|
64
|
-
version: "0.
|
|
65
|
+
version: "0.10.0",
|
|
65
66
|
description: "Tarout CLI \u2014 the Saudi cloud platform for coding agents",
|
|
66
67
|
type: "module",
|
|
67
68
|
bin: {
|
|
@@ -632,7 +633,7 @@ Root access: ${hasAccess ? colors.success("yes") : colors.error("no")}
|
|
|
632
633
|
try {
|
|
633
634
|
if (!isLoggedIn()) throw new AuthError();
|
|
634
635
|
if (!shouldSkipConfirmation()) {
|
|
635
|
-
const { confirm: confirmFn } = await import("./prompts-
|
|
636
|
+
const { confirm: confirmFn } = await import("./prompts-D72VJYWE.js");
|
|
636
637
|
const ok = await confirmFn(
|
|
637
638
|
`Remove user "${userId}" from the organization?`,
|
|
638
639
|
false,
|
|
@@ -659,7 +660,7 @@ Root access: ${hasAccess ? colors.success("yes") : colors.error("no")}
|
|
|
659
660
|
account.command("assign-permissions").argument("<user-id>", "User ID").option("--role <role>", "Role: admin, member").description("Assign permissions/role to a member (org owner only)").action(async (userId, options) => {
|
|
660
661
|
try {
|
|
661
662
|
if (!isLoggedIn()) throw new AuthError();
|
|
662
|
-
const { select: selectFn } = await import("./prompts-
|
|
663
|
+
const { select: selectFn } = await import("./prompts-D72VJYWE.js");
|
|
663
664
|
const role = options.role || await selectFn(
|
|
664
665
|
"Role:",
|
|
665
666
|
[
|
|
@@ -724,6 +725,205 @@ Root access: ${hasAccess ? colors.success("yes") : colors.error("no")}
|
|
|
724
725
|
});
|
|
725
726
|
}
|
|
726
727
|
|
|
728
|
+
// src/commands/agent.ts
|
|
729
|
+
import { resolve } from "path";
|
|
730
|
+
|
|
731
|
+
// src/lib/agent-scaffold.ts
|
|
732
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
|
|
733
|
+
import { join } from "path";
|
|
734
|
+
var AGENT_TYPES = [
|
|
735
|
+
"claude",
|
|
736
|
+
"codex",
|
|
737
|
+
"cursor",
|
|
738
|
+
"other"
|
|
739
|
+
];
|
|
740
|
+
var TAROUT_ALLOW_ENTRY = "Bash(tarout:*)";
|
|
741
|
+
var BLOCK_BEGIN = "<!-- BEGIN TAROUT -->";
|
|
742
|
+
var BLOCK_END = "<!-- END TAROUT -->";
|
|
743
|
+
var TAROUT_AGENT_BLOCK = `${BLOCK_BEGIN}
|
|
744
|
+
## Tarout
|
|
745
|
+
|
|
746
|
+
This project deploys to [Tarout](https://tarout.sa) (PaaS). Use the **Tarout CLI**
|
|
747
|
+
for all deployment, database, storage, environment-variable, and domain operations \u2014
|
|
748
|
+
don't hand-edit infrastructure.
|
|
749
|
+
|
|
750
|
+
- **Deploy** the current folder: \`tarout up --json --yes\` (inspects \u2192 builds \u2192 deploys;
|
|
751
|
+
read the final JSON envelope's \`success\` and \`data.url\`).
|
|
752
|
+
- **Re-deploy** a linked app: \`tarout deploy --wait\`.
|
|
753
|
+
- **Run locally** with cloud env vars: \`tarout dev\`.
|
|
754
|
+
- **Full agent guide:** https://tarout.sa/docs/for-ai/onboarding
|
|
755
|
+
|
|
756
|
+
Run Tarout commands with \`--json\` for machine-readable output. On a \`NEEDS_UPGRADE\`
|
|
757
|
+
error, surface it to the user and follow the upgrade flow instead of auto-retrying.
|
|
758
|
+
Ask before destructive actions (delete, rollback, revealing secrets).
|
|
759
|
+
${BLOCK_END}`;
|
|
760
|
+
function markdownTargetFor(agent) {
|
|
761
|
+
return agent === "claude" ? "CLAUDE.md" : "AGENTS.md";
|
|
762
|
+
}
|
|
763
|
+
function hasMarkers(content) {
|
|
764
|
+
return content.includes(BLOCK_BEGIN) && content.includes(BLOCK_END);
|
|
765
|
+
}
|
|
766
|
+
function replaceBlock(content, block) {
|
|
767
|
+
const begin = content.indexOf(BLOCK_BEGIN);
|
|
768
|
+
const end = content.indexOf(BLOCK_END);
|
|
769
|
+
if (begin === -1 || end === -1 || end < begin) return content;
|
|
770
|
+
return `${content.slice(0, begin)}${block}${content.slice(end + BLOCK_END.length)}`;
|
|
771
|
+
}
|
|
772
|
+
function upsertMarkdownBlock(filePath, block) {
|
|
773
|
+
if (!existsSync(filePath)) {
|
|
774
|
+
writeFileSync(filePath, `${block}
|
|
775
|
+
`, "utf-8");
|
|
776
|
+
return "created";
|
|
777
|
+
}
|
|
778
|
+
const existing = readFileSync(filePath, "utf-8");
|
|
779
|
+
if (hasMarkers(existing)) {
|
|
780
|
+
const replaced = replaceBlock(existing, block);
|
|
781
|
+
if (replaced === existing) return "unchanged";
|
|
782
|
+
writeFileSync(filePath, replaced, "utf-8");
|
|
783
|
+
return "updated";
|
|
784
|
+
}
|
|
785
|
+
const separator = existing.endsWith("\n") ? "\n" : "\n\n";
|
|
786
|
+
writeFileSync(filePath, `${existing}${separator}${block}
|
|
787
|
+
`, "utf-8");
|
|
788
|
+
return "appended";
|
|
789
|
+
}
|
|
790
|
+
function hasTaroutAllowlist(cwd) {
|
|
791
|
+
const settingsPath = join(cwd, ".claude", "settings.local.json");
|
|
792
|
+
if (!existsSync(settingsPath)) return false;
|
|
793
|
+
try {
|
|
794
|
+
const settings = JSON.parse(
|
|
795
|
+
readFileSync(settingsPath, "utf-8")
|
|
796
|
+
);
|
|
797
|
+
const allow = settings?.permissions?.allow;
|
|
798
|
+
return Array.isArray(allow) && allow.includes(TAROUT_ALLOW_ENTRY);
|
|
799
|
+
} catch {
|
|
800
|
+
return false;
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
function mergeClaudeSettings(claudeDir) {
|
|
804
|
+
const settingsPath = join(claudeDir, "settings.local.json");
|
|
805
|
+
const relPath = join(".claude", "settings.local.json");
|
|
806
|
+
if (!existsSync(settingsPath)) {
|
|
807
|
+
mkdirSync(claudeDir, { recursive: true });
|
|
808
|
+
const settings2 = {
|
|
809
|
+
permissions: { allow: [TAROUT_ALLOW_ENTRY] }
|
|
810
|
+
};
|
|
811
|
+
writeFileSync(settingsPath, `${JSON.stringify(settings2, null, 2)}
|
|
812
|
+
`, "utf-8");
|
|
813
|
+
return { path: relPath, action: "created" };
|
|
814
|
+
}
|
|
815
|
+
let settings;
|
|
816
|
+
try {
|
|
817
|
+
settings = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
818
|
+
} catch {
|
|
819
|
+
return {
|
|
820
|
+
path: relPath,
|
|
821
|
+
action: "skipped",
|
|
822
|
+
reason: "existing settings.local.json is not valid JSON; left untouched"
|
|
823
|
+
};
|
|
824
|
+
}
|
|
825
|
+
if (typeof settings !== "object" || settings === null) {
|
|
826
|
+
return {
|
|
827
|
+
path: relPath,
|
|
828
|
+
action: "skipped",
|
|
829
|
+
reason: "existing settings.local.json is not a JSON object; left untouched"
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
const permissions = settings.permissions ??= {};
|
|
833
|
+
const allow = Array.isArray(permissions.allow) ? permissions.allow : [];
|
|
834
|
+
if (allow.includes(TAROUT_ALLOW_ENTRY)) {
|
|
835
|
+
return { path: relPath, action: "unchanged" };
|
|
836
|
+
}
|
|
837
|
+
permissions.allow = [...allow, TAROUT_ALLOW_ENTRY];
|
|
838
|
+
writeFileSync(settingsPath, `${JSON.stringify(settings, null, 2)}
|
|
839
|
+
`, "utf-8");
|
|
840
|
+
return { path: relPath, action: "updated" };
|
|
841
|
+
}
|
|
842
|
+
function scaffoldAgentConfig(options) {
|
|
843
|
+
const { cwd, agent } = options;
|
|
844
|
+
const files = [];
|
|
845
|
+
const mdName = markdownTargetFor(agent);
|
|
846
|
+
files.push({
|
|
847
|
+
path: mdName,
|
|
848
|
+
action: upsertMarkdownBlock(join(cwd, mdName), TAROUT_AGENT_BLOCK)
|
|
849
|
+
});
|
|
850
|
+
if (agent === "claude") {
|
|
851
|
+
files.push(mergeClaudeSettings(join(cwd, ".claude")));
|
|
852
|
+
}
|
|
853
|
+
return {
|
|
854
|
+
agent,
|
|
855
|
+
files,
|
|
856
|
+
nextSteps: ["tarout up --json --yes"]
|
|
857
|
+
};
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
// src/commands/agent.ts
|
|
861
|
+
function parseAgent(value) {
|
|
862
|
+
const agent = (value ?? "claude").toLowerCase();
|
|
863
|
+
if (AGENT_TYPES.includes(agent)) {
|
|
864
|
+
return agent;
|
|
865
|
+
}
|
|
866
|
+
throw new CliError(
|
|
867
|
+
`Invalid agent "${value}". Use one of: ${AGENT_TYPES.join(", ")}.`,
|
|
868
|
+
ExitCode.INVALID_ARGUMENTS
|
|
869
|
+
);
|
|
870
|
+
}
|
|
871
|
+
function registerAgentCommands(program2) {
|
|
872
|
+
const agent = program2.command("agent").description("Configure coding agents to use the Tarout CLI");
|
|
873
|
+
agent.command("init").argument("[path]", "Project directory (defaults to current)").description(
|
|
874
|
+
"Write agent instructions (CLAUDE.md/AGENTS.md) and a Bash(tarout:*) permission allowlist so a coding agent can drive Tarout"
|
|
875
|
+
).option(
|
|
876
|
+
"--agent <type>",
|
|
877
|
+
`Coding agent to configure: ${AGENT_TYPES.join(", ")}`,
|
|
878
|
+
"claude"
|
|
879
|
+
).action(async (cwdArg, options) => {
|
|
880
|
+
try {
|
|
881
|
+
const cwd = cwdArg ? resolve(cwdArg) : process.cwd();
|
|
882
|
+
const agentType = parseAgent(options.agent);
|
|
883
|
+
const result = scaffoldAgentConfig({ cwd, agent: agentType });
|
|
884
|
+
if (isJsonMode()) {
|
|
885
|
+
for (const file of result.files) {
|
|
886
|
+
outputJsonLine({
|
|
887
|
+
type: "event",
|
|
888
|
+
event: "file_written",
|
|
889
|
+
path: file.path,
|
|
890
|
+
action: file.action,
|
|
891
|
+
...file.reason ? { reason: file.reason } : {}
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
outputJsonLine({
|
|
895
|
+
type: "result",
|
|
896
|
+
ok: true,
|
|
897
|
+
agent: result.agent,
|
|
898
|
+
files: result.files,
|
|
899
|
+
nextSteps: result.nextSteps
|
|
900
|
+
});
|
|
901
|
+
return;
|
|
902
|
+
}
|
|
903
|
+
success("Coding agents configured");
|
|
904
|
+
box(
|
|
905
|
+
`Agent: ${colors.cyan(result.agent)}`,
|
|
906
|
+
result.files.map((file) => {
|
|
907
|
+
const label = `${colors.bold(file.action)} ${file.path}`;
|
|
908
|
+
return file.reason ? `${label} \u2014 ${colors.dim(file.reason)}` : label;
|
|
909
|
+
})
|
|
910
|
+
);
|
|
911
|
+
for (const file of result.files) {
|
|
912
|
+
if (file.action === "skipped") {
|
|
913
|
+
warn(`${file.path} was left untouched (${file.reason}).`);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
log("Next steps:");
|
|
917
|
+
for (const step of result.nextSteps) {
|
|
918
|
+
log(` ${colors.dim(step)}`);
|
|
919
|
+
}
|
|
920
|
+
log("");
|
|
921
|
+
} catch (err) {
|
|
922
|
+
handleError(err);
|
|
923
|
+
}
|
|
924
|
+
});
|
|
925
|
+
}
|
|
926
|
+
|
|
727
927
|
// src/commands/ai.ts
|
|
728
928
|
function registerAiCommands(program2) {
|
|
729
929
|
const ai = program2.command("ai").description("Manage AI Gateway models and API keys");
|
|
@@ -1544,7 +1744,7 @@ function registerAppsCommands(program2) {
|
|
|
1544
1744
|
throw new NotFoundError("Application", appIdentifier, suggestions);
|
|
1545
1745
|
}
|
|
1546
1746
|
if (!shouldSkipConfirmation()) {
|
|
1547
|
-
const { confirm: confirm2 } = await import("./prompts-
|
|
1747
|
+
const { confirm: confirm2 } = await import("./prompts-D72VJYWE.js");
|
|
1548
1748
|
const confirmed = await confirm2(
|
|
1549
1749
|
`Stop application "${app.name}"?`,
|
|
1550
1750
|
false,
|
|
@@ -1862,7 +2062,7 @@ function registerAppsCommands(program2) {
|
|
|
1862
2062
|
throw new NotFoundError("Application", appIdentifier);
|
|
1863
2063
|
}
|
|
1864
2064
|
if (!shouldSkipConfirmation()) {
|
|
1865
|
-
const { confirm: confirm2 } = await import("./prompts-
|
|
2065
|
+
const { confirm: confirm2 } = await import("./prompts-D72VJYWE.js");
|
|
1866
2066
|
const confirmed = await confirm2(
|
|
1867
2067
|
`Disconnect source provider from "${app.name}"?`,
|
|
1868
2068
|
false,
|
|
@@ -2880,7 +3080,7 @@ function formatTime(ts) {
|
|
|
2880
3080
|
}
|
|
2881
3081
|
|
|
2882
3082
|
// src/commands/auth.ts
|
|
2883
|
-
import
|
|
3083
|
+
import open3 from "open";
|
|
2884
3084
|
|
|
2885
3085
|
// src/lib/auth-server.ts
|
|
2886
3086
|
import { randomBytes, timingSafeEqual } from "crypto";
|
|
@@ -2898,7 +3098,7 @@ function escapeHtml(value) {
|
|
|
2898
3098
|
return String(value).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
2899
3099
|
}
|
|
2900
3100
|
function startAuthServer(options = {}) {
|
|
2901
|
-
return new Promise((
|
|
3101
|
+
return new Promise((resolve4) => {
|
|
2902
3102
|
const app = express();
|
|
2903
3103
|
const expectedState = options.state ?? createAuthState();
|
|
2904
3104
|
let server;
|
|
@@ -3022,7 +3222,7 @@ function startAuthServer(options = {}) {
|
|
|
3022
3222
|
server = app.listen(0, "127.0.0.1", () => {
|
|
3023
3223
|
const address = server.address();
|
|
3024
3224
|
const port = typeof address === "object" && address ? address.port : 0;
|
|
3025
|
-
|
|
3225
|
+
resolve4({
|
|
3026
3226
|
port,
|
|
3027
3227
|
state: expectedState,
|
|
3028
3228
|
waitForCallback: () => callbackPromise,
|
|
@@ -3032,6 +3232,28 @@ function startAuthServer(options = {}) {
|
|
|
3032
3232
|
});
|
|
3033
3233
|
}
|
|
3034
3234
|
|
|
3235
|
+
// src/lib/browser.ts
|
|
3236
|
+
import open2 from "open";
|
|
3237
|
+
function canLaunchBrowser() {
|
|
3238
|
+
if (process.platform === "darwin" || process.platform === "win32") {
|
|
3239
|
+
return true;
|
|
3240
|
+
}
|
|
3241
|
+
return Boolean(process.env.DISPLAY || process.env.WAYLAND_DISPLAY);
|
|
3242
|
+
}
|
|
3243
|
+
function paymentBrowserOpener(opts) {
|
|
3244
|
+
if (opts?.noOpen || !canLaunchBrowser()) return void 0;
|
|
3245
|
+
return async (url) => {
|
|
3246
|
+
try {
|
|
3247
|
+
await open2(url);
|
|
3248
|
+
} catch {
|
|
3249
|
+
}
|
|
3250
|
+
};
|
|
3251
|
+
}
|
|
3252
|
+
function shouldAutoConfirmPaidCheckout(amountDueHalalas) {
|
|
3253
|
+
const isPaidCheckout = typeof amountDueHalalas === "number" && amountDueHalalas > 0;
|
|
3254
|
+
return !isJsonMode() && isNonInteractiveMode() && canLaunchBrowser() && isPaidCheckout;
|
|
3255
|
+
}
|
|
3256
|
+
|
|
3035
3257
|
// src/commands/auth.ts
|
|
3036
3258
|
function refuseBrowserAuthForAgent(action) {
|
|
3037
3259
|
const message = `tarout ${action} requires a browser. Agents should ask the user to run \`tarout token <api-token>\` or set TAROUT_TOKEN \u2014 generate one at https://tarout.sa/dashboard/settings/profile.`;
|
|
@@ -3070,7 +3292,7 @@ function registerAuthCommands(program2) {
|
|
|
3070
3292
|
return;
|
|
3071
3293
|
}
|
|
3072
3294
|
}
|
|
3073
|
-
if (isJsonMode() ||
|
|
3295
|
+
if (isJsonMode() || !canLaunchBrowser()) {
|
|
3074
3296
|
refuseBrowserAuthForAgent("login");
|
|
3075
3297
|
}
|
|
3076
3298
|
const apiUrl = options.apiUrl;
|
|
@@ -3079,7 +3301,12 @@ function registerAuthCommands(program2) {
|
|
|
3079
3301
|
const authServer = await startAuthServer();
|
|
3080
3302
|
const callbackUrl = `http://localhost:${authServer.port}/callback?state=${encodeURIComponent(authServer.state)}`;
|
|
3081
3303
|
const authUrl = `${apiUrl}/cli-authorize?callback=${encodeURIComponent(callbackUrl)}`;
|
|
3082
|
-
|
|
3304
|
+
try {
|
|
3305
|
+
await open3(authUrl);
|
|
3306
|
+
} catch {
|
|
3307
|
+
authServer.close();
|
|
3308
|
+
refuseBrowserAuthForAgent("login");
|
|
3309
|
+
}
|
|
3083
3310
|
const _spinner = startSpinner("Waiting for authentication...");
|
|
3084
3311
|
try {
|
|
3085
3312
|
const authData = await authServer.waitForCallback();
|
|
@@ -3179,7 +3406,7 @@ function registerAuthCommands(program2) {
|
|
|
3179
3406
|
return;
|
|
3180
3407
|
}
|
|
3181
3408
|
}
|
|
3182
|
-
if (isJsonMode() ||
|
|
3409
|
+
if (isJsonMode() || !canLaunchBrowser()) {
|
|
3183
3410
|
refuseBrowserAuthForAgent("register");
|
|
3184
3411
|
}
|
|
3185
3412
|
const apiUrl = options.apiUrl;
|
|
@@ -3188,7 +3415,12 @@ function registerAuthCommands(program2) {
|
|
|
3188
3415
|
const authServer = await startAuthServer();
|
|
3189
3416
|
const callbackUrl = `http://localhost:${authServer.port}/callback?state=${encodeURIComponent(authServer.state)}`;
|
|
3190
3417
|
const authUrl = `${apiUrl}/cli-authorize?action=register&callback=${encodeURIComponent(callbackUrl)}`;
|
|
3191
|
-
|
|
3418
|
+
try {
|
|
3419
|
+
await open3(authUrl);
|
|
3420
|
+
} catch {
|
|
3421
|
+
authServer.close();
|
|
3422
|
+
refuseBrowserAuthForAgent("register");
|
|
3423
|
+
}
|
|
3192
3424
|
const _spinner = startSpinner("Waiting for account creation...");
|
|
3193
3425
|
try {
|
|
3194
3426
|
const authData = await authServer.waitForCallback();
|
|
@@ -3303,7 +3535,7 @@ function registerAuthCommands(program2) {
|
|
|
3303
3535
|
() => input("Token name (e.g., ci-deploy):")
|
|
3304
3536
|
);
|
|
3305
3537
|
}
|
|
3306
|
-
const { getApiClient: getApiClient2 } = await import("./api-
|
|
3538
|
+
const { getApiClient: getApiClient2 } = await import("./api-YFXACHOB.js");
|
|
3307
3539
|
const client = getApiClient2();
|
|
3308
3540
|
const profile = getCurrentProfile();
|
|
3309
3541
|
let keyOrg = profile?.organizationId;
|
|
@@ -3680,7 +3912,7 @@ function registerBackupsCommands(program2) {
|
|
|
3680
3912
|
try {
|
|
3681
3913
|
if (!isLoggedIn()) throw new AuthError();
|
|
3682
3914
|
if (!shouldSkipConfirmation()) {
|
|
3683
|
-
const { confirm: confirmFn } = await import("./prompts-
|
|
3915
|
+
const { confirm: confirmFn } = await import("./prompts-D72VJYWE.js");
|
|
3684
3916
|
const ok = await confirmFn(
|
|
3685
3917
|
`Restore backup file "${backupFile}"? This will overwrite current data.`,
|
|
3686
3918
|
false
|
|
@@ -3729,9 +3961,9 @@ function formatBytes2(bytes) {
|
|
|
3729
3961
|
|
|
3730
3962
|
// src/commands/billing.ts
|
|
3731
3963
|
import { InvalidArgumentError as InvalidArgumentError2 } from "commander";
|
|
3732
|
-
import open3 from "open";
|
|
3733
3964
|
|
|
3734
3965
|
// src/lib/billing-upgrade.ts
|
|
3966
|
+
var AGENT_BILLING_PERMISSION_HINT = `If your agent's permission system blocks this billing command, ask the user to allowlist Tarout billing once so you can run it directly (Claude Code: add "Bash(tarout billing:*)" to .claude/settings.json). Running an upgrade only opens the hosted payment page \u2014 the user still completes payment in the browser.`;
|
|
3735
3967
|
function resolveTarget(input2) {
|
|
3736
3968
|
if (input2.kind === "plan") return input2.planKey ?? "";
|
|
3737
3969
|
if (input2.kind === "addon") {
|
|
@@ -3797,6 +4029,13 @@ async function finalizeBillingMutation(client, result, ctx) {
|
|
|
3797
4029
|
}
|
|
3798
4030
|
const orderId = result.orderId;
|
|
3799
4031
|
const paymentUrl = result.paymentUrl;
|
|
4032
|
+
if (ctx.wait) ctx.onCheckoutOpened?.({ orderId, paymentUrl });
|
|
4033
|
+
if (ctx.openBrowser) {
|
|
4034
|
+
try {
|
|
4035
|
+
await ctx.openBrowser(paymentUrl);
|
|
4036
|
+
} catch {
|
|
4037
|
+
}
|
|
4038
|
+
}
|
|
3800
4039
|
if (!ctx.wait) {
|
|
3801
4040
|
return {
|
|
3802
4041
|
status: "payment_required",
|
|
@@ -3807,13 +4046,6 @@ async function finalizeBillingMutation(client, result, ctx) {
|
|
|
3807
4046
|
amountHalalas
|
|
3808
4047
|
};
|
|
3809
4048
|
}
|
|
3810
|
-
ctx.onCheckoutOpened?.({ orderId, paymentUrl });
|
|
3811
|
-
if (ctx.openBrowser) {
|
|
3812
|
-
try {
|
|
3813
|
-
await ctx.openBrowser(paymentUrl);
|
|
3814
|
-
} catch {
|
|
3815
|
-
}
|
|
3816
|
-
}
|
|
3817
4049
|
const final = await pollCheckoutUntilTerminal(client, orderId, {
|
|
3818
4050
|
timeoutMs: ctx.timeoutMs ?? 6e5,
|
|
3819
4051
|
intervalMs: 4e3
|
|
@@ -3994,12 +4226,6 @@ function reportBillingResult(result, label) {
|
|
|
3994
4226
|
const code = emitBillingResult(result, { label });
|
|
3995
4227
|
if (code !== ExitCode.SUCCESS) exit(code);
|
|
3996
4228
|
}
|
|
3997
|
-
function browserOpener(noOpen) {
|
|
3998
|
-
if (isJsonMode() || noOpen) return void 0;
|
|
3999
|
-
return async (url) => {
|
|
4000
|
-
await open3(url);
|
|
4001
|
-
};
|
|
4002
|
-
}
|
|
4003
4229
|
function isConflictError(err) {
|
|
4004
4230
|
const e = err;
|
|
4005
4231
|
return (e?.code ?? e?.data?.code) === "CONFLICT";
|
|
@@ -4205,24 +4431,30 @@ function registerBillingCommands(program2) {
|
|
|
4205
4431
|
);
|
|
4206
4432
|
}
|
|
4207
4433
|
log("");
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4434
|
+
if (shouldAutoConfirmPaidCheckout(amountDueHalalas)) {
|
|
4435
|
+
log(
|
|
4436
|
+
"Opening the secure payment page in your browser to complete the upgrade..."
|
|
4437
|
+
);
|
|
4438
|
+
} else {
|
|
4439
|
+
const confirmed = await confirm(
|
|
4440
|
+
`Switch to plan "${targetPlan}"?`,
|
|
4441
|
+
false,
|
|
4442
|
+
{
|
|
4443
|
+
field: "confirm_upgrade",
|
|
4444
|
+
flag: "--yes",
|
|
4445
|
+
context: {
|
|
4446
|
+
plan: targetPlan,
|
|
4447
|
+
quantity: planQuantity,
|
|
4448
|
+
billingPeriod,
|
|
4449
|
+
addons,
|
|
4450
|
+
amountDueHalalas
|
|
4451
|
+
}
|
|
4220
4452
|
}
|
|
4453
|
+
);
|
|
4454
|
+
if (!confirmed) {
|
|
4455
|
+
log("Cancelled.");
|
|
4456
|
+
return;
|
|
4221
4457
|
}
|
|
4222
|
-
);
|
|
4223
|
-
if (!confirmed) {
|
|
4224
|
-
log("Cancelled.");
|
|
4225
|
-
return;
|
|
4226
4458
|
}
|
|
4227
4459
|
}
|
|
4228
4460
|
const _changeSpinner = startSpinner("Changing plan...");
|
|
@@ -4234,7 +4466,7 @@ function registerBillingCommands(program2) {
|
|
|
4234
4466
|
addons,
|
|
4235
4467
|
wait: options.wait,
|
|
4236
4468
|
timeoutMs: options.timeout * 1e3,
|
|
4237
|
-
openBrowser:
|
|
4469
|
+
openBrowser: paymentBrowserOpener({ noOpen: options.open === false }),
|
|
4238
4470
|
onCheckoutOpened: ({ orderId, paymentUrl }) => {
|
|
4239
4471
|
if (isJsonMode()) {
|
|
4240
4472
|
outputJsonLine({
|
|
@@ -4438,7 +4670,7 @@ function registerBillingCommands(program2) {
|
|
|
4438
4670
|
target: addonKey,
|
|
4439
4671
|
wait: options.wait,
|
|
4440
4672
|
timeoutMs: options.timeout * 1e3,
|
|
4441
|
-
openBrowser:
|
|
4673
|
+
openBrowser: paymentBrowserOpener({ noOpen: options.open === false })
|
|
4442
4674
|
});
|
|
4443
4675
|
reportBillingResult(result, `Addon: ${addonKey} \xD7${quantity}`);
|
|
4444
4676
|
} catch (err) {
|
|
@@ -4492,7 +4724,7 @@ function registerBillingCommands(program2) {
|
|
|
4492
4724
|
quantity,
|
|
4493
4725
|
wait: options.wait,
|
|
4494
4726
|
timeoutMs: options.timeout * 1e3,
|
|
4495
|
-
openBrowser:
|
|
4727
|
+
openBrowser: paymentBrowserOpener({ noOpen: options.open === false })
|
|
4496
4728
|
});
|
|
4497
4729
|
succeedSpinner("Plan quantity processed.");
|
|
4498
4730
|
reportBillingResult(result, `Plan quantity: ${quantity}`);
|
|
@@ -4581,7 +4813,7 @@ Purchase ${quantity}\xD7 ${colors.cyan(addonKey)}?`);
|
|
|
4581
4813
|
quantity,
|
|
4582
4814
|
wait: options.wait,
|
|
4583
4815
|
timeoutMs: options.timeout * 1e3,
|
|
4584
|
-
openBrowser:
|
|
4816
|
+
openBrowser: paymentBrowserOpener({ noOpen: options.open === false })
|
|
4585
4817
|
});
|
|
4586
4818
|
succeedSpinner("Addon purchase processed.");
|
|
4587
4819
|
reportBillingResult(result, `Addon: ${addonKey} \xD7${quantity}`);
|
|
@@ -4863,16 +5095,16 @@ function formatDate4(date) {
|
|
|
4863
5095
|
|
|
4864
5096
|
// src/lib/process.ts
|
|
4865
5097
|
import { spawn } from "child_process";
|
|
4866
|
-
import { existsSync, readFileSync } from "fs";
|
|
4867
|
-
import { join } from "path";
|
|
5098
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
5099
|
+
import { join as join2 } from "path";
|
|
4868
5100
|
function readPackageJson(basePath) {
|
|
4869
5101
|
const base = basePath || process.cwd();
|
|
4870
|
-
const packagePath =
|
|
4871
|
-
if (!
|
|
5102
|
+
const packagePath = join2(base, "package.json");
|
|
5103
|
+
if (!existsSync2(packagePath)) {
|
|
4872
5104
|
return null;
|
|
4873
5105
|
}
|
|
4874
5106
|
try {
|
|
4875
|
-
const content =
|
|
5107
|
+
const content = readFileSync2(packagePath, "utf-8");
|
|
4876
5108
|
return JSON.parse(content);
|
|
4877
5109
|
} catch {
|
|
4878
5110
|
return null;
|
|
@@ -4880,16 +5112,16 @@ function readPackageJson(basePath) {
|
|
|
4880
5112
|
}
|
|
4881
5113
|
function detectPackageManager(basePath) {
|
|
4882
5114
|
const base = basePath || process.cwd();
|
|
4883
|
-
if (
|
|
5115
|
+
if (existsSync2(join2(base, "bun.lockb")) || existsSync2(join2(base, "bun.lock"))) {
|
|
4884
5116
|
return "bun";
|
|
4885
5117
|
}
|
|
4886
|
-
if (
|
|
5118
|
+
if (existsSync2(join2(base, "pnpm-lock.yaml"))) {
|
|
4887
5119
|
return "pnpm";
|
|
4888
5120
|
}
|
|
4889
|
-
if (
|
|
5121
|
+
if (existsSync2(join2(base, "yarn.lock"))) {
|
|
4890
5122
|
return "yarn";
|
|
4891
5123
|
}
|
|
4892
|
-
if (
|
|
5124
|
+
if (existsSync2(join2(base, "package-lock.json"))) {
|
|
4893
5125
|
return "npm";
|
|
4894
5126
|
}
|
|
4895
5127
|
const pkg = readPackageJson(basePath);
|
|
@@ -5044,7 +5276,7 @@ function getDefaultPort(pkg) {
|
|
|
5044
5276
|
return framework?.defaultPort || 3e3;
|
|
5045
5277
|
}
|
|
5046
5278
|
function runCommand(command, env, options = {}) {
|
|
5047
|
-
return new Promise((
|
|
5279
|
+
return new Promise((resolve4) => {
|
|
5048
5280
|
const [cmd, ...args] = parseCommand(command);
|
|
5049
5281
|
const spawnOptions = {
|
|
5050
5282
|
cwd: options.cwd || process.cwd(),
|
|
@@ -5079,7 +5311,7 @@ function runCommand(command, env, options = {}) {
|
|
|
5079
5311
|
child.on("close", (code, signal) => {
|
|
5080
5312
|
process.off("SIGINT", handleSignal);
|
|
5081
5313
|
process.off("SIGTERM", handleSignal);
|
|
5082
|
-
|
|
5314
|
+
resolve4({
|
|
5083
5315
|
exitCode: code ?? 1,
|
|
5084
5316
|
signal
|
|
5085
5317
|
});
|
|
@@ -5088,7 +5320,7 @@ function runCommand(command, env, options = {}) {
|
|
|
5088
5320
|
process.off("SIGINT", handleSignal);
|
|
5089
5321
|
process.off("SIGTERM", handleSignal);
|
|
5090
5322
|
console.error(`Failed to start process: ${err.message}`);
|
|
5091
|
-
|
|
5323
|
+
resolve4({
|
|
5092
5324
|
exitCode: 1,
|
|
5093
5325
|
signal: null
|
|
5094
5326
|
});
|
|
@@ -5277,32 +5509,32 @@ function findApp2(apps, identifier) {
|
|
|
5277
5509
|
}
|
|
5278
5510
|
|
|
5279
5511
|
// src/commands/call.ts
|
|
5280
|
-
import { existsSync as
|
|
5512
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
5281
5513
|
import { homedir } from "os";
|
|
5282
|
-
import { join as
|
|
5514
|
+
import { join as join3 } from "path";
|
|
5283
5515
|
var MANIFEST_TTL_MS = 5 * 60 * 1e3;
|
|
5284
5516
|
function manifestCachePath() {
|
|
5285
|
-
return
|
|
5517
|
+
return join3(homedir(), ".tarout", "surface-manifest-cache.json");
|
|
5286
5518
|
}
|
|
5287
5519
|
async function fetchManifestFresh(client, apiUrl) {
|
|
5288
5520
|
const manifest = await client.settings.getSurfaceManifest.query();
|
|
5289
5521
|
try {
|
|
5290
|
-
const dir =
|
|
5291
|
-
if (!
|
|
5522
|
+
const dir = join3(homedir(), ".tarout");
|
|
5523
|
+
if (!existsSync3(dir)) mkdirSync2(dir, { recursive: true });
|
|
5292
5524
|
let cache = {};
|
|
5293
5525
|
try {
|
|
5294
|
-
cache = JSON.parse(
|
|
5526
|
+
cache = JSON.parse(readFileSync3(manifestCachePath(), "utf8"));
|
|
5295
5527
|
} catch {
|
|
5296
5528
|
}
|
|
5297
5529
|
cache[apiUrl] = { at: Date.now(), manifest };
|
|
5298
|
-
|
|
5530
|
+
writeFileSync2(manifestCachePath(), JSON.stringify(cache), { mode: 384 });
|
|
5299
5531
|
} catch {
|
|
5300
5532
|
}
|
|
5301
5533
|
return manifest;
|
|
5302
5534
|
}
|
|
5303
5535
|
async function loadManifest(client, apiUrl) {
|
|
5304
5536
|
try {
|
|
5305
|
-
const cache = JSON.parse(
|
|
5537
|
+
const cache = JSON.parse(readFileSync3(manifestCachePath(), "utf8"));
|
|
5306
5538
|
const entry = cache[apiUrl];
|
|
5307
5539
|
if (entry && Date.now() - entry.at < MANIFEST_TTL_MS && Array.isArray(entry.manifest)) {
|
|
5308
5540
|
return entry.manifest;
|
|
@@ -5362,7 +5594,7 @@ function registerCallCommand(program2) {
|
|
|
5362
5594
|
);
|
|
5363
5595
|
}
|
|
5364
5596
|
let input2 = {};
|
|
5365
|
-
const rawInput = opts.inputFile ?
|
|
5597
|
+
const rawInput = opts.inputFile ? readFileSync3(opts.inputFile, "utf8") : opts.input;
|
|
5366
5598
|
if (rawInput && rawInput.trim()) {
|
|
5367
5599
|
try {
|
|
5368
5600
|
input2 = JSON.parse(rawInput);
|
|
@@ -5493,18 +5725,51 @@ import { spawn as spawn2 } from "child_process";
|
|
|
5493
5725
|
import { execFile } from "child_process";
|
|
5494
5726
|
import {
|
|
5495
5727
|
createReadStream,
|
|
5496
|
-
existsSync as
|
|
5728
|
+
existsSync as existsSync4,
|
|
5497
5729
|
mkdtempSync,
|
|
5498
5730
|
readdirSync,
|
|
5499
|
-
readFileSync as
|
|
5731
|
+
readFileSync as readFileSync4,
|
|
5500
5732
|
rmSync,
|
|
5501
5733
|
statSync
|
|
5502
5734
|
} from "fs";
|
|
5503
5735
|
import { tmpdir } from "os";
|
|
5504
|
-
import { basename, dirname, join as
|
|
5736
|
+
import { basename, dirname, join as join4 } from "path";
|
|
5505
5737
|
import { promisify } from "util";
|
|
5506
5738
|
import open4 from "open";
|
|
5507
5739
|
|
|
5740
|
+
// src/lib/agent-setup.ts
|
|
5741
|
+
var SETUP_HINT = "Run `tarout agent init` to allowlist Bash(tarout:*) so tarout commands run without per-command approval prompts.";
|
|
5742
|
+
function isAgentDriven() {
|
|
5743
|
+
return isJsonMode() || isNonInteractiveMode();
|
|
5744
|
+
}
|
|
5745
|
+
function ensureAgentSetup(cwd, disabled = false) {
|
|
5746
|
+
if (disabled || !isAgentDriven() || hasTaroutAllowlist(cwd)) return;
|
|
5747
|
+
const result = scaffoldAgentConfig({ cwd, agent: "claude" });
|
|
5748
|
+
if (isJsonMode()) {
|
|
5749
|
+
outputJsonLine({
|
|
5750
|
+
type: "event",
|
|
5751
|
+
event: "agent_setup_done",
|
|
5752
|
+
files: result.files
|
|
5753
|
+
});
|
|
5754
|
+
} else {
|
|
5755
|
+
for (const file of result.files) {
|
|
5756
|
+
log(colors.dim(` agent setup: ${file.action} ${file.path}`));
|
|
5757
|
+
}
|
|
5758
|
+
}
|
|
5759
|
+
}
|
|
5760
|
+
function emitAgentSetupHint(cwd) {
|
|
5761
|
+
if (!isAgentDriven() || hasTaroutAllowlist(cwd)) return;
|
|
5762
|
+
if (isJsonMode()) {
|
|
5763
|
+
outputJsonLine({
|
|
5764
|
+
type: "event",
|
|
5765
|
+
event: "agent_setup_required",
|
|
5766
|
+
hint: SETUP_HINT
|
|
5767
|
+
});
|
|
5768
|
+
} else {
|
|
5769
|
+
warn(SETUP_HINT);
|
|
5770
|
+
}
|
|
5771
|
+
}
|
|
5772
|
+
|
|
5508
5773
|
// src/lib/entitlement-remedy.ts
|
|
5509
5774
|
var planKeyOf = (p) => p.planKey ?? p.key ?? "";
|
|
5510
5775
|
var addonKeyOf = (a) => a.addonKey ?? a.key ?? "";
|
|
@@ -5603,13 +5868,13 @@ function streamDeploymentLogs(deploymentId, options) {
|
|
|
5603
5868
|
}
|
|
5604
5869
|
});
|
|
5605
5870
|
let buffer = "";
|
|
5606
|
-
const done = new Promise((
|
|
5871
|
+
const done = new Promise((resolve4) => {
|
|
5607
5872
|
ws.on("close", (code, reason) => {
|
|
5608
5873
|
if (buffer.length > 0) {
|
|
5609
5874
|
options.onData(buffer);
|
|
5610
5875
|
}
|
|
5611
5876
|
options.onClose?.(code, reason.toString());
|
|
5612
|
-
|
|
5877
|
+
resolve4({ code, reason: reason.toString() });
|
|
5613
5878
|
});
|
|
5614
5879
|
});
|
|
5615
5880
|
ws.on("open", () => {
|
|
@@ -5868,7 +6133,7 @@ async function confirmRegion(region) {
|
|
|
5868
6133
|
}
|
|
5869
6134
|
}
|
|
5870
6135
|
function inspectCurrentProject(cwd = process.cwd()) {
|
|
5871
|
-
const packageJson = readJsonFile(
|
|
6136
|
+
const packageJson = readJsonFile(join4(cwd, "package.json"));
|
|
5872
6137
|
const dependencies = new Set(
|
|
5873
6138
|
Object.keys({
|
|
5874
6139
|
...packageJson?.dependencies ?? {},
|
|
@@ -5916,8 +6181,8 @@ function printProjectInspection(inspection) {
|
|
|
5916
6181
|
}
|
|
5917
6182
|
function readJsonFile(path) {
|
|
5918
6183
|
try {
|
|
5919
|
-
if (!
|
|
5920
|
-
return JSON.parse(
|
|
6184
|
+
if (!existsSync4(path)) return null;
|
|
6185
|
+
return JSON.parse(readFileSync4(path, "utf8"));
|
|
5921
6186
|
} catch {
|
|
5922
6187
|
return null;
|
|
5923
6188
|
}
|
|
@@ -5926,7 +6191,7 @@ function readTextFile(path, maxBytes) {
|
|
|
5926
6191
|
try {
|
|
5927
6192
|
const stat = statSync(path);
|
|
5928
6193
|
if (stat.size > maxBytes) return "";
|
|
5929
|
-
return
|
|
6194
|
+
return readFileSync4(path, "utf8");
|
|
5930
6195
|
} catch {
|
|
5931
6196
|
return "";
|
|
5932
6197
|
}
|
|
@@ -5981,7 +6246,7 @@ function collectInspectableFiles(root) {
|
|
|
5981
6246
|
}
|
|
5982
6247
|
for (const entry of entries) {
|
|
5983
6248
|
if (files.length >= 400) return;
|
|
5984
|
-
const fullPath =
|
|
6249
|
+
const fullPath = join4(dir, entry.name);
|
|
5985
6250
|
if (entry.isDirectory()) {
|
|
5986
6251
|
if (!excludedDirs.has(entry.name)) walk(fullPath, depth + 1);
|
|
5987
6252
|
continue;
|
|
@@ -6033,7 +6298,7 @@ function detectDatabase(dependencies, files, cwd) {
|
|
|
6033
6298
|
}
|
|
6034
6299
|
}
|
|
6035
6300
|
const prismaSchema = readTextFile(
|
|
6036
|
-
|
|
6301
|
+
join4(cwd, "prisma", "schema.prisma"),
|
|
6037
6302
|
256 * 1024
|
|
6038
6303
|
);
|
|
6039
6304
|
if (/provider\s*=\s*"postgresql"/i.test(prismaSchema)) {
|
|
@@ -6114,15 +6379,15 @@ function detectStorage(dependencies, files) {
|
|
|
6114
6379
|
return { detected: reasons.length > 0, reasons: uniqueReasons(reasons) };
|
|
6115
6380
|
}
|
|
6116
6381
|
function detectGitSource(cwd) {
|
|
6117
|
-
const gitPath =
|
|
6118
|
-
if (!
|
|
6119
|
-
let configPath =
|
|
6382
|
+
const gitPath = join4(cwd, ".git");
|
|
6383
|
+
if (!existsSync4(gitPath)) return { hasGit: false };
|
|
6384
|
+
let configPath = join4(gitPath, "config");
|
|
6120
6385
|
try {
|
|
6121
6386
|
const stat = statSync(gitPath);
|
|
6122
6387
|
if (stat.isFile()) {
|
|
6123
6388
|
const content = readTextFile(gitPath, 4096);
|
|
6124
6389
|
const match = content.match(/gitdir:\s*(.+)/i);
|
|
6125
|
-
if (match?.[1]) configPath =
|
|
6390
|
+
if (match?.[1]) configPath = join4(cwd, match[1].trim(), "config");
|
|
6126
6391
|
}
|
|
6127
6392
|
} catch {
|
|
6128
6393
|
}
|
|
@@ -6168,7 +6433,12 @@ async function resolveDeploymentTarget(client, profile, appIdentifier, options =
|
|
|
6168
6433
|
}
|
|
6169
6434
|
const linkedProject = getProjectConfig();
|
|
6170
6435
|
const linkedApp = linkedProject ? findApp3(apps, linkedProject.applicationId) ?? findApp3(apps, linkedProject.name) : void 0;
|
|
6171
|
-
if (
|
|
6436
|
+
if (linkedApp) {
|
|
6437
|
+
return reuseAppTarget(client, profile, linkedApp, {
|
|
6438
|
+
promptForSource: false
|
|
6439
|
+
});
|
|
6440
|
+
}
|
|
6441
|
+
if (linkedProject && !isJsonMode()) {
|
|
6172
6442
|
log("");
|
|
6173
6443
|
log(
|
|
6174
6444
|
colors.warn(
|
|
@@ -6181,12 +6451,10 @@ async function resolveDeploymentTarget(client, profile, appIdentifier, options =
|
|
|
6181
6451
|
return createNewAppTarget(client, profile, options);
|
|
6182
6452
|
}
|
|
6183
6453
|
if (shouldSkipConfirmation()) {
|
|
6184
|
-
if (linkedApp) return reuseAppTarget(client, profile, linkedApp);
|
|
6185
6454
|
assertConfiguredSourceAllowsCreate(sourcePreference, true);
|
|
6186
6455
|
return createNewAppTarget(client, profile, options);
|
|
6187
6456
|
}
|
|
6188
6457
|
const createValue = "__create__";
|
|
6189
|
-
const orderedApps = linkedApp ? [linkedApp, ...apps.filter((a) => a.applicationId !== linkedApp.applicationId)] : apps;
|
|
6190
6458
|
const selected = await select(
|
|
6191
6459
|
"Create a new app or reuse an existing one?",
|
|
6192
6460
|
[
|
|
@@ -6194,17 +6462,16 @@ async function resolveDeploymentTarget(client, profile, appIdentifier, options =
|
|
|
6194
6462
|
name: `Create a new app from ${colors.cyan(basename(process.cwd()) || "this directory")}`,
|
|
6195
6463
|
value: createValue
|
|
6196
6464
|
},
|
|
6197
|
-
...
|
|
6198
|
-
name: `Reuse ${app2.name} ${colors.dim(`(${app2.applicationId.slice(0, 8)})`)}
|
|
6465
|
+
...apps.map((app2) => ({
|
|
6466
|
+
name: `Reuse ${app2.name} ${colors.dim(`(${app2.applicationId.slice(0, 8)})`)}`,
|
|
6199
6467
|
value: app2.applicationId
|
|
6200
6468
|
}))
|
|
6201
6469
|
],
|
|
6202
6470
|
{
|
|
6203
6471
|
field: "deploy_app",
|
|
6204
|
-
flag: "--new-app to create a new app, or
|
|
6472
|
+
flag: "--new-app to create a new app, or pass the app id or name as the positional argument (tarout deploy <id|name>) to reuse an existing one",
|
|
6205
6473
|
context: {
|
|
6206
|
-
|
|
6207
|
-
apps: orderedApps.map((a) => ({
|
|
6474
|
+
apps: apps.map((a) => ({
|
|
6208
6475
|
id: a.applicationId,
|
|
6209
6476
|
name: a.name
|
|
6210
6477
|
}))
|
|
@@ -6236,7 +6503,7 @@ async function createNewAppTarget(client, profile, options) {
|
|
|
6236
6503
|
shouldUploadSource: true
|
|
6237
6504
|
};
|
|
6238
6505
|
}
|
|
6239
|
-
async function reuseAppTarget(client, profile, app) {
|
|
6506
|
+
async function reuseAppTarget(client, profile, app, opts = {}) {
|
|
6240
6507
|
setProjectConfig({
|
|
6241
6508
|
applicationId: app.applicationId,
|
|
6242
6509
|
name: app.name,
|
|
@@ -6248,7 +6515,11 @@ async function reuseAppTarget(client, profile, app) {
|
|
|
6248
6515
|
app,
|
|
6249
6516
|
createdApp: false,
|
|
6250
6517
|
hasConfiguredSource: hasConfiguredSource(details),
|
|
6251
|
-
|
|
6518
|
+
// A deterministic redeploy (linked app) must not prompt for a source
|
|
6519
|
+
// override — it silently reuses the app's existing source, or the current
|
|
6520
|
+
// folder when `--source upload` is set downstream. Only an interactive
|
|
6521
|
+
// menu reuse offers the override.
|
|
6522
|
+
shouldUploadSource: opts.promptForSource === false ? shouldUseLocalSource(details, { linkedProject: true }) : await promptForLocalSourceIfNeeded(details)
|
|
6252
6523
|
};
|
|
6253
6524
|
}
|
|
6254
6525
|
async function createAppFromCurrentDirectory(client, profile, options = {}) {
|
|
@@ -6400,9 +6671,7 @@ async function runInlineUpgrade(client, planKey) {
|
|
|
6400
6671
|
planKey,
|
|
6401
6672
|
wait: true,
|
|
6402
6673
|
timeoutMs: 6e5,
|
|
6403
|
-
openBrowser:
|
|
6404
|
-
await open4(url);
|
|
6405
|
-
},
|
|
6674
|
+
openBrowser: paymentBrowserOpener(),
|
|
6406
6675
|
onCheckoutOpened: ({ orderId, paymentUrl }) => {
|
|
6407
6676
|
log("");
|
|
6408
6677
|
log("Open this URL to complete payment:");
|
|
@@ -6452,9 +6721,7 @@ async function runInlineTargetedRemedy(client, remedy) {
|
|
|
6452
6721
|
...input2,
|
|
6453
6722
|
wait: true,
|
|
6454
6723
|
timeoutMs: 6e5,
|
|
6455
|
-
openBrowser:
|
|
6456
|
-
await open4(url);
|
|
6457
|
-
},
|
|
6724
|
+
openBrowser: paymentBrowserOpener(),
|
|
6458
6725
|
onCheckoutOpened: ({ orderId, paymentUrl }) => {
|
|
6459
6726
|
log("");
|
|
6460
6727
|
log("Open this URL to complete payment:");
|
|
@@ -6651,7 +6918,8 @@ async function emitNeedsUpgrade(client, err, requestedPlan, retryCommand) {
|
|
|
6651
6918
|
suggestedTarget: remedy.targetKey,
|
|
6652
6919
|
nextCommand: remedy.command,
|
|
6653
6920
|
options,
|
|
6654
|
-
hint
|
|
6921
|
+
hint,
|
|
6922
|
+
permissionHint: AGENT_BILLING_PERMISSION_HINT
|
|
6655
6923
|
});
|
|
6656
6924
|
}
|
|
6657
6925
|
async function listFreeDatabasesSafely(client) {
|
|
@@ -7725,8 +7993,8 @@ async function uploadCurrentDirectorySource(client, applicationId, appName) {
|
|
|
7725
7993
|
}
|
|
7726
7994
|
}
|
|
7727
7995
|
async function createSourceArchive() {
|
|
7728
|
-
const tempDir = mkdtempSync(
|
|
7729
|
-
const archivePath =
|
|
7996
|
+
const tempDir = mkdtempSync(join4(tmpdir(), "tarout-source-"));
|
|
7997
|
+
const archivePath = join4(tempDir, "source.zip");
|
|
7730
7998
|
const excludes = [
|
|
7731
7999
|
".git/*",
|
|
7732
8000
|
".tarout/*",
|
|
@@ -7800,8 +8068,12 @@ function registerDeployCommands(program2) {
|
|
|
7800
8068
|
).option("--install-command <cmd>", "Custom install command").option("--build-command <cmd>", "Custom build command").option(
|
|
7801
8069
|
"--output-directory <path>",
|
|
7802
8070
|
"Build output directory (static assets)"
|
|
7803
|
-
).option("--start-command <cmd>", "Custom start command").option("-w, --wait", "Wait for deployment to complete and stream logs").option("--watch", "Alias for --wait").
|
|
8071
|
+
).option("--start-command <cmd>", "Custom start command").option("-w, --wait", "Wait for deployment to complete and stream logs").option("--watch", "Alias for --wait").option(
|
|
8072
|
+
"--no-agent-setup",
|
|
8073
|
+
"Don't auto-write the agent permission allowlist (CLAUDE.md / .claude/settings.local.json) on first run"
|
|
8074
|
+
).action(async (appIdentifier, options) => {
|
|
7804
8075
|
try {
|
|
8076
|
+
ensureAgentSetup(process.cwd(), options.agentSetup === false);
|
|
7805
8077
|
const inspection = inspectCurrentProject();
|
|
7806
8078
|
printProjectInspection(inspection);
|
|
7807
8079
|
const profile = await ensureAuthenticatedForDeploy(options);
|
|
@@ -8231,7 +8503,7 @@ function registerDeployCommands(program2) {
|
|
|
8231
8503
|
name: `${colors.cyan(d.deploymentId.slice(0, 8))} - ${d.title || "Deployment"} (${formatDate5(d.createdAt)})${index === 0 ? colors.dim(" [current]") : ""}`,
|
|
8232
8504
|
value: d.deploymentId
|
|
8233
8505
|
}));
|
|
8234
|
-
const { select: select2 } = await import("./prompts-
|
|
8506
|
+
const { select: select2 } = await import("./prompts-D72VJYWE.js");
|
|
8235
8507
|
targetDeploymentId = await select2(
|
|
8236
8508
|
"Select deployment:",
|
|
8237
8509
|
choices,
|
|
@@ -8250,7 +8522,7 @@ function registerDeployCommands(program2) {
|
|
|
8250
8522
|
` Created: ${targetDeployment ? formatDate5(targetDeployment.createdAt) : colors.dim("unknown")}`
|
|
8251
8523
|
);
|
|
8252
8524
|
log("");
|
|
8253
|
-
const { confirm: confirm2 } = await import("./prompts-
|
|
8525
|
+
const { confirm: confirm2 } = await import("./prompts-D72VJYWE.js");
|
|
8254
8526
|
const confirmed = await confirm2(
|
|
8255
8527
|
"Are you sure you want to rollback?",
|
|
8256
8528
|
false,
|
|
@@ -8382,7 +8654,7 @@ function formatDate5(date) {
|
|
|
8382
8654
|
});
|
|
8383
8655
|
}
|
|
8384
8656
|
function sleep(ms) {
|
|
8385
|
-
return new Promise((
|
|
8657
|
+
return new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
8386
8658
|
}
|
|
8387
8659
|
async function streamDeploymentWithLogs(client, deploymentId, appName, applicationId) {
|
|
8388
8660
|
stopSpinner();
|
|
@@ -11953,7 +12225,7 @@ function truncate(str, max) {
|
|
|
11953
12225
|
}
|
|
11954
12226
|
|
|
11955
12227
|
// src/commands/env.ts
|
|
11956
|
-
import { chmodSync, existsSync as
|
|
12228
|
+
import { chmodSync, existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
11957
12229
|
function registerEnvCommands(program2) {
|
|
11958
12230
|
const env = program2.command("env").argument("<app>", "Application ID or name").description("Manage environment variables");
|
|
11959
12231
|
env.command("list").alias("ls").description("List all environment variables").option("--reveal", "Show actual values (not masked)").action(async (options, command) => {
|
|
@@ -12113,7 +12385,7 @@ function registerEnvCommands(program2) {
|
|
|
12113
12385
|
);
|
|
12114
12386
|
throw new NotFoundError("Application", appIdentifier, suggestions);
|
|
12115
12387
|
}
|
|
12116
|
-
if (
|
|
12388
|
+
if (existsSync5(options.output) && !shouldSkipConfirmation()) {
|
|
12117
12389
|
succeedSpinner();
|
|
12118
12390
|
const confirmed = await confirm(
|
|
12119
12391
|
`File ${options.output} already exists. Overwrite?`,
|
|
@@ -12134,7 +12406,7 @@ function registerEnvCommands(program2) {
|
|
|
12134
12406
|
format: "dotenv",
|
|
12135
12407
|
maskSecrets: !options.reveal
|
|
12136
12408
|
});
|
|
12137
|
-
|
|
12409
|
+
writeFileSync3(options.output, result.content, { mode: 384 });
|
|
12138
12410
|
try {
|
|
12139
12411
|
chmodSync(options.output, 384);
|
|
12140
12412
|
} catch {
|
|
@@ -12153,10 +12425,10 @@ function registerEnvCommands(program2) {
|
|
|
12153
12425
|
try {
|
|
12154
12426
|
if (!isLoggedIn()) throw new AuthError();
|
|
12155
12427
|
const appIdentifier = command.parent.parent.args[0];
|
|
12156
|
-
if (!
|
|
12428
|
+
if (!existsSync5(options.input)) {
|
|
12157
12429
|
throw new InvalidArgumentError(`File not found: ${options.input}`);
|
|
12158
12430
|
}
|
|
12159
|
-
const content =
|
|
12431
|
+
const content = readFileSync5(options.input, "utf-8");
|
|
12160
12432
|
const client = getApiClient();
|
|
12161
12433
|
const _spinner = startSpinner("Uploading environment variables...");
|
|
12162
12434
|
const apps = await client.application.allByOrganization.query();
|
|
@@ -12380,7 +12652,7 @@ ${colors.bold(key)}: ${maskValue(val.value || String(v))}
|
|
|
12380
12652
|
} else {
|
|
12381
12653
|
const _raw = await import("process");
|
|
12382
12654
|
log('Enter JSON key-value object (e.g. {"KEY":"value"}):');
|
|
12383
|
-
const input2 = await (await import("./prompts-
|
|
12655
|
+
const input2 = await (await import("./prompts-D72VJYWE.js")).input(
|
|
12384
12656
|
"JSON:"
|
|
12385
12657
|
);
|
|
12386
12658
|
vars = JSON.parse(input2);
|
|
@@ -12403,7 +12675,7 @@ ${colors.bold(key)}: ${maskValue(val.value || String(v))}
|
|
|
12403
12675
|
try {
|
|
12404
12676
|
if (!isLoggedIn()) throw new AuthError();
|
|
12405
12677
|
if (!shouldSkipConfirmation()) {
|
|
12406
|
-
const { confirm: confirmFn } = await import("./prompts-
|
|
12678
|
+
const { confirm: confirmFn } = await import("./prompts-D72VJYWE.js");
|
|
12407
12679
|
const ok = await confirmFn(
|
|
12408
12680
|
`Delete ${keys.length} variable(s)?`,
|
|
12409
12681
|
false
|
|
@@ -12442,7 +12714,7 @@ ${colors.bold(key)}: ${maskValue(val.value || String(v))}
|
|
|
12442
12714
|
);
|
|
12443
12715
|
if (!app) throw new NotFoundError("Application", appIdentifier);
|
|
12444
12716
|
if (!shouldSkipConfirmation()) {
|
|
12445
|
-
const { confirm: confirmFn } = await import("./prompts-
|
|
12717
|
+
const { confirm: confirmFn } = await import("./prompts-D72VJYWE.js");
|
|
12446
12718
|
const ok = await confirmFn(
|
|
12447
12719
|
`Copy env vars from ${fromEnvId} to ${toEnvId}?`,
|
|
12448
12720
|
false
|
|
@@ -12890,8 +13162,8 @@ function registerInboxCommands(program2) {
|
|
|
12890
13162
|
}
|
|
12891
13163
|
|
|
12892
13164
|
// src/commands/init.ts
|
|
12893
|
-
import { existsSync as
|
|
12894
|
-
import { basename as basename2, join as
|
|
13165
|
+
import { existsSync as existsSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
13166
|
+
import { basename as basename2, join as join5, resolve as resolve2 } from "path";
|
|
12895
13167
|
var DEFAULT_REGION2 = "me-central2";
|
|
12896
13168
|
var STARTER_INDEX_JS = `import { createServer } from "node:http";
|
|
12897
13169
|
|
|
@@ -12909,8 +13181,8 @@ function toPackageName(name) {
|
|
|
12909
13181
|
}
|
|
12910
13182
|
function scaffoldStarter(cwd) {
|
|
12911
13183
|
const written = [];
|
|
12912
|
-
const pkgPath =
|
|
12913
|
-
if (
|
|
13184
|
+
const pkgPath = join5(cwd, "package.json");
|
|
13185
|
+
if (existsSync6(pkgPath)) return written;
|
|
12914
13186
|
const pkg = {
|
|
12915
13187
|
name: toPackageName(basename2(cwd) || "tarout-app"),
|
|
12916
13188
|
version: "0.1.0",
|
|
@@ -12918,12 +13190,12 @@ function scaffoldStarter(cwd) {
|
|
|
12918
13190
|
type: "module",
|
|
12919
13191
|
scripts: { start: "node index.js", dev: "node index.js" }
|
|
12920
13192
|
};
|
|
12921
|
-
|
|
13193
|
+
writeFileSync4(pkgPath, `${JSON.stringify(pkg, null, 2)}
|
|
12922
13194
|
`);
|
|
12923
13195
|
written.push("package.json");
|
|
12924
|
-
const indexPath =
|
|
12925
|
-
if (!
|
|
12926
|
-
|
|
13196
|
+
const indexPath = join5(cwd, "index.js");
|
|
13197
|
+
if (!existsSync6(indexPath)) {
|
|
13198
|
+
writeFileSync4(indexPath, STARTER_INDEX_JS);
|
|
12927
13199
|
written.push("index.js");
|
|
12928
13200
|
}
|
|
12929
13201
|
return written;
|
|
@@ -12935,9 +13207,9 @@ function writeEnvFile(cwd, vars) {
|
|
|
12935
13207
|
const lines = Object.entries(vars).map(
|
|
12936
13208
|
([k, v]) => `${k}=${envValueNeedsQuote(v) ? JSON.stringify(v) : v}`
|
|
12937
13209
|
);
|
|
12938
|
-
const primary =
|
|
12939
|
-
const target =
|
|
12940
|
-
|
|
13210
|
+
const primary = join5(cwd, ".env");
|
|
13211
|
+
const target = existsSync6(primary) ? join5(cwd, ".env.tarout") : primary;
|
|
13212
|
+
writeFileSync4(target, `${lines.join("\n")}
|
|
12941
13213
|
`, { mode: 384 });
|
|
12942
13214
|
return target;
|
|
12943
13215
|
}
|
|
@@ -12954,10 +13226,14 @@ function registerInitCommand(program2) {
|
|
|
12954
13226
|
).option("-r, --region <region>", "Deployment region", DEFAULT_REGION2).option("--description <text>", "Description for the newly created app").option(
|
|
12955
13227
|
"--database <type>",
|
|
12956
13228
|
"Provision a database: none, postgres, or mysql (defaults to auto-detected)"
|
|
12957
|
-
).option("--database-plan <plan>", "Database plan (e.g. free, starter)").option("--storage", "Provision file storage").option("--storage-plan <plan>", "Storage plan (e.g. free, starter)").option("--scaffold", "Write a minimal starter app if the directory is empty").option("--no-env-write", "Do not write a local .env file with connection strings").
|
|
13229
|
+
).option("--database-plan <plan>", "Database plan (e.g. free, starter)").option("--storage", "Provision file storage").option("--storage-plan <plan>", "Storage plan (e.g. free, starter)").option("--scaffold", "Write a minimal starter app if the directory is empty").option("--no-env-write", "Do not write a local .env file with connection strings").option(
|
|
13230
|
+
"--no-agent-setup",
|
|
13231
|
+
"Don't auto-write the agent permission allowlist (CLAUDE.md / .claude/settings.local.json) on first run"
|
|
13232
|
+
).action(async (cwdArg, options) => {
|
|
12958
13233
|
try {
|
|
12959
|
-
const cwd = cwdArg ?
|
|
13234
|
+
const cwd = cwdArg ? resolve2(cwdArg) : process.cwd();
|
|
12960
13235
|
if (cwdArg) process.chdir(cwd);
|
|
13236
|
+
ensureAgentSetup(cwd, options.agentSetup === false);
|
|
12961
13237
|
if (options.scaffold) {
|
|
12962
13238
|
const files = scaffoldStarter(cwd);
|
|
12963
13239
|
emitEvent({ event: "scaffold_done", files });
|
|
@@ -13019,7 +13295,8 @@ function registerInitCommand(program2) {
|
|
|
13019
13295
|
outputError("NEEDS_UPGRADE", message, {
|
|
13020
13296
|
suggestedPlan: inferSuggestedPlan(options.plan),
|
|
13021
13297
|
failedEntitlementKey: extractEntitlementKeyFromError(err),
|
|
13022
|
-
hint: "Run `tarout billing upgrade <plan> --wait` to add slots, then retry `tarout init`."
|
|
13298
|
+
hint: "Run `tarout billing upgrade <plan> --wait` to add slots, then retry `tarout init`.",
|
|
13299
|
+
permissionHint: AGENT_BILLING_PERMISSION_HINT
|
|
13023
13300
|
});
|
|
13024
13301
|
exit(ExitCode.PERMISSION_DENIED);
|
|
13025
13302
|
}
|
|
@@ -13156,8 +13433,8 @@ function registerKeysCommands(program2) {
|
|
|
13156
13433
|
});
|
|
13157
13434
|
}
|
|
13158
13435
|
if (!publicKey && options.file) {
|
|
13159
|
-
const { readFileSync:
|
|
13160
|
-
publicKey =
|
|
13436
|
+
const { readFileSync: readFileSync6 } = await import("fs");
|
|
13437
|
+
publicKey = readFileSync6(options.file, "utf-8").trim();
|
|
13161
13438
|
}
|
|
13162
13439
|
if (!publicKey) {
|
|
13163
13440
|
log(
|
|
@@ -19345,7 +19622,7 @@ function truncate3(str, max) {
|
|
|
19345
19622
|
}
|
|
19346
19623
|
|
|
19347
19624
|
// src/commands/up.ts
|
|
19348
|
-
import { resolve as
|
|
19625
|
+
import { resolve as resolve3 } from "path";
|
|
19349
19626
|
var DEFAULT_REGION3 = "me-central2";
|
|
19350
19627
|
function normalizeSource(value) {
|
|
19351
19628
|
if (!value) return "upload";
|
|
@@ -19402,10 +19679,14 @@ function registerUpCommand(program2) {
|
|
|
19402
19679
|
).option("--start-command <cmd>", "Custom start command").option(
|
|
19403
19680
|
"--idempotency-key <key>",
|
|
19404
19681
|
"Idempotency key for safe retries (Phase 2; logged only in v1)"
|
|
19682
|
+
).option(
|
|
19683
|
+
"--no-agent-setup",
|
|
19684
|
+
"Don't auto-write the agent permission allowlist (CLAUDE.md / .claude/settings.local.json) on first run"
|
|
19405
19685
|
).action(async (cwdArg, options) => {
|
|
19406
19686
|
try {
|
|
19407
|
-
const cwd = cwdArg ?
|
|
19687
|
+
const cwd = cwdArg ? resolve3(cwdArg) : process.cwd();
|
|
19408
19688
|
if (cwdArg) process.chdir(cwd);
|
|
19689
|
+
ensureAgentSetup(cwd, options.agentSetup === false);
|
|
19409
19690
|
const source = normalizeSource(options.source);
|
|
19410
19691
|
const idempotencyKey = options.idempotencyKey?.trim();
|
|
19411
19692
|
if (idempotencyKey) {
|
|
@@ -19905,7 +20186,7 @@ var program = new Command();
|
|
|
19905
20186
|
program.name("tarout").description("Tarout PaaS Command Line Interface").version(package_default.version).option("--json", "Output as JSON (machine-readable)").option("-y, --yes", "Skip all confirmation prompts").option(
|
|
19906
20187
|
"--non-interactive",
|
|
19907
20188
|
"Fail fast on missing input (emit needs_input + exit 6 instead of prompting on TTY)"
|
|
19908
|
-
).option("-q, --quiet", "Minimal output").option("-v, --verbose", "Extra debug information").option("--no-color", "Disable colored output").hook("preAction", (thisCommand) => {
|
|
20189
|
+
).option("-q, --quiet", "Minimal output").option("-v, --verbose", "Extra debug information").option("--no-color", "Disable colored output").hook("preAction", (thisCommand, actionCommand) => {
|
|
19909
20190
|
const opts = thisCommand.opts();
|
|
19910
20191
|
const stdinIsTTY = Boolean(process.stdin.isTTY);
|
|
19911
20192
|
setGlobalOptions({
|
|
@@ -19916,11 +20197,18 @@ program.name("tarout").description("Tarout PaaS Command Line Interface").version
|
|
|
19916
20197
|
verbose: opts.verbose || false,
|
|
19917
20198
|
noColor: opts.color === false
|
|
19918
20199
|
});
|
|
20200
|
+
const sub = actionCommand?.name();
|
|
20201
|
+
const isAgentNamespace = actionCommand?.parent?.name() === "agent";
|
|
20202
|
+
const autoRunsSetup = !!sub && ["up", "deploy", "init"].includes(sub);
|
|
20203
|
+
if (!isAgentNamespace && !autoRunsSetup) {
|
|
20204
|
+
emitAgentSetupHint(process.cwd());
|
|
20205
|
+
}
|
|
19919
20206
|
});
|
|
19920
20207
|
registerAuthCommands(program);
|
|
19921
20208
|
registerAppsCommands(program);
|
|
19922
20209
|
registerDeployCommands(program);
|
|
19923
20210
|
registerInitCommand(program);
|
|
20211
|
+
registerAgentCommands(program);
|
|
19924
20212
|
registerUpCommand(program);
|
|
19925
20213
|
registerLogsCommand(program);
|
|
19926
20214
|
registerEnvCommands(program);
|