@useorgx/wizard 0.1.10 → 0.1.12
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 +35 -11
- package/dist/cli.js +609 -96
- package/dist/cli.js.map +1 -1
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import * as clack from "@clack/prompts";
|
|
5
|
+
import { spawnSync as spawnSync3 } from "child_process";
|
|
5
6
|
import { hostname } from "os";
|
|
6
7
|
import { Command } from "commander";
|
|
7
8
|
import pc3 from "picocolors";
|
|
@@ -54,6 +55,7 @@ var XDG_CONFIG_HOME = process.env.XDG_CONFIG_HOME?.trim() || join(HOME, ".config
|
|
|
54
55
|
var ORGX_WIZARD_CONFIG_HOME = process.env.ORGX_WIZARD_CONFIG_HOME?.trim() || join(XDG_CONFIG_HOME, "useorgx", "wizard");
|
|
55
56
|
var ORGX_WIZARD_AUTH_PATH = join(ORGX_WIZARD_CONFIG_HOME, "auth.json");
|
|
56
57
|
var ORGX_WIZARD_STATE_PATH = join(ORGX_WIZARD_CONFIG_HOME, "state.json");
|
|
58
|
+
var ORGX_SKILL_EXTENSIONS_DIR = join(ORGX_WIZARD_CONFIG_HOME, "skill-extensions");
|
|
57
59
|
var ORGX_WIZARD_KEYTAR_SERVICE = "@useorgx/wizard";
|
|
58
60
|
var ORGX_WIZARD_KEYTAR_ACCOUNT = "orgx-api-key";
|
|
59
61
|
function normalizeOrgxApiBaseUrl(baseUrl) {
|
|
@@ -80,6 +82,8 @@ var CLAUDE_ORGX_SKILL_DIR = join(CLAUDE_SKILLS_DIR, "orgx");
|
|
|
80
82
|
var CLAUDE_ORGX_SKILL_PATH = join(CLAUDE_ORGX_SKILL_DIR, "SKILL.md");
|
|
81
83
|
var CURSOR_RULES_DIR = join(CURSOR_DIR, "rules");
|
|
82
84
|
var CURSOR_ORGX_RULE_PATH = join(CURSOR_RULES_DIR, "orgx.md");
|
|
85
|
+
var CURSOR_PLUGINS_DIR = join(CURSOR_DIR, "plugins", "local");
|
|
86
|
+
var CURSOR_ORGX_PLUGIN_DIR = join(CURSOR_PLUGINS_DIR, "cursor-plugin");
|
|
83
87
|
var CODEX_PLUGINS_DIR = join(CODEX_DIR, "plugins");
|
|
84
88
|
var CODEX_ORGX_PLUGIN_DIR = join(CODEX_PLUGINS_DIR, "orgx-codex-plugin");
|
|
85
89
|
var CODEX_MARKETPLACE_DIR = join(AGENTS_DIR, "plugins");
|
|
@@ -978,6 +982,39 @@ function parseAgentRoster(value) {
|
|
|
978
982
|
...isNonEmptyString2(record.workspaceName) ? { workspaceName: record.workspaceName.trim() } : {}
|
|
979
983
|
};
|
|
980
984
|
}
|
|
985
|
+
function parseSkillFileRecord(value) {
|
|
986
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
987
|
+
return void 0;
|
|
988
|
+
}
|
|
989
|
+
const record = value;
|
|
990
|
+
if (!isNonEmptyString2(record.path) || !isNonEmptyString2(record.skillId) || !isNonEmptyString2(record.contentSha256) || !isNonEmptyString2(record.updatedAt)) {
|
|
991
|
+
return void 0;
|
|
992
|
+
}
|
|
993
|
+
return {
|
|
994
|
+
contentSha256: record.contentSha256.trim(),
|
|
995
|
+
path: record.path.trim(),
|
|
996
|
+
skillId: record.skillId.trim(),
|
|
997
|
+
updatedAt: record.updatedAt.trim(),
|
|
998
|
+
...isNonEmptyString2(record.coreSha256) ? { coreSha256: record.coreSha256.trim() } : {}
|
|
999
|
+
};
|
|
1000
|
+
}
|
|
1001
|
+
function parseSkillFiles(value) {
|
|
1002
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1003
|
+
return void 0;
|
|
1004
|
+
}
|
|
1005
|
+
const record = value;
|
|
1006
|
+
if (!isNonEmptyString2(record.updatedAt) || !Array.isArray(record.files)) {
|
|
1007
|
+
return void 0;
|
|
1008
|
+
}
|
|
1009
|
+
const files = record.files.map((entry) => parseSkillFileRecord(entry)).filter((entry) => Boolean(entry));
|
|
1010
|
+
if (files.length === 0) {
|
|
1011
|
+
return void 0;
|
|
1012
|
+
}
|
|
1013
|
+
return {
|
|
1014
|
+
files,
|
|
1015
|
+
updatedAt: record.updatedAt.trim()
|
|
1016
|
+
};
|
|
1017
|
+
}
|
|
981
1018
|
function createWizardState(now = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
982
1019
|
return {
|
|
983
1020
|
installationId: `wizard-${randomUUID()}`,
|
|
@@ -990,6 +1027,7 @@ function sanitizeWizardStateRecord(record) {
|
|
|
990
1027
|
const agentRoster = parseAgentRoster(record.agentRoster);
|
|
991
1028
|
const demoInitiative = parseDemoInitiative(record.demoInitiative);
|
|
992
1029
|
const onboardingTask = parseOnboardingTask(record.onboardingTask);
|
|
1030
|
+
const skillFiles = parseSkillFiles(record.skillFiles);
|
|
993
1031
|
return {
|
|
994
1032
|
installationId: record.installationId.trim(),
|
|
995
1033
|
createdAt: record.createdAt.trim(),
|
|
@@ -997,7 +1035,8 @@ function sanitizeWizardStateRecord(record) {
|
|
|
997
1035
|
...continuity ? { continuity } : {},
|
|
998
1036
|
...agentRoster ? { agentRoster } : {},
|
|
999
1037
|
...demoInitiative ? { demoInitiative } : {},
|
|
1000
|
-
...onboardingTask ? { onboardingTask } : {}
|
|
1038
|
+
...onboardingTask ? { onboardingTask } : {},
|
|
1039
|
+
...skillFiles ? { skillFiles } : {}
|
|
1001
1040
|
};
|
|
1002
1041
|
}
|
|
1003
1042
|
function readWizardState(statePath = ORGX_WIZARD_STATE_PATH) {
|
|
@@ -1018,6 +1057,8 @@ function readWizardState(statePath = ORGX_WIZARD_STATE_PATH) {
|
|
|
1018
1057
|
if (demoInitiative !== void 0) state.demoInitiative = demoInitiative;
|
|
1019
1058
|
const onboardingTask = parseOnboardingTask(parsed.onboardingTask);
|
|
1020
1059
|
if (onboardingTask !== void 0) state.onboardingTask = onboardingTask;
|
|
1060
|
+
const skillFiles = parseSkillFiles(parsed.skillFiles);
|
|
1061
|
+
if (skillFiles !== void 0) state.skillFiles = skillFiles;
|
|
1021
1062
|
return state;
|
|
1022
1063
|
}
|
|
1023
1064
|
function writeWizardState(value, statePath = ORGX_WIZARD_STATE_PATH) {
|
|
@@ -3005,7 +3046,9 @@ async function ensureOnboardingTask(workspace, options = {}) {
|
|
|
3005
3046
|
}
|
|
3006
3047
|
|
|
3007
3048
|
// src/lib/skills.ts
|
|
3008
|
-
import {
|
|
3049
|
+
import { createHash } from "crypto";
|
|
3050
|
+
import { existsSync as existsSync3, readdirSync } from "fs";
|
|
3051
|
+
import { basename, join as join2 } from "path";
|
|
3009
3052
|
var DEFAULT_ORGX_SKILL_PACKS = [
|
|
3010
3053
|
"morning-briefing",
|
|
3011
3054
|
"initiative-kickoff",
|
|
@@ -3017,6 +3060,9 @@ var EXCLUDED_PACK_DIRS = /* @__PURE__ */ new Set([".github", "scripts"]);
|
|
|
3017
3060
|
var ORGX_SKILLS_OWNER = "useorgx";
|
|
3018
3061
|
var ORGX_SKILLS_REPO = "skills";
|
|
3019
3062
|
var ORGX_SKILLS_REF = "main";
|
|
3063
|
+
var SKILL_EXTENSION_SCOPES = ["user", "workspace", "project"];
|
|
3064
|
+
var COMPOSED_SKILL_MARKER = "ORGX SKILL COMPOSED v1";
|
|
3065
|
+
var EXTENSION_FRONTMATTER_DELIMITER = "---";
|
|
3020
3066
|
var CURSOR_RULES_CONTENT = `# OrgX Rules
|
|
3021
3067
|
|
|
3022
3068
|
- Prefer \`workspace_id\` on OrgX tool calls. \`command_center_id\` is a deprecated alias and should only be used for backwards compatibility. If both are present, they must match.
|
|
@@ -3072,6 +3118,219 @@ Install and use these packs alongside this base skill:
|
|
|
3072
3118
|
4. When you scaffold, decide up front whether \`continue_on_error\` is acceptable.
|
|
3073
3119
|
5. Carry \`_context\` through any widget-producing flows so the UI can render and resume correctly.
|
|
3074
3120
|
`;
|
|
3121
|
+
function sha256(value) {
|
|
3122
|
+
return createHash("sha256").update(value).digest("hex");
|
|
3123
|
+
}
|
|
3124
|
+
function normalizeSkillId(value) {
|
|
3125
|
+
const normalized = value.trim().toLowerCase();
|
|
3126
|
+
if (!/^[a-z0-9][a-z0-9._-]*$/.test(normalized)) {
|
|
3127
|
+
throw new Error(
|
|
3128
|
+
"Skill id must start with a letter or number and only contain letters, numbers, '.', '_' or '-'."
|
|
3129
|
+
);
|
|
3130
|
+
}
|
|
3131
|
+
return normalized;
|
|
3132
|
+
}
|
|
3133
|
+
function normalizeSkillExtensionScope(value) {
|
|
3134
|
+
const normalized = (value ?? "user").trim().toLowerCase();
|
|
3135
|
+
if (!SKILL_EXTENSION_SCOPES.includes(normalized)) {
|
|
3136
|
+
throw new Error("Skill extension scope must be one of: user, workspace, project.");
|
|
3137
|
+
}
|
|
3138
|
+
return normalized;
|
|
3139
|
+
}
|
|
3140
|
+
function defaultExtensionTitle(skillId, scope) {
|
|
3141
|
+
const prefix = scope === "user" ? "Personal" : scope === "workspace" ? "Workspace" : "Project";
|
|
3142
|
+
return `${prefix} ${skillId} behavior`;
|
|
3143
|
+
}
|
|
3144
|
+
function extensionFilePath(skillId, scope, extensionsDir = ORGX_SKILL_EXTENSIONS_DIR) {
|
|
3145
|
+
return join2(extensionsDir, `${scope}.${skillId}.md`);
|
|
3146
|
+
}
|
|
3147
|
+
function extensionTemplate(input) {
|
|
3148
|
+
const body = input.content?.trim() ? input.content.trim() : [
|
|
3149
|
+
`# ${input.title}`,
|
|
3150
|
+
"",
|
|
3151
|
+
"- Add your custom behavior here.",
|
|
3152
|
+
"- These instructions are appended after the OrgX-managed core skill when the wizard syncs skills."
|
|
3153
|
+
].join("\n");
|
|
3154
|
+
return [
|
|
3155
|
+
EXTENSION_FRONTMATTER_DELIMITER,
|
|
3156
|
+
`skill: ${input.skillId}`,
|
|
3157
|
+
`scope: ${input.scope}`,
|
|
3158
|
+
"enabled: true",
|
|
3159
|
+
`title: ${input.title}`,
|
|
3160
|
+
EXTENSION_FRONTMATTER_DELIMITER,
|
|
3161
|
+
"",
|
|
3162
|
+
body,
|
|
3163
|
+
""
|
|
3164
|
+
].join("\n");
|
|
3165
|
+
}
|
|
3166
|
+
function parseFrontmatter(content) {
|
|
3167
|
+
if (!content.startsWith(`${EXTENSION_FRONTMATTER_DELIMITER}
|
|
3168
|
+
`)) {
|
|
3169
|
+
return { body: content, data: {} };
|
|
3170
|
+
}
|
|
3171
|
+
const closeIndex = content.indexOf(`
|
|
3172
|
+
${EXTENSION_FRONTMATTER_DELIMITER}
|
|
3173
|
+
`, 4);
|
|
3174
|
+
if (closeIndex === -1) {
|
|
3175
|
+
return { body: content, data: {} };
|
|
3176
|
+
}
|
|
3177
|
+
const raw = content.slice(4, closeIndex);
|
|
3178
|
+
const body = content.slice(closeIndex + 5);
|
|
3179
|
+
const data = {};
|
|
3180
|
+
for (const line of raw.split("\n")) {
|
|
3181
|
+
const index = line.indexOf(":");
|
|
3182
|
+
if (index === -1) {
|
|
3183
|
+
continue;
|
|
3184
|
+
}
|
|
3185
|
+
const key = line.slice(0, index).trim();
|
|
3186
|
+
const value = line.slice(index + 1).trim();
|
|
3187
|
+
if (key) {
|
|
3188
|
+
data[key] = value;
|
|
3189
|
+
}
|
|
3190
|
+
}
|
|
3191
|
+
return { body, data };
|
|
3192
|
+
}
|
|
3193
|
+
function serializeFrontmatter(data, body) {
|
|
3194
|
+
return [
|
|
3195
|
+
EXTENSION_FRONTMATTER_DELIMITER,
|
|
3196
|
+
...Object.entries(data).map(([key, value]) => `${key}: ${value}`),
|
|
3197
|
+
EXTENSION_FRONTMATTER_DELIMITER,
|
|
3198
|
+
"",
|
|
3199
|
+
body.trimEnd(),
|
|
3200
|
+
""
|
|
3201
|
+
].join("\n");
|
|
3202
|
+
}
|
|
3203
|
+
function parseSkillExtension(path, content) {
|
|
3204
|
+
const fallbackId = basename(path, ".md");
|
|
3205
|
+
const fallbackParts = fallbackId.split(".");
|
|
3206
|
+
const fallbackScope = normalizeSkillExtensionScope(
|
|
3207
|
+
SKILL_EXTENSION_SCOPES.includes(fallbackParts[0]) ? fallbackParts.shift() : "user"
|
|
3208
|
+
);
|
|
3209
|
+
const fallbackSkillId = normalizeSkillId(fallbackParts.join(".") || fallbackId);
|
|
3210
|
+
const parsed = parseFrontmatter(content);
|
|
3211
|
+
const skillId = normalizeSkillId(parsed.data.skill || fallbackSkillId);
|
|
3212
|
+
const scope = normalizeSkillExtensionScope(parsed.data.scope || fallbackScope);
|
|
3213
|
+
const title = parsed.data.title?.trim() || defaultExtensionTitle(skillId, scope);
|
|
3214
|
+
return {
|
|
3215
|
+
content: parsed.body.trim(),
|
|
3216
|
+
enabled: parsed.data.enabled?.trim().toLowerCase() !== "false",
|
|
3217
|
+
id: `${scope}.${skillId}`,
|
|
3218
|
+
path,
|
|
3219
|
+
scope,
|
|
3220
|
+
skillId,
|
|
3221
|
+
title
|
|
3222
|
+
};
|
|
3223
|
+
}
|
|
3224
|
+
function listSkillExtensions(options = {}) {
|
|
3225
|
+
const extensionsDir = options.extensionsDir ?? ORGX_SKILL_EXTENSIONS_DIR;
|
|
3226
|
+
if (!existsSync3(extensionsDir)) {
|
|
3227
|
+
return [];
|
|
3228
|
+
}
|
|
3229
|
+
return readdirSync(extensionsDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".md")).map((entry) => {
|
|
3230
|
+
const path = join2(extensionsDir, entry.name);
|
|
3231
|
+
const content = readTextIfExists(path);
|
|
3232
|
+
return content === null ? null : parseSkillExtension(path, content);
|
|
3233
|
+
}).filter((entry) => Boolean(entry)).sort((left, right) => left.id.localeCompare(right.id));
|
|
3234
|
+
}
|
|
3235
|
+
function addSkillExtension(options) {
|
|
3236
|
+
const skillId = normalizeSkillId(options.skillId);
|
|
3237
|
+
const scope = normalizeSkillExtensionScope(options.scope);
|
|
3238
|
+
const path = extensionFilePath(skillId, scope, options.extensionsDir);
|
|
3239
|
+
const title = options.title?.trim() || defaultExtensionTitle(skillId, scope);
|
|
3240
|
+
const existing = readTextIfExists(path);
|
|
3241
|
+
if (existing !== null && options.overwrite !== true) {
|
|
3242
|
+
const extension2 = parseSkillExtension(path, existing);
|
|
3243
|
+
if (!extension2) {
|
|
3244
|
+
throw new Error(`Could not parse existing skill extension at ${path}.`);
|
|
3245
|
+
}
|
|
3246
|
+
return {
|
|
3247
|
+
changed: false,
|
|
3248
|
+
created: false,
|
|
3249
|
+
extension: extension2,
|
|
3250
|
+
path
|
|
3251
|
+
};
|
|
3252
|
+
}
|
|
3253
|
+
const nextContent = extensionTemplate({
|
|
3254
|
+
scope,
|
|
3255
|
+
skillId,
|
|
3256
|
+
title,
|
|
3257
|
+
...options.content !== void 0 ? { content: options.content } : {}
|
|
3258
|
+
});
|
|
3259
|
+
writeTextFile(path, nextContent);
|
|
3260
|
+
const extension = parseSkillExtension(path, nextContent);
|
|
3261
|
+
if (!extension) {
|
|
3262
|
+
throw new Error(`Could not parse newly written skill extension at ${path}.`);
|
|
3263
|
+
}
|
|
3264
|
+
return {
|
|
3265
|
+
changed: existing !== nextContent,
|
|
3266
|
+
created: existing === null,
|
|
3267
|
+
extension,
|
|
3268
|
+
path
|
|
3269
|
+
};
|
|
3270
|
+
}
|
|
3271
|
+
function setSkillExtensionEnabled(input) {
|
|
3272
|
+
const skillId = normalizeSkillId(input.skillId);
|
|
3273
|
+
const scope = normalizeSkillExtensionScope(input.scope);
|
|
3274
|
+
const path = extensionFilePath(skillId, scope, input.extensionsDir);
|
|
3275
|
+
const existing = readTextIfExists(path);
|
|
3276
|
+
if (existing === null) {
|
|
3277
|
+
if (!input.enabled) {
|
|
3278
|
+
throw new Error(`No ${scope} extension exists for ${skillId}.`);
|
|
3279
|
+
}
|
|
3280
|
+
return addSkillExtension({
|
|
3281
|
+
scope,
|
|
3282
|
+
skillId,
|
|
3283
|
+
...input.extensionsDir !== void 0 ? { extensionsDir: input.extensionsDir } : {}
|
|
3284
|
+
});
|
|
3285
|
+
}
|
|
3286
|
+
const parsed = parseFrontmatter(existing);
|
|
3287
|
+
const data = {
|
|
3288
|
+
skill: parsed.data.skill || skillId,
|
|
3289
|
+
scope: parsed.data.scope || scope,
|
|
3290
|
+
enabled: input.enabled ? "true" : "false",
|
|
3291
|
+
title: parsed.data.title || defaultExtensionTitle(skillId, scope)
|
|
3292
|
+
};
|
|
3293
|
+
const nextContent = serializeFrontmatter(data, parsed.body);
|
|
3294
|
+
if (nextContent !== existing) {
|
|
3295
|
+
writeTextFile(path, nextContent);
|
|
3296
|
+
}
|
|
3297
|
+
const extension = parseSkillExtension(path, nextContent);
|
|
3298
|
+
if (!extension) {
|
|
3299
|
+
throw new Error(`Could not parse skill extension at ${path}.`);
|
|
3300
|
+
}
|
|
3301
|
+
return {
|
|
3302
|
+
changed: nextContent !== existing,
|
|
3303
|
+
created: false,
|
|
3304
|
+
extension,
|
|
3305
|
+
path
|
|
3306
|
+
};
|
|
3307
|
+
}
|
|
3308
|
+
function composeSkillContent(skillId, coreContent, extensions) {
|
|
3309
|
+
const enabled = extensions.filter((extension) => extension.enabled && extension.skillId === skillId);
|
|
3310
|
+
if (enabled.length === 0) {
|
|
3311
|
+
return coreContent;
|
|
3312
|
+
}
|
|
3313
|
+
const extensionBlocks = enabled.map((extension) => [
|
|
3314
|
+
`<!-- extension: ${extension.id} -->`,
|
|
3315
|
+
extension.content.trim()
|
|
3316
|
+
].join("\n"));
|
|
3317
|
+
return [
|
|
3318
|
+
`<!-- ${COMPOSED_SKILL_MARKER}`,
|
|
3319
|
+
`skill: ${skillId}`,
|
|
3320
|
+
`core-sha256: ${sha256(coreContent)}`,
|
|
3321
|
+
"generated: true",
|
|
3322
|
+
`edit-with: orgx-wizard skills extensions edit ${skillId}`,
|
|
3323
|
+
"-->",
|
|
3324
|
+
`<!-- ORGX CORE BEGIN ${skillId} -->`,
|
|
3325
|
+
coreContent.trimEnd(),
|
|
3326
|
+
`<!-- ORGX CORE END ${skillId} -->`,
|
|
3327
|
+
"",
|
|
3328
|
+
"<!-- ORGX USER EXTENSIONS BEGIN -->",
|
|
3329
|
+
...extensionBlocks,
|
|
3330
|
+
"<!-- ORGX USER EXTENSIONS END -->",
|
|
3331
|
+
""
|
|
3332
|
+
].join("\n");
|
|
3333
|
+
}
|
|
3075
3334
|
function encodeRepoPath(value) {
|
|
3076
3335
|
return value.split("/").filter((segment) => segment.length > 0).map((segment) => encodeURIComponent(segment)).join("/");
|
|
3077
3336
|
}
|
|
@@ -3137,12 +3396,35 @@ async function fetchRemoteText(sourceUrl, fetchImpl) {
|
|
|
3137
3396
|
}
|
|
3138
3397
|
return readResponseText(response);
|
|
3139
3398
|
}
|
|
3140
|
-
function
|
|
3399
|
+
function getTrackedSkillFile(records, path) {
|
|
3400
|
+
return records.find((record) => record.path === path);
|
|
3401
|
+
}
|
|
3402
|
+
function writeManagedFile(path, content, label, sourceUrl, tracking) {
|
|
3141
3403
|
const existing = readTextIfExists(path);
|
|
3404
|
+
const tracked = tracking ? getTrackedSkillFile(tracking.records, path) : void 0;
|
|
3405
|
+
if (tracking && existing !== null && tracked && sha256(existing) !== tracked.contentSha256 && tracking.force !== true) {
|
|
3406
|
+
return {
|
|
3407
|
+
label,
|
|
3408
|
+
path,
|
|
3409
|
+
changed: false,
|
|
3410
|
+
skipped: true,
|
|
3411
|
+
reason: "manual edits detected; move them into a skill extension or rerun with --force",
|
|
3412
|
+
...sourceUrl ? { sourceUrl } : {}
|
|
3413
|
+
};
|
|
3414
|
+
}
|
|
3142
3415
|
const changed = existing !== content;
|
|
3143
3416
|
if (changed) {
|
|
3144
3417
|
writeTextFile(path, content);
|
|
3145
3418
|
}
|
|
3419
|
+
if (tracking) {
|
|
3420
|
+
tracking.stagedRecords.set(path, {
|
|
3421
|
+
contentSha256: sha256(content),
|
|
3422
|
+
...tracking.coreContent ? { coreSha256: sha256(tracking.coreContent) } : {},
|
|
3423
|
+
path,
|
|
3424
|
+
skillId: tracking.skillId,
|
|
3425
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3426
|
+
});
|
|
3427
|
+
}
|
|
3146
3428
|
return {
|
|
3147
3429
|
label,
|
|
3148
3430
|
path,
|
|
@@ -3207,19 +3489,27 @@ async function fetchAvailablePackNames(fetchImpl, ref) {
|
|
|
3207
3489
|
const entries = await fetchDirectoryEntries("", fetchImpl, ref);
|
|
3208
3490
|
return entries.filter((e) => e.type === "dir" && !EXCLUDED_PACK_DIRS.has(e.name)).map((e) => e.name);
|
|
3209
3491
|
}
|
|
3210
|
-
async function installSkillPack(skillName, claudeSkillsDir, fetchImpl, ref) {
|
|
3492
|
+
async function installSkillPack(skillName, claudeSkillsDir, fetchImpl, ref, tracking) {
|
|
3211
3493
|
const rootPath = skillName;
|
|
3212
3494
|
const files = await listRemoteSkillFiles(rootPath, fetchImpl, ref);
|
|
3213
3495
|
const writes = [];
|
|
3214
3496
|
for (const file of files) {
|
|
3215
|
-
const
|
|
3497
|
+
const coreContent = await fetchRemoteText(file.sourceUrl, fetchImpl);
|
|
3216
3498
|
const relativePath = file.path.slice(`${rootPath}/`.length);
|
|
3499
|
+
const content = relativePath === "SKILL.md" ? composeSkillContent(skillName, coreContent, tracking.extensions) : coreContent;
|
|
3217
3500
|
writes.push(
|
|
3218
3501
|
writeManagedFile(
|
|
3219
3502
|
join2(claudeSkillsDir, skillName, relativePath),
|
|
3220
3503
|
content,
|
|
3221
3504
|
`${skillName}/${relativePath}`,
|
|
3222
|
-
file.sourceUrl
|
|
3505
|
+
file.sourceUrl,
|
|
3506
|
+
{
|
|
3507
|
+
coreContent,
|
|
3508
|
+
records: tracking.records,
|
|
3509
|
+
skillId: skillName,
|
|
3510
|
+
stagedRecords: tracking.stagedRecords,
|
|
3511
|
+
...tracking.force !== void 0 ? { force: tracking.force } : {}
|
|
3512
|
+
}
|
|
3223
3513
|
)
|
|
3224
3514
|
);
|
|
3225
3515
|
}
|
|
@@ -3237,6 +3527,13 @@ async function installOrgxSkills(options = {}) {
|
|
|
3237
3527
|
const claudeSkillsDir = options.claudeSkillsDir ?? CLAUDE_SKILLS_DIR;
|
|
3238
3528
|
const claudeOrgxSkillPath = options.claudeOrgxSkillPath ?? CLAUDE_ORGX_SKILL_PATH;
|
|
3239
3529
|
const cursorRulePath = options.cursorRulePath ?? CURSOR_ORGX_RULE_PATH;
|
|
3530
|
+
const statePath = options.statePath ?? ORGX_WIZARD_STATE_PATH;
|
|
3531
|
+
const extensions = listSkillExtensions(
|
|
3532
|
+
options.skillExtensionsDir !== void 0 ? { extensionsDir: options.skillExtensionsDir } : {}
|
|
3533
|
+
);
|
|
3534
|
+
const enabledExtensions = extensions.filter((extension) => extension.enabled);
|
|
3535
|
+
const trackedRecords = readWizardState(statePath)?.skillFiles?.files ?? [];
|
|
3536
|
+
const stagedRecords = /* @__PURE__ */ new Map();
|
|
3240
3537
|
const plan = planOrgxSkillsInstall(options.pluginTargets ?? []);
|
|
3241
3538
|
const requestedNames = options.skillNames ?? [];
|
|
3242
3539
|
let skillNames;
|
|
@@ -3250,34 +3547,101 @@ async function installOrgxSkills(options = {}) {
|
|
|
3250
3547
|
skillNames = resolveSkillPackNames(requestedNames);
|
|
3251
3548
|
}
|
|
3252
3549
|
const writes = [
|
|
3253
|
-
writeManagedFile(
|
|
3550
|
+
writeManagedFile(
|
|
3551
|
+
cursorRulePath,
|
|
3552
|
+
composeSkillContent("cursor-rules", CURSOR_RULES_CONTENT, extensions),
|
|
3553
|
+
"cursor-rules",
|
|
3554
|
+
void 0,
|
|
3555
|
+
{
|
|
3556
|
+
coreContent: CURSOR_RULES_CONTENT,
|
|
3557
|
+
records: trackedRecords,
|
|
3558
|
+
skillId: "cursor-rules",
|
|
3559
|
+
stagedRecords,
|
|
3560
|
+
...options.force !== void 0 ? { force: options.force } : {}
|
|
3561
|
+
}
|
|
3562
|
+
)
|
|
3254
3563
|
];
|
|
3255
3564
|
if (plan.installClaudeSkillBootstrap) {
|
|
3256
3565
|
writes.push(
|
|
3257
|
-
writeManagedFile(
|
|
3566
|
+
writeManagedFile(
|
|
3567
|
+
claudeOrgxSkillPath,
|
|
3568
|
+
composeSkillContent("orgx", CLAUDE_ORGX_SKILL_CONTENT, extensions),
|
|
3569
|
+
"claude-orgx-skill",
|
|
3570
|
+
void 0,
|
|
3571
|
+
{
|
|
3572
|
+
coreContent: CLAUDE_ORGX_SKILL_CONTENT,
|
|
3573
|
+
records: trackedRecords,
|
|
3574
|
+
skillId: "orgx",
|
|
3575
|
+
stagedRecords,
|
|
3576
|
+
...options.force !== void 0 ? { force: options.force } : {}
|
|
3577
|
+
}
|
|
3578
|
+
)
|
|
3258
3579
|
);
|
|
3259
3580
|
}
|
|
3260
3581
|
const packs = [];
|
|
3261
3582
|
if (plan.installClaudeSkillPacks) {
|
|
3262
3583
|
for (const skillName of skillNames) {
|
|
3263
|
-
packs.push(await installSkillPack(skillName, claudeSkillsDir, fetchImpl, ref
|
|
3584
|
+
packs.push(await installSkillPack(skillName, claudeSkillsDir, fetchImpl, ref, {
|
|
3585
|
+
extensions,
|
|
3586
|
+
records: trackedRecords,
|
|
3587
|
+
stagedRecords,
|
|
3588
|
+
...options.force !== void 0 ? { force: options.force } : {}
|
|
3589
|
+
}));
|
|
3264
3590
|
}
|
|
3265
3591
|
}
|
|
3592
|
+
if (stagedRecords.size > 0) {
|
|
3593
|
+
updateWizardState((current) => {
|
|
3594
|
+
const previousFiles = current.skillFiles?.files ?? [];
|
|
3595
|
+
const nextFiles = /* @__PURE__ */ new Map();
|
|
3596
|
+
for (const record of previousFiles) {
|
|
3597
|
+
nextFiles.set(record.path, record);
|
|
3598
|
+
}
|
|
3599
|
+
for (const record of stagedRecords.values()) {
|
|
3600
|
+
nextFiles.set(record.path, record);
|
|
3601
|
+
}
|
|
3602
|
+
return {
|
|
3603
|
+
...current,
|
|
3604
|
+
skillFiles: {
|
|
3605
|
+
files: [...nextFiles.values()].sort((left, right) => left.path.localeCompare(right.path)),
|
|
3606
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3607
|
+
}
|
|
3608
|
+
};
|
|
3609
|
+
}, statePath);
|
|
3610
|
+
}
|
|
3611
|
+
const notes = [...plan.notes];
|
|
3612
|
+
if (enabledExtensions.length > 0) {
|
|
3613
|
+
notes.push(
|
|
3614
|
+
`Applied ${enabledExtensions.length} enabled OrgX skill extension${enabledExtensions.length === 1 ? "" : "s"} while syncing skills/rules.`
|
|
3615
|
+
);
|
|
3616
|
+
}
|
|
3617
|
+
if (writes.some((write) => write.skipped) || packs.some((pack) => pack.files.some((file) => file.skipped))) {
|
|
3618
|
+
notes.push("Some generated skill files were skipped because local manual edits were detected.");
|
|
3619
|
+
}
|
|
3266
3620
|
return {
|
|
3267
|
-
|
|
3621
|
+
extensions,
|
|
3622
|
+
notes,
|
|
3268
3623
|
writes,
|
|
3269
3624
|
packs
|
|
3270
3625
|
};
|
|
3271
3626
|
}
|
|
3627
|
+
function getSkillStatus(options = {}) {
|
|
3628
|
+
const state = readWizardState(options.statePath ?? ORGX_WIZARD_STATE_PATH);
|
|
3629
|
+
return {
|
|
3630
|
+
extensions: listSkillExtensions(
|
|
3631
|
+
options.extensionsDir !== void 0 ? { extensionsDir: options.extensionsDir } : {}
|
|
3632
|
+
),
|
|
3633
|
+
trackedFiles: state?.skillFiles?.files ?? []
|
|
3634
|
+
};
|
|
3635
|
+
}
|
|
3272
3636
|
|
|
3273
3637
|
// src/lib/plugins.ts
|
|
3274
3638
|
import { spawn } from "child_process";
|
|
3275
3639
|
import {
|
|
3276
|
-
existsSync as
|
|
3640
|
+
existsSync as existsSync4,
|
|
3277
3641
|
mkdirSync as mkdirSync2,
|
|
3278
3642
|
mkdtempSync,
|
|
3279
3643
|
readFileSync as readFileSync2,
|
|
3280
|
-
readdirSync,
|
|
3644
|
+
readdirSync as readdirSync2,
|
|
3281
3645
|
rmSync,
|
|
3282
3646
|
statSync as statSync2,
|
|
3283
3647
|
writeFileSync as writeFileSync2
|
|
@@ -3290,6 +3654,7 @@ var ORGX_PLUGIN_GITHUB_REF = "main";
|
|
|
3290
3654
|
var ORGX_CLAUDE_PLUGIN_NAME = "orgx-claude-code-plugin";
|
|
3291
3655
|
var ORGX_CLAUDE_MARKETPLACE_NAME = "orgx-local";
|
|
3292
3656
|
var ORGX_CODEX_PLUGIN_NAME = "orgx-codex-plugin";
|
|
3657
|
+
var ORGX_CURSOR_PLUGIN_NAME = "cursor-plugin";
|
|
3293
3658
|
var ORGX_OPENCLAW_PLUGIN_ID = "orgx";
|
|
3294
3659
|
var ORGX_OPENCLAW_PLUGIN_PACKAGE_NAME = "@useorgx/openclaw-plugin";
|
|
3295
3660
|
var CLAUDE_PLUGIN_SYNC_SPEC = {
|
|
@@ -3317,6 +3682,22 @@ var CODEX_PLUGIN_SYNC_SPEC = {
|
|
|
3317
3682
|
{ localPath: "skills", remotePath: "skills" }
|
|
3318
3683
|
]
|
|
3319
3684
|
};
|
|
3685
|
+
var CURSOR_PLUGIN_SYNC_SPEC = {
|
|
3686
|
+
owner: ORGX_PLUGIN_GITHUB_OWNER,
|
|
3687
|
+
repo: ORGX_CURSOR_PLUGIN_NAME,
|
|
3688
|
+
ref: ORGX_PLUGIN_GITHUB_REF,
|
|
3689
|
+
include: [
|
|
3690
|
+
{ localPath: ".cursor-plugin", remotePath: ".cursor-plugin" },
|
|
3691
|
+
{ localPath: ".mcp.json", remotePath: ".mcp.json" },
|
|
3692
|
+
{ localPath: "agents", remotePath: "agents" },
|
|
3693
|
+
{ localPath: "assets", remotePath: "assets" },
|
|
3694
|
+
{ localPath: "commands", remotePath: "commands" },
|
|
3695
|
+
{ localPath: "hooks", remotePath: "hooks" },
|
|
3696
|
+
{ localPath: "rules", remotePath: "rules" },
|
|
3697
|
+
{ localPath: "scripts", remotePath: "scripts" },
|
|
3698
|
+
{ localPath: "skills", remotePath: "skills" }
|
|
3699
|
+
]
|
|
3700
|
+
};
|
|
3320
3701
|
function defaultPluginPaths() {
|
|
3321
3702
|
return {
|
|
3322
3703
|
claudeMarketplaceDir: CLAUDE_MANAGED_MARKETPLACE_DIR,
|
|
@@ -3324,6 +3705,7 @@ function defaultPluginPaths() {
|
|
|
3324
3705
|
claudePluginDir: CLAUDE_MANAGED_PLUGIN_DIR,
|
|
3325
3706
|
codexMarketplacePath: CODEX_MARKETPLACE_PATH,
|
|
3326
3707
|
codexPluginDir: CODEX_ORGX_PLUGIN_DIR,
|
|
3708
|
+
cursorPluginDir: CURSOR_ORGX_PLUGIN_DIR,
|
|
3327
3709
|
cursorRulePath: CURSOR_ORGX_RULE_PATH
|
|
3328
3710
|
};
|
|
3329
3711
|
}
|
|
@@ -3343,8 +3725,8 @@ function encodeRepoPath2(value) {
|
|
|
3343
3725
|
return value.split("/").filter((segment) => segment.length > 0).map((segment) => encodeURIComponent(segment)).join("/");
|
|
3344
3726
|
}
|
|
3345
3727
|
function isLikelyRepoFilePath(path) {
|
|
3346
|
-
const
|
|
3347
|
-
return
|
|
3728
|
+
const basename2 = path.split("/").pop() ?? path;
|
|
3729
|
+
return basename2.includes(".") && !/^\.[^./]+$/.test(basename2);
|
|
3348
3730
|
}
|
|
3349
3731
|
function buildContentsUrl2(spec, path) {
|
|
3350
3732
|
const encodedPath = encodeRepoPath2(path);
|
|
@@ -3454,7 +3836,7 @@ async function fetchRemoteBytes(sourceUrl, fetchImpl) {
|
|
|
3454
3836
|
return Buffer.from(await response.arrayBuffer());
|
|
3455
3837
|
}
|
|
3456
3838
|
function readBytesIfExists(path) {
|
|
3457
|
-
if (!
|
|
3839
|
+
if (!existsSync4(path)) return null;
|
|
3458
3840
|
try {
|
|
3459
3841
|
if (!statSync2(path).isFile()) {
|
|
3460
3842
|
return null;
|
|
@@ -3478,17 +3860,17 @@ function writeBytesIfChanged(path, bytes) {
|
|
|
3478
3860
|
return true;
|
|
3479
3861
|
}
|
|
3480
3862
|
function removePathIfExists(path) {
|
|
3481
|
-
if (!
|
|
3863
|
+
if (!existsSync4(path)) return false;
|
|
3482
3864
|
rmSync(path, { force: true, recursive: true });
|
|
3483
3865
|
return true;
|
|
3484
3866
|
}
|
|
3485
3867
|
function listRelativeFiles(root, base = root) {
|
|
3486
|
-
if (!
|
|
3868
|
+
if (!existsSync4(root)) return [];
|
|
3487
3869
|
if (!statSync2(root).isDirectory()) {
|
|
3488
3870
|
return [];
|
|
3489
3871
|
}
|
|
3490
3872
|
const files = [];
|
|
3491
|
-
for (const entry of
|
|
3873
|
+
for (const entry of readdirSync2(root, { withFileTypes: true })) {
|
|
3492
3874
|
const nextPath = join3(root, entry.name);
|
|
3493
3875
|
if (entry.isDirectory()) {
|
|
3494
3876
|
files.push(...listRelativeFiles(nextPath, base));
|
|
@@ -3501,15 +3883,15 @@ function listRelativeFiles(root, base = root) {
|
|
|
3501
3883
|
return files.sort();
|
|
3502
3884
|
}
|
|
3503
3885
|
function pruneEmptyDirectories(root, current = root) {
|
|
3504
|
-
if (!
|
|
3886
|
+
if (!existsSync4(current) || !statSync2(current).isDirectory()) {
|
|
3505
3887
|
return false;
|
|
3506
3888
|
}
|
|
3507
3889
|
let changed = false;
|
|
3508
|
-
for (const entry of
|
|
3890
|
+
for (const entry of readdirSync2(current, { withFileTypes: true })) {
|
|
3509
3891
|
if (!entry.isDirectory()) continue;
|
|
3510
3892
|
changed = pruneEmptyDirectories(root, join3(current, entry.name)) || changed;
|
|
3511
3893
|
}
|
|
3512
|
-
if (current !== root &&
|
|
3894
|
+
if (current !== root && readdirSync2(current).length === 0) {
|
|
3513
3895
|
rmSync(current, { force: true, recursive: true });
|
|
3514
3896
|
return true;
|
|
3515
3897
|
}
|
|
@@ -3519,7 +3901,7 @@ async function syncManagedRepoTree(spec, destinationRoot, fetchImpl) {
|
|
|
3519
3901
|
const remoteFiles = await collectRemoteRepoFiles(spec, fetchImpl);
|
|
3520
3902
|
let changed = false;
|
|
3521
3903
|
const expected = new Set(remoteFiles.map((file) => file.localPath));
|
|
3522
|
-
if (
|
|
3904
|
+
if (existsSync4(destinationRoot) && !statSync2(destinationRoot).isDirectory()) {
|
|
3523
3905
|
rmSync(destinationRoot, { force: true, recursive: true });
|
|
3524
3906
|
changed = true;
|
|
3525
3907
|
}
|
|
@@ -3610,7 +3992,7 @@ function upsertCodexMarketplaceEntry(path) {
|
|
|
3610
3992
|
return writeJsonIfChanged(path, nextDocument);
|
|
3611
3993
|
}
|
|
3612
3994
|
function removeCodexMarketplaceEntry(path) {
|
|
3613
|
-
if (!
|
|
3995
|
+
if (!existsSync4(path)) {
|
|
3614
3996
|
return false;
|
|
3615
3997
|
}
|
|
3616
3998
|
const { document, plugins } = readMarketplacePlugins(path);
|
|
@@ -3744,15 +4126,36 @@ async function getOpenclawInstallState(runner) {
|
|
|
3744
4126
|
installed: extractOpenclawPluginIds(result.stdout).includes(ORGX_OPENCLAW_PLUGIN_ID)
|
|
3745
4127
|
};
|
|
3746
4128
|
}
|
|
4129
|
+
function cursorPluginManifestPath(paths) {
|
|
4130
|
+
return join3(paths.cursorPluginDir, ".cursor-plugin", "plugin.json");
|
|
4131
|
+
}
|
|
4132
|
+
function cursorPluginMcpPath(paths) {
|
|
4133
|
+
return join3(paths.cursorPluginDir, ".mcp.json");
|
|
4134
|
+
}
|
|
4135
|
+
function isCursorPluginInstalled(paths) {
|
|
4136
|
+
return existsSync4(cursorPluginManifestPath(paths)) && existsSync4(cursorPluginMcpPath(paths));
|
|
4137
|
+
}
|
|
4138
|
+
function isCursorPluginAvailable(paths) {
|
|
4139
|
+
return detectSurface("cursor").detected || existsSync4(paths.cursorPluginDir) || existsSync4(dirname3(paths.cursorPluginDir)) || readTextIfExists(paths.cursorRulePath) !== null;
|
|
4140
|
+
}
|
|
3747
4141
|
function buildCursorStatus(paths) {
|
|
3748
4142
|
const existingRules = readTextIfExists(paths.cursorRulePath);
|
|
3749
|
-
const available =
|
|
3750
|
-
|
|
4143
|
+
const available = isCursorPluginAvailable(paths);
|
|
4144
|
+
const installed = isCursorPluginInstalled(paths);
|
|
4145
|
+
if (installed) {
|
|
3751
4146
|
return {
|
|
3752
4147
|
target: "cursor",
|
|
3753
4148
|
available: true,
|
|
3754
4149
|
installed: true,
|
|
3755
|
-
message: "Cursor OrgX
|
|
4150
|
+
message: "Cursor OrgX plugin bundle is installed."
|
|
4151
|
+
};
|
|
4152
|
+
}
|
|
4153
|
+
if (existingRules === CURSOR_RULES_CONTENT) {
|
|
4154
|
+
return {
|
|
4155
|
+
target: "cursor",
|
|
4156
|
+
available: true,
|
|
4157
|
+
installed: false,
|
|
4158
|
+
message: "Legacy Cursor OrgX rules are installed; run plugins add cursor to install the full plugin bundle."
|
|
3756
4159
|
};
|
|
3757
4160
|
}
|
|
3758
4161
|
if (existingRules !== null) {
|
|
@@ -3760,14 +4163,14 @@ function buildCursorStatus(paths) {
|
|
|
3760
4163
|
target: "cursor",
|
|
3761
4164
|
available: true,
|
|
3762
4165
|
installed: false,
|
|
3763
|
-
message: "Cursor
|
|
4166
|
+
message: "Cursor rules file exists, but the OrgX plugin bundle is missing."
|
|
3764
4167
|
};
|
|
3765
4168
|
}
|
|
3766
4169
|
return {
|
|
3767
4170
|
target: "cursor",
|
|
3768
4171
|
available,
|
|
3769
4172
|
installed: false,
|
|
3770
|
-
message: available ? "Cursor is available and ready for OrgX
|
|
4173
|
+
message: available ? "Cursor is available and ready for OrgX plugin install." : "Cursor was not detected."
|
|
3771
4174
|
};
|
|
3772
4175
|
}
|
|
3773
4176
|
async function buildClaudeStatus(paths, runner) {
|
|
@@ -3788,7 +4191,7 @@ async function buildClaudeStatus(paths, runner) {
|
|
|
3788
4191
|
message: "Claude Code was not detected."
|
|
3789
4192
|
};
|
|
3790
4193
|
}
|
|
3791
|
-
const marketplaceExists =
|
|
4194
|
+
const marketplaceExists = existsSync4(paths.claudeMarketplaceManifestPath);
|
|
3792
4195
|
return {
|
|
3793
4196
|
target: "claude",
|
|
3794
4197
|
available: true,
|
|
@@ -3799,7 +4202,7 @@ async function buildClaudeStatus(paths, runner) {
|
|
|
3799
4202
|
function buildCodexStatus(paths, runner) {
|
|
3800
4203
|
return (async () => {
|
|
3801
4204
|
const available = detectSurface("codex").detected || await commandExists("codex", runner);
|
|
3802
|
-
const pluginExists =
|
|
4205
|
+
const pluginExists = existsSync4(paths.codexPluginDir);
|
|
3803
4206
|
const marketplaceExists = codexMarketplaceHasOrgxEntry(paths.codexMarketplacePath);
|
|
3804
4207
|
const installed = pluginExists && marketplaceExists;
|
|
3805
4208
|
if (installed) {
|
|
@@ -3885,28 +4288,19 @@ async function resolveOpenclawTarball(fetchImpl) {
|
|
|
3885
4288
|
version: latestVersion
|
|
3886
4289
|
};
|
|
3887
4290
|
}
|
|
3888
|
-
function installCursorPlugin(paths) {
|
|
3889
|
-
|
|
3890
|
-
const available = detectSurface("cursor").detected || existingRules !== null;
|
|
3891
|
-
if (!available) {
|
|
4291
|
+
async function installCursorPlugin(paths, fetchImpl) {
|
|
4292
|
+
if (!isCursorPluginAvailable(paths)) {
|
|
3892
4293
|
return {
|
|
3893
4294
|
target: "cursor",
|
|
3894
4295
|
changed: false,
|
|
3895
4296
|
message: "Cursor is not available on this machine."
|
|
3896
4297
|
};
|
|
3897
4298
|
}
|
|
3898
|
-
|
|
3899
|
-
return {
|
|
3900
|
-
target: "cursor",
|
|
3901
|
-
changed: false,
|
|
3902
|
-
message: "Cursor OrgX rules are already installed."
|
|
3903
|
-
};
|
|
3904
|
-
}
|
|
3905
|
-
writeTextFile(paths.cursorRulePath, CURSOR_RULES_CONTENT);
|
|
4299
|
+
const syncResult = await syncManagedRepoTree(CURSOR_PLUGIN_SYNC_SPEC, paths.cursorPluginDir, fetchImpl);
|
|
3906
4300
|
return {
|
|
3907
4301
|
target: "cursor",
|
|
3908
|
-
changed:
|
|
3909
|
-
message:
|
|
4302
|
+
changed: syncResult.changed,
|
|
4303
|
+
message: syncResult.changed ? `Synced ${syncResult.fileCount} Cursor plugin files into ${paths.cursorPluginDir}. Reload Cursor to finish loading the plugin.` : "Cursor plugin bundle is already installed and up to date."
|
|
3910
4304
|
};
|
|
3911
4305
|
}
|
|
3912
4306
|
async function installClaudePlugin(paths, fetchImpl, runner) {
|
|
@@ -4017,25 +4411,13 @@ async function installOpenclawPlugin(fetchImpl, runner) {
|
|
|
4017
4411
|
}
|
|
4018
4412
|
function uninstallCursorPlugin(paths) {
|
|
4019
4413
|
const existingRules = readTextIfExists(paths.cursorRulePath);
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
changed: false,
|
|
4024
|
-
message: "Cursor OrgX rules were not installed."
|
|
4025
|
-
};
|
|
4026
|
-
}
|
|
4027
|
-
if (existingRules !== CURSOR_RULES_CONTENT) {
|
|
4028
|
-
return {
|
|
4029
|
-
target: "cursor",
|
|
4030
|
-
changed: false,
|
|
4031
|
-
message: "Cursor rules file differs from the managed OrgX rules, so it was left in place."
|
|
4032
|
-
};
|
|
4033
|
-
}
|
|
4034
|
-
const changed = deleteFileIfExists(paths.cursorRulePath);
|
|
4414
|
+
const removedPluginDir = removePathIfExists(paths.cursorPluginDir);
|
|
4415
|
+
const removedLegacyRules = existingRules === CURSOR_RULES_CONTENT ? deleteFileIfExists(paths.cursorRulePath) : false;
|
|
4416
|
+
const changed = removedPluginDir || removedLegacyRules;
|
|
4035
4417
|
return {
|
|
4036
4418
|
target: "cursor",
|
|
4037
4419
|
changed,
|
|
4038
|
-
message: changed ? "Removed the managed Cursor OrgX rules." : "Cursor OrgX rules were not installed."
|
|
4420
|
+
message: changed ? existingRules !== null && existingRules !== CURSOR_RULES_CONTENT ? "Removed the managed Cursor OrgX plugin bundle. Existing Cursor rules differ from managed OrgX rules, so they were left in place." : "Removed the managed Cursor OrgX plugin bundle and legacy managed Cursor rules." : existingRules !== null && existingRules !== CURSOR_RULES_CONTENT ? "Cursor plugin was not installed. Existing Cursor rules differ from managed OrgX rules, so they were left in place." : "Cursor plugin was not installed."
|
|
4039
4421
|
};
|
|
4040
4422
|
}
|
|
4041
4423
|
async function uninstallClaudePlugin(paths, runner) {
|
|
@@ -4151,7 +4533,7 @@ async function installOrgxPlugins(options = {}) {
|
|
|
4151
4533
|
for (const target of targets) {
|
|
4152
4534
|
switch (target) {
|
|
4153
4535
|
case "cursor":
|
|
4154
|
-
results.push(installCursorPlugin(paths));
|
|
4536
|
+
results.push(await installCursorPlugin(paths, fetchImpl));
|
|
4155
4537
|
break;
|
|
4156
4538
|
case "claude":
|
|
4157
4539
|
results.push(await installClaudePlugin(paths, fetchImpl, runner));
|
|
@@ -4643,7 +5025,7 @@ function formatAuthSource(source) {
|
|
|
4643
5025
|
function formatPluginTargetLabel(target) {
|
|
4644
5026
|
switch (target) {
|
|
4645
5027
|
case "cursor":
|
|
4646
|
-
return "Cursor
|
|
5028
|
+
return "Cursor plugin";
|
|
4647
5029
|
case "claude":
|
|
4648
5030
|
return "Claude Code";
|
|
4649
5031
|
case "codex":
|
|
@@ -4689,10 +5071,10 @@ function printPluginMutationReport(report) {
|
|
|
4689
5071
|
}
|
|
4690
5072
|
}
|
|
4691
5073
|
async function printPluginStatusSection() {
|
|
4692
|
-
const spinner = createOrgxSpinner("Checking OrgX plugin
|
|
5074
|
+
const spinner = createOrgxSpinner("Checking OrgX companion plugin status");
|
|
4693
5075
|
spinner.start();
|
|
4694
5076
|
const statuses = await listOrgxPluginStatuses();
|
|
4695
|
-
spinner.succeed("OrgX plugin
|
|
5077
|
+
spinner.succeed("OrgX companion plugin status checked");
|
|
4696
5078
|
console.log("");
|
|
4697
5079
|
console.log(pc3.dim(" plugins"));
|
|
4698
5080
|
printPluginStatusReport(statuses);
|
|
@@ -4700,28 +5082,67 @@ async function printPluginStatusSection() {
|
|
|
4700
5082
|
}
|
|
4701
5083
|
function printSkillInstallReport(report) {
|
|
4702
5084
|
for (const write of report.writes) {
|
|
4703
|
-
const icon = write.changed ? ICON.ok : ICON.skip;
|
|
4704
|
-
const state = write.changed ? pc3.green("updated ") : pc3.dim("unchanged");
|
|
5085
|
+
const icon = write.skipped ? ICON.warn : write.changed ? ICON.ok : ICON.skip;
|
|
5086
|
+
const state = write.skipped ? pc3.yellow("skipped ") : write.changed ? pc3.green("updated ") : pc3.dim("unchanged");
|
|
4705
5087
|
console.log(` ${icon} ${pc3.bold(write.label.padEnd(10))} ${state}`);
|
|
5088
|
+
if (write.reason) {
|
|
5089
|
+
console.log(` ${pc3.dim(write.reason)}`);
|
|
5090
|
+
}
|
|
4706
5091
|
}
|
|
4707
5092
|
for (const pack of report.packs) {
|
|
4708
5093
|
const changedCount = pack.files.filter((f) => f.changed).length;
|
|
4709
|
-
const
|
|
4710
|
-
const
|
|
5094
|
+
const skippedCount = pack.files.filter((f) => f.skipped).length;
|
|
5095
|
+
const icon = skippedCount > 0 ? ICON.warn : changedCount > 0 ? ICON.ok : ICON.skip;
|
|
5096
|
+
const state = skippedCount > 0 ? pc3.yellow(`${skippedCount} skipped `) : changedCount > 0 ? pc3.green(`${changedCount} updated `) : pc3.dim("unchanged");
|
|
4711
5097
|
console.log(` ${icon} ${pc3.bold(pack.name.padEnd(10))} ${state} ${pc3.dim(`${pack.files.length} files`)}`);
|
|
5098
|
+
for (const file of pack.files.filter((entry) => entry.skipped && entry.reason)) {
|
|
5099
|
+
console.log(` ${pc3.dim(`${file.label}: ${file.reason}`)}`);
|
|
5100
|
+
}
|
|
4712
5101
|
}
|
|
4713
5102
|
for (const note of report.notes) {
|
|
4714
5103
|
console.log(` ${ICON.skip} ${pc3.dim(note)}`);
|
|
4715
5104
|
}
|
|
4716
5105
|
}
|
|
4717
5106
|
function countSkillReportChanges(report) {
|
|
4718
|
-
const writeChanges = report.writes.filter((write) => write.changed).length;
|
|
5107
|
+
const writeChanges = report.writes.filter((write) => write.changed && !write.skipped).length;
|
|
4719
5108
|
const packChanges = report.packs.reduce(
|
|
4720
|
-
(count, pack) => count + pack.files.filter((file) => file.changed).length,
|
|
5109
|
+
(count, pack) => count + pack.files.filter((file) => file.changed && !file.skipped).length,
|
|
4721
5110
|
0
|
|
4722
5111
|
);
|
|
4723
5112
|
return writeChanges + packChanges;
|
|
4724
5113
|
}
|
|
5114
|
+
function printSkillExtensions(extensions) {
|
|
5115
|
+
if (extensions.length === 0) {
|
|
5116
|
+
console.log(` ${ICON.skip} ${pc3.dim("no skill extensions yet")}`);
|
|
5117
|
+
return;
|
|
5118
|
+
}
|
|
5119
|
+
for (const extension of extensions) {
|
|
5120
|
+
const icon = extension.enabled ? ICON.ok : ICON.skip;
|
|
5121
|
+
const state = extension.enabled ? pc3.green("enabled ") : pc3.dim("disabled ");
|
|
5122
|
+
console.log(
|
|
5123
|
+
` ${icon} ${pc3.bold(extension.id.padEnd(24))} ${state} ${pc3.dim(extension.path)}`
|
|
5124
|
+
);
|
|
5125
|
+
}
|
|
5126
|
+
}
|
|
5127
|
+
function printSkillExtensionWrite(result) {
|
|
5128
|
+
const action = result.created ? "created" : result.changed ? "updated" : "unchanged";
|
|
5129
|
+
const color = result.created || result.changed ? pc3.green : pc3.dim;
|
|
5130
|
+
console.log(
|
|
5131
|
+
` ${result.created || result.changed ? ICON.ok : ICON.skip} ${pc3.bold(result.extension.id.padEnd(24))} ${color(action)}`
|
|
5132
|
+
);
|
|
5133
|
+
console.log(` ${pc3.dim(result.path)}`);
|
|
5134
|
+
}
|
|
5135
|
+
function openPathInEditor(path) {
|
|
5136
|
+
const editor = process.env.EDITOR || process.env.VISUAL;
|
|
5137
|
+
if (!editor) {
|
|
5138
|
+
return false;
|
|
5139
|
+
}
|
|
5140
|
+
const result = spawnSync3(editor, [path], {
|
|
5141
|
+
shell: true,
|
|
5142
|
+
stdio: "inherit"
|
|
5143
|
+
});
|
|
5144
|
+
return result.status === 0;
|
|
5145
|
+
}
|
|
4725
5146
|
async function safeTrackWizardTelemetry(event, properties = {}) {
|
|
4726
5147
|
try {
|
|
4727
5148
|
await trackWizardTelemetry(event, properties);
|
|
@@ -5012,17 +5433,18 @@ async function promptOptionalCompanionPluginTargets(input) {
|
|
|
5012
5433
|
}
|
|
5013
5434
|
let statuses = input.statuses;
|
|
5014
5435
|
if (!statuses) {
|
|
5015
|
-
const spinner = createOrgxSpinner("Checking optional OrgX plugin
|
|
5436
|
+
const spinner = createOrgxSpinner("Checking optional OrgX companion plugin status");
|
|
5016
5437
|
spinner.start();
|
|
5017
5438
|
statuses = await listOrgxPluginStatuses();
|
|
5018
|
-
spinner.succeed("Optional OrgX plugin
|
|
5439
|
+
spinner.succeed("Optional OrgX companion plugin status checked");
|
|
5019
5440
|
}
|
|
5020
5441
|
const installable = statuses.filter((status) => status.available && !status.installed);
|
|
5021
5442
|
if (installable.length === 0) {
|
|
5022
5443
|
return [];
|
|
5023
5444
|
}
|
|
5024
5445
|
const selection = await multiselectPrompt({
|
|
5025
|
-
|
|
5446
|
+
initialValues: installable.map((status) => status.target),
|
|
5447
|
+
message: "Install OrgX companion plugins into your detected AI tools?",
|
|
5026
5448
|
options: installable.map((status) => ({
|
|
5027
5449
|
value: status.target,
|
|
5028
5450
|
label: `Install ${formatPluginTargetLabel(status.target)}`,
|
|
@@ -5037,12 +5459,12 @@ async function promptOptionalCompanionPluginTargets(input) {
|
|
|
5037
5459
|
return selection;
|
|
5038
5460
|
}
|
|
5039
5461
|
function printPluginSkillOwnershipNote(targets) {
|
|
5040
|
-
if (!targets.some((target) => target === "claude" || target === "codex")) {
|
|
5462
|
+
if (!targets.some((target) => target === "cursor" || target === "claude" || target === "codex")) {
|
|
5041
5463
|
return;
|
|
5042
5464
|
}
|
|
5043
5465
|
console.log(
|
|
5044
5466
|
` ${ICON.skip} ${pc3.dim(
|
|
5045
|
-
"Claude Code and Codex companion plugins carry their own OrgX skills. Use 'wizard skills add' for
|
|
5467
|
+
"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."
|
|
5046
5468
|
)}`
|
|
5047
5469
|
);
|
|
5048
5470
|
}
|
|
@@ -5155,13 +5577,13 @@ function printDoctorReport(report, assessment) {
|
|
|
5155
5577
|
}
|
|
5156
5578
|
async function main() {
|
|
5157
5579
|
const program = new Command();
|
|
5158
|
-
program.name("orgx-wizard").description("
|
|
5159
|
-
const pkgVersion = true ? "0.1.
|
|
5580
|
+
program.name("orgx-wizard").description("Add OrgX MCP configs, skills/rules, and companion plugins to your local AI tools.").showHelpAfterError();
|
|
5581
|
+
const pkgVersion = true ? "0.1.12" : void 0;
|
|
5160
5582
|
program.version(pkgVersion ?? "unknown", "-V, --version");
|
|
5161
5583
|
program.hook("preAction", () => {
|
|
5162
5584
|
console.log(renderBanner(pkgVersion));
|
|
5163
5585
|
});
|
|
5164
|
-
program.command("setup").description("
|
|
5586
|
+
program.command("setup").description("Add OrgX MCP configs, skills/rules, and companion plugins to detected tools.").option("--preset <name>", "run a setup bundle (currently: founder)").action(async (options) => {
|
|
5165
5587
|
const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
5166
5588
|
await safeTrackWizardTelemetry("wizard_started", {
|
|
5167
5589
|
command: "setup",
|
|
@@ -5527,7 +5949,7 @@ async function main() {
|
|
|
5527
5949
|
);
|
|
5528
5950
|
}
|
|
5529
5951
|
});
|
|
5530
|
-
program.command("uninstall").description("Remove OrgX-managed
|
|
5952
|
+
program.command("uninstall").description("Remove OrgX-managed MCP tool configs, companion plugins, auth, and wizard state from this machine.").option("--keep-auth", "Keep the wizard-local saved OrgX API key.").option("--keep-state", "Keep wizard-local setup state.").option("--skip-plugins", "Skip companion plugin and legacy Cursor rules removal.").option("--skip-surfaces", "Skip MCP tool config removal.").action(async (options) => {
|
|
5531
5953
|
await safeTrackWizardTelemetry("wizard_uninstalled", {
|
|
5532
5954
|
keep_auth: Boolean(options.keepAuth),
|
|
5533
5955
|
keep_state: Boolean(options.keepState),
|
|
@@ -5548,10 +5970,10 @@ async function main() {
|
|
|
5548
5970
|
} else {
|
|
5549
5971
|
console.log("");
|
|
5550
5972
|
console.log(pc3.dim(" plugins"));
|
|
5551
|
-
const spinner = createOrgxSpinner("Removing OrgX companion plugins and rules");
|
|
5973
|
+
const spinner = createOrgxSpinner("Removing OrgX companion plugins and legacy Cursor rules");
|
|
5552
5974
|
spinner.start();
|
|
5553
5975
|
const pluginReport = await uninstallOrgxPlugins({ targets: ["all"] });
|
|
5554
|
-
spinner.succeed("OrgX companion plugins and rules processed");
|
|
5976
|
+
spinner.succeed("OrgX companion plugins and legacy Cursor rules processed");
|
|
5555
5977
|
printPluginMutationReport(pluginReport);
|
|
5556
5978
|
}
|
|
5557
5979
|
console.log("");
|
|
@@ -5584,24 +6006,24 @@ async function main() {
|
|
|
5584
6006
|
const results = removeSurface(names);
|
|
5585
6007
|
printMutationResults(results);
|
|
5586
6008
|
});
|
|
5587
|
-
const mcp = program.command("mcp").description("
|
|
5588
|
-
mcp.command("add").description("Add OrgX MCP entries to one
|
|
6009
|
+
const mcp = program.command("mcp").description("Add or remove OrgX MCP config entries in Claude, Cursor, Codex, VS Code, Windsurf, and Zed.");
|
|
6010
|
+
mcp.command("add").description("Add OrgX MCP entries to one tool config or all supported MCP tool configs.").argument("[surfaces...]", "claude, cursor, codex, vscode, windsurf, zed, or all", ["all"]).action(async (names) => {
|
|
5589
6011
|
const results = await addMcpSurface(names);
|
|
5590
6012
|
printMutationResults(results);
|
|
5591
6013
|
});
|
|
5592
|
-
mcp.command("remove").description("Remove OrgX MCP entries from one
|
|
6014
|
+
mcp.command("remove").description("Remove OrgX MCP entries from one tool config or all supported MCP tool configs.").argument("[surfaces...]", "claude, cursor, codex, vscode, windsurf, zed, or all", ["all"]).action((names) => {
|
|
5593
6015
|
const results = removeMcpSurface(names);
|
|
5594
6016
|
printMutationResults(results);
|
|
5595
6017
|
});
|
|
5596
|
-
const plugins = program.command("plugins").description("Install or remove
|
|
5597
|
-
plugins.command("list").description("Show companion plugin availability and install status.").action(async () => {
|
|
5598
|
-
const spinner = createOrgxSpinner("Checking OrgX plugin
|
|
6018
|
+
const plugins = program.command("plugins").description("Install or remove OrgX companion plugins in Cursor, Claude Code, Codex, and OpenClaw.");
|
|
6019
|
+
plugins.command("list").description("Show companion plugin availability and install status in your tools.").action(async () => {
|
|
6020
|
+
const spinner = createOrgxSpinner("Checking OrgX companion plugin status");
|
|
5599
6021
|
spinner.start();
|
|
5600
6022
|
const statuses = await listOrgxPluginStatuses();
|
|
5601
|
-
spinner.succeed("OrgX plugin
|
|
6023
|
+
spinner.succeed("OrgX companion plugin status checked");
|
|
5602
6024
|
printPluginStatusReport(statuses);
|
|
5603
6025
|
});
|
|
5604
|
-
plugins.command("add").description("Install
|
|
6026
|
+
plugins.command("add").description("Install OrgX companion plugins into Cursor, Claude Code, Codex, and OpenClaw.").argument("[targets...]", "cursor, claude, codex, openclaw, or all", ["all"]).action(async (targets) => {
|
|
5605
6027
|
const spinner = createOrgxSpinner("Installing OrgX companion plugins");
|
|
5606
6028
|
spinner.start();
|
|
5607
6029
|
const report = await installOrgxPlugins({ targets });
|
|
@@ -5615,11 +6037,11 @@ async function main() {
|
|
|
5615
6037
|
target_count: report.results.length
|
|
5616
6038
|
});
|
|
5617
6039
|
});
|
|
5618
|
-
plugins.command("remove").description("Uninstall managed
|
|
5619
|
-
const spinner = createOrgxSpinner("Removing OrgX companion plugins");
|
|
6040
|
+
plugins.command("remove").description("Uninstall managed OrgX companion plugins and legacy managed Cursor rules from Cursor, Claude Code, Codex, and OpenClaw.").argument("[targets...]", "cursor, claude, codex, openclaw, or all", ["all"]).action(async (targets) => {
|
|
6041
|
+
const spinner = createOrgxSpinner("Removing OrgX companion plugins and legacy Cursor rules");
|
|
5620
6042
|
spinner.start();
|
|
5621
6043
|
const report = await uninstallOrgxPlugins({ targets });
|
|
5622
|
-
spinner.succeed("OrgX companion plugins
|
|
6044
|
+
spinner.succeed("OrgX companion plugins and legacy Cursor rules processed");
|
|
5623
6045
|
printPluginMutationReport(report);
|
|
5624
6046
|
await safeTrackWizardTelemetry("plugins_removed", {
|
|
5625
6047
|
changed_count: countPluginReportChanges(report),
|
|
@@ -5694,16 +6116,17 @@ async function main() {
|
|
|
5694
6116
|
process.exitCode = 1;
|
|
5695
6117
|
}
|
|
5696
6118
|
});
|
|
5697
|
-
const skills = program.command("skills").description("Install OrgX
|
|
5698
|
-
skills.command("add").description("Write standalone OrgX
|
|
6119
|
+
const skills = program.command("skills").description("Install OrgX skills and rules into supported local tools.");
|
|
6120
|
+
skills.command("add").description("Write standalone OrgX Cursor rules and Claude skills, skipping tool surfaces already owned by companion plugins.").argument("[packs...]", "skill pack names or 'all'", ["all"]).option("--force", "Overwrite generated skill files even when manual edits are detected.").action(async (packs, options) => {
|
|
5699
6121
|
const pluginTargets = (await listOrgxPluginStatuses()).filter((status) => status.installed).map((status) => status.target);
|
|
5700
|
-
const spinner = createOrgxSpinner("Installing OrgX rules
|
|
6122
|
+
const spinner = createOrgxSpinner("Installing OrgX skills/rules into tools");
|
|
5701
6123
|
spinner.start();
|
|
5702
6124
|
const report = await installOrgxSkills({
|
|
6125
|
+
force: options.force === true,
|
|
5703
6126
|
pluginTargets,
|
|
5704
6127
|
skillNames: packs
|
|
5705
6128
|
});
|
|
5706
|
-
spinner.succeed("OrgX rules
|
|
6129
|
+
spinner.succeed("OrgX skills/rules installed into tools");
|
|
5707
6130
|
printSkillInstallReport(report);
|
|
5708
6131
|
await safeTrackWizardTelemetry("skills_installed", {
|
|
5709
6132
|
changed_count: countSkillReportChanges(report),
|
|
@@ -5711,9 +6134,99 @@ async function main() {
|
|
|
5711
6134
|
pack_count: report.packs.length,
|
|
5712
6135
|
plugin_managed_target_count: pluginTargets.length,
|
|
5713
6136
|
requested_pack_count: packs.length,
|
|
6137
|
+
skill_extension_count: report.extensions.length,
|
|
6138
|
+
write_count: report.writes.length
|
|
6139
|
+
});
|
|
6140
|
+
});
|
|
6141
|
+
skills.command("sync").description("Recompose installed OrgX skills/rules from core skills plus local extensions.").argument("[packs...]", "skill pack names or 'all'", ["all"]).option("--force", "Overwrite generated skill files even when manual edits are detected.").action(async (packs, options) => {
|
|
6142
|
+
const pluginTargets = (await listOrgxPluginStatuses()).filter((status) => status.installed).map((status) => status.target);
|
|
6143
|
+
const spinner = createOrgxSpinner("Syncing OrgX skills/rules and extensions into tools");
|
|
6144
|
+
spinner.start();
|
|
6145
|
+
const report = await installOrgxSkills({
|
|
6146
|
+
force: options.force === true,
|
|
6147
|
+
pluginTargets,
|
|
6148
|
+
skillNames: packs
|
|
6149
|
+
});
|
|
6150
|
+
spinner.succeed("OrgX skills/rules synced into tools");
|
|
6151
|
+
printSkillInstallReport(report);
|
|
6152
|
+
await safeTrackWizardTelemetry("skills_synced", {
|
|
6153
|
+
changed_count: countSkillReportChanges(report),
|
|
6154
|
+
command: "skills:sync",
|
|
6155
|
+
pack_count: report.packs.length,
|
|
6156
|
+
plugin_managed_target_count: pluginTargets.length,
|
|
6157
|
+
requested_pack_count: packs.length,
|
|
6158
|
+
skill_extension_count: report.extensions.length,
|
|
5714
6159
|
write_count: report.writes.length
|
|
5715
6160
|
});
|
|
5716
6161
|
});
|
|
6162
|
+
skills.command("status").description("Show installed skill/rule tracking and local skill extensions.").action(async () => {
|
|
6163
|
+
const report = getSkillStatus();
|
|
6164
|
+
console.log(pc3.dim(" extensions"));
|
|
6165
|
+
printSkillExtensions(report.extensions);
|
|
6166
|
+
console.log("");
|
|
6167
|
+
console.log(pc3.dim(" generated files"));
|
|
6168
|
+
if (report.trackedFiles.length === 0) {
|
|
6169
|
+
console.log(` ${ICON.skip} ${pc3.dim("no generated skill files tracked yet")}`);
|
|
6170
|
+
} else {
|
|
6171
|
+
for (const file of report.trackedFiles) {
|
|
6172
|
+
console.log(` ${ICON.ok} ${pc3.bold(file.skillId.padEnd(24))} ${pc3.dim(file.path)}`);
|
|
6173
|
+
}
|
|
6174
|
+
}
|
|
6175
|
+
});
|
|
6176
|
+
const skillExtensions = skills.command("extensions").description("Create, edit, and sync user extensions appended after OrgX core skills.");
|
|
6177
|
+
skillExtensions.command("list").description("List local OrgX skill extensions.").action(() => {
|
|
6178
|
+
printSkillExtensions(listSkillExtensions());
|
|
6179
|
+
});
|
|
6180
|
+
skillExtensions.command("add").description("Create a local extension file for an OrgX skill.").argument("<skill>", "Skill id, for example orgx, cursor-rules, or morning-briefing").option("--scope <scope>", "Extension scope: user, workspace, or project.", "user").option("--title <title>", "Extension title.").option("--content <content>", "Initial extension body content.").option("--overwrite", "Overwrite an existing extension file.").action((skill, options) => {
|
|
6181
|
+
const result = addSkillExtension({
|
|
6182
|
+
overwrite: options.overwrite === true,
|
|
6183
|
+
skillId: skill,
|
|
6184
|
+
...options.content !== void 0 ? { content: options.content } : {},
|
|
6185
|
+
...options.scope !== void 0 ? { scope: options.scope } : {},
|
|
6186
|
+
...options.title !== void 0 ? { title: options.title } : {}
|
|
6187
|
+
});
|
|
6188
|
+
printSkillExtensionWrite(result);
|
|
6189
|
+
console.log(
|
|
6190
|
+
` ${ICON.skip} ${pc3.dim(`Run ${getCmd()} skills sync to apply it to configured tools.`)}`
|
|
6191
|
+
);
|
|
6192
|
+
});
|
|
6193
|
+
skillExtensions.command("edit").description("Create if needed, then open a local OrgX skill extension in $EDITOR.").argument("<skill>", "Skill id, for example orgx, cursor-rules, or morning-briefing").option("--scope <scope>", "Extension scope: user, workspace, or project.", "user").action((skill, options) => {
|
|
6194
|
+
const result = addSkillExtension({
|
|
6195
|
+
skillId: skill,
|
|
6196
|
+
...options.scope !== void 0 ? { scope: options.scope } : {}
|
|
6197
|
+
});
|
|
6198
|
+
printSkillExtensionWrite(result);
|
|
6199
|
+
if (!openPathInEditor(result.path)) {
|
|
6200
|
+
console.log(
|
|
6201
|
+
` ${ICON.warn} ${pc3.yellow("editor not opened")} ${pc3.dim(`Set EDITOR or edit ${result.path}`)}`
|
|
6202
|
+
);
|
|
6203
|
+
}
|
|
6204
|
+
console.log(
|
|
6205
|
+
` ${ICON.skip} ${pc3.dim(`Run ${getCmd()} skills sync to apply it to configured tools.`)}`
|
|
6206
|
+
);
|
|
6207
|
+
});
|
|
6208
|
+
skillExtensions.command("enable").description("Enable a local OrgX skill extension.").argument("<skill>", "Skill id, for example orgx, cursor-rules, or morning-briefing").option("--scope <scope>", "Extension scope: user, workspace, or project.", "user").action((skill, options) => {
|
|
6209
|
+
const result = setSkillExtensionEnabled({
|
|
6210
|
+
enabled: true,
|
|
6211
|
+
skillId: skill,
|
|
6212
|
+
...options.scope !== void 0 ? { scope: options.scope } : {}
|
|
6213
|
+
});
|
|
6214
|
+
printSkillExtensionWrite(result);
|
|
6215
|
+
console.log(
|
|
6216
|
+
` ${ICON.skip} ${pc3.dim(`Run ${getCmd()} skills sync to apply it to configured tools.`)}`
|
|
6217
|
+
);
|
|
6218
|
+
});
|
|
6219
|
+
skillExtensions.command("disable").description("Disable a local OrgX skill extension without deleting it.").argument("<skill>", "Skill id, for example orgx, cursor-rules, or morning-briefing").option("--scope <scope>", "Extension scope: user, workspace, or project.", "user").action((skill, options) => {
|
|
6220
|
+
const result = setSkillExtensionEnabled({
|
|
6221
|
+
enabled: false,
|
|
6222
|
+
skillId: skill,
|
|
6223
|
+
...options.scope !== void 0 ? { scope: options.scope } : {}
|
|
6224
|
+
});
|
|
6225
|
+
printSkillExtensionWrite(result);
|
|
6226
|
+
console.log(
|
|
6227
|
+
` ${ICON.skip} ${pc3.dim(`Run ${getCmd()} skills sync to apply it to configured tools.`)}`
|
|
6228
|
+
);
|
|
6229
|
+
});
|
|
5717
6230
|
await program.parseAsync(process.argv);
|
|
5718
6231
|
}
|
|
5719
6232
|
main().catch((error) => {
|