deepline 0.3.293 → 0.3.295
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/bundling-sources/sdk/src/compat.ts +35 -7
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres-pool.ts +269 -267
- package/dist/bundling-sources/shared_libs/play-runtime/scheduler-backends/postgres.ts +3 -4
- package/dist/bundling-sources/shared_libs/play-runtime/tool-http-errors.ts +14 -1
- package/dist/cli/auth-EDTRERZP.mjs +31 -0
- package/dist/cli/auth-TDHKB277.js +31 -0
- package/dist/cli/billing-ELIDPILY.js +1749 -0
- package/dist/cli/billing-EXGXJVAU.mjs +1749 -0
- package/dist/cli/chunk-2S5Y3TZP.js +5688 -0
- package/dist/cli/chunk-3KC45UVF.js +150 -0
- package/dist/cli/chunk-3XX5TEA4.js +15 -0
- package/dist/cli/chunk-4MBOJQPL.mjs +0 -0
- package/dist/cli/chunk-4NEFYBF7.js +2240 -0
- package/dist/cli/chunk-5JLQPVNX.js +3056 -0
- package/dist/cli/chunk-5KDKFHZI.js +1269 -0
- package/dist/cli/chunk-6A3TJUWC.js +76 -0
- package/dist/cli/chunk-6O5YZOVN.mjs +890 -0
- package/dist/cli/chunk-7P5AA3SN.js +344 -0
- package/dist/cli/chunk-AYHLUHE5.js +52 -0
- package/dist/cli/chunk-CBVIJSHF.mjs +560 -0
- package/dist/cli/chunk-CFVVCN4A.js +735 -0
- package/dist/cli/chunk-COGTRVWW.js +30 -0
- package/dist/cli/chunk-D4AZUZO4.js +190 -0
- package/dist/cli/chunk-DLIRSHV6.mjs +28 -0
- package/dist/cli/chunk-EACVZI6N.mjs +1995 -0
- package/dist/cli/chunk-EDWJY6T4.mjs +3056 -0
- package/dist/cli/chunk-EXMLR72R.mjs +0 -0
- package/dist/cli/chunk-F35VOIQL.js +890 -0
- package/dist/cli/chunk-GAMFK2ZP.mjs +148 -0
- package/dist/cli/chunk-GHRQQPW2.mjs +2240 -0
- package/dist/cli/chunk-GONRLVV3.js +3440 -0
- package/dist/cli/chunk-GVUJJJ5G.mjs +76 -0
- package/dist/cli/chunk-H7HIDGZ7.mjs +150 -0
- package/dist/cli/chunk-HUZXWOSK.mjs +503 -0
- package/dist/cli/chunk-I5YZLGMG.js +1 -0
- package/dist/cli/chunk-ITOFSXIU.mjs +15 -0
- package/dist/cli/chunk-J5NA2TTX.js +503 -0
- package/dist/cli/chunk-JCS5TPNY.mjs +3440 -0
- package/dist/cli/chunk-JNNOCMQY.js +47 -0
- package/dist/cli/chunk-KRD6H754.mjs +30 -0
- package/dist/cli/chunk-LA46MMTL.js +560 -0
- package/dist/cli/chunk-LDWT7RJK.mjs +190 -0
- package/dist/cli/chunk-M2V26OR5.js +499 -0
- package/dist/cli/chunk-MIMASXO4.mjs +389 -0
- package/dist/cli/chunk-MROPCKW2.mjs +190 -0
- package/dist/cli/chunk-NXDRDJ4K.js +389 -0
- package/dist/cli/chunk-NXGCO4JB.mjs +344 -0
- package/dist/cli/chunk-OG64RBAC.js +6 -0
- package/dist/cli/chunk-OQYEC4GL.mjs +34 -0
- package/dist/cli/chunk-OWJZUE3Y.mjs +103 -0
- package/dist/cli/chunk-SDK3ZA2C.js +103 -0
- package/dist/cli/chunk-SFLARO4Y.mjs +47 -0
- package/dist/cli/chunk-SVIIIYIQ.js +923 -0
- package/dist/cli/chunk-TAC3JIFE.mjs +354 -0
- package/dist/cli/chunk-U3PI7HBM.js +34 -0
- package/dist/cli/chunk-UFS752TU.mjs +52 -0
- package/dist/cli/chunk-UI37DQE7.mjs +499 -0
- package/dist/cli/chunk-UNEMDKXN.js +1 -0
- package/dist/cli/chunk-WB6Z2Q44.mjs +1622 -0
- package/dist/cli/chunk-WJYPBHTE.js +148 -0
- package/dist/cli/chunk-WOHBA5PV.js +354 -0
- package/dist/cli/chunk-WQICC2B3.js +190 -0
- package/dist/cli/chunk-WZYKRD7T.mjs +6 -0
- package/dist/cli/chunk-XL2FO6CW.mjs +5688 -0
- package/dist/cli/chunk-XNYIZMNQ.js +28 -0
- package/dist/cli/chunk-XRK2TZT5.js +1995 -0
- package/dist/cli/chunk-YJYPL5OK.mjs +1269 -0
- package/dist/cli/chunk-YWNDYCXR.mjs +735 -0
- package/dist/cli/chunk-YWWAF7KZ.mjs +923 -0
- package/dist/cli/chunk-ZDO3TO3M.js +1622 -0
- package/dist/cli/client-4JVOYVC5.js +20 -0
- package/dist/cli/client-EEN2IJN2.mjs +20 -0
- package/dist/cli/csv-BOHBEP2I.mjs +585 -0
- package/dist/cli/csv-S5NYRUEX.js +585 -0
- package/dist/cli/db-CLODWCOB.mjs +486 -0
- package/dist/cli/db-F6PKFOOV.js +486 -0
- package/dist/cli/executions-5TQAKLJU.js +28 -0
- package/dist/cli/executions-MAKW6QOY.mjs +28 -0
- package/dist/cli/feedback-GV4QJFEN.js +107 -0
- package/dist/cli/feedback-XY24TW7H.mjs +107 -0
- package/dist/cli/getting-started.js +18 -76
- package/dist/cli/getting-started.mjs +10 -37
- package/dist/cli/git-6S2C22T5.js +23 -0
- package/dist/cli/git-OZLBD5HH.mjs +23 -0
- package/dist/cli/index.js +291 -54294
- package/dist/cli/index.mjs +209 -54352
- package/dist/cli/legacy-noops-LLCGDPQE.js +157 -0
- package/dist/cli/legacy-noops-TYH3TW2D.mjs +157 -0
- package/dist/cli/monitors-CABMB4DW.js +3251 -0
- package/dist/cli/monitors-TTD55HMK.mjs +3251 -0
- package/dist/cli/org-MSF3RG76.js +849 -0
- package/dist/cli/org-SFJ77MWY.mjs +849 -0
- package/dist/cli/play-NXHJSCKL.mjs +18439 -0
- package/dist/cli/play-OKSFNNO4.js +18439 -0
- package/dist/cli/providers-QC2ERERL.js +95 -0
- package/dist/cli/providers-TIIAZEUA.mjs +95 -0
- package/dist/cli/proxy-env-EBANZHPV.js +161 -0
- package/dist/cli/proxy-env-M4ZHXHRL.mjs +161 -0
- package/dist/cli/quickstart-ICANHLMI.js +69 -0
- package/dist/cli/quickstart-KWUOP3FI.mjs +69 -0
- package/dist/cli/search-U5H2FDOO.mjs +18 -0
- package/dist/cli/search-XQRQOLWS.js +18 -0
- package/dist/cli/secrets-3J6YTWFA.mjs +400 -0
- package/dist/cli/secrets-YNMNZNOM.js +400 -0
- package/dist/cli/sessions-CLEES4L6.mjs +15 -0
- package/dist/cli/sessions-J6VR47FG.js +15 -0
- package/dist/cli/settings-EEKZMTY4.js +846 -0
- package/dist/cli/settings-UVLOQZRH.mjs +846 -0
- package/dist/cli/setup-DLMDXPGJ.mjs +1257 -0
- package/dist/cli/setup-HC4Q7QM4.js +1257 -0
- package/dist/cli/skills-33PHFBSB.mjs +28 -0
- package/dist/cli/skills-LFRY3KPX.js +28 -0
- package/dist/cli/tools-3COEPKML.mjs +2955 -0
- package/dist/cli/tools-QXEVCN45.js +2955 -0
- package/dist/cli/update-LSAC4FF5.mjs +28 -0
- package/dist/cli/update-NXHSPYXA.js +28 -0
- package/dist/cli/workflow-7S44OECF.mjs +1936 -0
- package/dist/cli/workflow-QPZWYSZE.js +1936 -0
- package/dist/helpers.js +6 -32
- package/dist/helpers.mjs +2 -0
- package/dist/index.js +1972 -12825
- package/dist/index.mjs +1910 -12672
- package/dist/install-integrity.json +110 -0
- package/dist/monitor-fleet-contract.js +31 -730
- package/dist/monitor-fleet-contract.mjs +18 -667
- package/dist/monitor-input-contract.js +10 -390
- package/dist/monitor-input-contract.mjs +7 -348
- package/dist/plays/bundle-play-file.mjs +13 -5178
- package/dist/plays/csv-data-input.js +5 -3132
- package/dist/plays/csv-data-input.mjs +5 -3105
- package/dist/plays/run-request.js +56 -664
- package/dist/plays/run-request.mjs +30 -588
- package/dist/release.d.mts +1 -1
- package/dist/release.d.ts +1 -1
- package/dist/release.js +5 -212
- package/dist/release.mjs +5 -185
- package/package.json +1 -1
|
@@ -0,0 +1,890 @@
|
|
|
1
|
+
import {
|
|
2
|
+
HttpClient,
|
|
3
|
+
detectAgentRuntime,
|
|
4
|
+
resolveCliCommandContext,
|
|
5
|
+
resolveConfig
|
|
6
|
+
} from "./chunk-EACVZI6N.mjs";
|
|
7
|
+
import {
|
|
8
|
+
DeeplineError
|
|
9
|
+
} from "./chunk-NXGCO4JB.mjs";
|
|
10
|
+
|
|
11
|
+
// src/cli/json-fields.ts
|
|
12
|
+
var RUN_FIELDS = new Set(
|
|
13
|
+
"id playName status dashboardUrl acceptedAt updatedAt startedAt finishedAt durationMs revisionId recovery error activity work".split(
|
|
14
|
+
" "
|
|
15
|
+
)
|
|
16
|
+
);
|
|
17
|
+
var ROOTS = {
|
|
18
|
+
describe: "name playKey reference displayName description pinned toolCategories tags origin ownerType canEdit canClone aliases inputSchema outputSchema staticPipeline csvInput rowOutputSchema runCommand examples cloneEditStarter currentPublishedVersion liveVersion triggerStatus triggerMetadata isDraftDirty latestRunId runtimeLimit activeScheduledPlays command_context",
|
|
19
|
+
check: "kind target checked scope name exportName valid stage issues inputSchema outputSchema recognized triggers runtimeLimit limits featureFlags sourceHash artifactHash graphHash toolGetterHints exports actions diagnostics reference origin ownerType activeScheduledPlays command_context",
|
|
20
|
+
run: "schemaVersion kind run datasets actions apiVersion dashboardUrl progress rowOutcomes steps errors error warnings result resultState execution command_context diagnostics",
|
|
21
|
+
get: "schemaVersion kind run runStatus steps failures errorDetails rowOutcomes warnings failedLogs datasets result resultState actions diagnostics command_context",
|
|
22
|
+
config: "runId contract command_context",
|
|
23
|
+
export: "runId datasets csv_path json_path format source rowCount columns notice metadata_path actions command_context"
|
|
24
|
+
};
|
|
25
|
+
function parseJsonFields(args, surface) {
|
|
26
|
+
const normalized = [];
|
|
27
|
+
let fields;
|
|
28
|
+
const allowed = new Set(ROOTS[surface].split(" "));
|
|
29
|
+
for (let i = 0; i < args.length; i++) {
|
|
30
|
+
const arg = args[i];
|
|
31
|
+
if (arg !== "--json" && !arg.startsWith("--json=")) {
|
|
32
|
+
normalized.push(arg);
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
normalized.push("--json");
|
|
36
|
+
const value = arg.startsWith("--json=") ? arg.slice(7) : args[i + 1] && !args[i + 1].startsWith("-") ? args[++i] : void 0;
|
|
37
|
+
if (value === void 0) continue;
|
|
38
|
+
const paths = value.split(",").map((path) => path.trim());
|
|
39
|
+
for (const path of paths) {
|
|
40
|
+
const parts = path.split(".");
|
|
41
|
+
if (parts.some(
|
|
42
|
+
(part) => !/^[a-zA-Z_][a-zA-Z_0-9]*$/.test(part) || ["__proto__", "prototype", "constructor"].includes(part)
|
|
43
|
+
) || !allowed.has(parts[0])) {
|
|
44
|
+
throw new DeeplineError(
|
|
45
|
+
`Unknown --json field '${path}'. Available roots: ${[...allowed].join(", ")}.`,
|
|
46
|
+
void 0,
|
|
47
|
+
"INVALID_ARGUMENT"
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
if (parts[0] === "run" && parts[1] && !RUN_FIELDS.has(parts[1])) {
|
|
51
|
+
const hint = parts[1] === "url" ? " Use run.dashboardUrl." : parts[1] === "stats" ? " Dataset summaries are in datasets; run timing is in run.durationMs." : "";
|
|
52
|
+
throw new DeeplineError(
|
|
53
|
+
`Unknown --json run field '${parts[1]}'. Available: ${[...RUN_FIELDS].join(", ")}.${hint}`,
|
|
54
|
+
void 0,
|
|
55
|
+
"INVALID_ARGUMENT"
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
if (parts[0] === "diagnostics" && !args.includes("--full")) {
|
|
59
|
+
const target = args[0] && !args[0].startsWith("-") ? args[0] : "<target>";
|
|
60
|
+
const command = surface === "get" ? "runs get" : `plays ${surface}`;
|
|
61
|
+
const quotedTarget = `'${target.replace(/'/g, "'\\''")}'`;
|
|
62
|
+
throw new DeeplineError(
|
|
63
|
+
`--json diagnostics requires --full. For inspection, use: deepline ${surface === "run" ? "runs get <run-id>" : `${command} ${quotedTarget}`} --full --json ${path}`,
|
|
64
|
+
void 0,
|
|
65
|
+
"INVALID_ARGUMENT"
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
fields = [...fields ?? [], ...paths];
|
|
70
|
+
}
|
|
71
|
+
if (fields && normalized.includes("--input") && surface === "get") {
|
|
72
|
+
throw new DeeplineError(
|
|
73
|
+
"--json fields selects the run response, not --input. Use bare --json with --input.",
|
|
74
|
+
void 0,
|
|
75
|
+
"INVALID_ARGUMENT"
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
return { args: normalized, fields };
|
|
79
|
+
}
|
|
80
|
+
function selectJsonFields(value, fields) {
|
|
81
|
+
if (!fields) return value;
|
|
82
|
+
function project(source, paths) {
|
|
83
|
+
if (paths.some((path) => path.length === 0)) return source;
|
|
84
|
+
if (source === null) return null;
|
|
85
|
+
if (Array.isArray(source))
|
|
86
|
+
return source.map((item) => project(item, paths));
|
|
87
|
+
if (typeof source !== "object" || source === void 0) return void 0;
|
|
88
|
+
const groups = /* @__PURE__ */ new Map();
|
|
89
|
+
for (const [key, ...rest] of paths)
|
|
90
|
+
groups.set(key, [...groups.get(key) ?? [], rest]);
|
|
91
|
+
return Object.fromEntries(
|
|
92
|
+
[...groups].flatMap(([key, tails]) => {
|
|
93
|
+
if (!Object.hasOwn(source, key)) return [];
|
|
94
|
+
const child = project(source[key], tails);
|
|
95
|
+
return child === void 0 ? [] : [[key, child]];
|
|
96
|
+
})
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
return project(
|
|
100
|
+
value,
|
|
101
|
+
fields.map((path) => path.split("."))
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
function jsonFieldArgs(value) {
|
|
105
|
+
return typeof value === "string" ? [`--json=${value}`] : value ? ["--json"] : [];
|
|
106
|
+
}
|
|
107
|
+
function describeArgs(target, options) {
|
|
108
|
+
let fields = options.json;
|
|
109
|
+
if (!target && typeof fields === "string") {
|
|
110
|
+
target = fields;
|
|
111
|
+
fields = true;
|
|
112
|
+
}
|
|
113
|
+
return [
|
|
114
|
+
...target ? [target] : [],
|
|
115
|
+
...options.compact ? ["--compact"] : [],
|
|
116
|
+
...jsonFieldArgs(fields)
|
|
117
|
+
];
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// src/cli/utils.ts
|
|
121
|
+
import { createHash } from "crypto";
|
|
122
|
+
import {
|
|
123
|
+
existsSync,
|
|
124
|
+
mkdirSync,
|
|
125
|
+
readFileSync,
|
|
126
|
+
rmSync,
|
|
127
|
+
writeFileSync
|
|
128
|
+
} from "fs";
|
|
129
|
+
import { mkdir, writeFile } from "fs/promises";
|
|
130
|
+
import { homedir, tmpdir, userInfo } from "os";
|
|
131
|
+
import { dirname, join, resolve } from "path";
|
|
132
|
+
import * as childProcess from "child_process";
|
|
133
|
+
import { parse } from "csv-parse/sync";
|
|
134
|
+
import { stringify } from "csv-stringify/sync";
|
|
135
|
+
var BROWSER_OPEN_COOLDOWN_MS = 3e4;
|
|
136
|
+
var SAME_URL_BROWSER_OPEN_COOLDOWN_MS = 5 * 6e4;
|
|
137
|
+
var defaultBrowserCommandRunner = childProcess;
|
|
138
|
+
function getAuthedHttpClient() {
|
|
139
|
+
const config = resolveConfig();
|
|
140
|
+
return { config, http: new HttpClient(config) };
|
|
141
|
+
}
|
|
142
|
+
function stableOsUserId() {
|
|
143
|
+
try {
|
|
144
|
+
const info = userInfo();
|
|
145
|
+
if (typeof info.uid === "number") return `uid-${info.uid}`;
|
|
146
|
+
if (info.username) return `user-${info.username}`;
|
|
147
|
+
} catch {
|
|
148
|
+
}
|
|
149
|
+
return "unknown-user";
|
|
150
|
+
}
|
|
151
|
+
function defaultBrowserOpenStateDir() {
|
|
152
|
+
return join(tmpdir(), `deepline-${stableOsUserId()}`, "runtime", "state");
|
|
153
|
+
}
|
|
154
|
+
function browserOpenStateFile(stateDir = defaultBrowserOpenStateDir()) {
|
|
155
|
+
return join(stateDir, "browser-open.json");
|
|
156
|
+
}
|
|
157
|
+
function normalizeBrowserOpenTarget(raw) {
|
|
158
|
+
return String(raw || "").trim();
|
|
159
|
+
}
|
|
160
|
+
function browserOpenTargetKey(raw) {
|
|
161
|
+
const normalized = normalizeBrowserOpenTarget(raw);
|
|
162
|
+
return normalized ? createHash("sha256").update(normalized).digest("hex") : "";
|
|
163
|
+
}
|
|
164
|
+
function claimBrowserOpen(now = Date.now(), stateDir, targetUrl) {
|
|
165
|
+
const statePath = browserOpenStateFile(stateDir);
|
|
166
|
+
const lockPath = `${statePath}.lock`;
|
|
167
|
+
const targetKey = browserOpenTargetKey(targetUrl);
|
|
168
|
+
let locked = false;
|
|
169
|
+
try {
|
|
170
|
+
mkdirSync(dirname(statePath), { recursive: true, mode: 448 });
|
|
171
|
+
try {
|
|
172
|
+
mkdirSync(lockPath, { mode: 448 });
|
|
173
|
+
locked = true;
|
|
174
|
+
} catch {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
let lastOpenedAt = 0;
|
|
178
|
+
if (existsSync(statePath)) {
|
|
179
|
+
const payload = JSON.parse(readFileSync(statePath, "utf-8"));
|
|
180
|
+
const value = payload.lastOpenedAt ?? payload.last_opened_at ?? payload.lastFocusedAt ?? payload.last_focused_at;
|
|
181
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
182
|
+
lastOpenedAt = value;
|
|
183
|
+
}
|
|
184
|
+
const targetValue = payload.targetKey ?? payload.target_key ?? payload.targetHash ?? payload.target_hash;
|
|
185
|
+
const lastTargetKey = typeof targetValue === "string" ? targetValue.trim() : "";
|
|
186
|
+
const cooldownMs = targetKey && targetKey === lastTargetKey ? SAME_URL_BROWSER_OPEN_COOLDOWN_MS : BROWSER_OPEN_COOLDOWN_MS;
|
|
187
|
+
if (lastOpenedAt > now) {
|
|
188
|
+
lastOpenedAt = 0;
|
|
189
|
+
}
|
|
190
|
+
if (now - lastOpenedAt < cooldownMs) {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
writeFileSync(
|
|
195
|
+
statePath,
|
|
196
|
+
JSON.stringify({
|
|
197
|
+
lastOpenedAt: now,
|
|
198
|
+
...targetKey ? { targetKey } : {}
|
|
199
|
+
}),
|
|
200
|
+
{ encoding: "utf-8", mode: 384 }
|
|
201
|
+
);
|
|
202
|
+
return true;
|
|
203
|
+
} catch {
|
|
204
|
+
return true;
|
|
205
|
+
} finally {
|
|
206
|
+
if (locked) {
|
|
207
|
+
rmSync(lockPath, { recursive: true, force: true });
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
function extractUrlHost(raw) {
|
|
212
|
+
try {
|
|
213
|
+
const parsed = new URL(raw.includes("://") ? raw : `https://${raw}`);
|
|
214
|
+
return parsed.port ? `${parsed.hostname.toLowerCase()}:${parsed.port}` : parsed.hostname.toLowerCase();
|
|
215
|
+
} catch {
|
|
216
|
+
return "";
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
function browserAppNameFromBundleId(bundleId) {
|
|
220
|
+
const names = {
|
|
221
|
+
"com.google.chrome": "Google Chrome",
|
|
222
|
+
"com.google.chrome.canary": "Google Chrome Canary",
|
|
223
|
+
"com.microsoft.edgemac": "Microsoft Edge",
|
|
224
|
+
"com.brave.browser": "Brave Browser",
|
|
225
|
+
"com.operasoftware.opera": "Opera",
|
|
226
|
+
"com.operasoftware.operagx": "Opera GX",
|
|
227
|
+
"com.vivaldi.vivaldi": "Vivaldi",
|
|
228
|
+
"company.thebrowser.browser": "Arc",
|
|
229
|
+
"com.apple.safari": "Safari"
|
|
230
|
+
};
|
|
231
|
+
return names[bundleId.toLowerCase()] ?? "";
|
|
232
|
+
}
|
|
233
|
+
function currentOsUsername() {
|
|
234
|
+
try {
|
|
235
|
+
return userInfo().username || "";
|
|
236
|
+
} catch {
|
|
237
|
+
return "";
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
function readMacosUserHome(runner = defaultBrowserCommandRunner) {
|
|
241
|
+
const username = currentOsUsername();
|
|
242
|
+
if (process.platform === "darwin" && username) {
|
|
243
|
+
try {
|
|
244
|
+
const output = runner.execFileSync(
|
|
245
|
+
"dscl",
|
|
246
|
+
[".", "-read", `/Users/${username}`, "NFSHomeDirectory"],
|
|
247
|
+
{ encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }
|
|
248
|
+
);
|
|
249
|
+
const match = String(output).match(/NFSHomeDirectory:\s*(.+)\s*$/m);
|
|
250
|
+
const home = match?.[1]?.trim();
|
|
251
|
+
if (home) return home;
|
|
252
|
+
} catch {
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return homedir();
|
|
256
|
+
}
|
|
257
|
+
function readDefaultMacBrowserBundleId(runner = defaultBrowserCommandRunner) {
|
|
258
|
+
try {
|
|
259
|
+
const output = runner.execFileSync(
|
|
260
|
+
"plutil",
|
|
261
|
+
[
|
|
262
|
+
"-convert",
|
|
263
|
+
"json",
|
|
264
|
+
"-o",
|
|
265
|
+
"-",
|
|
266
|
+
`${readMacosUserHome(runner)}/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure.plist`
|
|
267
|
+
],
|
|
268
|
+
{ encoding: "utf-8", stdio: ["ignore", "pipe", "ignore"] }
|
|
269
|
+
);
|
|
270
|
+
const payload = JSON.parse(String(output));
|
|
271
|
+
const handlers = Array.isArray(payload.LSHandlers) ? payload.LSHandlers : [];
|
|
272
|
+
const pickBundle = (scheme) => {
|
|
273
|
+
for (const handler of handlers) {
|
|
274
|
+
if (!handler || typeof handler !== "object") continue;
|
|
275
|
+
if (String(handler.LSHandlerURLScheme ?? "").toLowerCase() !== scheme) {
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
const bundle = String(
|
|
279
|
+
handler.LSHandlerRoleAll ?? handler.LSHandlerRoleViewer ?? handler.LSHandlerRoleEditor ?? ""
|
|
280
|
+
).trim();
|
|
281
|
+
if (bundle) return bundle;
|
|
282
|
+
}
|
|
283
|
+
return "";
|
|
284
|
+
};
|
|
285
|
+
return pickBundle("https") || pickBundle("http");
|
|
286
|
+
} catch {
|
|
287
|
+
return "";
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
function browserStrategyForBundleId(bundleId) {
|
|
291
|
+
const normalized = bundleId.toLowerCase();
|
|
292
|
+
if ((/* @__PURE__ */ new Set([
|
|
293
|
+
"com.google.chrome",
|
|
294
|
+
"com.google.chrome.canary",
|
|
295
|
+
"com.microsoft.edgemac",
|
|
296
|
+
"com.brave.browser",
|
|
297
|
+
"com.operasoftware.opera",
|
|
298
|
+
"com.operasoftware.operagx",
|
|
299
|
+
"com.vivaldi.vivaldi",
|
|
300
|
+
"company.thebrowser.browser"
|
|
301
|
+
])).has(normalized)) {
|
|
302
|
+
return "chromium";
|
|
303
|
+
}
|
|
304
|
+
return normalized === "com.apple.safari" ? "safari" : "fallback";
|
|
305
|
+
}
|
|
306
|
+
function runAppleScript(script, args, runner = defaultBrowserCommandRunner) {
|
|
307
|
+
const result = runner.spawnSync("osascript", ["-", ...args], {
|
|
308
|
+
input: script,
|
|
309
|
+
encoding: "utf-8",
|
|
310
|
+
stdio: ["pipe", "ignore", "ignore"],
|
|
311
|
+
timeout: 5e3
|
|
312
|
+
});
|
|
313
|
+
return result.status === 0;
|
|
314
|
+
}
|
|
315
|
+
function retargetChromiumMacos(appName, targetUrl, allowFocus, runner = defaultBrowserCommandRunner) {
|
|
316
|
+
const host = extractUrlHost(targetUrl);
|
|
317
|
+
if (!host) return false;
|
|
318
|
+
const escapedAppName = appName.replace(/"/g, '\\"');
|
|
319
|
+
const activateBlock = allowFocus ? " activate\n" : "";
|
|
320
|
+
const foundTabBlock = allowFocus ? " set active tab index of w to i\n set index of w to 1\n set URL of t to targetUrl\n" : " set URL of t to targetUrl\n";
|
|
321
|
+
const newTabBlock = allowFocus ? " tell window 1\n make new tab with properties {URL:targetUrl}\n set active tab index to (count of tabs)\n set index to 1\n end tell\n" : " tell window 1\n make new tab with properties {URL:targetUrl}\n end tell\n";
|
|
322
|
+
const script = `
|
|
323
|
+
on run argv
|
|
324
|
+
set targetUrl to item 1 of argv
|
|
325
|
+
set targetHost to item 2 of argv
|
|
326
|
+
tell application "${escapedAppName}"
|
|
327
|
+
${activateBlock} if (count of windows) is 0 then
|
|
328
|
+
make new window
|
|
329
|
+
end if
|
|
330
|
+
set foundTab to false
|
|
331
|
+
repeat with w in windows
|
|
332
|
+
set tabCount to count of tabs of w
|
|
333
|
+
repeat with i from 1 to tabCount
|
|
334
|
+
set t to tab i of w
|
|
335
|
+
if (URL of t) contains targetHost then
|
|
336
|
+
${foundTabBlock} set foundTab to true
|
|
337
|
+
exit repeat
|
|
338
|
+
end if
|
|
339
|
+
end repeat
|
|
340
|
+
if foundTab then exit repeat
|
|
341
|
+
end repeat
|
|
342
|
+
if not foundTab then
|
|
343
|
+
${newTabBlock} end if
|
|
344
|
+
end tell
|
|
345
|
+
end run
|
|
346
|
+
`;
|
|
347
|
+
return runAppleScript(script, [targetUrl, host], runner);
|
|
348
|
+
}
|
|
349
|
+
function retargetSafariMacos(appName, targetUrl, allowFocus, runner = defaultBrowserCommandRunner) {
|
|
350
|
+
const host = extractUrlHost(targetUrl);
|
|
351
|
+
if (!host) return false;
|
|
352
|
+
const escapedAppName = appName.replace(/"/g, '\\"');
|
|
353
|
+
const activateBlock = allowFocus ? " activate\n" : "";
|
|
354
|
+
const foundTabBlock = allowFocus ? " set current tab of w to t\n set index of w to 1\n set URL of t to targetUrl\n" : " set URL of t to targetUrl\n";
|
|
355
|
+
const newTabBlock = allowFocus ? " tell window 1\n set current tab to (make new tab with properties {URL:targetUrl})\n set index to 1\n end tell\n" : " tell window 1\n make new tab with properties {URL:targetUrl}\n end tell\n";
|
|
356
|
+
const script = `
|
|
357
|
+
on run argv
|
|
358
|
+
set targetUrl to item 1 of argv
|
|
359
|
+
set targetHost to item 2 of argv
|
|
360
|
+
tell application "${escapedAppName}"
|
|
361
|
+
${activateBlock} if (count of windows) is 0 then
|
|
362
|
+
make new document
|
|
363
|
+
end if
|
|
364
|
+
set foundTab to false
|
|
365
|
+
repeat with w in windows
|
|
366
|
+
set tabCount to count of tabs of w
|
|
367
|
+
repeat with i from 1 to tabCount
|
|
368
|
+
set t to tab i of w
|
|
369
|
+
if (URL of t) contains targetHost then
|
|
370
|
+
${foundTabBlock} set foundTab to true
|
|
371
|
+
exit repeat
|
|
372
|
+
end if
|
|
373
|
+
end repeat
|
|
374
|
+
if foundTab then exit repeat
|
|
375
|
+
end repeat
|
|
376
|
+
if not foundTab then
|
|
377
|
+
${newTabBlock} end if
|
|
378
|
+
end tell
|
|
379
|
+
end run
|
|
380
|
+
`;
|
|
381
|
+
return runAppleScript(script, [targetUrl, host], runner);
|
|
382
|
+
}
|
|
383
|
+
function hasOnlyHeadlessMacosBrowserInstances(appName, runner = defaultBrowserCommandRunner) {
|
|
384
|
+
try {
|
|
385
|
+
const output = runner.execFileSync("ps", ["-axo", "args="], {
|
|
386
|
+
encoding: "utf-8",
|
|
387
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
388
|
+
});
|
|
389
|
+
const executableSuffix = `/Contents/MacOS/${appName}`;
|
|
390
|
+
const lines = String(output).split(/\r?\n/).map((line) => line.trim()).filter((line) => {
|
|
391
|
+
const executableIndex = line.indexOf(executableSuffix);
|
|
392
|
+
if (executableIndex < 0 || !line.includes(".app/Contents/MacOS/")) {
|
|
393
|
+
return false;
|
|
394
|
+
}
|
|
395
|
+
const rest = line.slice(executableIndex + executableSuffix.length);
|
|
396
|
+
return rest === "" || /^\s+-/.test(rest);
|
|
397
|
+
});
|
|
398
|
+
if (lines.length === 0) return false;
|
|
399
|
+
return lines.every(
|
|
400
|
+
(line) => line.includes("--headless") || line.includes("--no-startup-window")
|
|
401
|
+
);
|
|
402
|
+
} catch {
|
|
403
|
+
return false;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
function openNewVisibleMacosBrowserInstance(appName, targetUrl, runner = defaultBrowserCommandRunner) {
|
|
407
|
+
try {
|
|
408
|
+
runner.execFileSync(
|
|
409
|
+
"open",
|
|
410
|
+
["-na", appName, "--args", "--new-window", targetUrl],
|
|
411
|
+
{
|
|
412
|
+
stdio: "ignore"
|
|
413
|
+
}
|
|
414
|
+
);
|
|
415
|
+
return true;
|
|
416
|
+
} catch {
|
|
417
|
+
return false;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
function openUrlMacos(targetUrl, allowFocus, runner = defaultBrowserCommandRunner) {
|
|
421
|
+
const defaultBundleId = readDefaultMacBrowserBundleId(runner);
|
|
422
|
+
const appName = defaultBundleId ? browserAppNameFromBundleId(defaultBundleId) : "";
|
|
423
|
+
const strategy = browserStrategyForBundleId(defaultBundleId);
|
|
424
|
+
if (allowFocus && appName && strategy === "chromium" && hasOnlyHeadlessMacosBrowserInstances(appName, runner) && openNewVisibleMacosBrowserInstance(appName, targetUrl, runner)) {
|
|
425
|
+
return true;
|
|
426
|
+
}
|
|
427
|
+
if (appName && strategy === "chromium" && retargetChromiumMacos(appName, targetUrl, allowFocus, runner)) {
|
|
428
|
+
return true;
|
|
429
|
+
}
|
|
430
|
+
if (appName && strategy === "safari" && retargetSafariMacos(appName, targetUrl, allowFocus, runner)) {
|
|
431
|
+
return true;
|
|
432
|
+
}
|
|
433
|
+
try {
|
|
434
|
+
runner.execFileSync("open", [...allowFocus ? [] : ["-g"], targetUrl], {
|
|
435
|
+
stdio: "ignore"
|
|
436
|
+
});
|
|
437
|
+
return true;
|
|
438
|
+
} catch {
|
|
439
|
+
return false;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
function browserOpeningDisabled() {
|
|
443
|
+
const value = String(process.env.DEEPLINE_NO_BROWSER ?? "").trim().toLowerCase();
|
|
444
|
+
return value === "1" || value === "true" || value === "yes" || value === "on";
|
|
445
|
+
}
|
|
446
|
+
function openInBrowser(url, options = {}) {
|
|
447
|
+
try {
|
|
448
|
+
if (browserOpeningDisabled()) return "failed";
|
|
449
|
+
const targetUrl = String(url || "").trim();
|
|
450
|
+
if (!targetUrl) return "failed";
|
|
451
|
+
if (options.deduplicate !== false && !claimBrowserOpen(Date.now(), void 0, targetUrl)) {
|
|
452
|
+
return "suppressed";
|
|
453
|
+
}
|
|
454
|
+
const allowFocus = true;
|
|
455
|
+
if (process.platform === "darwin") {
|
|
456
|
+
return openUrlMacos(targetUrl, allowFocus) ? "opened" : "failed";
|
|
457
|
+
}
|
|
458
|
+
if (!allowFocus) return "failed";
|
|
459
|
+
if (process.platform === "win32") {
|
|
460
|
+
childProcess.execFileSync("cmd.exe", ["/c", "start", "", targetUrl], {
|
|
461
|
+
stdio: "ignore"
|
|
462
|
+
});
|
|
463
|
+
return "opened";
|
|
464
|
+
}
|
|
465
|
+
childProcess.execFileSync("xdg-open", [targetUrl], { stdio: "ignore" });
|
|
466
|
+
return "opened";
|
|
467
|
+
} catch {
|
|
468
|
+
return "failed";
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
function sleep(ms) {
|
|
472
|
+
return new Promise((resolvePromise) => setTimeout(resolvePromise, ms));
|
|
473
|
+
}
|
|
474
|
+
function collectLocalEnvInfo() {
|
|
475
|
+
const homeDir = process.env.HOME?.trim() || homedir();
|
|
476
|
+
const info = {
|
|
477
|
+
os: `${process.platform} ${process.arch}`,
|
|
478
|
+
node_version: process.version,
|
|
479
|
+
home_dir: homeDir,
|
|
480
|
+
agent_runtime: detectAgentRuntime()
|
|
481
|
+
};
|
|
482
|
+
const env = process.env;
|
|
483
|
+
const optional = {
|
|
484
|
+
claude_code_remote: env.CLAUDE_CODE_REMOTE,
|
|
485
|
+
deepline_plugin_mode: env.DEEPLINE_PLUGIN_MODE
|
|
486
|
+
};
|
|
487
|
+
for (const [key, value] of Object.entries(optional)) {
|
|
488
|
+
if (value?.trim()) info[key] = value.trim();
|
|
489
|
+
}
|
|
490
|
+
if (env.CLAUDE_PROJECT_DIR?.trim()) {
|
|
491
|
+
info.claude_project_dir_present = "true";
|
|
492
|
+
}
|
|
493
|
+
if (env.DEEPLINE_PLUGIN_ROOT?.trim()) {
|
|
494
|
+
info.deepline_plugin_root_present = "true";
|
|
495
|
+
}
|
|
496
|
+
if (env.DEEPLINE_PLUGIN_SKILLS_DIR?.trim()) {
|
|
497
|
+
info.deepline_plugin_skills_dir_present = "true";
|
|
498
|
+
}
|
|
499
|
+
if (info.home_dir === "/sessions" || info.home_dir.startsWith("/sessions/")) {
|
|
500
|
+
info.home_scope = "sessions";
|
|
501
|
+
}
|
|
502
|
+
return info;
|
|
503
|
+
}
|
|
504
|
+
function readCsvRows(csvPath) {
|
|
505
|
+
const raw = readFileSync(resolve(csvPath), "utf-8");
|
|
506
|
+
return parse(raw, {
|
|
507
|
+
// `csv-parse` otherwise treats a BOM before an opening quote as a field
|
|
508
|
+
// value, then rejects the quote as invalid. A UTF-8 BOM is a valid file
|
|
509
|
+
// prefix and must not become part of the first column name either.
|
|
510
|
+
bom: true,
|
|
511
|
+
columns: true,
|
|
512
|
+
skip_empty_lines: true
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
function csvStringFromRows(rows, columns) {
|
|
516
|
+
const effectiveColumns = columns?.length ? columns : Object.keys(rows[0] ?? {});
|
|
517
|
+
if (!effectiveColumns.length) {
|
|
518
|
+
return stringify(
|
|
519
|
+
rows.map(() => ({})),
|
|
520
|
+
{ header: true }
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
const records = rows.map(
|
|
524
|
+
(row) => effectiveColumns.map(
|
|
525
|
+
(column) => csvSafeCell(
|
|
526
|
+
Object.prototype.hasOwnProperty.call(row, column) ? row[column] : void 0
|
|
527
|
+
)
|
|
528
|
+
)
|
|
529
|
+
);
|
|
530
|
+
return stringify(records, {
|
|
531
|
+
header: true,
|
|
532
|
+
cast: {
|
|
533
|
+
boolean: (value) => value ? "true" : "false",
|
|
534
|
+
object: (value) => {
|
|
535
|
+
const cell = csvSafeCell(value);
|
|
536
|
+
return typeof cell === "string" ? cell : null;
|
|
537
|
+
}
|
|
538
|
+
},
|
|
539
|
+
...effectiveColumns.length ? { columns: effectiveColumns } : {}
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
function csvSafeCell(value) {
|
|
543
|
+
if (value === void 0) {
|
|
544
|
+
return null;
|
|
545
|
+
}
|
|
546
|
+
if (value === null) {
|
|
547
|
+
return null;
|
|
548
|
+
}
|
|
549
|
+
if (typeof value === "bigint") {
|
|
550
|
+
return value.toString();
|
|
551
|
+
}
|
|
552
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
553
|
+
return value;
|
|
554
|
+
}
|
|
555
|
+
if (value instanceof Date) {
|
|
556
|
+
return value.toISOString();
|
|
557
|
+
}
|
|
558
|
+
if (typeof value === "symbol" || typeof value === "function") {
|
|
559
|
+
return null;
|
|
560
|
+
}
|
|
561
|
+
if (typeof value !== "object") {
|
|
562
|
+
return String(value);
|
|
563
|
+
}
|
|
564
|
+
return csvSafeJsonString(value);
|
|
565
|
+
}
|
|
566
|
+
function csvSafeJsonReplacer(_key, nested) {
|
|
567
|
+
if (typeof nested === "bigint") {
|
|
568
|
+
return nested.toString();
|
|
569
|
+
}
|
|
570
|
+
if (nested === void 0 || typeof nested === "symbol" || typeof nested === "function") {
|
|
571
|
+
return null;
|
|
572
|
+
}
|
|
573
|
+
return nested;
|
|
574
|
+
}
|
|
575
|
+
function csvSafeJsonString(value) {
|
|
576
|
+
try {
|
|
577
|
+
const serialized = JSON.stringify(value, csvSafeJsonReplacer);
|
|
578
|
+
return serialized ?? null;
|
|
579
|
+
} catch {
|
|
580
|
+
return String(value);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
function parseMaybeJsonObject(value) {
|
|
584
|
+
if (typeof value !== "string") {
|
|
585
|
+
return value;
|
|
586
|
+
}
|
|
587
|
+
const trimmed = value.trim();
|
|
588
|
+
if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) {
|
|
589
|
+
return value;
|
|
590
|
+
}
|
|
591
|
+
try {
|
|
592
|
+
return JSON.parse(trimmed);
|
|
593
|
+
} catch {
|
|
594
|
+
return value;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
function failureMessageFromRecord(value) {
|
|
598
|
+
const status = typeof value.status === "string" ? value.status.trim().toLowerCase() : "";
|
|
599
|
+
const directError = typeof value.error === "string" ? value.error.trim() : typeof value.last_error === "string" ? value.last_error.trim() : "";
|
|
600
|
+
const result = value.result && typeof value.result === "object" && !Array.isArray(value.result) ? value.result : null;
|
|
601
|
+
const resultError = typeof result?.error === "string" ? result.error.trim() : typeof result?.message === "string" ? result.message.trim() : "";
|
|
602
|
+
if (!directError && !resultError && status !== "error" && status !== "failed") {
|
|
603
|
+
return null;
|
|
604
|
+
}
|
|
605
|
+
return directError || resultError || `Column status: ${status}`;
|
|
606
|
+
}
|
|
607
|
+
function shouldPreserveJsonStringColumn(columns, key) {
|
|
608
|
+
if (!columns) {
|
|
609
|
+
return false;
|
|
610
|
+
}
|
|
611
|
+
if (columns.has(key)) {
|
|
612
|
+
return true;
|
|
613
|
+
}
|
|
614
|
+
const normalizedKey = key.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
615
|
+
return normalizedKey ? columns.has(normalizedKey) : false;
|
|
616
|
+
}
|
|
617
|
+
function flattenObjectColumns(row, options = {}) {
|
|
618
|
+
const flattened = {};
|
|
619
|
+
for (const [key, rawValue] of Object.entries(row)) {
|
|
620
|
+
const value = parseMaybeJsonObject(rawValue);
|
|
621
|
+
const parsedFromString = typeof rawValue === "string" && value !== rawValue;
|
|
622
|
+
if (key === "_metadata") {
|
|
623
|
+
flattened[key] = value && typeof value === "object" ? csvSafeJsonString(value) : value;
|
|
624
|
+
continue;
|
|
625
|
+
}
|
|
626
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
627
|
+
const record = value;
|
|
628
|
+
if (options.objectColumns === "json") {
|
|
629
|
+
flattened[key] = csvSafeJsonString(record);
|
|
630
|
+
continue;
|
|
631
|
+
}
|
|
632
|
+
const hasMatchedEnvelope = Object.prototype.hasOwnProperty.call(record, "matched_result") || Object.prototype.hasOwnProperty.call(record, "matchedResult");
|
|
633
|
+
if (hasMatchedEnvelope) {
|
|
634
|
+
flattened[key] = csvSafeJsonString(record);
|
|
635
|
+
continue;
|
|
636
|
+
}
|
|
637
|
+
if (parsedFromString && shouldPreserveJsonStringColumn(options.preserveJsonStringColumns, key)) {
|
|
638
|
+
flattened[key] = rawValue;
|
|
639
|
+
continue;
|
|
640
|
+
} else {
|
|
641
|
+
const failureMessage = failureMessageFromRecord(record);
|
|
642
|
+
if (failureMessage) {
|
|
643
|
+
flattened[key] = failureMessage;
|
|
644
|
+
continue;
|
|
645
|
+
} else if (Object.prototype.hasOwnProperty.call(record, "result")) {
|
|
646
|
+
flattened[key] = csvSafeJsonString(record);
|
|
647
|
+
continue;
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
for (const [nestedKey, nestedValue] of Object.entries(record)) {
|
|
651
|
+
flattened[`${key}.${nestedKey}`] = nestedValue && typeof nestedValue === "object" ? csvSafeJsonString(nestedValue) : nestedValue;
|
|
652
|
+
}
|
|
653
|
+
continue;
|
|
654
|
+
}
|
|
655
|
+
flattened[key] = Array.isArray(value) ? csvSafeJsonString(value) : value;
|
|
656
|
+
}
|
|
657
|
+
return flattened;
|
|
658
|
+
}
|
|
659
|
+
function recordRows(value) {
|
|
660
|
+
return value.filter(
|
|
661
|
+
(row) => Boolean(row) && typeof row === "object" && !Array.isArray(row)
|
|
662
|
+
);
|
|
663
|
+
}
|
|
664
|
+
function dataExportRows(rows, options = {}) {
|
|
665
|
+
return rows.map((row) => flattenObjectColumns(row, options));
|
|
666
|
+
}
|
|
667
|
+
function dataExportColumns(rows, preferredColumns = []) {
|
|
668
|
+
const discoveredColumns = [
|
|
669
|
+
...new Set(rows.flatMap((row) => Object.keys(row)))
|
|
670
|
+
];
|
|
671
|
+
if (rows.length === 0) {
|
|
672
|
+
return [...new Set(preferredColumns.filter(Boolean))];
|
|
673
|
+
}
|
|
674
|
+
const discovered = new Set(discoveredColumns);
|
|
675
|
+
const columns = [];
|
|
676
|
+
const seen = /* @__PURE__ */ new Set();
|
|
677
|
+
for (const column of preferredColumns) {
|
|
678
|
+
if (!column) {
|
|
679
|
+
continue;
|
|
680
|
+
}
|
|
681
|
+
const expandedColumns = discovered.has(column) ? [column] : discoveredColumns.filter(
|
|
682
|
+
(discoveredColumn) => discoveredColumn.startsWith(`${column}.`)
|
|
683
|
+
);
|
|
684
|
+
for (const expandedColumn of expandedColumns) {
|
|
685
|
+
if (seen.has(expandedColumn)) {
|
|
686
|
+
continue;
|
|
687
|
+
}
|
|
688
|
+
seen.add(expandedColumn);
|
|
689
|
+
columns.push(expandedColumn);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
for (const column of discoveredColumns) {
|
|
693
|
+
if (seen.has(column)) {
|
|
694
|
+
continue;
|
|
695
|
+
}
|
|
696
|
+
seen.add(column);
|
|
697
|
+
columns.push(column);
|
|
698
|
+
}
|
|
699
|
+
return columns;
|
|
700
|
+
}
|
|
701
|
+
function dataExportCsvString(rows, preferredColumns = []) {
|
|
702
|
+
const flattenedRows = dataExportRows(rows);
|
|
703
|
+
return csvStringFromRows(
|
|
704
|
+
flattenedRows,
|
|
705
|
+
dataExportColumns(flattenedRows, preferredColumns)
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
function markdownCell(value) {
|
|
709
|
+
if (value === null || value === void 0) {
|
|
710
|
+
return "";
|
|
711
|
+
}
|
|
712
|
+
const text = typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
713
|
+
return text.replace(/\|/g, "\\|").replace(/\r?\n/g, "<br>");
|
|
714
|
+
}
|
|
715
|
+
function markdownTableFromRows(rows, preferredColumns = []) {
|
|
716
|
+
const flattenedRows = dataExportRows(rows);
|
|
717
|
+
const columns = dataExportColumns(flattenedRows, preferredColumns);
|
|
718
|
+
const header = `| ${columns.map(markdownCell).join(" | ")} |`;
|
|
719
|
+
const separator = `| ${columns.map(() => "---").join(" | ")} |`;
|
|
720
|
+
const body = flattenedRows.map(
|
|
721
|
+
(row) => `| ${columns.map((column) => markdownCell(row[column])).join(" | ")} |`
|
|
722
|
+
);
|
|
723
|
+
return `${[header, separator, ...body].join("\n")}
|
|
724
|
+
`;
|
|
725
|
+
}
|
|
726
|
+
function withAgentCommandContext(value) {
|
|
727
|
+
const valueRecord = value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
728
|
+
return detectAgentRuntime() !== "unknown" && valueRecord && !Object.prototype.hasOwnProperty.call(valueRecord, "command_context") ? {
|
|
729
|
+
...valueRecord,
|
|
730
|
+
command_context: resolveCliCommandContext()
|
|
731
|
+
} : value;
|
|
732
|
+
}
|
|
733
|
+
function printJson(value, fields) {
|
|
734
|
+
process.stdout.write(
|
|
735
|
+
`${JSON.stringify(selectJsonFields(withAgentCommandContext(value), fields), null, 2)}
|
|
736
|
+
`
|
|
737
|
+
);
|
|
738
|
+
}
|
|
739
|
+
function printCompactJson(value) {
|
|
740
|
+
process.stdout.write(`${JSON.stringify(withAgentCommandContext(value))}
|
|
741
|
+
`);
|
|
742
|
+
}
|
|
743
|
+
function errorToJsonPayload(error) {
|
|
744
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
745
|
+
const maybeRecord = error && typeof error === "object" ? error : null;
|
|
746
|
+
const code = typeof maybeRecord?.code === "string" ? maybeRecord.code : error instanceof SyntaxError ? "INVALID_JSON" : "CLI_ERROR";
|
|
747
|
+
const details = {};
|
|
748
|
+
const exitCode = typeof maybeRecord?.exitCode === "number" ? maybeRecord.exitCode : void 0;
|
|
749
|
+
if (typeof maybeRecord?.statusCode === "number") {
|
|
750
|
+
details.statusCode = maybeRecord.statusCode;
|
|
751
|
+
}
|
|
752
|
+
if (typeof maybeRecord?.status === "number") {
|
|
753
|
+
details.status = maybeRecord.status;
|
|
754
|
+
}
|
|
755
|
+
if (typeof maybeRecord?.requestId === "string" || maybeRecord?.requestId === null) {
|
|
756
|
+
details.requestId = maybeRecord.requestId;
|
|
757
|
+
}
|
|
758
|
+
if (typeof maybeRecord?.retryable === "boolean") {
|
|
759
|
+
details.retryable = maybeRecord.retryable;
|
|
760
|
+
}
|
|
761
|
+
if (maybeRecord?.publicDetails && typeof maybeRecord.publicDetails === "object" && !Array.isArray(maybeRecord.publicDetails)) {
|
|
762
|
+
details.publicDetails = maybeRecord.publicDetails;
|
|
763
|
+
}
|
|
764
|
+
if (maybeRecord?.details && typeof maybeRecord.details === "object" && !Array.isArray(maybeRecord.details)) {
|
|
765
|
+
details.details = maybeRecord.details;
|
|
766
|
+
}
|
|
767
|
+
if (maybeRecord?.guidance && typeof maybeRecord.guidance === "object" && !Array.isArray(maybeRecord.guidance)) {
|
|
768
|
+
details.guidance = maybeRecord.guidance;
|
|
769
|
+
}
|
|
770
|
+
const providerConcurrency = providerConcurrencyDiagnostic(maybeRecord);
|
|
771
|
+
if (providerConcurrency) {
|
|
772
|
+
details.providerConcurrency = providerConcurrency;
|
|
773
|
+
}
|
|
774
|
+
if (typeof maybeRecord?.cause === "string") {
|
|
775
|
+
details.cause = maybeRecord.cause;
|
|
776
|
+
}
|
|
777
|
+
return {
|
|
778
|
+
ok: false,
|
|
779
|
+
...exitCode !== void 0 ? { exitCode } : {},
|
|
780
|
+
error: {
|
|
781
|
+
message,
|
|
782
|
+
code,
|
|
783
|
+
...Object.keys(details).length > 0 ? { details } : {}
|
|
784
|
+
}
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
function formatProviderConcurrencyDiagnostic(error) {
|
|
788
|
+
const value = error && typeof error === "object" ? error : null;
|
|
789
|
+
const diagnostic = providerConcurrencyDiagnostic(value);
|
|
790
|
+
if (!diagnostic) return null;
|
|
791
|
+
const count = diagnostic.inFlightProviderRequestsAt429;
|
|
792
|
+
const concurrency = count > 1 ? `${count - 1} other same-provider request${count === 2 ? "" : "s"} overlapped the failed request` : "no other same-provider request was active";
|
|
793
|
+
return `Provider concurrency at the 429: ${count} active request${count === 1 ? "" : "s"} in this Play execution, including the failed request; ${concurrency}. Other Play executions and direct CLI/API calls are not included.`;
|
|
794
|
+
}
|
|
795
|
+
function providerConcurrencyDiagnostic(value) {
|
|
796
|
+
if (!value || value.origin !== "provider" || value.statusCode !== 429 && value.status !== 429) {
|
|
797
|
+
return null;
|
|
798
|
+
}
|
|
799
|
+
const publicDetails = value.publicDetails;
|
|
800
|
+
if (!publicDetails || typeof publicDetails !== "object" || Array.isArray(publicDetails)) {
|
|
801
|
+
return null;
|
|
802
|
+
}
|
|
803
|
+
const details = publicDetails;
|
|
804
|
+
const count = details.inFlightProviderRequestsAt429;
|
|
805
|
+
if (details.providerConcurrencyScope !== "same_provider_in_play_execution" || details.includesFailedRequest !== true || typeof count !== "number" || !Number.isInteger(count) || count < 1) {
|
|
806
|
+
return null;
|
|
807
|
+
}
|
|
808
|
+
return {
|
|
809
|
+
scope: "same_provider_in_play_execution",
|
|
810
|
+
inFlightProviderRequestsAt429: count,
|
|
811
|
+
includesFailedRequest: true
|
|
812
|
+
};
|
|
813
|
+
}
|
|
814
|
+
function printJsonError(error) {
|
|
815
|
+
printJson(errorToJsonPayload(error));
|
|
816
|
+
}
|
|
817
|
+
function shouldEmitJson(explicitJson = false) {
|
|
818
|
+
return explicitJson || !process.stdout.isTTY;
|
|
819
|
+
}
|
|
820
|
+
function argsWantJson(args) {
|
|
821
|
+
return shouldEmitJson(args.includes("--json"));
|
|
822
|
+
}
|
|
823
|
+
function createTimestampedName(prefix, extension) {
|
|
824
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
825
|
+
return `${prefix}-${timestamp}.${extension}`;
|
|
826
|
+
}
|
|
827
|
+
function clip(value, maxLength) {
|
|
828
|
+
return value.length > maxLength ? `${value.slice(0, maxLength - 1)}\u2026` : value;
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
// src/cli/command-envelope.ts
|
|
832
|
+
function renderSections(render) {
|
|
833
|
+
const lines = [];
|
|
834
|
+
for (const section of render?.sections ?? []) {
|
|
835
|
+
if (!section.title || section.lines.length === 0) continue;
|
|
836
|
+
lines.push(section.title);
|
|
837
|
+
lines.push(...section.lines.map((line) => ` ${line}`));
|
|
838
|
+
}
|
|
839
|
+
for (const action of render?.actions ?? []) {
|
|
840
|
+
if (!action.label || !action.command) continue;
|
|
841
|
+
lines.push(`${action.label}: ${action.command}`);
|
|
842
|
+
}
|
|
843
|
+
return lines;
|
|
844
|
+
}
|
|
845
|
+
function renderCommandEnvelopeText(envelope) {
|
|
846
|
+
const lines = renderSections(envelope.render);
|
|
847
|
+
if (lines.length > 0) {
|
|
848
|
+
return `${lines.join("\n")}
|
|
849
|
+
`;
|
|
850
|
+
}
|
|
851
|
+
return `${JSON.stringify(envelope, null, 2)}
|
|
852
|
+
`;
|
|
853
|
+
}
|
|
854
|
+
function printCommandEnvelope(envelope, options = {}) {
|
|
855
|
+
const jsonOutput = typeof options.json === "boolean" ? options.json : shouldEmitJson();
|
|
856
|
+
if (jsonOutput) {
|
|
857
|
+
printJson(envelope, options.fields);
|
|
858
|
+
return;
|
|
859
|
+
}
|
|
860
|
+
process.stdout.write(options.text ?? renderCommandEnvelopeText(envelope));
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
export {
|
|
864
|
+
parseJsonFields,
|
|
865
|
+
jsonFieldArgs,
|
|
866
|
+
describeArgs,
|
|
867
|
+
getAuthedHttpClient,
|
|
868
|
+
openInBrowser,
|
|
869
|
+
sleep,
|
|
870
|
+
collectLocalEnvInfo,
|
|
871
|
+
readCsvRows,
|
|
872
|
+
csvStringFromRows,
|
|
873
|
+
csvSafeJsonString,
|
|
874
|
+
recordRows,
|
|
875
|
+
dataExportRows,
|
|
876
|
+
dataExportColumns,
|
|
877
|
+
dataExportCsvString,
|
|
878
|
+
markdownTableFromRows,
|
|
879
|
+
printJson,
|
|
880
|
+
printCompactJson,
|
|
881
|
+
errorToJsonPayload,
|
|
882
|
+
formatProviderConcurrencyDiagnostic,
|
|
883
|
+
printJsonError,
|
|
884
|
+
shouldEmitJson,
|
|
885
|
+
argsWantJson,
|
|
886
|
+
createTimestampedName,
|
|
887
|
+
clip,
|
|
888
|
+
renderCommandEnvelopeText,
|
|
889
|
+
printCommandEnvelope
|
|
890
|
+
};
|