@useorgx/wizard 0.1.10 → 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 -9
- package/dist/cli.js +545 -53
- 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) {
|
|
@@ -3005,7 +3044,9 @@ async function ensureOnboardingTask(workspace, options = {}) {
|
|
|
3005
3044
|
}
|
|
3006
3045
|
|
|
3007
3046
|
// src/lib/skills.ts
|
|
3008
|
-
import {
|
|
3047
|
+
import { createHash } from "crypto";
|
|
3048
|
+
import { existsSync as existsSync3, readdirSync } from "fs";
|
|
3049
|
+
import { basename, join as join2 } from "path";
|
|
3009
3050
|
var DEFAULT_ORGX_SKILL_PACKS = [
|
|
3010
3051
|
"morning-briefing",
|
|
3011
3052
|
"initiative-kickoff",
|
|
@@ -3017,6 +3058,9 @@ var EXCLUDED_PACK_DIRS = /* @__PURE__ */ new Set([".github", "scripts"]);
|
|
|
3017
3058
|
var ORGX_SKILLS_OWNER = "useorgx";
|
|
3018
3059
|
var ORGX_SKILLS_REPO = "skills";
|
|
3019
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 = "---";
|
|
3020
3064
|
var CURSOR_RULES_CONTENT = `# OrgX Rules
|
|
3021
3065
|
|
|
3022
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.
|
|
@@ -3072,6 +3116,219 @@ Install and use these packs alongside this base skill:
|
|
|
3072
3116
|
4. When you scaffold, decide up front whether \`continue_on_error\` is acceptable.
|
|
3073
3117
|
5. Carry \`_context\` through any widget-producing flows so the UI can render and resume correctly.
|
|
3074
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
|
+
}
|
|
3075
3332
|
function encodeRepoPath(value) {
|
|
3076
3333
|
return value.split("/").filter((segment) => segment.length > 0).map((segment) => encodeURIComponent(segment)).join("/");
|
|
3077
3334
|
}
|
|
@@ -3137,12 +3394,35 @@ async function fetchRemoteText(sourceUrl, fetchImpl) {
|
|
|
3137
3394
|
}
|
|
3138
3395
|
return readResponseText(response);
|
|
3139
3396
|
}
|
|
3140
|
-
function
|
|
3397
|
+
function getTrackedSkillFile(records, path) {
|
|
3398
|
+
return records.find((record) => record.path === path);
|
|
3399
|
+
}
|
|
3400
|
+
function writeManagedFile(path, content, label, sourceUrl, tracking) {
|
|
3141
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
|
+
}
|
|
3142
3413
|
const changed = existing !== content;
|
|
3143
3414
|
if (changed) {
|
|
3144
3415
|
writeTextFile(path, content);
|
|
3145
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
|
+
}
|
|
3146
3426
|
return {
|
|
3147
3427
|
label,
|
|
3148
3428
|
path,
|
|
@@ -3207,19 +3487,27 @@ async function fetchAvailablePackNames(fetchImpl, ref) {
|
|
|
3207
3487
|
const entries = await fetchDirectoryEntries("", fetchImpl, ref);
|
|
3208
3488
|
return entries.filter((e) => e.type === "dir" && !EXCLUDED_PACK_DIRS.has(e.name)).map((e) => e.name);
|
|
3209
3489
|
}
|
|
3210
|
-
async function installSkillPack(skillName, claudeSkillsDir, fetchImpl, ref) {
|
|
3490
|
+
async function installSkillPack(skillName, claudeSkillsDir, fetchImpl, ref, tracking) {
|
|
3211
3491
|
const rootPath = skillName;
|
|
3212
3492
|
const files = await listRemoteSkillFiles(rootPath, fetchImpl, ref);
|
|
3213
3493
|
const writes = [];
|
|
3214
3494
|
for (const file of files) {
|
|
3215
|
-
const
|
|
3495
|
+
const coreContent = await fetchRemoteText(file.sourceUrl, fetchImpl);
|
|
3216
3496
|
const relativePath = file.path.slice(`${rootPath}/`.length);
|
|
3497
|
+
const content = relativePath === "SKILL.md" ? composeSkillContent(skillName, coreContent, tracking.extensions) : coreContent;
|
|
3217
3498
|
writes.push(
|
|
3218
3499
|
writeManagedFile(
|
|
3219
3500
|
join2(claudeSkillsDir, skillName, relativePath),
|
|
3220
3501
|
content,
|
|
3221
3502
|
`${skillName}/${relativePath}`,
|
|
3222
|
-
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
|
+
}
|
|
3223
3511
|
)
|
|
3224
3512
|
);
|
|
3225
3513
|
}
|
|
@@ -3237,6 +3525,13 @@ async function installOrgxSkills(options = {}) {
|
|
|
3237
3525
|
const claudeSkillsDir = options.claudeSkillsDir ?? CLAUDE_SKILLS_DIR;
|
|
3238
3526
|
const claudeOrgxSkillPath = options.claudeOrgxSkillPath ?? CLAUDE_ORGX_SKILL_PATH;
|
|
3239
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();
|
|
3240
3535
|
const plan = planOrgxSkillsInstall(options.pluginTargets ?? []);
|
|
3241
3536
|
const requestedNames = options.skillNames ?? [];
|
|
3242
3537
|
let skillNames;
|
|
@@ -3250,34 +3545,101 @@ async function installOrgxSkills(options = {}) {
|
|
|
3250
3545
|
skillNames = resolveSkillPackNames(requestedNames);
|
|
3251
3546
|
}
|
|
3252
3547
|
const writes = [
|
|
3253
|
-
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
|
+
)
|
|
3254
3561
|
];
|
|
3255
3562
|
if (plan.installClaudeSkillBootstrap) {
|
|
3256
3563
|
writes.push(
|
|
3257
|
-
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
|
+
)
|
|
3258
3577
|
);
|
|
3259
3578
|
}
|
|
3260
3579
|
const packs = [];
|
|
3261
3580
|
if (plan.installClaudeSkillPacks) {
|
|
3262
3581
|
for (const skillName of skillNames) {
|
|
3263
|
-
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
|
+
}));
|
|
3264
3588
|
}
|
|
3265
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
|
+
}
|
|
3266
3618
|
return {
|
|
3267
|
-
|
|
3619
|
+
extensions,
|
|
3620
|
+
notes,
|
|
3268
3621
|
writes,
|
|
3269
3622
|
packs
|
|
3270
3623
|
};
|
|
3271
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
|
+
}
|
|
3272
3634
|
|
|
3273
3635
|
// src/lib/plugins.ts
|
|
3274
3636
|
import { spawn } from "child_process";
|
|
3275
3637
|
import {
|
|
3276
|
-
existsSync as
|
|
3638
|
+
existsSync as existsSync4,
|
|
3277
3639
|
mkdirSync as mkdirSync2,
|
|
3278
3640
|
mkdtempSync,
|
|
3279
3641
|
readFileSync as readFileSync2,
|
|
3280
|
-
readdirSync,
|
|
3642
|
+
readdirSync as readdirSync2,
|
|
3281
3643
|
rmSync,
|
|
3282
3644
|
statSync as statSync2,
|
|
3283
3645
|
writeFileSync as writeFileSync2
|
|
@@ -3343,8 +3705,8 @@ function encodeRepoPath2(value) {
|
|
|
3343
3705
|
return value.split("/").filter((segment) => segment.length > 0).map((segment) => encodeURIComponent(segment)).join("/");
|
|
3344
3706
|
}
|
|
3345
3707
|
function isLikelyRepoFilePath(path) {
|
|
3346
|
-
const
|
|
3347
|
-
return
|
|
3708
|
+
const basename2 = path.split("/").pop() ?? path;
|
|
3709
|
+
return basename2.includes(".") && !/^\.[^./]+$/.test(basename2);
|
|
3348
3710
|
}
|
|
3349
3711
|
function buildContentsUrl2(spec, path) {
|
|
3350
3712
|
const encodedPath = encodeRepoPath2(path);
|
|
@@ -3454,7 +3816,7 @@ async function fetchRemoteBytes(sourceUrl, fetchImpl) {
|
|
|
3454
3816
|
return Buffer.from(await response.arrayBuffer());
|
|
3455
3817
|
}
|
|
3456
3818
|
function readBytesIfExists(path) {
|
|
3457
|
-
if (!
|
|
3819
|
+
if (!existsSync4(path)) return null;
|
|
3458
3820
|
try {
|
|
3459
3821
|
if (!statSync2(path).isFile()) {
|
|
3460
3822
|
return null;
|
|
@@ -3478,17 +3840,17 @@ function writeBytesIfChanged(path, bytes) {
|
|
|
3478
3840
|
return true;
|
|
3479
3841
|
}
|
|
3480
3842
|
function removePathIfExists(path) {
|
|
3481
|
-
if (!
|
|
3843
|
+
if (!existsSync4(path)) return false;
|
|
3482
3844
|
rmSync(path, { force: true, recursive: true });
|
|
3483
3845
|
return true;
|
|
3484
3846
|
}
|
|
3485
3847
|
function listRelativeFiles(root, base = root) {
|
|
3486
|
-
if (!
|
|
3848
|
+
if (!existsSync4(root)) return [];
|
|
3487
3849
|
if (!statSync2(root).isDirectory()) {
|
|
3488
3850
|
return [];
|
|
3489
3851
|
}
|
|
3490
3852
|
const files = [];
|
|
3491
|
-
for (const entry of
|
|
3853
|
+
for (const entry of readdirSync2(root, { withFileTypes: true })) {
|
|
3492
3854
|
const nextPath = join3(root, entry.name);
|
|
3493
3855
|
if (entry.isDirectory()) {
|
|
3494
3856
|
files.push(...listRelativeFiles(nextPath, base));
|
|
@@ -3501,15 +3863,15 @@ function listRelativeFiles(root, base = root) {
|
|
|
3501
3863
|
return files.sort();
|
|
3502
3864
|
}
|
|
3503
3865
|
function pruneEmptyDirectories(root, current = root) {
|
|
3504
|
-
if (!
|
|
3866
|
+
if (!existsSync4(current) || !statSync2(current).isDirectory()) {
|
|
3505
3867
|
return false;
|
|
3506
3868
|
}
|
|
3507
3869
|
let changed = false;
|
|
3508
|
-
for (const entry of
|
|
3870
|
+
for (const entry of readdirSync2(current, { withFileTypes: true })) {
|
|
3509
3871
|
if (!entry.isDirectory()) continue;
|
|
3510
3872
|
changed = pruneEmptyDirectories(root, join3(current, entry.name)) || changed;
|
|
3511
3873
|
}
|
|
3512
|
-
if (current !== root &&
|
|
3874
|
+
if (current !== root && readdirSync2(current).length === 0) {
|
|
3513
3875
|
rmSync(current, { force: true, recursive: true });
|
|
3514
3876
|
return true;
|
|
3515
3877
|
}
|
|
@@ -3519,7 +3881,7 @@ async function syncManagedRepoTree(spec, destinationRoot, fetchImpl) {
|
|
|
3519
3881
|
const remoteFiles = await collectRemoteRepoFiles(spec, fetchImpl);
|
|
3520
3882
|
let changed = false;
|
|
3521
3883
|
const expected = new Set(remoteFiles.map((file) => file.localPath));
|
|
3522
|
-
if (
|
|
3884
|
+
if (existsSync4(destinationRoot) && !statSync2(destinationRoot).isDirectory()) {
|
|
3523
3885
|
rmSync(destinationRoot, { force: true, recursive: true });
|
|
3524
3886
|
changed = true;
|
|
3525
3887
|
}
|
|
@@ -3610,7 +3972,7 @@ function upsertCodexMarketplaceEntry(path) {
|
|
|
3610
3972
|
return writeJsonIfChanged(path, nextDocument);
|
|
3611
3973
|
}
|
|
3612
3974
|
function removeCodexMarketplaceEntry(path) {
|
|
3613
|
-
if (!
|
|
3975
|
+
if (!existsSync4(path)) {
|
|
3614
3976
|
return false;
|
|
3615
3977
|
}
|
|
3616
3978
|
const { document, plugins } = readMarketplacePlugins(path);
|
|
@@ -3788,7 +4150,7 @@ async function buildClaudeStatus(paths, runner) {
|
|
|
3788
4150
|
message: "Claude Code was not detected."
|
|
3789
4151
|
};
|
|
3790
4152
|
}
|
|
3791
|
-
const marketplaceExists =
|
|
4153
|
+
const marketplaceExists = existsSync4(paths.claudeMarketplaceManifestPath);
|
|
3792
4154
|
return {
|
|
3793
4155
|
target: "claude",
|
|
3794
4156
|
available: true,
|
|
@@ -3799,7 +4161,7 @@ async function buildClaudeStatus(paths, runner) {
|
|
|
3799
4161
|
function buildCodexStatus(paths, runner) {
|
|
3800
4162
|
return (async () => {
|
|
3801
4163
|
const available = detectSurface("codex").detected || await commandExists("codex", runner);
|
|
3802
|
-
const pluginExists =
|
|
4164
|
+
const pluginExists = existsSync4(paths.codexPluginDir);
|
|
3803
4165
|
const marketplaceExists = codexMarketplaceHasOrgxEntry(paths.codexMarketplacePath);
|
|
3804
4166
|
const installed = pluginExists && marketplaceExists;
|
|
3805
4167
|
if (installed) {
|
|
@@ -4700,28 +5062,67 @@ async function printPluginStatusSection() {
|
|
|
4700
5062
|
}
|
|
4701
5063
|
function printSkillInstallReport(report) {
|
|
4702
5064
|
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");
|
|
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");
|
|
4705
5067
|
console.log(` ${icon} ${pc3.bold(write.label.padEnd(10))} ${state}`);
|
|
5068
|
+
if (write.reason) {
|
|
5069
|
+
console.log(` ${pc3.dim(write.reason)}`);
|
|
5070
|
+
}
|
|
4706
5071
|
}
|
|
4707
5072
|
for (const pack of report.packs) {
|
|
4708
5073
|
const changedCount = pack.files.filter((f) => f.changed).length;
|
|
4709
|
-
const
|
|
4710
|
-
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");
|
|
4711
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
|
+
}
|
|
4712
5081
|
}
|
|
4713
5082
|
for (const note of report.notes) {
|
|
4714
5083
|
console.log(` ${ICON.skip} ${pc3.dim(note)}`);
|
|
4715
5084
|
}
|
|
4716
5085
|
}
|
|
4717
5086
|
function countSkillReportChanges(report) {
|
|
4718
|
-
const writeChanges = report.writes.filter((write) => write.changed).length;
|
|
5087
|
+
const writeChanges = report.writes.filter((write) => write.changed && !write.skipped).length;
|
|
4719
5088
|
const packChanges = report.packs.reduce(
|
|
4720
|
-
(count, pack) => count + pack.files.filter((file) => file.changed).length,
|
|
5089
|
+
(count, pack) => count + pack.files.filter((file) => file.changed && !file.skipped).length,
|
|
4721
5090
|
0
|
|
4722
5091
|
);
|
|
4723
5092
|
return writeChanges + packChanges;
|
|
4724
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
|
+
}
|
|
4725
5126
|
async function safeTrackWizardTelemetry(event, properties = {}) {
|
|
4726
5127
|
try {
|
|
4727
5128
|
await trackWizardTelemetry(event, properties);
|
|
@@ -5022,7 +5423,7 @@ async function promptOptionalCompanionPluginTargets(input) {
|
|
|
5022
5423
|
return [];
|
|
5023
5424
|
}
|
|
5024
5425
|
const selection = await multiselectPrompt({
|
|
5025
|
-
message: "Install companion
|
|
5426
|
+
message: "Install OrgX companion plugins/rules into your detected AI tools?",
|
|
5026
5427
|
options: installable.map((status) => ({
|
|
5027
5428
|
value: status.target,
|
|
5028
5429
|
label: `Install ${formatPluginTargetLabel(status.target)}`,
|
|
@@ -5050,10 +5451,10 @@ async function installSelectedCompanionPlugins(input) {
|
|
|
5050
5451
|
if (input.targets.length === 0) {
|
|
5051
5452
|
return "skipped";
|
|
5052
5453
|
}
|
|
5053
|
-
const spinner = createOrgxSpinner("Installing OrgX companion plugins");
|
|
5454
|
+
const spinner = createOrgxSpinner("Installing OrgX companion plugins/rules");
|
|
5054
5455
|
spinner.start();
|
|
5055
5456
|
const report = await installOrgxPlugins({ targets: input.targets });
|
|
5056
|
-
spinner.succeed("OrgX companion plugins processed");
|
|
5457
|
+
spinner.succeed("OrgX companion plugins/rules processed");
|
|
5057
5458
|
printPluginMutationReport(report);
|
|
5058
5459
|
printPluginSkillOwnershipNote(input.targets);
|
|
5059
5460
|
await safeTrackWizardTelemetry("plugins_installed", {
|
|
@@ -5155,13 +5556,13 @@ function printDoctorReport(report, assessment) {
|
|
|
5155
5556
|
}
|
|
5156
5557
|
async function main() {
|
|
5157
5558
|
const program = new Command();
|
|
5158
|
-
program.name("orgx-wizard").description("
|
|
5159
|
-
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;
|
|
5160
5561
|
program.version(pkgVersion ?? "unknown", "-V, --version");
|
|
5161
5562
|
program.hook("preAction", () => {
|
|
5162
5563
|
console.log(renderBanner(pkgVersion));
|
|
5163
5564
|
});
|
|
5164
|
-
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) => {
|
|
5165
5566
|
const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
5166
5567
|
await safeTrackWizardTelemetry("wizard_started", {
|
|
5167
5568
|
command: "setup",
|
|
@@ -5527,7 +5928,7 @@ async function main() {
|
|
|
5527
5928
|
);
|
|
5528
5929
|
}
|
|
5529
5930
|
});
|
|
5530
|
-
program.command("uninstall").description("Remove OrgX-managed
|
|
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) => {
|
|
5531
5932
|
await safeTrackWizardTelemetry("wizard_uninstalled", {
|
|
5532
5933
|
keep_auth: Boolean(options.keepAuth),
|
|
5533
5934
|
keep_state: Boolean(options.keepState),
|
|
@@ -5584,28 +5985,28 @@ async function main() {
|
|
|
5584
5985
|
const results = removeSurface(names);
|
|
5585
5986
|
printMutationResults(results);
|
|
5586
5987
|
});
|
|
5587
|
-
const mcp = program.command("mcp").description("
|
|
5588
|
-
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) => {
|
|
5589
5990
|
const results = await addMcpSurface(names);
|
|
5590
5991
|
printMutationResults(results);
|
|
5591
5992
|
});
|
|
5592
|
-
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) => {
|
|
5593
5994
|
const results = removeMcpSurface(names);
|
|
5594
5995
|
printMutationResults(results);
|
|
5595
5996
|
});
|
|
5596
|
-
const plugins = program.command("plugins").description("Install or remove
|
|
5597
|
-
plugins.command("list").description("Show companion plugin availability and install status.").action(async () => {
|
|
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 () => {
|
|
5598
5999
|
const spinner = createOrgxSpinner("Checking OrgX plugin and Cursor rules status");
|
|
5599
6000
|
spinner.start();
|
|
5600
6001
|
const statuses = await listOrgxPluginStatuses();
|
|
5601
6002
|
spinner.succeed("OrgX plugin and Cursor rules status checked");
|
|
5602
6003
|
printPluginStatusReport(statuses);
|
|
5603
6004
|
});
|
|
5604
|
-
plugins.command("add").description("Install
|
|
5605
|
-
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");
|
|
5606
6007
|
spinner.start();
|
|
5607
6008
|
const report = await installOrgxPlugins({ targets });
|
|
5608
|
-
spinner.succeed("OrgX companion plugins processed");
|
|
6009
|
+
spinner.succeed("OrgX companion plugins/rules processed");
|
|
5609
6010
|
printPluginMutationReport(report);
|
|
5610
6011
|
printPluginSkillOwnershipNote(report.results.map((result) => result.target));
|
|
5611
6012
|
await safeTrackWizardTelemetry("plugins_installed", {
|
|
@@ -5615,11 +6016,11 @@ async function main() {
|
|
|
5615
6016
|
target_count: report.results.length
|
|
5616
6017
|
});
|
|
5617
6018
|
});
|
|
5618
|
-
plugins.command("remove").description("Uninstall managed
|
|
5619
|
-
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");
|
|
5620
6021
|
spinner.start();
|
|
5621
6022
|
const report = await uninstallOrgxPlugins({ targets });
|
|
5622
|
-
spinner.succeed("OrgX companion plugins removed");
|
|
6023
|
+
spinner.succeed("OrgX companion plugins/rules removed");
|
|
5623
6024
|
printPluginMutationReport(report);
|
|
5624
6025
|
await safeTrackWizardTelemetry("plugins_removed", {
|
|
5625
6026
|
changed_count: countPluginReportChanges(report),
|
|
@@ -5694,16 +6095,17 @@ async function main() {
|
|
|
5694
6095
|
process.exitCode = 1;
|
|
5695
6096
|
}
|
|
5696
6097
|
});
|
|
5697
|
-
const skills = program.command("skills").description("Install OrgX
|
|
5698
|
-
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) => {
|
|
5699
6100
|
const pluginTargets = (await listOrgxPluginStatuses()).filter((status) => status.installed).map((status) => status.target);
|
|
5700
|
-
const spinner = createOrgxSpinner("Installing OrgX rules
|
|
6101
|
+
const spinner = createOrgxSpinner("Installing OrgX skills/rules into tools");
|
|
5701
6102
|
spinner.start();
|
|
5702
6103
|
const report = await installOrgxSkills({
|
|
6104
|
+
force: options.force === true,
|
|
5703
6105
|
pluginTargets,
|
|
5704
6106
|
skillNames: packs
|
|
5705
6107
|
});
|
|
5706
|
-
spinner.succeed("OrgX rules
|
|
6108
|
+
spinner.succeed("OrgX skills/rules installed into tools");
|
|
5707
6109
|
printSkillInstallReport(report);
|
|
5708
6110
|
await safeTrackWizardTelemetry("skills_installed", {
|
|
5709
6111
|
changed_count: countSkillReportChanges(report),
|
|
@@ -5711,9 +6113,99 @@ async function main() {
|
|
|
5711
6113
|
pack_count: report.packs.length,
|
|
5712
6114
|
plugin_managed_target_count: pluginTargets.length,
|
|
5713
6115
|
requested_pack_count: packs.length,
|
|
6116
|
+
skill_extension_count: report.extensions.length,
|
|
5714
6117
|
write_count: report.writes.length
|
|
5715
6118
|
});
|
|
5716
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,
|
|
6138
|
+
write_count: report.writes.length
|
|
6139
|
+
});
|
|
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
|
+
});
|
|
5717
6209
|
await program.parseAsync(process.argv);
|
|
5718
6210
|
}
|
|
5719
6211
|
main().catch((error) => {
|