@useorgx/wizard 0.1.9 → 0.1.11
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 +31 -8
- package/dist/cli.js +705 -61
- 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) {
|
|
@@ -978,6 +980,39 @@ function parseAgentRoster(value) {
|
|
|
978
980
|
...isNonEmptyString2(record.workspaceName) ? { workspaceName: record.workspaceName.trim() } : {}
|
|
979
981
|
};
|
|
980
982
|
}
|
|
983
|
+
function parseSkillFileRecord(value) {
|
|
984
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
985
|
+
return void 0;
|
|
986
|
+
}
|
|
987
|
+
const record = value;
|
|
988
|
+
if (!isNonEmptyString2(record.path) || !isNonEmptyString2(record.skillId) || !isNonEmptyString2(record.contentSha256) || !isNonEmptyString2(record.updatedAt)) {
|
|
989
|
+
return void 0;
|
|
990
|
+
}
|
|
991
|
+
return {
|
|
992
|
+
contentSha256: record.contentSha256.trim(),
|
|
993
|
+
path: record.path.trim(),
|
|
994
|
+
skillId: record.skillId.trim(),
|
|
995
|
+
updatedAt: record.updatedAt.trim(),
|
|
996
|
+
...isNonEmptyString2(record.coreSha256) ? { coreSha256: record.coreSha256.trim() } : {}
|
|
997
|
+
};
|
|
998
|
+
}
|
|
999
|
+
function parseSkillFiles(value) {
|
|
1000
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1001
|
+
return void 0;
|
|
1002
|
+
}
|
|
1003
|
+
const record = value;
|
|
1004
|
+
if (!isNonEmptyString2(record.updatedAt) || !Array.isArray(record.files)) {
|
|
1005
|
+
return void 0;
|
|
1006
|
+
}
|
|
1007
|
+
const files = record.files.map((entry) => parseSkillFileRecord(entry)).filter((entry) => Boolean(entry));
|
|
1008
|
+
if (files.length === 0) {
|
|
1009
|
+
return void 0;
|
|
1010
|
+
}
|
|
1011
|
+
return {
|
|
1012
|
+
files,
|
|
1013
|
+
updatedAt: record.updatedAt.trim()
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
981
1016
|
function createWizardState(now = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
982
1017
|
return {
|
|
983
1018
|
installationId: `wizard-${randomUUID()}`,
|
|
@@ -990,6 +1025,7 @@ function sanitizeWizardStateRecord(record) {
|
|
|
990
1025
|
const agentRoster = parseAgentRoster(record.agentRoster);
|
|
991
1026
|
const demoInitiative = parseDemoInitiative(record.demoInitiative);
|
|
992
1027
|
const onboardingTask = parseOnboardingTask(record.onboardingTask);
|
|
1028
|
+
const skillFiles = parseSkillFiles(record.skillFiles);
|
|
993
1029
|
return {
|
|
994
1030
|
installationId: record.installationId.trim(),
|
|
995
1031
|
createdAt: record.createdAt.trim(),
|
|
@@ -997,7 +1033,8 @@ function sanitizeWizardStateRecord(record) {
|
|
|
997
1033
|
...continuity ? { continuity } : {},
|
|
998
1034
|
...agentRoster ? { agentRoster } : {},
|
|
999
1035
|
...demoInitiative ? { demoInitiative } : {},
|
|
1000
|
-
...onboardingTask ? { onboardingTask } : {}
|
|
1036
|
+
...onboardingTask ? { onboardingTask } : {},
|
|
1037
|
+
...skillFiles ? { skillFiles } : {}
|
|
1001
1038
|
};
|
|
1002
1039
|
}
|
|
1003
1040
|
function readWizardState(statePath = ORGX_WIZARD_STATE_PATH) {
|
|
@@ -1018,6 +1055,8 @@ function readWizardState(statePath = ORGX_WIZARD_STATE_PATH) {
|
|
|
1018
1055
|
if (demoInitiative !== void 0) state.demoInitiative = demoInitiative;
|
|
1019
1056
|
const onboardingTask = parseOnboardingTask(parsed.onboardingTask);
|
|
1020
1057
|
if (onboardingTask !== void 0) state.onboardingTask = onboardingTask;
|
|
1058
|
+
const skillFiles = parseSkillFiles(parsed.skillFiles);
|
|
1059
|
+
if (skillFiles !== void 0) state.skillFiles = skillFiles;
|
|
1021
1060
|
return state;
|
|
1022
1061
|
}
|
|
1023
1062
|
function writeWizardState(value, statePath = ORGX_WIZARD_STATE_PATH) {
|
|
@@ -1046,6 +1085,9 @@ function getOrCreateWizardInstallationId(statePath = ORGX_WIZARD_STATE_PATH) {
|
|
|
1046
1085
|
writeWizardState(record, statePath);
|
|
1047
1086
|
return record.installationId;
|
|
1048
1087
|
}
|
|
1088
|
+
function clearWizardState(statePath = ORGX_WIZARD_STATE_PATH) {
|
|
1089
|
+
return deleteFileIfExists(statePath);
|
|
1090
|
+
}
|
|
1049
1091
|
|
|
1050
1092
|
// src/lib/agent-roster.ts
|
|
1051
1093
|
var AGENT_ROSTER_PROFILES = [
|
|
@@ -3002,7 +3044,9 @@ async function ensureOnboardingTask(workspace, options = {}) {
|
|
|
3002
3044
|
}
|
|
3003
3045
|
|
|
3004
3046
|
// src/lib/skills.ts
|
|
3005
|
-
import {
|
|
3047
|
+
import { createHash } from "crypto";
|
|
3048
|
+
import { existsSync as existsSync3, readdirSync } from "fs";
|
|
3049
|
+
import { basename, join as join2 } from "path";
|
|
3006
3050
|
var DEFAULT_ORGX_SKILL_PACKS = [
|
|
3007
3051
|
"morning-briefing",
|
|
3008
3052
|
"initiative-kickoff",
|
|
@@ -3014,6 +3058,9 @@ var EXCLUDED_PACK_DIRS = /* @__PURE__ */ new Set([".github", "scripts"]);
|
|
|
3014
3058
|
var ORGX_SKILLS_OWNER = "useorgx";
|
|
3015
3059
|
var ORGX_SKILLS_REPO = "skills";
|
|
3016
3060
|
var ORGX_SKILLS_REF = "main";
|
|
3061
|
+
var SKILL_EXTENSION_SCOPES = ["user", "workspace", "project"];
|
|
3062
|
+
var COMPOSED_SKILL_MARKER = "ORGX SKILL COMPOSED v1";
|
|
3063
|
+
var EXTENSION_FRONTMATTER_DELIMITER = "---";
|
|
3017
3064
|
var CURSOR_RULES_CONTENT = `# OrgX Rules
|
|
3018
3065
|
|
|
3019
3066
|
- 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.
|
|
@@ -3069,6 +3116,219 @@ Install and use these packs alongside this base skill:
|
|
|
3069
3116
|
4. When you scaffold, decide up front whether \`continue_on_error\` is acceptable.
|
|
3070
3117
|
5. Carry \`_context\` through any widget-producing flows so the UI can render and resume correctly.
|
|
3071
3118
|
`;
|
|
3119
|
+
function sha256(value) {
|
|
3120
|
+
return createHash("sha256").update(value).digest("hex");
|
|
3121
|
+
}
|
|
3122
|
+
function normalizeSkillId(value) {
|
|
3123
|
+
const normalized = value.trim().toLowerCase();
|
|
3124
|
+
if (!/^[a-z0-9][a-z0-9._-]*$/.test(normalized)) {
|
|
3125
|
+
throw new Error(
|
|
3126
|
+
"Skill id must start with a letter or number and only contain letters, numbers, '.', '_' or '-'."
|
|
3127
|
+
);
|
|
3128
|
+
}
|
|
3129
|
+
return normalized;
|
|
3130
|
+
}
|
|
3131
|
+
function normalizeSkillExtensionScope(value) {
|
|
3132
|
+
const normalized = (value ?? "user").trim().toLowerCase();
|
|
3133
|
+
if (!SKILL_EXTENSION_SCOPES.includes(normalized)) {
|
|
3134
|
+
throw new Error("Skill extension scope must be one of: user, workspace, project.");
|
|
3135
|
+
}
|
|
3136
|
+
return normalized;
|
|
3137
|
+
}
|
|
3138
|
+
function defaultExtensionTitle(skillId, scope) {
|
|
3139
|
+
const prefix = scope === "user" ? "Personal" : scope === "workspace" ? "Workspace" : "Project";
|
|
3140
|
+
return `${prefix} ${skillId} behavior`;
|
|
3141
|
+
}
|
|
3142
|
+
function extensionFilePath(skillId, scope, extensionsDir = ORGX_SKILL_EXTENSIONS_DIR) {
|
|
3143
|
+
return join2(extensionsDir, `${scope}.${skillId}.md`);
|
|
3144
|
+
}
|
|
3145
|
+
function extensionTemplate(input) {
|
|
3146
|
+
const body = input.content?.trim() ? input.content.trim() : [
|
|
3147
|
+
`# ${input.title}`,
|
|
3148
|
+
"",
|
|
3149
|
+
"- Add your custom behavior here.",
|
|
3150
|
+
"- These instructions are appended after the OrgX-managed core skill when the wizard syncs skills."
|
|
3151
|
+
].join("\n");
|
|
3152
|
+
return [
|
|
3153
|
+
EXTENSION_FRONTMATTER_DELIMITER,
|
|
3154
|
+
`skill: ${input.skillId}`,
|
|
3155
|
+
`scope: ${input.scope}`,
|
|
3156
|
+
"enabled: true",
|
|
3157
|
+
`title: ${input.title}`,
|
|
3158
|
+
EXTENSION_FRONTMATTER_DELIMITER,
|
|
3159
|
+
"",
|
|
3160
|
+
body,
|
|
3161
|
+
""
|
|
3162
|
+
].join("\n");
|
|
3163
|
+
}
|
|
3164
|
+
function parseFrontmatter(content) {
|
|
3165
|
+
if (!content.startsWith(`${EXTENSION_FRONTMATTER_DELIMITER}
|
|
3166
|
+
`)) {
|
|
3167
|
+
return { body: content, data: {} };
|
|
3168
|
+
}
|
|
3169
|
+
const closeIndex = content.indexOf(`
|
|
3170
|
+
${EXTENSION_FRONTMATTER_DELIMITER}
|
|
3171
|
+
`, 4);
|
|
3172
|
+
if (closeIndex === -1) {
|
|
3173
|
+
return { body: content, data: {} };
|
|
3174
|
+
}
|
|
3175
|
+
const raw = content.slice(4, closeIndex);
|
|
3176
|
+
const body = content.slice(closeIndex + 5);
|
|
3177
|
+
const data = {};
|
|
3178
|
+
for (const line of raw.split("\n")) {
|
|
3179
|
+
const index = line.indexOf(":");
|
|
3180
|
+
if (index === -1) {
|
|
3181
|
+
continue;
|
|
3182
|
+
}
|
|
3183
|
+
const key = line.slice(0, index).trim();
|
|
3184
|
+
const value = line.slice(index + 1).trim();
|
|
3185
|
+
if (key) {
|
|
3186
|
+
data[key] = value;
|
|
3187
|
+
}
|
|
3188
|
+
}
|
|
3189
|
+
return { body, data };
|
|
3190
|
+
}
|
|
3191
|
+
function serializeFrontmatter(data, body) {
|
|
3192
|
+
return [
|
|
3193
|
+
EXTENSION_FRONTMATTER_DELIMITER,
|
|
3194
|
+
...Object.entries(data).map(([key, value]) => `${key}: ${value}`),
|
|
3195
|
+
EXTENSION_FRONTMATTER_DELIMITER,
|
|
3196
|
+
"",
|
|
3197
|
+
body.trimEnd(),
|
|
3198
|
+
""
|
|
3199
|
+
].join("\n");
|
|
3200
|
+
}
|
|
3201
|
+
function parseSkillExtension(path, content) {
|
|
3202
|
+
const fallbackId = basename(path, ".md");
|
|
3203
|
+
const fallbackParts = fallbackId.split(".");
|
|
3204
|
+
const fallbackScope = normalizeSkillExtensionScope(
|
|
3205
|
+
SKILL_EXTENSION_SCOPES.includes(fallbackParts[0]) ? fallbackParts.shift() : "user"
|
|
3206
|
+
);
|
|
3207
|
+
const fallbackSkillId = normalizeSkillId(fallbackParts.join(".") || fallbackId);
|
|
3208
|
+
const parsed = parseFrontmatter(content);
|
|
3209
|
+
const skillId = normalizeSkillId(parsed.data.skill || fallbackSkillId);
|
|
3210
|
+
const scope = normalizeSkillExtensionScope(parsed.data.scope || fallbackScope);
|
|
3211
|
+
const title = parsed.data.title?.trim() || defaultExtensionTitle(skillId, scope);
|
|
3212
|
+
return {
|
|
3213
|
+
content: parsed.body.trim(),
|
|
3214
|
+
enabled: parsed.data.enabled?.trim().toLowerCase() !== "false",
|
|
3215
|
+
id: `${scope}.${skillId}`,
|
|
3216
|
+
path,
|
|
3217
|
+
scope,
|
|
3218
|
+
skillId,
|
|
3219
|
+
title
|
|
3220
|
+
};
|
|
3221
|
+
}
|
|
3222
|
+
function listSkillExtensions(options = {}) {
|
|
3223
|
+
const extensionsDir = options.extensionsDir ?? ORGX_SKILL_EXTENSIONS_DIR;
|
|
3224
|
+
if (!existsSync3(extensionsDir)) {
|
|
3225
|
+
return [];
|
|
3226
|
+
}
|
|
3227
|
+
return readdirSync(extensionsDir, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".md")).map((entry) => {
|
|
3228
|
+
const path = join2(extensionsDir, entry.name);
|
|
3229
|
+
const content = readTextIfExists(path);
|
|
3230
|
+
return content === null ? null : parseSkillExtension(path, content);
|
|
3231
|
+
}).filter((entry) => Boolean(entry)).sort((left, right) => left.id.localeCompare(right.id));
|
|
3232
|
+
}
|
|
3233
|
+
function addSkillExtension(options) {
|
|
3234
|
+
const skillId = normalizeSkillId(options.skillId);
|
|
3235
|
+
const scope = normalizeSkillExtensionScope(options.scope);
|
|
3236
|
+
const path = extensionFilePath(skillId, scope, options.extensionsDir);
|
|
3237
|
+
const title = options.title?.trim() || defaultExtensionTitle(skillId, scope);
|
|
3238
|
+
const existing = readTextIfExists(path);
|
|
3239
|
+
if (existing !== null && options.overwrite !== true) {
|
|
3240
|
+
const extension2 = parseSkillExtension(path, existing);
|
|
3241
|
+
if (!extension2) {
|
|
3242
|
+
throw new Error(`Could not parse existing skill extension at ${path}.`);
|
|
3243
|
+
}
|
|
3244
|
+
return {
|
|
3245
|
+
changed: false,
|
|
3246
|
+
created: false,
|
|
3247
|
+
extension: extension2,
|
|
3248
|
+
path
|
|
3249
|
+
};
|
|
3250
|
+
}
|
|
3251
|
+
const nextContent = extensionTemplate({
|
|
3252
|
+
scope,
|
|
3253
|
+
skillId,
|
|
3254
|
+
title,
|
|
3255
|
+
...options.content !== void 0 ? { content: options.content } : {}
|
|
3256
|
+
});
|
|
3257
|
+
writeTextFile(path, nextContent);
|
|
3258
|
+
const extension = parseSkillExtension(path, nextContent);
|
|
3259
|
+
if (!extension) {
|
|
3260
|
+
throw new Error(`Could not parse newly written skill extension at ${path}.`);
|
|
3261
|
+
}
|
|
3262
|
+
return {
|
|
3263
|
+
changed: existing !== nextContent,
|
|
3264
|
+
created: existing === null,
|
|
3265
|
+
extension,
|
|
3266
|
+
path
|
|
3267
|
+
};
|
|
3268
|
+
}
|
|
3269
|
+
function setSkillExtensionEnabled(input) {
|
|
3270
|
+
const skillId = normalizeSkillId(input.skillId);
|
|
3271
|
+
const scope = normalizeSkillExtensionScope(input.scope);
|
|
3272
|
+
const path = extensionFilePath(skillId, scope, input.extensionsDir);
|
|
3273
|
+
const existing = readTextIfExists(path);
|
|
3274
|
+
if (existing === null) {
|
|
3275
|
+
if (!input.enabled) {
|
|
3276
|
+
throw new Error(`No ${scope} extension exists for ${skillId}.`);
|
|
3277
|
+
}
|
|
3278
|
+
return addSkillExtension({
|
|
3279
|
+
scope,
|
|
3280
|
+
skillId,
|
|
3281
|
+
...input.extensionsDir !== void 0 ? { extensionsDir: input.extensionsDir } : {}
|
|
3282
|
+
});
|
|
3283
|
+
}
|
|
3284
|
+
const parsed = parseFrontmatter(existing);
|
|
3285
|
+
const data = {
|
|
3286
|
+
skill: parsed.data.skill || skillId,
|
|
3287
|
+
scope: parsed.data.scope || scope,
|
|
3288
|
+
enabled: input.enabled ? "true" : "false",
|
|
3289
|
+
title: parsed.data.title || defaultExtensionTitle(skillId, scope)
|
|
3290
|
+
};
|
|
3291
|
+
const nextContent = serializeFrontmatter(data, parsed.body);
|
|
3292
|
+
if (nextContent !== existing) {
|
|
3293
|
+
writeTextFile(path, nextContent);
|
|
3294
|
+
}
|
|
3295
|
+
const extension = parseSkillExtension(path, nextContent);
|
|
3296
|
+
if (!extension) {
|
|
3297
|
+
throw new Error(`Could not parse skill extension at ${path}.`);
|
|
3298
|
+
}
|
|
3299
|
+
return {
|
|
3300
|
+
changed: nextContent !== existing,
|
|
3301
|
+
created: false,
|
|
3302
|
+
extension,
|
|
3303
|
+
path
|
|
3304
|
+
};
|
|
3305
|
+
}
|
|
3306
|
+
function composeSkillContent(skillId, coreContent, extensions) {
|
|
3307
|
+
const enabled = extensions.filter((extension) => extension.enabled && extension.skillId === skillId);
|
|
3308
|
+
if (enabled.length === 0) {
|
|
3309
|
+
return coreContent;
|
|
3310
|
+
}
|
|
3311
|
+
const extensionBlocks = enabled.map((extension) => [
|
|
3312
|
+
`<!-- extension: ${extension.id} -->`,
|
|
3313
|
+
extension.content.trim()
|
|
3314
|
+
].join("\n"));
|
|
3315
|
+
return [
|
|
3316
|
+
`<!-- ${COMPOSED_SKILL_MARKER}`,
|
|
3317
|
+
`skill: ${skillId}`,
|
|
3318
|
+
`core-sha256: ${sha256(coreContent)}`,
|
|
3319
|
+
"generated: true",
|
|
3320
|
+
`edit-with: orgx-wizard skills extensions edit ${skillId}`,
|
|
3321
|
+
"-->",
|
|
3322
|
+
`<!-- ORGX CORE BEGIN ${skillId} -->`,
|
|
3323
|
+
coreContent.trimEnd(),
|
|
3324
|
+
`<!-- ORGX CORE END ${skillId} -->`,
|
|
3325
|
+
"",
|
|
3326
|
+
"<!-- ORGX USER EXTENSIONS BEGIN -->",
|
|
3327
|
+
...extensionBlocks,
|
|
3328
|
+
"<!-- ORGX USER EXTENSIONS END -->",
|
|
3329
|
+
""
|
|
3330
|
+
].join("\n");
|
|
3331
|
+
}
|
|
3072
3332
|
function encodeRepoPath(value) {
|
|
3073
3333
|
return value.split("/").filter((segment) => segment.length > 0).map((segment) => encodeURIComponent(segment)).join("/");
|
|
3074
3334
|
}
|
|
@@ -3134,12 +3394,35 @@ async function fetchRemoteText(sourceUrl, fetchImpl) {
|
|
|
3134
3394
|
}
|
|
3135
3395
|
return readResponseText(response);
|
|
3136
3396
|
}
|
|
3137
|
-
function
|
|
3397
|
+
function getTrackedSkillFile(records, path) {
|
|
3398
|
+
return records.find((record) => record.path === path);
|
|
3399
|
+
}
|
|
3400
|
+
function writeManagedFile(path, content, label, sourceUrl, tracking) {
|
|
3138
3401
|
const existing = readTextIfExists(path);
|
|
3402
|
+
const tracked = tracking ? getTrackedSkillFile(tracking.records, path) : void 0;
|
|
3403
|
+
if (tracking && existing !== null && tracked && sha256(existing) !== tracked.contentSha256 && tracking.force !== true) {
|
|
3404
|
+
return {
|
|
3405
|
+
label,
|
|
3406
|
+
path,
|
|
3407
|
+
changed: false,
|
|
3408
|
+
skipped: true,
|
|
3409
|
+
reason: "manual edits detected; move them into a skill extension or rerun with --force",
|
|
3410
|
+
...sourceUrl ? { sourceUrl } : {}
|
|
3411
|
+
};
|
|
3412
|
+
}
|
|
3139
3413
|
const changed = existing !== content;
|
|
3140
3414
|
if (changed) {
|
|
3141
3415
|
writeTextFile(path, content);
|
|
3142
3416
|
}
|
|
3417
|
+
if (tracking) {
|
|
3418
|
+
tracking.stagedRecords.set(path, {
|
|
3419
|
+
contentSha256: sha256(content),
|
|
3420
|
+
...tracking.coreContent ? { coreSha256: sha256(tracking.coreContent) } : {},
|
|
3421
|
+
path,
|
|
3422
|
+
skillId: tracking.skillId,
|
|
3423
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3424
|
+
});
|
|
3425
|
+
}
|
|
3143
3426
|
return {
|
|
3144
3427
|
label,
|
|
3145
3428
|
path,
|
|
@@ -3204,19 +3487,27 @@ async function fetchAvailablePackNames(fetchImpl, ref) {
|
|
|
3204
3487
|
const entries = await fetchDirectoryEntries("", fetchImpl, ref);
|
|
3205
3488
|
return entries.filter((e) => e.type === "dir" && !EXCLUDED_PACK_DIRS.has(e.name)).map((e) => e.name);
|
|
3206
3489
|
}
|
|
3207
|
-
async function installSkillPack(skillName, claudeSkillsDir, fetchImpl, ref) {
|
|
3490
|
+
async function installSkillPack(skillName, claudeSkillsDir, fetchImpl, ref, tracking) {
|
|
3208
3491
|
const rootPath = skillName;
|
|
3209
3492
|
const files = await listRemoteSkillFiles(rootPath, fetchImpl, ref);
|
|
3210
3493
|
const writes = [];
|
|
3211
3494
|
for (const file of files) {
|
|
3212
|
-
const
|
|
3495
|
+
const coreContent = await fetchRemoteText(file.sourceUrl, fetchImpl);
|
|
3213
3496
|
const relativePath = file.path.slice(`${rootPath}/`.length);
|
|
3497
|
+
const content = relativePath === "SKILL.md" ? composeSkillContent(skillName, coreContent, tracking.extensions) : coreContent;
|
|
3214
3498
|
writes.push(
|
|
3215
3499
|
writeManagedFile(
|
|
3216
3500
|
join2(claudeSkillsDir, skillName, relativePath),
|
|
3217
3501
|
content,
|
|
3218
3502
|
`${skillName}/${relativePath}`,
|
|
3219
|
-
file.sourceUrl
|
|
3503
|
+
file.sourceUrl,
|
|
3504
|
+
{
|
|
3505
|
+
coreContent,
|
|
3506
|
+
records: tracking.records,
|
|
3507
|
+
skillId: skillName,
|
|
3508
|
+
stagedRecords: tracking.stagedRecords,
|
|
3509
|
+
...tracking.force !== void 0 ? { force: tracking.force } : {}
|
|
3510
|
+
}
|
|
3220
3511
|
)
|
|
3221
3512
|
);
|
|
3222
3513
|
}
|
|
@@ -3234,6 +3525,13 @@ async function installOrgxSkills(options = {}) {
|
|
|
3234
3525
|
const claudeSkillsDir = options.claudeSkillsDir ?? CLAUDE_SKILLS_DIR;
|
|
3235
3526
|
const claudeOrgxSkillPath = options.claudeOrgxSkillPath ?? CLAUDE_ORGX_SKILL_PATH;
|
|
3236
3527
|
const cursorRulePath = options.cursorRulePath ?? CURSOR_ORGX_RULE_PATH;
|
|
3528
|
+
const statePath = options.statePath ?? ORGX_WIZARD_STATE_PATH;
|
|
3529
|
+
const extensions = listSkillExtensions(
|
|
3530
|
+
options.skillExtensionsDir !== void 0 ? { extensionsDir: options.skillExtensionsDir } : {}
|
|
3531
|
+
);
|
|
3532
|
+
const enabledExtensions = extensions.filter((extension) => extension.enabled);
|
|
3533
|
+
const trackedRecords = readWizardState(statePath)?.skillFiles?.files ?? [];
|
|
3534
|
+
const stagedRecords = /* @__PURE__ */ new Map();
|
|
3237
3535
|
const plan = planOrgxSkillsInstall(options.pluginTargets ?? []);
|
|
3238
3536
|
const requestedNames = options.skillNames ?? [];
|
|
3239
3537
|
let skillNames;
|
|
@@ -3247,41 +3545,108 @@ async function installOrgxSkills(options = {}) {
|
|
|
3247
3545
|
skillNames = resolveSkillPackNames(requestedNames);
|
|
3248
3546
|
}
|
|
3249
3547
|
const writes = [
|
|
3250
|
-
writeManagedFile(
|
|
3548
|
+
writeManagedFile(
|
|
3549
|
+
cursorRulePath,
|
|
3550
|
+
composeSkillContent("cursor-rules", CURSOR_RULES_CONTENT, extensions),
|
|
3551
|
+
"cursor-rules",
|
|
3552
|
+
void 0,
|
|
3553
|
+
{
|
|
3554
|
+
coreContent: CURSOR_RULES_CONTENT,
|
|
3555
|
+
records: trackedRecords,
|
|
3556
|
+
skillId: "cursor-rules",
|
|
3557
|
+
stagedRecords,
|
|
3558
|
+
...options.force !== void 0 ? { force: options.force } : {}
|
|
3559
|
+
}
|
|
3560
|
+
)
|
|
3251
3561
|
];
|
|
3252
3562
|
if (plan.installClaudeSkillBootstrap) {
|
|
3253
3563
|
writes.push(
|
|
3254
|
-
writeManagedFile(
|
|
3564
|
+
writeManagedFile(
|
|
3565
|
+
claudeOrgxSkillPath,
|
|
3566
|
+
composeSkillContent("orgx", CLAUDE_ORGX_SKILL_CONTENT, extensions),
|
|
3567
|
+
"claude-orgx-skill",
|
|
3568
|
+
void 0,
|
|
3569
|
+
{
|
|
3570
|
+
coreContent: CLAUDE_ORGX_SKILL_CONTENT,
|
|
3571
|
+
records: trackedRecords,
|
|
3572
|
+
skillId: "orgx",
|
|
3573
|
+
stagedRecords,
|
|
3574
|
+
...options.force !== void 0 ? { force: options.force } : {}
|
|
3575
|
+
}
|
|
3576
|
+
)
|
|
3255
3577
|
);
|
|
3256
3578
|
}
|
|
3257
3579
|
const packs = [];
|
|
3258
3580
|
if (plan.installClaudeSkillPacks) {
|
|
3259
3581
|
for (const skillName of skillNames) {
|
|
3260
|
-
packs.push(await installSkillPack(skillName, claudeSkillsDir, fetchImpl, ref
|
|
3582
|
+
packs.push(await installSkillPack(skillName, claudeSkillsDir, fetchImpl, ref, {
|
|
3583
|
+
extensions,
|
|
3584
|
+
records: trackedRecords,
|
|
3585
|
+
stagedRecords,
|
|
3586
|
+
...options.force !== void 0 ? { force: options.force } : {}
|
|
3587
|
+
}));
|
|
3261
3588
|
}
|
|
3262
3589
|
}
|
|
3590
|
+
if (stagedRecords.size > 0) {
|
|
3591
|
+
updateWizardState((current) => {
|
|
3592
|
+
const previousFiles = current.skillFiles?.files ?? [];
|
|
3593
|
+
const nextFiles = /* @__PURE__ */ new Map();
|
|
3594
|
+
for (const record of previousFiles) {
|
|
3595
|
+
nextFiles.set(record.path, record);
|
|
3596
|
+
}
|
|
3597
|
+
for (const record of stagedRecords.values()) {
|
|
3598
|
+
nextFiles.set(record.path, record);
|
|
3599
|
+
}
|
|
3600
|
+
return {
|
|
3601
|
+
...current,
|
|
3602
|
+
skillFiles: {
|
|
3603
|
+
files: [...nextFiles.values()].sort((left, right) => left.path.localeCompare(right.path)),
|
|
3604
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
3605
|
+
}
|
|
3606
|
+
};
|
|
3607
|
+
}, statePath);
|
|
3608
|
+
}
|
|
3609
|
+
const notes = [...plan.notes];
|
|
3610
|
+
if (enabledExtensions.length > 0) {
|
|
3611
|
+
notes.push(
|
|
3612
|
+
`Applied ${enabledExtensions.length} enabled OrgX skill extension${enabledExtensions.length === 1 ? "" : "s"} while syncing skills/rules.`
|
|
3613
|
+
);
|
|
3614
|
+
}
|
|
3615
|
+
if (writes.some((write) => write.skipped) || packs.some((pack) => pack.files.some((file) => file.skipped))) {
|
|
3616
|
+
notes.push("Some generated skill files were skipped because local manual edits were detected.");
|
|
3617
|
+
}
|
|
3263
3618
|
return {
|
|
3264
|
-
|
|
3619
|
+
extensions,
|
|
3620
|
+
notes,
|
|
3265
3621
|
writes,
|
|
3266
3622
|
packs
|
|
3267
3623
|
};
|
|
3268
3624
|
}
|
|
3625
|
+
function getSkillStatus(options = {}) {
|
|
3626
|
+
const state = readWizardState(options.statePath ?? ORGX_WIZARD_STATE_PATH);
|
|
3627
|
+
return {
|
|
3628
|
+
extensions: listSkillExtensions(
|
|
3629
|
+
options.extensionsDir !== void 0 ? { extensionsDir: options.extensionsDir } : {}
|
|
3630
|
+
),
|
|
3631
|
+
trackedFiles: state?.skillFiles?.files ?? []
|
|
3632
|
+
};
|
|
3633
|
+
}
|
|
3269
3634
|
|
|
3270
3635
|
// src/lib/plugins.ts
|
|
3271
3636
|
import { spawn } from "child_process";
|
|
3272
3637
|
import {
|
|
3273
|
-
existsSync as
|
|
3638
|
+
existsSync as existsSync4,
|
|
3274
3639
|
mkdirSync as mkdirSync2,
|
|
3275
3640
|
mkdtempSync,
|
|
3276
3641
|
readFileSync as readFileSync2,
|
|
3277
|
-
readdirSync,
|
|
3642
|
+
readdirSync as readdirSync2,
|
|
3278
3643
|
rmSync,
|
|
3279
3644
|
statSync as statSync2,
|
|
3280
3645
|
writeFileSync as writeFileSync2
|
|
3281
3646
|
} from "fs";
|
|
3282
3647
|
import { tmpdir } from "os";
|
|
3283
3648
|
import { dirname as dirname3, join as join3, relative } from "path";
|
|
3284
|
-
var DEFAULT_ORGX_PLUGIN_TARGETS = ["claude", "codex", "openclaw"];
|
|
3649
|
+
var DEFAULT_ORGX_PLUGIN_TARGETS = ["cursor", "claude", "codex", "openclaw"];
|
|
3285
3650
|
var ORGX_PLUGIN_GITHUB_OWNER = "useorgx";
|
|
3286
3651
|
var ORGX_PLUGIN_GITHUB_REF = "main";
|
|
3287
3652
|
var ORGX_CLAUDE_PLUGIN_NAME = "orgx-claude-code-plugin";
|
|
@@ -3320,7 +3685,8 @@ function defaultPluginPaths() {
|
|
|
3320
3685
|
claudeMarketplaceManifestPath: CLAUDE_MANAGED_MARKETPLACE_MANIFEST_PATH,
|
|
3321
3686
|
claudePluginDir: CLAUDE_MANAGED_PLUGIN_DIR,
|
|
3322
3687
|
codexMarketplacePath: CODEX_MARKETPLACE_PATH,
|
|
3323
|
-
codexPluginDir: CODEX_ORGX_PLUGIN_DIR
|
|
3688
|
+
codexPluginDir: CODEX_ORGX_PLUGIN_DIR,
|
|
3689
|
+
cursorRulePath: CURSOR_ORGX_RULE_PATH
|
|
3324
3690
|
};
|
|
3325
3691
|
}
|
|
3326
3692
|
function resolvePluginPaths(paths = {}) {
|
|
@@ -3339,8 +3705,8 @@ function encodeRepoPath2(value) {
|
|
|
3339
3705
|
return value.split("/").filter((segment) => segment.length > 0).map((segment) => encodeURIComponent(segment)).join("/");
|
|
3340
3706
|
}
|
|
3341
3707
|
function isLikelyRepoFilePath(path) {
|
|
3342
|
-
const
|
|
3343
|
-
return
|
|
3708
|
+
const basename2 = path.split("/").pop() ?? path;
|
|
3709
|
+
return basename2.includes(".") && !/^\.[^./]+$/.test(basename2);
|
|
3344
3710
|
}
|
|
3345
3711
|
function buildContentsUrl2(spec, path) {
|
|
3346
3712
|
const encodedPath = encodeRepoPath2(path);
|
|
@@ -3450,7 +3816,7 @@ async function fetchRemoteBytes(sourceUrl, fetchImpl) {
|
|
|
3450
3816
|
return Buffer.from(await response.arrayBuffer());
|
|
3451
3817
|
}
|
|
3452
3818
|
function readBytesIfExists(path) {
|
|
3453
|
-
if (!
|
|
3819
|
+
if (!existsSync4(path)) return null;
|
|
3454
3820
|
try {
|
|
3455
3821
|
if (!statSync2(path).isFile()) {
|
|
3456
3822
|
return null;
|
|
@@ -3474,17 +3840,17 @@ function writeBytesIfChanged(path, bytes) {
|
|
|
3474
3840
|
return true;
|
|
3475
3841
|
}
|
|
3476
3842
|
function removePathIfExists(path) {
|
|
3477
|
-
if (!
|
|
3843
|
+
if (!existsSync4(path)) return false;
|
|
3478
3844
|
rmSync(path, { force: true, recursive: true });
|
|
3479
3845
|
return true;
|
|
3480
3846
|
}
|
|
3481
3847
|
function listRelativeFiles(root, base = root) {
|
|
3482
|
-
if (!
|
|
3848
|
+
if (!existsSync4(root)) return [];
|
|
3483
3849
|
if (!statSync2(root).isDirectory()) {
|
|
3484
3850
|
return [];
|
|
3485
3851
|
}
|
|
3486
3852
|
const files = [];
|
|
3487
|
-
for (const entry of
|
|
3853
|
+
for (const entry of readdirSync2(root, { withFileTypes: true })) {
|
|
3488
3854
|
const nextPath = join3(root, entry.name);
|
|
3489
3855
|
if (entry.isDirectory()) {
|
|
3490
3856
|
files.push(...listRelativeFiles(nextPath, base));
|
|
@@ -3497,15 +3863,15 @@ function listRelativeFiles(root, base = root) {
|
|
|
3497
3863
|
return files.sort();
|
|
3498
3864
|
}
|
|
3499
3865
|
function pruneEmptyDirectories(root, current = root) {
|
|
3500
|
-
if (!
|
|
3866
|
+
if (!existsSync4(current) || !statSync2(current).isDirectory()) {
|
|
3501
3867
|
return false;
|
|
3502
3868
|
}
|
|
3503
3869
|
let changed = false;
|
|
3504
|
-
for (const entry of
|
|
3870
|
+
for (const entry of readdirSync2(current, { withFileTypes: true })) {
|
|
3505
3871
|
if (!entry.isDirectory()) continue;
|
|
3506
3872
|
changed = pruneEmptyDirectories(root, join3(current, entry.name)) || changed;
|
|
3507
3873
|
}
|
|
3508
|
-
if (current !== root &&
|
|
3874
|
+
if (current !== root && readdirSync2(current).length === 0) {
|
|
3509
3875
|
rmSync(current, { force: true, recursive: true });
|
|
3510
3876
|
return true;
|
|
3511
3877
|
}
|
|
@@ -3515,7 +3881,7 @@ async function syncManagedRepoTree(spec, destinationRoot, fetchImpl) {
|
|
|
3515
3881
|
const remoteFiles = await collectRemoteRepoFiles(spec, fetchImpl);
|
|
3516
3882
|
let changed = false;
|
|
3517
3883
|
const expected = new Set(remoteFiles.map((file) => file.localPath));
|
|
3518
|
-
if (
|
|
3884
|
+
if (existsSync4(destinationRoot) && !statSync2(destinationRoot).isDirectory()) {
|
|
3519
3885
|
rmSync(destinationRoot, { force: true, recursive: true });
|
|
3520
3886
|
changed = true;
|
|
3521
3887
|
}
|
|
@@ -3606,7 +3972,7 @@ function upsertCodexMarketplaceEntry(path) {
|
|
|
3606
3972
|
return writeJsonIfChanged(path, nextDocument);
|
|
3607
3973
|
}
|
|
3608
3974
|
function removeCodexMarketplaceEntry(path) {
|
|
3609
|
-
if (!
|
|
3975
|
+
if (!existsSync4(path)) {
|
|
3610
3976
|
return false;
|
|
3611
3977
|
}
|
|
3612
3978
|
const { document, plugins } = readMarketplacePlugins(path);
|
|
@@ -3740,6 +4106,32 @@ async function getOpenclawInstallState(runner) {
|
|
|
3740
4106
|
installed: extractOpenclawPluginIds(result.stdout).includes(ORGX_OPENCLAW_PLUGIN_ID)
|
|
3741
4107
|
};
|
|
3742
4108
|
}
|
|
4109
|
+
function buildCursorStatus(paths) {
|
|
4110
|
+
const existingRules = readTextIfExists(paths.cursorRulePath);
|
|
4111
|
+
const available = detectSurface("cursor").detected || existingRules !== null;
|
|
4112
|
+
if (existingRules === CURSOR_RULES_CONTENT) {
|
|
4113
|
+
return {
|
|
4114
|
+
target: "cursor",
|
|
4115
|
+
available: true,
|
|
4116
|
+
installed: true,
|
|
4117
|
+
message: "Cursor OrgX rules are installed."
|
|
4118
|
+
};
|
|
4119
|
+
}
|
|
4120
|
+
if (existingRules !== null) {
|
|
4121
|
+
return {
|
|
4122
|
+
target: "cursor",
|
|
4123
|
+
available: true,
|
|
4124
|
+
installed: false,
|
|
4125
|
+
message: "Cursor OrgX rules file exists, but differs from the managed rules."
|
|
4126
|
+
};
|
|
4127
|
+
}
|
|
4128
|
+
return {
|
|
4129
|
+
target: "cursor",
|
|
4130
|
+
available,
|
|
4131
|
+
installed: false,
|
|
4132
|
+
message: available ? "Cursor is available and ready for OrgX rules install." : "Cursor was not detected."
|
|
4133
|
+
};
|
|
4134
|
+
}
|
|
3743
4135
|
async function buildClaudeStatus(paths, runner) {
|
|
3744
4136
|
const state = await getClaudeInstallState(runner);
|
|
3745
4137
|
if (state.installed) {
|
|
@@ -3758,7 +4150,7 @@ async function buildClaudeStatus(paths, runner) {
|
|
|
3758
4150
|
message: "Claude Code was not detected."
|
|
3759
4151
|
};
|
|
3760
4152
|
}
|
|
3761
|
-
const marketplaceExists =
|
|
4153
|
+
const marketplaceExists = existsSync4(paths.claudeMarketplaceManifestPath);
|
|
3762
4154
|
return {
|
|
3763
4155
|
target: "claude",
|
|
3764
4156
|
available: true,
|
|
@@ -3769,7 +4161,7 @@ async function buildClaudeStatus(paths, runner) {
|
|
|
3769
4161
|
function buildCodexStatus(paths, runner) {
|
|
3770
4162
|
return (async () => {
|
|
3771
4163
|
const available = detectSurface("codex").detected || await commandExists("codex", runner);
|
|
3772
|
-
const pluginExists =
|
|
4164
|
+
const pluginExists = existsSync4(paths.codexPluginDir);
|
|
3773
4165
|
const marketplaceExists = codexMarketplaceHasOrgxEntry(paths.codexMarketplacePath);
|
|
3774
4166
|
const installed = pluginExists && marketplaceExists;
|
|
3775
4167
|
if (installed) {
|
|
@@ -3855,6 +4247,30 @@ async function resolveOpenclawTarball(fetchImpl) {
|
|
|
3855
4247
|
version: latestVersion
|
|
3856
4248
|
};
|
|
3857
4249
|
}
|
|
4250
|
+
function installCursorPlugin(paths) {
|
|
4251
|
+
const existingRules = readTextIfExists(paths.cursorRulePath);
|
|
4252
|
+
const available = detectSurface("cursor").detected || existingRules !== null;
|
|
4253
|
+
if (!available) {
|
|
4254
|
+
return {
|
|
4255
|
+
target: "cursor",
|
|
4256
|
+
changed: false,
|
|
4257
|
+
message: "Cursor is not available on this machine."
|
|
4258
|
+
};
|
|
4259
|
+
}
|
|
4260
|
+
if (existingRules === CURSOR_RULES_CONTENT) {
|
|
4261
|
+
return {
|
|
4262
|
+
target: "cursor",
|
|
4263
|
+
changed: false,
|
|
4264
|
+
message: "Cursor OrgX rules are already installed."
|
|
4265
|
+
};
|
|
4266
|
+
}
|
|
4267
|
+
writeTextFile(paths.cursorRulePath, CURSOR_RULES_CONTENT);
|
|
4268
|
+
return {
|
|
4269
|
+
target: "cursor",
|
|
4270
|
+
changed: true,
|
|
4271
|
+
message: "Installed the managed Cursor OrgX rules."
|
|
4272
|
+
};
|
|
4273
|
+
}
|
|
3858
4274
|
async function installClaudePlugin(paths, fetchImpl, runner) {
|
|
3859
4275
|
const state = await getClaudeInstallState(runner);
|
|
3860
4276
|
if (!state.available) {
|
|
@@ -3961,6 +4377,29 @@ async function installOpenclawPlugin(fetchImpl, runner) {
|
|
|
3961
4377
|
message: `Installed OpenClaw plugin ${ORGX_OPENCLAW_PLUGIN_ID} from ${ORGX_OPENCLAW_PLUGIN_PACKAGE_NAME}@${version}.`
|
|
3962
4378
|
};
|
|
3963
4379
|
}
|
|
4380
|
+
function uninstallCursorPlugin(paths) {
|
|
4381
|
+
const existingRules = readTextIfExists(paths.cursorRulePath);
|
|
4382
|
+
if (existingRules === null) {
|
|
4383
|
+
return {
|
|
4384
|
+
target: "cursor",
|
|
4385
|
+
changed: false,
|
|
4386
|
+
message: "Cursor OrgX rules were not installed."
|
|
4387
|
+
};
|
|
4388
|
+
}
|
|
4389
|
+
if (existingRules !== CURSOR_RULES_CONTENT) {
|
|
4390
|
+
return {
|
|
4391
|
+
target: "cursor",
|
|
4392
|
+
changed: false,
|
|
4393
|
+
message: "Cursor rules file differs from the managed OrgX rules, so it was left in place."
|
|
4394
|
+
};
|
|
4395
|
+
}
|
|
4396
|
+
const changed = deleteFileIfExists(paths.cursorRulePath);
|
|
4397
|
+
return {
|
|
4398
|
+
target: "cursor",
|
|
4399
|
+
changed,
|
|
4400
|
+
message: changed ? "Removed the managed Cursor OrgX rules." : "Cursor OrgX rules were not installed."
|
|
4401
|
+
};
|
|
4402
|
+
}
|
|
3964
4403
|
async function uninstallClaudePlugin(paths, runner) {
|
|
3965
4404
|
const state = await getClaudeInstallState(runner);
|
|
3966
4405
|
let changed = false;
|
|
@@ -4056,6 +4495,7 @@ async function listOrgxPluginStatuses(options = {}) {
|
|
|
4056
4495
|
const paths = resolvePluginPaths(options.paths);
|
|
4057
4496
|
const runner = resolveCommandRunner(options.commandRunner);
|
|
4058
4497
|
return await Promise.all([
|
|
4498
|
+
buildCursorStatus(paths),
|
|
4059
4499
|
buildClaudeStatus(paths, runner),
|
|
4060
4500
|
buildCodexStatus(paths, runner),
|
|
4061
4501
|
buildOpenclawStatus(runner)
|
|
@@ -4072,6 +4512,9 @@ async function installOrgxPlugins(options = {}) {
|
|
|
4072
4512
|
const results = [];
|
|
4073
4513
|
for (const target of targets) {
|
|
4074
4514
|
switch (target) {
|
|
4515
|
+
case "cursor":
|
|
4516
|
+
results.push(installCursorPlugin(paths));
|
|
4517
|
+
break;
|
|
4075
4518
|
case "claude":
|
|
4076
4519
|
results.push(await installClaudePlugin(paths, fetchImpl, runner));
|
|
4077
4520
|
break;
|
|
@@ -4092,6 +4535,9 @@ async function uninstallOrgxPlugins(options = {}) {
|
|
|
4092
4535
|
const results = [];
|
|
4093
4536
|
for (const target of targets) {
|
|
4094
4537
|
switch (target) {
|
|
4538
|
+
case "cursor":
|
|
4539
|
+
results.push(uninstallCursorPlugin(paths));
|
|
4540
|
+
break;
|
|
4095
4541
|
case "claude":
|
|
4096
4542
|
results.push(await uninstallClaudePlugin(paths, runner));
|
|
4097
4543
|
break;
|
|
@@ -4558,6 +5004,8 @@ function formatAuthSource(source) {
|
|
|
4558
5004
|
}
|
|
4559
5005
|
function formatPluginTargetLabel(target) {
|
|
4560
5006
|
switch (target) {
|
|
5007
|
+
case "cursor":
|
|
5008
|
+
return "Cursor rules";
|
|
4561
5009
|
case "claude":
|
|
4562
5010
|
return "Claude Code";
|
|
4563
5011
|
case "codex":
|
|
@@ -4602,30 +5050,79 @@ function printPluginMutationReport(report) {
|
|
|
4602
5050
|
);
|
|
4603
5051
|
}
|
|
4604
5052
|
}
|
|
5053
|
+
async function printPluginStatusSection() {
|
|
5054
|
+
const spinner = createOrgxSpinner("Checking OrgX plugin and Cursor rules status");
|
|
5055
|
+
spinner.start();
|
|
5056
|
+
const statuses = await listOrgxPluginStatuses();
|
|
5057
|
+
spinner.succeed("OrgX plugin and Cursor rules status checked");
|
|
5058
|
+
console.log("");
|
|
5059
|
+
console.log(pc3.dim(" plugins"));
|
|
5060
|
+
printPluginStatusReport(statuses);
|
|
5061
|
+
return statuses;
|
|
5062
|
+
}
|
|
4605
5063
|
function printSkillInstallReport(report) {
|
|
4606
5064
|
for (const write of report.writes) {
|
|
4607
|
-
const icon = write.changed ? ICON.ok : ICON.skip;
|
|
4608
|
-
const state = write.changed ? pc3.green("updated ") : pc3.dim("unchanged");
|
|
5065
|
+
const icon = write.skipped ? ICON.warn : write.changed ? ICON.ok : ICON.skip;
|
|
5066
|
+
const state = write.skipped ? pc3.yellow("skipped ") : write.changed ? pc3.green("updated ") : pc3.dim("unchanged");
|
|
4609
5067
|
console.log(` ${icon} ${pc3.bold(write.label.padEnd(10))} ${state}`);
|
|
5068
|
+
if (write.reason) {
|
|
5069
|
+
console.log(` ${pc3.dim(write.reason)}`);
|
|
5070
|
+
}
|
|
4610
5071
|
}
|
|
4611
5072
|
for (const pack of report.packs) {
|
|
4612
5073
|
const changedCount = pack.files.filter((f) => f.changed).length;
|
|
4613
|
-
const
|
|
4614
|
-
const
|
|
5074
|
+
const skippedCount = pack.files.filter((f) => f.skipped).length;
|
|
5075
|
+
const icon = skippedCount > 0 ? ICON.warn : changedCount > 0 ? ICON.ok : ICON.skip;
|
|
5076
|
+
const state = skippedCount > 0 ? pc3.yellow(`${skippedCount} skipped `) : changedCount > 0 ? pc3.green(`${changedCount} updated `) : pc3.dim("unchanged");
|
|
4615
5077
|
console.log(` ${icon} ${pc3.bold(pack.name.padEnd(10))} ${state} ${pc3.dim(`${pack.files.length} files`)}`);
|
|
5078
|
+
for (const file of pack.files.filter((entry) => entry.skipped && entry.reason)) {
|
|
5079
|
+
console.log(` ${pc3.dim(`${file.label}: ${file.reason}`)}`);
|
|
5080
|
+
}
|
|
4616
5081
|
}
|
|
4617
5082
|
for (const note of report.notes) {
|
|
4618
5083
|
console.log(` ${ICON.skip} ${pc3.dim(note)}`);
|
|
4619
5084
|
}
|
|
4620
5085
|
}
|
|
4621
5086
|
function countSkillReportChanges(report) {
|
|
4622
|
-
const writeChanges = report.writes.filter((write) => write.changed).length;
|
|
5087
|
+
const writeChanges = report.writes.filter((write) => write.changed && !write.skipped).length;
|
|
4623
5088
|
const packChanges = report.packs.reduce(
|
|
4624
|
-
(count, pack) => count + pack.files.filter((file) => file.changed).length,
|
|
5089
|
+
(count, pack) => count + pack.files.filter((file) => file.changed && !file.skipped).length,
|
|
4625
5090
|
0
|
|
4626
5091
|
);
|
|
4627
5092
|
return writeChanges + packChanges;
|
|
4628
5093
|
}
|
|
5094
|
+
function printSkillExtensions(extensions) {
|
|
5095
|
+
if (extensions.length === 0) {
|
|
5096
|
+
console.log(` ${ICON.skip} ${pc3.dim("no skill extensions yet")}`);
|
|
5097
|
+
return;
|
|
5098
|
+
}
|
|
5099
|
+
for (const extension of extensions) {
|
|
5100
|
+
const icon = extension.enabled ? ICON.ok : ICON.skip;
|
|
5101
|
+
const state = extension.enabled ? pc3.green("enabled ") : pc3.dim("disabled ");
|
|
5102
|
+
console.log(
|
|
5103
|
+
` ${icon} ${pc3.bold(extension.id.padEnd(24))} ${state} ${pc3.dim(extension.path)}`
|
|
5104
|
+
);
|
|
5105
|
+
}
|
|
5106
|
+
}
|
|
5107
|
+
function printSkillExtensionWrite(result) {
|
|
5108
|
+
const action = result.created ? "created" : result.changed ? "updated" : "unchanged";
|
|
5109
|
+
const color = result.created || result.changed ? pc3.green : pc3.dim;
|
|
5110
|
+
console.log(
|
|
5111
|
+
` ${result.created || result.changed ? ICON.ok : ICON.skip} ${pc3.bold(result.extension.id.padEnd(24))} ${color(action)}`
|
|
5112
|
+
);
|
|
5113
|
+
console.log(` ${pc3.dim(result.path)}`);
|
|
5114
|
+
}
|
|
5115
|
+
function openPathInEditor(path) {
|
|
5116
|
+
const editor = process.env.EDITOR || process.env.VISUAL;
|
|
5117
|
+
if (!editor) {
|
|
5118
|
+
return false;
|
|
5119
|
+
}
|
|
5120
|
+
const result = spawnSync3(editor, [path], {
|
|
5121
|
+
shell: true,
|
|
5122
|
+
stdio: "inherit"
|
|
5123
|
+
});
|
|
5124
|
+
return result.status === 0;
|
|
5125
|
+
}
|
|
4629
5126
|
async function safeTrackWizardTelemetry(event, properties = {}) {
|
|
4630
5127
|
try {
|
|
4631
5128
|
await trackWizardTelemetry(event, properties);
|
|
@@ -4704,8 +5201,9 @@ async function textPrompt(input) {
|
|
|
4704
5201
|
}
|
|
4705
5202
|
async function multiselectPrompt(input) {
|
|
4706
5203
|
const promptInput = {
|
|
4707
|
-
message: input.message
|
|
5204
|
+
message: `${input.message} ${pc3.dim("Space selects items; Enter continues.")}`,
|
|
4708
5205
|
options: input.options,
|
|
5206
|
+
...input.initialValues ? { initialValues: input.initialValues } : {},
|
|
4709
5207
|
...input.required !== void 0 ? { required: input.required } : {}
|
|
4710
5208
|
};
|
|
4711
5209
|
return normalizePromptResult(await clack.multiselect(promptInput));
|
|
@@ -4854,10 +5352,11 @@ async function maybeConfigureOptionalWorkspaceAddOns(input) {
|
|
|
4854
5352
|
const hasAgentRoster = refreshedState?.agentRoster?.workspaceId === input.workspace.id;
|
|
4855
5353
|
if (!hasAgentRoster) {
|
|
4856
5354
|
const rosterChoice = await selectPrompt({
|
|
5355
|
+
initialValue: "default",
|
|
4857
5356
|
message: `Set up an OrgX agent roster for ${input.workspace.name}?`,
|
|
4858
5357
|
options: [
|
|
4859
|
-
{ value: "
|
|
4860
|
-
{ value: "
|
|
5358
|
+
{ value: "default", label: "Install the full default roster", hint: "recommended" },
|
|
5359
|
+
{ value: "guided", label: "Choose agents and domains" },
|
|
4861
5360
|
{ value: "no", label: "Skip roster setup" }
|
|
4862
5361
|
]
|
|
4863
5362
|
});
|
|
@@ -4912,13 +5411,19 @@ async function promptOptionalCompanionPluginTargets(input) {
|
|
|
4912
5411
|
if (!input.interactive) {
|
|
4913
5412
|
return [];
|
|
4914
5413
|
}
|
|
4915
|
-
|
|
5414
|
+
let statuses = input.statuses;
|
|
5415
|
+
if (!statuses) {
|
|
5416
|
+
const spinner = createOrgxSpinner("Checking optional OrgX plugin and Cursor rules status");
|
|
5417
|
+
spinner.start();
|
|
5418
|
+
statuses = await listOrgxPluginStatuses();
|
|
5419
|
+
spinner.succeed("Optional OrgX plugin and Cursor rules status checked");
|
|
5420
|
+
}
|
|
4916
5421
|
const installable = statuses.filter((status) => status.available && !status.installed);
|
|
4917
5422
|
if (installable.length === 0) {
|
|
4918
5423
|
return [];
|
|
4919
5424
|
}
|
|
4920
5425
|
const selection = await multiselectPrompt({
|
|
4921
|
-
message: "Install companion
|
|
5426
|
+
message: "Install OrgX companion plugins/rules into your detected AI tools?",
|
|
4922
5427
|
options: installable.map((status) => ({
|
|
4923
5428
|
value: status.target,
|
|
4924
5429
|
label: `Install ${formatPluginTargetLabel(status.target)}`,
|
|
@@ -4946,10 +5451,10 @@ async function installSelectedCompanionPlugins(input) {
|
|
|
4946
5451
|
if (input.targets.length === 0) {
|
|
4947
5452
|
return "skipped";
|
|
4948
5453
|
}
|
|
4949
|
-
const spinner = createOrgxSpinner("Installing OrgX companion plugins");
|
|
5454
|
+
const spinner = createOrgxSpinner("Installing OrgX companion plugins/rules");
|
|
4950
5455
|
spinner.start();
|
|
4951
5456
|
const report = await installOrgxPlugins({ targets: input.targets });
|
|
4952
|
-
spinner.succeed("OrgX companion plugins processed");
|
|
5457
|
+
spinner.succeed("OrgX companion plugins/rules processed");
|
|
4953
5458
|
printPluginMutationReport(report);
|
|
4954
5459
|
printPluginSkillOwnershipNote(input.targets);
|
|
4955
5460
|
await safeTrackWizardTelemetry("plugins_installed", {
|
|
@@ -4963,7 +5468,8 @@ async function installSelectedCompanionPlugins(input) {
|
|
|
4963
5468
|
}
|
|
4964
5469
|
async function maybeInstallOptionalCompanionPlugins(input) {
|
|
4965
5470
|
const selection = await promptOptionalCompanionPluginTargets({
|
|
4966
|
-
interactive: input.interactive
|
|
5471
|
+
interactive: input.interactive,
|
|
5472
|
+
...input.statuses ? { statuses: input.statuses } : {}
|
|
4967
5473
|
});
|
|
4968
5474
|
if (selection === "cancelled") {
|
|
4969
5475
|
return "cancelled";
|
|
@@ -5050,13 +5556,13 @@ function printDoctorReport(report, assessment) {
|
|
|
5050
5556
|
}
|
|
5051
5557
|
async function main() {
|
|
5052
5558
|
const program = new Command();
|
|
5053
|
-
program.name("orgx-wizard").description("
|
|
5054
|
-
const pkgVersion = true ? "0.1.
|
|
5559
|
+
program.name("orgx-wizard").description("Add OrgX MCP configs, skills/rules, and companion plugins to your local AI tools.").showHelpAfterError();
|
|
5560
|
+
const pkgVersion = true ? "0.1.11" : void 0;
|
|
5055
5561
|
program.version(pkgVersion ?? "unknown", "-V, --version");
|
|
5056
5562
|
program.hook("preAction", () => {
|
|
5057
5563
|
console.log(renderBanner(pkgVersion));
|
|
5058
5564
|
});
|
|
5059
|
-
program.command("setup").description("
|
|
5565
|
+
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) => {
|
|
5060
5566
|
const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
5061
5567
|
await safeTrackWizardTelemetry("wizard_started", {
|
|
5062
5568
|
command: "setup",
|
|
@@ -5162,6 +5668,7 @@ async function main() {
|
|
|
5162
5668
|
const results = await setupDetectedSurfaces();
|
|
5163
5669
|
spinner.succeed("Detected surfaces configured");
|
|
5164
5670
|
printMutationResults(results);
|
|
5671
|
+
const pluginStatuses = await printPluginStatusSection();
|
|
5165
5672
|
await safeTrackWizardTelemetry("mcp_injected", {
|
|
5166
5673
|
changed_count: results.filter((result) => result.changed).length,
|
|
5167
5674
|
preset: "standard",
|
|
@@ -5250,6 +5757,7 @@ async function main() {
|
|
|
5250
5757
|
}
|
|
5251
5758
|
const pluginInstallResult = await maybeInstallOptionalCompanionPlugins({
|
|
5252
5759
|
interactive,
|
|
5760
|
+
statuses: pluginStatuses,
|
|
5253
5761
|
telemetry: { command: "setup", preset: "standard" }
|
|
5254
5762
|
});
|
|
5255
5763
|
if (pluginInstallResult === "cancelled") {
|
|
@@ -5420,6 +5928,51 @@ async function main() {
|
|
|
5420
5928
|
);
|
|
5421
5929
|
}
|
|
5422
5930
|
});
|
|
5931
|
+
program.command("uninstall").description("Remove OrgX-managed MCP tool configs, companion plugins/rules, 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 Cursor rules removal.").option("--skip-surfaces", "Skip MCP tool config removal.").action(async (options) => {
|
|
5932
|
+
await safeTrackWizardTelemetry("wizard_uninstalled", {
|
|
5933
|
+
keep_auth: Boolean(options.keepAuth),
|
|
5934
|
+
keep_state: Boolean(options.keepState),
|
|
5935
|
+
skip_plugins: Boolean(options.skipPlugins),
|
|
5936
|
+
skip_surfaces: Boolean(options.skipSurfaces)
|
|
5937
|
+
});
|
|
5938
|
+
console.log(pc3.bold("Removing OrgX wizard-managed configuration"));
|
|
5939
|
+
if (options.skipSurfaces) {
|
|
5940
|
+
console.log(` ${ICON.skip} ${pc3.bold("surfaces".padEnd(10))} ${pc3.dim("skipped")}`);
|
|
5941
|
+
} else {
|
|
5942
|
+
console.log("");
|
|
5943
|
+
console.log(pc3.dim(" surfaces"));
|
|
5944
|
+
const surfaceResults = removeSurface(["all"]);
|
|
5945
|
+
printMutationResults(surfaceResults);
|
|
5946
|
+
}
|
|
5947
|
+
if (options.skipPlugins) {
|
|
5948
|
+
console.log(` ${ICON.skip} ${pc3.bold("plugins".padEnd(12))} ${pc3.dim("skipped")}`);
|
|
5949
|
+
} else {
|
|
5950
|
+
console.log("");
|
|
5951
|
+
console.log(pc3.dim(" plugins"));
|
|
5952
|
+
const spinner = createOrgxSpinner("Removing OrgX companion plugins and rules");
|
|
5953
|
+
spinner.start();
|
|
5954
|
+
const pluginReport = await uninstallOrgxPlugins({ targets: ["all"] });
|
|
5955
|
+
spinner.succeed("OrgX companion plugins and rules processed");
|
|
5956
|
+
printPluginMutationReport(pluginReport);
|
|
5957
|
+
}
|
|
5958
|
+
console.log("");
|
|
5959
|
+
if (options.keepAuth) {
|
|
5960
|
+
console.log(` ${ICON.skip} ${pc3.bold("auth".padEnd(12))} ${pc3.dim("kept")}`);
|
|
5961
|
+
} else {
|
|
5962
|
+
const removedAuth = await clearWizardAuth();
|
|
5963
|
+
const state = removedAuth ? pc3.green("updated ") : pc3.dim("unchanged");
|
|
5964
|
+
const message = removedAuth ? "Removed the wizard-local OrgX API key." : "No wizard-local OrgX API key was stored.";
|
|
5965
|
+
console.log(` ${removedAuth ? ICON.ok : ICON.skip} ${pc3.bold("auth".padEnd(12))} ${state} ${pc3.dim(message)}`);
|
|
5966
|
+
}
|
|
5967
|
+
if (options.keepState) {
|
|
5968
|
+
console.log(` ${ICON.skip} ${pc3.bold("state".padEnd(12))} ${pc3.dim("kept")}`);
|
|
5969
|
+
} else {
|
|
5970
|
+
const removedState = clearWizardState();
|
|
5971
|
+
const state = removedState ? pc3.green("updated ") : pc3.dim("unchanged");
|
|
5972
|
+
const message = removedState ? "Removed wizard-local setup state." : "No wizard-local setup state was stored.";
|
|
5973
|
+
console.log(` ${removedState ? ICON.ok : ICON.skip} ${pc3.bold("state".padEnd(12))} ${state} ${pc3.dim(message)}`);
|
|
5974
|
+
}
|
|
5975
|
+
});
|
|
5423
5976
|
const surface = program.command("surface").description("Manage supported OrgX surfaces.");
|
|
5424
5977
|
surface.command("list").description("Show supported surfaces and their current status.").action(() => {
|
|
5425
5978
|
printSurfaceTable(listSurfaceStatuses());
|
|
@@ -5432,28 +5985,28 @@ async function main() {
|
|
|
5432
5985
|
const results = removeSurface(names);
|
|
5433
5986
|
printMutationResults(results);
|
|
5434
5987
|
});
|
|
5435
|
-
const mcp = program.command("mcp").description("
|
|
5436
|
-
mcp.command("add").description("Add OrgX MCP entries to one
|
|
5988
|
+
const mcp = program.command("mcp").description("Add or remove OrgX MCP config entries in Claude, Cursor, Codex, VS Code, Windsurf, and Zed.");
|
|
5989
|
+
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) => {
|
|
5437
5990
|
const results = await addMcpSurface(names);
|
|
5438
5991
|
printMutationResults(results);
|
|
5439
5992
|
});
|
|
5440
|
-
mcp.command("remove").description("Remove OrgX MCP entries from one
|
|
5993
|
+
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) => {
|
|
5441
5994
|
const results = removeMcpSurface(names);
|
|
5442
5995
|
printMutationResults(results);
|
|
5443
5996
|
});
|
|
5444
|
-
const plugins = program.command("plugins").description("Install or remove companion
|
|
5445
|
-
plugins.command("list").description("Show companion plugin availability and install status.").action(async () => {
|
|
5446
|
-
const spinner = createOrgxSpinner("Checking
|
|
5997
|
+
const plugins = program.command("plugins").description("Install or remove OrgX companion plugins/rules in Cursor, Claude Code, Codex, and OpenClaw.");
|
|
5998
|
+
plugins.command("list").description("Show companion plugin/rules availability and install status in your tools.").action(async () => {
|
|
5999
|
+
const spinner = createOrgxSpinner("Checking OrgX plugin and Cursor rules status");
|
|
5447
6000
|
spinner.start();
|
|
5448
6001
|
const statuses = await listOrgxPluginStatuses();
|
|
5449
|
-
spinner.
|
|
6002
|
+
spinner.succeed("OrgX plugin and Cursor rules status checked");
|
|
5450
6003
|
printPluginStatusReport(statuses);
|
|
5451
6004
|
});
|
|
5452
|
-
plugins.command("add").description("Install OrgX companion plugins into Claude Code, Codex,
|
|
5453
|
-
const spinner = createOrgxSpinner("Installing OrgX companion plugins");
|
|
6005
|
+
plugins.command("add").description("Install OrgX companion plugins/rules into Cursor, Claude Code, Codex, and OpenClaw.").argument("[targets...]", "cursor, claude, codex, openclaw, or all", ["all"]).action(async (targets) => {
|
|
6006
|
+
const spinner = createOrgxSpinner("Installing OrgX companion plugins/rules");
|
|
5454
6007
|
spinner.start();
|
|
5455
6008
|
const report = await installOrgxPlugins({ targets });
|
|
5456
|
-
spinner.succeed("OrgX companion plugins processed");
|
|
6009
|
+
spinner.succeed("OrgX companion plugins/rules processed");
|
|
5457
6010
|
printPluginMutationReport(report);
|
|
5458
6011
|
printPluginSkillOwnershipNote(report.results.map((result) => result.target));
|
|
5459
6012
|
await safeTrackWizardTelemetry("plugins_installed", {
|
|
@@ -5463,11 +6016,11 @@ async function main() {
|
|
|
5463
6016
|
target_count: report.results.length
|
|
5464
6017
|
});
|
|
5465
6018
|
});
|
|
5466
|
-
plugins.command("remove").description("Uninstall managed OrgX companion plugins from Claude Code, Codex,
|
|
5467
|
-
const spinner = createOrgxSpinner("Removing OrgX companion plugins");
|
|
6019
|
+
plugins.command("remove").description("Uninstall managed OrgX companion plugins/rules from Cursor, Claude Code, Codex, and OpenClaw.").argument("[targets...]", "cursor, claude, codex, openclaw, or all", ["all"]).action(async (targets) => {
|
|
6020
|
+
const spinner = createOrgxSpinner("Removing OrgX companion plugins/rules");
|
|
5468
6021
|
spinner.start();
|
|
5469
6022
|
const report = await uninstallOrgxPlugins({ targets });
|
|
5470
|
-
spinner.succeed("OrgX companion plugins removed");
|
|
6023
|
+
spinner.succeed("OrgX companion plugins/rules removed");
|
|
5471
6024
|
printPluginMutationReport(report);
|
|
5472
6025
|
await safeTrackWizardTelemetry("plugins_removed", {
|
|
5473
6026
|
changed_count: countPluginReportChanges(report),
|
|
@@ -5542,16 +6095,17 @@ async function main() {
|
|
|
5542
6095
|
process.exitCode = 1;
|
|
5543
6096
|
}
|
|
5544
6097
|
});
|
|
5545
|
-
const skills = program.command("skills").description("Install OrgX
|
|
5546
|
-
skills.command("add").description("Write standalone OrgX
|
|
6098
|
+
const skills = program.command("skills").description("Install OrgX skills and rules into supported local tools.");
|
|
6099
|
+
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) => {
|
|
5547
6100
|
const pluginTargets = (await listOrgxPluginStatuses()).filter((status) => status.installed).map((status) => status.target);
|
|
5548
|
-
const spinner = createOrgxSpinner("Installing OrgX rules
|
|
6101
|
+
const spinner = createOrgxSpinner("Installing OrgX skills/rules into tools");
|
|
5549
6102
|
spinner.start();
|
|
5550
6103
|
const report = await installOrgxSkills({
|
|
6104
|
+
force: options.force === true,
|
|
5551
6105
|
pluginTargets,
|
|
5552
6106
|
skillNames: packs
|
|
5553
6107
|
});
|
|
5554
|
-
spinner.succeed("OrgX rules
|
|
6108
|
+
spinner.succeed("OrgX skills/rules installed into tools");
|
|
5555
6109
|
printSkillInstallReport(report);
|
|
5556
6110
|
await safeTrackWizardTelemetry("skills_installed", {
|
|
5557
6111
|
changed_count: countSkillReportChanges(report),
|
|
@@ -5559,9 +6113,99 @@ async function main() {
|
|
|
5559
6113
|
pack_count: report.packs.length,
|
|
5560
6114
|
plugin_managed_target_count: pluginTargets.length,
|
|
5561
6115
|
requested_pack_count: packs.length,
|
|
6116
|
+
skill_extension_count: report.extensions.length,
|
|
6117
|
+
write_count: report.writes.length
|
|
6118
|
+
});
|
|
6119
|
+
});
|
|
6120
|
+
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) => {
|
|
6121
|
+
const pluginTargets = (await listOrgxPluginStatuses()).filter((status) => status.installed).map((status) => status.target);
|
|
6122
|
+
const spinner = createOrgxSpinner("Syncing OrgX skills/rules and extensions into tools");
|
|
6123
|
+
spinner.start();
|
|
6124
|
+
const report = await installOrgxSkills({
|
|
6125
|
+
force: options.force === true,
|
|
6126
|
+
pluginTargets,
|
|
6127
|
+
skillNames: packs
|
|
6128
|
+
});
|
|
6129
|
+
spinner.succeed("OrgX skills/rules synced into tools");
|
|
6130
|
+
printSkillInstallReport(report);
|
|
6131
|
+
await safeTrackWizardTelemetry("skills_synced", {
|
|
6132
|
+
changed_count: countSkillReportChanges(report),
|
|
6133
|
+
command: "skills:sync",
|
|
6134
|
+
pack_count: report.packs.length,
|
|
6135
|
+
plugin_managed_target_count: pluginTargets.length,
|
|
6136
|
+
requested_pack_count: packs.length,
|
|
6137
|
+
skill_extension_count: report.extensions.length,
|
|
5562
6138
|
write_count: report.writes.length
|
|
5563
6139
|
});
|
|
5564
6140
|
});
|
|
6141
|
+
skills.command("status").description("Show installed skill/rule tracking and local skill extensions.").action(async () => {
|
|
6142
|
+
const report = getSkillStatus();
|
|
6143
|
+
console.log(pc3.dim(" extensions"));
|
|
6144
|
+
printSkillExtensions(report.extensions);
|
|
6145
|
+
console.log("");
|
|
6146
|
+
console.log(pc3.dim(" generated files"));
|
|
6147
|
+
if (report.trackedFiles.length === 0) {
|
|
6148
|
+
console.log(` ${ICON.skip} ${pc3.dim("no generated skill files tracked yet")}`);
|
|
6149
|
+
} else {
|
|
6150
|
+
for (const file of report.trackedFiles) {
|
|
6151
|
+
console.log(` ${ICON.ok} ${pc3.bold(file.skillId.padEnd(24))} ${pc3.dim(file.path)}`);
|
|
6152
|
+
}
|
|
6153
|
+
}
|
|
6154
|
+
});
|
|
6155
|
+
const skillExtensions = skills.command("extensions").description("Create, edit, and sync user extensions appended after OrgX core skills.");
|
|
6156
|
+
skillExtensions.command("list").description("List local OrgX skill extensions.").action(() => {
|
|
6157
|
+
printSkillExtensions(listSkillExtensions());
|
|
6158
|
+
});
|
|
6159
|
+
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) => {
|
|
6160
|
+
const result = addSkillExtension({
|
|
6161
|
+
overwrite: options.overwrite === true,
|
|
6162
|
+
skillId: skill,
|
|
6163
|
+
...options.content !== void 0 ? { content: options.content } : {},
|
|
6164
|
+
...options.scope !== void 0 ? { scope: options.scope } : {},
|
|
6165
|
+
...options.title !== void 0 ? { title: options.title } : {}
|
|
6166
|
+
});
|
|
6167
|
+
printSkillExtensionWrite(result);
|
|
6168
|
+
console.log(
|
|
6169
|
+
` ${ICON.skip} ${pc3.dim(`Run ${getCmd()} skills sync to apply it to configured tools.`)}`
|
|
6170
|
+
);
|
|
6171
|
+
});
|
|
6172
|
+
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) => {
|
|
6173
|
+
const result = addSkillExtension({
|
|
6174
|
+
skillId: skill,
|
|
6175
|
+
...options.scope !== void 0 ? { scope: options.scope } : {}
|
|
6176
|
+
});
|
|
6177
|
+
printSkillExtensionWrite(result);
|
|
6178
|
+
if (!openPathInEditor(result.path)) {
|
|
6179
|
+
console.log(
|
|
6180
|
+
` ${ICON.warn} ${pc3.yellow("editor not opened")} ${pc3.dim(`Set EDITOR or edit ${result.path}`)}`
|
|
6181
|
+
);
|
|
6182
|
+
}
|
|
6183
|
+
console.log(
|
|
6184
|
+
` ${ICON.skip} ${pc3.dim(`Run ${getCmd()} skills sync to apply it to configured tools.`)}`
|
|
6185
|
+
);
|
|
6186
|
+
});
|
|
6187
|
+
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) => {
|
|
6188
|
+
const result = setSkillExtensionEnabled({
|
|
6189
|
+
enabled: true,
|
|
6190
|
+
skillId: skill,
|
|
6191
|
+
...options.scope !== void 0 ? { scope: options.scope } : {}
|
|
6192
|
+
});
|
|
6193
|
+
printSkillExtensionWrite(result);
|
|
6194
|
+
console.log(
|
|
6195
|
+
` ${ICON.skip} ${pc3.dim(`Run ${getCmd()} skills sync to apply it to configured tools.`)}`
|
|
6196
|
+
);
|
|
6197
|
+
});
|
|
6198
|
+
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) => {
|
|
6199
|
+
const result = setSkillExtensionEnabled({
|
|
6200
|
+
enabled: false,
|
|
6201
|
+
skillId: skill,
|
|
6202
|
+
...options.scope !== void 0 ? { scope: options.scope } : {}
|
|
6203
|
+
});
|
|
6204
|
+
printSkillExtensionWrite(result);
|
|
6205
|
+
console.log(
|
|
6206
|
+
` ${ICON.skip} ${pc3.dim(`Run ${getCmd()} skills sync to apply it to configured tools.`)}`
|
|
6207
|
+
);
|
|
6208
|
+
});
|
|
5565
6209
|
await program.parseAsync(process.argv);
|
|
5566
6210
|
}
|
|
5567
6211
|
main().catch((error) => {
|