@useorgx/wizard 0.1.51 → 0.1.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -5
- package/dist/cli.js +777 -208
- package/dist/cli.js.map +1 -1
- package/package.json +3 -3
package/dist/cli.js
CHANGED
|
@@ -1,27 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
// _sentry-injection-stub
|
|
4
|
-
!(function() {
|
|
5
|
-
try {
|
|
6
|
-
var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {};
|
|
7
|
-
e.SENTRY_RELEASE = { id: "@useorgx/wizard@0.1.51" };
|
|
8
|
-
} catch (e2) {
|
|
9
|
-
}
|
|
10
|
-
})();
|
|
11
|
-
|
|
12
|
-
// sentry-debug-id-stub:_sentry-debug-id-injection-stub?sentry-module-id=50d660b4-210d-47c3-aad7-7a156a2728dc
|
|
13
|
-
!(function() {
|
|
14
|
-
try {
|
|
15
|
-
var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {};
|
|
16
|
-
var n = new e.Error().stack;
|
|
17
|
-
n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "3d12c6ba-ce58-4cb0-8416-25155e8d07f5", e._sentryDebugIdIdentifier = "sentry-dbid-3d12c6ba-ce58-4cb0-8416-25155e8d07f5");
|
|
18
|
-
} catch (e2) {
|
|
19
|
-
}
|
|
20
|
-
})();
|
|
21
|
-
|
|
22
3
|
// src/cli.ts
|
|
4
|
+
|
|
5
|
+
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="707a7fe5-404e-5aec-9c75-30f0f5d859d9")}catch(e){}}();
|
|
23
6
|
import * as clack from "@clack/prompts";
|
|
24
|
-
import { spawnSync as
|
|
7
|
+
import { spawnSync as spawnSync5 } from "child_process";
|
|
25
8
|
import { readFileSync as readFileSync8 } from "fs";
|
|
26
9
|
import { hostname } from "os";
|
|
27
10
|
import { resolve as resolve3 } from "path";
|
|
@@ -99,6 +82,7 @@ var CLAUDE_DIR = join(HOME, ".claude");
|
|
|
99
82
|
var CURSOR_DIR = join(HOME, ".cursor");
|
|
100
83
|
var CODEX_DIR = join(HOME, ".codex");
|
|
101
84
|
var OPENCLAW_DIR = join(HOME, ".openclaw");
|
|
85
|
+
var DEEPSEEK_HARNESS_DIR = process.env.DSH_HOME?.trim() || join(HOME, ".dsh");
|
|
102
86
|
var AGENTS_DIR = join(HOME, ".agents");
|
|
103
87
|
var CLAUDE_PROJECTS_DIR = join(CLAUDE_DIR, "projects");
|
|
104
88
|
var CODEX_SESSIONS_DIR = join(CODEX_DIR, "sessions");
|
|
@@ -142,6 +126,15 @@ var CLAUDE_INSTALL_PATHS = uniquePaths([CLAUDE_DIR]);
|
|
|
142
126
|
var CURSOR_INSTALL_PATHS = uniquePaths([CURSOR_DIR]);
|
|
143
127
|
var CODEX_INSTALL_PATHS = uniquePaths([CODEX_DIR]);
|
|
144
128
|
var OPENCLAW_INSTALL_PATHS = uniquePaths([OPENCLAW_DIR]);
|
|
129
|
+
var DEEPSEEK_HARNESS_PROFILE_PATH = join(
|
|
130
|
+
DEEPSEEK_HARNESS_DIR,
|
|
131
|
+
"profiles",
|
|
132
|
+
"headless",
|
|
133
|
+
"package.json"
|
|
134
|
+
);
|
|
135
|
+
var DEEPSEEK_HARNESS_INSTALL_PATHS = uniquePaths([
|
|
136
|
+
DEEPSEEK_HARNESS_DIR
|
|
137
|
+
]);
|
|
145
138
|
var VSCODE_MCP_PATHS = uniquePaths([
|
|
146
139
|
join(HOME, "Library", "Application Support", "Code", "User", "mcp.json"),
|
|
147
140
|
join(XDG_CONFIG_HOME, "Code", "User", "mcp.json"),
|
|
@@ -1115,6 +1108,34 @@ async function exchangeCodeForTokens(options) {
|
|
|
1115
1108
|
...typeof data.scope === "string" ? { scope: data.scope } : {}
|
|
1116
1109
|
};
|
|
1117
1110
|
}
|
|
1111
|
+
async function refreshAccessToken(options) {
|
|
1112
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
1113
|
+
const body = new URLSearchParams({
|
|
1114
|
+
grant_type: "refresh_token",
|
|
1115
|
+
refresh_token: options.refreshToken,
|
|
1116
|
+
client_id: options.clientId
|
|
1117
|
+
});
|
|
1118
|
+
const response = await fetchImpl(ORGX_HOSTED_OAUTH_TOKEN_URL, {
|
|
1119
|
+
method: "POST",
|
|
1120
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
1121
|
+
body: body.toString(),
|
|
1122
|
+
signal: AbortSignal.timeout(1e4)
|
|
1123
|
+
});
|
|
1124
|
+
if (!response.ok) {
|
|
1125
|
+
const text2 = await response.text().catch(() => "");
|
|
1126
|
+
throw new Error(`Token refresh failed (HTTP ${response.status}): ${text2}`);
|
|
1127
|
+
}
|
|
1128
|
+
const data = await response.json();
|
|
1129
|
+
if (!isRecord(data) || typeof data.access_token !== "string") {
|
|
1130
|
+
throw new Error("Refresh response missing access_token.");
|
|
1131
|
+
}
|
|
1132
|
+
return {
|
|
1133
|
+
access_token: data.access_token,
|
|
1134
|
+
token_type: typeof data.token_type === "string" ? data.token_type : "Bearer",
|
|
1135
|
+
...typeof data.expires_in === "number" ? { expires_in: data.expires_in } : {},
|
|
1136
|
+
...typeof data.refresh_token === "string" ? { refresh_token: data.refresh_token } : {}
|
|
1137
|
+
};
|
|
1138
|
+
}
|
|
1118
1139
|
async function startPkceLogin(options = {}) {
|
|
1119
1140
|
const port = options.preferredPort ?? ORGX_WIZARD_OAUTH_PREFERRED_PORT;
|
|
1120
1141
|
const scope = options.scope ?? ORGX_WIZARD_OAUTH_SCOPE;
|
|
@@ -1169,6 +1190,7 @@ var SURFACE_NAMES = [
|
|
|
1169
1190
|
"claude",
|
|
1170
1191
|
"cursor",
|
|
1171
1192
|
"codex",
|
|
1193
|
+
"deepseek",
|
|
1172
1194
|
"openclaw",
|
|
1173
1195
|
"vscode",
|
|
1174
1196
|
"windsurf",
|
|
@@ -1179,6 +1201,7 @@ var AUTOMATED_SURFACE_NAMES = [
|
|
|
1179
1201
|
"claude",
|
|
1180
1202
|
"cursor",
|
|
1181
1203
|
"codex",
|
|
1204
|
+
"deepseek",
|
|
1182
1205
|
"openclaw",
|
|
1183
1206
|
"vscode",
|
|
1184
1207
|
"windsurf",
|
|
@@ -2142,16 +2165,13 @@ async function checkWorkspaceConnectivity(options = {}) {
|
|
|
2142
2165
|
import { spawn } from "child_process";
|
|
2143
2166
|
import {
|
|
2144
2167
|
existsSync as existsSync4,
|
|
2145
|
-
mkdirSync as
|
|
2146
|
-
mkdtempSync,
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
rmSync,
|
|
2150
|
-
statSync as statSync2,
|
|
2151
|
-
writeFileSync as writeFileSync2
|
|
2168
|
+
mkdirSync as mkdirSync3,
|
|
2169
|
+
mkdtempSync as mkdtempSync2,
|
|
2170
|
+
rmSync as rmSync2,
|
|
2171
|
+
writeFileSync as writeFileSync3
|
|
2152
2172
|
} from "fs";
|
|
2153
2173
|
import { tmpdir } from "os";
|
|
2154
|
-
import { dirname as
|
|
2174
|
+
import { dirname as dirname4, join as join4 } from "path";
|
|
2155
2175
|
|
|
2156
2176
|
// src/surfaces/mcp-config.ts
|
|
2157
2177
|
import * as TOML from "@iarna/toml";
|
|
@@ -2498,6 +2518,10 @@ var SURFACE_LOCATORS = {
|
|
|
2498
2518
|
configPaths: CODEX_CONFIG_PATHS,
|
|
2499
2519
|
installPaths: CODEX_INSTALL_PATHS
|
|
2500
2520
|
},
|
|
2521
|
+
deepseek: {
|
|
2522
|
+
configPaths: [DEEPSEEK_HARNESS_PROFILE_PATH],
|
|
2523
|
+
installPaths: DEEPSEEK_HARNESS_INSTALL_PATHS
|
|
2524
|
+
},
|
|
2501
2525
|
openclaw: {
|
|
2502
2526
|
configPaths: OPENCLAW_CONFIG_PATHS,
|
|
2503
2527
|
installPaths: OPENCLAW_INSTALL_PATHS
|
|
@@ -2561,10 +2585,359 @@ function detectSurface(name, exists = existsSync2) {
|
|
|
2561
2585
|
return detection;
|
|
2562
2586
|
}
|
|
2563
2587
|
|
|
2588
|
+
// src/lib/claude-plugin-bundle.ts
|
|
2589
|
+
var ORGX_CLAUDE_PLUGIN_NAME = "orgx-claude-code-plugin";
|
|
2590
|
+
var ORGX_CLAUDE_MARKETPLACE_NAME = "orgx-local";
|
|
2591
|
+
var ORGX_CLAUDE_PLUGIN_VERSION = "0.1.12";
|
|
2592
|
+
var ORGX_CLAUDE_PLUGIN_REF = `v${ORGX_CLAUDE_PLUGIN_VERSION}`;
|
|
2593
|
+
var ORGX_CLAUDE_PLUGIN_MCP_URL = "https://mcp.useorgx.com/mcp?profile=claude-directory";
|
|
2594
|
+
var ALLOWED_FILES = [
|
|
2595
|
+
".claude-plugin/marketplace.json",
|
|
2596
|
+
".claude-plugin/plugin.json",
|
|
2597
|
+
".mcp.json",
|
|
2598
|
+
"commands/orgx-login.md",
|
|
2599
|
+
"commands/orgx-operator-chronicle.md",
|
|
2600
|
+
"commands/orgx-status.md",
|
|
2601
|
+
"skills/orgx-setup/SKILL.md"
|
|
2602
|
+
];
|
|
2603
|
+
var PROHIBITED_CONTENT = [
|
|
2604
|
+
{ label: "transcript access", pattern: /\btranscripts?\b/i },
|
|
2605
|
+
{
|
|
2606
|
+
label: "telemetry collection",
|
|
2607
|
+
pattern: /\b(?:collect|capture|record|send|upload|emit|track|enable|configure)\b[^\n]{0,80}\btelemetry\b/i
|
|
2608
|
+
},
|
|
2609
|
+
{
|
|
2610
|
+
label: "telemetry collection",
|
|
2611
|
+
pattern: /\btelemetry\b[^\n]{0,40}\b(?:collection|capture|recording|upload|emission|tracking|enabled)\b/i
|
|
2612
|
+
},
|
|
2613
|
+
{
|
|
2614
|
+
label: "telemetry collection",
|
|
2615
|
+
pattern: /\btelemetry\b\s*[:=]\s*true\b/i
|
|
2616
|
+
},
|
|
2617
|
+
{ label: "dynamic context sync", pattern: /dynamic(?:[\s_-]+context)?[\s_-]+sync/i },
|
|
2618
|
+
{ label: "runtime hook", pattern: /orgx-session-hook|emit-execution-graph|post-install\.sh/i }
|
|
2619
|
+
];
|
|
2620
|
+
var MANIFEST_CAPABILITY_FIELDS = [
|
|
2621
|
+
"agents",
|
|
2622
|
+
"commands",
|
|
2623
|
+
"hooks",
|
|
2624
|
+
"lspServers",
|
|
2625
|
+
"mcpServers",
|
|
2626
|
+
"skills"
|
|
2627
|
+
];
|
|
2628
|
+
var EXPECTED_PLUGIN_MANIFEST = {
|
|
2629
|
+
$schema: "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
2630
|
+
name: ORGX_CLAUDE_PLUGIN_NAME,
|
|
2631
|
+
displayName: "OrgX",
|
|
2632
|
+
version: ORGX_CLAUDE_PLUGIN_VERSION,
|
|
2633
|
+
description: "Connect Claude Code to a focused, non-destructive, closed-world OrgX status profile through native OAuth.",
|
|
2634
|
+
author: {
|
|
2635
|
+
name: "OrgX Team",
|
|
2636
|
+
email: "reviewers@useorgx.com",
|
|
2637
|
+
url: "https://useorgx.com"
|
|
2638
|
+
},
|
|
2639
|
+
homepage: "https://useorgx.com",
|
|
2640
|
+
repository: "https://github.com/useorgx/orgx-claude-code-plugin",
|
|
2641
|
+
license: "MIT",
|
|
2642
|
+
keywords: [
|
|
2643
|
+
"orgx",
|
|
2644
|
+
"mcp",
|
|
2645
|
+
"productivity",
|
|
2646
|
+
"status",
|
|
2647
|
+
"native-oauth"
|
|
2648
|
+
]
|
|
2649
|
+
};
|
|
2650
|
+
function parseJsonFile(files, path) {
|
|
2651
|
+
const bytes = files.get(path);
|
|
2652
|
+
if (!bytes) {
|
|
2653
|
+
throw new Error(`Rejected Claude plugin bundle: required file '${path}' is missing.`);
|
|
2654
|
+
}
|
|
2655
|
+
let value;
|
|
2656
|
+
try {
|
|
2657
|
+
value = JSON.parse(bytes.toString("utf8"));
|
|
2658
|
+
} catch {
|
|
2659
|
+
throw new Error(`Rejected Claude plugin bundle: '${path}' is not valid JSON.`);
|
|
2660
|
+
}
|
|
2661
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
2662
|
+
throw new Error(`Rejected Claude plugin bundle: '${path}' must contain a JSON object.`);
|
|
2663
|
+
}
|
|
2664
|
+
return value;
|
|
2665
|
+
}
|
|
2666
|
+
function assertExactKeys(value, expected, label) {
|
|
2667
|
+
const actualKeys = Object.keys(value).sort();
|
|
2668
|
+
const expectedKeys = [...expected].sort();
|
|
2669
|
+
if (actualKeys.length !== expectedKeys.length || actualKeys.some((key, index) => key !== expectedKeys[index])) {
|
|
2670
|
+
throw new Error(
|
|
2671
|
+
`Rejected Claude plugin bundle: ${label} must contain only ${expectedKeys.join(", ")}.`
|
|
2672
|
+
);
|
|
2673
|
+
}
|
|
2674
|
+
}
|
|
2675
|
+
function canonicalizeJson(value) {
|
|
2676
|
+
if (Array.isArray(value)) {
|
|
2677
|
+
return `[${value.map((item) => canonicalizeJson(item)).join(",")}]`;
|
|
2678
|
+
}
|
|
2679
|
+
if (value && typeof value === "object") {
|
|
2680
|
+
const entries = Object.entries(value).sort(([left], [right]) => left.localeCompare(right));
|
|
2681
|
+
return `{${entries.map(([key, item]) => `${JSON.stringify(key)}:${canonicalizeJson(item)}`).join(",")}}`;
|
|
2682
|
+
}
|
|
2683
|
+
return JSON.stringify(value) ?? "undefined";
|
|
2684
|
+
}
|
|
2685
|
+
function validateClaudePluginBundle(files) {
|
|
2686
|
+
const actualFiles = [...files.keys()].sort();
|
|
2687
|
+
const expectedFiles = [...ALLOWED_FILES].sort();
|
|
2688
|
+
const missingFiles = expectedFiles.filter((path) => !files.has(path));
|
|
2689
|
+
const unexpectedFiles = actualFiles.filter(
|
|
2690
|
+
(path) => !ALLOWED_FILES.includes(path)
|
|
2691
|
+
);
|
|
2692
|
+
if (missingFiles.length > 0 || unexpectedFiles.length > 0) {
|
|
2693
|
+
const details = [
|
|
2694
|
+
...missingFiles.length > 0 ? [`missing ${missingFiles.join(", ")}`] : [],
|
|
2695
|
+
...unexpectedFiles.length > 0 ? [`unexpected ${unexpectedFiles.join(", ")}`] : []
|
|
2696
|
+
].join("; ");
|
|
2697
|
+
throw new Error(`Rejected Claude plugin bundle: file set is not allowed (${details}).`);
|
|
2698
|
+
}
|
|
2699
|
+
const manifest = parseJsonFile(files, ".claude-plugin/plugin.json");
|
|
2700
|
+
if (manifest.name !== ORGX_CLAUDE_PLUGIN_NAME || manifest.version !== ORGX_CLAUDE_PLUGIN_VERSION) {
|
|
2701
|
+
throw new Error(
|
|
2702
|
+
`Rejected Claude plugin bundle: manifest must identify ${ORGX_CLAUDE_PLUGIN_NAME}@${ORGX_CLAUDE_PLUGIN_VERSION}.`
|
|
2703
|
+
);
|
|
2704
|
+
}
|
|
2705
|
+
const capabilityFields = MANIFEST_CAPABILITY_FIELDS.filter((field) => field in manifest);
|
|
2706
|
+
if (capabilityFields.length > 0) {
|
|
2707
|
+
throw new Error(
|
|
2708
|
+
`Rejected Claude plugin bundle: manifest cannot declare capability fields (${capabilityFields.join(", ")}).`
|
|
2709
|
+
);
|
|
2710
|
+
}
|
|
2711
|
+
if (canonicalizeJson(manifest) !== canonicalizeJson(EXPECTED_PLUGIN_MANIFEST)) {
|
|
2712
|
+
throw new Error(
|
|
2713
|
+
"Rejected Claude plugin bundle: manifest does not match the reviewed v0.1.12 metadata contract."
|
|
2714
|
+
);
|
|
2715
|
+
}
|
|
2716
|
+
const marketplace = parseJsonFile(files, ".claude-plugin/marketplace.json");
|
|
2717
|
+
if (marketplace.version !== ORGX_CLAUDE_PLUGIN_VERSION) {
|
|
2718
|
+
throw new Error(
|
|
2719
|
+
`Rejected Claude plugin bundle: marketplace version must be ${ORGX_CLAUDE_PLUGIN_VERSION}.`
|
|
2720
|
+
);
|
|
2721
|
+
}
|
|
2722
|
+
const mcp = parseJsonFile(files, ".mcp.json");
|
|
2723
|
+
assertExactKeys(mcp, ["mcpServers"], ".mcp.json");
|
|
2724
|
+
const mcpServers = mcp.mcpServers;
|
|
2725
|
+
if (!mcpServers || typeof mcpServers !== "object" || Array.isArray(mcpServers)) {
|
|
2726
|
+
throw new Error("Rejected Claude plugin bundle: mcpServers must be a JSON object.");
|
|
2727
|
+
}
|
|
2728
|
+
const servers = mcpServers;
|
|
2729
|
+
assertExactKeys(servers, ["orgx"], "mcpServers");
|
|
2730
|
+
const orgx = servers.orgx;
|
|
2731
|
+
if (!orgx || typeof orgx !== "object" || Array.isArray(orgx)) {
|
|
2732
|
+
throw new Error("Rejected Claude plugin bundle: the orgx MCP server must be a JSON object.");
|
|
2733
|
+
}
|
|
2734
|
+
const orgxServer = orgx;
|
|
2735
|
+
assertExactKeys(orgxServer, ["type", "url"], "the orgx MCP server");
|
|
2736
|
+
if (orgxServer.type !== "http" || orgxServer.url !== ORGX_CLAUDE_PLUGIN_MCP_URL) {
|
|
2737
|
+
throw new Error(
|
|
2738
|
+
"Rejected Claude plugin bundle: the orgx MCP server must match the reviewed closed-world status profile endpoint."
|
|
2739
|
+
);
|
|
2740
|
+
}
|
|
2741
|
+
const combinedContent = actualFiles.map((path) => files.get(path)?.toString("utf8") ?? "").join("\n");
|
|
2742
|
+
for (const prohibited of PROHIBITED_CONTENT) {
|
|
2743
|
+
if (prohibited.pattern.test(combinedContent)) {
|
|
2744
|
+
throw new Error(
|
|
2745
|
+
`Rejected Claude plugin bundle: prohibited ${prohibited.label} content was found.`
|
|
2746
|
+
);
|
|
2747
|
+
}
|
|
2748
|
+
}
|
|
2749
|
+
}
|
|
2750
|
+
|
|
2751
|
+
// src/lib/managed-plugin-tree.ts
|
|
2752
|
+
import {
|
|
2753
|
+
lstatSync,
|
|
2754
|
+
mkdirSync as mkdirSync2,
|
|
2755
|
+
mkdtempSync,
|
|
2756
|
+
readFileSync as readFileSync2,
|
|
2757
|
+
readlinkSync,
|
|
2758
|
+
readdirSync,
|
|
2759
|
+
renameSync,
|
|
2760
|
+
rmSync,
|
|
2761
|
+
writeFileSync as writeFileSync2
|
|
2762
|
+
} from "fs";
|
|
2763
|
+
import { dirname as dirname3, isAbsolute, join as join2, sep } from "path";
|
|
2764
|
+
function lstatIfExists(path) {
|
|
2765
|
+
try {
|
|
2766
|
+
return lstatSync(path);
|
|
2767
|
+
} catch (error) {
|
|
2768
|
+
const code = typeof error === "object" && error && "code" in error ? String(error.code) : void 0;
|
|
2769
|
+
if (code === "ENOENT" || code === "ENOTDIR") return null;
|
|
2770
|
+
throw error;
|
|
2771
|
+
}
|
|
2772
|
+
}
|
|
2773
|
+
function assertSafeRelativePath(path) {
|
|
2774
|
+
const segments = path.split(/[\\/]/);
|
|
2775
|
+
const hasUnsafeSegment = segments.some(
|
|
2776
|
+
(segment) => !segment || segment === "." || segment === ".."
|
|
2777
|
+
);
|
|
2778
|
+
if (isAbsolute(path) || hasUnsafeSegment) {
|
|
2779
|
+
throw new Error(`Refusing to sync managed plugin tree: unsafe destination path '${path}'.`);
|
|
2780
|
+
}
|
|
2781
|
+
}
|
|
2782
|
+
function occupiesExpectedManagedPath(relativePath, expectedPaths) {
|
|
2783
|
+
const descendantPrefix = `${relativePath}${sep}`;
|
|
2784
|
+
return [...expectedPaths].some(
|
|
2785
|
+
(expectedPath) => expectedPath === relativePath || expectedPath.startsWith(descendantPrefix)
|
|
2786
|
+
);
|
|
2787
|
+
}
|
|
2788
|
+
function readManagedTreeSnapshot(root, expectedPaths) {
|
|
2789
|
+
const rootStat = lstatIfExists(root);
|
|
2790
|
+
if (!rootStat) return null;
|
|
2791
|
+
if (rootStat.isSymbolicLink()) {
|
|
2792
|
+
throw new Error("Refusing to sync managed plugin tree: destination root is a symbolic link.");
|
|
2793
|
+
}
|
|
2794
|
+
if (!rootStat.isDirectory()) {
|
|
2795
|
+
throw new Error("Refusing to sync managed plugin tree: destination root is not a directory.");
|
|
2796
|
+
}
|
|
2797
|
+
const snapshot = {
|
|
2798
|
+
directories: /* @__PURE__ */ new Set(),
|
|
2799
|
+
files: /* @__PURE__ */ new Map(),
|
|
2800
|
+
symlinks: /* @__PURE__ */ new Map()
|
|
2801
|
+
};
|
|
2802
|
+
const visit = (directory, relativeDirectory) => {
|
|
2803
|
+
for (const name of readdirSync(directory)) {
|
|
2804
|
+
const path = join2(directory, name);
|
|
2805
|
+
const relativePath = relativeDirectory ? join2(relativeDirectory, name) : name;
|
|
2806
|
+
const entryStat = lstatSync(path);
|
|
2807
|
+
if (entryStat.isSymbolicLink()) {
|
|
2808
|
+
if (occupiesExpectedManagedPath(relativePath, expectedPaths)) {
|
|
2809
|
+
throw new Error(
|
|
2810
|
+
`Refusing to sync managed plugin tree: destination entry '${relativePath}' is a symbolic link.`
|
|
2811
|
+
);
|
|
2812
|
+
}
|
|
2813
|
+
snapshot.symlinks.set(relativePath, readlinkSync(path));
|
|
2814
|
+
continue;
|
|
2815
|
+
}
|
|
2816
|
+
if (entryStat.isDirectory()) {
|
|
2817
|
+
snapshot.directories.add(relativePath);
|
|
2818
|
+
visit(path, relativePath);
|
|
2819
|
+
continue;
|
|
2820
|
+
}
|
|
2821
|
+
if (entryStat.isFile()) {
|
|
2822
|
+
snapshot.files.set(relativePath, readFileSync2(path));
|
|
2823
|
+
continue;
|
|
2824
|
+
}
|
|
2825
|
+
throw new Error(
|
|
2826
|
+
`Refusing to sync managed plugin tree: destination entry '${relativePath}' is not a regular file or directory.`
|
|
2827
|
+
);
|
|
2828
|
+
}
|
|
2829
|
+
};
|
|
2830
|
+
visit(root, "");
|
|
2831
|
+
return snapshot;
|
|
2832
|
+
}
|
|
2833
|
+
function setsEqual(left, right) {
|
|
2834
|
+
return left.size === right.size && [...left].every((value) => right.has(value));
|
|
2835
|
+
}
|
|
2836
|
+
function snapshotsEqual(left, right) {
|
|
2837
|
+
if (!left || !right) return left === right;
|
|
2838
|
+
if (!setsEqual(left.directories, right.directories) || left.files.size !== right.files.size || left.symlinks.size !== right.symlinks.size) {
|
|
2839
|
+
return false;
|
|
2840
|
+
}
|
|
2841
|
+
const filesEqual = [...left.files].every(([path, bytes]) => {
|
|
2842
|
+
const other = right.files.get(path);
|
|
2843
|
+
return other !== void 0 && Buffer.compare(bytes, other) === 0;
|
|
2844
|
+
});
|
|
2845
|
+
if (!filesEqual) return false;
|
|
2846
|
+
return [...left.symlinks].every(
|
|
2847
|
+
([path, target]) => right.symlinks.get(path) === target
|
|
2848
|
+
);
|
|
2849
|
+
}
|
|
2850
|
+
function expectedDirectories(files) {
|
|
2851
|
+
const directories = /* @__PURE__ */ new Set();
|
|
2852
|
+
for (const file of files) {
|
|
2853
|
+
let current = dirname3(file.path);
|
|
2854
|
+
while (current !== "." && current !== "/") {
|
|
2855
|
+
directories.add(current);
|
|
2856
|
+
const parent = dirname3(current);
|
|
2857
|
+
if (parent === current) break;
|
|
2858
|
+
current = parent;
|
|
2859
|
+
}
|
|
2860
|
+
}
|
|
2861
|
+
return directories;
|
|
2862
|
+
}
|
|
2863
|
+
function snapshotMatchesFiles(snapshot, files) {
|
|
2864
|
+
if (!snapshot || snapshot.files.size !== files.length) return false;
|
|
2865
|
+
if (snapshot.symlinks.size > 0) return false;
|
|
2866
|
+
if (!setsEqual(snapshot.directories, expectedDirectories(files))) return false;
|
|
2867
|
+
return files.every((file) => {
|
|
2868
|
+
const existing = snapshot.files.get(file.path);
|
|
2869
|
+
return existing !== void 0 && Buffer.compare(existing, file.bytes) === 0;
|
|
2870
|
+
});
|
|
2871
|
+
}
|
|
2872
|
+
function stageAndReplaceManagedTree(destinationRoot, files, originalSnapshot, expectedPaths) {
|
|
2873
|
+
const destinationParent = dirname3(destinationRoot);
|
|
2874
|
+
mkdirSync2(destinationParent, { recursive: true });
|
|
2875
|
+
const transactionRoot = mkdtempSync(join2(destinationParent, ".orgx-plugin-sync-"));
|
|
2876
|
+
const nextRoot = join2(transactionRoot, "next");
|
|
2877
|
+
const previousRoot = join2(transactionRoot, "previous");
|
|
2878
|
+
let preserveTransaction = false;
|
|
2879
|
+
try {
|
|
2880
|
+
mkdirSync2(nextRoot);
|
|
2881
|
+
for (const file of files) {
|
|
2882
|
+
const destination = join2(nextRoot, file.path);
|
|
2883
|
+
mkdirSync2(dirname3(destination), { recursive: true });
|
|
2884
|
+
writeFileSync2(destination, file.bytes);
|
|
2885
|
+
}
|
|
2886
|
+
const latestSnapshot = readManagedTreeSnapshot(destinationRoot, expectedPaths);
|
|
2887
|
+
if (!snapshotsEqual(originalSnapshot, latestSnapshot)) {
|
|
2888
|
+
throw new Error("Refusing to sync managed plugin tree: destination changed during staging.");
|
|
2889
|
+
}
|
|
2890
|
+
let previousMoved = false;
|
|
2891
|
+
try {
|
|
2892
|
+
if (latestSnapshot) {
|
|
2893
|
+
renameSync(destinationRoot, previousRoot);
|
|
2894
|
+
previousMoved = true;
|
|
2895
|
+
}
|
|
2896
|
+
renameSync(nextRoot, destinationRoot);
|
|
2897
|
+
if (previousMoved) {
|
|
2898
|
+
rmSync(previousRoot, { force: true, recursive: true });
|
|
2899
|
+
previousMoved = false;
|
|
2900
|
+
}
|
|
2901
|
+
} catch (error) {
|
|
2902
|
+
if (previousMoved && !lstatIfExists(destinationRoot)) {
|
|
2903
|
+
try {
|
|
2904
|
+
renameSync(previousRoot, destinationRoot);
|
|
2905
|
+
previousMoved = false;
|
|
2906
|
+
} catch (rollbackError) {
|
|
2907
|
+
preserveTransaction = true;
|
|
2908
|
+
throw new AggregateError(
|
|
2909
|
+
[error, rollbackError],
|
|
2910
|
+
`Managed plugin replacement failed and rollback could not restore the prior tree. Recovery data remains at ${transactionRoot}.`
|
|
2911
|
+
);
|
|
2912
|
+
}
|
|
2913
|
+
}
|
|
2914
|
+
throw error;
|
|
2915
|
+
}
|
|
2916
|
+
} finally {
|
|
2917
|
+
if (!preserveTransaction) {
|
|
2918
|
+
rmSync(transactionRoot, { force: true, recursive: true });
|
|
2919
|
+
}
|
|
2920
|
+
}
|
|
2921
|
+
}
|
|
2922
|
+
function replaceManagedPluginTreeIfChanged(destinationRoot, files) {
|
|
2923
|
+
const paths = /* @__PURE__ */ new Set();
|
|
2924
|
+
for (const file of files) {
|
|
2925
|
+
assertSafeRelativePath(file.path);
|
|
2926
|
+
if (paths.has(file.path)) {
|
|
2927
|
+
throw new Error(`Refusing to sync managed plugin tree: duplicate destination path '${file.path}'.`);
|
|
2928
|
+
}
|
|
2929
|
+
paths.add(file.path);
|
|
2930
|
+
}
|
|
2931
|
+
const snapshot = readManagedTreeSnapshot(destinationRoot, paths);
|
|
2932
|
+
if (snapshotMatchesFiles(snapshot, files)) return false;
|
|
2933
|
+
stageAndReplaceManagedTree(destinationRoot, files, snapshot, paths);
|
|
2934
|
+
return true;
|
|
2935
|
+
}
|
|
2936
|
+
|
|
2564
2937
|
// src/lib/skills.ts
|
|
2565
2938
|
import { createHash as createHash2 } from "crypto";
|
|
2566
|
-
import { existsSync as existsSync3, readdirSync } from "fs";
|
|
2567
|
-
import { basename, join as
|
|
2939
|
+
import { existsSync as existsSync3, readdirSync as readdirSync2 } from "fs";
|
|
2940
|
+
import { basename, join as join3 } from "path";
|
|
2568
2941
|
var DEFAULT_ORGX_SKILL_PACKS = [
|
|
2569
2942
|
"morning-briefing",
|
|
2570
2943
|
"initiative-kickoff",
|
|
@@ -2662,7 +3035,7 @@ function defaultExtensionTitle(skillId, scope) {
|
|
|
2662
3035
|
return `${prefix} ${skillId} behavior`;
|
|
2663
3036
|
}
|
|
2664
3037
|
function extensionFilePath(skillId, scope, extensionsDir = ORGX_SKILL_EXTENSIONS_DIR) {
|
|
2665
|
-
return
|
|
3038
|
+
return join3(extensionsDir, `${scope}.${skillId}.md`);
|
|
2666
3039
|
}
|
|
2667
3040
|
function extensionTemplate(input) {
|
|
2668
3041
|
const body = input.content?.trim() ? input.content.trim() : [
|
|
@@ -2746,8 +3119,8 @@ function listSkillExtensions(options = {}) {
|
|
|
2746
3119
|
if (!existsSync3(extensionsDir)) {
|
|
2747
3120
|
return [];
|
|
2748
3121
|
}
|
|
2749
|
-
return
|
|
2750
|
-
const path =
|
|
3122
|
+
return readdirSync2(extensionsDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".md")).map((entry) => {
|
|
3123
|
+
const path = join3(extensionsDir, entry.name);
|
|
2751
3124
|
const content = readTextIfExists(path);
|
|
2752
3125
|
return content === null ? null : parseSkillExtension(path, content);
|
|
2753
3126
|
}).filter((entry) => Boolean(entry)).sort((left, right) => left.id.localeCompare(right.id));
|
|
@@ -3019,7 +3392,7 @@ async function installSkillPack(skillName, claudeSkillsDir, fetchImpl, ref, trac
|
|
|
3019
3392
|
const content = relativePath === "SKILL.md" ? composeSkillContent(skillName, coreContent, tracking.extensions) : coreContent;
|
|
3020
3393
|
writes.push(
|
|
3021
3394
|
writeManagedFile(
|
|
3022
|
-
|
|
3395
|
+
join3(claudeSkillsDir, skillName, relativePath),
|
|
3023
3396
|
content,
|
|
3024
3397
|
`${skillName}/${relativePath}`,
|
|
3025
3398
|
file.sourceUrl,
|
|
@@ -3158,8 +3531,6 @@ function getSkillStatus(options = {}) {
|
|
|
3158
3531
|
var DEFAULT_ORGX_PLUGIN_TARGETS = ["cursor", "claude", "codex", "openclaw"];
|
|
3159
3532
|
var ORGX_PLUGIN_GITHUB_OWNER = "useorgx";
|
|
3160
3533
|
var ORGX_PLUGIN_GITHUB_REF = "main";
|
|
3161
|
-
var ORGX_CLAUDE_PLUGIN_NAME = "orgx-claude-code-plugin";
|
|
3162
|
-
var ORGX_CLAUDE_MARKETPLACE_NAME = "orgx-local";
|
|
3163
3534
|
var ORGX_CODEX_PLUGIN_NAME = "orgx-codex-plugin";
|
|
3164
3535
|
var ORGX_CURSOR_PLUGIN_NAME = "cursor-plugin";
|
|
3165
3536
|
var ORGX_OPENCLAW_PLUGIN_ID = "orgx";
|
|
@@ -3167,16 +3538,14 @@ var ORGX_OPENCLAW_PLUGIN_PACKAGE_NAME = "@useorgx/openclaw-plugin";
|
|
|
3167
3538
|
var CLAUDE_PLUGIN_SYNC_SPEC = {
|
|
3168
3539
|
owner: ORGX_PLUGIN_GITHUB_OWNER,
|
|
3169
3540
|
repo: ORGX_CLAUDE_PLUGIN_NAME,
|
|
3170
|
-
ref:
|
|
3541
|
+
ref: ORGX_CLAUDE_PLUGIN_REF,
|
|
3171
3542
|
include: [
|
|
3172
3543
|
{ localPath: ".claude-plugin", remotePath: ".claude-plugin" },
|
|
3173
|
-
{ localPath: "
|
|
3544
|
+
{ localPath: ".mcp.json", remotePath: ".mcp.json" },
|
|
3174
3545
|
{ localPath: "commands", remotePath: "commands" },
|
|
3175
|
-
{ localPath: "hooks", remotePath: "hooks" },
|
|
3176
|
-
{ localPath: "lib", remotePath: "lib" },
|
|
3177
|
-
{ localPath: "scripts", remotePath: "scripts" },
|
|
3178
3546
|
{ localPath: "skills", remotePath: "skills" }
|
|
3179
|
-
]
|
|
3547
|
+
],
|
|
3548
|
+
validate: validateClaudePluginBundle
|
|
3180
3549
|
};
|
|
3181
3550
|
var CODEX_PLUGIN_SYNC_SPEC = {
|
|
3182
3551
|
owner: ORGX_PLUGIN_GITHUB_OWNER,
|
|
@@ -3299,7 +3668,7 @@ async function listRemoteRepoFiles(spec, path, localPath, fetchImpl) {
|
|
|
3299
3668
|
...await listRemoteRepoFiles(
|
|
3300
3669
|
spec,
|
|
3301
3670
|
entry.path,
|
|
3302
|
-
|
|
3671
|
+
join4(localPath, entry.name),
|
|
3303
3672
|
fetchImpl
|
|
3304
3673
|
)
|
|
3305
3674
|
);
|
|
@@ -3309,7 +3678,7 @@ async function listRemoteRepoFiles(spec, path, localPath, fetchImpl) {
|
|
|
3309
3678
|
throw new Error(`GitHub did not provide a download URL for '${entry.path}'.`);
|
|
3310
3679
|
}
|
|
3311
3680
|
files.push({
|
|
3312
|
-
localPath:
|
|
3681
|
+
localPath: join4(localPath, entry.name),
|
|
3313
3682
|
path: entry.path,
|
|
3314
3683
|
sourceUrl: entry.download_url
|
|
3315
3684
|
});
|
|
@@ -3345,88 +3714,25 @@ async function fetchRemoteBytes(sourceUrl, fetchImpl) {
|
|
|
3345
3714
|
}
|
|
3346
3715
|
return Buffer.from(await response.arrayBuffer());
|
|
3347
3716
|
}
|
|
3348
|
-
function readBytesIfExists(path) {
|
|
3349
|
-
if (!existsSync4(path)) return null;
|
|
3350
|
-
try {
|
|
3351
|
-
if (!statSync2(path).isFile()) {
|
|
3352
|
-
return null;
|
|
3353
|
-
}
|
|
3354
|
-
return readFileSync2(path);
|
|
3355
|
-
} catch (error) {
|
|
3356
|
-
const code = typeof error === "object" && error && "code" in error ? String(error.code) : void 0;
|
|
3357
|
-
if (code === "ENOENT" || code === "ENOTDIR" || code === "EISDIR") {
|
|
3358
|
-
return null;
|
|
3359
|
-
}
|
|
3360
|
-
throw error;
|
|
3361
|
-
}
|
|
3362
|
-
}
|
|
3363
|
-
function writeBytesIfChanged(path, bytes) {
|
|
3364
|
-
const existing = readBytesIfExists(path);
|
|
3365
|
-
if (existing && Buffer.compare(existing, bytes) === 0) {
|
|
3366
|
-
return false;
|
|
3367
|
-
}
|
|
3368
|
-
mkdirSync2(dirname3(path), { recursive: true });
|
|
3369
|
-
writeFileSync2(path, bytes);
|
|
3370
|
-
return true;
|
|
3371
|
-
}
|
|
3372
3717
|
function removePathIfExists(path) {
|
|
3373
3718
|
if (!existsSync4(path)) return false;
|
|
3374
|
-
|
|
3719
|
+
rmSync2(path, { force: true, recursive: true });
|
|
3375
3720
|
return true;
|
|
3376
3721
|
}
|
|
3377
|
-
function listRelativeFiles(root, base = root) {
|
|
3378
|
-
if (!existsSync4(root)) return [];
|
|
3379
|
-
if (!statSync2(root).isDirectory()) {
|
|
3380
|
-
return [];
|
|
3381
|
-
}
|
|
3382
|
-
const files = [];
|
|
3383
|
-
for (const entry of readdirSync2(root, { withFileTypes: true })) {
|
|
3384
|
-
const nextPath = join3(root, entry.name);
|
|
3385
|
-
if (entry.isDirectory()) {
|
|
3386
|
-
files.push(...listRelativeFiles(nextPath, base));
|
|
3387
|
-
continue;
|
|
3388
|
-
}
|
|
3389
|
-
if (entry.isFile()) {
|
|
3390
|
-
files.push(relative(base, nextPath));
|
|
3391
|
-
}
|
|
3392
|
-
}
|
|
3393
|
-
return files.sort();
|
|
3394
|
-
}
|
|
3395
|
-
function pruneEmptyDirectories(root, current = root) {
|
|
3396
|
-
if (!existsSync4(current) || !statSync2(current).isDirectory()) {
|
|
3397
|
-
return false;
|
|
3398
|
-
}
|
|
3399
|
-
let changed = false;
|
|
3400
|
-
for (const entry of readdirSync2(current, { withFileTypes: true })) {
|
|
3401
|
-
if (!entry.isDirectory()) continue;
|
|
3402
|
-
changed = pruneEmptyDirectories(root, join3(current, entry.name)) || changed;
|
|
3403
|
-
}
|
|
3404
|
-
if (current !== root && readdirSync2(current).length === 0) {
|
|
3405
|
-
rmSync(current, { force: true, recursive: true });
|
|
3406
|
-
return true;
|
|
3407
|
-
}
|
|
3408
|
-
return changed;
|
|
3409
|
-
}
|
|
3410
3722
|
async function syncManagedRepoTree(spec, destinationRoot, fetchImpl) {
|
|
3411
3723
|
const remoteFiles = await collectRemoteRepoFiles(spec, fetchImpl);
|
|
3412
|
-
|
|
3413
|
-
const expected = new Set(remoteFiles.map((file) => file.localPath));
|
|
3414
|
-
if (existsSync4(destinationRoot) && !statSync2(destinationRoot).isDirectory()) {
|
|
3415
|
-
rmSync(destinationRoot, { force: true, recursive: true });
|
|
3416
|
-
changed = true;
|
|
3417
|
-
}
|
|
3418
|
-
for (const file of listRelativeFiles(destinationRoot)) {
|
|
3419
|
-
if (expected.has(file)) continue;
|
|
3420
|
-
rmSync(join3(destinationRoot, file), { force: true });
|
|
3421
|
-
changed = true;
|
|
3422
|
-
}
|
|
3423
|
-
changed = pruneEmptyDirectories(destinationRoot) || changed;
|
|
3724
|
+
const fetchedFiles = [];
|
|
3424
3725
|
for (const file of remoteFiles) {
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
}
|
|
3726
|
+
fetchedFiles.push({
|
|
3727
|
+
...file,
|
|
3728
|
+
bytes: await fetchRemoteBytes(file.sourceUrl, fetchImpl)
|
|
3729
|
+
});
|
|
3429
3730
|
}
|
|
3731
|
+
spec.validate?.(new Map(fetchedFiles.map((file) => [file.localPath, file.bytes])));
|
|
3732
|
+
const changed = replaceManagedPluginTreeIfChanged(
|
|
3733
|
+
destinationRoot,
|
|
3734
|
+
fetchedFiles.map((file) => ({ path: file.localPath, bytes: file.bytes }))
|
|
3735
|
+
);
|
|
3430
3736
|
return { changed, fileCount: remoteFiles.length };
|
|
3431
3737
|
}
|
|
3432
3738
|
function serializeJson(value) {
|
|
@@ -3439,8 +3745,8 @@ function writeJsonIfChanged(path, value) {
|
|
|
3439
3745
|
if (existing === next) {
|
|
3440
3746
|
return false;
|
|
3441
3747
|
}
|
|
3442
|
-
|
|
3443
|
-
|
|
3748
|
+
mkdirSync3(dirname4(path), { recursive: true });
|
|
3749
|
+
writeFileSync3(path, next, "utf8");
|
|
3444
3750
|
return true;
|
|
3445
3751
|
}
|
|
3446
3752
|
function buildClaudeMarketplaceManifest() {
|
|
@@ -3454,7 +3760,7 @@ function buildClaudeMarketplaceManifest() {
|
|
|
3454
3760
|
plugins: [
|
|
3455
3761
|
{
|
|
3456
3762
|
name: ORGX_CLAUDE_PLUGIN_NAME,
|
|
3457
|
-
description: "
|
|
3763
|
+
description: "Connect Claude Code to a focused, non-destructive, closed-world OrgX status profile through native OAuth.",
|
|
3458
3764
|
source: `./plugins/${ORGX_CLAUDE_PLUGIN_NAME}`
|
|
3459
3765
|
}
|
|
3460
3766
|
]
|
|
@@ -3511,7 +3817,7 @@ function removeCodexMarketplaceEntry(path) {
|
|
|
3511
3817
|
return false;
|
|
3512
3818
|
}
|
|
3513
3819
|
if (nextPlugins.length === 0) {
|
|
3514
|
-
|
|
3820
|
+
rmSync2(path, { force: true });
|
|
3515
3821
|
return true;
|
|
3516
3822
|
}
|
|
3517
3823
|
return writeJsonIfChanged(path, {
|
|
@@ -3523,16 +3829,21 @@ function codexMarketplaceHasOrgxEntry(path) {
|
|
|
3523
3829
|
const { plugins } = readMarketplacePlugins(path);
|
|
3524
3830
|
return plugins.some((plugin) => plugin.name === ORGX_CODEX_PLUGIN_NAME);
|
|
3525
3831
|
}
|
|
3526
|
-
function
|
|
3832
|
+
function extractClaudePluginInstallations(payload) {
|
|
3527
3833
|
try {
|
|
3528
3834
|
const parsed = JSON.parse(payload);
|
|
3529
3835
|
if (!Array.isArray(parsed)) return [];
|
|
3530
3836
|
return parsed.flatMap((entry) => {
|
|
3531
|
-
if (typeof entry === "string") return [entry];
|
|
3837
|
+
if (typeof entry === "string") return [{ id: entry }];
|
|
3532
3838
|
if (!entry || typeof entry !== "object") return [];
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
return [];
|
|
3839
|
+
const item = entry;
|
|
3840
|
+
const id = typeof item.id === "string" ? item.id : typeof item.name === "string" ? item.name : void 0;
|
|
3841
|
+
if (!id) return [];
|
|
3842
|
+
return [{
|
|
3843
|
+
id,
|
|
3844
|
+
...typeof item.scope === "string" ? { scope: item.scope } : {},
|
|
3845
|
+
...typeof item.version === "string" ? { version: item.version } : {}
|
|
3846
|
+
}];
|
|
3536
3847
|
});
|
|
3537
3848
|
} catch {
|
|
3538
3849
|
return [];
|
|
@@ -3617,11 +3928,30 @@ async function getClaudeInstallState(runner) {
|
|
|
3617
3928
|
if (result.exitCode !== 0) {
|
|
3618
3929
|
return { available: true, installed: false };
|
|
3619
3930
|
}
|
|
3931
|
+
const managedPluginId = `${ORGX_CLAUDE_PLUGIN_NAME}@${ORGX_CLAUDE_MARKETPLACE_NAME}`;
|
|
3932
|
+
const installation = extractClaudePluginInstallations(result.stdout).find(
|
|
3933
|
+
(plugin) => plugin.id === managedPluginId && plugin.scope === "user"
|
|
3934
|
+
);
|
|
3620
3935
|
return {
|
|
3621
3936
|
available: true,
|
|
3622
|
-
installed:
|
|
3937
|
+
installed: Boolean(installation),
|
|
3938
|
+
...installation?.version ? { version: installation.version } : {}
|
|
3623
3939
|
};
|
|
3624
3940
|
}
|
|
3941
|
+
async function requireManagedClaudePluginVersion(runner, operation) {
|
|
3942
|
+
const state = await getClaudeInstallState(runner);
|
|
3943
|
+
if (!state.installed) {
|
|
3944
|
+
throw new Error(
|
|
3945
|
+
`Claude plugin ${operation} completed, but Claude Code does not report ${ORGX_CLAUDE_PLUGIN_NAME}@${ORGX_CLAUDE_MARKETPLACE_NAME} as installed at user scope.`
|
|
3946
|
+
);
|
|
3947
|
+
}
|
|
3948
|
+
if (state.version !== ORGX_CLAUDE_PLUGIN_VERSION) {
|
|
3949
|
+
throw new Error(
|
|
3950
|
+
`Claude plugin ${operation} completed, but Claude Code reports version ${state.version ?? "unknown"}; expected ${ORGX_CLAUDE_PLUGIN_VERSION}.`
|
|
3951
|
+
);
|
|
3952
|
+
}
|
|
3953
|
+
return state;
|
|
3954
|
+
}
|
|
3625
3955
|
async function getOpenclawInstallState(runner) {
|
|
3626
3956
|
const available = detectSurface("openclaw").detected || await commandExists("openclaw", runner);
|
|
3627
3957
|
if (!available) {
|
|
@@ -3637,17 +3967,17 @@ async function getOpenclawInstallState(runner) {
|
|
|
3637
3967
|
};
|
|
3638
3968
|
}
|
|
3639
3969
|
function cursorPluginManifestPath(paths) {
|
|
3640
|
-
return
|
|
3970
|
+
return join4(paths.cursorPluginDir, ".cursor-plugin", "plugin.json");
|
|
3641
3971
|
}
|
|
3642
3972
|
function cursorPluginMcpPath(paths) {
|
|
3643
|
-
return
|
|
3973
|
+
return join4(paths.cursorPluginDir, ".mcp.json");
|
|
3644
3974
|
}
|
|
3645
3975
|
function isCursorPluginInstalled(paths) {
|
|
3646
3976
|
return existsSync4(cursorPluginManifestPath(paths)) && existsSync4(cursorPluginMcpPath(paths));
|
|
3647
3977
|
}
|
|
3648
3978
|
function getCursorToolingState(options = {}) {
|
|
3649
3979
|
const paths = resolvePluginPaths(options.paths);
|
|
3650
|
-
const mcpFile = options.mcpPath ?? CURSOR_MCP_PATH ??
|
|
3980
|
+
const mcpFile = options.mcpPath ?? CURSOR_MCP_PATH ?? join4(CURSOR_DIR, "mcp.json");
|
|
3651
3981
|
const mcpText = readTextIfExists(mcpFile);
|
|
3652
3982
|
const inspection = inspectCursorMcpConfig(mcpText);
|
|
3653
3983
|
return {
|
|
@@ -3657,7 +3987,7 @@ function getCursorToolingState(options = {}) {
|
|
|
3657
3987
|
};
|
|
3658
3988
|
}
|
|
3659
3989
|
function isCursorPluginAvailable(paths) {
|
|
3660
|
-
return detectSurface("cursor").detected || existsSync4(paths.cursorPluginDir) || existsSync4(
|
|
3990
|
+
return detectSurface("cursor").detected || existsSync4(paths.cursorPluginDir) || existsSync4(dirname4(paths.cursorPluginDir)) || readTextIfExists(paths.cursorRulePath) !== null;
|
|
3661
3991
|
}
|
|
3662
3992
|
function buildCursorStatus(paths) {
|
|
3663
3993
|
const existingRules = readTextIfExists(paths.cursorRulePath);
|
|
@@ -3843,36 +4173,44 @@ async function installClaudePlugin(paths, fetchImpl, runner) {
|
|
|
3843
4173
|
throw new Error(formatCommandFailure("claude", ["plugin", "marketplace", "add", paths.claudeMarketplaceDir], marketplaceAdd));
|
|
3844
4174
|
}
|
|
3845
4175
|
let installedChanged = false;
|
|
4176
|
+
let updatedChanged = false;
|
|
3846
4177
|
if (!state.installed) {
|
|
3847
|
-
const
|
|
4178
|
+
const installArgs = [
|
|
3848
4179
|
"plugin",
|
|
3849
4180
|
"install",
|
|
3850
4181
|
`${ORGX_CLAUDE_PLUGIN_NAME}@${ORGX_CLAUDE_MARKETPLACE_NAME}`,
|
|
3851
4182
|
"--scope",
|
|
3852
4183
|
"user"
|
|
3853
|
-
]
|
|
4184
|
+
];
|
|
4185
|
+
const install = await runner("claude", installArgs);
|
|
3854
4186
|
if (install.exitCode !== 0) {
|
|
3855
4187
|
throw new Error(
|
|
3856
|
-
formatCommandFailure(
|
|
3857
|
-
"claude",
|
|
3858
|
-
[
|
|
3859
|
-
"plugin",
|
|
3860
|
-
"install",
|
|
3861
|
-
`${ORGX_CLAUDE_PLUGIN_NAME}@${ORGX_CLAUDE_MARKETPLACE_NAME}`,
|
|
3862
|
-
"--scope",
|
|
3863
|
-
"user"
|
|
3864
|
-
],
|
|
3865
|
-
install
|
|
3866
|
-
)
|
|
4188
|
+
formatCommandFailure("claude", installArgs, install)
|
|
3867
4189
|
);
|
|
3868
4190
|
}
|
|
4191
|
+
await requireManagedClaudePluginVersion(runner, "install");
|
|
3869
4192
|
installedChanged = true;
|
|
4193
|
+
} else {
|
|
4194
|
+
const updateArgs = [
|
|
4195
|
+
"plugin",
|
|
4196
|
+
"update",
|
|
4197
|
+
`${ORGX_CLAUDE_PLUGIN_NAME}@${ORGX_CLAUDE_MARKETPLACE_NAME}`,
|
|
4198
|
+
"--scope",
|
|
4199
|
+
"user"
|
|
4200
|
+
];
|
|
4201
|
+
const update = await runner("claude", updateArgs);
|
|
4202
|
+
if (update.exitCode !== 0) {
|
|
4203
|
+
throw new Error(formatCommandFailure("claude", updateArgs, update));
|
|
4204
|
+
}
|
|
4205
|
+
await requireManagedClaudePluginVersion(runner, "update");
|
|
4206
|
+
updatedChanged = state.version !== ORGX_CLAUDE_PLUGIN_VERSION;
|
|
3870
4207
|
}
|
|
3871
|
-
const changed = syncResult.changed || manifestChanged || installedChanged;
|
|
4208
|
+
const changed = syncResult.changed || manifestChanged || installedChanged || updatedChanged;
|
|
4209
|
+
const operationMessage = installedChanged ? `installed version ${ORGX_CLAUDE_PLUGIN_VERSION}` : updatedChanged ? `updated the Claude cache from ${state.version ?? "an older version"} to ${ORGX_CLAUDE_PLUGIN_VERSION}` : "confirmed the Claude cache is current";
|
|
3872
4210
|
return {
|
|
3873
4211
|
target: "claude",
|
|
3874
4212
|
changed,
|
|
3875
|
-
message: changed ? `Synced ${syncResult.fileCount} Claude plugin files and
|
|
4213
|
+
message: changed ? `Synced ${syncResult.fileCount} Claude plugin files and ${operationMessage}.` : `Claude Code plugin ${ORGX_CLAUDE_PLUGIN_VERSION} is already installed and up to date.`
|
|
3876
4214
|
};
|
|
3877
4215
|
}
|
|
3878
4216
|
async function installCodexPlugin(paths, fetchImpl, runner) {
|
|
@@ -3911,10 +4249,10 @@ async function installOpenclawPlugin(fetchImpl, runner) {
|
|
|
3911
4249
|
}
|
|
3912
4250
|
const { tarballUrl, version } = await resolveOpenclawTarball(fetchImpl);
|
|
3913
4251
|
const tarballBytes = await fetchRemoteBytes(tarballUrl, fetchImpl);
|
|
3914
|
-
const tempRoot =
|
|
3915
|
-
const archivePath =
|
|
4252
|
+
const tempRoot = mkdtempSync2(join4(tmpdir(), "orgx-wizard-openclaw-"));
|
|
4253
|
+
const archivePath = join4(tempRoot, `orgx-openclaw-plugin-${version}.tgz`);
|
|
3916
4254
|
try {
|
|
3917
|
-
|
|
4255
|
+
writeFileSync3(archivePath, tarballBytes);
|
|
3918
4256
|
const install = await runner("openclaw", ["plugins", "install", archivePath]);
|
|
3919
4257
|
if (install.exitCode !== 0) {
|
|
3920
4258
|
throw new Error(
|
|
@@ -3922,7 +4260,7 @@ async function installOpenclawPlugin(fetchImpl, runner) {
|
|
|
3922
4260
|
);
|
|
3923
4261
|
}
|
|
3924
4262
|
} finally {
|
|
3925
|
-
|
|
4263
|
+
rmSync2(tempRoot, { force: true, recursive: true });
|
|
3926
4264
|
}
|
|
3927
4265
|
return {
|
|
3928
4266
|
target: "openclaw",
|
|
@@ -4096,6 +4434,134 @@ function countPluginReportChanges(report) {
|
|
|
4096
4434
|
return report.results.filter((result) => result.changed).length;
|
|
4097
4435
|
}
|
|
4098
4436
|
|
|
4437
|
+
// src/surfaces/deepseek.ts
|
|
4438
|
+
import { spawnSync as spawnSync3 } from "child_process";
|
|
4439
|
+
var DEEPSEEK_HARNESS_VERSION = "0.1.0-rc.6";
|
|
4440
|
+
var DEEPSEEK_ORGX_PLUGIN = "@useorgx/deepseek-harness-plugin";
|
|
4441
|
+
var DEEPSEEK_ORGX_PLUGIN_VERSION = "0.1.0";
|
|
4442
|
+
var DEEPSEEK_PROFILE = "headless";
|
|
4443
|
+
var runDeepseekCommand = (command, args) => {
|
|
4444
|
+
const result = spawnSync3(command, [...args], {
|
|
4445
|
+
encoding: "utf8",
|
|
4446
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
4447
|
+
timeout: 3e4
|
|
4448
|
+
});
|
|
4449
|
+
return {
|
|
4450
|
+
status: result.status,
|
|
4451
|
+
stdout: result.stdout ?? "",
|
|
4452
|
+
stderr: result.stderr ?? "",
|
|
4453
|
+
...result.error ? { error: result.error } : {}
|
|
4454
|
+
};
|
|
4455
|
+
};
|
|
4456
|
+
function normalizeVersionOutput(value) {
|
|
4457
|
+
const normalized = value.trim();
|
|
4458
|
+
return /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(normalized) ? normalized : void 0;
|
|
4459
|
+
}
|
|
4460
|
+
function inspectDeepseekRuntime(runner = runDeepseekCommand) {
|
|
4461
|
+
const result = runner("dsh", ["--version"]);
|
|
4462
|
+
const version = normalizeVersionOutput(result.stdout);
|
|
4463
|
+
if (result.status !== 0 || !version) {
|
|
4464
|
+
return {
|
|
4465
|
+
installed: false,
|
|
4466
|
+
supported: false,
|
|
4467
|
+
details: [
|
|
4468
|
+
result.error?.message ?? (result.stderr.trim() || "dsh --version did not return a version")
|
|
4469
|
+
]
|
|
4470
|
+
};
|
|
4471
|
+
}
|
|
4472
|
+
const supported = version === DEEPSEEK_HARNESS_VERSION;
|
|
4473
|
+
return {
|
|
4474
|
+
installed: true,
|
|
4475
|
+
supported,
|
|
4476
|
+
version,
|
|
4477
|
+
details: [
|
|
4478
|
+
supported ? `DeepSeek Harness ${version} detected` : `DeepSeek Harness ${version} detected; OrgX currently requires ${DEEPSEEK_HARNESS_VERSION}`
|
|
4479
|
+
]
|
|
4480
|
+
};
|
|
4481
|
+
}
|
|
4482
|
+
function readDependencyVersion(raw) {
|
|
4483
|
+
if (!raw) return void 0;
|
|
4484
|
+
try {
|
|
4485
|
+
const parsed = JSON.parse(raw);
|
|
4486
|
+
for (const key of ["dependencies", "devDependencies", "optionalDependencies"]) {
|
|
4487
|
+
const dependencies = parsed[key];
|
|
4488
|
+
if (!dependencies || typeof dependencies !== "object" || Array.isArray(dependencies)) {
|
|
4489
|
+
continue;
|
|
4490
|
+
}
|
|
4491
|
+
const version = dependencies[DEEPSEEK_ORGX_PLUGIN];
|
|
4492
|
+
if (typeof version === "string" && version.trim()) return version.trim();
|
|
4493
|
+
}
|
|
4494
|
+
} catch {
|
|
4495
|
+
return void 0;
|
|
4496
|
+
}
|
|
4497
|
+
return void 0;
|
|
4498
|
+
}
|
|
4499
|
+
function inspectDeepseekPlugin(profileManifestPath) {
|
|
4500
|
+
const version = readDependencyVersion(readTextIfExists(profileManifestPath));
|
|
4501
|
+
return {
|
|
4502
|
+
installed: Boolean(version),
|
|
4503
|
+
...version ? { version } : {},
|
|
4504
|
+
details: [
|
|
4505
|
+
version ? `${DEEPSEEK_ORGX_PLUGIN} ${version} is installed in the ${DEEPSEEK_PROFILE} profile` : `${DEEPSEEK_ORGX_PLUGIN} is not installed in the ${DEEPSEEK_PROFILE} profile`
|
|
4506
|
+
]
|
|
4507
|
+
};
|
|
4508
|
+
}
|
|
4509
|
+
function installDeepseekPlugin(profileManifestPath, runner = runDeepseekCommand) {
|
|
4510
|
+
const runtime = inspectDeepseekRuntime(runner);
|
|
4511
|
+
if (!runtime.installed) {
|
|
4512
|
+
return {
|
|
4513
|
+
changed: false,
|
|
4514
|
+
message: `DeepSeek Harness was not found. Install @deepseek-ai/dsh@${DEEPSEEK_HARNESS_VERSION}, then run setup again.`
|
|
4515
|
+
};
|
|
4516
|
+
}
|
|
4517
|
+
if (!runtime.supported) {
|
|
4518
|
+
return {
|
|
4519
|
+
changed: false,
|
|
4520
|
+
message: `DeepSeek Harness ${runtime.version ?? "unknown"} is not supported; OrgX requires ${DEEPSEEK_HARNESS_VERSION}.`
|
|
4521
|
+
};
|
|
4522
|
+
}
|
|
4523
|
+
const before = inspectDeepseekPlugin(profileManifestPath);
|
|
4524
|
+
if (before.installed && before.version === DEEPSEEK_ORGX_PLUGIN_VERSION) {
|
|
4525
|
+
return {
|
|
4526
|
+
changed: false,
|
|
4527
|
+
message: `${DEEPSEEK_ORGX_PLUGIN}@${DEEPSEEK_ORGX_PLUGIN_VERSION} is already installed.`
|
|
4528
|
+
};
|
|
4529
|
+
}
|
|
4530
|
+
const spec = `${DEEPSEEK_ORGX_PLUGIN}@${DEEPSEEK_ORGX_PLUGIN_VERSION}`;
|
|
4531
|
+
const result = runner("dsh", ["plugin", "--profile", DEEPSEEK_PROFILE, "add", spec]);
|
|
4532
|
+
if (result.status !== 0) {
|
|
4533
|
+
const detail = result.stderr.trim() || result.error?.message || `exit ${result.status ?? "unknown"}`;
|
|
4534
|
+
throw new Error(`Could not install ${spec}: ${detail}`);
|
|
4535
|
+
}
|
|
4536
|
+
return {
|
|
4537
|
+
changed: true,
|
|
4538
|
+
message: `${spec} installed in the ${DEEPSEEK_PROFILE} profile.`
|
|
4539
|
+
};
|
|
4540
|
+
}
|
|
4541
|
+
function removeDeepseekPlugin(profileManifestPath, runner = runDeepseekCommand) {
|
|
4542
|
+
if (!inspectDeepseekPlugin(profileManifestPath).installed) {
|
|
4543
|
+
return {
|
|
4544
|
+
changed: false,
|
|
4545
|
+
message: `${DEEPSEEK_ORGX_PLUGIN} is not installed.`
|
|
4546
|
+
};
|
|
4547
|
+
}
|
|
4548
|
+
const result = runner("dsh", [
|
|
4549
|
+
"plugin",
|
|
4550
|
+
"--profile",
|
|
4551
|
+
DEEPSEEK_PROFILE,
|
|
4552
|
+
"remove",
|
|
4553
|
+
DEEPSEEK_ORGX_PLUGIN
|
|
4554
|
+
]);
|
|
4555
|
+
if (result.status !== 0) {
|
|
4556
|
+
const detail = result.stderr.trim() || result.error?.message || `exit ${result.status ?? "unknown"}`;
|
|
4557
|
+
throw new Error(`Could not remove ${DEEPSEEK_ORGX_PLUGIN}: ${detail}`);
|
|
4558
|
+
}
|
|
4559
|
+
return {
|
|
4560
|
+
changed: true,
|
|
4561
|
+
message: `${DEEPSEEK_ORGX_PLUGIN} removed from the ${DEEPSEEK_PROFILE} profile.`
|
|
4562
|
+
};
|
|
4563
|
+
}
|
|
4564
|
+
|
|
4099
4565
|
// src/surfaces/registry.ts
|
|
4100
4566
|
var AUTH_SETUP_HINT = "orgx-wizard auth login";
|
|
4101
4567
|
var AUTH_SET_KEY_HINT = "orgx-wizard auth set-key";
|
|
@@ -4130,6 +4596,19 @@ function automatedSurfaceStatus(name) {
|
|
|
4130
4596
|
const detection = detectSurface(name);
|
|
4131
4597
|
const path = detection.existingPath ?? detection.preferredPath;
|
|
4132
4598
|
const openclaw = getOpenClawDependencyState();
|
|
4599
|
+
if (name === "deepseek") {
|
|
4600
|
+
const runtime = inspectDeepseekRuntime();
|
|
4601
|
+
const plugin = path ? inspectDeepseekPlugin(path) : { installed: false, details: ["DeepSeek profile path is unavailable"] };
|
|
4602
|
+
return {
|
|
4603
|
+
name,
|
|
4604
|
+
mode: "automated",
|
|
4605
|
+
detected: detection.detected || runtime.installed,
|
|
4606
|
+
configured: runtime.supported && plugin.installed,
|
|
4607
|
+
...path ? { path } : {},
|
|
4608
|
+
details: [...runtime.details, ...plugin.details, ...detection.evidence],
|
|
4609
|
+
summary: !runtime.installed ? "DeepSeek Harness was not detected." : !runtime.supported ? "DeepSeek Harness is installed, but the version is not supported by the OrgX plugin." : plugin.installed ? "OrgX is installed in the DeepSeek Harness headless profile." : "DeepSeek Harness is ready for the OrgX plugin."
|
|
4610
|
+
};
|
|
4611
|
+
}
|
|
4133
4612
|
if (name === "claude") {
|
|
4134
4613
|
const inspection2 = inspectClaudeMcpConfig(path ? readTextIfExists(path) : null);
|
|
4135
4614
|
const configured = inspection2.hostedConfigured === true && (openclaw.detected ? inspection2.localConfigured === true : true);
|
|
@@ -4417,6 +4896,15 @@ async function addAutomatedSurface(name) {
|
|
|
4417
4896
|
message: openclaw.detected ? "OrgX is connected in Codex with the local OpenClaw bridge." : "OrgX cloud MCP is connected in Codex."
|
|
4418
4897
|
};
|
|
4419
4898
|
}
|
|
4899
|
+
case "deepseek": {
|
|
4900
|
+
const result = installDeepseekPlugin(path);
|
|
4901
|
+
return {
|
|
4902
|
+
name,
|
|
4903
|
+
changed: result.changed,
|
|
4904
|
+
path,
|
|
4905
|
+
message: result.message
|
|
4906
|
+
};
|
|
4907
|
+
}
|
|
4420
4908
|
case "openclaw": {
|
|
4421
4909
|
const previous = readTextIfExists(path);
|
|
4422
4910
|
const auth = await resolveOrgxAuth();
|
|
@@ -4514,6 +5002,15 @@ function removeAutomatedSurface(name) {
|
|
|
4514
5002
|
message: "OrgX connection was removed from Codex."
|
|
4515
5003
|
};
|
|
4516
5004
|
}
|
|
5005
|
+
case "deepseek": {
|
|
5006
|
+
const result = removeDeepseekPlugin(path);
|
|
5007
|
+
return {
|
|
5008
|
+
name,
|
|
5009
|
+
changed: result.changed,
|
|
5010
|
+
path,
|
|
5011
|
+
message: result.message
|
|
5012
|
+
};
|
|
5013
|
+
}
|
|
4517
5014
|
case "openclaw": {
|
|
4518
5015
|
const previous = readTextIfExists(path);
|
|
4519
5016
|
const next = removeOpenClawConfig(previous);
|
|
@@ -5247,8 +5744,8 @@ async function ensureOnboardingTask(workspace, options = {}) {
|
|
|
5247
5744
|
|
|
5248
5745
|
// src/lib/local-skill-discovery.ts
|
|
5249
5746
|
import { createHash as createHash3 } from "crypto";
|
|
5250
|
-
import { readdirSync as readdirSync3, readFileSync as readFileSync3, statSync as
|
|
5251
|
-
import { basename as basename2, join as
|
|
5747
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync3, statSync as statSync2 } from "fs";
|
|
5748
|
+
import { basename as basename2, join as join5, relative } from "path";
|
|
5252
5749
|
var DEFAULT_MAX_BYTES = 48e3;
|
|
5253
5750
|
var DEFAULT_LIMIT = 12;
|
|
5254
5751
|
var IGNORED_DIRS = /* @__PURE__ */ new Set([".git", ".next", ".turbo", "build", "dist", "node_modules"]);
|
|
@@ -5266,26 +5763,26 @@ function hash(value, length = 10) {
|
|
|
5266
5763
|
}
|
|
5267
5764
|
function safeStat(path) {
|
|
5268
5765
|
try {
|
|
5269
|
-
return
|
|
5766
|
+
return statSync2(path);
|
|
5270
5767
|
} catch {
|
|
5271
5768
|
return null;
|
|
5272
5769
|
}
|
|
5273
5770
|
}
|
|
5274
5771
|
function defaultRoots(input) {
|
|
5275
5772
|
return {
|
|
5276
|
-
agents: [
|
|
5277
|
-
claude: [
|
|
5278
|
-
codex: [
|
|
5773
|
+
agents: [join5(input.home, ".agents", "skills")],
|
|
5774
|
+
claude: [join5(input.home, ".claude", "skills"), join5(input.cwd, ".claude", "skills")],
|
|
5775
|
+
codex: [join5(input.home, ".codex", "skills"), join5(input.cwd, ".codex", "skills")],
|
|
5279
5776
|
opencode: [
|
|
5280
|
-
|
|
5281
|
-
|
|
5282
|
-
|
|
5283
|
-
|
|
5777
|
+
join5(input.home, ".opencode", "skills"),
|
|
5778
|
+
join5(input.home, ".config", "opencode", "skills"),
|
|
5779
|
+
join5(input.home, "Library", "Application Support", "opencode", "skills"),
|
|
5780
|
+
join5(input.cwd, ".opencode", "skills")
|
|
5284
5781
|
],
|
|
5285
5782
|
workspace: [
|
|
5286
|
-
|
|
5287
|
-
|
|
5288
|
-
|
|
5783
|
+
join5(input.cwd, "skills"),
|
|
5784
|
+
join5(input.cwd, ".agents", "skills"),
|
|
5785
|
+
join5(input.cwd, ".orgx", "skills")
|
|
5289
5786
|
]
|
|
5290
5787
|
};
|
|
5291
5788
|
}
|
|
@@ -5307,7 +5804,7 @@ function walkSkillFiles(root, maxFiles = 200) {
|
|
|
5307
5804
|
}
|
|
5308
5805
|
for (const entry of entries) {
|
|
5309
5806
|
if (IGNORED_DIRS.has(entry.name)) continue;
|
|
5310
|
-
const path =
|
|
5807
|
+
const path = join5(current, entry.name);
|
|
5311
5808
|
if (entry.isDirectory()) {
|
|
5312
5809
|
stack.push(path);
|
|
5313
5810
|
} else if (entry.isFile() && /\.(md|mdc|txt)$/i.test(entry.name)) {
|
|
@@ -5438,7 +5935,7 @@ function buildLocalSkillExtensionContent(candidates, context) {
|
|
|
5438
5935
|
"",
|
|
5439
5936
|
`## ${candidate.title}`,
|
|
5440
5937
|
"",
|
|
5441
|
-
`- Source: ${candidate.source} (${
|
|
5938
|
+
`- Source: ${candidate.source} (${relative(process.cwd(), candidate.path)})`,
|
|
5442
5939
|
`- Suggested agents: ${candidate.agentDomains.join(", ")}`,
|
|
5443
5940
|
`- Preserve: ${candidate.snippet || "local workflow preference from this skill file."}`
|
|
5444
5941
|
);
|
|
@@ -5714,7 +6211,7 @@ function initializeWizardSentry() {
|
|
|
5714
6211
|
Sentry.init({
|
|
5715
6212
|
dsn,
|
|
5716
6213
|
environment: process.env.ORGX_SENTRY_ENVIRONMENT || "production",
|
|
5717
|
-
release:
|
|
6214
|
+
release: "useorgx-wizard@0.1.55",
|
|
5718
6215
|
tracesSampleRate: sampleRate(process.env.ORGX_SENTRY_TRACES_SAMPLE_RATE),
|
|
5719
6216
|
enableLogs: true,
|
|
5720
6217
|
sendDefaultPii: false,
|
|
@@ -6432,8 +6929,8 @@ async function fetchOnboardingState(auth) {
|
|
|
6432
6929
|
}
|
|
6433
6930
|
|
|
6434
6931
|
// src/lib/ai-session-import.ts
|
|
6435
|
-
import { existsSync as existsSync6, readdirSync as readdirSync4, readFileSync as readFileSync4, statSync as
|
|
6436
|
-
import { basename as basename3, join as
|
|
6932
|
+
import { existsSync as existsSync6, readdirSync as readdirSync4, readFileSync as readFileSync4, statSync as statSync3 } from "fs";
|
|
6933
|
+
import { basename as basename3, join as join6, relative as relative2 } from "path";
|
|
6437
6934
|
var AI_SESSION_SOURCES = ["codex", "claude"];
|
|
6438
6935
|
var DEFAULT_LIMIT_PER_SOURCE = 3;
|
|
6439
6936
|
var DEFAULT_SINCE_DAYS = 30;
|
|
@@ -6599,10 +7096,10 @@ function collectJsonlFiles(root, source) {
|
|
|
6599
7096
|
continue;
|
|
6600
7097
|
}
|
|
6601
7098
|
for (const entry of entries) {
|
|
6602
|
-
const path =
|
|
7099
|
+
const path = join6(current, entry);
|
|
6603
7100
|
let stats;
|
|
6604
7101
|
try {
|
|
6605
|
-
stats =
|
|
7102
|
+
stats = statSync3(path);
|
|
6606
7103
|
} catch {
|
|
6607
7104
|
continue;
|
|
6608
7105
|
}
|
|
@@ -6620,7 +7117,7 @@ function collectJsonlFiles(root, source) {
|
|
|
6620
7117
|
function readSessionImport(candidate, root, options) {
|
|
6621
7118
|
let stats;
|
|
6622
7119
|
try {
|
|
6623
|
-
stats =
|
|
7120
|
+
stats = statSync3(candidate.path);
|
|
6624
7121
|
} catch {
|
|
6625
7122
|
return null;
|
|
6626
7123
|
}
|
|
@@ -6638,7 +7135,7 @@ function readSessionImport(candidate, root, options) {
|
|
|
6638
7135
|
}
|
|
6639
7136
|
const deduped = [...new Set(relevantLines)].slice(0, 80);
|
|
6640
7137
|
if (deduped.length === 0) return null;
|
|
6641
|
-
const relativePath =
|
|
7138
|
+
const relativePath = relative2(root, candidate.path);
|
|
6642
7139
|
return {
|
|
6643
7140
|
import: {
|
|
6644
7141
|
sourceId: `${candidate.source}:${basename3(candidate.path, ".jsonl")}`,
|
|
@@ -6713,9 +7210,9 @@ function loadAiSessionImports(options) {
|
|
|
6713
7210
|
// src/lib/work-graph-source-adapters.ts
|
|
6714
7211
|
import { createHash as createHash4 } from "crypto";
|
|
6715
7212
|
import { execFileSync } from "child_process";
|
|
6716
|
-
import { closeSync, existsSync as existsSync7, openSync, readFileSync as readFileSync5, readdirSync as readdirSync5, readSync, statSync as
|
|
7213
|
+
import { closeSync, existsSync as existsSync7, openSync, readFileSync as readFileSync5, readdirSync as readdirSync5, readSync, statSync as statSync4 } from "fs";
|
|
6717
7214
|
import { homedir as homedir2 } from "os";
|
|
6718
|
-
import { basename as basename4, join as
|
|
7215
|
+
import { basename as basename4, join as join7, resolve } from "path";
|
|
6719
7216
|
var CLIENT_SOURCES = ["claude_code", "codex", "opencode", "goose", "cursor", "github", "slack"];
|
|
6720
7217
|
var DEFAULT_LIMIT_PER_SOURCE2 = 8;
|
|
6721
7218
|
var DEFAULT_SINCE_DAYS2 = 45;
|
|
@@ -6742,7 +7239,7 @@ function expandPath(path, env) {
|
|
|
6742
7239
|
}
|
|
6743
7240
|
function safeStat2(path) {
|
|
6744
7241
|
try {
|
|
6745
|
-
return
|
|
7242
|
+
return statSync4(path);
|
|
6746
7243
|
} catch {
|
|
6747
7244
|
return null;
|
|
6748
7245
|
}
|
|
@@ -6763,7 +7260,7 @@ function walkFiles(root, predicate, maxFiles = 500) {
|
|
|
6763
7260
|
}
|
|
6764
7261
|
for (const entry of entries) {
|
|
6765
7262
|
if (ignored.has(entry)) continue;
|
|
6766
|
-
const path =
|
|
7263
|
+
const path = join7(current, entry);
|
|
6767
7264
|
const stats = safeStat2(path);
|
|
6768
7265
|
if (!stats) continue;
|
|
6769
7266
|
if (stats.isDirectory()) {
|
|
@@ -7017,8 +7514,8 @@ function readJsonlCandidate(candidate, options) {
|
|
|
7017
7514
|
searchedSessions: 0
|
|
7018
7515
|
};
|
|
7019
7516
|
}
|
|
7020
|
-
const
|
|
7021
|
-
const lines =
|
|
7517
|
+
const window = readTextWindow(candidate.path, stats, options.maxBytesPerFile);
|
|
7518
|
+
const lines = window.text.split(/\r?\n/);
|
|
7022
7519
|
const fallbackTimestamp = new Date(stats.mtimeMs).toISOString();
|
|
7023
7520
|
const sessionId = basename4(candidate.path).replace(/\.[^.]+$/, "");
|
|
7024
7521
|
const events = [];
|
|
@@ -7054,7 +7551,7 @@ function readJsonlCandidate(candidate, options) {
|
|
|
7054
7551
|
events,
|
|
7055
7552
|
filesRead: 1,
|
|
7056
7553
|
filesSkipped: [],
|
|
7057
|
-
notes:
|
|
7554
|
+
notes: window.truncated ? [`Read the latest ${options.maxBytesPerFile} bytes from oversized JSONL source instead of skipping it.`] : [],
|
|
7058
7555
|
searchedSessions: 1
|
|
7059
7556
|
};
|
|
7060
7557
|
}
|
|
@@ -12999,22 +13496,22 @@ function buildWorkGraphHookReplayPatch(readResult) {
|
|
|
12999
13496
|
}
|
|
13000
13497
|
|
|
13001
13498
|
// src/lib/runtime-hooks.ts
|
|
13002
|
-
import { copyFileSync, existsSync as existsSync9, mkdirSync as
|
|
13499
|
+
import { copyFileSync, existsSync as existsSync9, mkdirSync as mkdirSync4 } from "fs";
|
|
13003
13500
|
import { homedir as homedir3 } from "os";
|
|
13004
|
-
import { dirname as
|
|
13501
|
+
import { dirname as dirname5, join as join8 } from "path";
|
|
13005
13502
|
var HOOK_MARKER = "orgx-session-hook.mjs";
|
|
13006
13503
|
var EMIT_HOOK_MARKER = "orgx-emit-execution-graph.mjs";
|
|
13007
13504
|
var HOOK_EVENTS = ["SessionStart", "UserPromptSubmit", "PreToolUse", "PostToolUse", "PermissionRequest", "Stop"];
|
|
13008
13505
|
var CLAUDE_HOOK_EVENTS = ["SessionStart", "UserPromptSubmit", "PreToolUse", "PostToolUse", "SubagentStop", "Stop", "SessionEnd"];
|
|
13009
13506
|
function defaultPaths(options = {}) {
|
|
13010
|
-
const hookDir =
|
|
13507
|
+
const hookDir = join8(ORGX_WIZARD_CONFIG_HOME, "hooks");
|
|
13011
13508
|
return {
|
|
13012
|
-
claudeSettingsPath: options.claudeSettingsPath ??
|
|
13013
|
-
codexConfigPath: options.codexConfigPath ?? CODEX_CONFIG_PATH ??
|
|
13014
|
-
codexHooksPath: options.codexHooksPath ??
|
|
13015
|
-
hookScriptPath: options.hookScriptPath ??
|
|
13016
|
-
emitHookScriptPath: options.emitHookScriptPath ??
|
|
13017
|
-
outboxPath: options.outboxPath ??
|
|
13509
|
+
claudeSettingsPath: options.claudeSettingsPath ?? join8(CLAUDE_DIR, "settings.json"),
|
|
13510
|
+
codexConfigPath: options.codexConfigPath ?? CODEX_CONFIG_PATH ?? join8(CODEX_DIR, "config.toml"),
|
|
13511
|
+
codexHooksPath: options.codexHooksPath ?? join8(CODEX_DIR, "hooks.json"),
|
|
13512
|
+
hookScriptPath: options.hookScriptPath ?? join8(hookDir, HOOK_MARKER),
|
|
13513
|
+
emitHookScriptPath: options.emitHookScriptPath ?? join8(hookDir, EMIT_HOOK_MARKER),
|
|
13514
|
+
outboxPath: options.outboxPath ?? join8(hookDir, "events.jsonl")
|
|
13018
13515
|
};
|
|
13019
13516
|
}
|
|
13020
13517
|
function countJsonlLines(path) {
|
|
@@ -13396,7 +13893,7 @@ function installRuntimeHooks(targets, options = {}) {
|
|
|
13396
13893
|
hookScript: false,
|
|
13397
13894
|
emitHookScript: false
|
|
13398
13895
|
};
|
|
13399
|
-
|
|
13896
|
+
mkdirSync4(dirname5(paths.hookScriptPath), { recursive: true, mode: 448 });
|
|
13400
13897
|
const scriptContent = buildRuntimeHookScriptContent();
|
|
13401
13898
|
if (readTextIfExists(paths.hookScriptPath) !== scriptContent) {
|
|
13402
13899
|
const backup = backupExisting(paths.hookScriptPath, now);
|
|
@@ -13404,7 +13901,7 @@ function installRuntimeHooks(targets, options = {}) {
|
|
|
13404
13901
|
writeTextFile(paths.hookScriptPath, scriptContent, { mode: 448 });
|
|
13405
13902
|
changed.hookScript = true;
|
|
13406
13903
|
}
|
|
13407
|
-
|
|
13904
|
+
mkdirSync4(dirname5(paths.emitHookScriptPath), { recursive: true, mode: 448 });
|
|
13408
13905
|
const emitScriptContent = buildExecutionGraphEmitScriptContent();
|
|
13409
13906
|
if (readTextIfExists(paths.emitHookScriptPath) !== emitScriptContent) {
|
|
13410
13907
|
const backup = backupExisting(paths.emitHookScriptPath, now);
|
|
@@ -14030,6 +14527,73 @@ async function requestWorkloadDiagnosis(input, options = {}) {
|
|
|
14030
14527
|
return parsed.data;
|
|
14031
14528
|
}
|
|
14032
14529
|
|
|
14530
|
+
// src/lib/deepseek-launcher.ts
|
|
14531
|
+
import { spawnSync as spawnSync4 } from "child_process";
|
|
14532
|
+
async function resolveFreshMcpAuth(deps) {
|
|
14533
|
+
const authPath = deps.authPath ?? ORGX_WIZARD_AUTH_PATH;
|
|
14534
|
+
const readAuth = deps.readAuth ?? readWizardAuth;
|
|
14535
|
+
const stored = await readAuth(authPath);
|
|
14536
|
+
if (!stored) {
|
|
14537
|
+
throw new Error("OrgX is not paired. Run orgx-wizard auth login first.");
|
|
14538
|
+
}
|
|
14539
|
+
if (stored.source !== "pkce") return stored;
|
|
14540
|
+
if (!stored.refreshToken || !stored.oauthClientId) {
|
|
14541
|
+
throw new Error("OrgX browser authorization cannot be refreshed. Run orgx-wizard auth login again.");
|
|
14542
|
+
}
|
|
14543
|
+
const refresh = deps.refreshToken ?? refreshAccessToken;
|
|
14544
|
+
let refreshed;
|
|
14545
|
+
try {
|
|
14546
|
+
refreshed = await refresh({
|
|
14547
|
+
refreshToken: stored.refreshToken,
|
|
14548
|
+
clientId: stored.oauthClientId
|
|
14549
|
+
});
|
|
14550
|
+
} catch (error) {
|
|
14551
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
14552
|
+
throw new Error(`OrgX authorization refresh failed. Run orgx-wizard auth login again. ${detail}`);
|
|
14553
|
+
}
|
|
14554
|
+
const writeAuth = deps.writeAuth ?? writeWizardAuth;
|
|
14555
|
+
return writeAuth(
|
|
14556
|
+
{
|
|
14557
|
+
apiKey: refreshed.access_token,
|
|
14558
|
+
baseUrl: stored.baseUrl,
|
|
14559
|
+
verifiedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14560
|
+
source: "pkce",
|
|
14561
|
+
refreshToken: refreshed.refresh_token ?? stored.refreshToken,
|
|
14562
|
+
oauthClientId: stored.oauthClientId
|
|
14563
|
+
},
|
|
14564
|
+
authPath
|
|
14565
|
+
);
|
|
14566
|
+
}
|
|
14567
|
+
async function launchDeepseekWithOrgx(prompt, deps = {}) {
|
|
14568
|
+
if (prompt.length === 0 || prompt.every((part) => !part.trim())) {
|
|
14569
|
+
throw new Error('Give DeepSeek a prompt, for example: orgx-wizard deepseek "What changed while I was away?"');
|
|
14570
|
+
}
|
|
14571
|
+
const runtime = inspectDeepseekRuntime(deps.runtimeRunner);
|
|
14572
|
+
if (!runtime.installed) {
|
|
14573
|
+
throw new Error("DeepSeek Harness was not found. Run orgx-wizard setup after installing DSH.");
|
|
14574
|
+
}
|
|
14575
|
+
if (!runtime.supported) {
|
|
14576
|
+
throw new Error(`DeepSeek Harness ${runtime.version ?? "unknown"} is not supported by this OrgX plugin.`);
|
|
14577
|
+
}
|
|
14578
|
+
const auth = await resolveFreshMcpAuth(deps);
|
|
14579
|
+
const childEnv = {
|
|
14580
|
+
...deps.env ?? process.env,
|
|
14581
|
+
ORGX_MCP_ACCESS_TOKEN: auth.apiKey
|
|
14582
|
+
};
|
|
14583
|
+
delete childEnv.ORGX_API_KEY;
|
|
14584
|
+
const spawn2 = deps.spawn ?? spawnSync4;
|
|
14585
|
+
const result = spawn2(
|
|
14586
|
+
"dsh",
|
|
14587
|
+
["--profile", DEEPSEEK_PROFILE, prompt.join(" ")],
|
|
14588
|
+
{
|
|
14589
|
+
env: childEnv,
|
|
14590
|
+
stdio: "inherit"
|
|
14591
|
+
}
|
|
14592
|
+
);
|
|
14593
|
+
if (result.error) throw result.error;
|
|
14594
|
+
return { status: result.status ?? 1 };
|
|
14595
|
+
}
|
|
14596
|
+
|
|
14033
14597
|
// src/cli.ts
|
|
14034
14598
|
var ICON = {
|
|
14035
14599
|
ok: pc3.green("\u2713"),
|
|
@@ -14099,7 +14663,7 @@ function printSurfaceSummary(results) {
|
|
|
14099
14663
|
` ${ICON.skip} ${pc3.dim("No supported AI tools detected on this machine.")}`
|
|
14100
14664
|
);
|
|
14101
14665
|
console.log(
|
|
14102
|
-
` ${pc3.dim("\u2192")} ${pc3.dim("Install Claude, Cursor, Codex, VS Code, Windsurf, or Zed, then re-run setup.")}`
|
|
14666
|
+
` ${pc3.dim("\u2192")} ${pc3.dim("Install Claude, Cursor, Codex, DeepSeek Harness, VS Code, Windsurf, or Zed, then re-run setup.")}`
|
|
14103
14667
|
);
|
|
14104
14668
|
return;
|
|
14105
14669
|
}
|
|
@@ -14766,7 +15330,7 @@ function openPathInEditor(path) {
|
|
|
14766
15330
|
if (!editor) {
|
|
14767
15331
|
return false;
|
|
14768
15332
|
}
|
|
14769
|
-
const result =
|
|
15333
|
+
const result = spawnSync5(editor, [path], {
|
|
14770
15334
|
shell: true,
|
|
14771
15335
|
stdio: "inherit"
|
|
14772
15336
|
});
|
|
@@ -15584,14 +16148,20 @@ async function promptOptionalCompanionPluginTargets(input) {
|
|
|
15584
16148
|
return selection;
|
|
15585
16149
|
}
|
|
15586
16150
|
function printPluginSkillOwnershipNote(targets) {
|
|
15587
|
-
if (
|
|
15588
|
-
|
|
16151
|
+
if (targets.includes("claude")) {
|
|
16152
|
+
console.log(
|
|
16153
|
+
` ${ICON.skip} ${pc3.dim(
|
|
16154
|
+
"The Claude Code plugin carries static OrgX skills and commands plus a focused, non-destructive, closed-world OrgX status profile through native OAuth. It installs no runtime hooks or transcript/context sync code."
|
|
16155
|
+
)}`
|
|
16156
|
+
);
|
|
16157
|
+
}
|
|
16158
|
+
if (targets.some((target) => target === "cursor" || target === "codex")) {
|
|
16159
|
+
console.log(
|
|
16160
|
+
` ${ICON.skip} ${pc3.dim(
|
|
16161
|
+
"Cursor and Codex companion plugins carry their own OrgX assets. Use 'wizard skills add' only for standalone rules or skills when those plugins are not in play."
|
|
16162
|
+
)}`
|
|
16163
|
+
);
|
|
15589
16164
|
}
|
|
15590
|
-
console.log(
|
|
15591
|
-
` ${ICON.skip} ${pc3.dim(
|
|
15592
|
-
"Cursor, Claude Code, and Codex companion plugins carry their own OrgX skills, rules, MCP config, commands, hooks, and agent prompts. Use 'wizard skills add' only for standalone rules or skills when those plugins are not in play."
|
|
15593
|
-
)}`
|
|
15594
|
-
);
|
|
15595
16165
|
}
|
|
15596
16166
|
async function installSelectedCompanionPlugins(input) {
|
|
15597
16167
|
if (input.targets.length === 0) {
|
|
@@ -15749,7 +16319,7 @@ async function main() {
|
|
|
15749
16319
|
initializeWizardSentry();
|
|
15750
16320
|
const program = new Command();
|
|
15751
16321
|
program.name("orgx-wizard").description("Add OrgX MCP configs, skills/rules, and companion plugins to your local AI tools.").showHelpAfterError();
|
|
15752
|
-
const pkgVersion = true ? "0.1.
|
|
16322
|
+
const pkgVersion = true ? "0.1.55" : void 0;
|
|
15753
16323
|
program.version(pkgVersion ?? "unknown", "-V, --version");
|
|
15754
16324
|
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
15755
16325
|
if (Boolean(actionCommand.optsWithGlobals().json)) return;
|
|
@@ -16052,6 +16622,10 @@ async function main() {
|
|
|
16052
16622
|
}
|
|
16053
16623
|
}
|
|
16054
16624
|
});
|
|
16625
|
+
program.command("deepseek").description("Run the pinned DeepSeek Harness profile with refreshed OrgX authorization.").argument("<prompt...>", "prompt to run in the DeepSeek Harness headless profile").action(async (prompt) => {
|
|
16626
|
+
const result = await launchDeepseekWithOrgx(prompt);
|
|
16627
|
+
if (result.status !== 0) process.exitCode = result.status;
|
|
16628
|
+
});
|
|
16055
16629
|
async function runPkceLogin(opts = {}) {
|
|
16056
16630
|
const spinner = createOrgxSpinner("Starting OrgX OAuth login");
|
|
16057
16631
|
spinner.start();
|
|
@@ -16773,10 +17347,5 @@ main().catch(async (error) => {
|
|
|
16773
17347
|
console.error(pc3.red(error instanceof Error ? error.message : String(error)));
|
|
16774
17348
|
process.exitCode = 1;
|
|
16775
17349
|
});
|
|
16776
|
-
|
|
16777
|
-
|
|
16778
|
-
var cli_default = void 0;
|
|
16779
|
-
export {
|
|
16780
|
-
cli_default as default
|
|
16781
|
-
};
|
|
16782
|
-
//# sourceMappingURL=cli.js.map
|
|
17350
|
+
//# sourceMappingURL=cli.js.map
|
|
17351
|
+
//# debugId=707a7fe5-404e-5aec-9c75-30f0f5d859d9
|