deepline 0.1.32 → 0.1.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -20
- package/dist/cli/index.js +164 -180
- package/dist/cli/index.mjs +175 -191
- package/dist/index.d.mts +6 -24
- package/dist/index.d.ts +6 -24
- package/dist/index.js +55 -81
- package/dist/index.mjs +56 -82
- package/dist/repo/sdk/src/config.ts +109 -233
- package/dist/repo/sdk/src/types.ts +3 -1
- package/dist/repo/sdk/src/version.ts +2 -2
- package/dist/repo/shared_libs/play-runtime/scheduler-backend.ts +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -67,19 +67,12 @@ var ConfigError = class extends DeeplineError {
|
|
|
67
67
|
};
|
|
68
68
|
|
|
69
69
|
// src/config.ts
|
|
70
|
+
var HOST_URL_ENV = "DEEPLINE_HOST_URL";
|
|
71
|
+
var API_KEY_ENV = "DEEPLINE_API_KEY";
|
|
70
72
|
var PROD_URL = "https://code.deepline.com";
|
|
71
73
|
var DEFAULT_TIMEOUT = 6e4;
|
|
72
74
|
var DEFAULT_MAX_RETRIES = 3;
|
|
73
|
-
var
|
|
74
|
-
function isProdBaseUrl(baseUrl) {
|
|
75
|
-
return baseUrl.trim().replace(/\/$/, "") === PROD_URL;
|
|
76
|
-
}
|
|
77
|
-
function profileNameForBaseUrl(baseUrl) {
|
|
78
|
-
return isProdBaseUrl(baseUrl) ? "prod" : "dev";
|
|
79
|
-
}
|
|
80
|
-
function projectEnvStartDir() {
|
|
81
|
-
return process.env.DEEPLINE_PROJECT_ENV_DIR?.trim() || process.cwd();
|
|
82
|
-
}
|
|
75
|
+
var PROJECT_DEEPLINE_ENV_FILE = ".env.deepline";
|
|
83
76
|
function baseUrlSlug(baseUrl) {
|
|
84
77
|
let url;
|
|
85
78
|
try {
|
|
@@ -88,7 +81,7 @@ function baseUrlSlug(baseUrl) {
|
|
|
88
81
|
return "unknown";
|
|
89
82
|
}
|
|
90
83
|
const host = url.hostname || "unknown";
|
|
91
|
-
const port = url.port ? parseInt(url.port, 10) : null;
|
|
84
|
+
const port = url.port ? Number.parseInt(url.port, 10) : null;
|
|
92
85
|
let slug = host.replace(/[^a-zA-Z0-9]/g, "-");
|
|
93
86
|
if (port && port !== 80 && port !== 443) {
|
|
94
87
|
slug = `${slug}-${port}`;
|
|
@@ -115,79 +108,52 @@ function parseEnvFile(filePath) {
|
|
|
115
108
|
}
|
|
116
109
|
return env;
|
|
117
110
|
}
|
|
118
|
-
function findNearestEnvFile(
|
|
111
|
+
function findNearestEnvFile(name, startDir = process.cwd()) {
|
|
119
112
|
let current = (0, import_node_path.resolve)(startDir);
|
|
120
113
|
while (true) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if ((0, import_node_fs.existsSync)(filePath)) return filePath;
|
|
124
|
-
}
|
|
114
|
+
const filePath = (0, import_node_path.join)(current, name);
|
|
115
|
+
if ((0, import_node_fs.existsSync)(filePath)) return filePath;
|
|
125
116
|
const parent = (0, import_node_path.dirname)(current);
|
|
126
117
|
if (parent === current) return null;
|
|
127
118
|
current = parent;
|
|
128
119
|
}
|
|
129
120
|
}
|
|
130
|
-
function
|
|
131
|
-
const filePath = findNearestEnvFile(
|
|
121
|
+
function loadProjectDeeplineEnv(startDir = process.cwd()) {
|
|
122
|
+
const filePath = findNearestEnvFile(PROJECT_DEEPLINE_ENV_FILE, startDir);
|
|
132
123
|
return filePath ? parseEnvFile(filePath) : {};
|
|
133
124
|
}
|
|
134
|
-
function
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
function resolveProfileEnvFileNames() {
|
|
138
|
-
const explicitProfile = process.env.DEEPLINE_ENV_PROFILE?.trim() || process.env.DEEPLINE_PROFILE?.trim() || "";
|
|
139
|
-
const names = [];
|
|
140
|
-
if (explicitProfile) names.push(`.env.deepline.${explicitProfile}`);
|
|
141
|
-
const nodeEnv = process.env.NODE_ENV?.trim();
|
|
142
|
-
if (nodeEnv === "production") names.push(".env.deepline.prod");
|
|
143
|
-
else if (nodeEnv === "staging") names.push(".env.deepline.staging");
|
|
144
|
-
names.push(ACTIVE_DEEPLINE_ENV_FILE);
|
|
145
|
-
return names;
|
|
146
|
-
}
|
|
147
|
-
function resolveProjectAppEnvFileNames() {
|
|
148
|
-
const nodeEnv = process.env.NODE_ENV?.trim();
|
|
149
|
-
const names = [];
|
|
150
|
-
if (nodeEnv === "production") names.push(".env.prod");
|
|
151
|
-
if (nodeEnv === "staging") names.push(".env.staging");
|
|
152
|
-
names.push(".env.local", ".env");
|
|
153
|
-
return names;
|
|
154
|
-
}
|
|
155
|
-
function resolveBaseUrlFromEnvValues(env) {
|
|
156
|
-
return env.DEEPLINE_ORIGIN_URL?.trim() || env.DEEPLINE_API_BASE_URL?.trim() || "";
|
|
157
|
-
}
|
|
158
|
-
function loadProjectDeeplineEnv() {
|
|
159
|
-
return findNearestEnv(resolveProfileEnvFileNames(), projectEnvStartDir());
|
|
160
|
-
}
|
|
161
|
-
function loadProjectAppEnv() {
|
|
162
|
-
return findNearestEnv(resolveProjectAppEnvFileNames(), projectEnvStartDir());
|
|
163
|
-
}
|
|
164
|
-
function normalizeWorktreeBaseUrl(baseUrl, worktreeEnv = findNearestWorktreeEnv()) {
|
|
165
|
-
const trimmed = baseUrl.trim().replace(/\/$/, "");
|
|
166
|
-
if (!trimmed) return trimmed;
|
|
125
|
+
function normalizeBaseUrl(baseUrl) {
|
|
126
|
+
const trimmed = baseUrl.trim().replace(/\/+$/, "");
|
|
127
|
+
if (!trimmed) return "";
|
|
167
128
|
try {
|
|
168
129
|
const parsed = new URL(trimmed);
|
|
169
|
-
if (parsed.
|
|
170
|
-
|
|
171
|
-
if (port) return `${parsed.protocol}//localhost:${port}`;
|
|
130
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
131
|
+
return "";
|
|
172
132
|
}
|
|
133
|
+
return parsed.toString().replace(/\/+$/, "");
|
|
173
134
|
} catch {
|
|
135
|
+
return "";
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function firstNonEmpty(...values) {
|
|
139
|
+
for (const value of values) {
|
|
140
|
+
const trimmed = value?.trim();
|
|
141
|
+
if (trimmed) return trimmed;
|
|
174
142
|
}
|
|
175
|
-
return
|
|
143
|
+
return "";
|
|
176
144
|
}
|
|
177
|
-
function
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
if (declared) return normalizeWorktreeBaseUrl(declared, worktreeEnv);
|
|
181
|
-
const port = worktreeEnv.WORKTREE_APP_PORT || worktreeEnv.PORT || "";
|
|
182
|
-
return port ? `http://localhost:${port}` : "";
|
|
145
|
+
function sdkCliConfigDir(baseUrl) {
|
|
146
|
+
const home = process.env.HOME?.trim() || (0, import_node_os.homedir)();
|
|
147
|
+
return (0, import_node_path.join)(home, ".local", "deepline", baseUrlSlug(baseUrl || PROD_URL));
|
|
183
148
|
}
|
|
184
149
|
function sdkCliEnvFilePath(baseUrl) {
|
|
185
|
-
|
|
186
|
-
return (0, import_node_path.join)(home, ".local", "deepline", baseUrlSlug(baseUrl || PROD_URL), ".env");
|
|
150
|
+
return (0, import_node_path.join)(sdkCliConfigDir(baseUrl), ".env");
|
|
187
151
|
}
|
|
188
152
|
function loadCliEnv(baseUrl = PROD_URL) {
|
|
189
|
-
|
|
190
|
-
|
|
153
|
+
return parseEnvFile(sdkCliEnvFilePath(baseUrl));
|
|
154
|
+
}
|
|
155
|
+
function hostConfigDirPath(baseUrl) {
|
|
156
|
+
return sdkCliConfigDir(baseUrl);
|
|
191
157
|
}
|
|
192
158
|
function hostEnvFilePath(baseUrl) {
|
|
193
159
|
return sdkCliEnvFilePath(baseUrl);
|
|
@@ -198,9 +164,10 @@ function saveHostEnvValues(baseUrl, values) {
|
|
|
198
164
|
if (!(0, import_node_fs.existsSync)(dir)) {
|
|
199
165
|
(0, import_node_fs.mkdirSync)(dir, { recursive: true });
|
|
200
166
|
}
|
|
201
|
-
const existing =
|
|
167
|
+
const existing = parseEnvFile(filePath);
|
|
202
168
|
const merged = { ...existing, ...values };
|
|
203
|
-
const
|
|
169
|
+
const allowedKeys = /* @__PURE__ */ new Set([HOST_URL_ENV, API_KEY_ENV]);
|
|
170
|
+
const lines = Object.entries(merged).filter(([key, value]) => allowedKeys.has(key) && value !== "").map(([key, value]) => `${key}=${value}`);
|
|
204
171
|
(0, import_node_fs.writeFileSync)(filePath, `${lines.join("\n")}
|
|
205
172
|
`, "utf-8");
|
|
206
173
|
}
|
|
@@ -208,31 +175,36 @@ function loadGlobalCliEnv() {
|
|
|
208
175
|
return loadCliEnv(PROD_URL);
|
|
209
176
|
}
|
|
210
177
|
function autoDetectBaseUrl() {
|
|
211
|
-
const
|
|
212
|
-
if (envOrigin) return normalizeWorktreeBaseUrl(envOrigin);
|
|
213
|
-
const envBase = process.env.DEEPLINE_API_BASE_URL?.trim();
|
|
214
|
-
if (envBase) return normalizeWorktreeBaseUrl(envBase);
|
|
215
|
-
const projectDeeplineBaseUrl = resolveBaseUrlFromEnvValues(loadProjectDeeplineEnv());
|
|
216
|
-
if (projectDeeplineBaseUrl) return normalizeWorktreeBaseUrl(projectDeeplineBaseUrl);
|
|
217
|
-
const projectAppBaseUrl = resolveBaseUrlFromEnvValues(loadProjectAppEnv());
|
|
218
|
-
if (projectAppBaseUrl) return normalizeWorktreeBaseUrl(projectAppBaseUrl);
|
|
219
|
-
const worktreeBaseUrl = resolveWorktreeBaseUrl();
|
|
220
|
-
if (worktreeBaseUrl) return worktreeBaseUrl;
|
|
178
|
+
const projectEnv = loadProjectDeeplineEnv();
|
|
221
179
|
const globalEnv = loadGlobalCliEnv();
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
180
|
+
return normalizeBaseUrl(process.env[HOST_URL_ENV] ?? "") || normalizeBaseUrl(projectEnv[HOST_URL_ENV] ?? "") || normalizeBaseUrl(globalEnv[HOST_URL_ENV] ?? "") || PROD_URL;
|
|
181
|
+
}
|
|
182
|
+
function resolveApiKeyForBaseUrl(baseUrl, explicitApiKey) {
|
|
183
|
+
const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
|
|
184
|
+
const projectEnv = loadProjectDeeplineEnv();
|
|
185
|
+
const cliEnv = loadCliEnv(normalizedBaseUrl || baseUrl);
|
|
186
|
+
const projectBaseUrl = normalizeBaseUrl(projectEnv[HOST_URL_ENV] ?? "");
|
|
187
|
+
const projectKeyApplies = projectBaseUrl === normalizedBaseUrl;
|
|
188
|
+
return firstNonEmpty(
|
|
189
|
+
explicitApiKey,
|
|
190
|
+
process.env[API_KEY_ENV],
|
|
191
|
+
projectKeyApplies ? projectEnv[API_KEY_ENV] : "",
|
|
192
|
+
cliEnv[API_KEY_ENV]
|
|
193
|
+
);
|
|
225
194
|
}
|
|
226
195
|
function resolveConfig(options) {
|
|
227
|
-
const
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
196
|
+
const baseUrl = normalizeBaseUrl(
|
|
197
|
+
options?.baseUrl?.trim() || autoDetectBaseUrl()
|
|
198
|
+
);
|
|
199
|
+
if (!baseUrl) {
|
|
200
|
+
throw new ConfigError(
|
|
201
|
+
`Invalid ${HOST_URL_ENV}. Expected an http(s) URL such as https://code.deepline.com.`
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
const apiKey = resolveApiKeyForBaseUrl(baseUrl, options?.apiKey);
|
|
233
205
|
if (!apiKey) {
|
|
234
206
|
throw new ConfigError(
|
|
235
|
-
`No API key found. Set
|
|
207
|
+
`No API key found. Set ${API_KEY_ENV}, add it to .env.deepline, or run: deepline auth register`
|
|
236
208
|
);
|
|
237
209
|
}
|
|
238
210
|
return {
|
|
@@ -242,32 +214,10 @@ function resolveConfig(options) {
|
|
|
242
214
|
maxRetries: options?.maxRetries ?? DEFAULT_MAX_RETRIES
|
|
243
215
|
};
|
|
244
216
|
}
|
|
245
|
-
function mergeEnvFile(filePath, values) {
|
|
246
|
-
const existing = (0, import_node_fs.existsSync)(filePath) ? parseEnvFile(filePath) : {};
|
|
247
|
-
const merged = { ...existing, ...values };
|
|
248
|
-
const dir = (0, import_node_path.dirname)(filePath);
|
|
249
|
-
if (!(0, import_node_fs.existsSync)(dir)) (0, import_node_fs.mkdirSync)(dir, { recursive: true });
|
|
250
|
-
const lines = Object.entries(merged).filter(([, value]) => value !== "").map(([key, value]) => `${key}=${value}`);
|
|
251
|
-
(0, import_node_fs.writeFileSync)(filePath, `${lines.join("\n")}
|
|
252
|
-
`, "utf-8");
|
|
253
|
-
}
|
|
254
|
-
function saveProjectDeeplineEnvValues(baseUrl, values, startDir = projectEnvStartDir()) {
|
|
255
|
-
const root = (0, import_node_path.resolve)(startDir);
|
|
256
|
-
const profile = profileNameForBaseUrl(baseUrl);
|
|
257
|
-
const files = [
|
|
258
|
-
(0, import_node_path.join)(root, ACTIVE_DEEPLINE_ENV_FILE),
|
|
259
|
-
(0, import_node_path.join)(root, `.env.deepline.${profile}`)
|
|
260
|
-
];
|
|
261
|
-
if (profile === "dev") files.push((0, import_node_path.join)(root, ".env"));
|
|
262
|
-
for (const filePath of files) {
|
|
263
|
-
mergeEnvFile(filePath, values);
|
|
264
|
-
}
|
|
265
|
-
return files;
|
|
266
|
-
}
|
|
267
217
|
|
|
268
218
|
// src/version.ts
|
|
269
|
-
var SDK_VERSION = "0.1.
|
|
270
|
-
var SDK_API_CONTRACT = "2026-05-generic-play-input-flags";
|
|
219
|
+
var SDK_VERSION = "0.1.33";
|
|
220
|
+
var SDK_API_CONTRACT = "2026-05-host-env-generic-play-input-flags";
|
|
271
221
|
|
|
272
222
|
// ../shared_libs/play-runtime/coordinator-headers.ts
|
|
273
223
|
var COORDINATOR_INTERNAL_TOKEN_HEADER = "x-deepline-internal-token";
|
|
@@ -1686,10 +1636,11 @@ var import_node_fs2 = require("fs");
|
|
|
1686
1636
|
var import_promises = require("fs/promises");
|
|
1687
1637
|
var import_node_os2 = require("os");
|
|
1688
1638
|
var import_node_path2 = require("path");
|
|
1689
|
-
var
|
|
1639
|
+
var childProcess = __toESM(require("child_process"));
|
|
1690
1640
|
var import_sync = require("csv-parse/sync");
|
|
1691
1641
|
var import_sync2 = require("csv-stringify/sync");
|
|
1692
1642
|
var BROWSER_FOCUS_COOLDOWN_MS = 3e4;
|
|
1643
|
+
var defaultBrowserCommandRunner = childProcess;
|
|
1693
1644
|
function getAuthedHttpClient() {
|
|
1694
1645
|
const config = resolveConfig();
|
|
1695
1646
|
return { config, http: new HttpClient(config) };
|
|
@@ -1758,9 +1709,9 @@ function browserAppNameFromBundleId(bundleId) {
|
|
|
1758
1709
|
};
|
|
1759
1710
|
return names[bundleId.toLowerCase()] ?? "";
|
|
1760
1711
|
}
|
|
1761
|
-
function readDefaultMacBrowserBundleId() {
|
|
1712
|
+
function readDefaultMacBrowserBundleId(runner = defaultBrowserCommandRunner) {
|
|
1762
1713
|
try {
|
|
1763
|
-
const output =
|
|
1714
|
+
const output = runner.execFileSync(
|
|
1764
1715
|
"/usr/bin/defaults",
|
|
1765
1716
|
[
|
|
1766
1717
|
"read",
|
|
@@ -1796,8 +1747,8 @@ function browserStrategyForBundleId(bundleId) {
|
|
|
1796
1747
|
}
|
|
1797
1748
|
return normalized === "com.apple.safari" ? "safari" : "fallback";
|
|
1798
1749
|
}
|
|
1799
|
-
function runAppleScript(script, args) {
|
|
1800
|
-
const result =
|
|
1750
|
+
function runAppleScript(script, args, runner = defaultBrowserCommandRunner) {
|
|
1751
|
+
const result = runner.spawnSync("osascript", ["-", ...args], {
|
|
1801
1752
|
input: script,
|
|
1802
1753
|
encoding: "utf-8",
|
|
1803
1754
|
stdio: ["pipe", "ignore", "ignore"],
|
|
@@ -1805,7 +1756,7 @@ function runAppleScript(script, args) {
|
|
|
1805
1756
|
});
|
|
1806
1757
|
return result.status === 0;
|
|
1807
1758
|
}
|
|
1808
|
-
function retargetChromiumMacos(appName, targetUrl, allowFocus) {
|
|
1759
|
+
function retargetChromiumMacos(appName, targetUrl, allowFocus, runner = defaultBrowserCommandRunner) {
|
|
1809
1760
|
const host = extractUrlHost(targetUrl);
|
|
1810
1761
|
if (!host) return false;
|
|
1811
1762
|
const escapedAppName = appName.replace(/"/g, '\\"');
|
|
@@ -1837,9 +1788,9 @@ ${newTabBlock} end if
|
|
|
1837
1788
|
end tell
|
|
1838
1789
|
end run
|
|
1839
1790
|
`;
|
|
1840
|
-
return runAppleScript(script, [targetUrl, host]);
|
|
1791
|
+
return runAppleScript(script, [targetUrl, host], runner);
|
|
1841
1792
|
}
|
|
1842
|
-
function retargetSafariMacos(appName, targetUrl, allowFocus) {
|
|
1793
|
+
function retargetSafariMacos(appName, targetUrl, allowFocus, runner = defaultBrowserCommandRunner) {
|
|
1843
1794
|
const host = extractUrlHost(targetUrl);
|
|
1844
1795
|
if (!host) return false;
|
|
1845
1796
|
const escapedAppName = appName.replace(/"/g, '\\"');
|
|
@@ -1871,30 +1822,38 @@ ${newTabBlock} end if
|
|
|
1871
1822
|
end tell
|
|
1872
1823
|
end run
|
|
1873
1824
|
`;
|
|
1874
|
-
return runAppleScript(script, [targetUrl, host]);
|
|
1825
|
+
return runAppleScript(script, [targetUrl, host], runner);
|
|
1875
1826
|
}
|
|
1876
|
-
function openUrlMacos(targetUrl, allowFocus) {
|
|
1877
|
-
const defaultBundleId = readDefaultMacBrowserBundleId();
|
|
1827
|
+
function openUrlMacos(targetUrl, allowFocus, runner = defaultBrowserCommandRunner) {
|
|
1828
|
+
const defaultBundleId = readDefaultMacBrowserBundleId(runner);
|
|
1878
1829
|
const appName = defaultBundleId ? browserAppNameFromBundleId(defaultBundleId) : "";
|
|
1879
1830
|
const strategy = browserStrategyForBundleId(defaultBundleId);
|
|
1880
|
-
if (appName && strategy === "chromium" && retargetChromiumMacos(appName, targetUrl, allowFocus)) {
|
|
1831
|
+
if (appName && strategy === "chromium" && retargetChromiumMacos(appName, targetUrl, allowFocus, runner)) {
|
|
1881
1832
|
return true;
|
|
1882
1833
|
}
|
|
1883
|
-
if (appName && strategy === "safari" && retargetSafariMacos(appName, targetUrl, allowFocus)) {
|
|
1834
|
+
if (appName && strategy === "safari" && retargetSafariMacos(appName, targetUrl, allowFocus, runner)) {
|
|
1884
1835
|
return true;
|
|
1885
1836
|
}
|
|
1886
|
-
if (!allowFocus) {
|
|
1887
|
-
return false;
|
|
1888
|
-
}
|
|
1889
1837
|
try {
|
|
1890
|
-
|
|
1838
|
+
runner.execFileSync(
|
|
1839
|
+
"open",
|
|
1840
|
+
[...allowFocus ? [] : ["-g"], targetUrl],
|
|
1841
|
+
{ stdio: "ignore" }
|
|
1842
|
+
);
|
|
1891
1843
|
return true;
|
|
1892
1844
|
} catch {
|
|
1893
1845
|
return false;
|
|
1894
1846
|
}
|
|
1895
1847
|
}
|
|
1848
|
+
function browserOpeningDisabled() {
|
|
1849
|
+
const value = String(
|
|
1850
|
+
process.env.DEEPLINE_NO_BROWSER ?? process.env.PLAYGROUND_HEADLESS ?? ""
|
|
1851
|
+
).trim().toLowerCase();
|
|
1852
|
+
return value === "1" || value === "true" || value === "yes" || value === "on";
|
|
1853
|
+
}
|
|
1896
1854
|
function openInBrowser(url) {
|
|
1897
1855
|
try {
|
|
1856
|
+
if (browserOpeningDisabled()) return;
|
|
1898
1857
|
const targetUrl = String(url || "").trim();
|
|
1899
1858
|
if (!targetUrl) return;
|
|
1900
1859
|
const allowFocus = claimBrowserFocus();
|
|
@@ -1904,12 +1863,12 @@ function openInBrowser(url) {
|
|
|
1904
1863
|
}
|
|
1905
1864
|
if (!allowFocus) return;
|
|
1906
1865
|
if (process.platform === "win32") {
|
|
1907
|
-
|
|
1866
|
+
childProcess.execFileSync("cmd.exe", ["/c", "start", "", targetUrl], {
|
|
1908
1867
|
stdio: "ignore"
|
|
1909
1868
|
});
|
|
1910
1869
|
return;
|
|
1911
1870
|
}
|
|
1912
|
-
|
|
1871
|
+
childProcess.execFileSync("xdg-open", [targetUrl], { stdio: "ignore" });
|
|
1913
1872
|
} catch {
|
|
1914
1873
|
}
|
|
1915
1874
|
}
|
|
@@ -2023,17 +1982,39 @@ var EXIT_SERVER = 2;
|
|
|
2023
1982
|
function envFilePath(baseUrl) {
|
|
2024
1983
|
return hostEnvFilePath(baseUrl);
|
|
2025
1984
|
}
|
|
2026
|
-
function
|
|
2027
|
-
|
|
1985
|
+
function pendingClaimTokenPath(baseUrl) {
|
|
1986
|
+
return `${hostConfigDirPath(baseUrl)}/pending-claim-token`;
|
|
1987
|
+
}
|
|
1988
|
+
function savePendingClaimToken(baseUrl, claimToken) {
|
|
1989
|
+
const filePath = pendingClaimTokenPath(baseUrl);
|
|
2028
1990
|
const dir = (0, import_node_path3.dirname)(filePath);
|
|
2029
1991
|
if (!(0, import_node_fs3.existsSync)(dir)) {
|
|
2030
1992
|
(0, import_node_fs3.mkdirSync)(dir, { recursive: true });
|
|
2031
1993
|
}
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
1994
|
+
(0, import_node_fs3.writeFileSync)(filePath, `${claimToken}
|
|
1995
|
+
`, "utf-8");
|
|
1996
|
+
}
|
|
1997
|
+
function readPendingClaimToken(baseUrl) {
|
|
1998
|
+
const filePath = pendingClaimTokenPath(baseUrl);
|
|
1999
|
+
if (!(0, import_node_fs3.existsSync)(filePath)) return "";
|
|
2000
|
+
try {
|
|
2001
|
+
return (0, import_node_fs3.readFileSync)(filePath, "utf-8").trim();
|
|
2002
|
+
} catch {
|
|
2003
|
+
return "";
|
|
2004
|
+
}
|
|
2005
|
+
}
|
|
2006
|
+
function clearPendingClaimToken(baseUrl) {
|
|
2007
|
+
try {
|
|
2008
|
+
(0, import_node_fs3.rmSync)(pendingClaimTokenPath(baseUrl), { force: true });
|
|
2009
|
+
} catch {
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
function saveEnvValues(values, baseUrl) {
|
|
2013
|
+
const filtered = {
|
|
2014
|
+
...values[HOST_URL_ENV] ? { [HOST_URL_ENV]: values[HOST_URL_ENV] } : {},
|
|
2015
|
+
...values[API_KEY_ENV] ? { [API_KEY_ENV]: values[API_KEY_ENV] } : {}
|
|
2016
|
+
};
|
|
2017
|
+
saveHostEnvValues(baseUrl, filtered);
|
|
2037
2018
|
}
|
|
2038
2019
|
async function httpJson(method, url, apiKey, body) {
|
|
2039
2020
|
const headers = { "Content-Type": "application/json" };
|
|
@@ -2139,9 +2120,9 @@ async function handleRegister(args) {
|
|
|
2139
2120
|
const claimUrl = String(data.claim_url || "");
|
|
2140
2121
|
const claimToken = String(data.claim_token || "");
|
|
2141
2122
|
if (claimToken) {
|
|
2123
|
+
savePendingClaimToken(baseUrl, claimToken);
|
|
2142
2124
|
saveEnvValues({
|
|
2143
|
-
|
|
2144
|
-
DEEPLINE_CLAIM_TOKEN: claimToken
|
|
2125
|
+
[HOST_URL_ENV]: baseUrl
|
|
2145
2126
|
}, baseUrl);
|
|
2146
2127
|
}
|
|
2147
2128
|
if (claimUrl) {
|
|
@@ -2165,6 +2146,7 @@ async function handleRegister(args) {
|
|
|
2165
2146
|
{ claim_token: claimToken, reveal: true }
|
|
2166
2147
|
);
|
|
2167
2148
|
if (s === 401 || s === 403) {
|
|
2149
|
+
clearPendingClaimToken(baseUrl);
|
|
2168
2150
|
console.log("Status: unauthorized");
|
|
2169
2151
|
return EXIT_AUTH;
|
|
2170
2152
|
}
|
|
@@ -2181,15 +2163,16 @@ async function handleRegister(args) {
|
|
|
2181
2163
|
const apiKey = String(statusData.api_key || "");
|
|
2182
2164
|
if (apiKey) {
|
|
2183
2165
|
saveEnvValues({
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
DEEPLINE_CLAIM_TOKEN: ""
|
|
2166
|
+
[HOST_URL_ENV]: baseUrl,
|
|
2167
|
+
[API_KEY_ENV]: apiKey
|
|
2187
2168
|
}, baseUrl);
|
|
2169
|
+
clearPendingClaimToken(baseUrl);
|
|
2188
2170
|
printClaimSuccessBanner(statusData);
|
|
2189
2171
|
return EXIT_OK;
|
|
2190
2172
|
}
|
|
2191
2173
|
}
|
|
2192
2174
|
if (state === "expired") {
|
|
2175
|
+
clearPendingClaimToken(baseUrl);
|
|
2193
2176
|
console.log("That approval link expired. Please run: deepline auth register");
|
|
2194
2177
|
return EXIT_AUTH;
|
|
2195
2178
|
}
|
|
@@ -2207,13 +2190,12 @@ async function handleWait(args) {
|
|
|
2207
2190
|
}
|
|
2208
2191
|
}
|
|
2209
2192
|
}
|
|
2210
|
-
const
|
|
2211
|
-
if (env.DEEPLINE_API_KEY?.trim()) {
|
|
2212
|
-
console.log("Already connected.");
|
|
2213
|
-
return EXIT_OK;
|
|
2214
|
-
}
|
|
2215
|
-
const claimToken = env.DEEPLINE_CLAIM_TOKEN?.trim() || "";
|
|
2193
|
+
const claimToken = readPendingClaimToken(baseUrl);
|
|
2216
2194
|
if (!claimToken) {
|
|
2195
|
+
if (resolveApiKeyForBaseUrl(baseUrl)) {
|
|
2196
|
+
console.log("Already connected.");
|
|
2197
|
+
return EXIT_OK;
|
|
2198
|
+
}
|
|
2217
2199
|
console.error("No pending approval. Run: deepline auth register --no-wait");
|
|
2218
2200
|
return EXIT_AUTH;
|
|
2219
2201
|
}
|
|
@@ -2226,6 +2208,7 @@ async function handleWait(args) {
|
|
|
2226
2208
|
{ claim_token: claimToken, reveal: true }
|
|
2227
2209
|
);
|
|
2228
2210
|
if (status === 401 || status === 403) {
|
|
2211
|
+
clearPendingClaimToken(baseUrl);
|
|
2229
2212
|
console.error("Claim is invalid. Run: deepline auth register");
|
|
2230
2213
|
return EXIT_AUTH;
|
|
2231
2214
|
}
|
|
@@ -2242,15 +2225,16 @@ async function handleWait(args) {
|
|
|
2242
2225
|
const apiKey = String(data.api_key || "");
|
|
2243
2226
|
if (apiKey) {
|
|
2244
2227
|
saveEnvValues({
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
DEEPLINE_CLAIM_TOKEN: ""
|
|
2228
|
+
[HOST_URL_ENV]: baseUrl,
|
|
2229
|
+
[API_KEY_ENV]: apiKey
|
|
2248
2230
|
}, baseUrl);
|
|
2231
|
+
clearPendingClaimToken(baseUrl);
|
|
2249
2232
|
printClaimSuccessBanner(data);
|
|
2250
2233
|
return EXIT_OK;
|
|
2251
2234
|
}
|
|
2252
2235
|
}
|
|
2253
2236
|
if (state === "expired") {
|
|
2237
|
+
clearPendingClaimToken(baseUrl);
|
|
2254
2238
|
console.error("That approval link expired. Run: deepline auth register");
|
|
2255
2239
|
return EXIT_AUTH;
|
|
2256
2240
|
}
|
|
@@ -2285,10 +2269,9 @@ async function handleStatus(args) {
|
|
|
2285
2269
|
};
|
|
2286
2270
|
hostLines.push(`Host: ${baseUrl} (unreachable)`);
|
|
2287
2271
|
}
|
|
2288
|
-
const
|
|
2289
|
-
const apiKey = process.env.DEEPLINE_API_KEY?.trim() || env.DEEPLINE_API_KEY || "";
|
|
2272
|
+
const apiKey = resolveApiKeyForBaseUrl(baseUrl);
|
|
2290
2273
|
if (!apiKey) {
|
|
2291
|
-
if (
|
|
2274
|
+
if (readPendingClaimToken(baseUrl)) {
|
|
2292
2275
|
printCommandEnvelope({
|
|
2293
2276
|
...hostStatusPayload ?? { host: baseUrl },
|
|
2294
2277
|
status: "pending",
|
|
@@ -2334,6 +2317,7 @@ async function handleStatus(args) {
|
|
|
2334
2317
|
console.error(`Auth status error (status ${status}).`);
|
|
2335
2318
|
return EXIT_SERVER;
|
|
2336
2319
|
}
|
|
2320
|
+
clearPendingClaimToken(baseUrl);
|
|
2337
2321
|
const payload = {
|
|
2338
2322
|
...hostStatusPayload ?? { host: baseUrl },
|
|
2339
2323
|
status: data.status || "(unknown)",
|
|
@@ -2354,9 +2338,8 @@ async function handleStatus(args) {
|
|
|
2354
2338
|
const apiKeyResp = String(data.api_key || apiKey);
|
|
2355
2339
|
if (apiKeyResp) {
|
|
2356
2340
|
saveEnvValues({
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
DEEPLINE_CLAIM_TOKEN: ""
|
|
2341
|
+
[HOST_URL_ENV]: baseUrl,
|
|
2342
|
+
[API_KEY_ENV]: apiKeyResp
|
|
2360
2343
|
}, baseUrl);
|
|
2361
2344
|
savedApiKeyPath = envFilePath(baseUrl);
|
|
2362
2345
|
}
|
|
@@ -5843,10 +5826,6 @@ function openPlayDashboard(input) {
|
|
|
5843
5826
|
}
|
|
5844
5827
|
openInBrowser(input.dashboardUrl);
|
|
5845
5828
|
}
|
|
5846
|
-
function getDashboardUrlFromLiveEvent(event) {
|
|
5847
|
-
const dashboardUrl = getEventPayload(event).dashboardUrl;
|
|
5848
|
-
return typeof dashboardUrl === "string" && dashboardUrl.trim() ? dashboardUrl.trim() : null;
|
|
5849
|
-
}
|
|
5850
5829
|
function printPlayLogLines(input) {
|
|
5851
5830
|
for (const line of input.lines) {
|
|
5852
5831
|
if (input.emitLogs) {
|
|
@@ -5915,7 +5894,7 @@ async function waitForPlayCompletionByStream(input) {
|
|
|
5915
5894
|
billing: false
|
|
5916
5895
|
});
|
|
5917
5896
|
if (TERMINAL_PLAY_STATUSES2.has(finalStatus.status)) {
|
|
5918
|
-
return finalStatus;
|
|
5897
|
+
return input.dashboardUrl ? { ...finalStatus, dashboardUrl: input.dashboardUrl } : finalStatus;
|
|
5919
5898
|
}
|
|
5920
5899
|
}
|
|
5921
5900
|
}
|
|
@@ -5943,6 +5922,10 @@ async function waitForPlayCompletionByStream(input) {
|
|
|
5943
5922
|
}
|
|
5944
5923
|
async function startAndWaitForPlayCompletionByStream(input) {
|
|
5945
5924
|
const startedAt = Date.now();
|
|
5925
|
+
const dashboardUrl = buildPlayDashboardUrl(
|
|
5926
|
+
input.client.baseUrl,
|
|
5927
|
+
input.playName
|
|
5928
|
+
);
|
|
5946
5929
|
const state = {
|
|
5947
5930
|
lastLogIndex: 0,
|
|
5948
5931
|
emittedRunnerStarted: false
|
|
@@ -5973,7 +5956,6 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
5973
5956
|
}
|
|
5974
5957
|
const workflowId = lastKnownWorkflowId || "pending";
|
|
5975
5958
|
if (workflowId !== "pending" && !emittedDashboardUrl) {
|
|
5976
|
-
const dashboardUrl = getDashboardUrlFromLiveEvent(event) ?? buildPlayDashboardUrl(input.client.baseUrl, input.playName);
|
|
5977
5959
|
openPlayDashboard({
|
|
5978
5960
|
dashboardUrl,
|
|
5979
5961
|
jsonOutput: input.jsonOutput,
|
|
@@ -6022,7 +6004,7 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
6022
6004
|
firstRunIdMs,
|
|
6023
6005
|
lastPhase
|
|
6024
6006
|
});
|
|
6025
|
-
return finalStatus;
|
|
6007
|
+
return { ...finalStatus, dashboardUrl };
|
|
6026
6008
|
}
|
|
6027
6009
|
}
|
|
6028
6010
|
} catch (error) {
|
|
@@ -6059,6 +6041,7 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
6059
6041
|
return waitForPlayCompletionByStream({
|
|
6060
6042
|
client: input.client,
|
|
6061
6043
|
workflowId: lastKnownWorkflowId,
|
|
6044
|
+
dashboardUrl,
|
|
6062
6045
|
jsonOutput: input.jsonOutput,
|
|
6063
6046
|
emitLogs: input.emitLogs,
|
|
6064
6047
|
waitTimeoutMs: input.waitTimeoutMs,
|
|
@@ -6093,6 +6076,7 @@ async function startAndWaitForPlayCompletionByStream(input) {
|
|
|
6093
6076
|
return waitForPlayCompletionByStream({
|
|
6094
6077
|
client: input.client,
|
|
6095
6078
|
workflowId: lastKnownWorkflowId,
|
|
6079
|
+
dashboardUrl,
|
|
6096
6080
|
jsonOutput: input.jsonOutput,
|
|
6097
6081
|
emitLogs: input.emitLogs,
|
|
6098
6082
|
waitTimeoutMs: input.waitTimeoutMs,
|
|
@@ -6263,12 +6247,16 @@ function buildRunWarnings(status, rowsInfo) {
|
|
|
6263
6247
|
}
|
|
6264
6248
|
return [];
|
|
6265
6249
|
}
|
|
6266
|
-
function buildRunNextCommands(runId) {
|
|
6267
|
-
|
|
6250
|
+
function buildRunNextCommands(runId, dashboardUrl) {
|
|
6251
|
+
const commands = {
|
|
6268
6252
|
get: `deepline runs get ${runId} --json`,
|
|
6269
6253
|
stop: `deepline runs stop ${runId} --reason "stale lock" --json`,
|
|
6270
6254
|
logs: `deepline runs logs ${runId} --out run.log --json`
|
|
6271
6255
|
};
|
|
6256
|
+
if (dashboardUrl) {
|
|
6257
|
+
commands.open = `Open ${dashboardUrl} to see results.`;
|
|
6258
|
+
}
|
|
6259
|
+
return commands;
|
|
6272
6260
|
}
|
|
6273
6261
|
var RUN_LOG_PREVIEW_LIMIT = 20;
|
|
6274
6262
|
function getRecordField(value, key) {
|
|
@@ -6404,6 +6392,7 @@ function compactPlayStatus(status) {
|
|
|
6404
6392
|
apiVersion: status.apiVersion ?? 1,
|
|
6405
6393
|
...typeof status.name === "string" ? { name: status.name } : {},
|
|
6406
6394
|
...typeof status.playName === "string" ? { playName: status.playName } : {},
|
|
6395
|
+
...status.dashboardUrl ? { dashboardUrl: status.dashboardUrl } : {},
|
|
6407
6396
|
status: status.status,
|
|
6408
6397
|
run: normalizeRunStatusForEnvelope(status),
|
|
6409
6398
|
progress: normalizeProgressForEnvelope(status, rowsInfo),
|
|
@@ -6416,7 +6405,7 @@ function compactPlayStatus(status) {
|
|
|
6416
6405
|
...status.resultView ? { resultView: status.resultView } : {},
|
|
6417
6406
|
...datasetStats ? { dataset_stats: datasetStats } : {},
|
|
6418
6407
|
...billing ? { billing } : {},
|
|
6419
|
-
next: buildRunNextCommands(status.runId)
|
|
6408
|
+
next: buildRunNextCommands(status.runId, status.dashboardUrl)
|
|
6420
6409
|
};
|
|
6421
6410
|
}
|
|
6422
6411
|
function enrichPlayStatusWithDatasetStats(status) {
|
|
@@ -6629,7 +6618,7 @@ async function exportPlayStatusRows(client, status, outPath, options = {}) {
|
|
|
6629
6618
|
return null;
|
|
6630
6619
|
}
|
|
6631
6620
|
const availableRows = collectSerializedDatasetRowsInfos(status);
|
|
6632
|
-
|
|
6621
|
+
const rowsInfo = options.datasetPath ? availableRows.find((info) => info.source === options.datasetPath) ?? null : availableRows.length === 1 ? availableRows[0] : null;
|
|
6633
6622
|
if (!rowsInfo && options.datasetPath) {
|
|
6634
6623
|
const available = availableRows.map((info) => info.source).filter((source) => typeof source === "string");
|
|
6635
6624
|
throw new DeeplineError(
|
|
@@ -7112,8 +7101,7 @@ async function handleFileBackedRun(options) {
|
|
|
7112
7101
|
{ targetKind: "file", playName },
|
|
7113
7102
|
() => client.startPlayRun(startRequest)
|
|
7114
7103
|
);
|
|
7115
|
-
const
|
|
7116
|
-
const resolvedDashboardUrl = started.dashboardUrl ?? dashboardUrl;
|
|
7104
|
+
const resolvedDashboardUrl = buildPlayDashboardUrl(client.baseUrl, playName);
|
|
7117
7105
|
openPlayDashboard({
|
|
7118
7106
|
dashboardUrl: resolvedDashboardUrl,
|
|
7119
7107
|
jsonOutput: options.jsonOutput,
|
|
@@ -7248,11 +7236,7 @@ async function handleNamedRun(options) {
|
|
|
7248
7236
|
{ targetKind: "name", playName },
|
|
7249
7237
|
() => client.startPlayRun(startRequest)
|
|
7250
7238
|
);
|
|
7251
|
-
const
|
|
7252
|
-
client.baseUrl,
|
|
7253
|
-
playName
|
|
7254
|
-
);
|
|
7255
|
-
const resolvedDashboardUrl = started.dashboardUrl ?? dashboardUrl;
|
|
7239
|
+
const resolvedDashboardUrl = buildPlayDashboardUrl(client.baseUrl, playName);
|
|
7256
7240
|
openPlayDashboard({
|
|
7257
7241
|
dashboardUrl: resolvedDashboardUrl,
|
|
7258
7242
|
jsonOutput: options.jsonOutput,
|
|
@@ -9251,7 +9235,7 @@ async function executeTool(args) {
|
|
|
9251
9235
|
}
|
|
9252
9236
|
|
|
9253
9237
|
// src/cli/commands/update.ts
|
|
9254
|
-
var
|
|
9238
|
+
var import_node_child_process = require("child_process");
|
|
9255
9239
|
var import_node_fs10 = require("fs");
|
|
9256
9240
|
var import_node_path12 = require("path");
|
|
9257
9241
|
function posixShellQuote(value) {
|
|
@@ -9303,7 +9287,7 @@ function resolveUpdatePlan() {
|
|
|
9303
9287
|
}
|
|
9304
9288
|
function runCommand(command, args) {
|
|
9305
9289
|
return new Promise((resolveExitCode) => {
|
|
9306
|
-
const child = (0,
|
|
9290
|
+
const child = (0, import_node_child_process.spawn)(command, args, {
|
|
9307
9291
|
stdio: "inherit",
|
|
9308
9292
|
shell: process.platform === "win32",
|
|
9309
9293
|
env: process.env
|
|
@@ -9376,7 +9360,7 @@ Examples:
|
|
|
9376
9360
|
}
|
|
9377
9361
|
|
|
9378
9362
|
// src/cli/skills-sync.ts
|
|
9379
|
-
var
|
|
9363
|
+
var import_node_child_process2 = require("child_process");
|
|
9380
9364
|
var import_node_fs11 = require("fs");
|
|
9381
9365
|
var import_node_os8 = require("os");
|
|
9382
9366
|
var import_node_path13 = require("path");
|
|
@@ -9468,7 +9452,7 @@ function buildBunxSkillsInstallArgs(baseUrl) {
|
|
|
9468
9452
|
];
|
|
9469
9453
|
}
|
|
9470
9454
|
function hasCommand(command) {
|
|
9471
|
-
const result = (0,
|
|
9455
|
+
const result = (0, import_node_child_process2.spawnSync)(command, ["--version"], {
|
|
9472
9456
|
stdio: "ignore",
|
|
9473
9457
|
shell: process.platform === "win32"
|
|
9474
9458
|
});
|
|
@@ -9499,7 +9483,7 @@ function resolveSkillsInstallCommands(baseUrl) {
|
|
|
9499
9483
|
}
|
|
9500
9484
|
function runOneSkillsInstall(install) {
|
|
9501
9485
|
return new Promise((resolve10) => {
|
|
9502
|
-
const child = (0,
|
|
9486
|
+
const child = (0, import_node_child_process2.spawn)(install.command, install.args, {
|
|
9503
9487
|
stdio: ["ignore", "ignore", "pipe"],
|
|
9504
9488
|
env: process.env
|
|
9505
9489
|
});
|