deepline 0.1.258 → 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/play-runtime/transient-service-error.ts +5 -1
- 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.js
CHANGED
|
@@ -182,8 +182,8 @@ configureProxyFromEnv();
|
|
|
182
182
|
|
|
183
183
|
// src/cli/index.ts
|
|
184
184
|
var import_promises6 = require("fs/promises");
|
|
185
|
-
var
|
|
186
|
-
var
|
|
185
|
+
var import_node_path22 = require("path");
|
|
186
|
+
var import_node_os17 = require("os");
|
|
187
187
|
var import_commander4 = require("commander");
|
|
188
188
|
|
|
189
189
|
// src/config.ts
|
|
@@ -499,6 +499,21 @@ function resolveApiKeyForBaseUrl(baseUrl, explicitApiKey) {
|
|
|
499
499
|
cliEnv[API_KEY_ENV]
|
|
500
500
|
);
|
|
501
501
|
}
|
|
502
|
+
function resolveProjectApiKeyForBaseUrl(baseUrl, startDir = process.cwd()) {
|
|
503
|
+
const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
|
|
504
|
+
return firstNonEmpty(
|
|
505
|
+
...loadProjectEnvCandidates(startDir).map(({ env }) => {
|
|
506
|
+
const projectBaseUrl = normalizeBaseUrl(env[HOST_URL_ENV] ?? "");
|
|
507
|
+
return projectBaseUrl === normalizedBaseUrl ? env[API_KEY_ENV] : "";
|
|
508
|
+
})
|
|
509
|
+
);
|
|
510
|
+
}
|
|
511
|
+
function resolveGlobalApiKeyForBaseUrl(baseUrl) {
|
|
512
|
+
return firstNonEmpty(
|
|
513
|
+
process.env[API_KEY_ENV],
|
|
514
|
+
loadCliEnv(normalizeBaseUrl(baseUrl) || baseUrl)[API_KEY_ENV]
|
|
515
|
+
);
|
|
516
|
+
}
|
|
502
517
|
function getResolvedProjectAuthSource(baseUrl, apiKey, startDir = process.cwd()) {
|
|
503
518
|
const normalizedBaseUrl = normalizeBaseUrl(baseUrl);
|
|
504
519
|
const normalizedApiKey = apiKey.trim();
|
|
@@ -542,14 +557,79 @@ function mergeProjectEnvFile(filePath, values) {
|
|
|
542
557
|
`, "utf-8");
|
|
543
558
|
}
|
|
544
559
|
function ensureProjectEnvIsIgnored(dir) {
|
|
560
|
+
ensureProjectPrivatePathsIgnored(dir, [
|
|
561
|
+
PROJECT_DEEPLINE_ENV_FILE,
|
|
562
|
+
".deepline/"
|
|
563
|
+
]);
|
|
564
|
+
}
|
|
565
|
+
function ensureProjectPrivatePathsIgnored(dir, entries) {
|
|
566
|
+
const gitDir = findNearestGitCommonDir(dir);
|
|
567
|
+
if (gitDir) {
|
|
568
|
+
const excludePath = (0, import_node_path.join)(gitDir, "info", "exclude");
|
|
569
|
+
const existing2 = (0, import_node_fs.existsSync)(excludePath) ? (0, import_node_fs.readFileSync)(excludePath, "utf-8") : "";
|
|
570
|
+
const existingEntries2 = new Set(
|
|
571
|
+
existing2.split(/\r?\n/).map((line) => line.trim()).filter(Boolean)
|
|
572
|
+
);
|
|
573
|
+
const missing2 = entries.filter(
|
|
574
|
+
(entry) => !existingEntries2.has(entry) && !existingEntries2.has(`/${entry}`)
|
|
575
|
+
);
|
|
576
|
+
if (missing2.length === 0) return;
|
|
577
|
+
(0, import_node_fs.mkdirSync)((0, import_node_path.dirname)(excludePath), { recursive: true });
|
|
578
|
+
const prefix2 = existing2 && !existing2.endsWith("\n") ? "\n" : "";
|
|
579
|
+
(0, import_node_fs.writeFileSync)(
|
|
580
|
+
excludePath,
|
|
581
|
+
`${existing2}${prefix2}${missing2.join("\n")}
|
|
582
|
+
`,
|
|
583
|
+
"utf-8"
|
|
584
|
+
);
|
|
585
|
+
return;
|
|
586
|
+
}
|
|
545
587
|
const gitignorePath = (0, import_node_path.join)(dir, ".gitignore");
|
|
546
|
-
const entry = PROJECT_DEEPLINE_ENV_FILE;
|
|
547
588
|
const existing = (0, import_node_fs.existsSync)(gitignorePath) ? (0, import_node_fs.readFileSync)(gitignorePath, "utf-8") : "";
|
|
548
|
-
const
|
|
549
|
-
|
|
589
|
+
const existingEntries = new Set(
|
|
590
|
+
existing.split(/\r?\n/).map((line) => line.trim()).filter(Boolean)
|
|
591
|
+
);
|
|
592
|
+
const missing = entries.filter(
|
|
593
|
+
(entry) => !existingEntries.has(entry) && !existingEntries.has(`/${entry}`)
|
|
594
|
+
);
|
|
595
|
+
if (missing.length === 0) return;
|
|
550
596
|
const prefix = existing && !existing.endsWith("\n") ? "\n" : "";
|
|
551
|
-
(0, import_node_fs.writeFileSync)(
|
|
552
|
-
|
|
597
|
+
(0, import_node_fs.writeFileSync)(
|
|
598
|
+
gitignorePath,
|
|
599
|
+
`${existing}${prefix}${missing.join("\n")}
|
|
600
|
+
`,
|
|
601
|
+
"utf-8"
|
|
602
|
+
);
|
|
603
|
+
}
|
|
604
|
+
function findNearestGitCommonDir(startDir) {
|
|
605
|
+
let current = (0, import_node_path.resolve)(startDir);
|
|
606
|
+
while (true) {
|
|
607
|
+
const candidate = (0, import_node_path.join)(current, ".git");
|
|
608
|
+
if ((0, import_node_fs.existsSync)(candidate)) {
|
|
609
|
+
try {
|
|
610
|
+
const stat2 = (0, import_node_fs.statSync)(candidate);
|
|
611
|
+
if (stat2.isDirectory()) return candidate;
|
|
612
|
+
if (stat2.isFile()) {
|
|
613
|
+
const match = (0, import_node_fs.readFileSync)(candidate, "utf8").match(
|
|
614
|
+
/^gitdir:\s*(.+)$/m
|
|
615
|
+
);
|
|
616
|
+
const rawGitDir = match?.[1]?.trim();
|
|
617
|
+
if (rawGitDir) {
|
|
618
|
+
const gitDir = (0, import_node_path.isAbsolute)(rawGitDir) ? rawGitDir : (0, import_node_path.resolve)((0, import_node_path.dirname)(candidate), rawGitDir);
|
|
619
|
+
const commonDirPath = (0, import_node_path.join)(gitDir, "commondir");
|
|
620
|
+
if (!(0, import_node_fs.existsSync)(commonDirPath)) return gitDir;
|
|
621
|
+
const rawCommonDir = (0, import_node_fs.readFileSync)(commonDirPath, "utf8").trim();
|
|
622
|
+
return rawCommonDir ? (0, import_node_path.isAbsolute)(rawCommonDir) ? rawCommonDir : (0, import_node_path.resolve)(gitDir, rawCommonDir) : gitDir;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
} catch {
|
|
626
|
+
return null;
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
const parent = (0, import_node_path.dirname)(current);
|
|
630
|
+
if (parent === current) return null;
|
|
631
|
+
current = parent;
|
|
632
|
+
}
|
|
553
633
|
}
|
|
554
634
|
function saveProjectDeeplineEnvValues(values, startDir = process.cwd()) {
|
|
555
635
|
const target = resolveProjectPinTarget(startDir);
|
|
@@ -636,7 +716,7 @@ var SDK_RELEASE = {
|
|
|
636
716
|
// Deepline-native radars. Older clients must update before discovering,
|
|
637
717
|
// checking, or deploying an unlaunched monitor integration.
|
|
638
718
|
// 0.1.253 makes play-page browser opening opt-in and retires --no-open.
|
|
639
|
-
version: "0.1.
|
|
719
|
+
version: "0.1.260",
|
|
640
720
|
apiContract: "2026-07-native-monitor-launch-hard-cutover",
|
|
641
721
|
supportPolicy: {
|
|
642
722
|
minimumSupported: "0.1.53",
|
|
@@ -1321,7 +1401,7 @@ function decodeSseFrame(frame) {
|
|
|
1321
1401
|
return parsed;
|
|
1322
1402
|
}
|
|
1323
1403
|
function sleep(ms) {
|
|
1324
|
-
return new Promise((
|
|
1404
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
1325
1405
|
}
|
|
1326
1406
|
function withCoworkNetworkHint(message) {
|
|
1327
1407
|
if (!isCoworkLikeSandbox2() || message.includes(COWORK_NETWORK_HINT)) {
|
|
@@ -2293,14 +2373,14 @@ async function* observeRunEvents(options) {
|
|
|
2293
2373
|
try {
|
|
2294
2374
|
for (; ; ) {
|
|
2295
2375
|
if (queue.length === 0) {
|
|
2296
|
-
const waitForItem = new Promise((
|
|
2297
|
-
wake =
|
|
2376
|
+
const waitForItem = new Promise((resolve15) => {
|
|
2377
|
+
wake = resolve15;
|
|
2298
2378
|
});
|
|
2299
2379
|
if (!sawFirstSnapshot) {
|
|
2300
2380
|
const timedOut = await Promise.race([
|
|
2301
2381
|
waitForItem.then(() => false),
|
|
2302
2382
|
new Promise(
|
|
2303
|
-
(
|
|
2383
|
+
(resolve15) => setTimeout(() => resolve15(true), OBSERVE_BOOTSTRAP_TIMEOUT_MS)
|
|
2304
2384
|
)
|
|
2305
2385
|
]);
|
|
2306
2386
|
if (timedOut && queue.length === 0) {
|
|
@@ -2518,7 +2598,7 @@ function parseEnvTestPolicyOverrides() {
|
|
|
2518
2598
|
return normalizeTestPolicyOverrides(parsed, "DEEPLINE_TEST_POLICY_OVERRIDES");
|
|
2519
2599
|
}
|
|
2520
2600
|
function sleep2(ms) {
|
|
2521
|
-
return new Promise((
|
|
2601
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
2522
2602
|
}
|
|
2523
2603
|
function isTransientCompileManifestError(error) {
|
|
2524
2604
|
if (error instanceof DeeplineError && typeof error.statusCode === "number") {
|
|
@@ -5679,30 +5759,86 @@ var EXIT_SERVER = 5;
|
|
|
5679
5759
|
function envFilePath(baseUrl) {
|
|
5680
5760
|
return hostEnvFilePath(baseUrl);
|
|
5681
5761
|
}
|
|
5682
|
-
function
|
|
5762
|
+
function normalizeAuthScope(value) {
|
|
5763
|
+
if (!value || value === "global") return "global";
|
|
5764
|
+
if (value === "folder") return "folder";
|
|
5765
|
+
throw new Error("--auth-scope must be one of: folder, global");
|
|
5766
|
+
}
|
|
5767
|
+
function parseAuthScope(args) {
|
|
5768
|
+
const index = args.indexOf("--auth-scope");
|
|
5769
|
+
return normalizeAuthScope(index >= 0 ? args[index + 1] : void 0);
|
|
5770
|
+
}
|
|
5771
|
+
function pendingClaimPath(baseUrl, scope) {
|
|
5772
|
+
if (scope === "folder") {
|
|
5773
|
+
const target = resolveProjectPinTarget();
|
|
5774
|
+
if (!target.ok) {
|
|
5775
|
+
throw new Error(
|
|
5776
|
+
`Cowork project folder is ambiguous. Candidate folders: ${target.candidates.join(
|
|
5777
|
+
", "
|
|
5778
|
+
)}. Set CLAUDE_PROJECT_DIR or cd into the intended project folder.`
|
|
5779
|
+
);
|
|
5780
|
+
}
|
|
5781
|
+
return (0, import_node_path5.join)(target.dir, ".deepline", "setup", "pending-auth.json");
|
|
5782
|
+
}
|
|
5783
|
+
return `${hostConfigDirPath(baseUrl)}/pending-auth.json`;
|
|
5784
|
+
}
|
|
5785
|
+
function legacyPendingClaimTokenPath(baseUrl) {
|
|
5683
5786
|
return `${hostConfigDirPath(baseUrl)}/pending-claim-token`;
|
|
5684
5787
|
}
|
|
5685
|
-
function
|
|
5686
|
-
const filePath =
|
|
5788
|
+
function savePendingClaim(baseUrl, claim) {
|
|
5789
|
+
const filePath = pendingClaimPath(baseUrl, claim.scope);
|
|
5687
5790
|
const dir = (0, import_node_path5.dirname)(filePath);
|
|
5688
5791
|
if (!(0, import_node_fs5.existsSync)(dir)) {
|
|
5689
5792
|
(0, import_node_fs5.mkdirSync)(dir, { recursive: true });
|
|
5690
5793
|
}
|
|
5691
|
-
(0, import_node_fs5.writeFileSync)(filePath, `${
|
|
5692
|
-
`,
|
|
5794
|
+
(0, import_node_fs5.writeFileSync)(filePath, `${JSON.stringify(claim, null, 2)}
|
|
5795
|
+
`, {
|
|
5796
|
+
encoding: "utf-8",
|
|
5797
|
+
mode: 384
|
|
5798
|
+
});
|
|
5693
5799
|
}
|
|
5694
|
-
function
|
|
5695
|
-
|
|
5696
|
-
if (!(0, import_node_fs5.existsSync)(filePath)) return "";
|
|
5800
|
+
function readPendingAuthClaim(baseUrl, scope) {
|
|
5801
|
+
let filePath;
|
|
5697
5802
|
try {
|
|
5698
|
-
|
|
5803
|
+
filePath = pendingClaimPath(baseUrl, scope);
|
|
5699
5804
|
} catch {
|
|
5700
|
-
return
|
|
5805
|
+
return null;
|
|
5806
|
+
}
|
|
5807
|
+
if (!(0, import_node_fs5.existsSync)(filePath)) {
|
|
5808
|
+
if (scope !== "global") return null;
|
|
5809
|
+
try {
|
|
5810
|
+
const claimToken = (0, import_node_fs5.readFileSync)(
|
|
5811
|
+
legacyPendingClaimTokenPath(baseUrl),
|
|
5812
|
+
"utf-8"
|
|
5813
|
+
).trim();
|
|
5814
|
+
return claimToken ? {
|
|
5815
|
+
claimToken,
|
|
5816
|
+
claimUrl: `${baseUrl}/api/v2/auth/cli/claim/${encodeURIComponent(claimToken)}`,
|
|
5817
|
+
scope
|
|
5818
|
+
} : null;
|
|
5819
|
+
} catch {
|
|
5820
|
+
return null;
|
|
5821
|
+
}
|
|
5822
|
+
}
|
|
5823
|
+
try {
|
|
5824
|
+
const parsed = JSON.parse((0, import_node_fs5.readFileSync)(filePath, "utf-8"));
|
|
5825
|
+
const claimToken = typeof parsed.claimToken === "string" ? parsed.claimToken.trim() : "";
|
|
5826
|
+
if (!claimToken) return null;
|
|
5827
|
+
return {
|
|
5828
|
+
claimToken,
|
|
5829
|
+
claimUrl: typeof parsed.claimUrl === "string" ? parsed.claimUrl.trim() : "",
|
|
5830
|
+
scope
|
|
5831
|
+
};
|
|
5832
|
+
} catch {
|
|
5833
|
+
return null;
|
|
5701
5834
|
}
|
|
5702
5835
|
}
|
|
5703
|
-
function
|
|
5836
|
+
function clearPendingClaim(baseUrl, scope) {
|
|
5704
5837
|
try {
|
|
5705
|
-
(0, import_node_fs5.rmSync)(
|
|
5838
|
+
(0, import_node_fs5.rmSync)(pendingClaimPath(baseUrl, scope), { force: true });
|
|
5839
|
+
if (scope === "global") {
|
|
5840
|
+
(0, import_node_fs5.rmSync)(legacyPendingClaimTokenPath(baseUrl), { force: true });
|
|
5841
|
+
}
|
|
5706
5842
|
} catch {
|
|
5707
5843
|
}
|
|
5708
5844
|
}
|
|
@@ -5727,12 +5863,16 @@ function shouldWaitForRegisterClaim(mode) {
|
|
|
5727
5863
|
if (mode === "no") return false;
|
|
5728
5864
|
return detectAgentRuntime() !== "claude_cowork";
|
|
5729
5865
|
}
|
|
5730
|
-
function saveEnvValues(values, baseUrl) {
|
|
5866
|
+
function saveEnvValues(values, baseUrl, scope) {
|
|
5731
5867
|
const filtered = {
|
|
5732
5868
|
...values[HOST_URL_ENV] ? { [HOST_URL_ENV]: values[HOST_URL_ENV] } : {},
|
|
5733
5869
|
...values[API_KEY_ENV] ? { [API_KEY_ENV]: values[API_KEY_ENV] } : {}
|
|
5734
5870
|
};
|
|
5735
|
-
|
|
5871
|
+
if (scope === "folder") {
|
|
5872
|
+
saveProjectDeeplineEnvValues(filtered);
|
|
5873
|
+
} else {
|
|
5874
|
+
saveHostEnvValues(baseUrl, filtered);
|
|
5875
|
+
}
|
|
5736
5876
|
}
|
|
5737
5877
|
async function httpJson(method, url, apiKey, body) {
|
|
5738
5878
|
const headers = {
|
|
@@ -5795,7 +5935,7 @@ function buildCandidateUrls2(url) {
|
|
|
5795
5935
|
}
|
|
5796
5936
|
}
|
|
5797
5937
|
function sleep4(ms) {
|
|
5798
|
-
return new Promise((
|
|
5938
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
5799
5939
|
}
|
|
5800
5940
|
function printDeeplineLogo() {
|
|
5801
5941
|
if (process.stdout.isTTY && (process.stdout.columns ?? 80) >= 70) {
|
|
@@ -5856,8 +5996,13 @@ async function handleRegister(args) {
|
|
|
5856
5996
|
let orgName = "";
|
|
5857
5997
|
let agentName = "";
|
|
5858
5998
|
let waitMode;
|
|
5999
|
+
let authScope;
|
|
5859
6000
|
try {
|
|
5860
6001
|
waitMode = parseRegisterWaitMode(args);
|
|
6002
|
+
authScope = parseAuthScope(args);
|
|
6003
|
+
if (authScope === "folder") {
|
|
6004
|
+
pendingClaimPath(baseUrl, authScope);
|
|
6005
|
+
}
|
|
5861
6006
|
} catch (error) {
|
|
5862
6007
|
console.error(error instanceof Error ? error.message : String(error));
|
|
5863
6008
|
return 2;
|
|
@@ -5890,18 +6035,22 @@ async function handleRegister(args) {
|
|
|
5890
6035
|
const claimUrl = String(data.claim_url || "");
|
|
5891
6036
|
const claimToken = String(data.claim_token || "");
|
|
5892
6037
|
if (claimToken) {
|
|
5893
|
-
|
|
6038
|
+
savePendingClaim(baseUrl, { claimToken, claimUrl, scope: authScope });
|
|
5894
6039
|
saveEnvValues(
|
|
5895
6040
|
{
|
|
5896
6041
|
[HOST_URL_ENV]: baseUrl
|
|
5897
6042
|
},
|
|
5898
|
-
baseUrl
|
|
6043
|
+
baseUrl,
|
|
6044
|
+
authScope
|
|
5899
6045
|
);
|
|
5900
6046
|
}
|
|
5901
6047
|
if (claimUrl) {
|
|
5902
|
-
|
|
5903
|
-
console.log(
|
|
5904
|
-
|
|
6048
|
+
const shouldOpen = waitMode !== "no" && detectAgentRuntime() !== "claude_cowork";
|
|
6049
|
+
console.log(
|
|
6050
|
+
shouldOpen ? " Opening approval page in your browser." : " Open this approval page in your browser:"
|
|
6051
|
+
);
|
|
6052
|
+
console.log(` ${claimUrl}`);
|
|
6053
|
+
if (shouldOpen) openInBrowser(claimUrl);
|
|
5905
6054
|
}
|
|
5906
6055
|
if (data.cli_message) {
|
|
5907
6056
|
console.log(String(data.cli_message));
|
|
@@ -5919,7 +6068,7 @@ async function handleRegister(args) {
|
|
|
5919
6068
|
{ claim_token: claimToken, reveal: true }
|
|
5920
6069
|
);
|
|
5921
6070
|
if (s === 401 || s === 403) {
|
|
5922
|
-
|
|
6071
|
+
clearPendingClaim(baseUrl, authScope);
|
|
5923
6072
|
console.log("Status: unauthorized");
|
|
5924
6073
|
return EXIT_AUTH;
|
|
5925
6074
|
}
|
|
@@ -5940,15 +6089,16 @@ async function handleRegister(args) {
|
|
|
5940
6089
|
[HOST_URL_ENV]: baseUrl,
|
|
5941
6090
|
[API_KEY_ENV]: apiKey
|
|
5942
6091
|
},
|
|
5943
|
-
baseUrl
|
|
6092
|
+
baseUrl,
|
|
6093
|
+
authScope
|
|
5944
6094
|
);
|
|
5945
|
-
|
|
6095
|
+
clearPendingClaim(baseUrl, authScope);
|
|
5946
6096
|
await printClaimSuccessBanner(baseUrl, apiKey, statusData);
|
|
5947
6097
|
return EXIT_OK;
|
|
5948
6098
|
}
|
|
5949
6099
|
}
|
|
5950
6100
|
if (state === "expired") {
|
|
5951
|
-
|
|
6101
|
+
clearPendingClaim(baseUrl, authScope);
|
|
5952
6102
|
console.log(
|
|
5953
6103
|
"That approval link expired. Please run: deepline auth register"
|
|
5954
6104
|
);
|
|
@@ -5960,6 +6110,13 @@ async function handleRegister(args) {
|
|
|
5960
6110
|
async function handleWait(args) {
|
|
5961
6111
|
const baseUrl = autoDetectBaseUrl().replace(/\/$/, "");
|
|
5962
6112
|
let timeoutSeconds = 300;
|
|
6113
|
+
let authScope;
|
|
6114
|
+
try {
|
|
6115
|
+
authScope = parseAuthScope(args);
|
|
6116
|
+
} catch (error) {
|
|
6117
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
6118
|
+
return 2;
|
|
6119
|
+
}
|
|
5963
6120
|
for (let i = 0; i < args.length; i++) {
|
|
5964
6121
|
if (args[i] === "--timeout" && args[i + 1]) {
|
|
5965
6122
|
const parsed = Number.parseInt(args[++i], 10);
|
|
@@ -5968,9 +6125,11 @@ async function handleWait(args) {
|
|
|
5968
6125
|
}
|
|
5969
6126
|
}
|
|
5970
6127
|
}
|
|
5971
|
-
const
|
|
5972
|
-
|
|
5973
|
-
|
|
6128
|
+
const pendingClaim = readPendingAuthClaim(baseUrl, authScope);
|
|
6129
|
+
const claimToken = pendingClaim?.claimToken ?? "";
|
|
6130
|
+
if (!pendingClaim) {
|
|
6131
|
+
const scopedApiKey = authScope === "folder" ? resolveProjectApiKeyForBaseUrl(baseUrl) : resolveGlobalApiKeyForBaseUrl(baseUrl);
|
|
6132
|
+
if (scopedApiKey) {
|
|
5974
6133
|
console.log("Already connected.");
|
|
5975
6134
|
return EXIT_OK;
|
|
5976
6135
|
}
|
|
@@ -5986,7 +6145,7 @@ async function handleWait(args) {
|
|
|
5986
6145
|
{ claim_token: claimToken, reveal: true }
|
|
5987
6146
|
);
|
|
5988
6147
|
if (status === 401 || status === 403) {
|
|
5989
|
-
|
|
6148
|
+
clearPendingClaim(baseUrl, authScope);
|
|
5990
6149
|
console.error("Claim is invalid. Run: deepline auth register");
|
|
5991
6150
|
return EXIT_AUTH;
|
|
5992
6151
|
}
|
|
@@ -6007,15 +6166,16 @@ async function handleWait(args) {
|
|
|
6007
6166
|
[HOST_URL_ENV]: baseUrl,
|
|
6008
6167
|
[API_KEY_ENV]: apiKey
|
|
6009
6168
|
},
|
|
6010
|
-
baseUrl
|
|
6169
|
+
baseUrl,
|
|
6170
|
+
authScope
|
|
6011
6171
|
);
|
|
6012
|
-
|
|
6172
|
+
clearPendingClaim(baseUrl, authScope);
|
|
6013
6173
|
await printClaimSuccessBanner(baseUrl, apiKey, data);
|
|
6014
6174
|
return EXIT_OK;
|
|
6015
6175
|
}
|
|
6016
6176
|
}
|
|
6017
6177
|
if (state === "expired") {
|
|
6018
|
-
|
|
6178
|
+
clearPendingClaim(baseUrl, authScope);
|
|
6019
6179
|
console.error("That approval link expired. Run: deepline auth register");
|
|
6020
6180
|
return EXIT_AUTH;
|
|
6021
6181
|
}
|
|
@@ -6030,6 +6190,16 @@ async function handleStatus(args) {
|
|
|
6030
6190
|
const baseUrl = autoDetectBaseUrl().replace(/\/$/, "");
|
|
6031
6191
|
const reveal = args.includes("--reveal");
|
|
6032
6192
|
const jsonOutput = argsWantJson(args);
|
|
6193
|
+
const hasExplicitAuthScope = args.includes("--auth-scope");
|
|
6194
|
+
let authScope = null;
|
|
6195
|
+
if (hasExplicitAuthScope) {
|
|
6196
|
+
try {
|
|
6197
|
+
authScope = parseAuthScope(args);
|
|
6198
|
+
} catch (error) {
|
|
6199
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
6200
|
+
return 2;
|
|
6201
|
+
}
|
|
6202
|
+
}
|
|
6033
6203
|
let hostStatusPayload = null;
|
|
6034
6204
|
const hostLines = [];
|
|
6035
6205
|
try {
|
|
@@ -6056,14 +6226,16 @@ async function handleStatus(args) {
|
|
|
6056
6226
|
};
|
|
6057
6227
|
hostLines.push(`Host: ${baseUrl} (unreachable)`);
|
|
6058
6228
|
}
|
|
6059
|
-
const apiKey = resolveApiKeyForBaseUrl(baseUrl);
|
|
6229
|
+
const apiKey = authScope === "folder" ? resolveProjectApiKeyForBaseUrl(baseUrl) : authScope === "global" ? resolveGlobalApiKeyForBaseUrl(baseUrl) : resolveApiKeyForBaseUrl(baseUrl);
|
|
6060
6230
|
if (!apiKey) {
|
|
6061
|
-
|
|
6231
|
+
const pendingClaim = authScope ? readPendingAuthClaim(baseUrl, authScope) : readPendingAuthClaim(baseUrl, "folder") ?? readPendingAuthClaim(baseUrl, "global");
|
|
6232
|
+
if (pendingClaim) {
|
|
6062
6233
|
printCommandEnvelope(
|
|
6063
6234
|
{
|
|
6064
6235
|
...hostStatusPayload ?? { host: baseUrl },
|
|
6065
6236
|
status: "pending",
|
|
6066
6237
|
connected: false,
|
|
6238
|
+
authorization_url: pendingClaim.claimUrl || null,
|
|
6067
6239
|
next: "deepline auth wait",
|
|
6068
6240
|
render: {
|
|
6069
6241
|
sections: [
|
|
@@ -6145,7 +6317,8 @@ async function handleStatus(args) {
|
|
|
6145
6317
|
console.error(`Auth status error (status ${status}).`);
|
|
6146
6318
|
return EXIT_SERVER;
|
|
6147
6319
|
}
|
|
6148
|
-
|
|
6320
|
+
const resolvedAuthScope = authScope ?? (getResolvedProjectAuthSource(baseUrl, apiKey) ? "folder" : "global");
|
|
6321
|
+
clearPendingClaim(baseUrl, resolvedAuthScope);
|
|
6149
6322
|
const payload = {
|
|
6150
6323
|
...hostStatusPayload ?? { host: baseUrl },
|
|
6151
6324
|
status: data.status || "(unknown)",
|
|
@@ -6170,9 +6343,15 @@ async function handleStatus(args) {
|
|
|
6170
6343
|
[HOST_URL_ENV]: baseUrl,
|
|
6171
6344
|
[API_KEY_ENV]: apiKeyResp
|
|
6172
6345
|
},
|
|
6173
|
-
baseUrl
|
|
6346
|
+
baseUrl,
|
|
6347
|
+
resolvedAuthScope
|
|
6174
6348
|
);
|
|
6175
|
-
|
|
6349
|
+
if (resolvedAuthScope === "folder") {
|
|
6350
|
+
const target = resolveProjectPinTarget();
|
|
6351
|
+
savedApiKeyPath = target.ok ? (0, import_node_path5.join)(target.dir, ".env.deepline") : null;
|
|
6352
|
+
} else {
|
|
6353
|
+
savedApiKeyPath = envFilePath(baseUrl);
|
|
6354
|
+
}
|
|
6176
6355
|
}
|
|
6177
6356
|
}
|
|
6178
6357
|
printCommandEnvelope(
|
|
@@ -6237,12 +6416,19 @@ Examples:
|
|
|
6237
6416
|
deepline auth register
|
|
6238
6417
|
deepline auth register --org-name Acme --agent-name local-cli
|
|
6239
6418
|
deepline auth register --wait no
|
|
6419
|
+
deepline auth register --auth-scope folder --wait no
|
|
6240
6420
|
`
|
|
6241
|
-
).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").
|
|
6421
|
+
).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(
|
|
6422
|
+
"--auth-scope <scope>",
|
|
6423
|
+
"Credential scope: global or folder",
|
|
6424
|
+
"global"
|
|
6425
|
+
).action(async (options) => {
|
|
6242
6426
|
process.exitCode = await handleRegister([
|
|
6243
6427
|
...options.orgName ? ["--org-name", options.orgName] : [],
|
|
6244
6428
|
...options.agentName ? ["--agent-name", options.agentName] : [],
|
|
6245
|
-
...options.noWait || options.wait === false ? ["--wait", "no"] : ["--wait", String(options.wait ?? "auto")]
|
|
6429
|
+
...options.noWait || options.wait === false ? ["--wait", "no"] : ["--wait", String(options.wait ?? "auto")],
|
|
6430
|
+
"--auth-scope",
|
|
6431
|
+
String(options.authScope ?? "global")
|
|
6246
6432
|
]);
|
|
6247
6433
|
});
|
|
6248
6434
|
auth.command("wait").description("Wait for a pending browser approval and save the API key.").addHelpText(
|
|
@@ -6255,10 +6441,17 @@ Notes:
|
|
|
6255
6441
|
Examples:
|
|
6256
6442
|
deepline auth wait
|
|
6257
6443
|
deepline auth wait --timeout 120
|
|
6444
|
+
deepline auth wait --auth-scope folder --timeout 120
|
|
6258
6445
|
`
|
|
6259
|
-
).option("--timeout <seconds>", "Maximum seconds to wait", "300").
|
|
6446
|
+
).option("--timeout <seconds>", "Maximum seconds to wait", "300").option(
|
|
6447
|
+
"--auth-scope <scope>",
|
|
6448
|
+
"Credential scope: global or folder",
|
|
6449
|
+
"global"
|
|
6450
|
+
).action(async (options) => {
|
|
6260
6451
|
process.exitCode = await handleWait([
|
|
6261
|
-
...options.timeout ? ["--timeout", options.timeout] : []
|
|
6452
|
+
...options.timeout ? ["--timeout", options.timeout] : [],
|
|
6453
|
+
"--auth-scope",
|
|
6454
|
+
String(options.authScope ?? "global")
|
|
6262
6455
|
]);
|
|
6263
6456
|
});
|
|
6264
6457
|
auth.command("status").description("Show the current CLI auth and workspace status.").addHelpText(
|
|
@@ -6271,14 +6464,16 @@ Notes:
|
|
|
6271
6464
|
|
|
6272
6465
|
Examples:
|
|
6273
6466
|
deepline auth status
|
|
6467
|
+
deepline auth status --auth-scope folder
|
|
6274
6468
|
deepline auth status --json
|
|
6275
6469
|
`
|
|
6276
6470
|
).option(
|
|
6277
6471
|
"--reveal",
|
|
6278
6472
|
"Persist the revealed API key back to the host auth file"
|
|
6279
|
-
).option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
|
|
6473
|
+
).option("--auth-scope <scope>", "Read only folder or global auth").option("--json", "Emit JSON output. Also automatic when stdout is piped").action(async (options) => {
|
|
6280
6474
|
process.exitCode = await handleStatus([
|
|
6281
6475
|
...options.reveal ? ["--reveal"] : [],
|
|
6476
|
+
...options.authScope ? ["--auth-scope", String(options.authScope)] : [],
|
|
6282
6477
|
...options.json ? ["--json"] : []
|
|
6283
6478
|
]);
|
|
6284
6479
|
});
|
|
@@ -11302,7 +11497,7 @@ function traceCliSync(phase, fields, run) {
|
|
|
11302
11497
|
}
|
|
11303
11498
|
}
|
|
11304
11499
|
function sleep5(ms) {
|
|
11305
|
-
return new Promise((
|
|
11500
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
11306
11501
|
}
|
|
11307
11502
|
function parseReferencedPlayTarget2(target) {
|
|
11308
11503
|
const trimmed = target.trim();
|
|
@@ -19617,7 +19812,7 @@ function emitEnrichDebug(message) {
|
|
|
19617
19812
|
);
|
|
19618
19813
|
}
|
|
19619
19814
|
function sleep6(ms) {
|
|
19620
|
-
return new Promise((
|
|
19815
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
19621
19816
|
}
|
|
19622
19817
|
function enrichExportBackingRowsWaitMs() {
|
|
19623
19818
|
const raw = process.env.DEEPLINE_ENRICH_EXPORT_BACKING_ROWS_WAIT_MS?.trim();
|
|
@@ -25044,7 +25239,7 @@ Examples:
|
|
|
25044
25239
|
async function fetchOrganizations(http2, apiKey) {
|
|
25045
25240
|
return http2.post("/api/v2/auth/cli/organizations", { api_key: apiKey });
|
|
25046
25241
|
}
|
|
25047
|
-
function
|
|
25242
|
+
function normalizeAuthScope2(value) {
|
|
25048
25243
|
if (!value) return "auto";
|
|
25049
25244
|
if (value === "auto" || value === "folder" || value === "global") {
|
|
25050
25245
|
return value;
|
|
@@ -25247,7 +25442,7 @@ async function handleOrgStatus(options) {
|
|
|
25247
25442
|
);
|
|
25248
25443
|
}
|
|
25249
25444
|
async function handleOrgSwitch(selection, options) {
|
|
25250
|
-
const authScope =
|
|
25445
|
+
const authScope = normalizeAuthScope2(options.authScope);
|
|
25251
25446
|
const config = resolveConfig();
|
|
25252
25447
|
const http2 = new HttpClient(config);
|
|
25253
25448
|
const payload = await fetchOrganizations(http2, config.apiKey);
|
|
@@ -25624,17 +25819,17 @@ function hasClaudeBinary() {
|
|
|
25624
25819
|
}
|
|
25625
25820
|
}
|
|
25626
25821
|
function launchClaude(prompt) {
|
|
25627
|
-
return new Promise((
|
|
25822
|
+
return new Promise((resolve15) => {
|
|
25628
25823
|
const child = (0, import_node_child_process2.spawn)("claude", [prompt], {
|
|
25629
25824
|
stdio: "inherit",
|
|
25630
25825
|
shell: process.platform === "win32"
|
|
25631
25826
|
});
|
|
25632
|
-
child.on("error", () =>
|
|
25633
|
-
child.on("close", (status) =>
|
|
25827
|
+
child.on("error", () => resolve15(EXIT_SERVER3));
|
|
25828
|
+
child.on("close", (status) => resolve15(status ?? EXIT_OK2));
|
|
25634
25829
|
});
|
|
25635
25830
|
}
|
|
25636
25831
|
function readBody(req) {
|
|
25637
|
-
return new Promise((
|
|
25832
|
+
return new Promise((resolve15, reject) => {
|
|
25638
25833
|
let raw = "";
|
|
25639
25834
|
req.setEncoding("utf8");
|
|
25640
25835
|
req.on("data", (chunk) => {
|
|
@@ -25644,7 +25839,7 @@ function readBody(req) {
|
|
|
25644
25839
|
req.destroy();
|
|
25645
25840
|
}
|
|
25646
25841
|
});
|
|
25647
|
-
req.on("end", () =>
|
|
25842
|
+
req.on("end", () => resolve15(raw));
|
|
25648
25843
|
req.on("error", reject);
|
|
25649
25844
|
});
|
|
25650
25845
|
}
|
|
@@ -25699,7 +25894,7 @@ function startCallbackServer(input2) {
|
|
|
25699
25894
|
writeJson(res, 400, { error: "Invalid request body." });
|
|
25700
25895
|
});
|
|
25701
25896
|
});
|
|
25702
|
-
return new Promise((
|
|
25897
|
+
return new Promise((resolve15, reject) => {
|
|
25703
25898
|
server.once("error", reject);
|
|
25704
25899
|
server.listen(0, "127.0.0.1", () => {
|
|
25705
25900
|
const address = server.address();
|
|
@@ -25707,7 +25902,7 @@ function startCallbackServer(input2) {
|
|
|
25707
25902
|
reject(new Error("Failed to bind quickstart callback server."));
|
|
25708
25903
|
return;
|
|
25709
25904
|
}
|
|
25710
|
-
|
|
25905
|
+
resolve15({ server, port: address.port });
|
|
25711
25906
|
});
|
|
25712
25907
|
});
|
|
25713
25908
|
}
|
|
@@ -25733,8 +25928,8 @@ async function handleQuickstart(options) {
|
|
|
25733
25928
|
}
|
|
25734
25929
|
const state = (0, import_node_crypto6.randomBytes)(32).toString("hex");
|
|
25735
25930
|
let resolveSelection;
|
|
25736
|
-
const selectionPromise = new Promise((
|
|
25737
|
-
resolveSelection =
|
|
25931
|
+
const selectionPromise = new Promise((resolve15) => {
|
|
25932
|
+
resolveSelection = resolve15;
|
|
25738
25933
|
});
|
|
25739
25934
|
let callback;
|
|
25740
25935
|
try {
|
|
@@ -25873,7 +26068,7 @@ async function readHiddenLine(prompt, streams = {}) {
|
|
|
25873
26068
|
}
|
|
25874
26069
|
let value = "";
|
|
25875
26070
|
inputStream.resume();
|
|
25876
|
-
return await new Promise((
|
|
26071
|
+
return await new Promise((resolve15, reject) => {
|
|
25877
26072
|
let settled = false;
|
|
25878
26073
|
const cleanup = () => {
|
|
25879
26074
|
inputStream.off("data", onData);
|
|
@@ -25891,7 +26086,7 @@ async function readHiddenLine(prompt, streams = {}) {
|
|
|
25891
26086
|
settled = true;
|
|
25892
26087
|
outputStream.write("\n");
|
|
25893
26088
|
cleanup();
|
|
25894
|
-
|
|
26089
|
+
resolve15(line);
|
|
25895
26090
|
};
|
|
25896
26091
|
const fail = (error) => {
|
|
25897
26092
|
if (settled) return;
|
|
@@ -28694,12 +28889,13 @@ Notes:
|
|
|
28694
28889
|
// src/cli/commands/update.ts
|
|
28695
28890
|
var import_node_child_process4 = require("child_process");
|
|
28696
28891
|
var import_node_fs17 = require("fs");
|
|
28697
|
-
var
|
|
28892
|
+
var import_node_os14 = require("os");
|
|
28698
28893
|
var import_node_path19 = require("path");
|
|
28699
28894
|
|
|
28700
|
-
// src/cli/skills
|
|
28895
|
+
// src/cli/commands/skills.ts
|
|
28701
28896
|
var import_node_child_process3 = require("child_process");
|
|
28702
28897
|
var import_node_fs16 = require("fs");
|
|
28898
|
+
var import_node_os13 = require("os");
|
|
28703
28899
|
var import_node_path18 = require("path");
|
|
28704
28900
|
|
|
28705
28901
|
// ../shared_libs/cli/install-commands.json
|
|
@@ -28716,7 +28912,7 @@ var install_commands_default = {
|
|
|
28716
28912
|
npx_binary: "npx",
|
|
28717
28913
|
npx_add_args_template: [
|
|
28718
28914
|
"--yes",
|
|
28719
|
-
"skills",
|
|
28915
|
+
"skills@latest",
|
|
28720
28916
|
"add",
|
|
28721
28917
|
"{skills_index_url}",
|
|
28722
28918
|
"--agent",
|
|
@@ -28806,311 +29002,319 @@ function sdkNpmGlobalInstallCommand() {
|
|
|
28806
29002
|
return INSTALL_COMMANDS.cli.sdk_npm_global;
|
|
28807
29003
|
}
|
|
28808
29004
|
|
|
28809
|
-
// src/cli/skills
|
|
28810
|
-
var
|
|
28811
|
-
|
|
28812
|
-
|
|
28813
|
-
|
|
28814
|
-
|
|
28815
|
-
|
|
28816
|
-
|
|
28817
|
-
|
|
29005
|
+
// src/cli/commands/skills.ts
|
|
29006
|
+
var RUNTIME_TO_SKILLS_AGENT = {
|
|
29007
|
+
antigravity: "antigravity",
|
|
29008
|
+
claude_code: "claude-code",
|
|
29009
|
+
claude_cowork: "claude-code",
|
|
29010
|
+
cline: "cline",
|
|
29011
|
+
codex: "codex",
|
|
29012
|
+
cursor: "cursor",
|
|
29013
|
+
gemini: "gemini-cli",
|
|
29014
|
+
windsurf: "windsurf"
|
|
29015
|
+
};
|
|
29016
|
+
var AGENT_MARKERS = [
|
|
29017
|
+
{ agent: "codex", paths: [".codex"] },
|
|
29018
|
+
{ agent: "claude-code", paths: [".claude"] },
|
|
29019
|
+
{ agent: "cursor", paths: [".cursor"] },
|
|
29020
|
+
{ agent: "gemini-cli", paths: [".gemini", ".gemini-cli"] },
|
|
29021
|
+
{ agent: "antigravity", paths: [".antigravity"] }
|
|
29022
|
+
];
|
|
29023
|
+
var WORKSPACE_SKILL_ROOTS_BY_AGENT = {
|
|
29024
|
+
antigravity: [".agents"],
|
|
29025
|
+
"claude-code": [".claude"],
|
|
29026
|
+
cline: [".agents"],
|
|
29027
|
+
codex: [".agents"],
|
|
29028
|
+
cursor: [".agents"],
|
|
29029
|
+
"gemini-cli": [".agents"],
|
|
29030
|
+
windsurf: [".windsurf"],
|
|
29031
|
+
"*": [".agents", ".claude", ".windsurf"]
|
|
29032
|
+
};
|
|
29033
|
+
function workspaceSkillRootsForAgents(agents) {
|
|
29034
|
+
return [
|
|
29035
|
+
...new Set(
|
|
29036
|
+
agents.flatMap((agent) => WORKSPACE_SKILL_ROOTS_BY_AGENT[agent] ?? [])
|
|
29037
|
+
)
|
|
29038
|
+
].sort((a, b) => a.localeCompare(b));
|
|
28818
29039
|
}
|
|
28819
|
-
function
|
|
28820
|
-
|
|
28821
|
-
if (
|
|
28822
|
-
|
|
28823
|
-
|
|
28824
|
-
const dir = process.env.DEEPLINE_PLUGIN_SKILLS_DIR?.trim() ?? "";
|
|
28825
|
-
return dir && (0, import_node_fs16.existsSync)(dir) ? dir : "";
|
|
29040
|
+
function normalizeScope(value) {
|
|
29041
|
+
if (value === "global") return "global";
|
|
29042
|
+
if (value === "local") return "local";
|
|
29043
|
+
if (!value) return inferActiveSkillsScope();
|
|
29044
|
+
throw new Error("--scope must be one of: global, local");
|
|
28826
29045
|
}
|
|
28827
|
-
function
|
|
28828
|
-
|
|
28829
|
-
|
|
28830
|
-
|
|
28831
|
-
|
|
28832
|
-
|
|
28833
|
-
|
|
29046
|
+
function inferActiveSkillsScope(entrypoint = process.argv[1] ?? "") {
|
|
29047
|
+
return /[\\/]\.deepline[\\/]runtime[\\/]/.test(entrypoint) ? "local" : "global";
|
|
29048
|
+
}
|
|
29049
|
+
function resolveLocalRoot() {
|
|
29050
|
+
const target = resolveProjectPinTarget();
|
|
29051
|
+
if (!target.ok) {
|
|
29052
|
+
throw new Error(
|
|
29053
|
+
`Cowork project folder is ambiguous. Candidate folders: ${target.candidates.join(
|
|
29054
|
+
", "
|
|
29055
|
+
)}. Set CLAUDE_PROJECT_DIR or cd into the intended project folder.`
|
|
29056
|
+
);
|
|
28834
29057
|
}
|
|
29058
|
+
return target.dir;
|
|
28835
29059
|
}
|
|
28836
|
-
function
|
|
28837
|
-
|
|
29060
|
+
function detectSkillsAgents(input2) {
|
|
29061
|
+
const runtime = input2.runtime ?? detectAgentRuntime();
|
|
29062
|
+
const knownAgent = RUNTIME_TO_SKILLS_AGENT[runtime];
|
|
29063
|
+
if (knownAgent) return [knownAgent];
|
|
29064
|
+
const roots = [
|
|
29065
|
+
...input2.scope === "local" && input2.root ? [input2.root] : [],
|
|
29066
|
+
input2.homeDir ?? (0, import_node_os13.homedir)()
|
|
29067
|
+
];
|
|
29068
|
+
const detected = AGENT_MARKERS.filter(
|
|
29069
|
+
(marker) => roots.some(
|
|
29070
|
+
(root) => marker.paths.some((path) => (0, import_node_fs16.existsSync)((0, import_node_path18.join)(root, path)))
|
|
29071
|
+
)
|
|
29072
|
+
).map((marker) => marker.agent);
|
|
29073
|
+
return detected.length > 0 ? detected : ["*"];
|
|
28838
29074
|
}
|
|
28839
|
-
function
|
|
28840
|
-
|
|
29075
|
+
async function fetchSkillCatalog(baseUrl) {
|
|
29076
|
+
const response = await fetch(skillsIndexUrl(baseUrl));
|
|
29077
|
+
if (!response.ok) {
|
|
29078
|
+
throw new Error(
|
|
29079
|
+
`Skill catalog request failed (status ${response.status}).`
|
|
29080
|
+
);
|
|
29081
|
+
}
|
|
29082
|
+
const index = await response.json();
|
|
29083
|
+
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));
|
|
29084
|
+
if (skillNames.length === 0) {
|
|
29085
|
+
throw new Error(
|
|
29086
|
+
"The Deepline skill catalog contains no installable skills."
|
|
29087
|
+
);
|
|
29088
|
+
}
|
|
29089
|
+
return {
|
|
29090
|
+
skillNames,
|
|
29091
|
+
version: typeof index.version === "string" && index.version.trim() ? index.version.trim() : "unversioned"
|
|
29092
|
+
};
|
|
28841
29093
|
}
|
|
28842
|
-
function
|
|
28843
|
-
return (0, import_node_path18.join)(sdkCliStateDirPath(baseUrl), "skills-
|
|
29094
|
+
function skillsStatePathForScope(baseUrl, scope, root) {
|
|
29095
|
+
return scope === "local" && root ? (0, import_node_path18.join)(root, ".deepline", "setup", "skills.json") : (0, import_node_path18.join)(sdkCliStateDirPath(baseUrl), "skills-install.json");
|
|
28844
29096
|
}
|
|
28845
|
-
function
|
|
28846
|
-
const
|
|
28847
|
-
|
|
28848
|
-
|
|
28849
|
-
|
|
28850
|
-
|
|
28851
|
-
|
|
28852
|
-
|
|
28853
|
-
|
|
28854
|
-
|
|
29097
|
+
function buildSkillsPlan(input2) {
|
|
29098
|
+
const scopeArgs = input2.scope === "global" ? ["--global"] : [];
|
|
29099
|
+
const allManagedNames = [
|
|
29100
|
+
.../* @__PURE__ */ new Set([...input2.skillNames, ...LEGACY_SKILL_NAMES_TO_REMOVE])
|
|
29101
|
+
].sort((a, b) => a.localeCompare(b));
|
|
29102
|
+
return {
|
|
29103
|
+
scope: input2.scope,
|
|
29104
|
+
root: input2.root,
|
|
29105
|
+
agents: input2.agents,
|
|
29106
|
+
skillNames: input2.skillNames,
|
|
29107
|
+
version: input2.version,
|
|
29108
|
+
remove: {
|
|
29109
|
+
command: "npx",
|
|
29110
|
+
args: [
|
|
29111
|
+
"--yes",
|
|
29112
|
+
"skills@latest",
|
|
29113
|
+
"remove",
|
|
29114
|
+
...scopeArgs,
|
|
29115
|
+
"--agent",
|
|
29116
|
+
...input2.agents,
|
|
29117
|
+
"-y",
|
|
29118
|
+
...allManagedNames
|
|
29119
|
+
]
|
|
29120
|
+
},
|
|
29121
|
+
install: {
|
|
29122
|
+
command: "npx",
|
|
29123
|
+
args: [
|
|
29124
|
+
"--yes",
|
|
29125
|
+
"skills@latest",
|
|
29126
|
+
"add",
|
|
29127
|
+
skillsIndexUrl(input2.baseUrl),
|
|
29128
|
+
"--agent",
|
|
29129
|
+
...input2.agents,
|
|
29130
|
+
...scopeArgs,
|
|
29131
|
+
"--yes",
|
|
29132
|
+
...input2.skillNames.flatMap((name) => ["--skill", name]),
|
|
29133
|
+
"--full-depth"
|
|
29134
|
+
]
|
|
29135
|
+
},
|
|
29136
|
+
statePath: skillsStatePathForScope(input2.baseUrl, input2.scope, input2.root)
|
|
29137
|
+
};
|
|
28855
29138
|
}
|
|
28856
|
-
function
|
|
28857
|
-
|
|
28858
|
-
|
|
28859
|
-
|
|
28860
|
-
|
|
29139
|
+
function runProcess(command, args, cwd) {
|
|
29140
|
+
return new Promise((resolve15, reject) => {
|
|
29141
|
+
const child = (0, import_node_child_process3.spawn)(command, args, {
|
|
29142
|
+
cwd,
|
|
29143
|
+
env: process.env,
|
|
29144
|
+
stdio: ["ignore", "ignore", "pipe"],
|
|
29145
|
+
shell: process.platform === "win32"
|
|
29146
|
+
});
|
|
29147
|
+
let stderr = "";
|
|
29148
|
+
child.stderr.on("data", (chunk) => {
|
|
29149
|
+
stderr += chunk.toString("utf8");
|
|
29150
|
+
process.stderr.write(chunk);
|
|
29151
|
+
});
|
|
29152
|
+
child.once("error", reject);
|
|
29153
|
+
child.once("close", (code) => {
|
|
29154
|
+
if (code && stderr.trim()) {
|
|
29155
|
+
process.stderr.write(`skills@latest exited ${code}.
|
|
29156
|
+
`);
|
|
29157
|
+
}
|
|
29158
|
+
resolve15(code ?? 1);
|
|
29159
|
+
});
|
|
29160
|
+
});
|
|
28861
29161
|
}
|
|
28862
|
-
function
|
|
28863
|
-
|
|
29162
|
+
async function runSkillsCommand(options) {
|
|
29163
|
+
let scope;
|
|
29164
|
+
let root;
|
|
28864
29165
|
try {
|
|
28865
|
-
|
|
28866
|
-
|
|
28867
|
-
|
|
28868
|
-
(
|
|
28869
|
-
|
|
28870
|
-
|
|
28871
|
-
|
|
29166
|
+
scope = normalizeScope(options.scope);
|
|
29167
|
+
root = scope === "local" ? resolveLocalRoot() : null;
|
|
29168
|
+
} catch (error) {
|
|
29169
|
+
printCommandEnvelope(
|
|
29170
|
+
{
|
|
29171
|
+
ok: false,
|
|
29172
|
+
status: "failed",
|
|
29173
|
+
code: "INVALID_SKILLS_SCOPE",
|
|
29174
|
+
exitCode: 2,
|
|
29175
|
+
message: error instanceof Error ? error.message : String(error)
|
|
29176
|
+
},
|
|
29177
|
+
{ json: options.json }
|
|
29178
|
+
);
|
|
29179
|
+
return 2;
|
|
28872
29180
|
}
|
|
28873
|
-
const
|
|
28874
|
-
|
|
28875
|
-
`Deepline agent skills are out of date, but neither \`bunx\` nor \`npx\` is available. Install Node.js/npm or Bun, then run:
|
|
28876
|
-
${manualCommand}`
|
|
28877
|
-
);
|
|
28878
|
-
}
|
|
28879
|
-
function clearUnavailableSkillsNotice(baseUrl) {
|
|
29181
|
+
const baseUrl = autoDetectBaseUrl().replace(/\/$/, "");
|
|
29182
|
+
let catalog;
|
|
28880
29183
|
try {
|
|
28881
|
-
|
|
28882
|
-
} catch {
|
|
29184
|
+
catalog = options.dryRun ? { skillNames: [...DEFAULT_SDK_SKILL_NAMES], version: "latest" } : await fetchSkillCatalog(baseUrl);
|
|
29185
|
+
} catch (error) {
|
|
29186
|
+
printCommandEnvelope(
|
|
29187
|
+
{
|
|
29188
|
+
ok: false,
|
|
29189
|
+
status: "failed",
|
|
29190
|
+
code: "SKILLS_CATALOG_UNAVAILABLE",
|
|
29191
|
+
exitCode: 5,
|
|
29192
|
+
message: error instanceof Error ? error.message : String(error),
|
|
29193
|
+
next: "Retry: deepline skills"
|
|
29194
|
+
},
|
|
29195
|
+
{ json: options.json }
|
|
29196
|
+
);
|
|
29197
|
+
return 5;
|
|
28883
29198
|
}
|
|
28884
|
-
}
|
|
28885
|
-
|
|
28886
|
-
|
|
28887
|
-
(
|
|
29199
|
+
const agents = options.agent ? [options.agent] : detectSkillsAgents({ scope, root });
|
|
29200
|
+
const plan = buildSkillsPlan({ baseUrl, scope, root, agents, ...catalog });
|
|
29201
|
+
if (options.dryRun) {
|
|
29202
|
+
printCommandEnvelope(
|
|
29203
|
+
{ ok: true, status: "planned", dryRun: true, ...plan },
|
|
29204
|
+
{ json: options.json }
|
|
29205
|
+
);
|
|
29206
|
+
return 0;
|
|
29207
|
+
}
|
|
29208
|
+
if (scope === "local" && root) {
|
|
29209
|
+
const managedNames = [
|
|
29210
|
+
.../* @__PURE__ */ new Set([...plan.skillNames, ...LEGACY_SKILL_NAMES_TO_REMOVE])
|
|
29211
|
+
];
|
|
29212
|
+
const agentRoots = workspaceSkillRootsForAgents(plan.agents);
|
|
29213
|
+
ensureProjectPrivatePathsIgnored(root, [
|
|
29214
|
+
".deepline/",
|
|
29215
|
+
...agentRoots.flatMap(
|
|
29216
|
+
(agentRoot) => managedNames.map((name) => `${agentRoot}/skills/${name}/`)
|
|
29217
|
+
)
|
|
29218
|
+
]);
|
|
29219
|
+
}
|
|
29220
|
+
process.stderr.write(
|
|
29221
|
+
`Replacing Deepline skills for ${agents.join(", ")} (${scope})...
|
|
29222
|
+
`
|
|
28888
29223
|
);
|
|
28889
|
-
}
|
|
28890
|
-
async function fetchV1SkillNames(baseUrl) {
|
|
28891
|
-
const controller = new AbortController();
|
|
28892
|
-
const timeout = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS2);
|
|
28893
29224
|
try {
|
|
28894
|
-
const
|
|
28895
|
-
|
|
28896
|
-
|
|
29225
|
+
const removeCode = await runProcess(
|
|
29226
|
+
plan.remove.command,
|
|
29227
|
+
plan.remove.args,
|
|
29228
|
+
root ?? void 0
|
|
28897
29229
|
);
|
|
28898
|
-
if (
|
|
28899
|
-
|
|
28900
|
-
|
|
28901
|
-
|
|
29230
|
+
if (removeCode !== 0) {
|
|
29231
|
+
throw new Error("Could not remove the existing Deepline skills.");
|
|
29232
|
+
}
|
|
29233
|
+
const installCode = await runProcess(
|
|
29234
|
+
plan.install.command,
|
|
29235
|
+
plan.install.args,
|
|
29236
|
+
root ?? void 0
|
|
28902
29237
|
);
|
|
28903
|
-
|
|
28904
|
-
|
|
28905
|
-
|
|
28906
|
-
}
|
|
28907
|
-
|
|
28908
|
-
|
|
28909
|
-
}
|
|
28910
|
-
function buildSdkSkillNames(v1SkillNames) {
|
|
28911
|
-
return sortedUniqueSkillNames(v1SkillNames);
|
|
28912
|
-
}
|
|
28913
|
-
async function fetchSkillsUpdate(baseUrl, localVersion) {
|
|
28914
|
-
const controller = new AbortController();
|
|
28915
|
-
const timeout = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS2);
|
|
28916
|
-
try {
|
|
28917
|
-
const response = await fetch(new URL("/api/v2/cli/update-check", baseUrl), {
|
|
28918
|
-
method: "POST",
|
|
28919
|
-
headers: { "Content-Type": "application/json" },
|
|
28920
|
-
body: JSON.stringify({
|
|
28921
|
-
skills: {
|
|
28922
|
-
version: localVersion
|
|
28923
|
-
}
|
|
28924
|
-
}),
|
|
28925
|
-
signal: controller.signal
|
|
28926
|
-
});
|
|
28927
|
-
if (!response.ok) return null;
|
|
28928
|
-
const data = await response.json().catch(() => null);
|
|
28929
|
-
const skills = data?.skills;
|
|
28930
|
-
if (!skills) return null;
|
|
28931
|
-
return {
|
|
28932
|
-
needsUpdate: skills.needs_update === true,
|
|
28933
|
-
remoteVersion: typeof skills.remote?.version === "string" ? skills.remote.version.trim() : ""
|
|
28934
|
-
};
|
|
28935
|
-
} catch {
|
|
28936
|
-
return null;
|
|
28937
|
-
} finally {
|
|
28938
|
-
clearTimeout(timeout);
|
|
28939
|
-
}
|
|
28940
|
-
}
|
|
28941
|
-
function buildSkillsInstallArgs(baseUrl, skillNames = DEFAULT_SDK_SKILL_NAMES) {
|
|
28942
|
-
return buildSkillsAddArgs(baseUrl, sortedUniqueSkillNames(skillNames));
|
|
28943
|
-
}
|
|
28944
|
-
function buildBunxSkillsInstallArgs(baseUrl, skillNames) {
|
|
28945
|
-
return buildSkillsAddArgs(baseUrl, sortedUniqueSkillNames(skillNames), {
|
|
28946
|
-
firstArg: "--bun"
|
|
28947
|
-
});
|
|
28948
|
-
}
|
|
28949
|
-
function hasCommand(command) {
|
|
28950
|
-
const result = (0, import_node_child_process3.spawnSync)(command, ["--version"], {
|
|
28951
|
-
stdio: "ignore",
|
|
28952
|
-
shell: process.platform === "win32"
|
|
28953
|
-
});
|
|
28954
|
-
return result.status === 0;
|
|
28955
|
-
}
|
|
28956
|
-
function shellQuote5(arg) {
|
|
28957
|
-
return `'${arg.replace(/'/g, `'\\''`)}'`;
|
|
28958
|
-
}
|
|
28959
|
-
function resolveSkillsInstallCommands(baseUrl, skillNames = DEFAULT_SDK_SKILL_NAMES) {
|
|
28960
|
-
const commands = [];
|
|
28961
|
-
if (hasCommand("bunx")) {
|
|
28962
|
-
const bunxArgs = buildBunxSkillsInstallArgs(baseUrl, skillNames);
|
|
28963
|
-
commands.push({
|
|
28964
|
-
command: "bunx",
|
|
28965
|
-
args: bunxArgs,
|
|
28966
|
-
manualCommand: `bunx ${bunxArgs.map(shellQuote5).join(" ")}`
|
|
28967
|
-
});
|
|
28968
|
-
}
|
|
28969
|
-
if (hasCommand("npx")) {
|
|
28970
|
-
const npxArgs = buildSkillsInstallArgs(baseUrl, skillNames);
|
|
28971
|
-
commands.push({
|
|
28972
|
-
command: "npx",
|
|
28973
|
-
args: npxArgs,
|
|
28974
|
-
manualCommand: `npx ${npxArgs.map(shellQuote5).join(" ")}`
|
|
28975
|
-
});
|
|
28976
|
-
}
|
|
28977
|
-
return commands;
|
|
28978
|
-
}
|
|
28979
|
-
function runOneSkillsInstall(install) {
|
|
28980
|
-
return new Promise((resolve14) => {
|
|
28981
|
-
const child = (0, import_node_child_process3.spawn)(install.command, install.args, {
|
|
28982
|
-
stdio: ["ignore", "ignore", "pipe"],
|
|
28983
|
-
env: process.env
|
|
28984
|
-
});
|
|
28985
|
-
let stderr = "";
|
|
28986
|
-
child.stderr.on("data", (chunk) => {
|
|
28987
|
-
stderr += chunk.toString("utf-8");
|
|
28988
|
-
});
|
|
28989
|
-
child.on("error", (error) => {
|
|
28990
|
-
resolve14({
|
|
28991
|
-
ok: false,
|
|
28992
|
-
detail: `failed to start ${install.command}: ${error.message}`,
|
|
28993
|
-
manualCommand: install.manualCommand
|
|
28994
|
-
});
|
|
28995
|
-
});
|
|
28996
|
-
child.on("close", (code) => {
|
|
28997
|
-
if (code === 0) {
|
|
28998
|
-
resolve14({ ok: true, detail: "", manualCommand: install.manualCommand });
|
|
28999
|
-
return;
|
|
29000
|
-
}
|
|
29001
|
-
const detail = stderr.trim();
|
|
29002
|
-
resolve14({
|
|
29238
|
+
if (installCode !== 0) {
|
|
29239
|
+
throw new Error("Could not install the current Deepline skills.");
|
|
29240
|
+
}
|
|
29241
|
+
} catch (error) {
|
|
29242
|
+
printCommandEnvelope(
|
|
29243
|
+
{
|
|
29003
29244
|
ok: false,
|
|
29004
|
-
|
|
29005
|
-
|
|
29006
|
-
|
|
29007
|
-
|
|
29008
|
-
|
|
29009
|
-
|
|
29010
|
-
|
|
29011
|
-
|
|
29012
|
-
|
|
29013
|
-
|
|
29014
|
-
|
|
29015
|
-
failures.push(result);
|
|
29245
|
+
status: "failed",
|
|
29246
|
+
code: "SKILLS_INSTALL_FAILED",
|
|
29247
|
+
exitCode: 5,
|
|
29248
|
+
scope,
|
|
29249
|
+
agents,
|
|
29250
|
+
message: error instanceof Error ? error.message : String(error),
|
|
29251
|
+
next: `deepline skills --scope ${scope} --json`
|
|
29252
|
+
},
|
|
29253
|
+
{ json: options.json }
|
|
29254
|
+
);
|
|
29255
|
+
return 5;
|
|
29016
29256
|
}
|
|
29017
|
-
|
|
29018
|
-
|
|
29019
|
-
|
|
29020
|
-
|
|
29021
|
-
|
|
29022
|
-
|
|
29023
|
-
|
|
29257
|
+
(0, import_node_fs16.mkdirSync)((0, import_node_path18.dirname)(plan.statePath), { recursive: true });
|
|
29258
|
+
(0, import_node_fs16.writeFileSync)(
|
|
29259
|
+
plan.statePath,
|
|
29260
|
+
`${JSON.stringify(
|
|
29261
|
+
{
|
|
29262
|
+
schemaVersion: 1,
|
|
29263
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
29264
|
+
cliVersion: SDK_VERSION,
|
|
29265
|
+
scope,
|
|
29266
|
+
agents,
|
|
29267
|
+
skillsVersion: plan.version,
|
|
29268
|
+
skillNames: plan.skillNames
|
|
29269
|
+
},
|
|
29270
|
+
null,
|
|
29271
|
+
2
|
|
29272
|
+
)}
|
|
29273
|
+
`,
|
|
29274
|
+
"utf8"
|
|
29024
29275
|
);
|
|
29025
|
-
|
|
29026
|
-
}
|
|
29027
|
-
function runLegacySkillsCleanup() {
|
|
29028
|
-
const candidates = hasCommand("bunx") ? [
|
|
29276
|
+
printCommandEnvelope(
|
|
29029
29277
|
{
|
|
29030
|
-
|
|
29031
|
-
|
|
29032
|
-
|
|
29033
|
-
|
|
29034
|
-
|
|
29035
|
-
|
|
29036
|
-
|
|
29037
|
-
|
|
29038
|
-
|
|
29278
|
+
ok: true,
|
|
29279
|
+
status: "complete",
|
|
29280
|
+
scope,
|
|
29281
|
+
agents,
|
|
29282
|
+
skillsVersion: plan.version,
|
|
29283
|
+
skillCount: plan.skillNames.length,
|
|
29284
|
+
statePath: plan.statePath,
|
|
29285
|
+
render: {
|
|
29286
|
+
sections: [
|
|
29287
|
+
{
|
|
29288
|
+
title: "skills",
|
|
29289
|
+
lines: [
|
|
29290
|
+
`Scope: ${scope}`,
|
|
29291
|
+
`Agents: ${agents.join(", ")}`,
|
|
29292
|
+
`Installed: ${plan.skillNames.length}`
|
|
29293
|
+
]
|
|
29294
|
+
}
|
|
29295
|
+
]
|
|
29296
|
+
}
|
|
29039
29297
|
},
|
|
29040
|
-
{
|
|
29041
|
-
command: "npx",
|
|
29042
|
-
args: [
|
|
29043
|
-
"--yes",
|
|
29044
|
-
"skills",
|
|
29045
|
-
"remove",
|
|
29046
|
-
"--global",
|
|
29047
|
-
"-y",
|
|
29048
|
-
...LEGACY_SKILL_NAMES_TO_REMOVE
|
|
29049
|
-
]
|
|
29050
|
-
}
|
|
29051
|
-
] : [
|
|
29052
|
-
{
|
|
29053
|
-
command: "npx",
|
|
29054
|
-
args: [
|
|
29055
|
-
"--yes",
|
|
29056
|
-
"skills",
|
|
29057
|
-
"remove",
|
|
29058
|
-
"--global",
|
|
29059
|
-
"-y",
|
|
29060
|
-
...LEGACY_SKILL_NAMES_TO_REMOVE
|
|
29061
|
-
]
|
|
29062
|
-
}
|
|
29063
|
-
];
|
|
29064
|
-
for (const candidate of candidates) {
|
|
29065
|
-
const result = (0, import_node_child_process3.spawnSync)(candidate.command, candidate.args, {
|
|
29066
|
-
stdio: "ignore",
|
|
29067
|
-
env: process.env,
|
|
29068
|
-
shell: process.platform === "win32"
|
|
29069
|
-
});
|
|
29070
|
-
if (result.status === 0) return;
|
|
29071
|
-
}
|
|
29072
|
-
}
|
|
29073
|
-
function writeSdkSkillsStatusLine(line) {
|
|
29074
|
-
const progress = getActiveCliProgress();
|
|
29075
|
-
if (progress) {
|
|
29076
|
-
progress.writeLine(line);
|
|
29077
|
-
return;
|
|
29078
|
-
}
|
|
29079
|
-
process.stderr.write(`${line}
|
|
29080
|
-
`);
|
|
29081
|
-
}
|
|
29082
|
-
async function syncSdkSkillsIfNeeded(baseUrl, options = {}) {
|
|
29083
|
-
if (attemptedSync || shouldSkipSkillsSync()) return;
|
|
29084
|
-
attemptedSync = true;
|
|
29085
|
-
const usingPluginSkills = Boolean(activePluginSkillsDir());
|
|
29086
|
-
if (usingPluginSkills) {
|
|
29087
|
-
return;
|
|
29088
|
-
}
|
|
29089
|
-
const localVersion = readSdkSkillsLocalVersion(baseUrl);
|
|
29090
|
-
const update = options.update === void 0 ? await fetchSkillsUpdate(baseUrl, localVersion) : options.update ? {
|
|
29091
|
-
needsUpdate: options.update.needs_update,
|
|
29092
|
-
remoteVersion: options.update.remote.version
|
|
29093
|
-
} : null;
|
|
29094
|
-
if (!update?.needsUpdate || !update.remoteVersion) {
|
|
29095
|
-
return;
|
|
29096
|
-
}
|
|
29097
|
-
const remoteSkillNames = await fetchV1SkillNames(baseUrl);
|
|
29098
|
-
const skillNames = buildSdkSkillNames(
|
|
29099
|
-
remoteSkillNames.length > 0 ? remoteSkillNames : DEFAULT_SDK_SKILL_NAMES
|
|
29298
|
+
{ json: options.json }
|
|
29100
29299
|
);
|
|
29101
|
-
|
|
29102
|
-
|
|
29103
|
-
|
|
29104
|
-
|
|
29105
|
-
|
|
29106
|
-
|
|
29107
|
-
|
|
29108
|
-
|
|
29109
|
-
|
|
29110
|
-
|
|
29111
|
-
|
|
29112
|
-
|
|
29113
|
-
|
|
29300
|
+
return 0;
|
|
29301
|
+
}
|
|
29302
|
+
function registerSkillsCommand(program) {
|
|
29303
|
+
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(
|
|
29304
|
+
"after",
|
|
29305
|
+
`
|
|
29306
|
+
Notes:
|
|
29307
|
+
This command removes and reinstalls only Deepline-managed skill names using
|
|
29308
|
+
skills@latest. Local scope writes into the resolved persistent project.
|
|
29309
|
+
|
|
29310
|
+
Examples:
|
|
29311
|
+
deepline skills --json
|
|
29312
|
+
deepline skills --scope local --json
|
|
29313
|
+
deepline skills --agent codex --dry-run --json
|
|
29314
|
+
`
|
|
29315
|
+
).action(async (options) => {
|
|
29316
|
+
process.exitCode = await runSkillsCommand(options);
|
|
29317
|
+
});
|
|
29114
29318
|
}
|
|
29115
29319
|
|
|
29116
29320
|
// src/cli/commands/update.ts
|
|
@@ -29142,14 +29346,14 @@ function posixShellQuote(value) {
|
|
|
29142
29346
|
function windowsCmdQuote(value) {
|
|
29143
29347
|
return `"${value.replace(/"/g, '""')}"`;
|
|
29144
29348
|
}
|
|
29145
|
-
function
|
|
29349
|
+
function shellQuote5(value) {
|
|
29146
29350
|
if (process.platform === "win32") {
|
|
29147
29351
|
return /^[A-Za-z0-9_./:@%+=,-]+$/.test(value) ? value : windowsCmdQuote(value);
|
|
29148
29352
|
}
|
|
29149
29353
|
return posixShellQuote(value);
|
|
29150
29354
|
}
|
|
29151
29355
|
function buildSourceUpdateCommand(sourceRoot) {
|
|
29152
|
-
const quotedRoot =
|
|
29356
|
+
const quotedRoot = shellQuote5(sourceRoot);
|
|
29153
29357
|
const cdCommand = process.platform === "win32" ? `cd /d ${quotedRoot}` : `cd ${quotedRoot}`;
|
|
29154
29358
|
return `${cdCommand} && git fetch origin main --tags && git merge --ff-only origin/main`;
|
|
29155
29359
|
}
|
|
@@ -29161,7 +29365,7 @@ function buildSidecarProjectConfigCommand(versionDir, nodeBin) {
|
|
|
29161
29365
|
"fs.mkdirSync(dir,{recursive:true});",
|
|
29162
29366
|
`fs.writeFileSync(path.join(dir,'package.json'),${JSON.stringify(NPM_SDK_SIDECAR_PACKAGE_JSON)});`
|
|
29163
29367
|
].join("");
|
|
29164
|
-
return `${
|
|
29368
|
+
return `${shellQuote5(nodeBin)} -e ${shellQuote5(script)} ${shellQuote5(versionDir)}`;
|
|
29165
29369
|
}
|
|
29166
29370
|
function sidecarStateDir(input2) {
|
|
29167
29371
|
const scope = input2.env.DEEPLINE_CONFIG_SCOPE?.trim();
|
|
@@ -29224,7 +29428,7 @@ function resolvePythonSidecarUpdatePlan(options) {
|
|
|
29224
29428
|
const npmCommand = "npm";
|
|
29225
29429
|
const registryUrl = sidecarRegistryUrl(hostUrl);
|
|
29226
29430
|
const versionDir = (0, import_node_path19.join)(stateDir, "versions", "<version>");
|
|
29227
|
-
const manualCommand = `${buildSidecarProjectConfigCommand(versionDir, nodeBin)} && ${npmCommand} install --prefix ${
|
|
29431
|
+
const manualCommand = `${buildSidecarProjectConfigCommand(versionDir, nodeBin)} && ${npmCommand} install --prefix ${shellQuote5(versionDir)} --registry ${shellQuote5(registryUrl)} ${NPM_SDK_INSTALL_COMMON_FLAGS.map(shellQuote5).join(" ")} ${shellQuote5(packageSpec)}`;
|
|
29228
29432
|
return {
|
|
29229
29433
|
kind: "python-sidecar",
|
|
29230
29434
|
stateDir,
|
|
@@ -29272,7 +29476,7 @@ function inferNpmGlobalPrefixFromEntrypoint(entrypoint) {
|
|
|
29272
29476
|
}
|
|
29273
29477
|
function resolveUpdatePlan(options = {}) {
|
|
29274
29478
|
const env = options.env ?? process.env;
|
|
29275
|
-
const homeDir2 = options.homeDir ?? (0,
|
|
29479
|
+
const homeDir2 = options.homeDir ?? (0, import_node_os14.homedir)();
|
|
29276
29480
|
const entrypoint = options.entrypoint ?? (process.argv[1] ? (0, import_node_path19.resolve)(process.argv[1]) : "");
|
|
29277
29481
|
const sourceRoot = entrypoint ? findRepoBackedSdkRoot((0, import_node_path19.dirname)(entrypoint)) : null;
|
|
29278
29482
|
if (sourceRoot) {
|
|
@@ -29308,7 +29512,7 @@ function resolveUpdatePlan(options = {}) {
|
|
|
29308
29512
|
fallbackRegistryUrl: publicNpmFallbackRegistryUrl(
|
|
29309
29513
|
env.DEEPLINE_HOST_URL?.trim() || autoDetectBaseUrl()
|
|
29310
29514
|
),
|
|
29311
|
-
manualCommand: `${command} ${args.map(
|
|
29515
|
+
manualCommand: `${command} ${args.map(shellQuote5).join(" ")}`
|
|
29312
29516
|
};
|
|
29313
29517
|
}
|
|
29314
29518
|
var AUTO_UPDATE_FAILURE_FILE = ".auto-update-failure.json";
|
|
@@ -29318,7 +29522,7 @@ function autoUpdateFailurePath(plan) {
|
|
|
29318
29522
|
return (0, import_node_path19.join)(plan.stateDir, AUTO_UPDATE_FAILURE_FILE);
|
|
29319
29523
|
}
|
|
29320
29524
|
return (0, import_node_path19.join)(
|
|
29321
|
-
(0,
|
|
29525
|
+
(0, import_node_os14.homedir)(),
|
|
29322
29526
|
".local",
|
|
29323
29527
|
"deepline",
|
|
29324
29528
|
"sdk-cli",
|
|
@@ -29513,9 +29717,9 @@ function writeSidecarLauncher(input2) {
|
|
|
29513
29717
|
input2.path,
|
|
29514
29718
|
[
|
|
29515
29719
|
"#!/usr/bin/env sh",
|
|
29516
|
-
`export DEEPLINE_HOST_URL=${
|
|
29517
|
-
`export DEEPLINE_CONFIG_SCOPE=${
|
|
29518
|
-
`exec ${
|
|
29720
|
+
`export DEEPLINE_HOST_URL=${shellQuote5(input2.hostUrl)}`,
|
|
29721
|
+
`export DEEPLINE_CONFIG_SCOPE=${shellQuote5(input2.scope)}`,
|
|
29722
|
+
`exec ${shellQuote5(input2.nodeBin)} ${shellQuote5(input2.entryPath)} "$@"`,
|
|
29519
29723
|
""
|
|
29520
29724
|
].join("\n"),
|
|
29521
29725
|
{ encoding: "utf8", mode: 493 }
|
|
@@ -29645,7 +29849,20 @@ async function runUpdateCommand(options, dependencies = {}) {
|
|
|
29645
29849
|
const detectBaseUrl = dependencies.detectBaseUrl ?? autoDetectBaseUrl;
|
|
29646
29850
|
const resolvePlan = dependencies.resolvePlan ?? resolveUpdatePlan;
|
|
29647
29851
|
const runPlan = dependencies.runPlan ?? runUpdatePlan;
|
|
29648
|
-
const syncSkills = dependencies.syncSkillsIfNeeded ??
|
|
29852
|
+
const syncSkills = dependencies.syncSkillsIfNeeded ?? (async () => {
|
|
29853
|
+
const originalWrite = process.stdout.write.bind(process.stdout);
|
|
29854
|
+
process.stdout.write = (() => true);
|
|
29855
|
+
try {
|
|
29856
|
+
const exitCode = await runSkillsCommand({ json: true });
|
|
29857
|
+
if (exitCode !== 0) {
|
|
29858
|
+
throw new Error(
|
|
29859
|
+
`Deepline skills update failed with exit ${exitCode}.`
|
|
29860
|
+
);
|
|
29861
|
+
}
|
|
29862
|
+
} finally {
|
|
29863
|
+
process.stdout.write = originalWrite;
|
|
29864
|
+
}
|
|
29865
|
+
});
|
|
29649
29866
|
const stderr = dependencies.stderr ?? process.stderr;
|
|
29650
29867
|
const plan = resolvePlan();
|
|
29651
29868
|
const render = {
|
|
@@ -29713,27 +29930,644 @@ Examples:
|
|
|
29713
29930
|
});
|
|
29714
29931
|
}
|
|
29715
29932
|
|
|
29716
|
-
//
|
|
29717
|
-
var
|
|
29718
|
-
|
|
29719
|
-
|
|
29720
|
-
|
|
29721
|
-
|
|
29722
|
-
|
|
29723
|
-
|
|
29724
|
-
|
|
29725
|
-
|
|
29726
|
-
|
|
29727
|
-
|
|
29728
|
-
|
|
29729
|
-
|
|
29730
|
-
|
|
29731
|
-
|
|
29732
|
-
|
|
29733
|
-
|
|
29734
|
-
|
|
29735
|
-
|
|
29736
|
-
|
|
29933
|
+
// src/cli/commands/setup.ts
|
|
29934
|
+
var import_node_child_process5 = require("child_process");
|
|
29935
|
+
var import_node_fs18 = require("fs");
|
|
29936
|
+
var import_node_os15 = require("os");
|
|
29937
|
+
var import_node_path20 = require("path");
|
|
29938
|
+
function normalizeScope2(value) {
|
|
29939
|
+
if (!value || value === "global") return "global";
|
|
29940
|
+
if (value === "local") return "local";
|
|
29941
|
+
throw new Error("--scope must be one of: global, local");
|
|
29942
|
+
}
|
|
29943
|
+
function resolveScopeRoot(scope) {
|
|
29944
|
+
if (scope === "global") return null;
|
|
29945
|
+
const target = resolveProjectPinTarget();
|
|
29946
|
+
if (!target.ok) {
|
|
29947
|
+
throw new Error(
|
|
29948
|
+
`Cowork project folder is ambiguous. Candidate folders: ${target.candidates.join(
|
|
29949
|
+
", "
|
|
29950
|
+
)}. Set CLAUDE_PROJECT_DIR or cd into the intended project folder.`
|
|
29951
|
+
);
|
|
29952
|
+
}
|
|
29953
|
+
return target.dir;
|
|
29954
|
+
}
|
|
29955
|
+
function authScopeForSetup(scope) {
|
|
29956
|
+
return scope === "local" ? "folder" : "global";
|
|
29957
|
+
}
|
|
29958
|
+
function setupStatePath(baseUrl, scope, root) {
|
|
29959
|
+
return scope === "local" && root ? (0, import_node_path20.join)(root, ".deepline", "setup", "state.json") : (0, import_node_path20.join)(sdkCliStateDirPath(baseUrl), "setup.json");
|
|
29960
|
+
}
|
|
29961
|
+
async function captureStdout2(run) {
|
|
29962
|
+
let stdout = "";
|
|
29963
|
+
const originalWrite = process.stdout.write.bind(process.stdout);
|
|
29964
|
+
process.stdout.write = ((chunk) => {
|
|
29965
|
+
stdout += typeof chunk === "string" ? chunk : String(chunk);
|
|
29966
|
+
return true;
|
|
29967
|
+
});
|
|
29968
|
+
try {
|
|
29969
|
+
return { exitCode: await run(), stdout, error: null };
|
|
29970
|
+
} catch (error) {
|
|
29971
|
+
return { exitCode: 4, stdout, error };
|
|
29972
|
+
} finally {
|
|
29973
|
+
process.stdout.write = originalWrite;
|
|
29974
|
+
}
|
|
29975
|
+
}
|
|
29976
|
+
function parseCapturedJson(stdout) {
|
|
29977
|
+
try {
|
|
29978
|
+
return JSON.parse(stdout.trim());
|
|
29979
|
+
} catch {
|
|
29980
|
+
return null;
|
|
29981
|
+
}
|
|
29982
|
+
}
|
|
29983
|
+
function asRecord2(value) {
|
|
29984
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
29985
|
+
}
|
|
29986
|
+
function printCapturedAuthorizationUrl(stdout) {
|
|
29987
|
+
const urls = stdout.match(/https:\/\/[^\s]+/g) ?? [];
|
|
29988
|
+
for (const url of new Set(
|
|
29989
|
+
urls.map((value) => value.replace(/[).,]+$/, ""))
|
|
29990
|
+
)) {
|
|
29991
|
+
process.stderr.write(`Authorize Deepline: ${url}
|
|
29992
|
+
`);
|
|
29993
|
+
}
|
|
29994
|
+
}
|
|
29995
|
+
function safeRead(path) {
|
|
29996
|
+
try {
|
|
29997
|
+
return (0, import_node_fs18.readFileSync)(path, "utf8");
|
|
29998
|
+
} catch {
|
|
29999
|
+
return "";
|
|
30000
|
+
}
|
|
30001
|
+
}
|
|
30002
|
+
function isNpmManagedDeeplinePath(path) {
|
|
30003
|
+
try {
|
|
30004
|
+
return (0, import_node_fs18.realpathSync)(path).includes(`${(0, import_node_path20.join)("node_modules", "deepline")}`);
|
|
30005
|
+
} catch {
|
|
30006
|
+
return false;
|
|
30007
|
+
}
|
|
30008
|
+
}
|
|
30009
|
+
function removeKnownLegacyPaths(baseUrl) {
|
|
30010
|
+
const home = (0, import_node_os15.homedir)();
|
|
30011
|
+
const hostDir = (0, import_node_path20.join)(home, ".local", "deepline", baseUrlSlug(baseUrl));
|
|
30012
|
+
const installerCommandPath = safeRead(
|
|
30013
|
+
(0, import_node_path20.join)(hostDir, "sdk", ".command-path")
|
|
30014
|
+
).trim();
|
|
30015
|
+
const candidates = [
|
|
30016
|
+
(0, import_node_path20.join)(home, ".local", "bin", "deepline-real"),
|
|
30017
|
+
(0, import_node_path20.join)(hostDir, "bin", "deepline"),
|
|
30018
|
+
(0, import_node_path20.join)(hostDir, "bin", "deepline-real"),
|
|
30019
|
+
(0, import_node_path20.join)(hostDir, "cli", ".install-method"),
|
|
30020
|
+
(0, import_node_path20.join)(hostDir, "cli", ".version"),
|
|
30021
|
+
(0, import_node_path20.join)(hostDir, "sdk", ".install-method"),
|
|
30022
|
+
(0, import_node_path20.join)(hostDir, "sdk", ".command-path"),
|
|
30023
|
+
...installerCommandPath ? [
|
|
30024
|
+
installerCommandPath,
|
|
30025
|
+
(0, import_node_path20.join)((0, import_node_path20.dirname)(installerCommandPath), "deepline-sdk")
|
|
30026
|
+
] : []
|
|
30027
|
+
];
|
|
30028
|
+
const removed = [];
|
|
30029
|
+
for (const path of candidates) {
|
|
30030
|
+
if (!(0, import_node_fs18.existsSync)(path)) continue;
|
|
30031
|
+
if (path === installerCommandPath && isNpmManagedDeeplinePath(path)) {
|
|
30032
|
+
continue;
|
|
30033
|
+
}
|
|
30034
|
+
(0, import_node_fs18.rmSync)(path, { force: true });
|
|
30035
|
+
removed.push(path);
|
|
30036
|
+
}
|
|
30037
|
+
return removed;
|
|
30038
|
+
}
|
|
30039
|
+
function resolvePathCommands(command) {
|
|
30040
|
+
const lookup = (0, import_node_child_process5.spawnSync)(
|
|
30041
|
+
process.platform === "win32" ? "where" : "which",
|
|
30042
|
+
process.platform === "win32" ? [command] : ["-a", command],
|
|
30043
|
+
{ encoding: "utf8", shell: process.platform === "win32" }
|
|
30044
|
+
);
|
|
30045
|
+
return [
|
|
30046
|
+
...new Set(
|
|
30047
|
+
String(lookup.stdout ?? "").split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((path) => (0, import_node_path20.resolve)(path))
|
|
30048
|
+
)
|
|
30049
|
+
];
|
|
30050
|
+
}
|
|
30051
|
+
function resolvePathCommand(command) {
|
|
30052
|
+
return resolvePathCommands(command)[0] ?? null;
|
|
30053
|
+
}
|
|
30054
|
+
function resolvePersistentGlobalCommand() {
|
|
30055
|
+
const prefix = (0, import_node_child_process5.spawnSync)("npm", ["prefix", "-g"], { encoding: "utf8" });
|
|
30056
|
+
if (prefix.status !== 0) return null;
|
|
30057
|
+
const root = String(prefix.stdout ?? "").trim();
|
|
30058
|
+
if (!root) return null;
|
|
30059
|
+
const candidates = process.platform === "win32" ? [(0, import_node_path20.join)(root, "deepline.cmd"), (0, import_node_path20.join)(root, "deepline")] : [(0, import_node_path20.join)(root, "bin", "deepline")];
|
|
30060
|
+
return candidates.find((candidate) => (0, import_node_fs18.existsSync)(candidate)) ?? null;
|
|
30061
|
+
}
|
|
30062
|
+
function inspectGlobalCliAvailability(input2) {
|
|
30063
|
+
const persistentPath = input2 && "persistentGlobalCli" in input2 ? input2.persistentGlobalCli ?? null : resolvePersistentGlobalCommand();
|
|
30064
|
+
const pathClis = input2?.pathClis ?? resolvePathCommands("deepline");
|
|
30065
|
+
const path = persistentPath ? pathClis.find(
|
|
30066
|
+
(candidate) => pathsResolveToSameFile(candidate, persistentPath)
|
|
30067
|
+
) ?? null : null;
|
|
30068
|
+
return { ok: Boolean(path), persistentPath, path };
|
|
30069
|
+
}
|
|
30070
|
+
function pathsResolveToSameFile(left, right) {
|
|
30071
|
+
try {
|
|
30072
|
+
return (0, import_node_fs18.realpathSync)(left) === (0, import_node_fs18.realpathSync)(right);
|
|
30073
|
+
} catch {
|
|
30074
|
+
return (0, import_node_path20.resolve)(left) === (0, import_node_path20.resolve)(right);
|
|
30075
|
+
}
|
|
30076
|
+
}
|
|
30077
|
+
function isKnownDeeplineCommand(path) {
|
|
30078
|
+
const entrypoint = process.argv[1] ? (0, import_node_path20.resolve)(process.argv[1]) : "";
|
|
30079
|
+
let resolvedPath = path;
|
|
30080
|
+
try {
|
|
30081
|
+
resolvedPath = (0, import_node_fs18.realpathSync)(path);
|
|
30082
|
+
} catch {
|
|
30083
|
+
}
|
|
30084
|
+
if (entrypoint && resolvedPath === entrypoint) return true;
|
|
30085
|
+
if (resolvedPath.includes(`${(0, import_node_path20.join)("node_modules", "deepline")}`)) return true;
|
|
30086
|
+
const content = safeRead(path);
|
|
30087
|
+
return content.includes("node_modules/deepline") || content.includes("node_modules\\deepline") || content.includes("DEEPLINE_CONFIG_SCOPE") || content.includes("deepline-real");
|
|
30088
|
+
}
|
|
30089
|
+
function inspectPathConflict() {
|
|
30090
|
+
const commandPath = resolvePathCommand("deepline");
|
|
30091
|
+
if (!commandPath || isKnownDeeplineCommand(commandPath)) return null;
|
|
30092
|
+
try {
|
|
30093
|
+
if ((0, import_node_fs18.lstatSync)(commandPath).isSymbolicLink()) {
|
|
30094
|
+
const target = (0, import_node_fs18.realpathSync)(commandPath);
|
|
30095
|
+
if (target.includes(`${(0, import_node_path20.join)("node_modules", "deepline")}`)) return null;
|
|
30096
|
+
}
|
|
30097
|
+
} catch {
|
|
30098
|
+
}
|
|
30099
|
+
return commandPath;
|
|
30100
|
+
}
|
|
30101
|
+
function writeSetupState(input2) {
|
|
30102
|
+
const path = setupStatePath(input2.baseUrl, input2.scope, input2.root);
|
|
30103
|
+
(0, import_node_fs18.mkdirSync)((0, import_node_path20.dirname)(path), { recursive: true });
|
|
30104
|
+
(0, import_node_fs18.writeFileSync)(
|
|
30105
|
+
path,
|
|
30106
|
+
`${JSON.stringify(
|
|
30107
|
+
{
|
|
30108
|
+
schemaVersion: 1,
|
|
30109
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
30110
|
+
cliVersion: SDK_VERSION,
|
|
30111
|
+
host: input2.baseUrl,
|
|
30112
|
+
scope: input2.scope,
|
|
30113
|
+
root: input2.root,
|
|
30114
|
+
status: input2.status
|
|
30115
|
+
},
|
|
30116
|
+
null,
|
|
30117
|
+
2
|
|
30118
|
+
)}
|
|
30119
|
+
`,
|
|
30120
|
+
"utf8"
|
|
30121
|
+
);
|
|
30122
|
+
return path;
|
|
30123
|
+
}
|
|
30124
|
+
function rollbackCommand(scope, root) {
|
|
30125
|
+
const prefix = scope === "local" && root ? ` --prefix ${JSON.stringify((0, import_node_path20.join)(root, ".deepline", "runtime"))}` : "";
|
|
30126
|
+
return `npm install -g${prefix} --no-audit --no-fund --include=optional --allow-scripts=esbuild deepline@${SDK_VERSION}`;
|
|
30127
|
+
}
|
|
30128
|
+
function setupQuickstartCommand(baseUrl) {
|
|
30129
|
+
return baseUrl === "https://code.deepline.com" ? "deepline quickstart" : `DEEPLINE_HOST_URL=${JSON.stringify(baseUrl)} deepline quickstart`;
|
|
30130
|
+
}
|
|
30131
|
+
function setupResumeCommand(baseUrl, scope) {
|
|
30132
|
+
const hostPrefix = baseUrl === "https://code.deepline.com" ? "" : `DEEPLINE_HOST_URL=${JSON.stringify(baseUrl)} `;
|
|
30133
|
+
return `${hostPrefix}deepline setup --scope ${scope} --json`;
|
|
30134
|
+
}
|
|
30135
|
+
async function readAuthStatus(authScope) {
|
|
30136
|
+
try {
|
|
30137
|
+
const captured = await captureStdout2(
|
|
30138
|
+
() => handleStatus([
|
|
30139
|
+
"--json",
|
|
30140
|
+
...authScope ? ["--auth-scope", authScope] : []
|
|
30141
|
+
])
|
|
30142
|
+
);
|
|
30143
|
+
return {
|
|
30144
|
+
exitCode: captured.exitCode,
|
|
30145
|
+
payload: parseCapturedJson(captured.stdout),
|
|
30146
|
+
error: captured.error
|
|
30147
|
+
};
|
|
30148
|
+
} catch (error) {
|
|
30149
|
+
return { exitCode: 4, payload: null, error };
|
|
30150
|
+
}
|
|
30151
|
+
}
|
|
30152
|
+
function reportSetupAuthStatusFailure(input2) {
|
|
30153
|
+
if (!input2.auth.error) return null;
|
|
30154
|
+
printCommandEnvelope(
|
|
30155
|
+
{
|
|
30156
|
+
ok: false,
|
|
30157
|
+
status: "failed",
|
|
30158
|
+
code: "AUTH_STATUS_FAILED",
|
|
30159
|
+
exitCode: 4,
|
|
30160
|
+
scope: input2.scope,
|
|
30161
|
+
message: "Deepline could not verify authorization with the configured host.",
|
|
30162
|
+
next: `Check network access, then rerun: deepline setup --scope ${input2.scope} --json`,
|
|
30163
|
+
authScope: input2.authScope
|
|
30164
|
+
},
|
|
30165
|
+
{ json: input2.json }
|
|
30166
|
+
);
|
|
30167
|
+
return 4;
|
|
30168
|
+
}
|
|
30169
|
+
async function runDoctorCommand(options) {
|
|
30170
|
+
let scope;
|
|
30171
|
+
let root;
|
|
30172
|
+
try {
|
|
30173
|
+
scope = normalizeScope2(options.scope);
|
|
30174
|
+
root = resolveScopeRoot(scope);
|
|
30175
|
+
} catch (error) {
|
|
30176
|
+
printCommandEnvelope(
|
|
30177
|
+
{
|
|
30178
|
+
ok: false,
|
|
30179
|
+
status: "failed",
|
|
30180
|
+
code: "INVALID_SETUP_SCOPE",
|
|
30181
|
+
exitCode: 2,
|
|
30182
|
+
message: error instanceof Error ? error.message : String(error)
|
|
30183
|
+
},
|
|
30184
|
+
{ json: options.json }
|
|
30185
|
+
);
|
|
30186
|
+
return 2;
|
|
30187
|
+
}
|
|
30188
|
+
const baseUrl = autoDetectBaseUrl().replace(/\/$/, "");
|
|
30189
|
+
const skillsStatePath = skillsStatePathForScope(baseUrl, scope, root);
|
|
30190
|
+
const skillsState = parseCapturedJson(safeRead(skillsStatePath));
|
|
30191
|
+
const authScope = authScopeForSetup(scope);
|
|
30192
|
+
const apiKey = scope === "local" ? resolveProjectApiKeyForBaseUrl(baseUrl) : resolveGlobalApiKeyForBaseUrl(baseUrl);
|
|
30193
|
+
const projectAuth = scope === "local" && apiKey ? getResolvedProjectAuthSource(baseUrl, apiKey) : null;
|
|
30194
|
+
const authStatus = await readAuthStatus(authScope);
|
|
30195
|
+
const connected = authStatus.payload?.connected === true;
|
|
30196
|
+
const authScopeOk = scope === "local" ? Boolean(projectAuth) : Boolean(apiKey && !projectAuth);
|
|
30197
|
+
const skillsOk = skillsState?.scope === scope && Array.isArray(skillsState.agents) && skillsState.agents.length > 0;
|
|
30198
|
+
const runningCliPath = process.argv[1] ? (0, import_node_path20.resolve)(process.argv[1]) : null;
|
|
30199
|
+
const globalCli = scope === "global" ? inspectGlobalCliAvailability() : null;
|
|
30200
|
+
const pathGlobalCli = globalCli?.path ?? null;
|
|
30201
|
+
const cliPath = scope === "global" ? pathGlobalCli : runningCliPath;
|
|
30202
|
+
const cliScopeOk = scope === "global" ? Boolean(pathGlobalCli) : Boolean(
|
|
30203
|
+
root && runningCliPath?.includes((0, import_node_path20.join)(root, ".deepline", "runtime"))
|
|
30204
|
+
);
|
|
30205
|
+
const checks = {
|
|
30206
|
+
cli: {
|
|
30207
|
+
ok: Boolean(cliPath) && cliScopeOk,
|
|
30208
|
+
version: SDK_VERSION,
|
|
30209
|
+
path: cliPath,
|
|
30210
|
+
scope
|
|
30211
|
+
},
|
|
30212
|
+
skills: {
|
|
30213
|
+
ok: skillsOk,
|
|
30214
|
+
statePath: skillsStatePath,
|
|
30215
|
+
version: skillsState?.skillsVersion ?? null,
|
|
30216
|
+
agents: skillsState?.agents ?? []
|
|
30217
|
+
},
|
|
30218
|
+
auth: {
|
|
30219
|
+
ok: connected && authScopeOk,
|
|
30220
|
+
scope: projectAuth ? "local" : apiKey ? "global" : null,
|
|
30221
|
+
status: authStatus.payload?.status ?? "not_connected"
|
|
30222
|
+
},
|
|
30223
|
+
api: {
|
|
30224
|
+
ok: connected && authStatus.exitCode === 0,
|
|
30225
|
+
host: baseUrl,
|
|
30226
|
+
workspace: authStatus.payload?.workspace ?? null,
|
|
30227
|
+
providerSpend: false
|
|
30228
|
+
}
|
|
30229
|
+
};
|
|
30230
|
+
const ok = Object.values(checks).every((check) => check.ok);
|
|
30231
|
+
const quickstart = setupQuickstartCommand(baseUrl);
|
|
30232
|
+
printCommandEnvelope(
|
|
30233
|
+
{
|
|
30234
|
+
ok,
|
|
30235
|
+
status: ok ? "complete" : "failed",
|
|
30236
|
+
code: ok ? "DOCTOR_OK" : "DOCTOR_FAILED",
|
|
30237
|
+
exitCode: ok ? 0 : 7,
|
|
30238
|
+
checks,
|
|
30239
|
+
next: ok ? quickstart : "Review failed checks, then rerun: deepline doctor --json",
|
|
30240
|
+
render: {
|
|
30241
|
+
sections: [
|
|
30242
|
+
{
|
|
30243
|
+
title: "doctor",
|
|
30244
|
+
lines: Object.entries(checks).map(
|
|
30245
|
+
([name, check]) => `${check.ok ? "pass" : "fail"} ${name}`
|
|
30246
|
+
)
|
|
30247
|
+
}
|
|
30248
|
+
]
|
|
30249
|
+
}
|
|
30250
|
+
},
|
|
30251
|
+
{ json: options.json }
|
|
30252
|
+
);
|
|
30253
|
+
return ok ? 0 : 7;
|
|
30254
|
+
}
|
|
30255
|
+
function pendingResult(input2) {
|
|
30256
|
+
const statePath = writeSetupState({
|
|
30257
|
+
baseUrl: input2.baseUrl,
|
|
30258
|
+
scope: input2.scope,
|
|
30259
|
+
root: input2.root,
|
|
30260
|
+
status: "authorization_pending"
|
|
30261
|
+
});
|
|
30262
|
+
if (input2.authorizationUrl) {
|
|
30263
|
+
process.stderr.write(`Authorize Deepline: ${input2.authorizationUrl}
|
|
30264
|
+
`);
|
|
30265
|
+
}
|
|
30266
|
+
printCommandEnvelope(
|
|
30267
|
+
{
|
|
30268
|
+
ok: true,
|
|
30269
|
+
status: "authorization_pending",
|
|
30270
|
+
complete: false,
|
|
30271
|
+
scope: input2.scope,
|
|
30272
|
+
authorizationUrl: input2.authorizationUrl || null,
|
|
30273
|
+
statePath,
|
|
30274
|
+
next: `Approve the link, then run: ${setupResumeCommand(input2.baseUrl, input2.scope)}`,
|
|
30275
|
+
render: {
|
|
30276
|
+
sections: [
|
|
30277
|
+
{
|
|
30278
|
+
title: "setup",
|
|
30279
|
+
lines: [
|
|
30280
|
+
"Authorization is waiting for browser approval.",
|
|
30281
|
+
...input2.authorizationUrl ? [input2.authorizationUrl] : []
|
|
30282
|
+
]
|
|
30283
|
+
}
|
|
30284
|
+
]
|
|
30285
|
+
}
|
|
30286
|
+
},
|
|
30287
|
+
{ json: input2.json }
|
|
30288
|
+
);
|
|
30289
|
+
return 0;
|
|
30290
|
+
}
|
|
30291
|
+
async function runSetupCommand(options) {
|
|
30292
|
+
let scope;
|
|
30293
|
+
let root;
|
|
30294
|
+
try {
|
|
30295
|
+
scope = normalizeScope2(options.scope);
|
|
30296
|
+
root = resolveScopeRoot(scope);
|
|
30297
|
+
} catch (error) {
|
|
30298
|
+
printCommandEnvelope(
|
|
30299
|
+
{
|
|
30300
|
+
ok: false,
|
|
30301
|
+
status: "failed",
|
|
30302
|
+
code: "INVALID_SETUP_SCOPE",
|
|
30303
|
+
exitCode: 2,
|
|
30304
|
+
message: error instanceof Error ? error.message : String(error)
|
|
30305
|
+
},
|
|
30306
|
+
{ json: options.json }
|
|
30307
|
+
);
|
|
30308
|
+
return 2;
|
|
30309
|
+
}
|
|
30310
|
+
const baseUrl = autoDetectBaseUrl().replace(/\/$/, "");
|
|
30311
|
+
if (scope === "global") {
|
|
30312
|
+
const globalCli = inspectGlobalCliAvailability();
|
|
30313
|
+
if (!globalCli.ok) {
|
|
30314
|
+
const installedButUnreachable = Boolean(globalCli.persistentPath);
|
|
30315
|
+
printCommandEnvelope(
|
|
30316
|
+
{
|
|
30317
|
+
ok: false,
|
|
30318
|
+
status: "failed",
|
|
30319
|
+
code: installedButUnreachable ? "GLOBAL_CLI_NOT_ON_PATH" : "GLOBAL_CLI_NOT_INSTALLED",
|
|
30320
|
+
exitCode: 7,
|
|
30321
|
+
scope,
|
|
30322
|
+
persistentPath: globalCli.persistentPath,
|
|
30323
|
+
message: installedButUnreachable ? `The global Deepline executable is not reachable on PATH: ${globalCli.persistentPath}` : "No persistent global Deepline executable was found.",
|
|
30324
|
+
next: "Use the automatic project-local fallback in https://code.deepline.com/SKILL.md"
|
|
30325
|
+
},
|
|
30326
|
+
{ json: options.json }
|
|
30327
|
+
);
|
|
30328
|
+
return 7;
|
|
30329
|
+
}
|
|
30330
|
+
}
|
|
30331
|
+
const conflict = inspectPathConflict();
|
|
30332
|
+
if (conflict) {
|
|
30333
|
+
printCommandEnvelope(
|
|
30334
|
+
{
|
|
30335
|
+
ok: false,
|
|
30336
|
+
status: "failed",
|
|
30337
|
+
code: "PATH_CONFLICT",
|
|
30338
|
+
exitCode: 7,
|
|
30339
|
+
path: conflict,
|
|
30340
|
+
message: `An unknown executable named deepline is first on PATH: ${conflict}`,
|
|
30341
|
+
next: "Move or rename that executable, then rerun: deepline setup --json"
|
|
30342
|
+
},
|
|
30343
|
+
{ json: options.json }
|
|
30344
|
+
);
|
|
30345
|
+
return 7;
|
|
30346
|
+
}
|
|
30347
|
+
const removedLegacyPaths = removeKnownLegacyPaths(baseUrl);
|
|
30348
|
+
if (removedLegacyPaths.length > 0) {
|
|
30349
|
+
process.stderr.write(
|
|
30350
|
+
`Removed ${removedLegacyPaths.length} known legacy Deepline path(s).
|
|
30351
|
+
`
|
|
30352
|
+
);
|
|
30353
|
+
}
|
|
30354
|
+
process.stderr.write(`Installing Deepline skills (${scope})...
|
|
30355
|
+
`);
|
|
30356
|
+
const skills = await captureStdout2(
|
|
30357
|
+
() => runSkillsCommand({ scope, json: true })
|
|
30358
|
+
);
|
|
30359
|
+
const skillsPayload = parseCapturedJson(skills.stdout);
|
|
30360
|
+
if (skills.exitCode !== 0) {
|
|
30361
|
+
printCommandEnvelope(
|
|
30362
|
+
{
|
|
30363
|
+
ok: false,
|
|
30364
|
+
status: "failed",
|
|
30365
|
+
code: "SKILLS_INSTALL_FAILED",
|
|
30366
|
+
exitCode: skills.exitCode,
|
|
30367
|
+
scope,
|
|
30368
|
+
detail: skillsPayload,
|
|
30369
|
+
next: `deepline skills --scope ${scope} --json`
|
|
30370
|
+
},
|
|
30371
|
+
{ json: options.json }
|
|
30372
|
+
);
|
|
30373
|
+
return skills.exitCode;
|
|
30374
|
+
}
|
|
30375
|
+
writeSetupState({ baseUrl, scope, root, status: "skills_installed" });
|
|
30376
|
+
const authScope = authScopeForSetup(scope);
|
|
30377
|
+
let auth = await readAuthStatus(authScope);
|
|
30378
|
+
const initialAuthFailure = reportSetupAuthStatusFailure({
|
|
30379
|
+
auth,
|
|
30380
|
+
authScope,
|
|
30381
|
+
scope,
|
|
30382
|
+
json: options.json
|
|
30383
|
+
});
|
|
30384
|
+
if (initialAuthFailure !== null) return initialAuthFailure;
|
|
30385
|
+
if (auth.payload?.connected !== true) {
|
|
30386
|
+
const pending = readPendingAuthClaim(baseUrl, authScope);
|
|
30387
|
+
if (pending) {
|
|
30388
|
+
process.stderr.write("Checking pending Deepline authorization...\n");
|
|
30389
|
+
const waited = await captureStdout2(
|
|
30390
|
+
() => handleWait(["--timeout", "1", "--auth-scope", authScope])
|
|
30391
|
+
);
|
|
30392
|
+
printCapturedAuthorizationUrl(waited.stdout);
|
|
30393
|
+
auth = await readAuthStatus(authScope);
|
|
30394
|
+
const resumedAuthFailure = reportSetupAuthStatusFailure({
|
|
30395
|
+
auth,
|
|
30396
|
+
authScope,
|
|
30397
|
+
scope,
|
|
30398
|
+
json: options.json
|
|
30399
|
+
});
|
|
30400
|
+
if (resumedAuthFailure !== null) return resumedAuthFailure;
|
|
30401
|
+
if (auth.payload?.connected !== true) {
|
|
30402
|
+
const stillPending = readPendingAuthClaim(baseUrl, authScope);
|
|
30403
|
+
if (stillPending) {
|
|
30404
|
+
return pendingResult({
|
|
30405
|
+
baseUrl,
|
|
30406
|
+
scope,
|
|
30407
|
+
root,
|
|
30408
|
+
authorizationUrl: stillPending.claimUrl,
|
|
30409
|
+
json: options.json
|
|
30410
|
+
});
|
|
30411
|
+
}
|
|
30412
|
+
}
|
|
30413
|
+
}
|
|
30414
|
+
}
|
|
30415
|
+
if (auth.payload?.connected !== true) {
|
|
30416
|
+
process.stderr.write("Starting Deepline browser authorization...\n");
|
|
30417
|
+
const agentRuntime = detectAgentRuntime();
|
|
30418
|
+
const agentLed = agentRuntime !== "unknown";
|
|
30419
|
+
const waitMode = options.json || agentLed || !process.stdin.isTTY ? "no" : "auto";
|
|
30420
|
+
const registered = await captureStdout2(
|
|
30421
|
+
() => handleRegister(["--wait", waitMode, "--auth-scope", authScope])
|
|
30422
|
+
);
|
|
30423
|
+
printCapturedAuthorizationUrl(registered.stdout);
|
|
30424
|
+
if (registered.exitCode !== 0) {
|
|
30425
|
+
printCommandEnvelope(
|
|
30426
|
+
{
|
|
30427
|
+
ok: false,
|
|
30428
|
+
status: "failed",
|
|
30429
|
+
code: "AUTH_REGISTER_FAILED",
|
|
30430
|
+
exitCode: registered.exitCode,
|
|
30431
|
+
scope,
|
|
30432
|
+
next: `deepline auth register --auth-scope ${authScope}`
|
|
30433
|
+
},
|
|
30434
|
+
{ json: options.json }
|
|
30435
|
+
);
|
|
30436
|
+
return registered.exitCode;
|
|
30437
|
+
}
|
|
30438
|
+
auth = await readAuthStatus(authScope);
|
|
30439
|
+
const registeredAuthFailure = reportSetupAuthStatusFailure({
|
|
30440
|
+
auth,
|
|
30441
|
+
authScope,
|
|
30442
|
+
scope,
|
|
30443
|
+
json: options.json
|
|
30444
|
+
});
|
|
30445
|
+
if (registeredAuthFailure !== null) return registeredAuthFailure;
|
|
30446
|
+
if (auth.payload?.connected !== true) {
|
|
30447
|
+
const pending = readPendingAuthClaim(baseUrl, authScope);
|
|
30448
|
+
return pendingResult({
|
|
30449
|
+
baseUrl,
|
|
30450
|
+
scope,
|
|
30451
|
+
root,
|
|
30452
|
+
authorizationUrl: pending?.claimUrl ?? "",
|
|
30453
|
+
json: options.json
|
|
30454
|
+
});
|
|
30455
|
+
}
|
|
30456
|
+
}
|
|
30457
|
+
process.stderr.write("Verifying Deepline setup...\n");
|
|
30458
|
+
const doctor = await captureStdout2(
|
|
30459
|
+
() => runDoctorCommand({ scope, json: true })
|
|
30460
|
+
);
|
|
30461
|
+
const doctorPayload = parseCapturedJson(doctor.stdout);
|
|
30462
|
+
if (doctor.exitCode !== 0) {
|
|
30463
|
+
printCommandEnvelope(
|
|
30464
|
+
{
|
|
30465
|
+
ok: false,
|
|
30466
|
+
status: "failed",
|
|
30467
|
+
code: "DOCTOR_FAILED",
|
|
30468
|
+
exitCode: doctor.exitCode,
|
|
30469
|
+
scope,
|
|
30470
|
+
doctor: doctorPayload,
|
|
30471
|
+
next: "Review the doctor result and choose a repair, then rerun: deepline setup --json"
|
|
30472
|
+
},
|
|
30473
|
+
{ json: options.json }
|
|
30474
|
+
);
|
|
30475
|
+
return doctor.exitCode;
|
|
30476
|
+
}
|
|
30477
|
+
const statePath = writeSetupState({
|
|
30478
|
+
baseUrl,
|
|
30479
|
+
scope,
|
|
30480
|
+
root,
|
|
30481
|
+
status: "complete"
|
|
30482
|
+
});
|
|
30483
|
+
const doctorChecks = asRecord2(doctorPayload?.checks);
|
|
30484
|
+
const apiCheck = asRecord2(doctorChecks?.api);
|
|
30485
|
+
const quickstart = setupQuickstartCommand(baseUrl);
|
|
30486
|
+
printCommandEnvelope(
|
|
30487
|
+
{
|
|
30488
|
+
ok: true,
|
|
30489
|
+
status: "complete",
|
|
30490
|
+
complete: true,
|
|
30491
|
+
scope,
|
|
30492
|
+
cliVersion: SDK_VERSION,
|
|
30493
|
+
agents: skillsPayload?.agents ?? [],
|
|
30494
|
+
workspace: apiCheck?.workspace ?? null,
|
|
30495
|
+
rollbackCommand: rollbackCommand(scope, root),
|
|
30496
|
+
statePath,
|
|
30497
|
+
doctor: doctorPayload,
|
|
30498
|
+
next: quickstart,
|
|
30499
|
+
render: {
|
|
30500
|
+
sections: [
|
|
30501
|
+
{
|
|
30502
|
+
title: "setup",
|
|
30503
|
+
lines: [
|
|
30504
|
+
"Deepline is installed and connected.",
|
|
30505
|
+
`Next: ${quickstart}`
|
|
30506
|
+
]
|
|
30507
|
+
}
|
|
30508
|
+
]
|
|
30509
|
+
}
|
|
30510
|
+
},
|
|
30511
|
+
{ json: options.json }
|
|
30512
|
+
);
|
|
30513
|
+
return 0;
|
|
30514
|
+
}
|
|
30515
|
+
function registerSetupCommands(program) {
|
|
30516
|
+
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(
|
|
30517
|
+
"after",
|
|
30518
|
+
`
|
|
30519
|
+
Notes:
|
|
30520
|
+
Setup is idempotent. Bare setup resumes pending browser authorization.
|
|
30521
|
+
It installs skills before auth and does not run quickstart.
|
|
30522
|
+
|
|
30523
|
+
Examples:
|
|
30524
|
+
deepline setup --json
|
|
30525
|
+
deepline setup --scope local --json
|
|
30526
|
+
`
|
|
30527
|
+
).action(async (options) => {
|
|
30528
|
+
process.exitCode = await runSetupCommand(options);
|
|
30529
|
+
});
|
|
30530
|
+
program.command("doctor").description("Verify CLI, skills, auth, workspace, and API connectivity.").option(
|
|
30531
|
+
"--scope <scope>",
|
|
30532
|
+
"Expected setup scope: global or local",
|
|
30533
|
+
"global"
|
|
30534
|
+
).option("--json", "Emit one JSON result envelope").addHelpText(
|
|
30535
|
+
"after",
|
|
30536
|
+
`
|
|
30537
|
+
Notes:
|
|
30538
|
+
Doctor is read-only and makes no paid provider calls. It reports repairs but
|
|
30539
|
+
does not apply them automatically.
|
|
30540
|
+
|
|
30541
|
+
Examples:
|
|
30542
|
+
deepline doctor --json
|
|
30543
|
+
deepline doctor --scope local --json
|
|
30544
|
+
`
|
|
30545
|
+
).action(async (options) => {
|
|
30546
|
+
process.exitCode = await runDoctorCommand(options);
|
|
30547
|
+
});
|
|
30548
|
+
}
|
|
30549
|
+
|
|
30550
|
+
// ../shared_libs/cli/command-compatibility.json
|
|
30551
|
+
var command_compatibility_default = {
|
|
30552
|
+
enrich: {
|
|
30553
|
+
family: "python",
|
|
30554
|
+
label: "a legacy Python CLI enrichment command",
|
|
30555
|
+
sdk_alternative: "Use `deepline plays ...` for durable workflows or `deepline tools execute ...` for one tool call."
|
|
30556
|
+
},
|
|
30557
|
+
session: {
|
|
30558
|
+
family: "python",
|
|
30559
|
+
label: "a legacy Python CLI session/playground command",
|
|
30560
|
+
sdk_alternative: "Use `deepline sessions send ...` or `deepline sessions render ...` for transcript workflows."
|
|
30561
|
+
},
|
|
30562
|
+
workflows: {
|
|
30563
|
+
family: "python",
|
|
30564
|
+
label: "a legacy Python CLI workflow command",
|
|
30565
|
+
sdk_alternative: "Use `deepline plays ...` in the SDK CLI."
|
|
30566
|
+
},
|
|
30567
|
+
events: {
|
|
30568
|
+
family: "python",
|
|
30569
|
+
label: "a legacy Python CLI event command"
|
|
30570
|
+
},
|
|
29737
30571
|
plays: {
|
|
29738
30572
|
family: "sdk",
|
|
29739
30573
|
label: "an SDK CLI play command",
|
|
@@ -29797,130 +30631,440 @@ function commandCompatibilityHint(currentFamily, commandName, baseUrl) {
|
|
|
29797
30631
|
lines.push(` Python alternative: ${compatibility.python_alternative}`);
|
|
29798
30632
|
}
|
|
29799
30633
|
}
|
|
29800
|
-
return lines.join("\n");
|
|
29801
|
-
}
|
|
29802
|
-
function unknownCommandNameFromMessage(message) {
|
|
29803
|
-
const match = message.match(/unknown command ['"]([^'"]+)['"]/i);
|
|
29804
|
-
const command = match?.[1]?.trim();
|
|
29805
|
-
return command ? command : null;
|
|
30634
|
+
return lines.join("\n");
|
|
30635
|
+
}
|
|
30636
|
+
function unknownCommandNameFromMessage(message) {
|
|
30637
|
+
const match = message.match(/unknown command ['"]([^'"]+)['"]/i);
|
|
30638
|
+
const command = match?.[1]?.trim();
|
|
30639
|
+
return command ? command : null;
|
|
30640
|
+
}
|
|
30641
|
+
|
|
30642
|
+
// src/cli/self-update.ts
|
|
30643
|
+
var import_node_child_process6 = require("child_process");
|
|
30644
|
+
function envTruthy(name) {
|
|
30645
|
+
const value = process.env[name]?.trim().toLowerCase();
|
|
30646
|
+
return value === "1" || value === "true" || value === "yes";
|
|
30647
|
+
}
|
|
30648
|
+
function isCi() {
|
|
30649
|
+
return envTruthy("CI") || envTruthy("GITHUB_ACTIONS");
|
|
30650
|
+
}
|
|
30651
|
+
function shouldSkipSelfUpdate() {
|
|
30652
|
+
return envTruthy("DEEPLINE_SKIP_SELF_UPDATE") || envTruthy("DEEPLINE_NO_AUTO_UPDATE") || envTruthy("DEEPLINE_SKIP_SDK_AUTO_UPDATE") || envTruthy("DEEPLINE_DISABLE_AUTO_UPDATE") || isCi();
|
|
30653
|
+
}
|
|
30654
|
+
function parseSemver(version) {
|
|
30655
|
+
const trimmed = version?.trim();
|
|
30656
|
+
if (!trimmed) return null;
|
|
30657
|
+
const match = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(
|
|
30658
|
+
trimmed
|
|
30659
|
+
);
|
|
30660
|
+
if (!match) return null;
|
|
30661
|
+
return {
|
|
30662
|
+
major: Number(match[1]),
|
|
30663
|
+
minor: Number(match[2]),
|
|
30664
|
+
patch: Number(match[3]),
|
|
30665
|
+
prerelease: match[4] ?? ""
|
|
30666
|
+
};
|
|
30667
|
+
}
|
|
30668
|
+
function compareSemver(left, right) {
|
|
30669
|
+
const a = parseSemver(left);
|
|
30670
|
+
const b = parseSemver(right);
|
|
30671
|
+
if (!a || !b) {
|
|
30672
|
+
return left.localeCompare(right);
|
|
30673
|
+
}
|
|
30674
|
+
for (const key of ["major", "minor", "patch"]) {
|
|
30675
|
+
if (a[key] !== b[key]) return a[key] > b[key] ? 1 : -1;
|
|
30676
|
+
}
|
|
30677
|
+
if (a.prerelease === b.prerelease) return 0;
|
|
30678
|
+
if (!a.prerelease) return 1;
|
|
30679
|
+
if (!b.prerelease) return -1;
|
|
30680
|
+
return a.prerelease.localeCompare(b.prerelease);
|
|
30681
|
+
}
|
|
30682
|
+
function isDowngradeAutoUpdateResponse(response) {
|
|
30683
|
+
const target = response?.latest?.trim();
|
|
30684
|
+
const current = response?.current?.trim() || SDK_VERSION;
|
|
30685
|
+
if (!target) return false;
|
|
30686
|
+
return compareSemver(target, current) < 0;
|
|
30687
|
+
}
|
|
30688
|
+
function relaunchCurrentCommand(plan) {
|
|
30689
|
+
return new Promise((resolve15) => {
|
|
30690
|
+
const command = plan.kind === "python-sidecar" ? plan.sidecarPath : process.execPath;
|
|
30691
|
+
const args = plan.kind === "python-sidecar" ? process.argv.slice(2) : process.argv.slice(1);
|
|
30692
|
+
const child = (0, import_node_child_process6.spawn)(command, args, {
|
|
30693
|
+
stdio: "inherit",
|
|
30694
|
+
shell: process.platform === "win32",
|
|
30695
|
+
env: {
|
|
30696
|
+
...process.env,
|
|
30697
|
+
DEEPLINE_NO_AUTO_UPDATE: "1"
|
|
30698
|
+
}
|
|
30699
|
+
});
|
|
30700
|
+
child.on("error", (error) => {
|
|
30701
|
+
process.stderr.write(
|
|
30702
|
+
`Deepline SDK/CLI updated, but relaunch failed: ${error.message}
|
|
30703
|
+
`
|
|
30704
|
+
);
|
|
30705
|
+
resolve15(1);
|
|
30706
|
+
});
|
|
30707
|
+
child.on("close", (code) => resolve15(code ?? 1));
|
|
30708
|
+
});
|
|
30709
|
+
}
|
|
30710
|
+
async function maybeAutoUpdateAndRelaunch(response) {
|
|
30711
|
+
const autoUpdate = response?.auto_update;
|
|
30712
|
+
if (!response || !autoUpdate?.should_auto_update || shouldSkipSelfUpdate()) {
|
|
30713
|
+
return false;
|
|
30714
|
+
}
|
|
30715
|
+
if (isDowngradeAutoUpdateResponse(response)) {
|
|
30716
|
+
const target = response.latest;
|
|
30717
|
+
const current = response.current?.trim() || SDK_VERSION;
|
|
30718
|
+
process.stderr.write(
|
|
30719
|
+
`Deepline SDK/CLI auto-update refused: server advertised older ${target} than current ${current}. Continuing without mutating the CLI.
|
|
30720
|
+
`
|
|
30721
|
+
);
|
|
30722
|
+
return false;
|
|
30723
|
+
}
|
|
30724
|
+
const packageSpec = response.latest ? `deepline@${response.latest}` : void 0;
|
|
30725
|
+
const plan = resolveUpdatePlan({ packageSpec });
|
|
30726
|
+
if (plan.kind === "source") {
|
|
30727
|
+
return false;
|
|
30728
|
+
}
|
|
30729
|
+
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";
|
|
30730
|
+
process.stderr.write(
|
|
30731
|
+
`Deepline SDK/CLI ${label}; running ${plan.manualCommand}
|
|
30732
|
+
`
|
|
30733
|
+
);
|
|
30734
|
+
const updateResult = await runAutomaticUpdatePlan(plan);
|
|
30735
|
+
if (updateResult.status === "skipped_previous_failure") {
|
|
30736
|
+
return false;
|
|
30737
|
+
}
|
|
30738
|
+
if (updateResult.exitCode !== 0) {
|
|
30739
|
+
if (autoUpdate.required) {
|
|
30740
|
+
throw new Error(
|
|
30741
|
+
`Automatic Deepline SDK/CLI update failed with exit code ${updateResult.exitCode}. ${response.message}`
|
|
30742
|
+
);
|
|
30743
|
+
}
|
|
30744
|
+
process.stderr.write(
|
|
30745
|
+
`Deepline SDK/CLI auto-update failed with exit code ${updateResult.exitCode}; continuing with ${response.current ?? "current version"}.
|
|
30746
|
+
`
|
|
30747
|
+
);
|
|
30748
|
+
return false;
|
|
30749
|
+
}
|
|
30750
|
+
process.stderr.write("Deepline SDK/CLI updated; rerunning command.\n");
|
|
30751
|
+
const exitCode = await relaunchCurrentCommand(plan);
|
|
30752
|
+
process.exit(exitCode);
|
|
30753
|
+
return true;
|
|
30754
|
+
}
|
|
30755
|
+
|
|
30756
|
+
// src/cli/skills-sync.ts
|
|
30757
|
+
var import_node_child_process7 = require("child_process");
|
|
30758
|
+
var import_node_fs19 = require("fs");
|
|
30759
|
+
var import_node_path21 = require("path");
|
|
30760
|
+
var CHECK_TIMEOUT_MS2 = 3e3;
|
|
30761
|
+
var attemptedSync = false;
|
|
30762
|
+
function shouldSkipSkillsSync() {
|
|
30763
|
+
if (detectAgentRuntime() === "claude_cowork") {
|
|
30764
|
+
return true;
|
|
30765
|
+
}
|
|
30766
|
+
const value = process.env.DEEPLINE_SKIP_SKILLS_SYNC?.trim().toLowerCase();
|
|
30767
|
+
return value === "1" || value === "true" || value === "yes" || value === "on";
|
|
30768
|
+
}
|
|
30769
|
+
function activePluginSkillsDir() {
|
|
30770
|
+
const pluginMode = process.env.DEEPLINE_PLUGIN_MODE?.trim().toLowerCase();
|
|
30771
|
+
if (pluginMode !== "true" && pluginMode !== "1" && pluginMode !== "yes" && pluginMode !== "on") {
|
|
30772
|
+
return "";
|
|
30773
|
+
}
|
|
30774
|
+
const dir = process.env.DEEPLINE_PLUGIN_SKILLS_DIR?.trim() ?? "";
|
|
30775
|
+
return dir && (0, import_node_fs19.existsSync)(dir) ? dir : "";
|
|
30776
|
+
}
|
|
30777
|
+
function readPluginSkillsVersion() {
|
|
30778
|
+
const dir = activePluginSkillsDir();
|
|
30779
|
+
if (!dir) return "";
|
|
30780
|
+
try {
|
|
30781
|
+
return (0, import_node_fs19.readFileSync)((0, import_node_path21.join)(dir, ".version"), "utf-8").trim();
|
|
30782
|
+
} catch {
|
|
30783
|
+
return "";
|
|
30784
|
+
}
|
|
30785
|
+
}
|
|
30786
|
+
function sdkSkillsVersionPath(baseUrl) {
|
|
30787
|
+
return (0, import_node_path21.join)(sdkCliStateDirPath(baseUrl), "skills-version");
|
|
30788
|
+
}
|
|
30789
|
+
function legacySdkSkillsVersionPath(baseUrl) {
|
|
30790
|
+
return (0, import_node_path21.join)((0, import_node_path21.dirname)(sdkCliStateDirPath(baseUrl)), "sdk-skills", ".version");
|
|
30791
|
+
}
|
|
30792
|
+
function unavailableSkillsNoticePath(baseUrl) {
|
|
30793
|
+
return (0, import_node_path21.join)(sdkCliStateDirPath(baseUrl), "skills-sync-unavailable-version");
|
|
30794
|
+
}
|
|
30795
|
+
function readSdkSkillsLocalVersion(baseUrl) {
|
|
30796
|
+
const pluginVersion = readPluginSkillsVersion();
|
|
30797
|
+
if (pluginVersion) return pluginVersion;
|
|
30798
|
+
const path = (0, import_node_fs19.existsSync)(sdkSkillsVersionPath(baseUrl)) ? sdkSkillsVersionPath(baseUrl) : legacySdkSkillsVersionPath(baseUrl);
|
|
30799
|
+
if (!(0, import_node_fs19.existsSync)(path)) return "";
|
|
30800
|
+
try {
|
|
30801
|
+
return (0, import_node_fs19.readFileSync)(path, "utf-8").trim();
|
|
30802
|
+
} catch {
|
|
30803
|
+
return "";
|
|
30804
|
+
}
|
|
30805
|
+
}
|
|
30806
|
+
function writeLocalSkillsVersion(baseUrl, version) {
|
|
30807
|
+
const path = sdkSkillsVersionPath(baseUrl);
|
|
30808
|
+
(0, import_node_fs19.mkdirSync)((0, import_node_path21.dirname)(path), { recursive: true });
|
|
30809
|
+
(0, import_node_fs19.writeFileSync)(path, `${version}
|
|
30810
|
+
`, "utf-8");
|
|
30811
|
+
}
|
|
30812
|
+
function writeUnavailableSkillsNotice(baseUrl, remoteVersion, skillNames) {
|
|
30813
|
+
const path = unavailableSkillsNoticePath(baseUrl);
|
|
30814
|
+
try {
|
|
30815
|
+
if ((0, import_node_fs19.existsSync)(path) && (0, import_node_fs19.readFileSync)(path, "utf-8").trim() === remoteVersion) {
|
|
30816
|
+
return;
|
|
30817
|
+
}
|
|
30818
|
+
(0, import_node_fs19.mkdirSync)((0, import_node_path21.dirname)(path), { recursive: true });
|
|
30819
|
+
(0, import_node_fs19.writeFileSync)(path, `${remoteVersion}
|
|
30820
|
+
`, "utf-8");
|
|
30821
|
+
} catch {
|
|
30822
|
+
}
|
|
30823
|
+
const manualCommand = `npx ${buildSkillsInstallArgs(baseUrl, skillNames).join(" ")}`;
|
|
30824
|
+
writeSdkSkillsStatusLine(
|
|
30825
|
+
`Deepline agent skills are out of date, but neither \`bunx\` nor \`npx\` is available. Install Node.js/npm or Bun, then run:
|
|
30826
|
+
${manualCommand}`
|
|
30827
|
+
);
|
|
30828
|
+
}
|
|
30829
|
+
function clearUnavailableSkillsNotice(baseUrl) {
|
|
30830
|
+
try {
|
|
30831
|
+
(0, import_node_fs19.unlinkSync)(unavailableSkillsNoticePath(baseUrl));
|
|
30832
|
+
} catch {
|
|
30833
|
+
}
|
|
30834
|
+
}
|
|
30835
|
+
function sortedUniqueSkillNames(names) {
|
|
30836
|
+
return [...new Set(names.map((name) => name.trim()).filter(Boolean))].sort(
|
|
30837
|
+
(a, b) => a.localeCompare(b)
|
|
30838
|
+
);
|
|
30839
|
+
}
|
|
30840
|
+
async function fetchV1SkillNames(baseUrl) {
|
|
30841
|
+
const controller = new AbortController();
|
|
30842
|
+
const timeout = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS2);
|
|
30843
|
+
try {
|
|
30844
|
+
const response = await fetch(
|
|
30845
|
+
new URL("/.well-known/skills/index.json", baseUrl),
|
|
30846
|
+
{ signal: controller.signal }
|
|
30847
|
+
);
|
|
30848
|
+
if (!response.ok) return [];
|
|
30849
|
+
const data = await response.json().catch(() => null);
|
|
30850
|
+
const names = (data?.skills ?? []).filter((skill) => skill.install_surface === "v1").map((skill) => skill.name).filter(
|
|
30851
|
+
(name) => typeof name === "string" && name.length > 0
|
|
30852
|
+
);
|
|
30853
|
+
return sortedUniqueSkillNames(names);
|
|
30854
|
+
} catch {
|
|
30855
|
+
return [];
|
|
30856
|
+
} finally {
|
|
30857
|
+
clearTimeout(timeout);
|
|
30858
|
+
}
|
|
30859
|
+
}
|
|
30860
|
+
function buildSdkSkillNames(v1SkillNames) {
|
|
30861
|
+
return sortedUniqueSkillNames(v1SkillNames);
|
|
30862
|
+
}
|
|
30863
|
+
async function fetchSkillsUpdate(baseUrl, localVersion) {
|
|
30864
|
+
const controller = new AbortController();
|
|
30865
|
+
const timeout = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS2);
|
|
30866
|
+
try {
|
|
30867
|
+
const response = await fetch(new URL("/api/v2/cli/update-check", baseUrl), {
|
|
30868
|
+
method: "POST",
|
|
30869
|
+
headers: { "Content-Type": "application/json" },
|
|
30870
|
+
body: JSON.stringify({
|
|
30871
|
+
skills: {
|
|
30872
|
+
version: localVersion
|
|
30873
|
+
}
|
|
30874
|
+
}),
|
|
30875
|
+
signal: controller.signal
|
|
30876
|
+
});
|
|
30877
|
+
if (!response.ok) return null;
|
|
30878
|
+
const data = await response.json().catch(() => null);
|
|
30879
|
+
const skills = data?.skills;
|
|
30880
|
+
if (!skills) return null;
|
|
30881
|
+
return {
|
|
30882
|
+
needsUpdate: skills.needs_update === true,
|
|
30883
|
+
remoteVersion: typeof skills.remote?.version === "string" ? skills.remote.version.trim() : ""
|
|
30884
|
+
};
|
|
30885
|
+
} catch {
|
|
30886
|
+
return null;
|
|
30887
|
+
} finally {
|
|
30888
|
+
clearTimeout(timeout);
|
|
30889
|
+
}
|
|
29806
30890
|
}
|
|
29807
|
-
|
|
29808
|
-
|
|
29809
|
-
var import_node_child_process5 = require("child_process");
|
|
29810
|
-
function envTruthy(name) {
|
|
29811
|
-
const value = process.env[name]?.trim().toLowerCase();
|
|
29812
|
-
return value === "1" || value === "true" || value === "yes";
|
|
30891
|
+
function buildSkillsInstallArgs(baseUrl, skillNames = DEFAULT_SDK_SKILL_NAMES) {
|
|
30892
|
+
return buildSkillsAddArgs(baseUrl, sortedUniqueSkillNames(skillNames));
|
|
29813
30893
|
}
|
|
29814
|
-
function
|
|
29815
|
-
return
|
|
30894
|
+
function buildBunxSkillsInstallArgs(baseUrl, skillNames) {
|
|
30895
|
+
return buildSkillsAddArgs(baseUrl, sortedUniqueSkillNames(skillNames), {
|
|
30896
|
+
firstArg: "--bun"
|
|
30897
|
+
});
|
|
29816
30898
|
}
|
|
29817
|
-
function
|
|
29818
|
-
|
|
30899
|
+
function hasCommand(command) {
|
|
30900
|
+
const result = (0, import_node_child_process7.spawnSync)(command, ["--version"], {
|
|
30901
|
+
stdio: "ignore",
|
|
30902
|
+
shell: process.platform === "win32"
|
|
30903
|
+
});
|
|
30904
|
+
return result.status === 0;
|
|
29819
30905
|
}
|
|
29820
|
-
function
|
|
29821
|
-
|
|
29822
|
-
if (!trimmed) return null;
|
|
29823
|
-
const match = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?$/.exec(
|
|
29824
|
-
trimmed
|
|
29825
|
-
);
|
|
29826
|
-
if (!match) return null;
|
|
29827
|
-
return {
|
|
29828
|
-
major: Number(match[1]),
|
|
29829
|
-
minor: Number(match[2]),
|
|
29830
|
-
patch: Number(match[3]),
|
|
29831
|
-
prerelease: match[4] ?? ""
|
|
29832
|
-
};
|
|
30906
|
+
function shellQuote6(arg) {
|
|
30907
|
+
return `'${arg.replace(/'/g, `'\\''`)}'`;
|
|
29833
30908
|
}
|
|
29834
|
-
function
|
|
29835
|
-
const
|
|
29836
|
-
|
|
29837
|
-
|
|
29838
|
-
|
|
30909
|
+
function resolveSkillsInstallCommands(baseUrl, skillNames = DEFAULT_SDK_SKILL_NAMES) {
|
|
30910
|
+
const commands = [];
|
|
30911
|
+
if (hasCommand("bunx")) {
|
|
30912
|
+
const bunxArgs = buildBunxSkillsInstallArgs(baseUrl, skillNames);
|
|
30913
|
+
commands.push({
|
|
30914
|
+
command: "bunx",
|
|
30915
|
+
args: bunxArgs,
|
|
30916
|
+
manualCommand: `bunx ${bunxArgs.map(shellQuote6).join(" ")}`
|
|
30917
|
+
});
|
|
29839
30918
|
}
|
|
29840
|
-
|
|
29841
|
-
|
|
30919
|
+
if (hasCommand("npx")) {
|
|
30920
|
+
const npxArgs = buildSkillsInstallArgs(baseUrl, skillNames);
|
|
30921
|
+
commands.push({
|
|
30922
|
+
command: "npx",
|
|
30923
|
+
args: npxArgs,
|
|
30924
|
+
manualCommand: `npx ${npxArgs.map(shellQuote6).join(" ")}`
|
|
30925
|
+
});
|
|
29842
30926
|
}
|
|
29843
|
-
|
|
29844
|
-
if (!a.prerelease) return 1;
|
|
29845
|
-
if (!b.prerelease) return -1;
|
|
29846
|
-
return a.prerelease.localeCompare(b.prerelease);
|
|
29847
|
-
}
|
|
29848
|
-
function isDowngradeAutoUpdateResponse(response) {
|
|
29849
|
-
const target = response?.latest?.trim();
|
|
29850
|
-
const current = response?.current?.trim() || SDK_VERSION;
|
|
29851
|
-
if (!target) return false;
|
|
29852
|
-
return compareSemver(target, current) < 0;
|
|
30927
|
+
return commands;
|
|
29853
30928
|
}
|
|
29854
|
-
function
|
|
29855
|
-
return new Promise((
|
|
29856
|
-
const
|
|
29857
|
-
|
|
29858
|
-
|
|
29859
|
-
|
|
29860
|
-
|
|
29861
|
-
|
|
29862
|
-
|
|
29863
|
-
DEEPLINE_NO_AUTO_UPDATE: "1"
|
|
29864
|
-
}
|
|
30929
|
+
function runOneSkillsInstall(install) {
|
|
30930
|
+
return new Promise((resolve15) => {
|
|
30931
|
+
const child = (0, import_node_child_process7.spawn)(install.command, install.args, {
|
|
30932
|
+
stdio: ["ignore", "ignore", "pipe"],
|
|
30933
|
+
env: process.env
|
|
30934
|
+
});
|
|
30935
|
+
let stderr = "";
|
|
30936
|
+
child.stderr.on("data", (chunk) => {
|
|
30937
|
+
stderr += chunk.toString("utf-8");
|
|
29865
30938
|
});
|
|
29866
30939
|
child.on("error", (error) => {
|
|
29867
|
-
|
|
29868
|
-
|
|
29869
|
-
`
|
|
29870
|
-
|
|
29871
|
-
|
|
30940
|
+
resolve15({
|
|
30941
|
+
ok: false,
|
|
30942
|
+
detail: `failed to start ${install.command}: ${error.message}`,
|
|
30943
|
+
manualCommand: install.manualCommand
|
|
30944
|
+
});
|
|
30945
|
+
});
|
|
30946
|
+
child.on("close", (code) => {
|
|
30947
|
+
if (code === 0) {
|
|
30948
|
+
resolve15({ ok: true, detail: "", manualCommand: install.manualCommand });
|
|
30949
|
+
return;
|
|
30950
|
+
}
|
|
30951
|
+
const detail = stderr.trim();
|
|
30952
|
+
resolve15({
|
|
30953
|
+
ok: false,
|
|
30954
|
+
detail: detail ? `${install.command}: ${detail}` : `${install.command} exited ${code}`,
|
|
30955
|
+
manualCommand: install.manualCommand
|
|
30956
|
+
});
|
|
29872
30957
|
});
|
|
29873
|
-
child.on("close", (code) => resolve14(code ?? 1));
|
|
29874
30958
|
});
|
|
29875
30959
|
}
|
|
29876
|
-
async function
|
|
29877
|
-
const
|
|
29878
|
-
|
|
29879
|
-
|
|
29880
|
-
|
|
29881
|
-
|
|
29882
|
-
const target = response.latest;
|
|
29883
|
-
const current = response.current?.trim() || SDK_VERSION;
|
|
29884
|
-
process.stderr.write(
|
|
29885
|
-
`Deepline SDK/CLI auto-update refused: server advertised older ${target} than current ${current}. Continuing without mutating the CLI.
|
|
29886
|
-
`
|
|
29887
|
-
);
|
|
29888
|
-
return false;
|
|
29889
|
-
}
|
|
29890
|
-
const packageSpec = response.latest ? `deepline@${response.latest}` : void 0;
|
|
29891
|
-
const plan = resolveUpdatePlan({ packageSpec });
|
|
29892
|
-
if (plan.kind === "source") {
|
|
29893
|
-
return false;
|
|
30960
|
+
async function runSkillsInstall(installs) {
|
|
30961
|
+
const failures = [];
|
|
30962
|
+
for (const install of installs) {
|
|
30963
|
+
const result = await runOneSkillsInstall(install);
|
|
30964
|
+
if (result.ok) return true;
|
|
30965
|
+
failures.push(result);
|
|
29894
30966
|
}
|
|
29895
|
-
const
|
|
30967
|
+
const details = failures.map((failure) => failure.detail).filter(Boolean).join("\n");
|
|
30968
|
+
const manualCommand = failures.at(-1)?.manualCommand;
|
|
29896
30969
|
process.stderr.write(
|
|
29897
|
-
`
|
|
29898
|
-
`
|
|
30970
|
+
`SDK skills sync failed${details ? `:
|
|
30971
|
+
${details}` : ""}
|
|
30972
|
+
` + (manualCommand ? `Run manually: ${manualCommand}
|
|
30973
|
+
` : "")
|
|
29899
30974
|
);
|
|
29900
|
-
|
|
29901
|
-
|
|
29902
|
-
|
|
29903
|
-
|
|
29904
|
-
|
|
29905
|
-
|
|
29906
|
-
|
|
29907
|
-
|
|
29908
|
-
|
|
30975
|
+
return false;
|
|
30976
|
+
}
|
|
30977
|
+
function runLegacySkillsCleanup() {
|
|
30978
|
+
const candidates = hasCommand("bunx") ? [
|
|
30979
|
+
{
|
|
30980
|
+
command: "bunx",
|
|
30981
|
+
args: [
|
|
30982
|
+
"--bun",
|
|
30983
|
+
"skills",
|
|
30984
|
+
"remove",
|
|
30985
|
+
"--global",
|
|
30986
|
+
"-y",
|
|
30987
|
+
...LEGACY_SKILL_NAMES_TO_REMOVE
|
|
30988
|
+
]
|
|
30989
|
+
},
|
|
30990
|
+
{
|
|
30991
|
+
command: "npx",
|
|
30992
|
+
args: [
|
|
30993
|
+
"--yes",
|
|
30994
|
+
"skills",
|
|
30995
|
+
"remove",
|
|
30996
|
+
"--global",
|
|
30997
|
+
"-y",
|
|
30998
|
+
...LEGACY_SKILL_NAMES_TO_REMOVE
|
|
30999
|
+
]
|
|
29909
31000
|
}
|
|
29910
|
-
|
|
29911
|
-
|
|
29912
|
-
|
|
29913
|
-
|
|
29914
|
-
|
|
31001
|
+
] : [
|
|
31002
|
+
{
|
|
31003
|
+
command: "npx",
|
|
31004
|
+
args: [
|
|
31005
|
+
"--yes",
|
|
31006
|
+
"skills",
|
|
31007
|
+
"remove",
|
|
31008
|
+
"--global",
|
|
31009
|
+
"-y",
|
|
31010
|
+
...LEGACY_SKILL_NAMES_TO_REMOVE
|
|
31011
|
+
]
|
|
31012
|
+
}
|
|
31013
|
+
];
|
|
31014
|
+
for (const candidate of candidates) {
|
|
31015
|
+
const result = (0, import_node_child_process7.spawnSync)(candidate.command, candidate.args, {
|
|
31016
|
+
stdio: "ignore",
|
|
31017
|
+
env: process.env,
|
|
31018
|
+
shell: process.platform === "win32"
|
|
31019
|
+
});
|
|
31020
|
+
if (result.status === 0) return;
|
|
29915
31021
|
}
|
|
29916
|
-
|
|
29917
|
-
|
|
29918
|
-
|
|
29919
|
-
|
|
31022
|
+
}
|
|
31023
|
+
function writeSdkSkillsStatusLine(line) {
|
|
31024
|
+
const progress = getActiveCliProgress();
|
|
31025
|
+
if (progress) {
|
|
31026
|
+
progress.writeLine(line);
|
|
31027
|
+
return;
|
|
31028
|
+
}
|
|
31029
|
+
process.stderr.write(`${line}
|
|
31030
|
+
`);
|
|
31031
|
+
}
|
|
31032
|
+
async function syncSdkSkillsIfNeeded(baseUrl, options = {}) {
|
|
31033
|
+
if (attemptedSync || shouldSkipSkillsSync()) return;
|
|
31034
|
+
attemptedSync = true;
|
|
31035
|
+
const usingPluginSkills = Boolean(activePluginSkillsDir());
|
|
31036
|
+
if (usingPluginSkills) {
|
|
31037
|
+
return;
|
|
31038
|
+
}
|
|
31039
|
+
const localVersion = readSdkSkillsLocalVersion(baseUrl);
|
|
31040
|
+
const update = options.update === void 0 ? await fetchSkillsUpdate(baseUrl, localVersion) : options.update ? {
|
|
31041
|
+
needsUpdate: options.update.needs_update,
|
|
31042
|
+
remoteVersion: options.update.remote.version
|
|
31043
|
+
} : null;
|
|
31044
|
+
if (!update?.needsUpdate || !update.remoteVersion) {
|
|
31045
|
+
return;
|
|
31046
|
+
}
|
|
31047
|
+
const remoteSkillNames = await fetchV1SkillNames(baseUrl);
|
|
31048
|
+
const skillNames = buildSdkSkillNames(
|
|
31049
|
+
remoteSkillNames.length > 0 ? remoteSkillNames : DEFAULT_SDK_SKILL_NAMES
|
|
31050
|
+
);
|
|
31051
|
+
if (skillNames.length === 0) return;
|
|
31052
|
+
const installs = resolveSkillsInstallCommands(baseUrl, skillNames);
|
|
31053
|
+
if (installs.length === 0) {
|
|
31054
|
+
writeUnavailableSkillsNotice(baseUrl, update.remoteVersion, skillNames);
|
|
31055
|
+
return;
|
|
31056
|
+
}
|
|
31057
|
+
writeSdkSkillsStatusLine("Deepline skills changed; syncing agent skills...");
|
|
31058
|
+
const installed = await runSkillsInstall(installs);
|
|
31059
|
+
if (!installed) return;
|
|
31060
|
+
runLegacySkillsCleanup();
|
|
31061
|
+
writeLocalSkillsVersion(baseUrl, update.remoteVersion);
|
|
31062
|
+
clearUnavailableSkillsNotice(baseUrl);
|
|
31063
|
+
writeSdkSkillsStatusLine("Deepline agent skills are up to date.");
|
|
29920
31064
|
}
|
|
29921
31065
|
|
|
29922
31066
|
// src/cli/failure-reporting.ts
|
|
29923
|
-
var
|
|
31067
|
+
var import_node_os16 = require("os");
|
|
29924
31068
|
var FAILURE_REPORT_DISABLE_ENV = "DEEPLINE_DISABLE_FAILURE_REPORTING";
|
|
29925
31069
|
var REPORT_FAILURE_TIMEOUT_MS = 1e4;
|
|
29926
31070
|
var MAX_FAILURE_TEXT_CHARS = 4e3;
|
|
@@ -30022,12 +31166,12 @@ function isNetworkFailure(error) {
|
|
|
30022
31166
|
}
|
|
30023
31167
|
function buildEnvironmentContext() {
|
|
30024
31168
|
const context = {
|
|
30025
|
-
os: (0,
|
|
30026
|
-
os_release: (0,
|
|
30027
|
-
platform: `${(0,
|
|
31169
|
+
os: (0, import_node_os16.platform)(),
|
|
31170
|
+
os_release: (0, import_node_os16.release)(),
|
|
31171
|
+
platform: `${(0, import_node_os16.platform)()}-${(0, import_node_os16.release)()}-${process.arch}`,
|
|
30028
31172
|
node_version: process.version,
|
|
30029
31173
|
runtime: "Node.js",
|
|
30030
|
-
hostname: (0,
|
|
31174
|
+
hostname: (0, import_node_os16.hostname)(),
|
|
30031
31175
|
agent_runtime: detectAgentRuntime()
|
|
30032
31176
|
};
|
|
30033
31177
|
for (const key of ["CLAUDE_CODE_REMOTE", "DEEPLINE_PLUGIN_MODE"]) {
|
|
@@ -30220,8 +31364,8 @@ function topLevelCommandKnown(program, commandName) {
|
|
|
30220
31364
|
);
|
|
30221
31365
|
}
|
|
30222
31366
|
async function runPlayRunnerHealthCheck() {
|
|
30223
|
-
const dir = await (0, import_promises6.mkdtemp)((0,
|
|
30224
|
-
const file = (0,
|
|
31367
|
+
const dir = await (0, import_promises6.mkdtemp)((0, import_node_path22.join)((0, import_node_os17.tmpdir)(), "deepline-health-play-"));
|
|
31368
|
+
const file = (0, import_node_path22.join)(dir, "health-check.play.ts");
|
|
30225
31369
|
try {
|
|
30226
31370
|
await (0, import_promises6.writeFile)(
|
|
30227
31371
|
file,
|
|
@@ -30439,7 +31583,7 @@ Exit codes:
|
|
|
30439
31583
|
`
|
|
30440
31584
|
);
|
|
30441
31585
|
program.hook("preAction", async (_thisCommand, actionCommand) => {
|
|
30442
|
-
if (actionCommand.name() === "version" || actionCommand.name() === "update" || actionCommand.name() === "switch" || isLegacyNoopInvocation()) {
|
|
31586
|
+
if (actionCommand.name() === "version" || actionCommand.name() === "update" || actionCommand.name() === "switch" || actionCommand.name() === "setup" || actionCommand.name() === "skills" || actionCommand.name() === "doctor" || isLegacyNoopInvocation()) {
|
|
30443
31587
|
return;
|
|
30444
31588
|
}
|
|
30445
31589
|
if (printStartupPhase) {
|
|
@@ -30511,6 +31655,8 @@ Exit codes:
|
|
|
30511
31655
|
registerFeedbackCommands(program);
|
|
30512
31656
|
registerLegacyNoopCommands(program);
|
|
30513
31657
|
registerUpdateCommand(program);
|
|
31658
|
+
registerSkillsCommand(program);
|
|
31659
|
+
registerSetupCommands(program);
|
|
30514
31660
|
registerQuickstartCommands(program);
|
|
30515
31661
|
registerSwitchCommands(program);
|
|
30516
31662
|
program.command("preflight").description("Run compact health, auth, and Deepline billing checks.").option("--json", "Force JSON output.").addHelpText(
|