deepline 0.1.259 → 0.1.260
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/config.ts +110 -8
- package/dist/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +124 -34
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-postgres-admission.ts +130 -21
- package/dist/bundling-sources/shared_libs/plays/static-pipeline.ts +21 -0
- package/dist/cli/index.js +1642 -496
- package/dist/cli/index.mjs +1783 -629
- package/dist/index.js +1 -1
- package/dist/index.mjs +2 -2
- package/package.json +1 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -159,7 +159,7 @@ configureProxyFromEnv();
|
|
|
159
159
|
|
|
160
160
|
// src/cli/index.ts
|
|
161
161
|
import { mkdtemp as mkdtemp2, rm as rm2, writeFile as writeFile5 } from "fs/promises";
|
|
162
|
-
import { join as
|
|
162
|
+
import { join as join18 } from "path";
|
|
163
163
|
import { tmpdir as tmpdir4 } from "os";
|
|
164
164
|
import { Command as Command4 } from "commander";
|
|
165
165
|
|
|
@@ -174,7 +174,7 @@ import {
|
|
|
174
174
|
writeFileSync
|
|
175
175
|
} from "fs";
|
|
176
176
|
import { homedir } from "os";
|
|
177
|
-
import { dirname, join, resolve } from "path";
|
|
177
|
+
import { dirname, isAbsolute, join, resolve } from "path";
|
|
178
178
|
|
|
179
179
|
// src/errors.ts
|
|
180
180
|
var DeeplineError = class extends Error {
|
|
@@ -484,6 +484,21 @@ function resolveApiKeyForBaseUrl(baseUrl, explicitApiKey) {
|
|
|
484
484
|
cliEnv[API_KEY_ENV]
|
|
485
485
|
);
|
|
486
486
|
}
|
|
487
|
+
function resolveProjectApiKeyForBaseUrl(baseUrl, startDir = process.cwd()) {
|
|
488
|
+
const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
|
|
489
|
+
return firstNonEmpty(
|
|
490
|
+
...loadProjectEnvCandidates(startDir).map(({ env }) => {
|
|
491
|
+
const projectBaseUrl = normalizeBaseUrl(env[HOST_URL_ENV] ?? "");
|
|
492
|
+
return projectBaseUrl === normalizedBaseUrl ? env[API_KEY_ENV] : "";
|
|
493
|
+
})
|
|
494
|
+
);
|
|
495
|
+
}
|
|
496
|
+
function resolveGlobalApiKeyForBaseUrl(baseUrl) {
|
|
497
|
+
return firstNonEmpty(
|
|
498
|
+
process.env[API_KEY_ENV],
|
|
499
|
+
loadCliEnv(normalizeBaseUrl(baseUrl) || baseUrl)[API_KEY_ENV]
|
|
500
|
+
);
|
|
501
|
+
}
|
|
487
502
|
function getResolvedProjectAuthSource(baseUrl, apiKey, startDir = process.cwd()) {
|
|
488
503
|
const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
|
|
489
504
|
const normalizedApiKey = apiKey.trim();
|
|
@@ -527,14 +542,79 @@ function mergeProjectEnvFile(filePath, values) {
|
|
|
527
542
|
`, "utf-8");
|
|
528
543
|
}
|
|
529
544
|
function ensureProjectEnvIsIgnored(dir) {
|
|
545
|
+
ensureProjectPrivatePathsIgnored(dir, [
|
|
546
|
+
PROJECT_DEEPLINE_ENV_FILE,
|
|
547
|
+
".deepline/"
|
|
548
|
+
]);
|
|
549
|
+
}
|
|
550
|
+
function ensureProjectPrivatePathsIgnored(dir, entries) {
|
|
551
|
+
const gitDir = findNearestGitCommonDir(dir);
|
|
552
|
+
if (gitDir) {
|
|
553
|
+
const excludePath = join(gitDir, "info", "exclude");
|
|
554
|
+
const existing2 = existsSync(excludePath) ? readFileSync(excludePath, "utf-8") : "";
|
|
555
|
+
const existingEntries2 = new Set(
|
|
556
|
+
existing2.split(/\r?\n/).map((line) => line.trim()).filter(Boolean)
|
|
557
|
+
);
|
|
558
|
+
const missing2 = entries.filter(
|
|
559
|
+
(entry) => !existingEntries2.has(entry) && !existingEntries2.has(`/${entry}`)
|
|
560
|
+
);
|
|
561
|
+
if (missing2.length === 0) return;
|
|
562
|
+
mkdirSync(dirname(excludePath), { recursive: true });
|
|
563
|
+
const prefix2 = existing2 && !existing2.endsWith("\n") ? "\n" : "";
|
|
564
|
+
writeFileSync(
|
|
565
|
+
excludePath,
|
|
566
|
+
`${existing2}${prefix2}${missing2.join("\n")}
|
|
567
|
+
`,
|
|
568
|
+
"utf-8"
|
|
569
|
+
);
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
530
572
|
const gitignorePath = join(dir, ".gitignore");
|
|
531
|
-
const entry = PROJECT_DEEPLINE_ENV_FILE;
|
|
532
573
|
const existing = existsSync(gitignorePath) ? readFileSync(gitignorePath, "utf-8") : "";
|
|
533
|
-
const
|
|
534
|
-
|
|
574
|
+
const existingEntries = new Set(
|
|
575
|
+
existing.split(/\r?\n/).map((line) => line.trim()).filter(Boolean)
|
|
576
|
+
);
|
|
577
|
+
const missing = entries.filter(
|
|
578
|
+
(entry) => !existingEntries.has(entry) && !existingEntries.has(`/${entry}`)
|
|
579
|
+
);
|
|
580
|
+
if (missing.length === 0) return;
|
|
535
581
|
const prefix = existing && !existing.endsWith("\n") ? "\n" : "";
|
|
536
|
-
writeFileSync(
|
|
537
|
-
|
|
582
|
+
writeFileSync(
|
|
583
|
+
gitignorePath,
|
|
584
|
+
`${existing}${prefix}${missing.join("\n")}
|
|
585
|
+
`,
|
|
586
|
+
"utf-8"
|
|
587
|
+
);
|
|
588
|
+
}
|
|
589
|
+
function findNearestGitCommonDir(startDir) {
|
|
590
|
+
let current = resolve(startDir);
|
|
591
|
+
while (true) {
|
|
592
|
+
const candidate = join(current, ".git");
|
|
593
|
+
if (existsSync(candidate)) {
|
|
594
|
+
try {
|
|
595
|
+
const stat2 = statSync(candidate);
|
|
596
|
+
if (stat2.isDirectory()) return candidate;
|
|
597
|
+
if (stat2.isFile()) {
|
|
598
|
+
const match = readFileSync(candidate, "utf8").match(
|
|
599
|
+
/^gitdir:\s*(.+)$/m
|
|
600
|
+
);
|
|
601
|
+
const rawGitDir = match?.[1]?.trim();
|
|
602
|
+
if (rawGitDir) {
|
|
603
|
+
const gitDir = isAbsolute(rawGitDir) ? rawGitDir : resolve(dirname(candidate), rawGitDir);
|
|
604
|
+
const commonDirPath = join(gitDir, "commondir");
|
|
605
|
+
if (!existsSync(commonDirPath)) return gitDir;
|
|
606
|
+
const rawCommonDir = readFileSync(commonDirPath, "utf8").trim();
|
|
607
|
+
return rawCommonDir ? isAbsolute(rawCommonDir) ? rawCommonDir : resolve(gitDir, rawCommonDir) : gitDir;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
} catch {
|
|
611
|
+
return null;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
const parent = dirname(current);
|
|
615
|
+
if (parent === current) return null;
|
|
616
|
+
current = parent;
|
|
617
|
+
}
|
|
538
618
|
}
|
|
539
619
|
function saveProjectDeeplineEnvValues(values, startDir = process.cwd()) {
|
|
540
620
|
const target = resolveProjectPinTarget(startDir);
|
|
@@ -621,7 +701,7 @@ var SDK_RELEASE = {
|
|
|
621
701
|
// Deepline-native radars. Older clients must update before discovering,
|
|
622
702
|
// checking, or deploying an unlaunched monitor integration.
|
|
623
703
|
// 0.1.253 makes play-page browser opening opt-in and retires --no-open.
|
|
624
|
-
version: "0.1.
|
|
704
|
+
version: "0.1.260",
|
|
625
705
|
apiContract: "2026-07-native-monitor-launch-hard-cutover",
|
|
626
706
|
supportPolicy: {
|
|
627
707
|
minimumSupported: "0.1.53",
|
|
@@ -1306,7 +1386,7 @@ function decodeSseFrame(frame) {
|
|
|
1306
1386
|
return parsed;
|
|
1307
1387
|
}
|
|
1308
1388
|
function sleep(ms) {
|
|
1309
|
-
return new Promise((
|
|
1389
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
1310
1390
|
}
|
|
1311
1391
|
function withCoworkNetworkHint(message) {
|
|
1312
1392
|
if (!isCoworkLikeSandbox2() || message.includes(COWORK_NETWORK_HINT)) {
|
|
@@ -2278,14 +2358,14 @@ async function* observeRunEvents(options) {
|
|
|
2278
2358
|
try {
|
|
2279
2359
|
for (; ; ) {
|
|
2280
2360
|
if (queue.length === 0) {
|
|
2281
|
-
const waitForItem = new Promise((
|
|
2282
|
-
wake =
|
|
2361
|
+
const waitForItem = new Promise((resolve15) => {
|
|
2362
|
+
wake = resolve15;
|
|
2283
2363
|
});
|
|
2284
2364
|
if (!sawFirstSnapshot) {
|
|
2285
2365
|
const timedOut = await Promise.race([
|
|
2286
2366
|
waitForItem.then(() => false),
|
|
2287
2367
|
new Promise(
|
|
2288
|
-
(
|
|
2368
|
+
(resolve15) => setTimeout(() => resolve15(true), OBSERVE_BOOTSTRAP_TIMEOUT_MS)
|
|
2289
2369
|
)
|
|
2290
2370
|
]);
|
|
2291
2371
|
if (timedOut && queue.length === 0) {
|
|
@@ -2503,7 +2583,7 @@ function parseEnvTestPolicyOverrides() {
|
|
|
2503
2583
|
return normalizeTestPolicyOverrides(parsed, "DEEPLINE_TEST_POLICY_OVERRIDES");
|
|
2504
2584
|
}
|
|
2505
2585
|
function sleep2(ms) {
|
|
2506
|
-
return new Promise((
|
|
2586
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
2507
2587
|
}
|
|
2508
2588
|
function isTransientCompileManifestError(error) {
|
|
2509
2589
|
if (error instanceof DeeplineError && typeof error.statusCode === "number") {
|
|
@@ -5669,37 +5749,93 @@ import {
|
|
|
5669
5749
|
writeFileSync as writeFileSync4
|
|
5670
5750
|
} from "fs";
|
|
5671
5751
|
import { hostname } from "os";
|
|
5672
|
-
import { dirname as dirname4 } from "path";
|
|
5752
|
+
import { dirname as dirname4, join as join5 } from "path";
|
|
5673
5753
|
var EXIT_OK = 0;
|
|
5674
5754
|
var EXIT_AUTH = 3;
|
|
5675
5755
|
var EXIT_SERVER = 5;
|
|
5676
5756
|
function envFilePath(baseUrl) {
|
|
5677
5757
|
return hostEnvFilePath(baseUrl);
|
|
5678
5758
|
}
|
|
5679
|
-
function
|
|
5759
|
+
function normalizeAuthScope(value) {
|
|
5760
|
+
if (!value || value === "global") return "global";
|
|
5761
|
+
if (value === "folder") return "folder";
|
|
5762
|
+
throw new Error("--auth-scope must be one of: folder, global");
|
|
5763
|
+
}
|
|
5764
|
+
function parseAuthScope(args) {
|
|
5765
|
+
const index = args.indexOf("--auth-scope");
|
|
5766
|
+
return normalizeAuthScope(index >= 0 ? args[index + 1] : void 0);
|
|
5767
|
+
}
|
|
5768
|
+
function pendingClaimPath(baseUrl, scope) {
|
|
5769
|
+
if (scope === "folder") {
|
|
5770
|
+
const target = resolveProjectPinTarget();
|
|
5771
|
+
if (!target.ok) {
|
|
5772
|
+
throw new Error(
|
|
5773
|
+
`Cowork project folder is ambiguous. Candidate folders: ${target.candidates.join(
|
|
5774
|
+
", "
|
|
5775
|
+
)}. Set CLAUDE_PROJECT_DIR or cd into the intended project folder.`
|
|
5776
|
+
);
|
|
5777
|
+
}
|
|
5778
|
+
return join5(target.dir, ".deepline", "setup", "pending-auth.json");
|
|
5779
|
+
}
|
|
5780
|
+
return `${hostConfigDirPath(baseUrl)}/pending-auth.json`;
|
|
5781
|
+
}
|
|
5782
|
+
function legacyPendingClaimTokenPath(baseUrl) {
|
|
5680
5783
|
return `${hostConfigDirPath(baseUrl)}/pending-claim-token`;
|
|
5681
5784
|
}
|
|
5682
|
-
function
|
|
5683
|
-
const filePath =
|
|
5785
|
+
function savePendingClaim(baseUrl, claim) {
|
|
5786
|
+
const filePath = pendingClaimPath(baseUrl, claim.scope);
|
|
5684
5787
|
const dir = dirname4(filePath);
|
|
5685
5788
|
if (!existsSync5(dir)) {
|
|
5686
5789
|
mkdirSync4(dir, { recursive: true });
|
|
5687
5790
|
}
|
|
5688
|
-
writeFileSync4(filePath, `${
|
|
5689
|
-
`,
|
|
5791
|
+
writeFileSync4(filePath, `${JSON.stringify(claim, null, 2)}
|
|
5792
|
+
`, {
|
|
5793
|
+
encoding: "utf-8",
|
|
5794
|
+
mode: 384
|
|
5795
|
+
});
|
|
5690
5796
|
}
|
|
5691
|
-
function
|
|
5692
|
-
|
|
5693
|
-
if (!existsSync5(filePath)) return "";
|
|
5797
|
+
function readPendingAuthClaim(baseUrl, scope) {
|
|
5798
|
+
let filePath;
|
|
5694
5799
|
try {
|
|
5695
|
-
|
|
5800
|
+
filePath = pendingClaimPath(baseUrl, scope);
|
|
5696
5801
|
} catch {
|
|
5697
|
-
return
|
|
5802
|
+
return null;
|
|
5803
|
+
}
|
|
5804
|
+
if (!existsSync5(filePath)) {
|
|
5805
|
+
if (scope !== "global") return null;
|
|
5806
|
+
try {
|
|
5807
|
+
const claimToken = readFileSync5(
|
|
5808
|
+
legacyPendingClaimTokenPath(baseUrl),
|
|
5809
|
+
"utf-8"
|
|
5810
|
+
).trim();
|
|
5811
|
+
return claimToken ? {
|
|
5812
|
+
claimToken,
|
|
5813
|
+
claimUrl: `${baseUrl}/api/v2/auth/cli/claim/${encodeURIComponent(claimToken)}`,
|
|
5814
|
+
scope
|
|
5815
|
+
} : null;
|
|
5816
|
+
} catch {
|
|
5817
|
+
return null;
|
|
5818
|
+
}
|
|
5819
|
+
}
|
|
5820
|
+
try {
|
|
5821
|
+
const parsed = JSON.parse(readFileSync5(filePath, "utf-8"));
|
|
5822
|
+
const claimToken = typeof parsed.claimToken === "string" ? parsed.claimToken.trim() : "";
|
|
5823
|
+
if (!claimToken) return null;
|
|
5824
|
+
return {
|
|
5825
|
+
claimToken,
|
|
5826
|
+
claimUrl: typeof parsed.claimUrl === "string" ? parsed.claimUrl.trim() : "",
|
|
5827
|
+
scope
|
|
5828
|
+
};
|
|
5829
|
+
} catch {
|
|
5830
|
+
return null;
|
|
5698
5831
|
}
|
|
5699
5832
|
}
|
|
5700
|
-
function
|
|
5833
|
+
function clearPendingClaim(baseUrl, scope) {
|
|
5701
5834
|
try {
|
|
5702
|
-
rmSync2(
|
|
5835
|
+
rmSync2(pendingClaimPath(baseUrl, scope), { force: true });
|
|
5836
|
+
if (scope === "global") {
|
|
5837
|
+
rmSync2(legacyPendingClaimTokenPath(baseUrl), { force: true });
|
|
5838
|
+
}
|
|
5703
5839
|
} catch {
|
|
5704
5840
|
}
|
|
5705
5841
|
}
|
|
@@ -5724,12 +5860,16 @@ function shouldWaitForRegisterClaim(mode) {
|
|
|
5724
5860
|
if (mode === "no") return false;
|
|
5725
5861
|
return detectAgentRuntime() !== "claude_cowork";
|
|
5726
5862
|
}
|
|
5727
|
-
function saveEnvValues(values, baseUrl) {
|
|
5863
|
+
function saveEnvValues(values, baseUrl, scope) {
|
|
5728
5864
|
const filtered = {
|
|
5729
5865
|
...values[HOST_URL_ENV] ? { [HOST_URL_ENV]: values[HOST_URL_ENV] } : {},
|
|
5730
5866
|
...values[API_KEY_ENV] ? { [API_KEY_ENV]: values[API_KEY_ENV] } : {}
|
|
5731
5867
|
};
|
|
5732
|
-
|
|
5868
|
+
if (scope === "folder") {
|
|
5869
|
+
saveProjectDeeplineEnvValues(filtered);
|
|
5870
|
+
} else {
|
|
5871
|
+
saveHostEnvValues(baseUrl, filtered);
|
|
5872
|
+
}
|
|
5733
5873
|
}
|
|
5734
5874
|
async function httpJson(method, url, apiKey, body) {
|
|
5735
5875
|
const headers = {
|
|
@@ -5792,7 +5932,7 @@ function buildCandidateUrls2(url) {
|
|
|
5792
5932
|
}
|
|
5793
5933
|
}
|
|
5794
5934
|
function sleep4(ms) {
|
|
5795
|
-
return new Promise((
|
|
5935
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
5796
5936
|
}
|
|
5797
5937
|
function printDeeplineLogo() {
|
|
5798
5938
|
if (process.stdout.isTTY && (process.stdout.columns ?? 80) >= 70) {
|
|
@@ -5853,8 +5993,13 @@ async function handleRegister(args) {
|
|
|
5853
5993
|
let orgName = "";
|
|
5854
5994
|
let agentName = "";
|
|
5855
5995
|
let waitMode;
|
|
5996
|
+
let authScope;
|
|
5856
5997
|
try {
|
|
5857
5998
|
waitMode = parseRegisterWaitMode(args);
|
|
5999
|
+
authScope = parseAuthScope(args);
|
|
6000
|
+
if (authScope === "folder") {
|
|
6001
|
+
pendingClaimPath(baseUrl, authScope);
|
|
6002
|
+
}
|
|
5858
6003
|
} catch (error) {
|
|
5859
6004
|
console.error(error instanceof Error ? error.message : String(error));
|
|
5860
6005
|
return 2;
|
|
@@ -5887,18 +6032,22 @@ async function handleRegister(args) {
|
|
|
5887
6032
|
const claimUrl = String(data.claim_url || "");
|
|
5888
6033
|
const claimToken = String(data.claim_token || "");
|
|
5889
6034
|
if (claimToken) {
|
|
5890
|
-
|
|
6035
|
+
savePendingClaim(baseUrl, { claimToken, claimUrl, scope: authScope });
|
|
5891
6036
|
saveEnvValues(
|
|
5892
6037
|
{
|
|
5893
6038
|
[HOST_URL_ENV]: baseUrl
|
|
5894
6039
|
},
|
|
5895
|
-
baseUrl
|
|
6040
|
+
baseUrl,
|
|
6041
|
+
authScope
|
|
5896
6042
|
);
|
|
5897
6043
|
}
|
|
5898
6044
|
if (claimUrl) {
|
|
5899
|
-
|
|
5900
|
-
console.log(
|
|
5901
|
-
|
|
6045
|
+
const shouldOpen = waitMode !== "no" && detectAgentRuntime() !== "claude_cowork";
|
|
6046
|
+
console.log(
|
|
6047
|
+
shouldOpen ? " Opening approval page in your browser." : " Open this approval page in your browser:"
|
|
6048
|
+
);
|
|
6049
|
+
console.log(` ${claimUrl}`);
|
|
6050
|
+
if (shouldOpen) openInBrowser(claimUrl);
|
|
5902
6051
|
}
|
|
5903
6052
|
if (data.cli_message) {
|
|
5904
6053
|
console.log(String(data.cli_message));
|
|
@@ -5916,7 +6065,7 @@ async function handleRegister(args) {
|
|
|
5916
6065
|
{ claim_token: claimToken, reveal: true }
|
|
5917
6066
|
);
|
|
5918
6067
|
if (s === 401 || s === 403) {
|
|
5919
|
-
|
|
6068
|
+
clearPendingClaim(baseUrl, authScope);
|
|
5920
6069
|
console.log("Status: unauthorized");
|
|
5921
6070
|
return EXIT_AUTH;
|
|
5922
6071
|
}
|
|
@@ -5937,15 +6086,16 @@ async function handleRegister(args) {
|
|
|
5937
6086
|
[HOST_URL_ENV]: baseUrl,
|
|
5938
6087
|
[API_KEY_ENV]: apiKey
|
|
5939
6088
|
},
|
|
5940
|
-
baseUrl
|
|
6089
|
+
baseUrl,
|
|
6090
|
+
authScope
|
|
5941
6091
|
);
|
|
5942
|
-
|
|
6092
|
+
clearPendingClaim(baseUrl, authScope);
|
|
5943
6093
|
await printClaimSuccessBanner(baseUrl, apiKey, statusData);
|
|
5944
6094
|
return EXIT_OK;
|
|
5945
6095
|
}
|
|
5946
6096
|
}
|
|
5947
6097
|
if (state === "expired") {
|
|
5948
|
-
|
|
6098
|
+
clearPendingClaim(baseUrl, authScope);
|
|
5949
6099
|
console.log(
|
|
5950
6100
|
"That approval link expired. Please run: deepline auth register"
|
|
5951
6101
|
);
|
|
@@ -5957,6 +6107,13 @@ async function handleRegister(args) {
|
|
|
5957
6107
|
async function handleWait(args) {
|
|
5958
6108
|
const baseUrl = autoDetectBaseUrl().replace(/\/$/, "");
|
|
5959
6109
|
let timeoutSeconds = 300;
|
|
6110
|
+
let authScope;
|
|
6111
|
+
try {
|
|
6112
|
+
authScope = parseAuthScope(args);
|
|
6113
|
+
} catch (error) {
|
|
6114
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
6115
|
+
return 2;
|
|
6116
|
+
}
|
|
5960
6117
|
for (let i = 0; i < args.length; i++) {
|
|
5961
6118
|
if (args[i] === "--timeout" && args[i + 1]) {
|
|
5962
6119
|
const parsed = Number.parseInt(args[++i], 10);
|
|
@@ -5965,9 +6122,11 @@ async function handleWait(args) {
|
|
|
5965
6122
|
}
|
|
5966
6123
|
}
|
|
5967
6124
|
}
|
|
5968
|
-
const
|
|
5969
|
-
|
|
5970
|
-
|
|
6125
|
+
const pendingClaim = readPendingAuthClaim(baseUrl, authScope);
|
|
6126
|
+
const claimToken = pendingClaim?.claimToken ?? "";
|
|
6127
|
+
if (!pendingClaim) {
|
|
6128
|
+
const scopedApiKey = authScope === "folder" ? resolveProjectApiKeyForBaseUrl(baseUrl) : resolveGlobalApiKeyForBaseUrl(baseUrl);
|
|
6129
|
+
if (scopedApiKey) {
|
|
5971
6130
|
console.log("Already connected.");
|
|
5972
6131
|
return EXIT_OK;
|
|
5973
6132
|
}
|
|
@@ -5983,7 +6142,7 @@ async function handleWait(args) {
|
|
|
5983
6142
|
{ claim_token: claimToken, reveal: true }
|
|
5984
6143
|
);
|
|
5985
6144
|
if (status === 401 || status === 403) {
|
|
5986
|
-
|
|
6145
|
+
clearPendingClaim(baseUrl, authScope);
|
|
5987
6146
|
console.error("Claim is invalid. Run: deepline auth register");
|
|
5988
6147
|
return EXIT_AUTH;
|
|
5989
6148
|
}
|
|
@@ -6004,15 +6163,16 @@ async function handleWait(args) {
|
|
|
6004
6163
|
[HOST_URL_ENV]: baseUrl,
|
|
6005
6164
|
[API_KEY_ENV]: apiKey
|
|
6006
6165
|
},
|
|
6007
|
-
baseUrl
|
|
6166
|
+
baseUrl,
|
|
6167
|
+
authScope
|
|
6008
6168
|
);
|
|
6009
|
-
|
|
6169
|
+
clearPendingClaim(baseUrl, authScope);
|
|
6010
6170
|
await printClaimSuccessBanner(baseUrl, apiKey, data);
|
|
6011
6171
|
return EXIT_OK;
|
|
6012
6172
|
}
|
|
6013
6173
|
}
|
|
6014
6174
|
if (state === "expired") {
|
|
6015
|
-
|
|
6175
|
+
clearPendingClaim(baseUrl, authScope);
|
|
6016
6176
|
console.error("That approval link expired. Run: deepline auth register");
|
|
6017
6177
|
return EXIT_AUTH;
|
|
6018
6178
|
}
|
|
@@ -6027,6 +6187,16 @@ async function handleStatus(args) {
|
|
|
6027
6187
|
const baseUrl = autoDetectBaseUrl().replace(/\/$/, "");
|
|
6028
6188
|
const reveal = args.includes("--reveal");
|
|
6029
6189
|
const jsonOutput = argsWantJson(args);
|
|
6190
|
+
const hasExplicitAuthScope = args.includes("--auth-scope");
|
|
6191
|
+
let authScope = null;
|
|
6192
|
+
if (hasExplicitAuthScope) {
|
|
6193
|
+
try {
|
|
6194
|
+
authScope = parseAuthScope(args);
|
|
6195
|
+
} catch (error) {
|
|
6196
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
6197
|
+
return 2;
|
|
6198
|
+
}
|
|
6199
|
+
}
|
|
6030
6200
|
let hostStatusPayload = null;
|
|
6031
6201
|
const hostLines = [];
|
|
6032
6202
|
try {
|
|
@@ -6053,14 +6223,16 @@ async function handleStatus(args) {
|
|
|
6053
6223
|
};
|
|
6054
6224
|
hostLines.push(`Host: ${baseUrl} (unreachable)`);
|
|
6055
6225
|
}
|
|
6056
|
-
const apiKey = resolveApiKeyForBaseUrl(baseUrl);
|
|
6226
|
+
const apiKey = authScope === "folder" ? resolveProjectApiKeyForBaseUrl(baseUrl) : authScope === "global" ? resolveGlobalApiKeyForBaseUrl(baseUrl) : resolveApiKeyForBaseUrl(baseUrl);
|
|
6057
6227
|
if (!apiKey) {
|
|
6058
|
-
|
|
6228
|
+
const pendingClaim = authScope ? readPendingAuthClaim(baseUrl, authScope) : readPendingAuthClaim(baseUrl, "folder") ?? readPendingAuthClaim(baseUrl, "global");
|
|
6229
|
+
if (pendingClaim) {
|
|
6059
6230
|
printCommandEnvelope(
|
|
6060
6231
|
{
|
|
6061
6232
|
...hostStatusPayload ?? { host: baseUrl },
|
|
6062
6233
|
status: "pending",
|
|
6063
6234
|
connected: false,
|
|
6235
|
+
authorization_url: pendingClaim.claimUrl || null,
|
|
6064
6236
|
next: "deepline auth wait",
|
|
6065
6237
|
render: {
|
|
6066
6238
|
sections: [
|
|
@@ -6142,7 +6314,8 @@ async function handleStatus(args) {
|
|
|
6142
6314
|
console.error(`Auth status error (status ${status}).`);
|
|
6143
6315
|
return EXIT_SERVER;
|
|
6144
6316
|
}
|
|
6145
|
-
|
|
6317
|
+
const resolvedAuthScope = authScope ?? (getResolvedProjectAuthSource(baseUrl, apiKey) ? "folder" : "global");
|
|
6318
|
+
clearPendingClaim(baseUrl, resolvedAuthScope);
|
|
6146
6319
|
const payload = {
|
|
6147
6320
|
...hostStatusPayload ?? { host: baseUrl },
|
|
6148
6321
|
status: data.status || "(unknown)",
|
|
@@ -6167,9 +6340,15 @@ async function handleStatus(args) {
|
|
|
6167
6340
|
[HOST_URL_ENV]: baseUrl,
|
|
6168
6341
|
[API_KEY_ENV]: apiKeyResp
|
|
6169
6342
|
},
|
|
6170
|
-
baseUrl
|
|
6343
|
+
baseUrl,
|
|
6344
|
+
resolvedAuthScope
|
|
6171
6345
|
);
|
|
6172
|
-
|
|
6346
|
+
if (resolvedAuthScope === "folder") {
|
|
6347
|
+
const target = resolveProjectPinTarget();
|
|
6348
|
+
savedApiKeyPath = target.ok ? join5(target.dir, ".env.deepline") : null;
|
|
6349
|
+
} else {
|
|
6350
|
+
savedApiKeyPath = envFilePath(baseUrl);
|
|
6351
|
+
}
|
|
6173
6352
|
}
|
|
6174
6353
|
}
|
|
6175
6354
|
printCommandEnvelope(
|
|
@@ -6234,12 +6413,19 @@ Examples:
|
|
|
6234
6413
|
deepline auth register
|
|
6235
6414
|
deepline auth register --org-name Acme --agent-name local-cli
|
|
6236
6415
|
deepline auth register --wait no
|
|
6416
|
+
deepline auth register --auth-scope folder --wait no
|
|
6237
6417
|
`
|
|
6238
|
-
).option("--org-name <name>", "Workspace name to prefill").option("--agent-name <name>", "Agent name to register").option("--wait <mode>", "Wait mode: auto, yes, or no", "auto").option("--no-wait", "Alias for --wait no").
|
|
6418
|
+
).option("--org-name <name>", "Workspace name to prefill").option("--agent-name <name>", "Agent name to register").option("--wait <mode>", "Wait mode: auto, yes, or no", "auto").option("--no-wait", "Alias for --wait no").option(
|
|
6419
|
+
"--auth-scope <scope>",
|
|
6420
|
+
"Credential scope: global or folder",
|
|
6421
|
+
"global"
|
|
6422
|
+
).action(async (options) => {
|
|
6239
6423
|
process.exitCode = await handleRegister([
|
|
6240
6424
|
...options.orgName ? ["--org-name", options.orgName] : [],
|
|
6241
6425
|
...options.agentName ? ["--agent-name", options.agentName] : [],
|
|
6242
|
-
...options.noWait || options.wait === false ? ["--wait", "no"] : ["--wait", String(options.wait ?? "auto")]
|
|
6426
|
+
...options.noWait || options.wait === false ? ["--wait", "no"] : ["--wait", String(options.wait ?? "auto")],
|
|
6427
|
+
"--auth-scope",
|
|
6428
|
+
String(options.authScope ?? "global")
|
|
6243
6429
|
]);
|
|
6244
6430
|
});
|
|
6245
6431
|
auth.command("wait").description("Wait for a pending browser approval and save the API key.").addHelpText(
|
|
@@ -6252,10 +6438,17 @@ Notes:
|
|
|
6252
6438
|
Examples:
|
|
6253
6439
|
deepline auth wait
|
|
6254
6440
|
deepline auth wait --timeout 120
|
|
6441
|
+
deepline auth wait --auth-scope folder --timeout 120
|
|
6255
6442
|
`
|
|
6256
|
-
).option("--timeout <seconds>", "Maximum seconds to wait", "300").
|
|
6443
|
+
).option("--timeout <seconds>", "Maximum seconds to wait", "300").option(
|
|
6444
|
+
"--auth-scope <scope>",
|
|
6445
|
+
"Credential scope: global or folder",
|
|
6446
|
+
"global"
|
|
6447
|
+
).action(async (options) => {
|
|
6257
6448
|
process.exitCode = await handleWait([
|
|
6258
|
-
...options.timeout ? ["--timeout", options.timeout] : []
|
|
6449
|
+
...options.timeout ? ["--timeout", options.timeout] : [],
|
|
6450
|
+
"--auth-scope",
|
|
6451
|
+
String(options.authScope ?? "global")
|
|
6259
6452
|
]);
|
|
6260
6453
|
});
|
|
6261
6454
|
auth.command("status").description("Show the current CLI auth and workspace status.").addHelpText(
|
|
@@ -6268,14 +6461,16 @@ Notes:
|
|
|
6268
6461
|
|
|
6269
6462
|
Examples:
|
|
6270
6463
|
deepline auth status
|
|
6464
|
+
deepline auth status --auth-scope folder
|
|
6271
6465
|
deepline auth status --json
|
|
6272
6466
|
`
|
|
6273
6467
|
).option(
|
|
6274
6468
|
"--reveal",
|
|
6275
6469
|
"Persist the revealed API key back to the host auth file"
|
|
6276
|
-
).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
|
|
6470
|
+
).option("--auth-scope <scope>", "Read only folder or global auth").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
|
|
6277
6471
|
process.exitCode = await handleStatus([
|
|
6278
6472
|
...options.reveal ? ["--reveal"] : [],
|
|
6473
|
+
...options.authScope ? ["--auth-scope", String(options.authScope)] : [],
|
|
6279
6474
|
...options.json ? ["--json"] : []
|
|
6280
6475
|
]);
|
|
6281
6476
|
});
|
|
@@ -7486,7 +7681,7 @@ import {
|
|
|
7486
7681
|
writeFileSync as writeFileSync6
|
|
7487
7682
|
} from "fs";
|
|
7488
7683
|
import { homedir as homedir6 } from "os";
|
|
7489
|
-
import { join as
|
|
7684
|
+
import { join as join6, resolve as resolve5 } from "path";
|
|
7490
7685
|
|
|
7491
7686
|
// src/cli/dataset-stats.ts
|
|
7492
7687
|
import { writeFileSync as writeFileSync5 } from "fs";
|
|
@@ -8252,13 +8447,13 @@ async function handleCsvShow(options) {
|
|
|
8252
8447
|
);
|
|
8253
8448
|
}
|
|
8254
8449
|
function csvRenderStatePath() {
|
|
8255
|
-
return
|
|
8450
|
+
return join6(homedir6(), ".local", "deepline", "runtime", "csv-render.json");
|
|
8256
8451
|
}
|
|
8257
8452
|
function csvRenderLogPath() {
|
|
8258
|
-
return
|
|
8453
|
+
return join6(homedir6(), ".local", "deepline", "runtime", "csv-render.log");
|
|
8259
8454
|
}
|
|
8260
8455
|
function ensureCsvRenderStateDir() {
|
|
8261
|
-
mkdirSync5(
|
|
8456
|
+
mkdirSync5(join6(homedir6(), ".local", "deepline", "runtime"), {
|
|
8262
8457
|
recursive: true
|
|
8263
8458
|
});
|
|
8264
8459
|
}
|
|
@@ -9037,7 +9232,7 @@ import {
|
|
|
9037
9232
|
writeFile as writeFile3
|
|
9038
9233
|
} from "fs/promises";
|
|
9039
9234
|
import { homedir as homedir7, tmpdir as tmpdir2 } from "os";
|
|
9040
|
-
import { basename as basename2, dirname as dirname7, extname, join as
|
|
9235
|
+
import { basename as basename2, dirname as dirname7, extname, join as join8, resolve as resolve9 } from "path";
|
|
9041
9236
|
import { Option } from "commander";
|
|
9042
9237
|
|
|
9043
9238
|
// src/cli/commands/play.ts
|
|
@@ -9050,7 +9245,7 @@ import {
|
|
|
9050
9245
|
statSync as statSync3,
|
|
9051
9246
|
writeFileSync as writeFileSync9
|
|
9052
9247
|
} from "fs";
|
|
9053
|
-
import { basename, dirname as dirname6, join as
|
|
9248
|
+
import { basename, dirname as dirname6, join as join7, resolve as resolve8 } from "path";
|
|
9054
9249
|
import { parse as parseCsvSync2 } from "csv-parse/sync";
|
|
9055
9250
|
|
|
9056
9251
|
// src/cli/commands/plays/bootstrap.ts
|
|
@@ -9061,7 +9256,7 @@ import {
|
|
|
9061
9256
|
statSync as statSync2,
|
|
9062
9257
|
writeFileSync as writeFileSync8
|
|
9063
9258
|
} from "fs";
|
|
9064
|
-
import { isAbsolute, relative, resolve as resolve7 } from "path";
|
|
9259
|
+
import { isAbsolute as isAbsolute2, relative, resolve as resolve7 } from "path";
|
|
9065
9260
|
import { parse as parseCsvSync } from "csv-parse/sync";
|
|
9066
9261
|
|
|
9067
9262
|
// ../shared_libs/plays/bootstrap-routes.ts
|
|
@@ -9709,7 +9904,7 @@ function packagedCsvPathForPlay(csvPath) {
|
|
|
9709
9904
|
const playDir = process.cwd();
|
|
9710
9905
|
const absoluteCsvPath = resolve7(csvPath);
|
|
9711
9906
|
const relativePath = relative(playDir, absoluteCsvPath);
|
|
9712
|
-
if (relativePath === "" || relativePath.startsWith("..") ||
|
|
9907
|
+
if (relativePath === "" || relativePath.startsWith("..") || isAbsolute2(relativePath)) {
|
|
9713
9908
|
throw new PlayBootstrapUsageError(
|
|
9714
9909
|
`--from csv:${csvPath} must point to a file inside the directory where you run plays bootstrap. Run bootstrap from the intended play directory and write the play with --out there.`
|
|
9715
9910
|
);
|
|
@@ -11331,7 +11526,7 @@ function traceCliSync(phase, fields, run) {
|
|
|
11331
11526
|
}
|
|
11332
11527
|
}
|
|
11333
11528
|
function sleep5(ms) {
|
|
11334
|
-
return new Promise((
|
|
11529
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
11335
11530
|
}
|
|
11336
11531
|
function parseReferencedPlayTarget2(target) {
|
|
11337
11532
|
const trimmed = target.trim();
|
|
@@ -15985,7 +16180,7 @@ async function handlePlayRun(args, hooks) {
|
|
|
15985
16180
|
if (siblings.length > 0) {
|
|
15986
16181
|
console.error(`Did you mean one of these?`);
|
|
15987
16182
|
for (const s of siblings.slice(0, 5)) {
|
|
15988
|
-
console.error(` ${
|
|
16183
|
+
console.error(` ${join7(dir, s)}`);
|
|
15989
16184
|
}
|
|
15990
16185
|
}
|
|
15991
16186
|
} catch {
|
|
@@ -19646,7 +19841,7 @@ function emitEnrichDebug(message) {
|
|
|
19646
19841
|
);
|
|
19647
19842
|
}
|
|
19648
19843
|
function sleep6(ms) {
|
|
19649
|
-
return new Promise((
|
|
19844
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
19650
19845
|
}
|
|
19651
19846
|
function enrichExportBackingRowsWaitMs() {
|
|
19652
19847
|
const raw = process.env.DEEPLINE_ENRICH_EXPORT_BACKING_ROWS_WAIT_MS?.trim();
|
|
@@ -19678,7 +19873,7 @@ function expandAtFilePath(rawPath) {
|
|
|
19678
19873
|
return homedir7();
|
|
19679
19874
|
}
|
|
19680
19875
|
if (expanded.startsWith("~/") || expanded.startsWith("~\\")) {
|
|
19681
|
-
return
|
|
19876
|
+
return join8(homedir7(), expanded.slice(2));
|
|
19682
19877
|
}
|
|
19683
19878
|
return expanded;
|
|
19684
19879
|
}
|
|
@@ -22048,7 +22243,7 @@ function sidecarEnrichRowsExportPath(outputPath) {
|
|
|
22048
22243
|
const resolved = resolve9(outputPath);
|
|
22049
22244
|
const ext = extname(resolved) || ".csv";
|
|
22050
22245
|
const stem = basename2(resolved, ext);
|
|
22051
|
-
return
|
|
22246
|
+
return join8(dirname7(resolved), `${stem}.deepline-enrich-rows${ext}`);
|
|
22052
22247
|
}
|
|
22053
22248
|
function collectDatasetFollowUpCommands(value, state) {
|
|
22054
22249
|
if (state.depth > 12 || !value || typeof value !== "object" || state.commands.length >= 8) {
|
|
@@ -22129,10 +22324,10 @@ async function persistEnrichFailureReport(input2) {
|
|
|
22129
22324
|
if (input2.jobs.length === 0 && input2.issues.length === 0) {
|
|
22130
22325
|
return null;
|
|
22131
22326
|
}
|
|
22132
|
-
const stateDir =
|
|
22327
|
+
const stateDir = join8(homedir7(), ".local", "deepline", "runtime", "state");
|
|
22133
22328
|
const reportPrefix = input2.jobs.length > 0 ? "run-block-failures" : "enrich-issues";
|
|
22134
22329
|
await mkdir3(stateDir, { recursive: true });
|
|
22135
|
-
const reportPath =
|
|
22330
|
+
const reportPath = join8(
|
|
22136
22331
|
stateDir,
|
|
22137
22332
|
`${reportPrefix}-${Math.floor(Date.now() / 1e3)}-${process.pid}.json`
|
|
22138
22333
|
);
|
|
@@ -23036,9 +23231,9 @@ function registerEnrichCommand(program) {
|
|
|
23036
23231
|
sdkEnrichTelemetryCompleted = true;
|
|
23037
23232
|
await completeSdkEnrichTelemetry(sdkEnrichTelemetry, input2);
|
|
23038
23233
|
};
|
|
23039
|
-
const tempDir = await mkdtemp(
|
|
23234
|
+
const tempDir = await mkdtemp(join8(tmpdir2(), "deepline-enrich-play-"));
|
|
23040
23235
|
await emitSdkEnrichTelemetry(sdkEnrichTelemetry, "enrich_started");
|
|
23041
|
-
const tempPlay =
|
|
23236
|
+
const tempPlay = join8(tempDir, "deepline-enrich.play.ts");
|
|
23042
23237
|
let inPlaceTempDir = null;
|
|
23043
23238
|
let inPlaceTempOutputPath = null;
|
|
23044
23239
|
const inPlaceFinalOutputPath = options.inPlace ? resolve9(inputCsv) : null;
|
|
@@ -23066,12 +23261,12 @@ function registerEnrichCommand(program) {
|
|
|
23066
23261
|
await rm(inPlaceTempDir, { recursive: true, force: true });
|
|
23067
23262
|
}
|
|
23068
23263
|
inPlaceTempDir = await mkdtemp(
|
|
23069
|
-
|
|
23264
|
+
join8(
|
|
23070
23265
|
dirname7(inPlaceCommitOutputPath ?? resolve9(inputCsv)),
|
|
23071
23266
|
".deepline-enrich-in-place-"
|
|
23072
23267
|
)
|
|
23073
23268
|
);
|
|
23074
|
-
inPlaceTempOutputPath =
|
|
23269
|
+
inPlaceTempOutputPath = join8(inPlaceTempDir, "output.csv");
|
|
23075
23270
|
await copyFile(resolve9(inputCsv), inPlaceTempOutputPath);
|
|
23076
23271
|
outputPath = inPlaceTempOutputPath;
|
|
23077
23272
|
};
|
|
@@ -23352,7 +23547,7 @@ import {
|
|
|
23352
23547
|
writeFileSync as writeFileSync10
|
|
23353
23548
|
} from "fs";
|
|
23354
23549
|
import { homedir as homedir8, platform } from "os";
|
|
23355
|
-
import { basename as basename3, dirname as dirname8, join as
|
|
23550
|
+
import { basename as basename3, dirname as dirname8, join as join9, resolve as resolve10 } from "path";
|
|
23356
23551
|
import { gzipSync } from "zlib";
|
|
23357
23552
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
23358
23553
|
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
@@ -23378,10 +23573,10 @@ function detectShellContext() {
|
|
|
23378
23573
|
};
|
|
23379
23574
|
}
|
|
23380
23575
|
function claudeProjectsRoot() {
|
|
23381
|
-
return
|
|
23576
|
+
return join9(homeDir(), ".claude", "projects");
|
|
23382
23577
|
}
|
|
23383
23578
|
function codexSessionsRoot() {
|
|
23384
|
-
return
|
|
23579
|
+
return join9(homeDir(), ".codex", "sessions");
|
|
23385
23580
|
}
|
|
23386
23581
|
function listClaudeSessionFiles() {
|
|
23387
23582
|
const root = claudeProjectsRoot();
|
|
@@ -23389,10 +23584,10 @@ function listClaudeSessionFiles() {
|
|
|
23389
23584
|
const projectDirs = readDirectoryNames(root);
|
|
23390
23585
|
const files = [];
|
|
23391
23586
|
for (const projectDir of projectDirs) {
|
|
23392
|
-
const fullProjectDir =
|
|
23587
|
+
const fullProjectDir = join9(root, projectDir);
|
|
23393
23588
|
for (const fileName of readDirectoryNames(fullProjectDir)) {
|
|
23394
23589
|
if (fileName.endsWith(".jsonl")) {
|
|
23395
|
-
const filePath =
|
|
23590
|
+
const filePath = join9(fullProjectDir, fileName);
|
|
23396
23591
|
const sessionId = sessionIdFromClaudeFilePath(filePath);
|
|
23397
23592
|
const stat2 = statIfReadable(filePath);
|
|
23398
23593
|
if (sessionId && stat2) {
|
|
@@ -23449,7 +23644,7 @@ function listJsonlFilesRecursive(root, maxDepth) {
|
|
|
23449
23644
|
return;
|
|
23450
23645
|
}
|
|
23451
23646
|
for (const entry of entries) {
|
|
23452
|
-
const fullPath =
|
|
23647
|
+
const fullPath = join9(dir, entry.name);
|
|
23453
23648
|
if (entry.isDirectory()) {
|
|
23454
23649
|
visit(fullPath, depth + 1);
|
|
23455
23650
|
} else if (entry.isFile() && entry.name.endsWith(".jsonl")) {
|
|
@@ -23864,8 +24059,8 @@ function loadViewerAssets() {
|
|
|
23864
24059
|
const cliEntry = process.argv[1]?.trim() ? resolve10(process.argv[1]) : null;
|
|
23865
24060
|
const candidateRoots2 = [
|
|
23866
24061
|
...cliEntry ? [
|
|
23867
|
-
|
|
23868
|
-
|
|
24062
|
+
join9(dirname8(dirname8(cliEntry)), "viewer"),
|
|
24063
|
+
join9(
|
|
23869
24064
|
dirname8(dirname8(dirname8(cliEntry))),
|
|
23870
24065
|
"src",
|
|
23871
24066
|
"lib",
|
|
@@ -23873,12 +24068,12 @@ function loadViewerAssets() {
|
|
|
23873
24068
|
"viewer"
|
|
23874
24069
|
)
|
|
23875
24070
|
] : [],
|
|
23876
|
-
|
|
24071
|
+
join9(process.cwd(), "src", "lib", "cli", "viewer")
|
|
23877
24072
|
];
|
|
23878
24073
|
for (const root of candidateRoots2) {
|
|
23879
24074
|
try {
|
|
23880
|
-
const cssPath =
|
|
23881
|
-
const jsPath =
|
|
24075
|
+
const cssPath = join9(root, "viewer.css");
|
|
24076
|
+
const jsPath = join9(root, "viewer.js");
|
|
23882
24077
|
if (!existsSync8(cssPath) || !existsSync8(jsPath)) continue;
|
|
23883
24078
|
return {
|
|
23884
24079
|
css: readFileSync8(cssPath, "utf8"),
|
|
@@ -23908,9 +24103,9 @@ async function handleSessionsRender(options) {
|
|
|
23908
24103
|
});
|
|
23909
24104
|
let outputPath = options.output ? resolve10(options.output) : "";
|
|
23910
24105
|
if (!outputPath) {
|
|
23911
|
-
const outputDir =
|
|
24106
|
+
const outputDir = join9(process.cwd(), "deepline", "data");
|
|
23912
24107
|
mkdirSync6(outputDir, { recursive: true });
|
|
23913
|
-
outputPath =
|
|
24108
|
+
outputPath = join9(
|
|
23914
24109
|
outputDir,
|
|
23915
24110
|
targets.length > 1 ? "session-viewer.html" : `session-${targets[0]?.sessionId}.html`
|
|
23916
24111
|
);
|
|
@@ -25080,7 +25275,7 @@ Examples:
|
|
|
25080
25275
|
async function fetchOrganizations(http2, apiKey) {
|
|
25081
25276
|
return http2.post("/api/v2/auth/cli/organizations", { api_key: apiKey });
|
|
25082
25277
|
}
|
|
25083
|
-
function
|
|
25278
|
+
function normalizeAuthScope2(value) {
|
|
25084
25279
|
if (!value) return "auto";
|
|
25085
25280
|
if (value === "auto" || value === "folder" || value === "global") {
|
|
25086
25281
|
return value;
|
|
@@ -25283,7 +25478,7 @@ async function handleOrgStatus(options) {
|
|
|
25283
25478
|
);
|
|
25284
25479
|
}
|
|
25285
25480
|
async function handleOrgSwitch(selection, options) {
|
|
25286
|
-
const authScope =
|
|
25481
|
+
const authScope = normalizeAuthScope2(options.authScope);
|
|
25287
25482
|
const config = resolveConfig();
|
|
25288
25483
|
const http2 = new HttpClient(config);
|
|
25289
25484
|
const payload = await fetchOrganizations(http2, config.apiKey);
|
|
@@ -25660,17 +25855,17 @@ function hasClaudeBinary() {
|
|
|
25660
25855
|
}
|
|
25661
25856
|
}
|
|
25662
25857
|
function launchClaude(prompt) {
|
|
25663
|
-
return new Promise((
|
|
25858
|
+
return new Promise((resolve15) => {
|
|
25664
25859
|
const child = spawn2("claude", [prompt], {
|
|
25665
25860
|
stdio: "inherit",
|
|
25666
25861
|
shell: process.platform === "win32"
|
|
25667
25862
|
});
|
|
25668
|
-
child.on("error", () =>
|
|
25669
|
-
child.on("close", (status) =>
|
|
25863
|
+
child.on("error", () => resolve15(EXIT_SERVER3));
|
|
25864
|
+
child.on("close", (status) => resolve15(status ?? EXIT_OK2));
|
|
25670
25865
|
});
|
|
25671
25866
|
}
|
|
25672
25867
|
function readBody(req) {
|
|
25673
|
-
return new Promise((
|
|
25868
|
+
return new Promise((resolve15, reject) => {
|
|
25674
25869
|
let raw = "";
|
|
25675
25870
|
req.setEncoding("utf8");
|
|
25676
25871
|
req.on("data", (chunk) => {
|
|
@@ -25680,7 +25875,7 @@ function readBody(req) {
|
|
|
25680
25875
|
req.destroy();
|
|
25681
25876
|
}
|
|
25682
25877
|
});
|
|
25683
|
-
req.on("end", () =>
|
|
25878
|
+
req.on("end", () => resolve15(raw));
|
|
25684
25879
|
req.on("error", reject);
|
|
25685
25880
|
});
|
|
25686
25881
|
}
|
|
@@ -25735,7 +25930,7 @@ function startCallbackServer(input2) {
|
|
|
25735
25930
|
writeJson(res, 400, { error: "Invalid request body." });
|
|
25736
25931
|
});
|
|
25737
25932
|
});
|
|
25738
|
-
return new Promise((
|
|
25933
|
+
return new Promise((resolve15, reject) => {
|
|
25739
25934
|
server.once("error", reject);
|
|
25740
25935
|
server.listen(0, "127.0.0.1", () => {
|
|
25741
25936
|
const address = server.address();
|
|
@@ -25743,7 +25938,7 @@ function startCallbackServer(input2) {
|
|
|
25743
25938
|
reject(new Error("Failed to bind quickstart callback server."));
|
|
25744
25939
|
return;
|
|
25745
25940
|
}
|
|
25746
|
-
|
|
25941
|
+
resolve15({ server, port: address.port });
|
|
25747
25942
|
});
|
|
25748
25943
|
});
|
|
25749
25944
|
}
|
|
@@ -25769,8 +25964,8 @@ async function handleQuickstart(options) {
|
|
|
25769
25964
|
}
|
|
25770
25965
|
const state = randomBytes(32).toString("hex");
|
|
25771
25966
|
let resolveSelection;
|
|
25772
|
-
const selectionPromise = new Promise((
|
|
25773
|
-
resolveSelection =
|
|
25967
|
+
const selectionPromise = new Promise((resolve15) => {
|
|
25968
|
+
resolveSelection = resolve15;
|
|
25774
25969
|
});
|
|
25775
25970
|
let callback;
|
|
25776
25971
|
try {
|
|
@@ -25909,7 +26104,7 @@ async function readHiddenLine(prompt, streams = {}) {
|
|
|
25909
26104
|
}
|
|
25910
26105
|
let value = "";
|
|
25911
26106
|
inputStream.resume();
|
|
25912
|
-
return await new Promise((
|
|
26107
|
+
return await new Promise((resolve15, reject) => {
|
|
25913
26108
|
let settled = false;
|
|
25914
26109
|
const cleanup = () => {
|
|
25915
26110
|
inputStream.off("data", onData);
|
|
@@ -25927,7 +26122,7 @@ async function readHiddenLine(prompt, streams = {}) {
|
|
|
25927
26122
|
settled = true;
|
|
25928
26123
|
outputStream.write("\n");
|
|
25929
26124
|
cleanup();
|
|
25930
|
-
|
|
26125
|
+
resolve15(line);
|
|
25931
26126
|
};
|
|
25932
26127
|
const fail = (error) => {
|
|
25933
26128
|
if (settled) return;
|
|
@@ -26100,7 +26295,7 @@ Examples:
|
|
|
26100
26295
|
// src/cli/commands/switch.ts
|
|
26101
26296
|
import { existsSync as existsSync9, mkdirSync as mkdirSync7, readFileSync as readFileSync10, writeFileSync as writeFileSync11 } from "fs";
|
|
26102
26297
|
import { homedir as homedir9 } from "os";
|
|
26103
|
-
import { dirname as dirname9, join as
|
|
26298
|
+
import { dirname as dirname9, join as join10 } from "path";
|
|
26104
26299
|
function hostSlugFromBaseUrl(baseUrl) {
|
|
26105
26300
|
try {
|
|
26106
26301
|
const url = new URL(baseUrl);
|
|
@@ -26121,7 +26316,7 @@ function resolveConfigScope() {
|
|
|
26121
26316
|
}
|
|
26122
26317
|
function activeFamilyPath() {
|
|
26123
26318
|
const home = process.env.HOME || process.env.USERPROFILE || homedir9();
|
|
26124
|
-
return
|
|
26319
|
+
return join10(
|
|
26125
26320
|
home,
|
|
26126
26321
|
".local",
|
|
26127
26322
|
"deepline",
|
|
@@ -26266,7 +26461,7 @@ import {
|
|
|
26266
26461
|
writeFileSync as writeFileSync13
|
|
26267
26462
|
} from "fs";
|
|
26268
26463
|
import { tmpdir as tmpdir3 } from "os";
|
|
26269
|
-
import { join as
|
|
26464
|
+
import { join as join12, resolve as resolve11 } from "path";
|
|
26270
26465
|
|
|
26271
26466
|
// src/tool-output.ts
|
|
26272
26467
|
import {
|
|
@@ -26277,7 +26472,7 @@ import {
|
|
|
26277
26472
|
writeSync
|
|
26278
26473
|
} from "fs";
|
|
26279
26474
|
import { homedir as homedir10 } from "os";
|
|
26280
|
-
import { dirname as dirname10, join as
|
|
26475
|
+
import { dirname as dirname10, join as join11 } from "path";
|
|
26281
26476
|
function isPlainObject(value) {
|
|
26282
26477
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
26283
26478
|
}
|
|
@@ -26404,18 +26599,18 @@ function projectRowOutput(conversion) {
|
|
|
26404
26599
|
};
|
|
26405
26600
|
}
|
|
26406
26601
|
function ensureOutputDir() {
|
|
26407
|
-
const outputDir =
|
|
26602
|
+
const outputDir = join11(homedir10(), ".local", "share", "deepline", "data");
|
|
26408
26603
|
mkdirSync8(outputDir, { recursive: true });
|
|
26409
26604
|
return outputDir;
|
|
26410
26605
|
}
|
|
26411
26606
|
function writeJsonOutputFile(payload, stem) {
|
|
26412
26607
|
const outputDir = ensureOutputDir();
|
|
26413
|
-
const outputPath =
|
|
26608
|
+
const outputPath = join11(outputDir, `${stem}_${Date.now()}.json`);
|
|
26414
26609
|
writeFileSync12(outputPath, JSON.stringify(payload, null, 2), "utf-8");
|
|
26415
26610
|
return outputPath;
|
|
26416
26611
|
}
|
|
26417
26612
|
function writeCsvOutputFile(rows, stem, options) {
|
|
26418
|
-
const outputPath = options?.outPath ? options.outPath :
|
|
26613
|
+
const outputPath = options?.outPath ? options.outPath : join11(ensureOutputDir(), `${stem}_${Date.now()}.csv`);
|
|
26419
26614
|
mkdirSync8(dirname10(outputPath), { recursive: true });
|
|
26420
26615
|
const columns = columnsForRows(rows);
|
|
26421
26616
|
const escapeCell = (value) => {
|
|
@@ -27812,9 +28007,9 @@ function starterScriptJson(script) {
|
|
|
27812
28007
|
function seedToolListScript(input2) {
|
|
27813
28008
|
const stem = safeFileStem(input2.toolId);
|
|
27814
28009
|
const fileName = `${stem}-workflow-seed-${Date.now()}.play.ts`;
|
|
27815
|
-
const scriptDir = mkdtempSync(
|
|
28010
|
+
const scriptDir = mkdtempSync(join12(tmpdir3(), "deepline-workflow-seed-"));
|
|
27816
28011
|
chmodSync(scriptDir, 448);
|
|
27817
|
-
const scriptPath =
|
|
28012
|
+
const scriptPath = join12(scriptDir, fileName);
|
|
27818
28013
|
const projectDir = `deepline/projects/${stem}-workflow`;
|
|
27819
28014
|
const playName = `${stem}-workflow`;
|
|
27820
28015
|
const sampleRows = input2.rows.length > 0 ? `${JSON.stringify(input2.rows.slice(0, 2)).replace(/\]$/, "")}, ...]` : "[]";
|
|
@@ -28200,7 +28395,7 @@ async function executeTool(args) {
|
|
|
28200
28395
|
|
|
28201
28396
|
// src/cli/commands/workflow.ts
|
|
28202
28397
|
import { mkdir as mkdir4, readFile as readFile2, writeFile as writeFile4 } from "fs/promises";
|
|
28203
|
-
import { dirname as dirname11, join as
|
|
28398
|
+
import { dirname as dirname11, join as join13, resolve as resolve12 } from "path";
|
|
28204
28399
|
|
|
28205
28400
|
// src/cli/workflow-to-play.ts
|
|
28206
28401
|
import { createHash as createHash3 } from "crypto";
|
|
@@ -28489,7 +28684,7 @@ async function transformOne(api, workflowId, outDir, publish) {
|
|
|
28489
28684
|
revision.config,
|
|
28490
28685
|
{ workflowName: workflow.name, version: revision.version }
|
|
28491
28686
|
);
|
|
28492
|
-
const file =
|
|
28687
|
+
const file = join13(resolve12(outDir), `${compiled.playName}.play.ts`);
|
|
28493
28688
|
await mkdir4(dirname11(file), { recursive: true });
|
|
28494
28689
|
await writeFile4(file, compiled.sourceCode, "utf8");
|
|
28495
28690
|
let published = false;
|
|
@@ -28745,25 +28940,20 @@ import {
|
|
|
28745
28940
|
existsSync as existsSync12,
|
|
28746
28941
|
mkdirSync as mkdirSync10,
|
|
28747
28942
|
realpathSync as realpathSync3,
|
|
28748
|
-
readFileSync as
|
|
28943
|
+
readFileSync as readFileSync12,
|
|
28749
28944
|
renameSync,
|
|
28750
28945
|
rmSync as rmSync4,
|
|
28751
|
-
unlinkSync
|
|
28946
|
+
unlinkSync,
|
|
28752
28947
|
writeFileSync as writeFileSync15
|
|
28753
28948
|
} from "fs";
|
|
28754
|
-
import { homedir as
|
|
28755
|
-
import { dirname as dirname13, isAbsolute as
|
|
28949
|
+
import { homedir as homedir12 } from "os";
|
|
28950
|
+
import { dirname as dirname13, isAbsolute as isAbsolute3, join as join15, relative as relative2, resolve as resolve13 } from "path";
|
|
28756
28951
|
|
|
28757
|
-
// src/cli/skills
|
|
28758
|
-
import { spawn as spawn3
|
|
28759
|
-
import {
|
|
28760
|
-
|
|
28761
|
-
|
|
28762
|
-
readFileSync as readFileSync12,
|
|
28763
|
-
unlinkSync,
|
|
28764
|
-
writeFileSync as writeFileSync14
|
|
28765
|
-
} from "fs";
|
|
28766
|
-
import { dirname as dirname12, join as join13 } from "path";
|
|
28952
|
+
// src/cli/commands/skills.ts
|
|
28953
|
+
import { spawn as spawn3 } from "child_process";
|
|
28954
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync9, writeFileSync as writeFileSync14 } from "fs";
|
|
28955
|
+
import { homedir as homedir11 } from "os";
|
|
28956
|
+
import { dirname as dirname12, join as join14 } from "path";
|
|
28767
28957
|
|
|
28768
28958
|
// ../shared_libs/cli/install-commands.json
|
|
28769
28959
|
var install_commands_default = {
|
|
@@ -28779,7 +28969,7 @@ var install_commands_default = {
|
|
|
28779
28969
|
npx_binary: "npx",
|
|
28780
28970
|
npx_add_args_template: [
|
|
28781
28971
|
"--yes",
|
|
28782
|
-
"skills",
|
|
28972
|
+
"skills@latest",
|
|
28783
28973
|
"add",
|
|
28784
28974
|
"{skills_index_url}",
|
|
28785
28975
|
"--agent",
|
|
@@ -28869,311 +29059,319 @@ function sdkNpmGlobalInstallCommand() {
|
|
|
28869
29059
|
return INSTALL_COMMANDS.cli.sdk_npm_global;
|
|
28870
29060
|
}
|
|
28871
29061
|
|
|
28872
|
-
// src/cli/skills
|
|
28873
|
-
var
|
|
28874
|
-
|
|
28875
|
-
|
|
28876
|
-
|
|
28877
|
-
|
|
28878
|
-
|
|
28879
|
-
|
|
28880
|
-
|
|
29062
|
+
// src/cli/commands/skills.ts
|
|
29063
|
+
var RUNTIME_TO_SKILLS_AGENT = {
|
|
29064
|
+
antigravity: "antigravity",
|
|
29065
|
+
claude_code: "claude-code",
|
|
29066
|
+
claude_cowork: "claude-code",
|
|
29067
|
+
cline: "cline",
|
|
29068
|
+
codex: "codex",
|
|
29069
|
+
cursor: "cursor",
|
|
29070
|
+
gemini: "gemini-cli",
|
|
29071
|
+
windsurf: "windsurf"
|
|
29072
|
+
};
|
|
29073
|
+
var AGENT_MARKERS = [
|
|
29074
|
+
{ agent: "codex", paths: [".codex"] },
|
|
29075
|
+
{ agent: "claude-code", paths: [".claude"] },
|
|
29076
|
+
{ agent: "cursor", paths: [".cursor"] },
|
|
29077
|
+
{ agent: "gemini-cli", paths: [".gemini", ".gemini-cli"] },
|
|
29078
|
+
{ agent: "antigravity", paths: [".antigravity"] }
|
|
29079
|
+
];
|
|
29080
|
+
var WORKSPACE_SKILL_ROOTS_BY_AGENT = {
|
|
29081
|
+
antigravity: [".agents"],
|
|
29082
|
+
"claude-code": [".claude"],
|
|
29083
|
+
cline: [".agents"],
|
|
29084
|
+
codex: [".agents"],
|
|
29085
|
+
cursor: [".agents"],
|
|
29086
|
+
"gemini-cli": [".agents"],
|
|
29087
|
+
windsurf: [".windsurf"],
|
|
29088
|
+
"*": [".agents", ".claude", ".windsurf"]
|
|
29089
|
+
};
|
|
29090
|
+
function workspaceSkillRootsForAgents(agents) {
|
|
29091
|
+
return [
|
|
29092
|
+
...new Set(
|
|
29093
|
+
agents.flatMap((agent) => WORKSPACE_SKILL_ROOTS_BY_AGENT[agent] ?? [])
|
|
29094
|
+
)
|
|
29095
|
+
].sort((a, b) => a.localeCompare(b));
|
|
28881
29096
|
}
|
|
28882
|
-
function
|
|
28883
|
-
|
|
28884
|
-
if (
|
|
28885
|
-
|
|
28886
|
-
|
|
28887
|
-
const dir = process.env.DEEPLINE_PLUGIN_SKILLS_DIR?.trim() ?? "";
|
|
28888
|
-
return dir && existsSync11(dir) ? dir : "";
|
|
29097
|
+
function normalizeScope(value) {
|
|
29098
|
+
if (value === "global") return "global";
|
|
29099
|
+
if (value === "local") return "local";
|
|
29100
|
+
if (!value) return inferActiveSkillsScope();
|
|
29101
|
+
throw new Error("--scope must be one of: global, local");
|
|
28889
29102
|
}
|
|
28890
|
-
function
|
|
28891
|
-
|
|
28892
|
-
|
|
28893
|
-
|
|
28894
|
-
|
|
28895
|
-
|
|
28896
|
-
|
|
29103
|
+
function inferActiveSkillsScope(entrypoint = process.argv[1] ?? "") {
|
|
29104
|
+
return /[\\/]\.deepline[\\/]runtime[\\/]/.test(entrypoint) ? "local" : "global";
|
|
29105
|
+
}
|
|
29106
|
+
function resolveLocalRoot() {
|
|
29107
|
+
const target = resolveProjectPinTarget();
|
|
29108
|
+
if (!target.ok) {
|
|
29109
|
+
throw new Error(
|
|
29110
|
+
`Cowork project folder is ambiguous. Candidate folders: ${target.candidates.join(
|
|
29111
|
+
", "
|
|
29112
|
+
)}. Set CLAUDE_PROJECT_DIR or cd into the intended project folder.`
|
|
29113
|
+
);
|
|
28897
29114
|
}
|
|
29115
|
+
return target.dir;
|
|
28898
29116
|
}
|
|
28899
|
-
function
|
|
28900
|
-
|
|
29117
|
+
function detectSkillsAgents(input2) {
|
|
29118
|
+
const runtime = input2.runtime ?? detectAgentRuntime();
|
|
29119
|
+
const knownAgent = RUNTIME_TO_SKILLS_AGENT[runtime];
|
|
29120
|
+
if (knownAgent) return [knownAgent];
|
|
29121
|
+
const roots = [
|
|
29122
|
+
...input2.scope === "local" && input2.root ? [input2.root] : [],
|
|
29123
|
+
input2.homeDir ?? homedir11()
|
|
29124
|
+
];
|
|
29125
|
+
const detected = AGENT_MARKERS.filter(
|
|
29126
|
+
(marker) => roots.some(
|
|
29127
|
+
(root) => marker.paths.some((path) => existsSync11(join14(root, path)))
|
|
29128
|
+
)
|
|
29129
|
+
).map((marker) => marker.agent);
|
|
29130
|
+
return detected.length > 0 ? detected : ["*"];
|
|
28901
29131
|
}
|
|
28902
|
-
function
|
|
28903
|
-
|
|
29132
|
+
async function fetchSkillCatalog(baseUrl) {
|
|
29133
|
+
const response = await fetch(skillsIndexUrl(baseUrl));
|
|
29134
|
+
if (!response.ok) {
|
|
29135
|
+
throw new Error(
|
|
29136
|
+
`Skill catalog request failed (status ${response.status}).`
|
|
29137
|
+
);
|
|
29138
|
+
}
|
|
29139
|
+
const index = await response.json();
|
|
29140
|
+
const skillNames = (index.skills ?? []).filter((skill) => skill.install_surface === "v1").map((skill) => skill.name).filter((name) => typeof name === "string" && Boolean(name)).sort((a, b) => a.localeCompare(b));
|
|
29141
|
+
if (skillNames.length === 0) {
|
|
29142
|
+
throw new Error(
|
|
29143
|
+
"The Deepline skill catalog contains no installable skills."
|
|
29144
|
+
);
|
|
29145
|
+
}
|
|
29146
|
+
return {
|
|
29147
|
+
skillNames,
|
|
29148
|
+
version: typeof index.version === "string" && index.version.trim() ? index.version.trim() : "unversioned"
|
|
29149
|
+
};
|
|
28904
29150
|
}
|
|
28905
|
-
function
|
|
28906
|
-
return
|
|
29151
|
+
function skillsStatePathForScope(baseUrl, scope, root) {
|
|
29152
|
+
return scope === "local" && root ? join14(root, ".deepline", "setup", "skills.json") : join14(sdkCliStateDirPath(baseUrl), "skills-install.json");
|
|
28907
29153
|
}
|
|
28908
|
-
function
|
|
28909
|
-
const
|
|
28910
|
-
|
|
28911
|
-
|
|
28912
|
-
|
|
28913
|
-
|
|
28914
|
-
|
|
28915
|
-
|
|
28916
|
-
|
|
28917
|
-
|
|
29154
|
+
function buildSkillsPlan(input2) {
|
|
29155
|
+
const scopeArgs = input2.scope === "global" ? ["--global"] : [];
|
|
29156
|
+
const allManagedNames = [
|
|
29157
|
+
.../* @__PURE__ */ new Set([...input2.skillNames, ...LEGACY_SKILL_NAMES_TO_REMOVE])
|
|
29158
|
+
].sort((a, b) => a.localeCompare(b));
|
|
29159
|
+
return {
|
|
29160
|
+
scope: input2.scope,
|
|
29161
|
+
root: input2.root,
|
|
29162
|
+
agents: input2.agents,
|
|
29163
|
+
skillNames: input2.skillNames,
|
|
29164
|
+
version: input2.version,
|
|
29165
|
+
remove: {
|
|
29166
|
+
command: "npx",
|
|
29167
|
+
args: [
|
|
29168
|
+
"--yes",
|
|
29169
|
+
"skills@latest",
|
|
29170
|
+
"remove",
|
|
29171
|
+
...scopeArgs,
|
|
29172
|
+
"--agent",
|
|
29173
|
+
...input2.agents,
|
|
29174
|
+
"-y",
|
|
29175
|
+
...allManagedNames
|
|
29176
|
+
]
|
|
29177
|
+
},
|
|
29178
|
+
install: {
|
|
29179
|
+
command: "npx",
|
|
29180
|
+
args: [
|
|
29181
|
+
"--yes",
|
|
29182
|
+
"skills@latest",
|
|
29183
|
+
"add",
|
|
29184
|
+
skillsIndexUrl(input2.baseUrl),
|
|
29185
|
+
"--agent",
|
|
29186
|
+
...input2.agents,
|
|
29187
|
+
...scopeArgs,
|
|
29188
|
+
"--yes",
|
|
29189
|
+
...input2.skillNames.flatMap((name) => ["--skill", name]),
|
|
29190
|
+
"--full-depth"
|
|
29191
|
+
]
|
|
29192
|
+
},
|
|
29193
|
+
statePath: skillsStatePathForScope(input2.baseUrl, input2.scope, input2.root)
|
|
29194
|
+
};
|
|
28918
29195
|
}
|
|
28919
|
-
function
|
|
28920
|
-
|
|
28921
|
-
|
|
28922
|
-
|
|
28923
|
-
|
|
29196
|
+
function runProcess(command, args, cwd) {
|
|
29197
|
+
return new Promise((resolve15, reject) => {
|
|
29198
|
+
const child = spawn3(command, args, {
|
|
29199
|
+
cwd,
|
|
29200
|
+
env: process.env,
|
|
29201
|
+
stdio: ["ignore", "ignore", "pipe"],
|
|
29202
|
+
shell: process.platform === "win32"
|
|
29203
|
+
});
|
|
29204
|
+
let stderr = "";
|
|
29205
|
+
child.stderr.on("data", (chunk) => {
|
|
29206
|
+
stderr += chunk.toString("utf8");
|
|
29207
|
+
process.stderr.write(chunk);
|
|
29208
|
+
});
|
|
29209
|
+
child.once("error", reject);
|
|
29210
|
+
child.once("close", (code) => {
|
|
29211
|
+
if (code && stderr.trim()) {
|
|
29212
|
+
process.stderr.write(`skills@latest exited ${code}.
|
|
29213
|
+
`);
|
|
29214
|
+
}
|
|
29215
|
+
resolve15(code ?? 1);
|
|
29216
|
+
});
|
|
29217
|
+
});
|
|
28924
29218
|
}
|
|
28925
|
-
function
|
|
28926
|
-
|
|
29219
|
+
async function runSkillsCommand(options) {
|
|
29220
|
+
let scope;
|
|
29221
|
+
let root;
|
|
28927
29222
|
try {
|
|
28928
|
-
|
|
28929
|
-
|
|
28930
|
-
|
|
28931
|
-
|
|
28932
|
-
|
|
28933
|
-
|
|
28934
|
-
|
|
29223
|
+
scope = normalizeScope(options.scope);
|
|
29224
|
+
root = scope === "local" ? resolveLocalRoot() : null;
|
|
29225
|
+
} catch (error) {
|
|
29226
|
+
printCommandEnvelope(
|
|
29227
|
+
{
|
|
29228
|
+
ok: false,
|
|
29229
|
+
status: "failed",
|
|
29230
|
+
code: "INVALID_SKILLS_SCOPE",
|
|
29231
|
+
exitCode: 2,
|
|
29232
|
+
message: error instanceof Error ? error.message : String(error)
|
|
29233
|
+
},
|
|
29234
|
+
{ json: options.json }
|
|
29235
|
+
);
|
|
29236
|
+
return 2;
|
|
28935
29237
|
}
|
|
28936
|
-
const
|
|
28937
|
-
|
|
28938
|
-
`Deepline agent skills are out of date, but neither \`bunx\` nor \`npx\` is available. Install Node.js/npm or Bun, then run:
|
|
28939
|
-
${manualCommand}`
|
|
28940
|
-
);
|
|
28941
|
-
}
|
|
28942
|
-
function clearUnavailableSkillsNotice(baseUrl) {
|
|
29238
|
+
const baseUrl = autoDetectBaseUrl().replace(/\/$/, "");
|
|
29239
|
+
let catalog;
|
|
28943
29240
|
try {
|
|
28944
|
-
|
|
28945
|
-
} catch {
|
|
29241
|
+
catalog = options.dryRun ? { skillNames: [...DEFAULT_SDK_SKILL_NAMES], version: "latest" } : await fetchSkillCatalog(baseUrl);
|
|
29242
|
+
} catch (error) {
|
|
29243
|
+
printCommandEnvelope(
|
|
29244
|
+
{
|
|
29245
|
+
ok: false,
|
|
29246
|
+
status: "failed",
|
|
29247
|
+
code: "SKILLS_CATALOG_UNAVAILABLE",
|
|
29248
|
+
exitCode: 5,
|
|
29249
|
+
message: error instanceof Error ? error.message : String(error),
|
|
29250
|
+
next: "Retry: deepline skills"
|
|
29251
|
+
},
|
|
29252
|
+
{ json: options.json }
|
|
29253
|
+
);
|
|
29254
|
+
return 5;
|
|
28946
29255
|
}
|
|
28947
|
-
}
|
|
28948
|
-
|
|
28949
|
-
|
|
28950
|
-
(
|
|
29256
|
+
const agents = options.agent ? [options.agent] : detectSkillsAgents({ scope, root });
|
|
29257
|
+
const plan = buildSkillsPlan({ baseUrl, scope, root, agents, ...catalog });
|
|
29258
|
+
if (options.dryRun) {
|
|
29259
|
+
printCommandEnvelope(
|
|
29260
|
+
{ ok: true, status: "planned", dryRun: true, ...plan },
|
|
29261
|
+
{ json: options.json }
|
|
29262
|
+
);
|
|
29263
|
+
return 0;
|
|
29264
|
+
}
|
|
29265
|
+
if (scope === "local" && root) {
|
|
29266
|
+
const managedNames = [
|
|
29267
|
+
.../* @__PURE__ */ new Set([...plan.skillNames, ...LEGACY_SKILL_NAMES_TO_REMOVE])
|
|
29268
|
+
];
|
|
29269
|
+
const agentRoots = workspaceSkillRootsForAgents(plan.agents);
|
|
29270
|
+
ensureProjectPrivatePathsIgnored(root, [
|
|
29271
|
+
".deepline/",
|
|
29272
|
+
...agentRoots.flatMap(
|
|
29273
|
+
(agentRoot) => managedNames.map((name) => `${agentRoot}/skills/${name}/`)
|
|
29274
|
+
)
|
|
29275
|
+
]);
|
|
29276
|
+
}
|
|
29277
|
+
process.stderr.write(
|
|
29278
|
+
`Replacing Deepline skills for ${agents.join(", ")} (${scope})...
|
|
29279
|
+
`
|
|
28951
29280
|
);
|
|
28952
|
-
}
|
|
28953
|
-
async function fetchV1SkillNames(baseUrl) {
|
|
28954
|
-
const controller = new AbortController();
|
|
28955
|
-
const timeout = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS2);
|
|
28956
29281
|
try {
|
|
28957
|
-
const
|
|
28958
|
-
|
|
28959
|
-
|
|
29282
|
+
const removeCode = await runProcess(
|
|
29283
|
+
plan.remove.command,
|
|
29284
|
+
plan.remove.args,
|
|
29285
|
+
root ?? void 0
|
|
28960
29286
|
);
|
|
28961
|
-
if (
|
|
28962
|
-
|
|
28963
|
-
|
|
28964
|
-
|
|
29287
|
+
if (removeCode !== 0) {
|
|
29288
|
+
throw new Error("Could not remove the existing Deepline skills.");
|
|
29289
|
+
}
|
|
29290
|
+
const installCode = await runProcess(
|
|
29291
|
+
plan.install.command,
|
|
29292
|
+
plan.install.args,
|
|
29293
|
+
root ?? void 0
|
|
28965
29294
|
);
|
|
28966
|
-
|
|
28967
|
-
|
|
28968
|
-
|
|
28969
|
-
}
|
|
28970
|
-
|
|
28971
|
-
|
|
28972
|
-
}
|
|
28973
|
-
function buildSdkSkillNames(v1SkillNames) {
|
|
28974
|
-
return sortedUniqueSkillNames(v1SkillNames);
|
|
28975
|
-
}
|
|
28976
|
-
async function fetchSkillsUpdate(baseUrl, localVersion) {
|
|
28977
|
-
const controller = new AbortController();
|
|
28978
|
-
const timeout = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS2);
|
|
28979
|
-
try {
|
|
28980
|
-
const response = await fetch(new URL("/api/v2/cli/update-check", baseUrl), {
|
|
28981
|
-
method: "POST",
|
|
28982
|
-
headers: { "Content-Type": "application/json" },
|
|
28983
|
-
body: JSON.stringify({
|
|
28984
|
-
skills: {
|
|
28985
|
-
version: localVersion
|
|
28986
|
-
}
|
|
28987
|
-
}),
|
|
28988
|
-
signal: controller.signal
|
|
28989
|
-
});
|
|
28990
|
-
if (!response.ok) return null;
|
|
28991
|
-
const data = await response.json().catch(() => null);
|
|
28992
|
-
const skills = data?.skills;
|
|
28993
|
-
if (!skills) return null;
|
|
28994
|
-
return {
|
|
28995
|
-
needsUpdate: skills.needs_update === true,
|
|
28996
|
-
remoteVersion: typeof skills.remote?.version === "string" ? skills.remote.version.trim() : ""
|
|
28997
|
-
};
|
|
28998
|
-
} catch {
|
|
28999
|
-
return null;
|
|
29000
|
-
} finally {
|
|
29001
|
-
clearTimeout(timeout);
|
|
29002
|
-
}
|
|
29003
|
-
}
|
|
29004
|
-
function buildSkillsInstallArgs(baseUrl, skillNames = DEFAULT_SDK_SKILL_NAMES) {
|
|
29005
|
-
return buildSkillsAddArgs(baseUrl, sortedUniqueSkillNames(skillNames));
|
|
29006
|
-
}
|
|
29007
|
-
function buildBunxSkillsInstallArgs(baseUrl, skillNames) {
|
|
29008
|
-
return buildSkillsAddArgs(baseUrl, sortedUniqueSkillNames(skillNames), {
|
|
29009
|
-
firstArg: "--bun"
|
|
29010
|
-
});
|
|
29011
|
-
}
|
|
29012
|
-
function hasCommand(command) {
|
|
29013
|
-
const result = spawnSync2(command, ["--version"], {
|
|
29014
|
-
stdio: "ignore",
|
|
29015
|
-
shell: process.platform === "win32"
|
|
29016
|
-
});
|
|
29017
|
-
return result.status === 0;
|
|
29018
|
-
}
|
|
29019
|
-
function shellQuote5(arg) {
|
|
29020
|
-
return `'${arg.replace(/'/g, `'\\''`)}'`;
|
|
29021
|
-
}
|
|
29022
|
-
function resolveSkillsInstallCommands(baseUrl, skillNames = DEFAULT_SDK_SKILL_NAMES) {
|
|
29023
|
-
const commands = [];
|
|
29024
|
-
if (hasCommand("bunx")) {
|
|
29025
|
-
const bunxArgs = buildBunxSkillsInstallArgs(baseUrl, skillNames);
|
|
29026
|
-
commands.push({
|
|
29027
|
-
command: "bunx",
|
|
29028
|
-
args: bunxArgs,
|
|
29029
|
-
manualCommand: `bunx ${bunxArgs.map(shellQuote5).join(" ")}`
|
|
29030
|
-
});
|
|
29031
|
-
}
|
|
29032
|
-
if (hasCommand("npx")) {
|
|
29033
|
-
const npxArgs = buildSkillsInstallArgs(baseUrl, skillNames);
|
|
29034
|
-
commands.push({
|
|
29035
|
-
command: "npx",
|
|
29036
|
-
args: npxArgs,
|
|
29037
|
-
manualCommand: `npx ${npxArgs.map(shellQuote5).join(" ")}`
|
|
29038
|
-
});
|
|
29039
|
-
}
|
|
29040
|
-
return commands;
|
|
29041
|
-
}
|
|
29042
|
-
function runOneSkillsInstall(install) {
|
|
29043
|
-
return new Promise((resolve14) => {
|
|
29044
|
-
const child = spawn3(install.command, install.args, {
|
|
29045
|
-
stdio: ["ignore", "ignore", "pipe"],
|
|
29046
|
-
env: process.env
|
|
29047
|
-
});
|
|
29048
|
-
let stderr = "";
|
|
29049
|
-
child.stderr.on("data", (chunk) => {
|
|
29050
|
-
stderr += chunk.toString("utf-8");
|
|
29051
|
-
});
|
|
29052
|
-
child.on("error", (error) => {
|
|
29053
|
-
resolve14({
|
|
29054
|
-
ok: false,
|
|
29055
|
-
detail: `failed to start ${install.command}: ${error.message}`,
|
|
29056
|
-
manualCommand: install.manualCommand
|
|
29057
|
-
});
|
|
29058
|
-
});
|
|
29059
|
-
child.on("close", (code) => {
|
|
29060
|
-
if (code === 0) {
|
|
29061
|
-
resolve14({ ok: true, detail: "", manualCommand: install.manualCommand });
|
|
29062
|
-
return;
|
|
29063
|
-
}
|
|
29064
|
-
const detail = stderr.trim();
|
|
29065
|
-
resolve14({
|
|
29295
|
+
if (installCode !== 0) {
|
|
29296
|
+
throw new Error("Could not install the current Deepline skills.");
|
|
29297
|
+
}
|
|
29298
|
+
} catch (error) {
|
|
29299
|
+
printCommandEnvelope(
|
|
29300
|
+
{
|
|
29066
29301
|
ok: false,
|
|
29067
|
-
|
|
29068
|
-
|
|
29069
|
-
|
|
29070
|
-
|
|
29071
|
-
|
|
29072
|
-
|
|
29073
|
-
|
|
29074
|
-
|
|
29075
|
-
|
|
29076
|
-
|
|
29077
|
-
|
|
29078
|
-
failures.push(result);
|
|
29302
|
+
status: "failed",
|
|
29303
|
+
code: "SKILLS_INSTALL_FAILED",
|
|
29304
|
+
exitCode: 5,
|
|
29305
|
+
scope,
|
|
29306
|
+
agents,
|
|
29307
|
+
message: error instanceof Error ? error.message : String(error),
|
|
29308
|
+
next: `deepline skills --scope ${scope} --json`
|
|
29309
|
+
},
|
|
29310
|
+
{ json: options.json }
|
|
29311
|
+
);
|
|
29312
|
+
return 5;
|
|
29079
29313
|
}
|
|
29080
|
-
|
|
29081
|
-
|
|
29082
|
-
|
|
29083
|
-
|
|
29084
|
-
|
|
29085
|
-
|
|
29086
|
-
|
|
29314
|
+
mkdirSync9(dirname12(plan.statePath), { recursive: true });
|
|
29315
|
+
writeFileSync14(
|
|
29316
|
+
plan.statePath,
|
|
29317
|
+
`${JSON.stringify(
|
|
29318
|
+
{
|
|
29319
|
+
schemaVersion: 1,
|
|
29320
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
29321
|
+
cliVersion: SDK_VERSION,
|
|
29322
|
+
scope,
|
|
29323
|
+
agents,
|
|
29324
|
+
skillsVersion: plan.version,
|
|
29325
|
+
skillNames: plan.skillNames
|
|
29326
|
+
},
|
|
29327
|
+
null,
|
|
29328
|
+
2
|
|
29329
|
+
)}
|
|
29330
|
+
`,
|
|
29331
|
+
"utf8"
|
|
29087
29332
|
);
|
|
29088
|
-
|
|
29089
|
-
}
|
|
29090
|
-
function runLegacySkillsCleanup() {
|
|
29091
|
-
const candidates = hasCommand("bunx") ? [
|
|
29333
|
+
printCommandEnvelope(
|
|
29092
29334
|
{
|
|
29093
|
-
|
|
29094
|
-
|
|
29095
|
-
|
|
29096
|
-
|
|
29097
|
-
|
|
29098
|
-
|
|
29099
|
-
|
|
29100
|
-
|
|
29101
|
-
|
|
29335
|
+
ok: true,
|
|
29336
|
+
status: "complete",
|
|
29337
|
+
scope,
|
|
29338
|
+
agents,
|
|
29339
|
+
skillsVersion: plan.version,
|
|
29340
|
+
skillCount: plan.skillNames.length,
|
|
29341
|
+
statePath: plan.statePath,
|
|
29342
|
+
render: {
|
|
29343
|
+
sections: [
|
|
29344
|
+
{
|
|
29345
|
+
title: "skills",
|
|
29346
|
+
lines: [
|
|
29347
|
+
`Scope: ${scope}`,
|
|
29348
|
+
`Agents: ${agents.join(", ")}`,
|
|
29349
|
+
`Installed: ${plan.skillNames.length}`
|
|
29350
|
+
]
|
|
29351
|
+
}
|
|
29352
|
+
]
|
|
29353
|
+
}
|
|
29102
29354
|
},
|
|
29103
|
-
{
|
|
29104
|
-
command: "npx",
|
|
29105
|
-
args: [
|
|
29106
|
-
"--yes",
|
|
29107
|
-
"skills",
|
|
29108
|
-
"remove",
|
|
29109
|
-
"--global",
|
|
29110
|
-
"-y",
|
|
29111
|
-
...LEGACY_SKILL_NAMES_TO_REMOVE
|
|
29112
|
-
]
|
|
29113
|
-
}
|
|
29114
|
-
] : [
|
|
29115
|
-
{
|
|
29116
|
-
command: "npx",
|
|
29117
|
-
args: [
|
|
29118
|
-
"--yes",
|
|
29119
|
-
"skills",
|
|
29120
|
-
"remove",
|
|
29121
|
-
"--global",
|
|
29122
|
-
"-y",
|
|
29123
|
-
...LEGACY_SKILL_NAMES_TO_REMOVE
|
|
29124
|
-
]
|
|
29125
|
-
}
|
|
29126
|
-
];
|
|
29127
|
-
for (const candidate of candidates) {
|
|
29128
|
-
const result = spawnSync2(candidate.command, candidate.args, {
|
|
29129
|
-
stdio: "ignore",
|
|
29130
|
-
env: process.env,
|
|
29131
|
-
shell: process.platform === "win32"
|
|
29132
|
-
});
|
|
29133
|
-
if (result.status === 0) return;
|
|
29134
|
-
}
|
|
29135
|
-
}
|
|
29136
|
-
function writeSdkSkillsStatusLine(line) {
|
|
29137
|
-
const progress = getActiveCliProgress();
|
|
29138
|
-
if (progress) {
|
|
29139
|
-
progress.writeLine(line);
|
|
29140
|
-
return;
|
|
29141
|
-
}
|
|
29142
|
-
process.stderr.write(`${line}
|
|
29143
|
-
`);
|
|
29144
|
-
}
|
|
29145
|
-
async function syncSdkSkillsIfNeeded(baseUrl, options = {}) {
|
|
29146
|
-
if (attemptedSync || shouldSkipSkillsSync()) return;
|
|
29147
|
-
attemptedSync = true;
|
|
29148
|
-
const usingPluginSkills = Boolean(activePluginSkillsDir());
|
|
29149
|
-
if (usingPluginSkills) {
|
|
29150
|
-
return;
|
|
29151
|
-
}
|
|
29152
|
-
const localVersion = readSdkSkillsLocalVersion(baseUrl);
|
|
29153
|
-
const update = options.update === void 0 ? await fetchSkillsUpdate(baseUrl, localVersion) : options.update ? {
|
|
29154
|
-
needsUpdate: options.update.needs_update,
|
|
29155
|
-
remoteVersion: options.update.remote.version
|
|
29156
|
-
} : null;
|
|
29157
|
-
if (!update?.needsUpdate || !update.remoteVersion) {
|
|
29158
|
-
return;
|
|
29159
|
-
}
|
|
29160
|
-
const remoteSkillNames = await fetchV1SkillNames(baseUrl);
|
|
29161
|
-
const skillNames = buildSdkSkillNames(
|
|
29162
|
-
remoteSkillNames.length > 0 ? remoteSkillNames : DEFAULT_SDK_SKILL_NAMES
|
|
29355
|
+
{ json: options.json }
|
|
29163
29356
|
);
|
|
29164
|
-
|
|
29165
|
-
|
|
29166
|
-
|
|
29167
|
-
|
|
29168
|
-
|
|
29169
|
-
|
|
29170
|
-
|
|
29171
|
-
|
|
29172
|
-
|
|
29173
|
-
|
|
29174
|
-
|
|
29175
|
-
|
|
29176
|
-
|
|
29357
|
+
return 0;
|
|
29358
|
+
}
|
|
29359
|
+
function registerSkillsCommand(program) {
|
|
29360
|
+
program.command("skills").description("Replace Deepline agent skills with the current release.").option("--scope <scope>", "Install scope: global or local").option("--agent <agent>", "Override the detected agent target").option("--dry-run", "Print the install plan without changing files").option("--json", "Emit one JSON result envelope").addHelpText(
|
|
29361
|
+
"after",
|
|
29362
|
+
`
|
|
29363
|
+
Notes:
|
|
29364
|
+
This command removes and reinstalls only Deepline-managed skill names using
|
|
29365
|
+
skills@latest. Local scope writes into the resolved persistent project.
|
|
29366
|
+
|
|
29367
|
+
Examples:
|
|
29368
|
+
deepline skills --json
|
|
29369
|
+
deepline skills --scope local --json
|
|
29370
|
+
deepline skills --agent codex --dry-run --json
|
|
29371
|
+
`
|
|
29372
|
+
).action(async (options) => {
|
|
29373
|
+
process.exitCode = await runSkillsCommand(options);
|
|
29374
|
+
});
|
|
29177
29375
|
}
|
|
29178
29376
|
|
|
29179
29377
|
// src/cli/commands/update.ts
|
|
@@ -29205,14 +29403,14 @@ function posixShellQuote(value) {
|
|
|
29205
29403
|
function windowsCmdQuote(value) {
|
|
29206
29404
|
return `"${value.replace(/"/g, '""')}"`;
|
|
29207
29405
|
}
|
|
29208
|
-
function
|
|
29406
|
+
function shellQuote5(value) {
|
|
29209
29407
|
if (process.platform === "win32") {
|
|
29210
29408
|
return /^[A-Za-z0-9_./:@%+=,-]+$/.test(value) ? value : windowsCmdQuote(value);
|
|
29211
29409
|
}
|
|
29212
29410
|
return posixShellQuote(value);
|
|
29213
29411
|
}
|
|
29214
29412
|
function buildSourceUpdateCommand(sourceRoot) {
|
|
29215
|
-
const quotedRoot =
|
|
29413
|
+
const quotedRoot = shellQuote5(sourceRoot);
|
|
29216
29414
|
const cdCommand = process.platform === "win32" ? `cd /d ${quotedRoot}` : `cd ${quotedRoot}`;
|
|
29217
29415
|
return `${cdCommand} && git fetch origin main --tags && git merge --ff-only origin/main`;
|
|
29218
29416
|
}
|
|
@@ -29224,14 +29422,14 @@ function buildSidecarProjectConfigCommand(versionDir, nodeBin) {
|
|
|
29224
29422
|
"fs.mkdirSync(dir,{recursive:true});",
|
|
29225
29423
|
`fs.writeFileSync(path.join(dir,'package.json'),${JSON.stringify(NPM_SDK_SIDECAR_PACKAGE_JSON)});`
|
|
29226
29424
|
].join("");
|
|
29227
|
-
return `${
|
|
29425
|
+
return `${shellQuote5(nodeBin)} -e ${shellQuote5(script)} ${shellQuote5(versionDir)}`;
|
|
29228
29426
|
}
|
|
29229
29427
|
function sidecarStateDir(input2) {
|
|
29230
29428
|
const scope = input2.env.DEEPLINE_CONFIG_SCOPE?.trim();
|
|
29231
29429
|
if (!scope || scope.includes("/") || scope.includes("\\")) {
|
|
29232
29430
|
return null;
|
|
29233
29431
|
}
|
|
29234
|
-
return
|
|
29432
|
+
return join15(input2.homeDir, ".local", "deepline", scope, "sdk-cli");
|
|
29235
29433
|
}
|
|
29236
29434
|
function sidecarRegistryUrl(hostUrl) {
|
|
29237
29435
|
let url;
|
|
@@ -29258,7 +29456,7 @@ function publicNpmFallbackRegistryUrl(hostUrl) {
|
|
|
29258
29456
|
}
|
|
29259
29457
|
function readOptionalText(path) {
|
|
29260
29458
|
try {
|
|
29261
|
-
return
|
|
29459
|
+
return readFileSync12(path, "utf8").trim();
|
|
29262
29460
|
} catch {
|
|
29263
29461
|
return "";
|
|
29264
29462
|
}
|
|
@@ -29270,15 +29468,15 @@ function resolvePythonSidecarUpdatePlan(options) {
|
|
|
29270
29468
|
resolve13(stateDir),
|
|
29271
29469
|
resolve13(options.entrypoint)
|
|
29272
29470
|
);
|
|
29273
|
-
if (!relativeEntrypoint || relativeEntrypoint.startsWith("..") ||
|
|
29471
|
+
if (!relativeEntrypoint || relativeEntrypoint.startsWith("..") || isAbsolute3(relativeEntrypoint)) {
|
|
29274
29472
|
return null;
|
|
29275
29473
|
}
|
|
29276
|
-
const installMethod = readOptionalText(
|
|
29474
|
+
const installMethod = readOptionalText(join15(stateDir, ".install-method"));
|
|
29277
29475
|
if (installMethod !== "python-sidecar") return null;
|
|
29278
29476
|
const scope = options.env.DEEPLINE_CONFIG_SCOPE?.trim() || "";
|
|
29279
29477
|
const hostUrl = options.env.DEEPLINE_HOST_URL?.trim() || "";
|
|
29280
|
-
const nodeBin = readOptionalText(
|
|
29281
|
-
const sidecarPath = readOptionalText(
|
|
29478
|
+
const nodeBin = readOptionalText(join15(stateDir, ".node-bin")) || process.execPath;
|
|
29479
|
+
const sidecarPath = readOptionalText(join15(stateDir, ".command-path")) || join15(
|
|
29282
29480
|
stateDir,
|
|
29283
29481
|
"bin",
|
|
29284
29482
|
process.platform === "win32" ? "deepline-sdk.cmd" : "deepline-sdk"
|
|
@@ -29286,8 +29484,8 @@ function resolvePythonSidecarUpdatePlan(options) {
|
|
|
29286
29484
|
const packageSpec = options.packageSpec || "deepline@latest";
|
|
29287
29485
|
const npmCommand = "npm";
|
|
29288
29486
|
const registryUrl = sidecarRegistryUrl(hostUrl);
|
|
29289
|
-
const versionDir =
|
|
29290
|
-
const manualCommand = `${buildSidecarProjectConfigCommand(versionDir, nodeBin)} && ${npmCommand} install --prefix ${
|
|
29487
|
+
const versionDir = join15(stateDir, "versions", "<version>");
|
|
29488
|
+
const manualCommand = `${buildSidecarProjectConfigCommand(versionDir, nodeBin)} && ${npmCommand} install --prefix ${shellQuote5(versionDir)} --registry ${shellQuote5(registryUrl)} ${NPM_SDK_INSTALL_COMMON_FLAGS.map(shellQuote5).join(" ")} ${shellQuote5(packageSpec)}`;
|
|
29291
29489
|
return {
|
|
29292
29490
|
kind: "python-sidecar",
|
|
29293
29491
|
stateDir,
|
|
@@ -29304,7 +29502,7 @@ function resolvePythonSidecarUpdatePlan(options) {
|
|
|
29304
29502
|
function findRepoBackedSdkRoot(startPath) {
|
|
29305
29503
|
let current = resolve13(startPath);
|
|
29306
29504
|
while (true) {
|
|
29307
|
-
if (existsSync12(
|
|
29505
|
+
if (existsSync12(join15(current, "sdk", "package.json")) && existsSync12(join15(current, "sdk", "bin", "deepline-dev.ts"))) {
|
|
29308
29506
|
return current;
|
|
29309
29507
|
}
|
|
29310
29508
|
const parent = dirname13(current);
|
|
@@ -29335,7 +29533,7 @@ function inferNpmGlobalPrefixFromEntrypoint(entrypoint) {
|
|
|
29335
29533
|
}
|
|
29336
29534
|
function resolveUpdatePlan(options = {}) {
|
|
29337
29535
|
const env = options.env ?? process.env;
|
|
29338
|
-
const homeDir2 = options.homeDir ??
|
|
29536
|
+
const homeDir2 = options.homeDir ?? homedir12();
|
|
29339
29537
|
const entrypoint = options.entrypoint ?? (process.argv[1] ? resolve13(process.argv[1]) : "");
|
|
29340
29538
|
const sourceRoot = entrypoint ? findRepoBackedSdkRoot(dirname13(entrypoint)) : null;
|
|
29341
29539
|
if (sourceRoot) {
|
|
@@ -29371,17 +29569,17 @@ function resolveUpdatePlan(options = {}) {
|
|
|
29371
29569
|
fallbackRegistryUrl: publicNpmFallbackRegistryUrl(
|
|
29372
29570
|
env.DEEPLINE_HOST_URL?.trim() || autoDetectBaseUrl()
|
|
29373
29571
|
),
|
|
29374
|
-
manualCommand: `${command} ${args.map(
|
|
29572
|
+
manualCommand: `${command} ${args.map(shellQuote5).join(" ")}`
|
|
29375
29573
|
};
|
|
29376
29574
|
}
|
|
29377
29575
|
var AUTO_UPDATE_FAILURE_FILE = ".auto-update-failure.json";
|
|
29378
29576
|
function autoUpdateFailurePath(plan) {
|
|
29379
29577
|
if (plan.kind === "source") return null;
|
|
29380
29578
|
if (plan.kind === "python-sidecar") {
|
|
29381
|
-
return
|
|
29579
|
+
return join15(plan.stateDir, AUTO_UPDATE_FAILURE_FILE);
|
|
29382
29580
|
}
|
|
29383
|
-
return
|
|
29384
|
-
|
|
29581
|
+
return join15(
|
|
29582
|
+
homedir12(),
|
|
29385
29583
|
".local",
|
|
29386
29584
|
"deepline",
|
|
29387
29585
|
"sdk-cli",
|
|
@@ -29398,7 +29596,7 @@ function readAutoUpdateFailure(plan) {
|
|
|
29398
29596
|
if (!path) return null;
|
|
29399
29597
|
try {
|
|
29400
29598
|
const parsed = JSON.parse(
|
|
29401
|
-
|
|
29599
|
+
readFileSync12(path, "utf8")
|
|
29402
29600
|
);
|
|
29403
29601
|
if ((parsed.kind === "npm-global" || parsed.kind === "python-sidecar") && typeof parsed.packageSpec === "string" && typeof parsed.failedAt === "string" && typeof parsed.exitCode === "number" && typeof parsed.manualCommand === "string") {
|
|
29404
29602
|
return parsed;
|
|
@@ -29429,7 +29627,7 @@ function clearAutoUpdateFailure(plan) {
|
|
|
29429
29627
|
const path = autoUpdateFailurePath(plan);
|
|
29430
29628
|
if (!path) return;
|
|
29431
29629
|
try {
|
|
29432
|
-
|
|
29630
|
+
unlinkSync(path);
|
|
29433
29631
|
} catch {
|
|
29434
29632
|
}
|
|
29435
29633
|
}
|
|
@@ -29465,7 +29663,7 @@ function safeVersionSegment(value) {
|
|
|
29465
29663
|
return /^[0-9A-Za-z._-]+$/.test(normalized) ? normalized : "";
|
|
29466
29664
|
}
|
|
29467
29665
|
function entryPathInVersionDir(versionDir) {
|
|
29468
|
-
return
|
|
29666
|
+
return join15(
|
|
29469
29667
|
versionDir,
|
|
29470
29668
|
"node_modules",
|
|
29471
29669
|
"deepline",
|
|
@@ -29475,14 +29673,14 @@ function entryPathInVersionDir(versionDir) {
|
|
|
29475
29673
|
);
|
|
29476
29674
|
}
|
|
29477
29675
|
function installedPackageVersion(versionDir) {
|
|
29478
|
-
const packageJsonPath =
|
|
29676
|
+
const packageJsonPath = join15(
|
|
29479
29677
|
versionDir,
|
|
29480
29678
|
"node_modules",
|
|
29481
29679
|
"deepline",
|
|
29482
29680
|
"package.json"
|
|
29483
29681
|
);
|
|
29484
29682
|
try {
|
|
29485
|
-
const parsed = JSON.parse(
|
|
29683
|
+
const parsed = JSON.parse(readFileSync12(packageJsonPath, "utf8"));
|
|
29486
29684
|
return typeof parsed.version === "string" ? safeVersionSegment(parsed.version) : "";
|
|
29487
29685
|
} catch {
|
|
29488
29686
|
return "";
|
|
@@ -29576,23 +29774,23 @@ function writeSidecarLauncher(input2) {
|
|
|
29576
29774
|
input2.path,
|
|
29577
29775
|
[
|
|
29578
29776
|
"#!/usr/bin/env sh",
|
|
29579
|
-
`export DEEPLINE_HOST_URL=${
|
|
29580
|
-
`export DEEPLINE_CONFIG_SCOPE=${
|
|
29581
|
-
`exec ${
|
|
29777
|
+
`export DEEPLINE_HOST_URL=${shellQuote5(input2.hostUrl)}`,
|
|
29778
|
+
`export DEEPLINE_CONFIG_SCOPE=${shellQuote5(input2.scope)}`,
|
|
29779
|
+
`exec ${shellQuote5(input2.nodeBin)} ${shellQuote5(input2.entryPath)} "$@"`,
|
|
29582
29780
|
""
|
|
29583
29781
|
].join("\n"),
|
|
29584
29782
|
{ encoding: "utf8", mode: 493 }
|
|
29585
29783
|
);
|
|
29586
29784
|
}
|
|
29587
29785
|
async function runPythonSidecarUpdatePlan(plan) {
|
|
29588
|
-
const versionsDir =
|
|
29589
|
-
const tempDir =
|
|
29786
|
+
const versionsDir = join15(plan.stateDir, "versions");
|
|
29787
|
+
const tempDir = join15(
|
|
29590
29788
|
versionsDir,
|
|
29591
29789
|
`.tmp-sdk-update-${process.pid}-${Date.now()}`
|
|
29592
29790
|
);
|
|
29593
29791
|
rmSync4(tempDir, { recursive: true, force: true });
|
|
29594
29792
|
mkdirSync10(tempDir, { recursive: true });
|
|
29595
|
-
writeFileSync15(
|
|
29793
|
+
writeFileSync15(join15(tempDir, "package.json"), NPM_SDK_SIDECAR_PACKAGE_JSON);
|
|
29596
29794
|
const env = {
|
|
29597
29795
|
...process.env,
|
|
29598
29796
|
PATH: `${dirname13(plan.nodeBin)}${process.platform === "win32" ? ";" : ":"}${process.env.PATH ?? ""}`
|
|
@@ -29623,7 +29821,7 @@ async function runPythonSidecarUpdatePlan(plan) {
|
|
|
29623
29821
|
rmSync4(tempDir, { recursive: true, force: true });
|
|
29624
29822
|
return 1;
|
|
29625
29823
|
}
|
|
29626
|
-
const finalDir =
|
|
29824
|
+
const finalDir = join15(versionsDir, installedVersion);
|
|
29627
29825
|
const finalEntryPath = entryPathInVersionDir(finalDir);
|
|
29628
29826
|
if (existsSync12(finalEntryPath)) {
|
|
29629
29827
|
rmSync4(tempDir, { recursive: true, force: true });
|
|
@@ -29655,27 +29853,27 @@ async function runPythonSidecarUpdatePlan(plan) {
|
|
|
29655
29853
|
entryPath: finalEntryPath
|
|
29656
29854
|
});
|
|
29657
29855
|
writeFileSync15(
|
|
29658
|
-
|
|
29856
|
+
join15(plan.stateDir, ".version"),
|
|
29659
29857
|
`${installedVersion}
|
|
29660
29858
|
`,
|
|
29661
29859
|
"utf8"
|
|
29662
29860
|
);
|
|
29663
29861
|
writeFileSync15(
|
|
29664
|
-
|
|
29862
|
+
join15(plan.stateDir, ".install-method"),
|
|
29665
29863
|
"python-sidecar\n",
|
|
29666
29864
|
"utf8"
|
|
29667
29865
|
);
|
|
29668
29866
|
writeFileSync15(
|
|
29669
|
-
|
|
29867
|
+
join15(plan.stateDir, ".command-path"),
|
|
29670
29868
|
`${plan.sidecarPath}
|
|
29671
29869
|
`,
|
|
29672
29870
|
"utf8"
|
|
29673
29871
|
);
|
|
29674
|
-
writeFileSync15(
|
|
29675
|
-
writeFileSync15(
|
|
29872
|
+
writeFileSync15(join15(plan.stateDir, ".runner"), "node\n", "utf8");
|
|
29873
|
+
writeFileSync15(join15(plan.stateDir, ".node-bin"), `${plan.nodeBin}
|
|
29676
29874
|
`, "utf8");
|
|
29677
29875
|
writeFileSync15(
|
|
29678
|
-
|
|
29876
|
+
join15(plan.stateDir, ".entry-path"),
|
|
29679
29877
|
`${finalEntryPath}
|
|
29680
29878
|
`,
|
|
29681
29879
|
"utf8"
|
|
@@ -29708,7 +29906,20 @@ async function runUpdateCommand(options, dependencies = {}) {
|
|
|
29708
29906
|
const detectBaseUrl = dependencies.detectBaseUrl ?? autoDetectBaseUrl;
|
|
29709
29907
|
const resolvePlan = dependencies.resolvePlan ?? resolveUpdatePlan;
|
|
29710
29908
|
const runPlan = dependencies.runPlan ?? runUpdatePlan;
|
|
29711
|
-
const syncSkills = dependencies.syncSkillsIfNeeded ??
|
|
29909
|
+
const syncSkills = dependencies.syncSkillsIfNeeded ?? (async () => {
|
|
29910
|
+
const originalWrite = process.stdout.write.bind(process.stdout);
|
|
29911
|
+
process.stdout.write = (() => true);
|
|
29912
|
+
try {
|
|
29913
|
+
const exitCode = await runSkillsCommand({ json: true });
|
|
29914
|
+
if (exitCode !== 0) {
|
|
29915
|
+
throw new Error(
|
|
29916
|
+
`Deepline skills update failed with exit ${exitCode}.`
|
|
29917
|
+
);
|
|
29918
|
+
}
|
|
29919
|
+
} finally {
|
|
29920
|
+
process.stdout.write = originalWrite;
|
|
29921
|
+
}
|
|
29922
|
+
});
|
|
29712
29923
|
const stderr = dependencies.stderr ?? process.stderr;
|
|
29713
29924
|
const plan = resolvePlan();
|
|
29714
29925
|
const render = {
|
|
@@ -29776,210 +29987,1151 @@ Examples:
|
|
|
29776
29987
|
});
|
|
29777
29988
|
}
|
|
29778
29989
|
|
|
29779
|
-
//
|
|
29780
|
-
|
|
29781
|
-
|
|
29782
|
-
|
|
29783
|
-
|
|
29784
|
-
|
|
29785
|
-
|
|
29786
|
-
|
|
29787
|
-
|
|
29788
|
-
|
|
29789
|
-
|
|
29790
|
-
|
|
29791
|
-
|
|
29792
|
-
|
|
29793
|
-
|
|
29794
|
-
|
|
29795
|
-
|
|
29796
|
-
|
|
29797
|
-
|
|
29798
|
-
|
|
29799
|
-
|
|
29800
|
-
|
|
29801
|
-
|
|
29802
|
-
|
|
29803
|
-
|
|
29804
|
-
|
|
29805
|
-
|
|
29806
|
-
family: "sdk",
|
|
29807
|
-
label: "an SDK CLI run inspection command"
|
|
29808
|
-
},
|
|
29809
|
-
sessions: {
|
|
29810
|
-
family: "sdk",
|
|
29811
|
-
label: "an SDK CLI session transcript command"
|
|
29812
|
-
},
|
|
29813
|
-
health: {
|
|
29814
|
-
family: "sdk",
|
|
29815
|
-
label: "an SDK CLI health command"
|
|
29990
|
+
// src/cli/commands/setup.ts
|
|
29991
|
+
import { spawnSync as spawnSync2 } from "child_process";
|
|
29992
|
+
import {
|
|
29993
|
+
existsSync as existsSync13,
|
|
29994
|
+
lstatSync,
|
|
29995
|
+
mkdirSync as mkdirSync11,
|
|
29996
|
+
readFileSync as readFileSync13,
|
|
29997
|
+
realpathSync as realpathSync4,
|
|
29998
|
+
rmSync as rmSync5,
|
|
29999
|
+
writeFileSync as writeFileSync16
|
|
30000
|
+
} from "fs";
|
|
30001
|
+
import { homedir as homedir13 } from "os";
|
|
30002
|
+
import { dirname as dirname14, join as join16, resolve as resolve14 } from "path";
|
|
30003
|
+
function normalizeScope2(value) {
|
|
30004
|
+
if (!value || value === "global") return "global";
|
|
30005
|
+
if (value === "local") return "local";
|
|
30006
|
+
throw new Error("--scope must be one of: global, local");
|
|
30007
|
+
}
|
|
30008
|
+
function resolveScopeRoot(scope) {
|
|
30009
|
+
if (scope === "global") return null;
|
|
30010
|
+
const target = resolveProjectPinTarget();
|
|
30011
|
+
if (!target.ok) {
|
|
30012
|
+
throw new Error(
|
|
30013
|
+
`Cowork project folder is ambiguous. Candidate folders: ${target.candidates.join(
|
|
30014
|
+
", "
|
|
30015
|
+
)}. Set CLAUDE_PROJECT_DIR or cd into the intended project folder.`
|
|
30016
|
+
);
|
|
29816
30017
|
}
|
|
29817
|
-
|
|
29818
|
-
|
|
29819
|
-
// src/cli/command-compatibility.ts
|
|
29820
|
-
var COMMAND_COMPATIBILITY = command_compatibility_default;
|
|
29821
|
-
function cliFamilyLabel(family) {
|
|
29822
|
-
return family === "sdk" ? "SDK CLI" : "legacy Python CLI";
|
|
30018
|
+
return target.dir;
|
|
29823
30019
|
}
|
|
29824
|
-
function
|
|
29825
|
-
|
|
29826
|
-
|
|
30020
|
+
function authScopeForSetup(scope) {
|
|
30021
|
+
return scope === "local" ? "folder" : "global";
|
|
30022
|
+
}
|
|
30023
|
+
function setupStatePath(baseUrl, scope, root) {
|
|
30024
|
+
return scope === "local" && root ? join16(root, ".deepline", "setup", "state.json") : join16(sdkCliStateDirPath(baseUrl), "setup.json");
|
|
30025
|
+
}
|
|
30026
|
+
async function captureStdout2(run) {
|
|
30027
|
+
let stdout = "";
|
|
30028
|
+
const originalWrite = process.stdout.write.bind(process.stdout);
|
|
30029
|
+
process.stdout.write = ((chunk) => {
|
|
30030
|
+
stdout += typeof chunk === "string" ? chunk : String(chunk);
|
|
30031
|
+
return true;
|
|
30032
|
+
});
|
|
30033
|
+
try {
|
|
30034
|
+
return { exitCode: await run(), stdout, error: null };
|
|
30035
|
+
} catch (error) {
|
|
30036
|
+
return { exitCode: 4, stdout, error };
|
|
30037
|
+
} finally {
|
|
30038
|
+
process.stdout.write = originalWrite;
|
|
30039
|
+
}
|
|
30040
|
+
}
|
|
30041
|
+
function parseCapturedJson(stdout) {
|
|
30042
|
+
try {
|
|
30043
|
+
return JSON.parse(stdout.trim());
|
|
30044
|
+
} catch {
|
|
29827
30045
|
return null;
|
|
29828
30046
|
}
|
|
29829
|
-
|
|
29830
|
-
|
|
29831
|
-
|
|
29832
|
-
|
|
29833
|
-
|
|
29834
|
-
|
|
29835
|
-
|
|
29836
|
-
|
|
29837
|
-
|
|
30047
|
+
}
|
|
30048
|
+
function asRecord2(value) {
|
|
30049
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
30050
|
+
}
|
|
30051
|
+
function printCapturedAuthorizationUrl(stdout) {
|
|
30052
|
+
const urls = stdout.match(/https:\/\/[^\s]+/g) ?? [];
|
|
30053
|
+
for (const url of new Set(
|
|
30054
|
+
urls.map((value) => value.replace(/[).,]+$/, ""))
|
|
30055
|
+
)) {
|
|
30056
|
+
process.stderr.write(`Authorize Deepline: ${url}
|
|
30057
|
+
`);
|
|
30058
|
+
}
|
|
30059
|
+
}
|
|
30060
|
+
function safeRead(path) {
|
|
30061
|
+
try {
|
|
30062
|
+
return readFileSync13(path, "utf8");
|
|
30063
|
+
} catch {
|
|
30064
|
+
return "";
|
|
30065
|
+
}
|
|
30066
|
+
}
|
|
30067
|
+
function isNpmManagedDeeplinePath(path) {
|
|
30068
|
+
try {
|
|
30069
|
+
return realpathSync4(path).includes(`${join16("node_modules", "deepline")}`);
|
|
30070
|
+
} catch {
|
|
30071
|
+
return false;
|
|
30072
|
+
}
|
|
30073
|
+
}
|
|
30074
|
+
function removeKnownLegacyPaths(baseUrl) {
|
|
30075
|
+
const home = homedir13();
|
|
30076
|
+
const hostDir = join16(home, ".local", "deepline", baseUrlSlug(baseUrl));
|
|
30077
|
+
const installerCommandPath = safeRead(
|
|
30078
|
+
join16(hostDir, "sdk", ".command-path")
|
|
30079
|
+
).trim();
|
|
30080
|
+
const candidates = [
|
|
30081
|
+
join16(home, ".local", "bin", "deepline-real"),
|
|
30082
|
+
join16(hostDir, "bin", "deepline"),
|
|
30083
|
+
join16(hostDir, "bin", "deepline-real"),
|
|
30084
|
+
join16(hostDir, "cli", ".install-method"),
|
|
30085
|
+
join16(hostDir, "cli", ".version"),
|
|
30086
|
+
join16(hostDir, "sdk", ".install-method"),
|
|
30087
|
+
join16(hostDir, "sdk", ".command-path"),
|
|
30088
|
+
...installerCommandPath ? [
|
|
30089
|
+
installerCommandPath,
|
|
30090
|
+
join16(dirname14(installerCommandPath), "deepline-sdk")
|
|
30091
|
+
] : []
|
|
29838
30092
|
];
|
|
29839
|
-
|
|
29840
|
-
|
|
29841
|
-
|
|
29842
|
-
|
|
29843
|
-
|
|
29844
|
-
" To use the legacy Python CLI instead:",
|
|
29845
|
-
` ${legacyPythonInstallCommand(baseUrl)}`,
|
|
29846
|
-
" `deepline update` updates this SDK CLI, but it will not switch CLI families."
|
|
29847
|
-
);
|
|
29848
|
-
if (compatibility.sdk_alternative) {
|
|
29849
|
-
lines.push(` SDK alternative: ${compatibility.sdk_alternative}`);
|
|
29850
|
-
}
|
|
29851
|
-
} else {
|
|
29852
|
-
lines.push(
|
|
29853
|
-
"",
|
|
29854
|
-
" To use SDK commands, install the SDK CLI and refresh Deepline agent skills:",
|
|
29855
|
-
` ${sdkNpmGlobalInstallCommand()}`,
|
|
29856
|
-
` ${skillsInstallCommand(baseUrl, DEFAULT_SDK_SKILL_NAMES)}`,
|
|
29857
|
-
" `deepline update` updates this Python CLI and its skills, but it will not switch CLI families."
|
|
29858
|
-
);
|
|
29859
|
-
if (compatibility.python_alternative) {
|
|
29860
|
-
lines.push(` Python alternative: ${compatibility.python_alternative}`);
|
|
30093
|
+
const removed = [];
|
|
30094
|
+
for (const path of candidates) {
|
|
30095
|
+
if (!existsSync13(path)) continue;
|
|
30096
|
+
if (path === installerCommandPath && isNpmManagedDeeplinePath(path)) {
|
|
30097
|
+
continue;
|
|
29861
30098
|
}
|
|
30099
|
+
rmSync5(path, { force: true });
|
|
30100
|
+
removed.push(path);
|
|
29862
30101
|
}
|
|
29863
|
-
return
|
|
30102
|
+
return removed;
|
|
29864
30103
|
}
|
|
29865
|
-
function
|
|
29866
|
-
const
|
|
29867
|
-
|
|
29868
|
-
|
|
30104
|
+
function resolvePathCommands(command) {
|
|
30105
|
+
const lookup = spawnSync2(
|
|
30106
|
+
process.platform === "win32" ? "where" : "which",
|
|
30107
|
+
process.platform === "win32" ? [command] : ["-a", command],
|
|
30108
|
+
{ encoding: "utf8", shell: process.platform === "win32" }
|
|
30109
|
+
);
|
|
30110
|
+
return [
|
|
30111
|
+
...new Set(
|
|
30112
|
+
String(lookup.stdout ?? "").split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((path) => resolve14(path))
|
|
30113
|
+
)
|
|
30114
|
+
];
|
|
29869
30115
|
}
|
|
29870
|
-
|
|
29871
|
-
|
|
29872
|
-
|
|
29873
|
-
function
|
|
29874
|
-
const
|
|
29875
|
-
|
|
30116
|
+
function resolvePathCommand(command) {
|
|
30117
|
+
return resolvePathCommands(command)[0] ?? null;
|
|
30118
|
+
}
|
|
30119
|
+
function resolvePersistentGlobalCommand() {
|
|
30120
|
+
const prefix = spawnSync2("npm", ["prefix", "-g"], { encoding: "utf8" });
|
|
30121
|
+
if (prefix.status !== 0) return null;
|
|
30122
|
+
const root = String(prefix.stdout ?? "").trim();
|
|
30123
|
+
if (!root) return null;
|
|
30124
|
+
const candidates = process.platform === "win32" ? [join16(root, "deepline.cmd"), join16(root, "deepline")] : [join16(root, "bin", "deepline")];
|
|
30125
|
+
return candidates.find((candidate) => existsSync13(candidate)) ?? null;
|
|
30126
|
+
}
|
|
30127
|
+
function inspectGlobalCliAvailability(input2) {
|
|
30128
|
+
const persistentPath = input2 && "persistentGlobalCli" in input2 ? input2.persistentGlobalCli ?? null : resolvePersistentGlobalCommand();
|
|
30129
|
+
const pathClis = input2?.pathClis ?? resolvePathCommands("deepline");
|
|
30130
|
+
const path = persistentPath ? pathClis.find(
|
|
30131
|
+
(candidate) => pathsResolveToSameFile(candidate, persistentPath)
|
|
30132
|
+
) ?? null : null;
|
|
30133
|
+
return { ok: Boolean(path), persistentPath, path };
|
|
30134
|
+
}
|
|
30135
|
+
function pathsResolveToSameFile(left, right) {
|
|
30136
|
+
try {
|
|
30137
|
+
return realpathSync4(left) === realpathSync4(right);
|
|
30138
|
+
} catch {
|
|
30139
|
+
return resolve14(left) === resolve14(right);
|
|
30140
|
+
}
|
|
29876
30141
|
}
|
|
29877
|
-
function
|
|
29878
|
-
|
|
30142
|
+
function isKnownDeeplineCommand(path) {
|
|
30143
|
+
const entrypoint = process.argv[1] ? resolve14(process.argv[1]) : "";
|
|
30144
|
+
let resolvedPath = path;
|
|
30145
|
+
try {
|
|
30146
|
+
resolvedPath = realpathSync4(path);
|
|
30147
|
+
} catch {
|
|
30148
|
+
}
|
|
30149
|
+
if (entrypoint && resolvedPath === entrypoint) return true;
|
|
30150
|
+
if (resolvedPath.includes(`${join16("node_modules", "deepline")}`)) return true;
|
|
30151
|
+
const content = safeRead(path);
|
|
30152
|
+
return content.includes("node_modules/deepline") || content.includes("node_modules\\deepline") || content.includes("DEEPLINE_CONFIG_SCOPE") || content.includes("deepline-real");
|
|
29879
30153
|
}
|
|
29880
|
-
function
|
|
29881
|
-
|
|
30154
|
+
function inspectPathConflict() {
|
|
30155
|
+
const commandPath = resolvePathCommand("deepline");
|
|
30156
|
+
if (!commandPath || isKnownDeeplineCommand(commandPath)) return null;
|
|
30157
|
+
try {
|
|
30158
|
+
if (lstatSync(commandPath).isSymbolicLink()) {
|
|
30159
|
+
const target = realpathSync4(commandPath);
|
|
30160
|
+
if (target.includes(`${join16("node_modules", "deepline")}`)) return null;
|
|
30161
|
+
}
|
|
30162
|
+
} catch {
|
|
30163
|
+
}
|
|
30164
|
+
return commandPath;
|
|
29882
30165
|
}
|
|
29883
|
-
function
|
|
29884
|
-
const
|
|
29885
|
-
|
|
29886
|
-
|
|
29887
|
-
|
|
30166
|
+
function writeSetupState(input2) {
|
|
30167
|
+
const path = setupStatePath(input2.baseUrl, input2.scope, input2.root);
|
|
30168
|
+
mkdirSync11(dirname14(path), { recursive: true });
|
|
30169
|
+
writeFileSync16(
|
|
30170
|
+
path,
|
|
30171
|
+
`${JSON.stringify(
|
|
30172
|
+
{
|
|
30173
|
+
schemaVersion: 1,
|
|
30174
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
30175
|
+
cliVersion: SDK_VERSION,
|
|
30176
|
+
host: input2.baseUrl,
|
|
30177
|
+
scope: input2.scope,
|
|
30178
|
+
root: input2.root,
|
|
30179
|
+
status: input2.status
|
|
30180
|
+
},
|
|
30181
|
+
null,
|
|
30182
|
+
2
|
|
30183
|
+
)}
|
|
30184
|
+
`,
|
|
30185
|
+
"utf8"
|
|
29888
30186
|
);
|
|
29889
|
-
|
|
29890
|
-
return {
|
|
29891
|
-
major: Number(match[1]),
|
|
29892
|
-
minor: Number(match[2]),
|
|
29893
|
-
patch: Number(match[3]),
|
|
29894
|
-
prerelease: match[4] ?? ""
|
|
29895
|
-
};
|
|
30187
|
+
return path;
|
|
29896
30188
|
}
|
|
29897
|
-
function
|
|
29898
|
-
const
|
|
29899
|
-
|
|
29900
|
-
if (!a || !b) {
|
|
29901
|
-
return left.localeCompare(right);
|
|
29902
|
-
}
|
|
29903
|
-
for (const key of ["major", "minor", "patch"]) {
|
|
29904
|
-
if (a[key] !== b[key]) return a[key] > b[key] ? 1 : -1;
|
|
29905
|
-
}
|
|
29906
|
-
if (a.prerelease === b.prerelease) return 0;
|
|
29907
|
-
if (!a.prerelease) return 1;
|
|
29908
|
-
if (!b.prerelease) return -1;
|
|
29909
|
-
return a.prerelease.localeCompare(b.prerelease);
|
|
30189
|
+
function rollbackCommand(scope, root) {
|
|
30190
|
+
const prefix = scope === "local" && root ? ` --prefix ${JSON.stringify(join16(root, ".deepline", "runtime"))}` : "";
|
|
30191
|
+
return `npm install -g${prefix} --no-audit --no-fund --include=optional --allow-scripts=esbuild deepline@${SDK_VERSION}`;
|
|
29910
30192
|
}
|
|
29911
|
-
function
|
|
29912
|
-
|
|
29913
|
-
const current = response?.current?.trim() || SDK_VERSION;
|
|
29914
|
-
if (!target) return false;
|
|
29915
|
-
return compareSemver(target, current) < 0;
|
|
30193
|
+
function setupQuickstartCommand(baseUrl) {
|
|
30194
|
+
return baseUrl === "https://code.deepline.com" ? "deepline quickstart" : `DEEPLINE_HOST_URL=${JSON.stringify(baseUrl)} deepline quickstart`;
|
|
29916
30195
|
}
|
|
29917
|
-
function
|
|
29918
|
-
|
|
29919
|
-
|
|
29920
|
-
const args = plan.kind === "python-sidecar" ? process.argv.slice(2) : process.argv.slice(1);
|
|
29921
|
-
const child = spawn5(command, args, {
|
|
29922
|
-
stdio: "inherit",
|
|
29923
|
-
shell: process.platform === "win32",
|
|
29924
|
-
env: {
|
|
29925
|
-
...process.env,
|
|
29926
|
-
DEEPLINE_NO_AUTO_UPDATE: "1"
|
|
29927
|
-
}
|
|
29928
|
-
});
|
|
29929
|
-
child.on("error", (error) => {
|
|
29930
|
-
process.stderr.write(
|
|
29931
|
-
`Deepline SDK/CLI updated, but relaunch failed: ${error.message}
|
|
29932
|
-
`
|
|
29933
|
-
);
|
|
29934
|
-
resolve14(1);
|
|
29935
|
-
});
|
|
29936
|
-
child.on("close", (code) => resolve14(code ?? 1));
|
|
29937
|
-
});
|
|
30196
|
+
function setupResumeCommand(baseUrl, scope) {
|
|
30197
|
+
const hostPrefix = baseUrl === "https://code.deepline.com" ? "" : `DEEPLINE_HOST_URL=${JSON.stringify(baseUrl)} `;
|
|
30198
|
+
return `${hostPrefix}deepline setup --scope ${scope} --json`;
|
|
29938
30199
|
}
|
|
29939
|
-
async function
|
|
29940
|
-
|
|
29941
|
-
|
|
29942
|
-
|
|
29943
|
-
|
|
29944
|
-
|
|
29945
|
-
|
|
29946
|
-
const current = response.current?.trim() || SDK_VERSION;
|
|
29947
|
-
process.stderr.write(
|
|
29948
|
-
`Deepline SDK/CLI auto-update refused: server advertised older ${target} than current ${current}. Continuing without mutating the CLI.
|
|
29949
|
-
`
|
|
30200
|
+
async function readAuthStatus(authScope) {
|
|
30201
|
+
try {
|
|
30202
|
+
const captured = await captureStdout2(
|
|
30203
|
+
() => handleStatus([
|
|
30204
|
+
"--json",
|
|
30205
|
+
...authScope ? ["--auth-scope", authScope] : []
|
|
30206
|
+
])
|
|
29950
30207
|
);
|
|
29951
|
-
return
|
|
29952
|
-
|
|
29953
|
-
|
|
29954
|
-
|
|
29955
|
-
|
|
29956
|
-
|
|
30208
|
+
return {
|
|
30209
|
+
exitCode: captured.exitCode,
|
|
30210
|
+
payload: parseCapturedJson(captured.stdout),
|
|
30211
|
+
error: captured.error
|
|
30212
|
+
};
|
|
30213
|
+
} catch (error) {
|
|
30214
|
+
return { exitCode: 4, payload: null, error };
|
|
29957
30215
|
}
|
|
29958
|
-
|
|
29959
|
-
|
|
29960
|
-
|
|
29961
|
-
|
|
30216
|
+
}
|
|
30217
|
+
function reportSetupAuthStatusFailure(input2) {
|
|
30218
|
+
if (!input2.auth.error) return null;
|
|
30219
|
+
printCommandEnvelope(
|
|
30220
|
+
{
|
|
30221
|
+
ok: false,
|
|
30222
|
+
status: "failed",
|
|
30223
|
+
code: "AUTH_STATUS_FAILED",
|
|
30224
|
+
exitCode: 4,
|
|
30225
|
+
scope: input2.scope,
|
|
30226
|
+
message: "Deepline could not verify authorization with the configured host.",
|
|
30227
|
+
next: `Check network access, then rerun: deepline setup --scope ${input2.scope} --json`,
|
|
30228
|
+
authScope: input2.authScope
|
|
30229
|
+
},
|
|
30230
|
+
{ json: input2.json }
|
|
29962
30231
|
);
|
|
29963
|
-
|
|
29964
|
-
|
|
29965
|
-
|
|
29966
|
-
|
|
29967
|
-
|
|
29968
|
-
|
|
29969
|
-
|
|
29970
|
-
|
|
29971
|
-
|
|
29972
|
-
|
|
29973
|
-
|
|
29974
|
-
|
|
29975
|
-
|
|
30232
|
+
return 4;
|
|
30233
|
+
}
|
|
30234
|
+
async function runDoctorCommand(options) {
|
|
30235
|
+
let scope;
|
|
30236
|
+
let root;
|
|
30237
|
+
try {
|
|
30238
|
+
scope = normalizeScope2(options.scope);
|
|
30239
|
+
root = resolveScopeRoot(scope);
|
|
30240
|
+
} catch (error) {
|
|
30241
|
+
printCommandEnvelope(
|
|
30242
|
+
{
|
|
30243
|
+
ok: false,
|
|
30244
|
+
status: "failed",
|
|
30245
|
+
code: "INVALID_SETUP_SCOPE",
|
|
30246
|
+
exitCode: 2,
|
|
30247
|
+
message: error instanceof Error ? error.message : String(error)
|
|
30248
|
+
},
|
|
30249
|
+
{ json: options.json }
|
|
29976
30250
|
);
|
|
29977
|
-
return
|
|
30251
|
+
return 2;
|
|
29978
30252
|
}
|
|
29979
|
-
|
|
29980
|
-
const
|
|
29981
|
-
|
|
29982
|
-
|
|
30253
|
+
const baseUrl = autoDetectBaseUrl().replace(/\/$/, "");
|
|
30254
|
+
const skillsStatePath = skillsStatePathForScope(baseUrl, scope, root);
|
|
30255
|
+
const skillsState = parseCapturedJson(safeRead(skillsStatePath));
|
|
30256
|
+
const authScope = authScopeForSetup(scope);
|
|
30257
|
+
const apiKey = scope === "local" ? resolveProjectApiKeyForBaseUrl(baseUrl) : resolveGlobalApiKeyForBaseUrl(baseUrl);
|
|
30258
|
+
const projectAuth = scope === "local" && apiKey ? getResolvedProjectAuthSource(baseUrl, apiKey) : null;
|
|
30259
|
+
const authStatus = await readAuthStatus(authScope);
|
|
30260
|
+
const connected = authStatus.payload?.connected === true;
|
|
30261
|
+
const authScopeOk = scope === "local" ? Boolean(projectAuth) : Boolean(apiKey && !projectAuth);
|
|
30262
|
+
const skillsOk = skillsState?.scope === scope && Array.isArray(skillsState.agents) && skillsState.agents.length > 0;
|
|
30263
|
+
const runningCliPath = process.argv[1] ? resolve14(process.argv[1]) : null;
|
|
30264
|
+
const globalCli = scope === "global" ? inspectGlobalCliAvailability() : null;
|
|
30265
|
+
const pathGlobalCli = globalCli?.path ?? null;
|
|
30266
|
+
const cliPath = scope === "global" ? pathGlobalCli : runningCliPath;
|
|
30267
|
+
const cliScopeOk = scope === "global" ? Boolean(pathGlobalCli) : Boolean(
|
|
30268
|
+
root && runningCliPath?.includes(join16(root, ".deepline", "runtime"))
|
|
30269
|
+
);
|
|
30270
|
+
const checks = {
|
|
30271
|
+
cli: {
|
|
30272
|
+
ok: Boolean(cliPath) && cliScopeOk,
|
|
30273
|
+
version: SDK_VERSION,
|
|
30274
|
+
path: cliPath,
|
|
30275
|
+
scope
|
|
30276
|
+
},
|
|
30277
|
+
skills: {
|
|
30278
|
+
ok: skillsOk,
|
|
30279
|
+
statePath: skillsStatePath,
|
|
30280
|
+
version: skillsState?.skillsVersion ?? null,
|
|
30281
|
+
agents: skillsState?.agents ?? []
|
|
30282
|
+
},
|
|
30283
|
+
auth: {
|
|
30284
|
+
ok: connected && authScopeOk,
|
|
30285
|
+
scope: projectAuth ? "local" : apiKey ? "global" : null,
|
|
30286
|
+
status: authStatus.payload?.status ?? "not_connected"
|
|
30287
|
+
},
|
|
30288
|
+
api: {
|
|
30289
|
+
ok: connected && authStatus.exitCode === 0,
|
|
30290
|
+
host: baseUrl,
|
|
30291
|
+
workspace: authStatus.payload?.workspace ?? null,
|
|
30292
|
+
providerSpend: false
|
|
30293
|
+
}
|
|
30294
|
+
};
|
|
30295
|
+
const ok = Object.values(checks).every((check) => check.ok);
|
|
30296
|
+
const quickstart = setupQuickstartCommand(baseUrl);
|
|
30297
|
+
printCommandEnvelope(
|
|
30298
|
+
{
|
|
30299
|
+
ok,
|
|
30300
|
+
status: ok ? "complete" : "failed",
|
|
30301
|
+
code: ok ? "DOCTOR_OK" : "DOCTOR_FAILED",
|
|
30302
|
+
exitCode: ok ? 0 : 7,
|
|
30303
|
+
checks,
|
|
30304
|
+
next: ok ? quickstart : "Review failed checks, then rerun: deepline doctor --json",
|
|
30305
|
+
render: {
|
|
30306
|
+
sections: [
|
|
30307
|
+
{
|
|
30308
|
+
title: "doctor",
|
|
30309
|
+
lines: Object.entries(checks).map(
|
|
30310
|
+
([name, check]) => `${check.ok ? "pass" : "fail"} ${name}`
|
|
30311
|
+
)
|
|
30312
|
+
}
|
|
30313
|
+
]
|
|
30314
|
+
}
|
|
30315
|
+
},
|
|
30316
|
+
{ json: options.json }
|
|
30317
|
+
);
|
|
30318
|
+
return ok ? 0 : 7;
|
|
30319
|
+
}
|
|
30320
|
+
function pendingResult(input2) {
|
|
30321
|
+
const statePath = writeSetupState({
|
|
30322
|
+
baseUrl: input2.baseUrl,
|
|
30323
|
+
scope: input2.scope,
|
|
30324
|
+
root: input2.root,
|
|
30325
|
+
status: "authorization_pending"
|
|
30326
|
+
});
|
|
30327
|
+
if (input2.authorizationUrl) {
|
|
30328
|
+
process.stderr.write(`Authorize Deepline: ${input2.authorizationUrl}
|
|
30329
|
+
`);
|
|
30330
|
+
}
|
|
30331
|
+
printCommandEnvelope(
|
|
30332
|
+
{
|
|
30333
|
+
ok: true,
|
|
30334
|
+
status: "authorization_pending",
|
|
30335
|
+
complete: false,
|
|
30336
|
+
scope: input2.scope,
|
|
30337
|
+
authorizationUrl: input2.authorizationUrl || null,
|
|
30338
|
+
statePath,
|
|
30339
|
+
next: `Approve the link, then run: ${setupResumeCommand(input2.baseUrl, input2.scope)}`,
|
|
30340
|
+
render: {
|
|
30341
|
+
sections: [
|
|
30342
|
+
{
|
|
30343
|
+
title: "setup",
|
|
30344
|
+
lines: [
|
|
30345
|
+
"Authorization is waiting for browser approval.",
|
|
30346
|
+
...input2.authorizationUrl ? [input2.authorizationUrl] : []
|
|
30347
|
+
]
|
|
30348
|
+
}
|
|
30349
|
+
]
|
|
30350
|
+
}
|
|
30351
|
+
},
|
|
30352
|
+
{ json: input2.json }
|
|
30353
|
+
);
|
|
30354
|
+
return 0;
|
|
30355
|
+
}
|
|
30356
|
+
async function runSetupCommand(options) {
|
|
30357
|
+
let scope;
|
|
30358
|
+
let root;
|
|
30359
|
+
try {
|
|
30360
|
+
scope = normalizeScope2(options.scope);
|
|
30361
|
+
root = resolveScopeRoot(scope);
|
|
30362
|
+
} catch (error) {
|
|
30363
|
+
printCommandEnvelope(
|
|
30364
|
+
{
|
|
30365
|
+
ok: false,
|
|
30366
|
+
status: "failed",
|
|
30367
|
+
code: "INVALID_SETUP_SCOPE",
|
|
30368
|
+
exitCode: 2,
|
|
30369
|
+
message: error instanceof Error ? error.message : String(error)
|
|
30370
|
+
},
|
|
30371
|
+
{ json: options.json }
|
|
30372
|
+
);
|
|
30373
|
+
return 2;
|
|
30374
|
+
}
|
|
30375
|
+
const baseUrl = autoDetectBaseUrl().replace(/\/$/, "");
|
|
30376
|
+
if (scope === "global") {
|
|
30377
|
+
const globalCli = inspectGlobalCliAvailability();
|
|
30378
|
+
if (!globalCli.ok) {
|
|
30379
|
+
const installedButUnreachable = Boolean(globalCli.persistentPath);
|
|
30380
|
+
printCommandEnvelope(
|
|
30381
|
+
{
|
|
30382
|
+
ok: false,
|
|
30383
|
+
status: "failed",
|
|
30384
|
+
code: installedButUnreachable ? "GLOBAL_CLI_NOT_ON_PATH" : "GLOBAL_CLI_NOT_INSTALLED",
|
|
30385
|
+
exitCode: 7,
|
|
30386
|
+
scope,
|
|
30387
|
+
persistentPath: globalCli.persistentPath,
|
|
30388
|
+
message: installedButUnreachable ? `The global Deepline executable is not reachable on PATH: ${globalCli.persistentPath}` : "No persistent global Deepline executable was found.",
|
|
30389
|
+
next: "Use the automatic project-local fallback in https://code.deepline.com/SKILL.md"
|
|
30390
|
+
},
|
|
30391
|
+
{ json: options.json }
|
|
30392
|
+
);
|
|
30393
|
+
return 7;
|
|
30394
|
+
}
|
|
30395
|
+
}
|
|
30396
|
+
const conflict = inspectPathConflict();
|
|
30397
|
+
if (conflict) {
|
|
30398
|
+
printCommandEnvelope(
|
|
30399
|
+
{
|
|
30400
|
+
ok: false,
|
|
30401
|
+
status: "failed",
|
|
30402
|
+
code: "PATH_CONFLICT",
|
|
30403
|
+
exitCode: 7,
|
|
30404
|
+
path: conflict,
|
|
30405
|
+
message: `An unknown executable named deepline is first on PATH: ${conflict}`,
|
|
30406
|
+
next: "Move or rename that executable, then rerun: deepline setup --json"
|
|
30407
|
+
},
|
|
30408
|
+
{ json: options.json }
|
|
30409
|
+
);
|
|
30410
|
+
return 7;
|
|
30411
|
+
}
|
|
30412
|
+
const removedLegacyPaths = removeKnownLegacyPaths(baseUrl);
|
|
30413
|
+
if (removedLegacyPaths.length > 0) {
|
|
30414
|
+
process.stderr.write(
|
|
30415
|
+
`Removed ${removedLegacyPaths.length} known legacy Deepline path(s).
|
|
30416
|
+
`
|
|
30417
|
+
);
|
|
30418
|
+
}
|
|
30419
|
+
process.stderr.write(`Installing Deepline skills (${scope})...
|
|
30420
|
+
`);
|
|
30421
|
+
const skills = await captureStdout2(
|
|
30422
|
+
() => runSkillsCommand({ scope, json: true })
|
|
30423
|
+
);
|
|
30424
|
+
const skillsPayload = parseCapturedJson(skills.stdout);
|
|
30425
|
+
if (skills.exitCode !== 0) {
|
|
30426
|
+
printCommandEnvelope(
|
|
30427
|
+
{
|
|
30428
|
+
ok: false,
|
|
30429
|
+
status: "failed",
|
|
30430
|
+
code: "SKILLS_INSTALL_FAILED",
|
|
30431
|
+
exitCode: skills.exitCode,
|
|
30432
|
+
scope,
|
|
30433
|
+
detail: skillsPayload,
|
|
30434
|
+
next: `deepline skills --scope ${scope} --json`
|
|
30435
|
+
},
|
|
30436
|
+
{ json: options.json }
|
|
30437
|
+
);
|
|
30438
|
+
return skills.exitCode;
|
|
30439
|
+
}
|
|
30440
|
+
writeSetupState({ baseUrl, scope, root, status: "skills_installed" });
|
|
30441
|
+
const authScope = authScopeForSetup(scope);
|
|
30442
|
+
let auth = await readAuthStatus(authScope);
|
|
30443
|
+
const initialAuthFailure = reportSetupAuthStatusFailure({
|
|
30444
|
+
auth,
|
|
30445
|
+
authScope,
|
|
30446
|
+
scope,
|
|
30447
|
+
json: options.json
|
|
30448
|
+
});
|
|
30449
|
+
if (initialAuthFailure !== null) return initialAuthFailure;
|
|
30450
|
+
if (auth.payload?.connected !== true) {
|
|
30451
|
+
const pending = readPendingAuthClaim(baseUrl, authScope);
|
|
30452
|
+
if (pending) {
|
|
30453
|
+
process.stderr.write("Checking pending Deepline authorization...\n");
|
|
30454
|
+
const waited = await captureStdout2(
|
|
30455
|
+
() => handleWait(["--timeout", "1", "--auth-scope", authScope])
|
|
30456
|
+
);
|
|
30457
|
+
printCapturedAuthorizationUrl(waited.stdout);
|
|
30458
|
+
auth = await readAuthStatus(authScope);
|
|
30459
|
+
const resumedAuthFailure = reportSetupAuthStatusFailure({
|
|
30460
|
+
auth,
|
|
30461
|
+
authScope,
|
|
30462
|
+
scope,
|
|
30463
|
+
json: options.json
|
|
30464
|
+
});
|
|
30465
|
+
if (resumedAuthFailure !== null) return resumedAuthFailure;
|
|
30466
|
+
if (auth.payload?.connected !== true) {
|
|
30467
|
+
const stillPending = readPendingAuthClaim(baseUrl, authScope);
|
|
30468
|
+
if (stillPending) {
|
|
30469
|
+
return pendingResult({
|
|
30470
|
+
baseUrl,
|
|
30471
|
+
scope,
|
|
30472
|
+
root,
|
|
30473
|
+
authorizationUrl: stillPending.claimUrl,
|
|
30474
|
+
json: options.json
|
|
30475
|
+
});
|
|
30476
|
+
}
|
|
30477
|
+
}
|
|
30478
|
+
}
|
|
30479
|
+
}
|
|
30480
|
+
if (auth.payload?.connected !== true) {
|
|
30481
|
+
process.stderr.write("Starting Deepline browser authorization...\n");
|
|
30482
|
+
const agentRuntime = detectAgentRuntime();
|
|
30483
|
+
const agentLed = agentRuntime !== "unknown";
|
|
30484
|
+
const waitMode = options.json || agentLed || !process.stdin.isTTY ? "no" : "auto";
|
|
30485
|
+
const registered = await captureStdout2(
|
|
30486
|
+
() => handleRegister(["--wait", waitMode, "--auth-scope", authScope])
|
|
30487
|
+
);
|
|
30488
|
+
printCapturedAuthorizationUrl(registered.stdout);
|
|
30489
|
+
if (registered.exitCode !== 0) {
|
|
30490
|
+
printCommandEnvelope(
|
|
30491
|
+
{
|
|
30492
|
+
ok: false,
|
|
30493
|
+
status: "failed",
|
|
30494
|
+
code: "AUTH_REGISTER_FAILED",
|
|
30495
|
+
exitCode: registered.exitCode,
|
|
30496
|
+
scope,
|
|
30497
|
+
next: `deepline auth register --auth-scope ${authScope}`
|
|
30498
|
+
},
|
|
30499
|
+
{ json: options.json }
|
|
30500
|
+
);
|
|
30501
|
+
return registered.exitCode;
|
|
30502
|
+
}
|
|
30503
|
+
auth = await readAuthStatus(authScope);
|
|
30504
|
+
const registeredAuthFailure = reportSetupAuthStatusFailure({
|
|
30505
|
+
auth,
|
|
30506
|
+
authScope,
|
|
30507
|
+
scope,
|
|
30508
|
+
json: options.json
|
|
30509
|
+
});
|
|
30510
|
+
if (registeredAuthFailure !== null) return registeredAuthFailure;
|
|
30511
|
+
if (auth.payload?.connected !== true) {
|
|
30512
|
+
const pending = readPendingAuthClaim(baseUrl, authScope);
|
|
30513
|
+
return pendingResult({
|
|
30514
|
+
baseUrl,
|
|
30515
|
+
scope,
|
|
30516
|
+
root,
|
|
30517
|
+
authorizationUrl: pending?.claimUrl ?? "",
|
|
30518
|
+
json: options.json
|
|
30519
|
+
});
|
|
30520
|
+
}
|
|
30521
|
+
}
|
|
30522
|
+
process.stderr.write("Verifying Deepline setup...\n");
|
|
30523
|
+
const doctor = await captureStdout2(
|
|
30524
|
+
() => runDoctorCommand({ scope, json: true })
|
|
30525
|
+
);
|
|
30526
|
+
const doctorPayload = parseCapturedJson(doctor.stdout);
|
|
30527
|
+
if (doctor.exitCode !== 0) {
|
|
30528
|
+
printCommandEnvelope(
|
|
30529
|
+
{
|
|
30530
|
+
ok: false,
|
|
30531
|
+
status: "failed",
|
|
30532
|
+
code: "DOCTOR_FAILED",
|
|
30533
|
+
exitCode: doctor.exitCode,
|
|
30534
|
+
scope,
|
|
30535
|
+
doctor: doctorPayload,
|
|
30536
|
+
next: "Review the doctor result and choose a repair, then rerun: deepline setup --json"
|
|
30537
|
+
},
|
|
30538
|
+
{ json: options.json }
|
|
30539
|
+
);
|
|
30540
|
+
return doctor.exitCode;
|
|
30541
|
+
}
|
|
30542
|
+
const statePath = writeSetupState({
|
|
30543
|
+
baseUrl,
|
|
30544
|
+
scope,
|
|
30545
|
+
root,
|
|
30546
|
+
status: "complete"
|
|
30547
|
+
});
|
|
30548
|
+
const doctorChecks = asRecord2(doctorPayload?.checks);
|
|
30549
|
+
const apiCheck = asRecord2(doctorChecks?.api);
|
|
30550
|
+
const quickstart = setupQuickstartCommand(baseUrl);
|
|
30551
|
+
printCommandEnvelope(
|
|
30552
|
+
{
|
|
30553
|
+
ok: true,
|
|
30554
|
+
status: "complete",
|
|
30555
|
+
complete: true,
|
|
30556
|
+
scope,
|
|
30557
|
+
cliVersion: SDK_VERSION,
|
|
30558
|
+
agents: skillsPayload?.agents ?? [],
|
|
30559
|
+
workspace: apiCheck?.workspace ?? null,
|
|
30560
|
+
rollbackCommand: rollbackCommand(scope, root),
|
|
30561
|
+
statePath,
|
|
30562
|
+
doctor: doctorPayload,
|
|
30563
|
+
next: quickstart,
|
|
30564
|
+
render: {
|
|
30565
|
+
sections: [
|
|
30566
|
+
{
|
|
30567
|
+
title: "setup",
|
|
30568
|
+
lines: [
|
|
30569
|
+
"Deepline is installed and connected.",
|
|
30570
|
+
`Next: ${quickstart}`
|
|
30571
|
+
]
|
|
30572
|
+
}
|
|
30573
|
+
]
|
|
30574
|
+
}
|
|
30575
|
+
},
|
|
30576
|
+
{ json: options.json }
|
|
30577
|
+
);
|
|
30578
|
+
return 0;
|
|
30579
|
+
}
|
|
30580
|
+
function registerSetupCommands(program) {
|
|
30581
|
+
program.command("setup").description("Install skills, authenticate, and verify Deepline.").option("--scope <scope>", "Setup scope: global or local", "global").option("--json", "Emit one final JSON result envelope").addHelpText(
|
|
30582
|
+
"after",
|
|
30583
|
+
`
|
|
30584
|
+
Notes:
|
|
30585
|
+
Setup is idempotent. Bare setup resumes pending browser authorization.
|
|
30586
|
+
It installs skills before auth and does not run quickstart.
|
|
30587
|
+
|
|
30588
|
+
Examples:
|
|
30589
|
+
deepline setup --json
|
|
30590
|
+
deepline setup --scope local --json
|
|
30591
|
+
`
|
|
30592
|
+
).action(async (options) => {
|
|
30593
|
+
process.exitCode = await runSetupCommand(options);
|
|
30594
|
+
});
|
|
30595
|
+
program.command("doctor").description("Verify CLI, skills, auth, workspace, and API connectivity.").option(
|
|
30596
|
+
"--scope <scope>",
|
|
30597
|
+
"Expected setup scope: global or local",
|
|
30598
|
+
"global"
|
|
30599
|
+
).option("--json", "Emit one JSON result envelope").addHelpText(
|
|
30600
|
+
"after",
|
|
30601
|
+
`
|
|
30602
|
+
Notes:
|
|
30603
|
+
Doctor is read-only and makes no paid provider calls. It reports repairs but
|
|
30604
|
+
does not apply them automatically.
|
|
30605
|
+
|
|
30606
|
+
Examples:
|
|
30607
|
+
deepline doctor --json
|
|
30608
|
+
deepline doctor --scope local --json
|
|
30609
|
+
`
|
|
30610
|
+
).action(async (options) => {
|
|
30611
|
+
process.exitCode = await runDoctorCommand(options);
|
|
30612
|
+
});
|
|
30613
|
+
}
|
|
30614
|
+
|
|
30615
|
+
// ../shared_libs/cli/command-compatibility.json
|
|
30616
|
+
var command_compatibility_default = {
|
|
30617
|
+
enrich: {
|
|
30618
|
+
family: "python",
|
|
30619
|
+
label: "a legacy Python CLI enrichment command",
|
|
30620
|
+
sdk_alternative: "Use `deepline plays ...` for durable workflows or `deepline tools execute ...` for one tool call."
|
|
30621
|
+
},
|
|
30622
|
+
session: {
|
|
30623
|
+
family: "python",
|
|
30624
|
+
label: "a legacy Python CLI session/playground command",
|
|
30625
|
+
sdk_alternative: "Use `deepline sessions send ...` or `deepline sessions render ...` for transcript workflows."
|
|
30626
|
+
},
|
|
30627
|
+
workflows: {
|
|
30628
|
+
family: "python",
|
|
30629
|
+
label: "a legacy Python CLI workflow command",
|
|
30630
|
+
sdk_alternative: "Use `deepline plays ...` in the SDK CLI."
|
|
30631
|
+
},
|
|
30632
|
+
events: {
|
|
30633
|
+
family: "python",
|
|
30634
|
+
label: "a legacy Python CLI event command"
|
|
30635
|
+
},
|
|
30636
|
+
plays: {
|
|
30637
|
+
family: "sdk",
|
|
30638
|
+
label: "an SDK CLI play command",
|
|
30639
|
+
python_alternative: "Use `deepline workflows ...` only for legacy workflows."
|
|
30640
|
+
},
|
|
30641
|
+
runs: {
|
|
30642
|
+
family: "sdk",
|
|
30643
|
+
label: "an SDK CLI run inspection command"
|
|
30644
|
+
},
|
|
30645
|
+
sessions: {
|
|
30646
|
+
family: "sdk",
|
|
30647
|
+
label: "an SDK CLI session transcript command"
|
|
30648
|
+
},
|
|
30649
|
+
health: {
|
|
30650
|
+
family: "sdk",
|
|
30651
|
+
label: "an SDK CLI health command"
|
|
30652
|
+
}
|
|
30653
|
+
};
|
|
30654
|
+
|
|
30655
|
+
// src/cli/command-compatibility.ts
|
|
30656
|
+
var COMMAND_COMPATIBILITY = command_compatibility_default;
|
|
30657
|
+
function cliFamilyLabel(family) {
|
|
30658
|
+
return family === "sdk" ? "SDK CLI" : "legacy Python CLI";
|
|
30659
|
+
}
|
|
30660
|
+
function commandCompatibilityHint(currentFamily, commandName, baseUrl) {
|
|
30661
|
+
const compatibility = COMMAND_COMPATIBILITY[commandName];
|
|
30662
|
+
if (!compatibility || compatibility.family === currentFamily) {
|
|
30663
|
+
return null;
|
|
30664
|
+
}
|
|
30665
|
+
const expectedFamily = compatibility.family;
|
|
30666
|
+
const currentLabel = cliFamilyLabel(currentFamily);
|
|
30667
|
+
const expectedLabel = cliFamilyLabel(expectedFamily);
|
|
30668
|
+
const lines = [
|
|
30669
|
+
"",
|
|
30670
|
+
"Command compatibility:",
|
|
30671
|
+
` \`deepline ${commandName}\` is ${compatibility.label}.`,
|
|
30672
|
+
` Current binary: ${currentLabel}. Required binary: ${expectedLabel}.`,
|
|
30673
|
+
" If this came from an agent skill, the installed skill likely targets the other Deepline CLI."
|
|
30674
|
+
];
|
|
30675
|
+
if (currentFamily === "sdk") {
|
|
30676
|
+
lines.push(
|
|
30677
|
+
"",
|
|
30678
|
+
" To stay on the SDK CLI, refresh the Deepline agent skills:",
|
|
30679
|
+
` ${skillsInstallCommand(baseUrl, DEFAULT_SDK_SKILL_NAMES)}`,
|
|
30680
|
+
" To use the legacy Python CLI instead:",
|
|
30681
|
+
` ${legacyPythonInstallCommand(baseUrl)}`,
|
|
30682
|
+
" `deepline update` updates this SDK CLI, but it will not switch CLI families."
|
|
30683
|
+
);
|
|
30684
|
+
if (compatibility.sdk_alternative) {
|
|
30685
|
+
lines.push(` SDK alternative: ${compatibility.sdk_alternative}`);
|
|
30686
|
+
}
|
|
30687
|
+
} else {
|
|
30688
|
+
lines.push(
|
|
30689
|
+
"",
|
|
30690
|
+
" To use SDK commands, install the SDK CLI and refresh Deepline agent skills:",
|
|
30691
|
+
` ${sdkNpmGlobalInstallCommand()}`,
|
|
30692
|
+
` ${skillsInstallCommand(baseUrl, DEFAULT_SDK_SKILL_NAMES)}`,
|
|
30693
|
+
" `deepline update` updates this Python CLI and its skills, but it will not switch CLI families."
|
|
30694
|
+
);
|
|
30695
|
+
if (compatibility.python_alternative) {
|
|
30696
|
+
lines.push(` Python alternative: ${compatibility.python_alternative}`);
|
|
30697
|
+
}
|
|
30698
|
+
}
|
|
30699
|
+
return lines.join("\n");
|
|
30700
|
+
}
|
|
30701
|
+
function unknownCommandNameFromMessage(message) {
|
|
30702
|
+
const match = message.match(/unknown command ['"]([^'"]+)['"]/i);
|
|
30703
|
+
const command = match?.[1]?.trim();
|
|
30704
|
+
return command ? command : null;
|
|
30705
|
+
}
|
|
30706
|
+
|
|
30707
|
+
// src/cli/self-update.ts
|
|
30708
|
+
import { spawn as spawn5 } from "child_process";
|
|
30709
|
+
function envTruthy(name) {
|
|
30710
|
+
const value = process.env[name]?.trim().toLowerCase();
|
|
30711
|
+
return value === "1" || value === "true" || value === "yes";
|
|
30712
|
+
}
|
|
30713
|
+
function isCi() {
|
|
30714
|
+
return envTruthy("CI") || envTruthy("GITHUB_ACTIONS");
|
|
30715
|
+
}
|
|
30716
|
+
function shouldSkipSelfUpdate() {
|
|
30717
|
+
return envTruthy("DEEPLINE_SKIP_SELF_UPDATE") || envTruthy("DEEPLINE_NO_AUTO_UPDATE") || envTruthy("DEEPLINE_SKIP_SDK_AUTO_UPDATE") || envTruthy("DEEPLINE_DISABLE_AUTO_UPDATE") || isCi();
|
|
30718
|
+
}
|
|
30719
|
+
function parseSemver(version) {
|
|
30720
|
+
const trimmed = version?.trim();
|
|
30721
|
+
if (!trimmed) return null;
|
|
30722
|
+
const match = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(
|
|
30723
|
+
trimmed
|
|
30724
|
+
);
|
|
30725
|
+
if (!match) return null;
|
|
30726
|
+
return {
|
|
30727
|
+
major: Number(match[1]),
|
|
30728
|
+
minor: Number(match[2]),
|
|
30729
|
+
patch: Number(match[3]),
|
|
30730
|
+
prerelease: match[4] ?? ""
|
|
30731
|
+
};
|
|
30732
|
+
}
|
|
30733
|
+
function compareSemver(left, right) {
|
|
30734
|
+
const a = parseSemver(left);
|
|
30735
|
+
const b = parseSemver(right);
|
|
30736
|
+
if (!a || !b) {
|
|
30737
|
+
return left.localeCompare(right);
|
|
30738
|
+
}
|
|
30739
|
+
for (const key of ["major", "minor", "patch"]) {
|
|
30740
|
+
if (a[key] !== b[key]) return a[key] > b[key] ? 1 : -1;
|
|
30741
|
+
}
|
|
30742
|
+
if (a.prerelease === b.prerelease) return 0;
|
|
30743
|
+
if (!a.prerelease) return 1;
|
|
30744
|
+
if (!b.prerelease) return -1;
|
|
30745
|
+
return a.prerelease.localeCompare(b.prerelease);
|
|
30746
|
+
}
|
|
30747
|
+
function isDowngradeAutoUpdateResponse(response) {
|
|
30748
|
+
const target = response?.latest?.trim();
|
|
30749
|
+
const current = response?.current?.trim() || SDK_VERSION;
|
|
30750
|
+
if (!target) return false;
|
|
30751
|
+
return compareSemver(target, current) < 0;
|
|
30752
|
+
}
|
|
30753
|
+
function relaunchCurrentCommand(plan) {
|
|
30754
|
+
return new Promise((resolve15) => {
|
|
30755
|
+
const command = plan.kind === "python-sidecar" ? plan.sidecarPath : process.execPath;
|
|
30756
|
+
const args = plan.kind === "python-sidecar" ? process.argv.slice(2) : process.argv.slice(1);
|
|
30757
|
+
const child = spawn5(command, args, {
|
|
30758
|
+
stdio: "inherit",
|
|
30759
|
+
shell: process.platform === "win32",
|
|
30760
|
+
env: {
|
|
30761
|
+
...process.env,
|
|
30762
|
+
DEEPLINE_NO_AUTO_UPDATE: "1"
|
|
30763
|
+
}
|
|
30764
|
+
});
|
|
30765
|
+
child.on("error", (error) => {
|
|
30766
|
+
process.stderr.write(
|
|
30767
|
+
`Deepline SDK/CLI updated, but relaunch failed: ${error.message}
|
|
30768
|
+
`
|
|
30769
|
+
);
|
|
30770
|
+
resolve15(1);
|
|
30771
|
+
});
|
|
30772
|
+
child.on("close", (code) => resolve15(code ?? 1));
|
|
30773
|
+
});
|
|
30774
|
+
}
|
|
30775
|
+
async function maybeAutoUpdateAndRelaunch(response) {
|
|
30776
|
+
const autoUpdate = response?.auto_update;
|
|
30777
|
+
if (!response || !autoUpdate?.should_auto_update || shouldSkipSelfUpdate()) {
|
|
30778
|
+
return false;
|
|
30779
|
+
}
|
|
30780
|
+
if (isDowngradeAutoUpdateResponse(response)) {
|
|
30781
|
+
const target = response.latest;
|
|
30782
|
+
const current = response.current?.trim() || SDK_VERSION;
|
|
30783
|
+
process.stderr.write(
|
|
30784
|
+
`Deepline SDK/CLI auto-update refused: server advertised older ${target} than current ${current}. Continuing without mutating the CLI.
|
|
30785
|
+
`
|
|
30786
|
+
);
|
|
30787
|
+
return false;
|
|
30788
|
+
}
|
|
30789
|
+
const packageSpec = response.latest ? `deepline@${response.latest}` : void 0;
|
|
30790
|
+
const plan = resolveUpdatePlan({ packageSpec });
|
|
30791
|
+
if (plan.kind === "source") {
|
|
30792
|
+
return false;
|
|
30793
|
+
}
|
|
30794
|
+
const label = autoUpdate.reason === "rollback_forced" ? "has a server rollback pending and needs the latest rollback-aware CLI" : autoUpdate.reason === "deprecated" ? "is deprecated and will update automatically" : autoUpdate.required ? "requires an update" : "is more than the supported auto-update lag behind";
|
|
30795
|
+
process.stderr.write(
|
|
30796
|
+
`Deepline SDK/CLI ${label}; running ${plan.manualCommand}
|
|
30797
|
+
`
|
|
30798
|
+
);
|
|
30799
|
+
const updateResult = await runAutomaticUpdatePlan(plan);
|
|
30800
|
+
if (updateResult.status === "skipped_previous_failure") {
|
|
30801
|
+
return false;
|
|
30802
|
+
}
|
|
30803
|
+
if (updateResult.exitCode !== 0) {
|
|
30804
|
+
if (autoUpdate.required) {
|
|
30805
|
+
throw new Error(
|
|
30806
|
+
`Automatic Deepline SDK/CLI update failed with exit code ${updateResult.exitCode}. ${response.message}`
|
|
30807
|
+
);
|
|
30808
|
+
}
|
|
30809
|
+
process.stderr.write(
|
|
30810
|
+
`Deepline SDK/CLI auto-update failed with exit code ${updateResult.exitCode}; continuing with ${response.current ?? "current version"}.
|
|
30811
|
+
`
|
|
30812
|
+
);
|
|
30813
|
+
return false;
|
|
30814
|
+
}
|
|
30815
|
+
process.stderr.write("Deepline SDK/CLI updated; rerunning command.\n");
|
|
30816
|
+
const exitCode = await relaunchCurrentCommand(plan);
|
|
30817
|
+
process.exit(exitCode);
|
|
30818
|
+
return true;
|
|
30819
|
+
}
|
|
30820
|
+
|
|
30821
|
+
// src/cli/skills-sync.ts
|
|
30822
|
+
import { spawn as spawn6, spawnSync as spawnSync3 } from "child_process";
|
|
30823
|
+
import {
|
|
30824
|
+
existsSync as existsSync14,
|
|
30825
|
+
mkdirSync as mkdirSync12,
|
|
30826
|
+
readFileSync as readFileSync14,
|
|
30827
|
+
unlinkSync as unlinkSync2,
|
|
30828
|
+
writeFileSync as writeFileSync17
|
|
30829
|
+
} from "fs";
|
|
30830
|
+
import { dirname as dirname15, join as join17 } from "path";
|
|
30831
|
+
var CHECK_TIMEOUT_MS2 = 3e3;
|
|
30832
|
+
var attemptedSync = false;
|
|
30833
|
+
function shouldSkipSkillsSync() {
|
|
30834
|
+
if (detectAgentRuntime() === "claude_cowork") {
|
|
30835
|
+
return true;
|
|
30836
|
+
}
|
|
30837
|
+
const value = process.env.DEEPLINE_SKIP_SKILLS_SYNC?.trim().toLowerCase();
|
|
30838
|
+
return value === "1" || value === "true" || value === "yes" || value === "on";
|
|
30839
|
+
}
|
|
30840
|
+
function activePluginSkillsDir() {
|
|
30841
|
+
const pluginMode = process.env.DEEPLINE_PLUGIN_MODE?.trim().toLowerCase();
|
|
30842
|
+
if (pluginMode !== "true" && pluginMode !== "1" && pluginMode !== "yes" && pluginMode !== "on") {
|
|
30843
|
+
return "";
|
|
30844
|
+
}
|
|
30845
|
+
const dir = process.env.DEEPLINE_PLUGIN_SKILLS_DIR?.trim() ?? "";
|
|
30846
|
+
return dir && existsSync14(dir) ? dir : "";
|
|
30847
|
+
}
|
|
30848
|
+
function readPluginSkillsVersion() {
|
|
30849
|
+
const dir = activePluginSkillsDir();
|
|
30850
|
+
if (!dir) return "";
|
|
30851
|
+
try {
|
|
30852
|
+
return readFileSync14(join17(dir, ".version"), "utf-8").trim();
|
|
30853
|
+
} catch {
|
|
30854
|
+
return "";
|
|
30855
|
+
}
|
|
30856
|
+
}
|
|
30857
|
+
function sdkSkillsVersionPath(baseUrl) {
|
|
30858
|
+
return join17(sdkCliStateDirPath(baseUrl), "skills-version");
|
|
30859
|
+
}
|
|
30860
|
+
function legacySdkSkillsVersionPath(baseUrl) {
|
|
30861
|
+
return join17(dirname15(sdkCliStateDirPath(baseUrl)), "sdk-skills", ".version");
|
|
30862
|
+
}
|
|
30863
|
+
function unavailableSkillsNoticePath(baseUrl) {
|
|
30864
|
+
return join17(sdkCliStateDirPath(baseUrl), "skills-sync-unavailable-version");
|
|
30865
|
+
}
|
|
30866
|
+
function readSdkSkillsLocalVersion(baseUrl) {
|
|
30867
|
+
const pluginVersion = readPluginSkillsVersion();
|
|
30868
|
+
if (pluginVersion) return pluginVersion;
|
|
30869
|
+
const path = existsSync14(sdkSkillsVersionPath(baseUrl)) ? sdkSkillsVersionPath(baseUrl) : legacySdkSkillsVersionPath(baseUrl);
|
|
30870
|
+
if (!existsSync14(path)) return "";
|
|
30871
|
+
try {
|
|
30872
|
+
return readFileSync14(path, "utf-8").trim();
|
|
30873
|
+
} catch {
|
|
30874
|
+
return "";
|
|
30875
|
+
}
|
|
30876
|
+
}
|
|
30877
|
+
function writeLocalSkillsVersion(baseUrl, version) {
|
|
30878
|
+
const path = sdkSkillsVersionPath(baseUrl);
|
|
30879
|
+
mkdirSync12(dirname15(path), { recursive: true });
|
|
30880
|
+
writeFileSync17(path, `${version}
|
|
30881
|
+
`, "utf-8");
|
|
30882
|
+
}
|
|
30883
|
+
function writeUnavailableSkillsNotice(baseUrl, remoteVersion, skillNames) {
|
|
30884
|
+
const path = unavailableSkillsNoticePath(baseUrl);
|
|
30885
|
+
try {
|
|
30886
|
+
if (existsSync14(path) && readFileSync14(path, "utf-8").trim() === remoteVersion) {
|
|
30887
|
+
return;
|
|
30888
|
+
}
|
|
30889
|
+
mkdirSync12(dirname15(path), { recursive: true });
|
|
30890
|
+
writeFileSync17(path, `${remoteVersion}
|
|
30891
|
+
`, "utf-8");
|
|
30892
|
+
} catch {
|
|
30893
|
+
}
|
|
30894
|
+
const manualCommand = `npx ${buildSkillsInstallArgs(baseUrl, skillNames).join(" ")}`;
|
|
30895
|
+
writeSdkSkillsStatusLine(
|
|
30896
|
+
`Deepline agent skills are out of date, but neither \`bunx\` nor \`npx\` is available. Install Node.js/npm or Bun, then run:
|
|
30897
|
+
${manualCommand}`
|
|
30898
|
+
);
|
|
30899
|
+
}
|
|
30900
|
+
function clearUnavailableSkillsNotice(baseUrl) {
|
|
30901
|
+
try {
|
|
30902
|
+
unlinkSync2(unavailableSkillsNoticePath(baseUrl));
|
|
30903
|
+
} catch {
|
|
30904
|
+
}
|
|
30905
|
+
}
|
|
30906
|
+
function sortedUniqueSkillNames(names) {
|
|
30907
|
+
return [...new Set(names.map((name) => name.trim()).filter(Boolean))].sort(
|
|
30908
|
+
(a, b) => a.localeCompare(b)
|
|
30909
|
+
);
|
|
30910
|
+
}
|
|
30911
|
+
async function fetchV1SkillNames(baseUrl) {
|
|
30912
|
+
const controller = new AbortController();
|
|
30913
|
+
const timeout = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS2);
|
|
30914
|
+
try {
|
|
30915
|
+
const response = await fetch(
|
|
30916
|
+
new URL("/.well-known/skills/index.json", baseUrl),
|
|
30917
|
+
{ signal: controller.signal }
|
|
30918
|
+
);
|
|
30919
|
+
if (!response.ok) return [];
|
|
30920
|
+
const data = await response.json().catch(() => null);
|
|
30921
|
+
const names = (data?.skills ?? []).filter((skill) => skill.install_surface === "v1").map((skill) => skill.name).filter(
|
|
30922
|
+
(name) => typeof name === "string" && name.length > 0
|
|
30923
|
+
);
|
|
30924
|
+
return sortedUniqueSkillNames(names);
|
|
30925
|
+
} catch {
|
|
30926
|
+
return [];
|
|
30927
|
+
} finally {
|
|
30928
|
+
clearTimeout(timeout);
|
|
30929
|
+
}
|
|
30930
|
+
}
|
|
30931
|
+
function buildSdkSkillNames(v1SkillNames) {
|
|
30932
|
+
return sortedUniqueSkillNames(v1SkillNames);
|
|
30933
|
+
}
|
|
30934
|
+
async function fetchSkillsUpdate(baseUrl, localVersion) {
|
|
30935
|
+
const controller = new AbortController();
|
|
30936
|
+
const timeout = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS2);
|
|
30937
|
+
try {
|
|
30938
|
+
const response = await fetch(new URL("/api/v2/cli/update-check", baseUrl), {
|
|
30939
|
+
method: "POST",
|
|
30940
|
+
headers: { "Content-Type": "application/json" },
|
|
30941
|
+
body: JSON.stringify({
|
|
30942
|
+
skills: {
|
|
30943
|
+
version: localVersion
|
|
30944
|
+
}
|
|
30945
|
+
}),
|
|
30946
|
+
signal: controller.signal
|
|
30947
|
+
});
|
|
30948
|
+
if (!response.ok) return null;
|
|
30949
|
+
const data = await response.json().catch(() => null);
|
|
30950
|
+
const skills = data?.skills;
|
|
30951
|
+
if (!skills) return null;
|
|
30952
|
+
return {
|
|
30953
|
+
needsUpdate: skills.needs_update === true,
|
|
30954
|
+
remoteVersion: typeof skills.remote?.version === "string" ? skills.remote.version.trim() : ""
|
|
30955
|
+
};
|
|
30956
|
+
} catch {
|
|
30957
|
+
return null;
|
|
30958
|
+
} finally {
|
|
30959
|
+
clearTimeout(timeout);
|
|
30960
|
+
}
|
|
30961
|
+
}
|
|
30962
|
+
function buildSkillsInstallArgs(baseUrl, skillNames = DEFAULT_SDK_SKILL_NAMES) {
|
|
30963
|
+
return buildSkillsAddArgs(baseUrl, sortedUniqueSkillNames(skillNames));
|
|
30964
|
+
}
|
|
30965
|
+
function buildBunxSkillsInstallArgs(baseUrl, skillNames) {
|
|
30966
|
+
return buildSkillsAddArgs(baseUrl, sortedUniqueSkillNames(skillNames), {
|
|
30967
|
+
firstArg: "--bun"
|
|
30968
|
+
});
|
|
30969
|
+
}
|
|
30970
|
+
function hasCommand(command) {
|
|
30971
|
+
const result = spawnSync3(command, ["--version"], {
|
|
30972
|
+
stdio: "ignore",
|
|
30973
|
+
shell: process.platform === "win32"
|
|
30974
|
+
});
|
|
30975
|
+
return result.status === 0;
|
|
30976
|
+
}
|
|
30977
|
+
function shellQuote6(arg) {
|
|
30978
|
+
return `'${arg.replace(/'/g, `'\\''`)}'`;
|
|
30979
|
+
}
|
|
30980
|
+
function resolveSkillsInstallCommands(baseUrl, skillNames = DEFAULT_SDK_SKILL_NAMES) {
|
|
30981
|
+
const commands = [];
|
|
30982
|
+
if (hasCommand("bunx")) {
|
|
30983
|
+
const bunxArgs = buildBunxSkillsInstallArgs(baseUrl, skillNames);
|
|
30984
|
+
commands.push({
|
|
30985
|
+
command: "bunx",
|
|
30986
|
+
args: bunxArgs,
|
|
30987
|
+
manualCommand: `bunx ${bunxArgs.map(shellQuote6).join(" ")}`
|
|
30988
|
+
});
|
|
30989
|
+
}
|
|
30990
|
+
if (hasCommand("npx")) {
|
|
30991
|
+
const npxArgs = buildSkillsInstallArgs(baseUrl, skillNames);
|
|
30992
|
+
commands.push({
|
|
30993
|
+
command: "npx",
|
|
30994
|
+
args: npxArgs,
|
|
30995
|
+
manualCommand: `npx ${npxArgs.map(shellQuote6).join(" ")}`
|
|
30996
|
+
});
|
|
30997
|
+
}
|
|
30998
|
+
return commands;
|
|
30999
|
+
}
|
|
31000
|
+
function runOneSkillsInstall(install) {
|
|
31001
|
+
return new Promise((resolve15) => {
|
|
31002
|
+
const child = spawn6(install.command, install.args, {
|
|
31003
|
+
stdio: ["ignore", "ignore", "pipe"],
|
|
31004
|
+
env: process.env
|
|
31005
|
+
});
|
|
31006
|
+
let stderr = "";
|
|
31007
|
+
child.stderr.on("data", (chunk) => {
|
|
31008
|
+
stderr += chunk.toString("utf-8");
|
|
31009
|
+
});
|
|
31010
|
+
child.on("error", (error) => {
|
|
31011
|
+
resolve15({
|
|
31012
|
+
ok: false,
|
|
31013
|
+
detail: `failed to start ${install.command}: ${error.message}`,
|
|
31014
|
+
manualCommand: install.manualCommand
|
|
31015
|
+
});
|
|
31016
|
+
});
|
|
31017
|
+
child.on("close", (code) => {
|
|
31018
|
+
if (code === 0) {
|
|
31019
|
+
resolve15({ ok: true, detail: "", manualCommand: install.manualCommand });
|
|
31020
|
+
return;
|
|
31021
|
+
}
|
|
31022
|
+
const detail = stderr.trim();
|
|
31023
|
+
resolve15({
|
|
31024
|
+
ok: false,
|
|
31025
|
+
detail: detail ? `${install.command}: ${detail}` : `${install.command} exited ${code}`,
|
|
31026
|
+
manualCommand: install.manualCommand
|
|
31027
|
+
});
|
|
31028
|
+
});
|
|
31029
|
+
});
|
|
31030
|
+
}
|
|
31031
|
+
async function runSkillsInstall(installs) {
|
|
31032
|
+
const failures = [];
|
|
31033
|
+
for (const install of installs) {
|
|
31034
|
+
const result = await runOneSkillsInstall(install);
|
|
31035
|
+
if (result.ok) return true;
|
|
31036
|
+
failures.push(result);
|
|
31037
|
+
}
|
|
31038
|
+
const details = failures.map((failure) => failure.detail).filter(Boolean).join("\n");
|
|
31039
|
+
const manualCommand = failures.at(-1)?.manualCommand;
|
|
31040
|
+
process.stderr.write(
|
|
31041
|
+
`SDK skills sync failed${details ? `:
|
|
31042
|
+
${details}` : ""}
|
|
31043
|
+
` + (manualCommand ? `Run manually: ${manualCommand}
|
|
31044
|
+
` : "")
|
|
31045
|
+
);
|
|
31046
|
+
return false;
|
|
31047
|
+
}
|
|
31048
|
+
function runLegacySkillsCleanup() {
|
|
31049
|
+
const candidates = hasCommand("bunx") ? [
|
|
31050
|
+
{
|
|
31051
|
+
command: "bunx",
|
|
31052
|
+
args: [
|
|
31053
|
+
"--bun",
|
|
31054
|
+
"skills",
|
|
31055
|
+
"remove",
|
|
31056
|
+
"--global",
|
|
31057
|
+
"-y",
|
|
31058
|
+
...LEGACY_SKILL_NAMES_TO_REMOVE
|
|
31059
|
+
]
|
|
31060
|
+
},
|
|
31061
|
+
{
|
|
31062
|
+
command: "npx",
|
|
31063
|
+
args: [
|
|
31064
|
+
"--yes",
|
|
31065
|
+
"skills",
|
|
31066
|
+
"remove",
|
|
31067
|
+
"--global",
|
|
31068
|
+
"-y",
|
|
31069
|
+
...LEGACY_SKILL_NAMES_TO_REMOVE
|
|
31070
|
+
]
|
|
31071
|
+
}
|
|
31072
|
+
] : [
|
|
31073
|
+
{
|
|
31074
|
+
command: "npx",
|
|
31075
|
+
args: [
|
|
31076
|
+
"--yes",
|
|
31077
|
+
"skills",
|
|
31078
|
+
"remove",
|
|
31079
|
+
"--global",
|
|
31080
|
+
"-y",
|
|
31081
|
+
...LEGACY_SKILL_NAMES_TO_REMOVE
|
|
31082
|
+
]
|
|
31083
|
+
}
|
|
31084
|
+
];
|
|
31085
|
+
for (const candidate of candidates) {
|
|
31086
|
+
const result = spawnSync3(candidate.command, candidate.args, {
|
|
31087
|
+
stdio: "ignore",
|
|
31088
|
+
env: process.env,
|
|
31089
|
+
shell: process.platform === "win32"
|
|
31090
|
+
});
|
|
31091
|
+
if (result.status === 0) return;
|
|
31092
|
+
}
|
|
31093
|
+
}
|
|
31094
|
+
function writeSdkSkillsStatusLine(line) {
|
|
31095
|
+
const progress = getActiveCliProgress();
|
|
31096
|
+
if (progress) {
|
|
31097
|
+
progress.writeLine(line);
|
|
31098
|
+
return;
|
|
31099
|
+
}
|
|
31100
|
+
process.stderr.write(`${line}
|
|
31101
|
+
`);
|
|
31102
|
+
}
|
|
31103
|
+
async function syncSdkSkillsIfNeeded(baseUrl, options = {}) {
|
|
31104
|
+
if (attemptedSync || shouldSkipSkillsSync()) return;
|
|
31105
|
+
attemptedSync = true;
|
|
31106
|
+
const usingPluginSkills = Boolean(activePluginSkillsDir());
|
|
31107
|
+
if (usingPluginSkills) {
|
|
31108
|
+
return;
|
|
31109
|
+
}
|
|
31110
|
+
const localVersion = readSdkSkillsLocalVersion(baseUrl);
|
|
31111
|
+
const update = options.update === void 0 ? await fetchSkillsUpdate(baseUrl, localVersion) : options.update ? {
|
|
31112
|
+
needsUpdate: options.update.needs_update,
|
|
31113
|
+
remoteVersion: options.update.remote.version
|
|
31114
|
+
} : null;
|
|
31115
|
+
if (!update?.needsUpdate || !update.remoteVersion) {
|
|
31116
|
+
return;
|
|
31117
|
+
}
|
|
31118
|
+
const remoteSkillNames = await fetchV1SkillNames(baseUrl);
|
|
31119
|
+
const skillNames = buildSdkSkillNames(
|
|
31120
|
+
remoteSkillNames.length > 0 ? remoteSkillNames : DEFAULT_SDK_SKILL_NAMES
|
|
31121
|
+
);
|
|
31122
|
+
if (skillNames.length === 0) return;
|
|
31123
|
+
const installs = resolveSkillsInstallCommands(baseUrl, skillNames);
|
|
31124
|
+
if (installs.length === 0) {
|
|
31125
|
+
writeUnavailableSkillsNotice(baseUrl, update.remoteVersion, skillNames);
|
|
31126
|
+
return;
|
|
31127
|
+
}
|
|
31128
|
+
writeSdkSkillsStatusLine("Deepline skills changed; syncing agent skills...");
|
|
31129
|
+
const installed = await runSkillsInstall(installs);
|
|
31130
|
+
if (!installed) return;
|
|
31131
|
+
runLegacySkillsCleanup();
|
|
31132
|
+
writeLocalSkillsVersion(baseUrl, update.remoteVersion);
|
|
31133
|
+
clearUnavailableSkillsNotice(baseUrl);
|
|
31134
|
+
writeSdkSkillsStatusLine("Deepline agent skills are up to date.");
|
|
29983
31135
|
}
|
|
29984
31136
|
|
|
29985
31137
|
// src/cli/failure-reporting.ts
|
|
@@ -30283,8 +31435,8 @@ function topLevelCommandKnown(program, commandName) {
|
|
|
30283
31435
|
);
|
|
30284
31436
|
}
|
|
30285
31437
|
async function runPlayRunnerHealthCheck() {
|
|
30286
|
-
const dir = await mkdtemp2(
|
|
30287
|
-
const file =
|
|
31438
|
+
const dir = await mkdtemp2(join18(tmpdir4(), "deepline-health-play-"));
|
|
31439
|
+
const file = join18(dir, "health-check.play.ts");
|
|
30288
31440
|
try {
|
|
30289
31441
|
await writeFile5(
|
|
30290
31442
|
file,
|
|
@@ -30502,7 +31654,7 @@ Exit codes:
|
|
|
30502
31654
|
`
|
|
30503
31655
|
);
|
|
30504
31656
|
program.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
30505
|
-
if (actionCommand.name() === "version" || actionCommand.name() === "update" || actionCommand.name() === "switch" || isLegacyNoopInvocation()) {
|
|
31657
|
+
if (actionCommand.name() === "version" || actionCommand.name() === "update" || actionCommand.name() === "switch" || actionCommand.name() === "setup" || actionCommand.name() === "skills" || actionCommand.name() === "doctor" || isLegacyNoopInvocation()) {
|
|
30506
31658
|
return;
|
|
30507
31659
|
}
|
|
30508
31660
|
if (printStartupPhase) {
|
|
@@ -30574,6 +31726,8 @@ Exit codes:
|
|
|
30574
31726
|
registerFeedbackCommands(program);
|
|
30575
31727
|
registerLegacyNoopCommands(program);
|
|
30576
31728
|
registerUpdateCommand(program);
|
|
31729
|
+
registerSkillsCommand(program);
|
|
31730
|
+
registerSetupCommands(program);
|
|
30577
31731
|
registerQuickstartCommands(program);
|
|
30578
31732
|
registerSwitchCommands(program);
|
|
30579
31733
|
program.command("preflight").description("Run compact health, auth, and Deepline billing checks.").option("--json", "Force JSON output.").addHelpText(
|