deepline 0.1.31 → 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 +169 -188
- package/dist/cli/index.mjs +180 -199
- 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-
|
|
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
|
}
|
|
@@ -5572,7 +5555,7 @@ function inputContainsLocalFilePath(value) {
|
|
|
5572
5555
|
return false;
|
|
5573
5556
|
}
|
|
5574
5557
|
function namedRunNeedsPlayDefinition(input) {
|
|
5575
|
-
return input.revisionSelector === "latest" ||
|
|
5558
|
+
return input.revisionSelector === "latest" || inputContainsLocalFilePath(input.runtimeInput);
|
|
5576
5559
|
}
|
|
5577
5560
|
async function stageFileInputArgs(input) {
|
|
5578
5561
|
const uniqueBindings = [
|
|
@@ -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(
|
|
@@ -6874,11 +6863,6 @@ function parsePlayRunOptions(args) {
|
|
|
6874
6863
|
}
|
|
6875
6864
|
continue;
|
|
6876
6865
|
}
|
|
6877
|
-
if (arg === "--csv" || arg.startsWith("--csv=")) {
|
|
6878
|
-
throw new Error(
|
|
6879
|
-
`--csv is not a plays run flag. Pass CSV paths through --input, for example: deepline plays run my.play.ts --input '{"file":"leads.csv"}' --watch`
|
|
6880
|
-
);
|
|
6881
|
-
}
|
|
6882
6866
|
if (arg.startsWith("--")) {
|
|
6883
6867
|
const { path, value } = parseInputFieldFlag(arg, args[index + 1]);
|
|
6884
6868
|
input ??= {};
|
|
@@ -7117,8 +7101,7 @@ async function handleFileBackedRun(options) {
|
|
|
7117
7101
|
{ targetKind: "file", playName },
|
|
7118
7102
|
() => client.startPlayRun(startRequest)
|
|
7119
7103
|
);
|
|
7120
|
-
const
|
|
7121
|
-
const resolvedDashboardUrl = started.dashboardUrl ?? dashboardUrl;
|
|
7104
|
+
const resolvedDashboardUrl = buildPlayDashboardUrl(client.baseUrl, playName);
|
|
7122
7105
|
openPlayDashboard({
|
|
7123
7106
|
dashboardUrl: resolvedDashboardUrl,
|
|
7124
7107
|
jsonOutput: options.jsonOutput,
|
|
@@ -7253,11 +7236,7 @@ async function handleNamedRun(options) {
|
|
|
7253
7236
|
{ targetKind: "name", playName },
|
|
7254
7237
|
() => client.startPlayRun(startRequest)
|
|
7255
7238
|
);
|
|
7256
|
-
const
|
|
7257
|
-
client.baseUrl,
|
|
7258
|
-
playName
|
|
7259
|
-
);
|
|
7260
|
-
const resolvedDashboardUrl = started.dashboardUrl ?? dashboardUrl;
|
|
7239
|
+
const resolvedDashboardUrl = buildPlayDashboardUrl(client.baseUrl, playName);
|
|
7261
7240
|
openPlayDashboard({
|
|
7262
7241
|
dashboardUrl: resolvedDashboardUrl,
|
|
7263
7242
|
jsonOutput: options.jsonOutput,
|
|
@@ -8026,8 +8005,10 @@ Examples:
|
|
|
8026
8005
|
Pass-through input flags:
|
|
8027
8006
|
Unknown flags are accepted intentionally and become play input fields. Use
|
|
8028
8007
|
this for play-specific inputs like --limit 5 or --filters.title "GTM Engineer".
|
|
8029
|
-
For CSV file inputs,
|
|
8030
|
-
|
|
8008
|
+
For CSV file inputs, the play owns the field name: --csv leads.csv becomes
|
|
8009
|
+
input.csv, and --columns.email "Email" becomes input.columns.email. Reserved
|
|
8010
|
+
run flags like --file and --name keep their command meaning; pass fields with
|
|
8011
|
+
those names through --input '{"file":"leads.csv"}'.
|
|
8031
8012
|
`
|
|
8032
8013
|
).action(async (target, options, command) => {
|
|
8033
8014
|
const passthroughArgs = [...command.args];
|
|
@@ -9254,7 +9235,7 @@ async function executeTool(args) {
|
|
|
9254
9235
|
}
|
|
9255
9236
|
|
|
9256
9237
|
// src/cli/commands/update.ts
|
|
9257
|
-
var
|
|
9238
|
+
var import_node_child_process = require("child_process");
|
|
9258
9239
|
var import_node_fs10 = require("fs");
|
|
9259
9240
|
var import_node_path12 = require("path");
|
|
9260
9241
|
function posixShellQuote(value) {
|
|
@@ -9306,7 +9287,7 @@ function resolveUpdatePlan() {
|
|
|
9306
9287
|
}
|
|
9307
9288
|
function runCommand(command, args) {
|
|
9308
9289
|
return new Promise((resolveExitCode) => {
|
|
9309
|
-
const child = (0,
|
|
9290
|
+
const child = (0, import_node_child_process.spawn)(command, args, {
|
|
9310
9291
|
stdio: "inherit",
|
|
9311
9292
|
shell: process.platform === "win32",
|
|
9312
9293
|
env: process.env
|
|
@@ -9379,7 +9360,7 @@ Examples:
|
|
|
9379
9360
|
}
|
|
9380
9361
|
|
|
9381
9362
|
// src/cli/skills-sync.ts
|
|
9382
|
-
var
|
|
9363
|
+
var import_node_child_process2 = require("child_process");
|
|
9383
9364
|
var import_node_fs11 = require("fs");
|
|
9384
9365
|
var import_node_os8 = require("os");
|
|
9385
9366
|
var import_node_path13 = require("path");
|
|
@@ -9471,7 +9452,7 @@ function buildBunxSkillsInstallArgs(baseUrl) {
|
|
|
9471
9452
|
];
|
|
9472
9453
|
}
|
|
9473
9454
|
function hasCommand(command) {
|
|
9474
|
-
const result = (0,
|
|
9455
|
+
const result = (0, import_node_child_process2.spawnSync)(command, ["--version"], {
|
|
9475
9456
|
stdio: "ignore",
|
|
9476
9457
|
shell: process.platform === "win32"
|
|
9477
9458
|
});
|
|
@@ -9502,7 +9483,7 @@ function resolveSkillsInstallCommands(baseUrl) {
|
|
|
9502
9483
|
}
|
|
9503
9484
|
function runOneSkillsInstall(install) {
|
|
9504
9485
|
return new Promise((resolve10) => {
|
|
9505
|
-
const child = (0,
|
|
9486
|
+
const child = (0, import_node_child_process2.spawn)(install.command, install.args, {
|
|
9506
9487
|
stdio: ["ignore", "ignore", "pipe"],
|
|
9507
9488
|
env: process.env
|
|
9508
9489
|
});
|