maxsimcli 3.12.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.tsbuildinfo +1 -1
- package/dist/adapters/index.d.ts +0 -11
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +4 -40
- package/dist/adapters/index.js.map +1 -1
- package/dist/assets/CHANGELOG.md +17 -0
- package/dist/assets/dashboard/client/assets/{index-wtQDvXzr.js → index-C_eAetZJ.js} +60 -60
- package/dist/assets/dashboard/client/assets/index-CmiJKqOU.css +32 -0
- package/dist/assets/dashboard/client/index.html +2 -2
- package/dist/assets/dashboard/server.js +467 -271
- package/dist/assets/templates/agents/AGENTS.md +13 -1
- package/dist/assets/templates/agents/maxsim-debugger.md +2 -2
- package/dist/assets/templates/agents/maxsim-executor.md +5 -5
- package/dist/assets/templates/agents/maxsim-phase-researcher.md +2 -2
- package/dist/assets/templates/agents/maxsim-plan-checker.md +2 -2
- package/dist/assets/templates/agents/maxsim-planner.md +3 -3
- package/dist/assets/templates/commands/maxsim/add-todo.md +15 -5
- package/dist/assets/templates/commands/maxsim/discuss-phase.md +1 -0
- package/dist/assets/templates/commands/maxsim/init-existing.md +4 -0
- package/dist/assets/templates/commands/maxsim/new-project.md +4 -0
- package/dist/assets/templates/references/thinking-partner.md +41 -0
- package/dist/assets/templates/skills/batch-worktree/SKILL.md +137 -0
- package/dist/assets/templates/skills/brainstorming/SKILL.md +159 -0
- package/dist/assets/templates/skills/roadmap-writing/SKILL.md +198 -0
- package/dist/assets/templates/skills/sdd/SKILL.md +175 -0
- package/dist/assets/templates/skills/simplify/SKILL.md +48 -0
- package/dist/assets/templates/skills/using-maxsim/SKILL.md +6 -1
- package/dist/assets/templates/templates/acceptance-criteria.md +10 -0
- package/dist/assets/templates/templates/decisions.md +10 -0
- package/dist/assets/templates/templates/no-gos.md +9 -0
- package/dist/assets/templates/workflows/add-todo.md +89 -0
- package/dist/assets/templates/workflows/discuss-phase.md +85 -1
- package/dist/assets/templates/workflows/execute-phase.md +22 -2
- package/dist/assets/templates/workflows/execute-plan.md +166 -0
- package/dist/assets/templates/workflows/init-existing.md +116 -0
- package/dist/assets/templates/workflows/new-project.md +105 -1
- package/dist/assets/templates/workflows/plan-phase.md +3 -3
- package/dist/assets/templates/workflows/quick.md +2 -2
- package/dist/cli.cjs +1264 -882
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +97 -74
- package/dist/cli.js.map +1 -1
- package/dist/core/artefakte.d.ts +12 -0
- package/dist/core/artefakte.d.ts.map +1 -0
- package/dist/core/artefakte.js +136 -0
- package/dist/core/artefakte.js.map +1 -0
- package/dist/core/commands.d.ts +13 -13
- package/dist/core/commands.d.ts.map +1 -1
- package/dist/core/commands.js +44 -57
- package/dist/core/commands.js.map +1 -1
- package/dist/core/config.d.ts +4 -3
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +14 -18
- package/dist/core/config.js.map +1 -1
- package/dist/core/context-loader.d.ts +20 -0
- package/dist/core/context-loader.d.ts.map +1 -0
- package/dist/core/context-loader.js +154 -0
- package/dist/core/context-loader.js.map +1 -0
- package/dist/core/core.d.ts +8 -2
- package/dist/core/core.d.ts.map +1 -1
- package/dist/core/core.js +47 -11
- package/dist/core/core.js.map +1 -1
- package/dist/core/dashboard-launcher.d.ts +1 -1
- package/dist/core/dashboard-launcher.d.ts.map +1 -1
- package/dist/core/dashboard-launcher.js +18 -15
- package/dist/core/dashboard-launcher.js.map +1 -1
- package/dist/core/frontmatter.d.ts +5 -5
- package/dist/core/frontmatter.d.ts.map +1 -1
- package/dist/core/frontmatter.js +21 -26
- package/dist/core/frontmatter.js.map +1 -1
- package/dist/core/index.d.ts +8 -3
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +23 -3
- package/dist/core/index.js.map +1 -1
- package/dist/core/init.d.ts +14 -14
- package/dist/core/init.d.ts.map +1 -1
- package/dist/core/init.js +93 -154
- package/dist/core/init.js.map +1 -1
- package/dist/core/milestone.d.ts +3 -3
- package/dist/core/milestone.d.ts.map +1 -1
- package/dist/core/milestone.js +9 -9
- package/dist/core/milestone.js.map +1 -1
- package/dist/core/phase.d.ts +9 -9
- package/dist/core/phase.d.ts.map +1 -1
- package/dist/core/phase.js +64 -68
- package/dist/core/phase.js.map +1 -1
- package/dist/core/roadmap.d.ts +4 -3
- package/dist/core/roadmap.d.ts.map +1 -1
- package/dist/core/roadmap.js +46 -109
- package/dist/core/roadmap.js.map +1 -1
- package/dist/core/skills.d.ts +19 -0
- package/dist/core/skills.d.ts.map +1 -0
- package/dist/core/skills.js +145 -0
- package/dist/core/skills.js.map +1 -0
- package/dist/core/start.d.ts +15 -0
- package/dist/core/start.d.ts.map +1 -0
- package/dist/core/start.js +80 -0
- package/dist/core/start.js.map +1 -0
- package/dist/core/state.d.ts +13 -13
- package/dist/core/state.d.ts.map +1 -1
- package/dist/core/state.js +119 -126
- package/dist/core/state.js.map +1 -1
- package/dist/core/template.d.ts +3 -3
- package/dist/core/template.d.ts.map +1 -1
- package/dist/core/template.js +12 -14
- package/dist/core/template.js.map +1 -1
- package/dist/core/types.d.ts +14 -2
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +8 -0
- package/dist/core/types.js.map +1 -1
- package/dist/core/verify.d.ts +10 -9
- package/dist/core/verify.d.ts.map +1 -1
- package/dist/core/verify.js +38 -48
- package/dist/core/verify.js.map +1 -1
- package/dist/core-TFSlUjV1.cjs +4312 -0
- package/dist/core-TFSlUjV1.cjs.map +1 -0
- package/dist/install/adapters.d.ts +2 -11
- package/dist/install/adapters.d.ts.map +1 -1
- package/dist/install/adapters.js +16 -154
- package/dist/install/adapters.js.map +1 -1
- package/dist/install/copy.d.ts +1 -10
- package/dist/install/copy.d.ts.map +1 -1
- package/dist/install/copy.js +5 -125
- package/dist/install/copy.js.map +1 -1
- package/dist/install/hooks.d.ts +4 -5
- package/dist/install/hooks.d.ts.map +1 -1
- package/dist/install/hooks.js +46 -71
- package/dist/install/hooks.js.map +1 -1
- package/dist/install/index.js +163 -226
- package/dist/install/index.js.map +1 -1
- package/dist/install/manifest.d.ts +5 -2
- package/dist/install/manifest.d.ts.map +1 -1
- package/dist/install/manifest.js +20 -26
- package/dist/install/manifest.js.map +1 -1
- package/dist/install/patches.d.ts +1 -2
- package/dist/install/patches.d.ts.map +1 -1
- package/dist/install/patches.js +4 -16
- package/dist/install/patches.js.map +1 -1
- package/dist/install/shared.d.ts +24 -18
- package/dist/install/shared.d.ts.map +1 -1
- package/dist/install/shared.js +65 -35
- package/dist/install/shared.js.map +1 -1
- package/dist/install/uninstall.d.ts +2 -3
- package/dist/install/uninstall.d.ts.map +1 -1
- package/dist/install/uninstall.js +24 -82
- package/dist/install/uninstall.js.map +1 -1
- package/dist/install.cjs +321 -1230
- package/dist/install.cjs.map +1 -1
- package/dist/mcp-server.cjs +38 -14
- package/dist/mcp-server.cjs.map +1 -1
- package/dist/skills-BOSxYUzf.cjs +6812 -0
- package/dist/skills-BOSxYUzf.cjs.map +1 -0
- package/package.json +1 -1
- package/dist/adapters/codex.d.ts +0 -19
- package/dist/adapters/codex.d.ts.map +0 -1
- package/dist/adapters/codex.js +0 -94
- package/dist/adapters/codex.js.map +0 -1
- package/dist/adapters/gemini.d.ts +0 -19
- package/dist/adapters/gemini.d.ts.map +0 -1
- package/dist/adapters/gemini.js +0 -96
- package/dist/adapters/gemini.js.map +0 -1
- package/dist/adapters/opencode.d.ts +0 -17
- package/dist/adapters/opencode.d.ts.map +0 -1
- package/dist/adapters/opencode.js +0 -111
- package/dist/adapters/opencode.js.map +0 -1
- package/dist/adapters/transforms/content.d.ts +0 -39
- package/dist/adapters/transforms/content.d.ts.map +0 -1
- package/dist/adapters/transforms/content.js +0 -125
- package/dist/adapters/transforms/content.js.map +0 -1
- package/dist/adapters/transforms/frontmatter.d.ts +0 -42
- package/dist/adapters/transforms/frontmatter.d.ts.map +0 -1
- package/dist/adapters/transforms/frontmatter.js +0 -204
- package/dist/adapters/transforms/frontmatter.js.map +0 -1
- package/dist/adapters/transforms/tool-maps.d.ts +0 -20
- package/dist/adapters/transforms/tool-maps.d.ts.map +0 -1
- package/dist/adapters/transforms/tool-maps.js +0 -64
- package/dist/adapters/transforms/tool-maps.js.map +0 -1
- package/dist/assets/dashboard/client/assets/index-CxFKStBk.css +0 -32
package/dist/install.cjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
3
|
//#region \0rolldown/runtime.js
|
|
3
4
|
var __create = Object.create;
|
|
4
5
|
var __defProp = Object.defineProperty;
|
|
@@ -5646,7 +5647,6 @@ function ora(options) {
|
|
|
5646
5647
|
//#region ../../node_modules/@inquirer/core/dist/lib/key.js
|
|
5647
5648
|
const isUpKey = (key, keybindings = []) => key.name === "up" || keybindings.includes("vim") && key.name === "k" || keybindings.includes("emacs") && key.ctrl && key.name === "p";
|
|
5648
5649
|
const isDownKey = (key, keybindings = []) => key.name === "down" || keybindings.includes("vim") && key.name === "j" || keybindings.includes("emacs") && key.ctrl && key.name === "n";
|
|
5649
|
-
const isSpaceKey = (key) => key.name === "space";
|
|
5650
5650
|
const isBackspaceKey = (key) => key.name === "backspace";
|
|
5651
5651
|
const isTabKey = (key) => key.name === "tab";
|
|
5652
5652
|
const isNumberKey = (key) => "1234567890".includes(key.name);
|
|
@@ -7138,187 +7138,6 @@ var Separator = class {
|
|
|
7138
7138
|
}
|
|
7139
7139
|
};
|
|
7140
7140
|
|
|
7141
|
-
//#endregion
|
|
7142
|
-
//#region ../../node_modules/@inquirer/checkbox/dist/index.js
|
|
7143
|
-
const checkboxTheme = {
|
|
7144
|
-
icon: {
|
|
7145
|
-
checked: (0, node_util.styleText)("green", figures.circleFilled),
|
|
7146
|
-
unchecked: figures.circle,
|
|
7147
|
-
cursor: figures.pointer,
|
|
7148
|
-
disabledChecked: (0, node_util.styleText)("green", figures.circleDouble),
|
|
7149
|
-
disabledUnchecked: "-"
|
|
7150
|
-
},
|
|
7151
|
-
style: {
|
|
7152
|
-
disabled: (text) => (0, node_util.styleText)("dim", text),
|
|
7153
|
-
renderSelectedChoices: (selectedChoices) => selectedChoices.map((choice) => choice.short).join(", "),
|
|
7154
|
-
description: (text) => (0, node_util.styleText)("cyan", text),
|
|
7155
|
-
keysHelpTip: (keys) => keys.map(([key, action]) => `${(0, node_util.styleText)("bold", key)} ${(0, node_util.styleText)("dim", action)}`).join((0, node_util.styleText)("dim", " • "))
|
|
7156
|
-
},
|
|
7157
|
-
i18n: { disabledError: "This option is disabled and cannot be toggled." },
|
|
7158
|
-
keybindings: []
|
|
7159
|
-
};
|
|
7160
|
-
function isSelectable$1(item) {
|
|
7161
|
-
return !Separator.isSeparator(item) && !item.disabled;
|
|
7162
|
-
}
|
|
7163
|
-
function isNavigable$1(item) {
|
|
7164
|
-
return !Separator.isSeparator(item);
|
|
7165
|
-
}
|
|
7166
|
-
function isChecked(item) {
|
|
7167
|
-
return !Separator.isSeparator(item) && item.checked;
|
|
7168
|
-
}
|
|
7169
|
-
function toggle(item) {
|
|
7170
|
-
return isSelectable$1(item) ? {
|
|
7171
|
-
...item,
|
|
7172
|
-
checked: !item.checked
|
|
7173
|
-
} : item;
|
|
7174
|
-
}
|
|
7175
|
-
function check(checked) {
|
|
7176
|
-
return function(item) {
|
|
7177
|
-
return isSelectable$1(item) ? {
|
|
7178
|
-
...item,
|
|
7179
|
-
checked
|
|
7180
|
-
} : item;
|
|
7181
|
-
};
|
|
7182
|
-
}
|
|
7183
|
-
function normalizeChoices$1(choices) {
|
|
7184
|
-
return choices.map((choice) => {
|
|
7185
|
-
if (Separator.isSeparator(choice)) return choice;
|
|
7186
|
-
if (typeof choice === "string") return {
|
|
7187
|
-
value: choice,
|
|
7188
|
-
name: choice,
|
|
7189
|
-
short: choice,
|
|
7190
|
-
checkedName: choice,
|
|
7191
|
-
disabled: false,
|
|
7192
|
-
checked: false
|
|
7193
|
-
};
|
|
7194
|
-
const name = choice.name ?? String(choice.value);
|
|
7195
|
-
const normalizedChoice = {
|
|
7196
|
-
value: choice.value,
|
|
7197
|
-
name,
|
|
7198
|
-
short: choice.short ?? name,
|
|
7199
|
-
checkedName: choice.checkedName ?? name,
|
|
7200
|
-
disabled: choice.disabled ?? false,
|
|
7201
|
-
checked: choice.checked ?? false
|
|
7202
|
-
};
|
|
7203
|
-
if (choice.description) normalizedChoice.description = choice.description;
|
|
7204
|
-
return normalizedChoice;
|
|
7205
|
-
});
|
|
7206
|
-
}
|
|
7207
|
-
var dist_default$2 = createPrompt((config, done) => {
|
|
7208
|
-
const { pageSize = 7, loop = true, required, validate = () => true } = config;
|
|
7209
|
-
const shortcuts = {
|
|
7210
|
-
all: "a",
|
|
7211
|
-
invert: "i",
|
|
7212
|
-
...config.shortcuts
|
|
7213
|
-
};
|
|
7214
|
-
const theme = makeTheme(checkboxTheme, config.theme);
|
|
7215
|
-
const { keybindings } = theme;
|
|
7216
|
-
const [status, setStatus] = useState("idle");
|
|
7217
|
-
const prefix = usePrefix({
|
|
7218
|
-
status,
|
|
7219
|
-
theme
|
|
7220
|
-
});
|
|
7221
|
-
const [items, setItems] = useState(normalizeChoices$1(config.choices));
|
|
7222
|
-
const bounds = useMemo(() => {
|
|
7223
|
-
const first = items.findIndex(isNavigable$1);
|
|
7224
|
-
const last = items.findLastIndex(isNavigable$1);
|
|
7225
|
-
if (first === -1) throw new ValidationError("[checkbox prompt] No selectable choices. All choices are disabled.");
|
|
7226
|
-
return {
|
|
7227
|
-
first,
|
|
7228
|
-
last
|
|
7229
|
-
};
|
|
7230
|
-
}, [items]);
|
|
7231
|
-
const [active, setActive] = useState(bounds.first);
|
|
7232
|
-
const [errorMsg, setError] = useState();
|
|
7233
|
-
useKeypress(async (key) => {
|
|
7234
|
-
if (isEnterKey(key)) {
|
|
7235
|
-
const selection = items.filter(isChecked);
|
|
7236
|
-
const isValid = await validate([...selection]);
|
|
7237
|
-
if (required && !selection.length) setError("At least one choice must be selected");
|
|
7238
|
-
else if (isValid === true) {
|
|
7239
|
-
setStatus("done");
|
|
7240
|
-
done(selection.map((choice) => choice.value));
|
|
7241
|
-
} else setError(isValid || "You must select a valid value");
|
|
7242
|
-
} else if (isUpKey(key, keybindings) || isDownKey(key, keybindings)) {
|
|
7243
|
-
if (errorMsg) setError(void 0);
|
|
7244
|
-
if (loop || isUpKey(key, keybindings) && active !== bounds.first || isDownKey(key, keybindings) && active !== bounds.last) {
|
|
7245
|
-
const offset = isUpKey(key, keybindings) ? -1 : 1;
|
|
7246
|
-
let next = active;
|
|
7247
|
-
do
|
|
7248
|
-
next = (next + offset + items.length) % items.length;
|
|
7249
|
-
while (!isNavigable$1(items[next]));
|
|
7250
|
-
setActive(next);
|
|
7251
|
-
}
|
|
7252
|
-
} else if (isSpaceKey(key)) {
|
|
7253
|
-
const activeItem = items[active];
|
|
7254
|
-
if (activeItem && !Separator.isSeparator(activeItem)) if (activeItem.disabled) setError(theme.i18n.disabledError);
|
|
7255
|
-
else {
|
|
7256
|
-
setError(void 0);
|
|
7257
|
-
setItems(items.map((choice, i) => i === active ? toggle(choice) : choice));
|
|
7258
|
-
}
|
|
7259
|
-
} else if (key.name === shortcuts.all) {
|
|
7260
|
-
const selectAll = items.some((choice) => isSelectable$1(choice) && !choice.checked);
|
|
7261
|
-
setItems(items.map(check(selectAll)));
|
|
7262
|
-
} else if (key.name === shortcuts.invert) setItems(items.map(toggle));
|
|
7263
|
-
else if (isNumberKey(key)) {
|
|
7264
|
-
const selectedIndex = Number(key.name) - 1;
|
|
7265
|
-
let selectableIndex = -1;
|
|
7266
|
-
const position = items.findIndex((item) => {
|
|
7267
|
-
if (Separator.isSeparator(item)) return false;
|
|
7268
|
-
selectableIndex++;
|
|
7269
|
-
return selectableIndex === selectedIndex;
|
|
7270
|
-
});
|
|
7271
|
-
const selectedItem = items[position];
|
|
7272
|
-
if (selectedItem && isSelectable$1(selectedItem)) {
|
|
7273
|
-
setActive(position);
|
|
7274
|
-
setItems(items.map((choice, i) => i === position ? toggle(choice) : choice));
|
|
7275
|
-
}
|
|
7276
|
-
}
|
|
7277
|
-
});
|
|
7278
|
-
const message = theme.style.message(config.message, status);
|
|
7279
|
-
let description;
|
|
7280
|
-
const page = usePagination({
|
|
7281
|
-
items,
|
|
7282
|
-
active,
|
|
7283
|
-
renderItem({ item, isActive }) {
|
|
7284
|
-
if (Separator.isSeparator(item)) return ` ${item.separator}`;
|
|
7285
|
-
const cursor = isActive ? theme.icon.cursor : " ";
|
|
7286
|
-
if (item.disabled) {
|
|
7287
|
-
const disabledLabel = typeof item.disabled === "string" ? item.disabled : "(disabled)";
|
|
7288
|
-
const checkbox = item.checked ? theme.icon.disabledChecked : theme.icon.disabledUnchecked;
|
|
7289
|
-
return theme.style.disabled(`${cursor}${checkbox} ${item.name} ${disabledLabel}`);
|
|
7290
|
-
}
|
|
7291
|
-
if (isActive) description = item.description;
|
|
7292
|
-
const checkbox = item.checked ? theme.icon.checked : theme.icon.unchecked;
|
|
7293
|
-
const name = item.checked ? item.checkedName : item.name;
|
|
7294
|
-
return (isActive ? theme.style.highlight : (x) => x)(`${cursor}${checkbox} ${name}`);
|
|
7295
|
-
},
|
|
7296
|
-
pageSize,
|
|
7297
|
-
loop
|
|
7298
|
-
});
|
|
7299
|
-
if (status === "done") {
|
|
7300
|
-
const selection = items.filter(isChecked);
|
|
7301
|
-
return [
|
|
7302
|
-
prefix,
|
|
7303
|
-
message,
|
|
7304
|
-
theme.style.answer(theme.style.renderSelectedChoices(selection, items))
|
|
7305
|
-
].filter(Boolean).join(" ");
|
|
7306
|
-
}
|
|
7307
|
-
const keys = [["↑↓", "navigate"], ["space", "select"]];
|
|
7308
|
-
if (shortcuts.all) keys.push([shortcuts.all, "all"]);
|
|
7309
|
-
if (shortcuts.invert) keys.push([shortcuts.invert, "invert"]);
|
|
7310
|
-
keys.push(["⏎", "submit"]);
|
|
7311
|
-
const helpLine = theme.style.keysHelpTip(keys);
|
|
7312
|
-
return `${[
|
|
7313
|
-
[prefix, message].filter(Boolean).join(" "),
|
|
7314
|
-
page,
|
|
7315
|
-
" ",
|
|
7316
|
-
description ? theme.style.description(description) : "",
|
|
7317
|
-
errorMsg ? theme.style.error(errorMsg) : "",
|
|
7318
|
-
helpLine
|
|
7319
|
-
].filter(Boolean).join("\n").trimEnd()}${cursorHide}`;
|
|
7320
|
-
});
|
|
7321
|
-
|
|
7322
7141
|
//#endregion
|
|
7323
7142
|
//#region ../../node_modules/@inquirer/confirm/dist/index.js
|
|
7324
7143
|
function getBooleanValue(value, defaultValue) {
|
|
@@ -7701,25 +7520,6 @@ function expandTilde(filePath) {
|
|
|
7701
7520
|
return filePath;
|
|
7702
7521
|
}
|
|
7703
7522
|
/**
|
|
7704
|
-
* Extract YAML frontmatter and body from markdown content.
|
|
7705
|
-
* Returns null frontmatter if content doesn't start with ---.
|
|
7706
|
-
*/
|
|
7707
|
-
function extractFrontmatterAndBody(content) {
|
|
7708
|
-
if (!content.startsWith("---")) return {
|
|
7709
|
-
frontmatter: null,
|
|
7710
|
-
body: content
|
|
7711
|
-
};
|
|
7712
|
-
const endIndex = content.indexOf("---", 3);
|
|
7713
|
-
if (endIndex === -1) return {
|
|
7714
|
-
frontmatter: null,
|
|
7715
|
-
body: content
|
|
7716
|
-
};
|
|
7717
|
-
return {
|
|
7718
|
-
frontmatter: content.substring(3, endIndex).trim(),
|
|
7719
|
-
body: content.substring(endIndex + 3)
|
|
7720
|
-
};
|
|
7721
|
-
}
|
|
7722
|
-
/**
|
|
7723
7523
|
* Process Co-Authored-By lines based on attribution setting.
|
|
7724
7524
|
* @param content - File content to process
|
|
7725
7525
|
* @param attribution - null=remove, undefined=keep default, string=replace
|
|
@@ -7769,7 +7569,7 @@ function writeSettings(settingsPath, settings) {
|
|
|
7769
7569
|
* Get the global config directory for Claude Code.
|
|
7770
7570
|
* Priority: explicitDir > CLAUDE_CONFIG_DIR env > ~/.claude
|
|
7771
7571
|
*/
|
|
7772
|
-
function getGlobalDir$
|
|
7572
|
+
function getGlobalDir$1(explicitDir) {
|
|
7773
7573
|
if (explicitDir) return expandTilde(explicitDir);
|
|
7774
7574
|
if (process.env.CLAUDE_CONFIG_DIR) return expandTilde(process.env.CLAUDE_CONFIG_DIR);
|
|
7775
7575
|
return node_path.join(node_os.homedir(), ".claude");
|
|
@@ -7778,7 +7578,7 @@ function getGlobalDir$4(explicitDir) {
|
|
|
7778
7578
|
* Get the config directory path relative to home for hook templating.
|
|
7779
7579
|
* Used for path.join(homeDir, '<configDir>', ...) replacement in hooks.
|
|
7780
7580
|
*/
|
|
7781
|
-
function getConfigDirFromHome$
|
|
7581
|
+
function getConfigDirFromHome$1(isGlobal) {
|
|
7782
7582
|
return "'.claude'";
|
|
7783
7583
|
}
|
|
7784
7584
|
/**
|
|
@@ -7786,7 +7586,7 @@ function getConfigDirFromHome$4(isGlobal) {
|
|
|
7786
7586
|
* For Claude, this is path replacement only — no frontmatter conversion needed.
|
|
7787
7587
|
* Replaces ~/.claude/ and ./.claude/ references with the actual install path prefix.
|
|
7788
7588
|
*/
|
|
7789
|
-
function transformContent
|
|
7589
|
+
function transformContent(content, pathPrefix) {
|
|
7790
7590
|
const globalClaudeRegex = /~\/\.claude\//g;
|
|
7791
7591
|
const localClaudeRegex = /\.\/\.claude\//g;
|
|
7792
7592
|
let result = content.replace(globalClaudeRegex, pathPrefix);
|
|
@@ -7800,525 +7600,44 @@ function transformContent$3(content, pathPrefix) {
|
|
|
7800
7600
|
const claudeAdapter = {
|
|
7801
7601
|
runtime: "claude",
|
|
7802
7602
|
dirName: ".claude",
|
|
7803
|
-
getGlobalDir: getGlobalDir$4,
|
|
7804
|
-
getConfigDirFromHome: getConfigDirFromHome$4,
|
|
7805
|
-
transformContent: transformContent$3,
|
|
7806
|
-
commandStructure: "nested"
|
|
7807
|
-
};
|
|
7808
|
-
|
|
7809
|
-
//#endregion
|
|
7810
|
-
//#region src/adapters/transforms/tool-maps.ts
|
|
7811
|
-
/**
|
|
7812
|
-
* @maxsim/adapters — Tool name mappings per runtime
|
|
7813
|
-
*
|
|
7814
|
-
* Ported from bin/install.js lines ~327-390
|
|
7815
|
-
*/
|
|
7816
|
-
/** Tool name mapping from Claude Code to OpenCode */
|
|
7817
|
-
const claudeToOpencodeTools = {
|
|
7818
|
-
AskUserQuestion: "question",
|
|
7819
|
-
SlashCommand: "skill",
|
|
7820
|
-
TodoWrite: "todowrite",
|
|
7821
|
-
WebFetch: "webfetch",
|
|
7822
|
-
WebSearch: "websearch"
|
|
7823
|
-
};
|
|
7824
|
-
/** Tool name mapping from Claude Code to Gemini CLI */
|
|
7825
|
-
const claudeToGeminiTools = {
|
|
7826
|
-
Read: "read_file",
|
|
7827
|
-
Write: "write_file",
|
|
7828
|
-
Edit: "replace",
|
|
7829
|
-
Bash: "run_shell_command",
|
|
7830
|
-
Glob: "glob",
|
|
7831
|
-
Grep: "search_file_content",
|
|
7832
|
-
WebSearch: "google_web_search",
|
|
7833
|
-
WebFetch: "web_fetch",
|
|
7834
|
-
TodoWrite: "write_todos",
|
|
7835
|
-
AskUserQuestion: "ask_user"
|
|
7836
|
-
};
|
|
7837
|
-
/**
|
|
7838
|
-
* Convert a Claude Code tool name to OpenCode format.
|
|
7839
|
-
* - Applies special mappings (AskUserQuestion -> question, etc.)
|
|
7840
|
-
* - Converts to lowercase (except MCP tools which keep their format)
|
|
7841
|
-
*/
|
|
7842
|
-
function convertToolName(claudeTool) {
|
|
7843
|
-
if (claudeToOpencodeTools[claudeTool]) return claudeToOpencodeTools[claudeTool];
|
|
7844
|
-
if (claudeTool.startsWith("mcp__")) return claudeTool;
|
|
7845
|
-
return claudeTool.toLowerCase();
|
|
7846
|
-
}
|
|
7847
|
-
/**
|
|
7848
|
-
* Convert a Claude Code tool name to Gemini CLI format.
|
|
7849
|
-
* - Applies Claude->Gemini mapping (Read->read_file, Bash->run_shell_command, etc.)
|
|
7850
|
-
* - Filters out MCP tools (mcp__*) -- auto-discovered at runtime in Gemini
|
|
7851
|
-
* - Filters out Task -- agents are auto-registered as tools in Gemini
|
|
7852
|
-
* @returns Gemini tool name, or null if tool should be excluded
|
|
7853
|
-
*/
|
|
7854
|
-
function convertGeminiToolName(claudeTool) {
|
|
7855
|
-
if (claudeTool.startsWith("mcp__")) return null;
|
|
7856
|
-
if (claudeTool === "Task") return null;
|
|
7857
|
-
if (claudeToGeminiTools[claudeTool]) return claudeToGeminiTools[claudeTool];
|
|
7858
|
-
return claudeTool.toLowerCase();
|
|
7859
|
-
}
|
|
7860
|
-
|
|
7861
|
-
//#endregion
|
|
7862
|
-
//#region src/adapters/transforms/content.ts
|
|
7863
|
-
/**
|
|
7864
|
-
* @maxsim/adapters — Content transformation utilities
|
|
7865
|
-
*
|
|
7866
|
-
* Ported from bin/install.js lines ~423-564
|
|
7867
|
-
*/
|
|
7868
|
-
/**
|
|
7869
|
-
* Convert /maxsim:command-name to $maxsim-command-name for Codex skill mentions.
|
|
7870
|
-
* Ported from install.js line ~423
|
|
7871
|
-
*/
|
|
7872
|
-
function convertSlashCommandsToCodexSkillMentions(content) {
|
|
7873
|
-
let converted = content.replace(/\/maxsim:([a-z0-9-]+)/gi, (_, commandName) => {
|
|
7874
|
-
return `$maxsim-${String(commandName).toLowerCase()}`;
|
|
7875
|
-
});
|
|
7876
|
-
converted = converted.replace(/\/maxsim-help\b/g, "$maxsim-help");
|
|
7877
|
-
return converted;
|
|
7878
|
-
}
|
|
7879
|
-
/**
|
|
7880
|
-
* Convert Claude markdown to Codex markdown format.
|
|
7881
|
-
* Replaces slash commands and $ARGUMENTS placeholder.
|
|
7882
|
-
* Ported from install.js line ~431
|
|
7883
|
-
*/
|
|
7884
|
-
function convertClaudeToCodexMarkdown(content) {
|
|
7885
|
-
let converted = convertSlashCommandsToCodexSkillMentions(content);
|
|
7886
|
-
converted = converted.replace(/\$ARGUMENTS\b/g, "{{MAXSIM_ARGS}}");
|
|
7887
|
-
return converted;
|
|
7888
|
-
}
|
|
7889
|
-
/**
|
|
7890
|
-
* Strip HTML <sub> tags for Gemini CLI output.
|
|
7891
|
-
* Terminals don't support subscript -- converts <sub>text</sub> to italic *(text)*.
|
|
7892
|
-
* Ported from install.js line ~474
|
|
7893
|
-
*/
|
|
7894
|
-
function stripSubTags(content) {
|
|
7895
|
-
return content.replace(/<sub>(.*?)<\/sub>/g, "*($1)*");
|
|
7896
|
-
}
|
|
7897
|
-
/**
|
|
7898
|
-
* Convert Claude Code agent frontmatter to Gemini CLI format.
|
|
7899
|
-
* - tools: must be a YAML array (not comma-separated string)
|
|
7900
|
-
* - tool names: must use Gemini built-in names (read_file, not Read)
|
|
7901
|
-
* - color: must be removed (causes validation error)
|
|
7902
|
-
* - mcp__* tools: must be excluded (auto-discovered at runtime)
|
|
7903
|
-
* - ${VAR} patterns: escaped to $VAR for Gemini template compatibility
|
|
7904
|
-
*
|
|
7905
|
-
* Ported from install.js line ~487
|
|
7906
|
-
*/
|
|
7907
|
-
function convertClaudeToGeminiAgent(content) {
|
|
7908
|
-
if (!content.startsWith("---")) return content;
|
|
7909
|
-
const endIndex = content.indexOf("---", 3);
|
|
7910
|
-
if (endIndex === -1) return content;
|
|
7911
|
-
const frontmatter = content.substring(3, endIndex).trim();
|
|
7912
|
-
const body = content.substring(endIndex + 3);
|
|
7913
|
-
const lines = frontmatter.split("\n");
|
|
7914
|
-
const newLines = [];
|
|
7915
|
-
let inAllowedTools = false;
|
|
7916
|
-
const tools = [];
|
|
7917
|
-
for (const line of lines) {
|
|
7918
|
-
const trimmed = line.trim();
|
|
7919
|
-
if (trimmed.startsWith("allowed-tools:")) {
|
|
7920
|
-
inAllowedTools = true;
|
|
7921
|
-
continue;
|
|
7922
|
-
}
|
|
7923
|
-
if (trimmed.startsWith("tools:")) {
|
|
7924
|
-
const toolsValue = trimmed.substring(6).trim();
|
|
7925
|
-
if (toolsValue) {
|
|
7926
|
-
const parsed = toolsValue.split(",").map((t) => t.trim()).filter((t) => t);
|
|
7927
|
-
for (const t of parsed) {
|
|
7928
|
-
const mapped = convertGeminiToolName(t);
|
|
7929
|
-
if (mapped) tools.push(mapped);
|
|
7930
|
-
}
|
|
7931
|
-
} else inAllowedTools = true;
|
|
7932
|
-
continue;
|
|
7933
|
-
}
|
|
7934
|
-
if (trimmed.startsWith("color:")) continue;
|
|
7935
|
-
if (inAllowedTools) {
|
|
7936
|
-
if (trimmed.startsWith("- ")) {
|
|
7937
|
-
const mapped = convertGeminiToolName(trimmed.substring(2).trim());
|
|
7938
|
-
if (mapped) tools.push(mapped);
|
|
7939
|
-
continue;
|
|
7940
|
-
} else if (trimmed && !trimmed.startsWith("-")) inAllowedTools = false;
|
|
7941
|
-
}
|
|
7942
|
-
if (!inAllowedTools) newLines.push(line);
|
|
7943
|
-
}
|
|
7944
|
-
if (tools.length > 0) {
|
|
7945
|
-
newLines.push("tools:");
|
|
7946
|
-
for (const tool of tools) newLines.push(` - ${tool}`);
|
|
7947
|
-
}
|
|
7948
|
-
return `---\n${newLines.join("\n").trim()}\n---${stripSubTags(body.replace(/\$\{(\w+)\}/g, "$$$1"))}`;
|
|
7949
|
-
}
|
|
7950
|
-
/**
|
|
7951
|
-
* Replace path references in markdown content for a target runtime.
|
|
7952
|
-
* Replaces ~/.claude/ with pathPrefix and ./.claude/ with ./dirName/.
|
|
7953
|
-
*/
|
|
7954
|
-
function replacePathReferences(content, pathPrefix, dirName) {
|
|
7955
|
-
const globalClaudeRegex = /~\/\.claude\//g;
|
|
7956
|
-
const localClaudeRegex = /\.\/\.claude\//g;
|
|
7957
|
-
let result = content.replace(globalClaudeRegex, pathPrefix);
|
|
7958
|
-
result = result.replace(localClaudeRegex, `./${dirName}/`);
|
|
7959
|
-
return result;
|
|
7960
|
-
}
|
|
7961
|
-
|
|
7962
|
-
//#endregion
|
|
7963
|
-
//#region src/adapters/transforms/frontmatter.ts
|
|
7964
|
-
/**
|
|
7965
|
-
* @maxsim/adapters — Frontmatter conversion functions for opencode, gemini, codex
|
|
7966
|
-
*
|
|
7967
|
-
* Ported from bin/install.js lines ~308-711
|
|
7968
|
-
*/
|
|
7969
|
-
/** Color name to hex mapping for opencode compatibility */
|
|
7970
|
-
const colorNameToHex = {
|
|
7971
|
-
cyan: "#00FFFF",
|
|
7972
|
-
red: "#FF0000",
|
|
7973
|
-
green: "#00FF00",
|
|
7974
|
-
blue: "#0000FF",
|
|
7975
|
-
yellow: "#FFFF00",
|
|
7976
|
-
magenta: "#FF00FF",
|
|
7977
|
-
orange: "#FFA500",
|
|
7978
|
-
purple: "#800080",
|
|
7979
|
-
pink: "#FFC0CB",
|
|
7980
|
-
white: "#FFFFFF",
|
|
7981
|
-
black: "#000000",
|
|
7982
|
-
gray: "#808080",
|
|
7983
|
-
grey: "#808080"
|
|
7984
|
-
};
|
|
7985
|
-
/** Collapse whitespace to single line */
|
|
7986
|
-
function toSingleLine(value) {
|
|
7987
|
-
return value.replace(/\s+/g, " ").trim();
|
|
7988
|
-
}
|
|
7989
|
-
/** Quote a value for YAML using JSON.stringify */
|
|
7990
|
-
function yamlQuote(value) {
|
|
7991
|
-
return JSON.stringify(value);
|
|
7992
|
-
}
|
|
7993
|
-
/** Extract a single-line field value from YAML frontmatter text */
|
|
7994
|
-
function extractFrontmatterField(frontmatter, fieldName) {
|
|
7995
|
-
const regex = new RegExp(`^${fieldName}:\\s*(.+)$`, "m");
|
|
7996
|
-
const match = frontmatter.match(regex);
|
|
7997
|
-
if (!match) return null;
|
|
7998
|
-
return match[1].trim().replace(/^['"]|['"]$/g, "");
|
|
7999
|
-
}
|
|
8000
|
-
/**
|
|
8001
|
-
* Convert Claude Code frontmatter to OpenCode format.
|
|
8002
|
-
* - Converts 'allowed-tools:' array to 'tools:' object with tool: true entries
|
|
8003
|
-
* - Converts color names to hex
|
|
8004
|
-
* - Removes name: field (opencode uses filename)
|
|
8005
|
-
* - Replaces tool name references in body content
|
|
8006
|
-
* - Replaces /maxsim: with /maxsim- (flat command structure)
|
|
8007
|
-
* - Replaces ~/.claude with ~/.config/opencode
|
|
8008
|
-
* - Replaces subagent_type="general-purpose" with "general"
|
|
8009
|
-
*
|
|
8010
|
-
* Ported from install.js line ~566
|
|
8011
|
-
*/
|
|
8012
|
-
function convertClaudeToOpencodeFrontmatter(content) {
|
|
8013
|
-
let convertedContent = content;
|
|
8014
|
-
convertedContent = convertedContent.replace(/\bAskUserQuestion\b/g, "question");
|
|
8015
|
-
convertedContent = convertedContent.replace(/\bSlashCommand\b/g, "skill");
|
|
8016
|
-
convertedContent = convertedContent.replace(/\bTodoWrite\b/g, "todowrite");
|
|
8017
|
-
convertedContent = convertedContent.replace(/\/maxsim:/g, "/maxsim-");
|
|
8018
|
-
convertedContent = convertedContent.replace(/~\/\.claude\b/g, "~/.config/opencode");
|
|
8019
|
-
convertedContent = convertedContent.replace(/subagent_type="general-purpose"/g, "subagent_type=\"general\"");
|
|
8020
|
-
if (!convertedContent.startsWith("---")) return convertedContent;
|
|
8021
|
-
const endIndex = convertedContent.indexOf("---", 3);
|
|
8022
|
-
if (endIndex === -1) return convertedContent;
|
|
8023
|
-
const frontmatter = convertedContent.substring(3, endIndex).trim();
|
|
8024
|
-
const body = convertedContent.substring(endIndex + 3);
|
|
8025
|
-
const lines = frontmatter.split("\n");
|
|
8026
|
-
const newLines = [];
|
|
8027
|
-
let inAllowedTools = false;
|
|
8028
|
-
const allowedTools = [];
|
|
8029
|
-
for (const line of lines) {
|
|
8030
|
-
const trimmed = line.trim();
|
|
8031
|
-
if (trimmed.startsWith("allowed-tools:")) {
|
|
8032
|
-
inAllowedTools = true;
|
|
8033
|
-
continue;
|
|
8034
|
-
}
|
|
8035
|
-
if (trimmed.startsWith("tools:")) {
|
|
8036
|
-
const toolsValue = trimmed.substring(6).trim();
|
|
8037
|
-
if (toolsValue) {
|
|
8038
|
-
const tools = toolsValue.split(",").map((t) => t.trim()).filter((t) => t);
|
|
8039
|
-
allowedTools.push(...tools);
|
|
8040
|
-
}
|
|
8041
|
-
continue;
|
|
8042
|
-
}
|
|
8043
|
-
if (trimmed.startsWith("name:")) continue;
|
|
8044
|
-
if (trimmed.startsWith("color:")) {
|
|
8045
|
-
const colorValue = trimmed.substring(6).trim().toLowerCase();
|
|
8046
|
-
const hexColor = colorNameToHex[colorValue];
|
|
8047
|
-
if (hexColor) newLines.push(`color: "${hexColor}"`);
|
|
8048
|
-
else if (colorValue.startsWith("#")) {
|
|
8049
|
-
if (/^#[0-9a-f]{3}$|^#[0-9a-f]{6}$/i.test(colorValue)) newLines.push(line);
|
|
8050
|
-
}
|
|
8051
|
-
continue;
|
|
8052
|
-
}
|
|
8053
|
-
if (inAllowedTools) {
|
|
8054
|
-
if (trimmed.startsWith("- ")) {
|
|
8055
|
-
allowedTools.push(trimmed.substring(2).trim());
|
|
8056
|
-
continue;
|
|
8057
|
-
} else if (trimmed && !trimmed.startsWith("-")) inAllowedTools = false;
|
|
8058
|
-
}
|
|
8059
|
-
if (!inAllowedTools) newLines.push(line);
|
|
8060
|
-
}
|
|
8061
|
-
if (allowedTools.length > 0) {
|
|
8062
|
-
newLines.push("tools:");
|
|
8063
|
-
for (const tool of allowedTools) newLines.push(` ${convertToolName(tool)}: true`);
|
|
8064
|
-
}
|
|
8065
|
-
return `---\n${newLines.join("\n").trim()}\n---${body}`;
|
|
8066
|
-
}
|
|
8067
|
-
/**
|
|
8068
|
-
* Convert Claude Code markdown command to Gemini TOML format.
|
|
8069
|
-
* Ported from install.js line ~677
|
|
8070
|
-
*/
|
|
8071
|
-
function convertClaudeToGeminiToml(content) {
|
|
8072
|
-
if (!content.startsWith("---")) return `prompt = ${JSON.stringify(content)}\n`;
|
|
8073
|
-
const endIndex = content.indexOf("---", 3);
|
|
8074
|
-
if (endIndex === -1) return `prompt = ${JSON.stringify(content)}\n`;
|
|
8075
|
-
const frontmatter = content.substring(3, endIndex).trim();
|
|
8076
|
-
const body = content.substring(endIndex + 3).trim();
|
|
8077
|
-
let description = "";
|
|
8078
|
-
const lines = frontmatter.split("\n");
|
|
8079
|
-
for (const line of lines) {
|
|
8080
|
-
const trimmed = line.trim();
|
|
8081
|
-
if (trimmed.startsWith("description:")) {
|
|
8082
|
-
description = trimmed.substring(12).trim();
|
|
8083
|
-
break;
|
|
8084
|
-
}
|
|
8085
|
-
}
|
|
8086
|
-
let toml = "";
|
|
8087
|
-
if (description) toml += `description = ${JSON.stringify(description)}\n`;
|
|
8088
|
-
toml += `prompt = ${JSON.stringify(body)}\n`;
|
|
8089
|
-
return toml;
|
|
8090
|
-
}
|
|
8091
|
-
/**
|
|
8092
|
-
* Convert Claude command to Codex skill format with adapter header.
|
|
8093
|
-
* Ported from install.js line ~452
|
|
8094
|
-
*/
|
|
8095
|
-
function convertClaudeCommandToCodexSkill(content, skillName) {
|
|
8096
|
-
const { frontmatter, body } = extractFrontmatterAndBody(convertClaudeToCodexMarkdown(content));
|
|
8097
|
-
let description = `Run MAXSIM workflow ${skillName}.`;
|
|
8098
|
-
if (frontmatter) {
|
|
8099
|
-
const maybeDescription = extractFrontmatterField(frontmatter, "description");
|
|
8100
|
-
if (maybeDescription) description = maybeDescription;
|
|
8101
|
-
}
|
|
8102
|
-
description = toSingleLine(description);
|
|
8103
|
-
const shortDescription = description.length > 180 ? `${description.slice(0, 177)}...` : description;
|
|
8104
|
-
const adapter = getCodexSkillAdapterHeader(skillName);
|
|
8105
|
-
return `---\nname: ${yamlQuote(skillName)}\ndescription: ${yamlQuote(description)}\nmetadata:\n short-description: ${yamlQuote(shortDescription)}\n---\n\n${adapter}\n\n${body.trimStart()}`;
|
|
8106
|
-
}
|
|
8107
|
-
/**
|
|
8108
|
-
* Generate the Codex skill adapter header block.
|
|
8109
|
-
* Ported from install.js line ~437
|
|
8110
|
-
*/
|
|
8111
|
-
function getCodexSkillAdapterHeader(skillName) {
|
|
8112
|
-
const invocation = `$${skillName}`;
|
|
8113
|
-
return `<codex_skill_adapter>
|
|
8114
|
-
Codex skills-first mode:
|
|
8115
|
-
- This skill is invoked by mentioning \`${invocation}\`.
|
|
8116
|
-
- Treat all user text after \`${invocation}\` as \`{{MAXSIM_ARGS}}\`.
|
|
8117
|
-
- If no arguments are present, treat \`{{MAXSIM_ARGS}}\` as empty.
|
|
8118
|
-
|
|
8119
|
-
Legacy orchestration compatibility:
|
|
8120
|
-
- Any \`Task(...)\` pattern in referenced workflow docs is legacy syntax.
|
|
8121
|
-
- Implement equivalent behavior with Codex collaboration tools: \`spawn_agent\`, \`wait\`, \`send_input\`, and \`close_agent\`.
|
|
8122
|
-
- Treat legacy \`subagent_type\` names as role hints in the spawned message.
|
|
8123
|
-
</codex_skill_adapter>`;
|
|
8124
|
-
}
|
|
8125
|
-
|
|
8126
|
-
//#endregion
|
|
8127
|
-
//#region src/adapters/opencode.ts
|
|
8128
|
-
/**
|
|
8129
|
-
* @maxsim/adapters — OpenCode adapter
|
|
8130
|
-
*
|
|
8131
|
-
* Ports the OpenCode-specific logic from bin/install.js:
|
|
8132
|
-
* - getOpencodeGlobalDir() (lines 79-97)
|
|
8133
|
-
* - getGlobalDir('opencode', ...) (lines 104-111)
|
|
8134
|
-
* - getDirName('opencode') (line 46)
|
|
8135
|
-
* - getConfigDirFromHome('opencode', isGlobal) (lines 58-68)
|
|
8136
|
-
* - convertClaudeToOpencodeFrontmatter + path replacement
|
|
8137
|
-
*/
|
|
8138
|
-
/**
|
|
8139
|
-
* Get the global config directory for OpenCode.
|
|
8140
|
-
* OpenCode follows XDG Base Directory spec and uses ~/.config/opencode/.
|
|
8141
|
-
* Priority: OPENCODE_CONFIG_DIR > dirname(OPENCODE_CONFIG) > XDG_CONFIG_HOME/opencode > ~/.config/opencode
|
|
8142
|
-
*/
|
|
8143
|
-
function getOpencodeGlobalDir$1() {
|
|
8144
|
-
if (process.env.OPENCODE_CONFIG_DIR) return expandTilde(process.env.OPENCODE_CONFIG_DIR);
|
|
8145
|
-
if (process.env.OPENCODE_CONFIG) return node_path.dirname(expandTilde(process.env.OPENCODE_CONFIG));
|
|
8146
|
-
if (process.env.XDG_CONFIG_HOME) return node_path.join(expandTilde(process.env.XDG_CONFIG_HOME), "opencode");
|
|
8147
|
-
return node_path.join(node_os.homedir(), ".config", "opencode");
|
|
8148
|
-
}
|
|
8149
|
-
/**
|
|
8150
|
-
* Get the global config directory for OpenCode.
|
|
8151
|
-
* Priority: explicitDir > env vars (via getOpencodeGlobalDir)
|
|
8152
|
-
*/
|
|
8153
|
-
function getGlobalDir$3(explicitDir) {
|
|
8154
|
-
if (explicitDir) return expandTilde(explicitDir);
|
|
8155
|
-
return getOpencodeGlobalDir$1();
|
|
8156
|
-
}
|
|
8157
|
-
/**
|
|
8158
|
-
* Get the config directory path relative to home for hook templating.
|
|
8159
|
-
*/
|
|
8160
|
-
function getConfigDirFromHome$3(isGlobal) {
|
|
8161
|
-
if (!isGlobal) return "'.opencode'";
|
|
8162
|
-
return "'.config', 'opencode'";
|
|
8163
|
-
}
|
|
8164
|
-
/**
|
|
8165
|
-
* Transform markdown content for OpenCode installation.
|
|
8166
|
-
* Applies frontmatter conversion and path replacement.
|
|
8167
|
-
*/
|
|
8168
|
-
function transformContent$2(content, pathPrefix) {
|
|
8169
|
-
let result = replacePathReferences(content, pathPrefix, ".opencode");
|
|
8170
|
-
result = result.replace(/~\/\.opencode\//g, pathPrefix);
|
|
8171
|
-
result = convertClaudeToOpencodeFrontmatter(result);
|
|
8172
|
-
return result;
|
|
8173
|
-
}
|
|
8174
|
-
/**
|
|
8175
|
-
* OpenCode adapter configuration.
|
|
8176
|
-
* OpenCode uses flat command structure (command/maxsim-*.md).
|
|
8177
|
-
*/
|
|
8178
|
-
const opencodeAdapter = {
|
|
8179
|
-
runtime: "opencode",
|
|
8180
|
-
dirName: ".opencode",
|
|
8181
|
-
getGlobalDir: getGlobalDir$3,
|
|
8182
|
-
getConfigDirFromHome: getConfigDirFromHome$3,
|
|
8183
|
-
transformContent: transformContent$2,
|
|
8184
|
-
commandStructure: "flat"
|
|
8185
|
-
};
|
|
8186
|
-
|
|
8187
|
-
//#endregion
|
|
8188
|
-
//#region src/adapters/gemini.ts
|
|
8189
|
-
/**
|
|
8190
|
-
* @maxsim/adapters — Gemini adapter
|
|
8191
|
-
*
|
|
8192
|
-
* Ports the Gemini-specific logic from bin/install.js:
|
|
8193
|
-
* - getGlobalDir('gemini', ...) (lines 113-122)
|
|
8194
|
-
* - getDirName('gemini') (line 47)
|
|
8195
|
-
* - getConfigDirFromHome('gemini', isGlobal) (line 69)
|
|
8196
|
-
* - convertClaudeToGeminiToml + convertClaudeToGeminiAgent + stripSubTags
|
|
8197
|
-
*/
|
|
8198
|
-
/**
|
|
8199
|
-
* Get the global config directory for Gemini.
|
|
8200
|
-
* Priority: explicitDir > GEMINI_CONFIG_DIR env > ~/.gemini
|
|
8201
|
-
*/
|
|
8202
|
-
function getGlobalDir$2(explicitDir) {
|
|
8203
|
-
if (explicitDir) return expandTilde(explicitDir);
|
|
8204
|
-
if (process.env.GEMINI_CONFIG_DIR) return expandTilde(process.env.GEMINI_CONFIG_DIR);
|
|
8205
|
-
return node_path.join(node_os.homedir(), ".gemini");
|
|
8206
|
-
}
|
|
8207
|
-
/**
|
|
8208
|
-
* Get the config directory path relative to home for hook templating.
|
|
8209
|
-
*/
|
|
8210
|
-
function getConfigDirFromHome$2(_isGlobal) {
|
|
8211
|
-
return "'.gemini'";
|
|
8212
|
-
}
|
|
8213
|
-
/**
|
|
8214
|
-
* Transform markdown content for Gemini installation.
|
|
8215
|
-
* Applies TOML conversion for commands, agent conversion for agents,
|
|
8216
|
-
* stripSubTags, and path replacement.
|
|
8217
|
-
*/
|
|
8218
|
-
function transformContent$1(content, pathPrefix) {
|
|
8219
|
-
let result = replacePathReferences(content, pathPrefix, ".gemini");
|
|
8220
|
-
result = stripSubTags(result);
|
|
8221
|
-
result = convertClaudeToGeminiToml(result);
|
|
8222
|
-
return result;
|
|
8223
|
-
}
|
|
8224
|
-
/**
|
|
8225
|
-
* Gemini adapter configuration.
|
|
8226
|
-
* Gemini uses nested command structure (commands/maxsim/*.toml).
|
|
8227
|
-
*/
|
|
8228
|
-
const geminiAdapter = {
|
|
8229
|
-
runtime: "gemini",
|
|
8230
|
-
dirName: ".gemini",
|
|
8231
|
-
getGlobalDir: getGlobalDir$2,
|
|
8232
|
-
getConfigDirFromHome: getConfigDirFromHome$2,
|
|
8233
|
-
transformContent: transformContent$1,
|
|
8234
|
-
commandStructure: "nested"
|
|
8235
|
-
};
|
|
8236
|
-
|
|
8237
|
-
//#endregion
|
|
8238
|
-
//#region src/adapters/codex.ts
|
|
8239
|
-
/**
|
|
8240
|
-
* @maxsim/adapters — Codex adapter
|
|
8241
|
-
*
|
|
8242
|
-
* Ports the Codex-specific logic from bin/install.js:
|
|
8243
|
-
* - getGlobalDir('codex', ...) (lines 124-133)
|
|
8244
|
-
* - getDirName('codex') (line 48)
|
|
8245
|
-
* - getConfigDirFromHome('codex', isGlobal) (line 70)
|
|
8246
|
-
* - convertClaudeCommandToCodexSkill + convertClaudeToCodexMarkdown
|
|
8247
|
-
*/
|
|
8248
|
-
/**
|
|
8249
|
-
* Get the global config directory for Codex.
|
|
8250
|
-
* Priority: explicitDir > CODEX_HOME env > ~/.codex
|
|
8251
|
-
*/
|
|
8252
|
-
function getGlobalDir$1(explicitDir) {
|
|
8253
|
-
if (explicitDir) return expandTilde(explicitDir);
|
|
8254
|
-
if (process.env.CODEX_HOME) return expandTilde(process.env.CODEX_HOME);
|
|
8255
|
-
return node_path.join(node_os.homedir(), ".codex");
|
|
8256
|
-
}
|
|
8257
|
-
/**
|
|
8258
|
-
* Get the config directory path relative to home for hook templating.
|
|
8259
|
-
*/
|
|
8260
|
-
function getConfigDirFromHome$1(_isGlobal) {
|
|
8261
|
-
return "'.codex'";
|
|
8262
|
-
}
|
|
8263
|
-
/**
|
|
8264
|
-
* Transform markdown content for Codex installation.
|
|
8265
|
-
* Applies Codex markdown conversion and path replacement.
|
|
8266
|
-
*/
|
|
8267
|
-
function transformContent(content, pathPrefix) {
|
|
8268
|
-
let result = replacePathReferences(content, pathPrefix, ".codex");
|
|
8269
|
-
result = result.replace(/~\/\.codex\//g, pathPrefix);
|
|
8270
|
-
result = convertClaudeCommandToCodexSkill(result);
|
|
8271
|
-
return result;
|
|
8272
|
-
}
|
|
8273
|
-
/**
|
|
8274
|
-
* Codex adapter configuration.
|
|
8275
|
-
* Codex uses skill-based command structure (skills/maxsim-star/SKILL.md).
|
|
8276
|
-
*/
|
|
8277
|
-
const codexAdapter = {
|
|
8278
|
-
runtime: "codex",
|
|
8279
|
-
dirName: ".codex",
|
|
8280
7603
|
getGlobalDir: getGlobalDir$1,
|
|
8281
7604
|
getConfigDirFromHome: getConfigDirFromHome$1,
|
|
8282
7605
|
transformContent,
|
|
8283
|
-
commandStructure: "
|
|
7606
|
+
commandStructure: "nested"
|
|
8284
7607
|
};
|
|
8285
7608
|
|
|
8286
7609
|
//#endregion
|
|
8287
7610
|
//#region src/install/shared.ts
|
|
8288
7611
|
const pkg = JSON.parse(node_fs.readFileSync(node_path.resolve(__dirname, "..", "package.json"), "utf-8"));
|
|
8289
7612
|
const templatesRoot = node_path.resolve(__dirname, "assets", "templates");
|
|
7613
|
+
const builtInSkills = [
|
|
7614
|
+
"tdd",
|
|
7615
|
+
"systematic-debugging",
|
|
7616
|
+
"verification-before-completion",
|
|
7617
|
+
"simplify",
|
|
7618
|
+
"code-review",
|
|
7619
|
+
"memory-management",
|
|
7620
|
+
"using-maxsim",
|
|
7621
|
+
"brainstorming",
|
|
7622
|
+
"roadmap-writing"
|
|
7623
|
+
];
|
|
8290
7624
|
/**
|
|
8291
|
-
*
|
|
8292
|
-
*/
|
|
8293
|
-
const adapterMap = {
|
|
8294
|
-
claude: claudeAdapter,
|
|
8295
|
-
opencode: opencodeAdapter,
|
|
8296
|
-
gemini: geminiAdapter,
|
|
8297
|
-
codex: codexAdapter
|
|
8298
|
-
};
|
|
8299
|
-
/**
|
|
8300
|
-
* Get adapter for a runtime
|
|
8301
|
-
*/
|
|
8302
|
-
function getAdapter(runtime) {
|
|
8303
|
-
return adapterMap[runtime];
|
|
8304
|
-
}
|
|
8305
|
-
/**
|
|
8306
|
-
* Get the global config directory for a runtime, using adapter
|
|
7625
|
+
* Get the global config directory, using the Claude adapter
|
|
8307
7626
|
*/
|
|
8308
|
-
function getGlobalDir(
|
|
8309
|
-
return
|
|
7627
|
+
function getGlobalDir(explicitDir = null) {
|
|
7628
|
+
return claudeAdapter.getGlobalDir(explicitDir);
|
|
8310
7629
|
}
|
|
8311
7630
|
/**
|
|
8312
7631
|
* Get the config directory path relative to home for hook templating
|
|
8313
7632
|
*/
|
|
8314
|
-
function getConfigDirFromHome(
|
|
8315
|
-
return
|
|
7633
|
+
function getConfigDirFromHome(isGlobal) {
|
|
7634
|
+
return claudeAdapter.getConfigDirFromHome(isGlobal);
|
|
8316
7635
|
}
|
|
8317
7636
|
/**
|
|
8318
|
-
* Get the local directory name
|
|
7637
|
+
* Get the local directory name
|
|
8319
7638
|
*/
|
|
8320
|
-
function getDirName(
|
|
8321
|
-
return
|
|
7639
|
+
function getDirName() {
|
|
7640
|
+
return claudeAdapter.dirName;
|
|
8322
7641
|
}
|
|
8323
7642
|
/**
|
|
8324
7643
|
* Recursively remove a directory, handling Windows read-only file attributes.
|
|
@@ -8334,16 +7653,10 @@ function copyDirRecursive(src, dest) {
|
|
|
8334
7653
|
import_lib.default.copySync(src, dest, { dereference: true });
|
|
8335
7654
|
}
|
|
8336
7655
|
/**
|
|
8337
|
-
*
|
|
8338
|
-
*
|
|
8339
|
-
*/
|
|
8340
|
-
function getOpencodeGlobalDir() {
|
|
8341
|
-
return opencodeAdapter.getGlobalDir();
|
|
8342
|
-
}
|
|
8343
|
-
/**
|
|
8344
|
-
* Verify a directory exists and contains files
|
|
7656
|
+
* Verify a directory exists and contains files.
|
|
7657
|
+
* If expectedFiles is provided, also checks that those specific files exist inside the directory.
|
|
8345
7658
|
*/
|
|
8346
|
-
function verifyInstalled(dirPath, description) {
|
|
7659
|
+
function verifyInstalled(dirPath, description, expectedFiles) {
|
|
8347
7660
|
if (!node_fs.existsSync(dirPath)) {
|
|
8348
7661
|
console.error(` \u2717 Failed to install ${description}: directory not created`);
|
|
8349
7662
|
return false;
|
|
@@ -8357,6 +7670,13 @@ function verifyInstalled(dirPath, description) {
|
|
|
8357
7670
|
console.error(` \u2717 Failed to install ${description}: ${e.message}`);
|
|
8358
7671
|
return false;
|
|
8359
7672
|
}
|
|
7673
|
+
if (expectedFiles && expectedFiles.length > 0) {
|
|
7674
|
+
const missing = expectedFiles.filter((f) => !node_fs.existsSync(node_path.join(dirPath, f)));
|
|
7675
|
+
if (missing.length > 0) {
|
|
7676
|
+
console.error(` \u2717 Failed to install ${description}: missing files: ${missing.join(", ")}`);
|
|
7677
|
+
return false;
|
|
7678
|
+
}
|
|
7679
|
+
}
|
|
8360
7680
|
return true;
|
|
8361
7681
|
}
|
|
8362
7682
|
/**
|
|
@@ -8369,102 +7689,69 @@ function verifyFileInstalled(filePath, description) {
|
|
|
8369
7689
|
}
|
|
8370
7690
|
return true;
|
|
8371
7691
|
}
|
|
8372
|
-
|
|
8373
|
-
//#endregion
|
|
8374
|
-
//#region src/install/adapters.ts
|
|
8375
|
-
const attributionCache = /* @__PURE__ */ new Map();
|
|
8376
7692
|
/**
|
|
8377
|
-
*
|
|
8378
|
-
*
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
|
|
8382
|
-
|
|
8383
|
-
if (runtime === "opencode") result = readSettings(node_path.join(getGlobalDir("opencode", null), "opencode.json")).disable_ai_attribution === true ? null : void 0;
|
|
8384
|
-
else if (runtime === "gemini") {
|
|
8385
|
-
const attr = readSettings(node_path.join(getGlobalDir("gemini", explicitConfigDir), "settings.json")).attribution;
|
|
8386
|
-
if (!attr || attr.commit === void 0) result = void 0;
|
|
8387
|
-
else if (attr.commit === "") result = null;
|
|
8388
|
-
else result = attr.commit;
|
|
8389
|
-
} else if (runtime === "claude") {
|
|
8390
|
-
const attr = readSettings(node_path.join(getGlobalDir("claude", explicitConfigDir), "settings.json")).attribution;
|
|
8391
|
-
if (!attr || attr.commit === void 0) result = void 0;
|
|
8392
|
-
else if (attr.commit === "") result = null;
|
|
8393
|
-
else result = attr.commit;
|
|
8394
|
-
} else result = void 0;
|
|
8395
|
-
attributionCache.set(runtime, result);
|
|
8396
|
-
return result;
|
|
8397
|
-
}
|
|
8398
|
-
/**
|
|
8399
|
-
* Parse JSONC (JSON with Comments) by stripping comments and trailing commas.
|
|
7693
|
+
* Verify that all major install components are present. Uses the manifest
|
|
7694
|
+
* (if available) to check individual files; otherwise falls back to
|
|
7695
|
+
* directory-level checks.
|
|
7696
|
+
*
|
|
7697
|
+
* Returns an object with `complete` (boolean) and `missing` (list of
|
|
7698
|
+
* component names that are absent or incomplete).
|
|
8400
7699
|
*/
|
|
8401
|
-
function
|
|
8402
|
-
|
|
8403
|
-
|
|
8404
|
-
|
|
8405
|
-
|
|
8406
|
-
|
|
8407
|
-
|
|
8408
|
-
|
|
8409
|
-
|
|
8410
|
-
|
|
8411
|
-
|
|
8412
|
-
|
|
8413
|
-
|
|
8414
|
-
|
|
8415
|
-
|
|
8416
|
-
|
|
8417
|
-
|
|
8418
|
-
}
|
|
8419
|
-
|
|
8420
|
-
|
|
8421
|
-
|
|
8422
|
-
}
|
|
8423
|
-
|
|
8424
|
-
|
|
8425
|
-
|
|
8426
|
-
i += 2;
|
|
8427
|
-
} else {
|
|
8428
|
-
result += char;
|
|
8429
|
-
i++;
|
|
7700
|
+
function verifyInstallComplete(configDir, _runtime, manifest = null) {
|
|
7701
|
+
const missing = [];
|
|
7702
|
+
if (manifest && manifest.files) {
|
|
7703
|
+
for (const relPath of Object.keys(manifest.files)) if (!node_fs.existsSync(node_path.join(configDir, relPath))) missing.push(relPath);
|
|
7704
|
+
return {
|
|
7705
|
+
complete: missing.length === 0,
|
|
7706
|
+
missing
|
|
7707
|
+
};
|
|
7708
|
+
}
|
|
7709
|
+
const components = [
|
|
7710
|
+
{
|
|
7711
|
+
dir: node_path.join(configDir, "maxsim"),
|
|
7712
|
+
label: "maxsim (workflows/templates)"
|
|
7713
|
+
},
|
|
7714
|
+
{
|
|
7715
|
+
dir: node_path.join(configDir, "agents"),
|
|
7716
|
+
label: "agents"
|
|
7717
|
+
},
|
|
7718
|
+
{
|
|
7719
|
+
dir: node_path.join(configDir, "commands", "maxsim"),
|
|
7720
|
+
label: "commands"
|
|
7721
|
+
},
|
|
7722
|
+
{
|
|
7723
|
+
dir: node_path.join(configDir, "hooks"),
|
|
7724
|
+
label: "hooks"
|
|
8430
7725
|
}
|
|
7726
|
+
];
|
|
7727
|
+
for (const { dir, label } of components) if (!node_fs.existsSync(dir)) missing.push(label);
|
|
7728
|
+
else try {
|
|
7729
|
+
if (node_fs.readdirSync(dir).length === 0) missing.push(label);
|
|
7730
|
+
} catch {
|
|
7731
|
+
missing.push(label);
|
|
8431
7732
|
}
|
|
8432
|
-
|
|
8433
|
-
|
|
7733
|
+
return {
|
|
7734
|
+
complete: missing.length === 0,
|
|
7735
|
+
missing
|
|
7736
|
+
};
|
|
8434
7737
|
}
|
|
7738
|
+
|
|
7739
|
+
//#endregion
|
|
7740
|
+
//#region src/install/adapters.ts
|
|
7741
|
+
let attributionCached = false;
|
|
7742
|
+
let attributionValue;
|
|
8435
7743
|
/**
|
|
8436
|
-
*
|
|
7744
|
+
* Get commit attribution setting for Claude Code
|
|
7745
|
+
* @returns null = remove, undefined = keep default, string = custom
|
|
8437
7746
|
*/
|
|
8438
|
-
function
|
|
8439
|
-
|
|
8440
|
-
const
|
|
8441
|
-
|
|
8442
|
-
|
|
8443
|
-
|
|
8444
|
-
|
|
8445
|
-
|
|
8446
|
-
console.log(` ${chalk.yellow("⚠")} Could not parse opencode.json - skipping permission config`);
|
|
8447
|
-
console.log(` ${chalk.dim(`Reason: ${e.message}`)}`);
|
|
8448
|
-
console.log(` ${chalk.dim("Your config was NOT modified. Fix the syntax manually if needed.")}`);
|
|
8449
|
-
return;
|
|
8450
|
-
}
|
|
8451
|
-
if (!config.permission) config.permission = {};
|
|
8452
|
-
const permission = config.permission;
|
|
8453
|
-
const maxsimPath = opencodeConfigDir === node_path.join(node_os.homedir(), ".config", "opencode") ? "~/.config/opencode/maxsim/*" : `${opencodeConfigDir.replace(/\\/g, "/")}/maxsim/*`;
|
|
8454
|
-
let modified = false;
|
|
8455
|
-
if (!permission.read || typeof permission.read !== "object") permission.read = {};
|
|
8456
|
-
if (permission.read[maxsimPath] !== "allow") {
|
|
8457
|
-
permission.read[maxsimPath] = "allow";
|
|
8458
|
-
modified = true;
|
|
8459
|
-
}
|
|
8460
|
-
if (!permission.external_directory || typeof permission.external_directory !== "object") permission.external_directory = {};
|
|
8461
|
-
if (permission.external_directory[maxsimPath] !== "allow") {
|
|
8462
|
-
permission.external_directory[maxsimPath] = "allow";
|
|
8463
|
-
modified = true;
|
|
8464
|
-
}
|
|
8465
|
-
if (!modified) return;
|
|
8466
|
-
node_fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
8467
|
-
console.log(` ${chalk.green("✓")} Configured read permission for MAXSIM docs`);
|
|
7747
|
+
function getCommitAttribution(explicitConfigDir) {
|
|
7748
|
+
if (attributionCached) return attributionValue;
|
|
7749
|
+
const attr = readSettings(node_path.join(getGlobalDir(explicitConfigDir), "settings.json")).attribution;
|
|
7750
|
+
if (!attr || attr.commit === void 0) attributionValue = void 0;
|
|
7751
|
+
else if (attr.commit === "") attributionValue = null;
|
|
7752
|
+
else attributionValue = attr.commit;
|
|
7753
|
+
attributionCached = true;
|
|
7754
|
+
return attributionValue;
|
|
8468
7755
|
}
|
|
8469
7756
|
|
|
8470
7757
|
//#endregion
|
|
@@ -8663,11 +7950,9 @@ function cleanupOrphanedHooks(settings) {
|
|
|
8663
7950
|
return settings;
|
|
8664
7951
|
}
|
|
8665
7952
|
/**
|
|
8666
|
-
* Install hook files and configure settings.json
|
|
7953
|
+
* Install hook files and configure settings.json
|
|
8667
7954
|
*/
|
|
8668
|
-
function installHookFiles(targetDir,
|
|
8669
|
-
getDirName(runtime);
|
|
8670
|
-
if (runtime === "codex") return;
|
|
7955
|
+
function installHookFiles(targetDir, isGlobal, failures) {
|
|
8671
7956
|
let hooksSrc = null;
|
|
8672
7957
|
const bundledHooksDir = node_path.resolve(__dirname, "assets", "hooks");
|
|
8673
7958
|
if (node_fs.existsSync(bundledHooksDir)) hooksSrc = bundledHooksDir;
|
|
@@ -8680,7 +7965,7 @@ function installHookFiles(targetDir, runtime, isGlobal, failures) {
|
|
|
8680
7965
|
const hooksDest = node_path.join(targetDir, "hooks");
|
|
8681
7966
|
node_fs.mkdirSync(hooksDest, { recursive: true });
|
|
8682
7967
|
const hookEntries = node_fs.readdirSync(hooksSrc);
|
|
8683
|
-
const configDirReplacement = getConfigDirFromHome(
|
|
7968
|
+
const configDirReplacement = getConfigDirFromHome(isGlobal);
|
|
8684
7969
|
for (const entry of hookEntries) {
|
|
8685
7970
|
const srcFile = node_path.join(hooksSrc, entry);
|
|
8686
7971
|
if (node_fs.statSync(srcFile).isFile() && entry.endsWith(".cjs") && !entry.includes(".d.")) {
|
|
@@ -8701,33 +7986,30 @@ function installHookFiles(targetDir, runtime, isGlobal, failures) {
|
|
|
8701
7986
|
/**
|
|
8702
7987
|
* Configure hooks and statusline in settings.json
|
|
8703
7988
|
*/
|
|
8704
|
-
function configureSettingsHooks(targetDir,
|
|
8705
|
-
const dirName = getDirName(
|
|
8706
|
-
const isOpencode = runtime === "opencode";
|
|
7989
|
+
function configureSettingsHooks(targetDir, isGlobal) {
|
|
7990
|
+
const dirName = getDirName();
|
|
8707
7991
|
const settingsPath = node_path.join(targetDir, "settings.json");
|
|
8708
7992
|
const settings = cleanupOrphanedHooks(readSettings(settingsPath));
|
|
8709
7993
|
const statuslineCommand = isGlobal ? buildHookCommand(targetDir, "maxsim-statusline.js") : "node " + dirName + "/hooks/maxsim-statusline.js";
|
|
8710
7994
|
const updateCheckCommand = isGlobal ? buildHookCommand(targetDir, "maxsim-check-update.js") : "node " + dirName + "/hooks/maxsim-check-update.js";
|
|
8711
7995
|
const contextMonitorCommand = isGlobal ? buildHookCommand(targetDir, "maxsim-context-monitor.js") : "node " + dirName + "/hooks/maxsim-context-monitor.js";
|
|
8712
|
-
if (!
|
|
8713
|
-
|
|
8714
|
-
|
|
8715
|
-
|
|
8716
|
-
|
|
8717
|
-
|
|
8718
|
-
|
|
8719
|
-
|
|
8720
|
-
|
|
8721
|
-
|
|
8722
|
-
|
|
8723
|
-
|
|
8724
|
-
|
|
8725
|
-
|
|
8726
|
-
|
|
8727
|
-
|
|
8728
|
-
|
|
8729
|
-
console.log(` ${chalk.green("✓")} Configured context window monitor hook`);
|
|
8730
|
-
}
|
|
7996
|
+
if (!settings.hooks) settings.hooks = {};
|
|
7997
|
+
const installHooks = settings.hooks;
|
|
7998
|
+
if (!installHooks.SessionStart) installHooks.SessionStart = [];
|
|
7999
|
+
if (!installHooks.SessionStart.some((entry) => entry.hooks && entry.hooks.some((h) => h.command && h.command.includes("maxsim-check-update")))) {
|
|
8000
|
+
installHooks.SessionStart.push({ hooks: [{
|
|
8001
|
+
type: "command",
|
|
8002
|
+
command: updateCheckCommand
|
|
8003
|
+
}] });
|
|
8004
|
+
console.log(` ${chalk.green("✓")} Configured update check hook`);
|
|
8005
|
+
}
|
|
8006
|
+
if (!installHooks.PostToolUse) installHooks.PostToolUse = [];
|
|
8007
|
+
if (!installHooks.PostToolUse.some((entry) => entry.hooks && entry.hooks.some((h) => h.command && h.command.includes("maxsim-context-monitor")))) {
|
|
8008
|
+
installHooks.PostToolUse.push({ hooks: [{
|
|
8009
|
+
type: "command",
|
|
8010
|
+
command: contextMonitorCommand
|
|
8011
|
+
}] });
|
|
8012
|
+
console.log(` ${chalk.green("✓")} Configured context window monitor hook`);
|
|
8731
8013
|
}
|
|
8732
8014
|
return {
|
|
8733
8015
|
settingsPath,
|
|
@@ -8769,138 +8051,22 @@ async function handleStatusline(settings, isInteractive, forceStatusline) {
|
|
|
8769
8051
|
/**
|
|
8770
8052
|
* Apply statusline config, then print completion message
|
|
8771
8053
|
*/
|
|
8772
|
-
function finishInstall(settingsPath, settings, statuslineCommand, shouldInstallStatusline,
|
|
8773
|
-
|
|
8774
|
-
const isCodex = runtime === "codex";
|
|
8775
|
-
if (shouldInstallStatusline && !isOpencode && !isCodex) {
|
|
8054
|
+
function finishInstall(settingsPath, settings, statuslineCommand, shouldInstallStatusline, isGlobal = true) {
|
|
8055
|
+
if (shouldInstallStatusline) {
|
|
8776
8056
|
settings.statusLine = {
|
|
8777
8057
|
type: "command",
|
|
8778
8058
|
command: statuslineCommand
|
|
8779
8059
|
};
|
|
8780
8060
|
console.log(` ${chalk.green("✓")} Configured statusline`);
|
|
8781
8061
|
}
|
|
8782
|
-
if (
|
|
8783
|
-
if (isOpencode) configureOpencodePermissions(isGlobal);
|
|
8784
|
-
let program = "Claude Code";
|
|
8785
|
-
if (runtime === "opencode") program = "OpenCode";
|
|
8786
|
-
if (runtime === "gemini") program = "Gemini";
|
|
8787
|
-
if (runtime === "codex") program = "Codex";
|
|
8788
|
-
let command = "/maxsim:help";
|
|
8789
|
-
if (runtime === "opencode") command = "/maxsim-help";
|
|
8790
|
-
if (runtime === "codex") command = "$maxsim-help";
|
|
8062
|
+
if (settingsPath && settings) writeSettings(settingsPath, settings);
|
|
8791
8063
|
console.log(`
|
|
8792
|
-
${chalk.green("Done!")} Launch
|
|
8064
|
+
${chalk.green("Done!")} Launch Claude Code and run ${chalk.cyan("/maxsim:help")}.
|
|
8793
8065
|
|
|
8794
8066
|
${chalk.cyan("Join the community:")} https://discord.gg/5JJgD5svVS
|
|
8795
8067
|
`);
|
|
8796
8068
|
}
|
|
8797
8069
|
|
|
8798
|
-
//#endregion
|
|
8799
|
-
//#region src/install/copy.ts
|
|
8800
|
-
/**
|
|
8801
|
-
* Copy commands to a flat structure for OpenCode
|
|
8802
|
-
* OpenCode expects: command/maxsim-help.md (invoked as /maxsim-help)
|
|
8803
|
-
* Source structure: commands/maxsim/help.md
|
|
8804
|
-
*/
|
|
8805
|
-
function copyFlattenedCommands(srcDir, destDir, prefix, pathPrefix, runtime, explicitConfigDir) {
|
|
8806
|
-
if (!node_fs.existsSync(srcDir)) return;
|
|
8807
|
-
if (node_fs.existsSync(destDir)) {
|
|
8808
|
-
for (const file of node_fs.readdirSync(destDir)) if (file.startsWith(`${prefix}-`) && file.endsWith(".md")) node_fs.unlinkSync(node_path.join(destDir, file));
|
|
8809
|
-
} else node_fs.mkdirSync(destDir, { recursive: true });
|
|
8810
|
-
const entries = node_fs.readdirSync(srcDir, { withFileTypes: true });
|
|
8811
|
-
for (const entry of entries) {
|
|
8812
|
-
const srcPath = node_path.join(srcDir, entry.name);
|
|
8813
|
-
if (entry.isDirectory()) copyFlattenedCommands(srcPath, destDir, `${prefix}-${entry.name}`, pathPrefix, runtime, explicitConfigDir);
|
|
8814
|
-
else if (entry.name.endsWith(".md")) {
|
|
8815
|
-
const destName = `${prefix}-${entry.name.replace(".md", "")}.md`;
|
|
8816
|
-
const destPath = node_path.join(destDir, destName);
|
|
8817
|
-
let content = node_fs.readFileSync(srcPath, "utf8");
|
|
8818
|
-
const globalClaudeRegex = /~\/\.claude\//g;
|
|
8819
|
-
const localClaudeRegex = /\.\/\.claude\//g;
|
|
8820
|
-
const opencodeDirRegex = /~\/\.opencode\//g;
|
|
8821
|
-
content = content.replace(globalClaudeRegex, pathPrefix);
|
|
8822
|
-
content = content.replace(localClaudeRegex, `./${getDirName(runtime)}/`);
|
|
8823
|
-
content = content.replace(opencodeDirRegex, pathPrefix);
|
|
8824
|
-
content = processAttribution(content, getCommitAttribution(runtime, explicitConfigDir));
|
|
8825
|
-
content = convertClaudeToOpencodeFrontmatter(content);
|
|
8826
|
-
node_fs.writeFileSync(destPath, content);
|
|
8827
|
-
}
|
|
8828
|
-
}
|
|
8829
|
-
}
|
|
8830
|
-
function listCodexSkillNames(skillsDir, prefix = "maxsim-") {
|
|
8831
|
-
if (!node_fs.existsSync(skillsDir)) return [];
|
|
8832
|
-
return node_fs.readdirSync(skillsDir, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.startsWith(prefix)).filter((entry) => node_fs.existsSync(node_path.join(skillsDir, entry.name, "SKILL.md"))).map((entry) => entry.name).sort();
|
|
8833
|
-
}
|
|
8834
|
-
function copyCommandsAsCodexSkills(srcDir, skillsDir, prefix, pathPrefix, runtime, explicitConfigDir) {
|
|
8835
|
-
if (!node_fs.existsSync(srcDir)) return;
|
|
8836
|
-
node_fs.mkdirSync(skillsDir, { recursive: true });
|
|
8837
|
-
const existing = node_fs.readdirSync(skillsDir, { withFileTypes: true });
|
|
8838
|
-
for (const entry of existing) if (entry.isDirectory() && entry.name.startsWith(`${prefix}-`)) node_fs.rmSync(node_path.join(skillsDir, entry.name), { recursive: true });
|
|
8839
|
-
function recurse(currentSrcDir, currentPrefix) {
|
|
8840
|
-
const entries = node_fs.readdirSync(currentSrcDir, { withFileTypes: true });
|
|
8841
|
-
for (const entry of entries) {
|
|
8842
|
-
const srcPath = node_path.join(currentSrcDir, entry.name);
|
|
8843
|
-
if (entry.isDirectory()) {
|
|
8844
|
-
recurse(srcPath, `${currentPrefix}-${entry.name}`);
|
|
8845
|
-
continue;
|
|
8846
|
-
}
|
|
8847
|
-
if (!entry.name.endsWith(".md")) continue;
|
|
8848
|
-
const skillName = `${currentPrefix}-${entry.name.replace(".md", "")}`;
|
|
8849
|
-
const skillDir = node_path.join(skillsDir, skillName);
|
|
8850
|
-
node_fs.mkdirSync(skillDir, { recursive: true });
|
|
8851
|
-
let content = node_fs.readFileSync(srcPath, "utf8");
|
|
8852
|
-
const globalClaudeRegex = /~\/\.claude\//g;
|
|
8853
|
-
const localClaudeRegex = /\.\/\.claude\//g;
|
|
8854
|
-
const codexDirRegex = /~\/\.codex\//g;
|
|
8855
|
-
content = content.replace(globalClaudeRegex, pathPrefix);
|
|
8856
|
-
content = content.replace(localClaudeRegex, `./${getDirName(runtime)}/`);
|
|
8857
|
-
content = content.replace(codexDirRegex, pathPrefix);
|
|
8858
|
-
content = processAttribution(content, getCommitAttribution(runtime, explicitConfigDir));
|
|
8859
|
-
content = convertClaudeCommandToCodexSkill(content, skillName);
|
|
8860
|
-
node_fs.writeFileSync(node_path.join(skillDir, "SKILL.md"), content);
|
|
8861
|
-
}
|
|
8862
|
-
}
|
|
8863
|
-
recurse(srcDir, prefix);
|
|
8864
|
-
}
|
|
8865
|
-
/**
|
|
8866
|
-
* Recursively copy directory, replacing paths in .md files
|
|
8867
|
-
* Deletes existing destDir first to remove orphaned files from previous versions
|
|
8868
|
-
*/
|
|
8869
|
-
function copyWithPathReplacement(srcDir, destDir, pathPrefix, runtime, explicitConfigDir, isCommand = false) {
|
|
8870
|
-
const isOpencode = runtime === "opencode";
|
|
8871
|
-
const isCodex = runtime === "codex";
|
|
8872
|
-
const dirName = getDirName(runtime);
|
|
8873
|
-
if (node_fs.existsSync(destDir)) node_fs.rmSync(destDir, { recursive: true });
|
|
8874
|
-
node_fs.mkdirSync(destDir, { recursive: true });
|
|
8875
|
-
const entries = node_fs.readdirSync(srcDir, { withFileTypes: true });
|
|
8876
|
-
for (const entry of entries) {
|
|
8877
|
-
const srcPath = node_path.join(srcDir, entry.name);
|
|
8878
|
-
const destPath = node_path.join(destDir, entry.name);
|
|
8879
|
-
if (entry.isDirectory()) copyWithPathReplacement(srcPath, destPath, pathPrefix, runtime, explicitConfigDir, isCommand);
|
|
8880
|
-
else if (entry.name.endsWith(".md")) {
|
|
8881
|
-
let content = node_fs.readFileSync(srcPath, "utf8");
|
|
8882
|
-
const globalClaudeRegex = /~\/\.claude\//g;
|
|
8883
|
-
const localClaudeRegex = /\.\/\.claude\//g;
|
|
8884
|
-
content = content.replace(globalClaudeRegex, pathPrefix);
|
|
8885
|
-
content = content.replace(localClaudeRegex, `./${dirName}/`);
|
|
8886
|
-
content = processAttribution(content, getCommitAttribution(runtime, explicitConfigDir));
|
|
8887
|
-
if (isOpencode) {
|
|
8888
|
-
content = convertClaudeToOpencodeFrontmatter(content);
|
|
8889
|
-
node_fs.writeFileSync(destPath, content);
|
|
8890
|
-
} else if (runtime === "gemini") if (isCommand) {
|
|
8891
|
-
content = stripSubTags(content);
|
|
8892
|
-
const tomlContent = convertClaudeToGeminiToml(content);
|
|
8893
|
-
const tomlPath = destPath.replace(/\.md$/, ".toml");
|
|
8894
|
-
node_fs.writeFileSync(tomlPath, tomlContent);
|
|
8895
|
-
} else node_fs.writeFileSync(destPath, content);
|
|
8896
|
-
else if (isCodex) {
|
|
8897
|
-
content = convertClaudeToCodexMarkdown(content);
|
|
8898
|
-
node_fs.writeFileSync(destPath, content);
|
|
8899
|
-
} else node_fs.writeFileSync(destPath, content);
|
|
8900
|
-
} else node_fs.copyFileSync(srcPath, destPath);
|
|
8901
|
-
}
|
|
8902
|
-
}
|
|
8903
|
-
|
|
8904
8070
|
//#endregion
|
|
8905
8071
|
//#region src/install/manifest.ts
|
|
8906
8072
|
const MANIFEST_NAME = "maxsim-file-manifest.json";
|
|
@@ -8930,13 +8096,9 @@ function generateManifest(dir, baseDir) {
|
|
|
8930
8096
|
/**
|
|
8931
8097
|
* Write file manifest after installation for future modification detection
|
|
8932
8098
|
*/
|
|
8933
|
-
function writeManifest(configDir
|
|
8934
|
-
const isOpencode = runtime === "opencode";
|
|
8935
|
-
const isCodex = runtime === "codex";
|
|
8099
|
+
function writeManifest(configDir) {
|
|
8936
8100
|
const maxsimDir = node_path.join(configDir, "maxsim");
|
|
8937
8101
|
const commandsDir = node_path.join(configDir, "commands", "maxsim");
|
|
8938
|
-
const opencodeCommandDir = node_path.join(configDir, "command");
|
|
8939
|
-
const codexSkillsDir = node_path.join(configDir, "skills");
|
|
8940
8102
|
const agentsDir = node_path.join(configDir, "agents");
|
|
8941
8103
|
const manifest = {
|
|
8942
8104
|
version: pkg.version,
|
|
@@ -8945,28 +8107,33 @@ function writeManifest(configDir, runtime = "claude") {
|
|
|
8945
8107
|
};
|
|
8946
8108
|
const maxsimHashes = generateManifest(maxsimDir);
|
|
8947
8109
|
for (const [rel, hash] of Object.entries(maxsimHashes)) manifest.files["maxsim/" + rel] = hash;
|
|
8948
|
-
if (
|
|
8110
|
+
if (node_fs.existsSync(commandsDir)) {
|
|
8949
8111
|
const cmdHashes = generateManifest(commandsDir);
|
|
8950
8112
|
for (const [rel, hash] of Object.entries(cmdHashes)) manifest.files["commands/maxsim/" + rel] = hash;
|
|
8951
8113
|
}
|
|
8952
|
-
if (isOpencode && node_fs.existsSync(opencodeCommandDir)) {
|
|
8953
|
-
for (const file of node_fs.readdirSync(opencodeCommandDir)) if (file.startsWith("maxsim-") && file.endsWith(".md")) manifest.files["command/" + file] = fileHash(node_path.join(opencodeCommandDir, file));
|
|
8954
|
-
}
|
|
8955
|
-
if (isCodex && node_fs.existsSync(codexSkillsDir)) for (const skillName of listCodexSkillNames(codexSkillsDir)) {
|
|
8956
|
-
const skillHashes = generateManifest(node_path.join(codexSkillsDir, skillName));
|
|
8957
|
-
for (const [rel, hash] of Object.entries(skillHashes)) manifest.files[`skills/${skillName}/${rel}`] = hash;
|
|
8958
|
-
}
|
|
8959
8114
|
if (node_fs.existsSync(agentsDir)) {
|
|
8960
8115
|
for (const file of node_fs.readdirSync(agentsDir)) if (file.startsWith("maxsim-") && file.endsWith(".md")) manifest.files["agents/" + file] = fileHash(node_path.join(agentsDir, file));
|
|
8961
8116
|
}
|
|
8962
|
-
const skillsManifestDir = node_path.join(
|
|
8117
|
+
const skillsManifestDir = node_path.join(configDir, "skills");
|
|
8963
8118
|
if (node_fs.existsSync(skillsManifestDir)) {
|
|
8964
8119
|
const skillHashes = generateManifest(skillsManifestDir);
|
|
8965
|
-
for (const [rel, hash] of Object.entries(skillHashes)) manifest.files["
|
|
8120
|
+
for (const [rel, hash] of Object.entries(skillHashes)) manifest.files["skills/" + rel] = hash;
|
|
8966
8121
|
}
|
|
8967
8122
|
node_fs.writeFileSync(node_path.join(configDir, MANIFEST_NAME), JSON.stringify(manifest, null, 2));
|
|
8968
8123
|
return manifest;
|
|
8969
8124
|
}
|
|
8125
|
+
/**
|
|
8126
|
+
* Read an existing manifest from the config directory, or return null if none exists / is invalid
|
|
8127
|
+
*/
|
|
8128
|
+
function readManifest(configDir) {
|
|
8129
|
+
const manifestPath = node_path.join(configDir, MANIFEST_NAME);
|
|
8130
|
+
if (!node_fs.existsSync(manifestPath)) return null;
|
|
8131
|
+
try {
|
|
8132
|
+
return JSON.parse(node_fs.readFileSync(manifestPath, "utf8"));
|
|
8133
|
+
} catch {
|
|
8134
|
+
return null;
|
|
8135
|
+
}
|
|
8136
|
+
}
|
|
8970
8137
|
|
|
8971
8138
|
//#endregion
|
|
8972
8139
|
//#region src/install/patches.ts
|
|
@@ -8975,14 +8142,8 @@ const PATCHES_DIR_NAME = "maxsim-local-patches";
|
|
|
8975
8142
|
* Detect user-modified MAXSIM files by comparing against install manifest.
|
|
8976
8143
|
*/
|
|
8977
8144
|
function saveLocalPatches(configDir) {
|
|
8978
|
-
const
|
|
8979
|
-
if (!
|
|
8980
|
-
let manifest;
|
|
8981
|
-
try {
|
|
8982
|
-
manifest = JSON.parse(node_fs.readFileSync(manifestPath, "utf8"));
|
|
8983
|
-
} catch {
|
|
8984
|
-
return [];
|
|
8985
|
-
}
|
|
8145
|
+
const manifest = readManifest(configDir);
|
|
8146
|
+
if (!manifest) return [];
|
|
8986
8147
|
const patchesDir = node_path.join(configDir, PATCHES_DIR_NAME);
|
|
8987
8148
|
const modified = [];
|
|
8988
8149
|
for (const [relPath, originalHash] of Object.entries(manifest.files || {})) {
|
|
@@ -9010,7 +8171,7 @@ function saveLocalPatches(configDir) {
|
|
|
9010
8171
|
/**
|
|
9011
8172
|
* After install, report backed-up patches for user to reapply.
|
|
9012
8173
|
*/
|
|
9013
|
-
function reportLocalPatches(configDir
|
|
8174
|
+
function reportLocalPatches(configDir) {
|
|
9014
8175
|
const patchesDir = node_path.join(configDir, PATCHES_DIR_NAME);
|
|
9015
8176
|
const metaPath = node_path.join(patchesDir, "backup-meta.json");
|
|
9016
8177
|
if (!node_fs.existsSync(metaPath)) return [];
|
|
@@ -9021,71 +8182,86 @@ function reportLocalPatches(configDir, runtime = "claude") {
|
|
|
9021
8182
|
return [];
|
|
9022
8183
|
}
|
|
9023
8184
|
if (meta.files && meta.files.length > 0) {
|
|
9024
|
-
const reapplyCommand = runtime === "opencode" ? "/maxsim-reapply-patches" : runtime === "codex" ? "$maxsim-reapply-patches" : "/maxsim:reapply-patches";
|
|
9025
8185
|
console.log("");
|
|
9026
8186
|
console.log(" " + chalk.yellow("Local patches detected") + " (from v" + meta.from_version + "):");
|
|
9027
8187
|
for (const f of meta.files) console.log(" " + chalk.cyan(f));
|
|
9028
8188
|
console.log("");
|
|
9029
8189
|
console.log(" Your modifications are saved in " + chalk.cyan(PATCHES_DIR_NAME + "/"));
|
|
9030
|
-
console.log(" Run " + chalk.cyan(
|
|
8190
|
+
console.log(" Run " + chalk.cyan("/maxsim:reapply-patches") + " to merge them into the new version.");
|
|
9031
8191
|
console.log(" Or manually compare and merge the files.");
|
|
9032
8192
|
console.log("");
|
|
9033
8193
|
}
|
|
9034
8194
|
return meta.files || [];
|
|
9035
8195
|
}
|
|
9036
8196
|
|
|
8197
|
+
//#endregion
|
|
8198
|
+
//#region src/install/copy.ts
|
|
8199
|
+
/**
|
|
8200
|
+
* Recursively copy directory, replacing paths in .md files
|
|
8201
|
+
* Deletes existing destDir first to remove orphaned files from previous versions
|
|
8202
|
+
*/
|
|
8203
|
+
function copyWithPathReplacement(srcDir, destDir, pathPrefix, explicitConfigDir, isCommand = false) {
|
|
8204
|
+
if (node_fs.existsSync(destDir)) node_fs.rmSync(destDir, { recursive: true });
|
|
8205
|
+
node_fs.mkdirSync(destDir, { recursive: true });
|
|
8206
|
+
const entries = node_fs.readdirSync(srcDir, { withFileTypes: true });
|
|
8207
|
+
for (const entry of entries) {
|
|
8208
|
+
const srcPath = node_path.join(srcDir, entry.name);
|
|
8209
|
+
const destPath = node_path.join(destDir, entry.name);
|
|
8210
|
+
if (entry.isDirectory()) copyWithPathReplacement(srcPath, destPath, pathPrefix, explicitConfigDir, isCommand);
|
|
8211
|
+
else if (entry.name.endsWith(".md")) {
|
|
8212
|
+
let content = node_fs.readFileSync(srcPath, "utf8");
|
|
8213
|
+
const globalClaudeRegex = /~\/\.claude\//g;
|
|
8214
|
+
const localClaudeRegex = /\.\/\.claude\//g;
|
|
8215
|
+
content = content.replace(globalClaudeRegex, pathPrefix);
|
|
8216
|
+
content = content.replace(localClaudeRegex, "./.claude/");
|
|
8217
|
+
content = processAttribution(content, getCommitAttribution(explicitConfigDir));
|
|
8218
|
+
node_fs.writeFileSync(destPath, content);
|
|
8219
|
+
} else node_fs.copyFileSync(srcPath, destPath);
|
|
8220
|
+
}
|
|
8221
|
+
}
|
|
8222
|
+
|
|
9037
8223
|
//#endregion
|
|
9038
8224
|
//#region src/install/uninstall.ts
|
|
9039
8225
|
/**
|
|
9040
|
-
* Uninstall MAXSIM from the specified directory
|
|
8226
|
+
* Uninstall MAXSIM from the specified directory
|
|
9041
8227
|
*/
|
|
9042
|
-
function uninstall(isGlobal,
|
|
9043
|
-
const
|
|
9044
|
-
const
|
|
9045
|
-
const dirName = getDirName(runtime);
|
|
9046
|
-
const targetDir = isGlobal ? getGlobalDir(runtime, explicitConfigDir) : node_path.join(process.cwd(), dirName);
|
|
8228
|
+
function uninstall(isGlobal, explicitConfigDir = null) {
|
|
8229
|
+
const dirName = getDirName();
|
|
8230
|
+
const targetDir = isGlobal ? getGlobalDir(explicitConfigDir) : node_path.join(process.cwd(), dirName);
|
|
9047
8231
|
const locationLabel = isGlobal ? targetDir.replace(node_os.homedir(), "~") : targetDir.replace(process.cwd(), ".");
|
|
9048
|
-
|
|
9049
|
-
if (runtime === "opencode") runtimeLabel = "OpenCode";
|
|
9050
|
-
if (runtime === "gemini") runtimeLabel = "Gemini";
|
|
9051
|
-
if (runtime === "codex") runtimeLabel = "Codex";
|
|
9052
|
-
console.log(` Uninstalling MAXSIM from ${chalk.cyan(runtimeLabel)} at ${chalk.cyan(locationLabel)}\n`);
|
|
8232
|
+
console.log(` Uninstalling MAXSIM from ${chalk.cyan("Claude Code")} at ${chalk.cyan(locationLabel)}\n`);
|
|
9053
8233
|
if (!node_fs.existsSync(targetDir)) {
|
|
9054
8234
|
console.log(` ${chalk.yellow("⚠")} Directory does not exist: ${locationLabel}`);
|
|
9055
8235
|
console.log(` Nothing to uninstall.\n`);
|
|
9056
8236
|
return;
|
|
9057
8237
|
}
|
|
9058
8238
|
let removedCount = 0;
|
|
9059
|
-
|
|
9060
|
-
|
|
9061
|
-
|
|
9062
|
-
|
|
9063
|
-
|
|
9064
|
-
|
|
9065
|
-
|
|
9066
|
-
}
|
|
9067
|
-
console.log(` ${chalk.green("✓")} Removed MAXSIM commands from command/`);
|
|
9068
|
-
}
|
|
9069
|
-
} else if (isCodex) {
|
|
8239
|
+
const maxsimCommandsDir = node_path.join(targetDir, "commands", "maxsim");
|
|
8240
|
+
if (node_fs.existsSync(maxsimCommandsDir)) {
|
|
8241
|
+
node_fs.rmSync(maxsimCommandsDir, { recursive: true });
|
|
8242
|
+
removedCount++;
|
|
8243
|
+
console.log(` ${chalk.green("✓")} Removed commands/maxsim/`);
|
|
8244
|
+
}
|
|
8245
|
+
{
|
|
9070
8246
|
const skillsDir = node_path.join(targetDir, "skills");
|
|
9071
8247
|
if (node_fs.existsSync(skillsDir)) {
|
|
9072
8248
|
let skillCount = 0;
|
|
9073
|
-
const
|
|
9074
|
-
|
|
9075
|
-
node_fs.
|
|
9076
|
-
|
|
8249
|
+
for (const skill of builtInSkills) {
|
|
8250
|
+
const skillDir = node_path.join(skillsDir, skill);
|
|
8251
|
+
if (node_fs.existsSync(skillDir)) {
|
|
8252
|
+
node_fs.rmSync(skillDir, { recursive: true });
|
|
8253
|
+
skillCount++;
|
|
8254
|
+
}
|
|
9077
8255
|
}
|
|
9078
8256
|
if (skillCount > 0) {
|
|
9079
8257
|
removedCount++;
|
|
9080
|
-
console.log(` ${chalk.green("✓")} Removed ${skillCount}
|
|
8258
|
+
console.log(` ${chalk.green("✓")} Removed ${skillCount} MAXSIM skills`);
|
|
9081
8259
|
}
|
|
9082
8260
|
}
|
|
9083
|
-
|
|
9084
|
-
|
|
9085
|
-
|
|
9086
|
-
|
|
9087
|
-
removedCount++;
|
|
9088
|
-
console.log(` ${chalk.green("✓")} Removed commands/maxsim/`);
|
|
8261
|
+
const legacySkillsDir = node_path.join(targetDir, "agents", "skills");
|
|
8262
|
+
if (node_fs.existsSync(legacySkillsDir)) {
|
|
8263
|
+
node_fs.rmSync(legacySkillsDir, { recursive: true });
|
|
8264
|
+
console.log(` ${chalk.green("✓")} Removed legacy agents/skills/ directory`);
|
|
9089
8265
|
}
|
|
9090
8266
|
}
|
|
9091
8267
|
const maxsimDir = node_path.join(targetDir, "maxsim");
|
|
@@ -9177,34 +8353,9 @@ function uninstall(isGlobal, runtime = "claude", explicitConfigDir = null) {
|
|
|
9177
8353
|
removedCount++;
|
|
9178
8354
|
}
|
|
9179
8355
|
}
|
|
9180
|
-
if (isOpencode) {
|
|
9181
|
-
const opencodeConfigDir = isGlobal ? getOpencodeGlobalDir() : node_path.join(process.cwd(), ".opencode");
|
|
9182
|
-
const configPath = node_path.join(opencodeConfigDir, "opencode.json");
|
|
9183
|
-
if (node_fs.existsSync(configPath)) try {
|
|
9184
|
-
const config = JSON.parse(node_fs.readFileSync(configPath, "utf8"));
|
|
9185
|
-
let modified = false;
|
|
9186
|
-
const permission = config.permission;
|
|
9187
|
-
if (permission) {
|
|
9188
|
-
for (const permType of ["read", "external_directory"]) if (permission[permType]) {
|
|
9189
|
-
const keys = Object.keys(permission[permType]);
|
|
9190
|
-
for (const key of keys) if (key.includes("maxsim")) {
|
|
9191
|
-
delete permission[permType][key];
|
|
9192
|
-
modified = true;
|
|
9193
|
-
}
|
|
9194
|
-
if (Object.keys(permission[permType]).length === 0) delete permission[permType];
|
|
9195
|
-
}
|
|
9196
|
-
if (Object.keys(permission).length === 0) delete config.permission;
|
|
9197
|
-
}
|
|
9198
|
-
if (modified) {
|
|
9199
|
-
node_fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
9200
|
-
removedCount++;
|
|
9201
|
-
console.log(` ${chalk.green("✓")} Removed MAXSIM permissions from opencode.json`);
|
|
9202
|
-
}
|
|
9203
|
-
} catch {}
|
|
9204
|
-
}
|
|
9205
8356
|
if (removedCount === 0) console.log(` ${chalk.yellow("⚠")} No MAXSIM files found to remove.`);
|
|
9206
8357
|
console.log(`
|
|
9207
|
-
${chalk.green("Done!")} MAXSIM has been uninstalled from
|
|
8358
|
+
${chalk.green("Done!")} MAXSIM has been uninstalled from Claude Code.
|
|
9208
8359
|
Your other files and settings have been preserved.
|
|
9209
8360
|
`);
|
|
9210
8361
|
}
|
|
@@ -9215,12 +8366,7 @@ const argv = (0, import_minimist.default)(process.argv.slice(2), {
|
|
|
9215
8366
|
boolean: [
|
|
9216
8367
|
"global",
|
|
9217
8368
|
"local",
|
|
9218
|
-
"opencode",
|
|
9219
8369
|
"claude",
|
|
9220
|
-
"gemini",
|
|
9221
|
-
"codex",
|
|
9222
|
-
"both",
|
|
9223
|
-
"all",
|
|
9224
8370
|
"uninstall",
|
|
9225
8371
|
"help",
|
|
9226
8372
|
"version",
|
|
@@ -9238,93 +8384,62 @@ const argv = (0, import_minimist.default)(process.argv.slice(2), {
|
|
|
9238
8384
|
});
|
|
9239
8385
|
const hasGlobal = !!argv["global"];
|
|
9240
8386
|
const hasLocal = !!argv["local"];
|
|
9241
|
-
const hasOpencode = !!argv["opencode"];
|
|
9242
|
-
const hasClaude = !!argv["claude"];
|
|
9243
|
-
const hasGemini = !!argv["gemini"];
|
|
9244
|
-
const hasCodex = !!argv["codex"];
|
|
9245
|
-
const hasBoth = !!argv["both"];
|
|
9246
|
-
const hasAll = !!argv["all"];
|
|
9247
8387
|
const hasUninstall = !!argv["uninstall"];
|
|
9248
|
-
|
|
9249
|
-
if (hasAll) selectedRuntimes = [
|
|
9250
|
-
"claude",
|
|
9251
|
-
"opencode",
|
|
9252
|
-
"gemini",
|
|
9253
|
-
"codex"
|
|
9254
|
-
];
|
|
9255
|
-
else if (hasBoth) selectedRuntimes = ["claude", "opencode"];
|
|
9256
|
-
else {
|
|
9257
|
-
if (hasOpencode) selectedRuntimes.push("opencode");
|
|
9258
|
-
if (hasClaude) selectedRuntimes.push("claude");
|
|
9259
|
-
if (hasGemini) selectedRuntimes.push("gemini");
|
|
9260
|
-
if (hasCodex) selectedRuntimes.push("codex");
|
|
9261
|
-
}
|
|
9262
|
-
const banner = "\n" + chalk.cyan(figlet.default.textSync("MAXSIM", { font: "ANSI Shadow" }).split("\n").map((line) => " " + line).join("\n")) + "\n\n MAXSIM " + chalk.dim("v" + pkg.version) + "\n A meta-prompting, context engineering and spec-driven\n development system for Claude Code, OpenCode, Gemini, and Codex.\n";
|
|
8388
|
+
const banner = "\n" + chalk.cyan(figlet.default.textSync("MAXSIM", { font: "ANSI Shadow" }).split("\n").map((line) => " " + line).join("\n")) + "\n\n MAXSIM " + chalk.dim("v" + pkg.version) + "\n A meta-prompting, context engineering and spec-driven\n development system for Claude Code.\n";
|
|
9263
8389
|
const explicitConfigDir = argv["config-dir"] || null;
|
|
9264
8390
|
const hasHelp = !!argv["help"];
|
|
9265
8391
|
const hasVersion = !!argv["version"];
|
|
9266
8392
|
const forceStatusline = !!argv["force-statusline"];
|
|
8393
|
+
for (const flag of [
|
|
8394
|
+
"opencode",
|
|
8395
|
+
"gemini",
|
|
8396
|
+
"codex",
|
|
8397
|
+
"both",
|
|
8398
|
+
"all"
|
|
8399
|
+
]) if (argv[flag]) {
|
|
8400
|
+
console.error(`Error: The --${flag} flag is no longer supported. MAXSIM v2.0 is Claude Code only.`);
|
|
8401
|
+
process.exit(1);
|
|
8402
|
+
}
|
|
9267
8403
|
if (hasVersion) {
|
|
9268
8404
|
console.log(pkg.version);
|
|
9269
8405
|
process.exit(0);
|
|
9270
8406
|
}
|
|
9271
8407
|
console.log(banner);
|
|
9272
8408
|
if (hasHelp) {
|
|
9273
|
-
console.log(` ${chalk.yellow("Usage:")} npx maxsimcli [options]\n\n ${chalk.yellow("Options:")}\n ${chalk.cyan("-g, --global")} Install globally (to config directory)\n ${chalk.cyan("-l, --local")} Install locally (to current directory)\n ${chalk.cyan("
|
|
8409
|
+
console.log(` ${chalk.yellow("Usage:")} npx maxsimcli [options]\n\n ${chalk.yellow("Options:")}\n ${chalk.cyan("-g, --global")} Install globally (to config directory)\n ${chalk.cyan("-l, --local")} Install locally (to current directory)\n ${chalk.cyan("-u, --uninstall")} Uninstall MAXSIM (remove all MAXSIM files)\n ${chalk.cyan("-c, --config-dir <path>")} Specify custom config directory\n ${chalk.cyan("-h, --help")} Show this help message\n ${chalk.cyan("--force-statusline")} Replace existing statusline config\n\n ${chalk.yellow("Examples:")}\n ${chalk.dim("# Interactive install (prompts for location)")}\n npx maxsimcli\n\n ${chalk.dim("# Install globally")}\n npx maxsimcli --global\n\n ${chalk.dim("# Install to current project only")}\n npx maxsimcli --local\n\n ${chalk.dim("# Install to custom config directory")}\n npx maxsimcli --global --config-dir ~/.claude-work\n\n ${chalk.dim("# Uninstall MAXSIM globally")}\n npx maxsimcli --global --uninstall\n\n ${chalk.yellow("Notes:")}\n The --config-dir option is useful when you have multiple configurations.\n It takes priority over the CLAUDE_CONFIG_DIR environment variable.\n`);
|
|
9274
8410
|
process.exit(0);
|
|
9275
8411
|
}
|
|
9276
|
-
async function install(isGlobal
|
|
9277
|
-
const
|
|
9278
|
-
const
|
|
9279
|
-
const isCodex = runtime === "codex";
|
|
9280
|
-
const dirName = getDirName(runtime);
|
|
8412
|
+
async function install(isGlobal) {
|
|
8413
|
+
const runtime = "claude";
|
|
8414
|
+
const dirName = getDirName();
|
|
9281
8415
|
const src = templatesRoot;
|
|
9282
|
-
const targetDir = isGlobal ? getGlobalDir(
|
|
8416
|
+
const targetDir = isGlobal ? getGlobalDir(explicitConfigDir) : node_path.join(process.cwd(), dirName);
|
|
9283
8417
|
const locationLabel = isGlobal ? targetDir.replace(node_os.homedir(), "~") : targetDir.replace(process.cwd(), ".");
|
|
9284
8418
|
const pathPrefix = isGlobal ? `${targetDir.replace(/\\/g, "/")}/` : `./${dirName}/`;
|
|
9285
|
-
|
|
9286
|
-
if (isOpencode) runtimeLabel = "OpenCode";
|
|
9287
|
-
if (isGemini) runtimeLabel = "Gemini";
|
|
9288
|
-
if (isCodex) runtimeLabel = "Codex";
|
|
9289
|
-
console.log(` Installing for ${chalk.cyan(runtimeLabel)} to ${chalk.cyan(locationLabel)}\n`);
|
|
8419
|
+
console.log(` Installing for ${chalk.cyan("Claude Code")} to ${chalk.cyan(locationLabel)}\n`);
|
|
9290
8420
|
const failures = [];
|
|
8421
|
+
const existingManifest = readManifest(targetDir);
|
|
8422
|
+
const isAlreadyCurrent = existingManifest !== null && existingManifest.version === pkg.version;
|
|
8423
|
+
if (existingManifest !== null) {
|
|
8424
|
+
const { complete, missing } = verifyInstallComplete(targetDir, runtime, existingManifest);
|
|
8425
|
+
if (!complete) console.log(` ${chalk.yellow("!")} Previous install (v${existingManifest.version}) is incomplete — ${missing.length} missing file(s). Re-installing.`);
|
|
8426
|
+
else if (isAlreadyCurrent) console.log(` ${chalk.dim(`Version ${pkg.version} already installed — upgrading in place`)}`);
|
|
8427
|
+
}
|
|
9291
8428
|
saveLocalPatches(targetDir);
|
|
9292
8429
|
cleanupOrphanedFiles(targetDir);
|
|
9293
8430
|
let spinner = ora({
|
|
9294
8431
|
text: "Installing commands...",
|
|
9295
8432
|
color: "cyan"
|
|
9296
8433
|
}).start();
|
|
9297
|
-
|
|
9298
|
-
|
|
9299
|
-
|
|
9300
|
-
|
|
9301
|
-
|
|
9302
|
-
|
|
9303
|
-
|
|
9304
|
-
|
|
9305
|
-
|
|
9306
|
-
failures.push("command/maxsim-*");
|
|
9307
|
-
}
|
|
9308
|
-
} else if (isCodex) {
|
|
9309
|
-
const skillsDir = node_path.join(targetDir, "skills");
|
|
9310
|
-
copyCommandsAsCodexSkills(node_path.join(src, "commands", "maxsim"), skillsDir, "maxsim", pathPrefix, runtime, explicitConfigDir);
|
|
9311
|
-
const installedSkillNames = listCodexSkillNames(skillsDir);
|
|
9312
|
-
if (installedSkillNames.length > 0) spinner.succeed(chalk.green("✓") + ` Installed ${installedSkillNames.length} skills to skills/`);
|
|
9313
|
-
else {
|
|
9314
|
-
spinner.fail("Failed to install skills");
|
|
9315
|
-
failures.push("skills/maxsim-*");
|
|
9316
|
-
}
|
|
9317
|
-
} else {
|
|
9318
|
-
const commandsDir = node_path.join(targetDir, "commands");
|
|
9319
|
-
node_fs.mkdirSync(commandsDir, { recursive: true });
|
|
9320
|
-
const maxsimSrc = node_path.join(src, "commands", "maxsim");
|
|
9321
|
-
const maxsimDest = node_path.join(commandsDir, "maxsim");
|
|
9322
|
-
copyWithPathReplacement(maxsimSrc, maxsimDest, pathPrefix, runtime, explicitConfigDir, true);
|
|
9323
|
-
if (verifyInstalled(maxsimDest, "commands/maxsim")) spinner.succeed(chalk.green("✓") + " Installed commands/maxsim");
|
|
9324
|
-
else {
|
|
9325
|
-
spinner.fail("Failed to install commands/maxsim");
|
|
9326
|
-
failures.push("commands/maxsim");
|
|
9327
|
-
}
|
|
8434
|
+
const commandsDir = node_path.join(targetDir, "commands");
|
|
8435
|
+
node_fs.mkdirSync(commandsDir, { recursive: true });
|
|
8436
|
+
const maxsimSrc = node_path.join(src, "commands", "maxsim");
|
|
8437
|
+
const maxsimDest = node_path.join(commandsDir, "maxsim");
|
|
8438
|
+
copyWithPathReplacement(maxsimSrc, maxsimDest, pathPrefix, explicitConfigDir, true);
|
|
8439
|
+
if (verifyInstalled(maxsimDest, "commands/maxsim")) spinner.succeed(chalk.green("✓") + " Installed commands/maxsim");
|
|
8440
|
+
else {
|
|
8441
|
+
spinner.fail("Failed to install commands/maxsim");
|
|
8442
|
+
failures.push("commands/maxsim");
|
|
9328
8443
|
}
|
|
9329
8444
|
spinner = ora({
|
|
9330
8445
|
text: "Installing workflows and templates...",
|
|
@@ -9340,7 +8455,7 @@ async function install(isGlobal, runtime = "claude") {
|
|
|
9340
8455
|
node_fs.mkdirSync(skillDest, { recursive: true });
|
|
9341
8456
|
for (const subdir of maxsimSubdirs) {
|
|
9342
8457
|
const subdirSrc = node_path.join(src, subdir);
|
|
9343
|
-
if (node_fs.existsSync(subdirSrc)) copyWithPathReplacement(subdirSrc, node_path.join(skillDest, subdir), pathPrefix,
|
|
8458
|
+
if (node_fs.existsSync(subdirSrc)) copyWithPathReplacement(subdirSrc, node_path.join(skillDest, subdir), pathPrefix, explicitConfigDir);
|
|
9344
8459
|
}
|
|
9345
8460
|
if (verifyInstalled(skillDest, "maxsim")) spinner.succeed(chalk.green("✓") + " Installed maxsim");
|
|
9346
8461
|
else {
|
|
@@ -9362,10 +8477,7 @@ async function install(isGlobal, runtime = "claude") {
|
|
|
9362
8477
|
for (const entry of agentEntries) if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
9363
8478
|
let content = node_fs.readFileSync(node_path.join(agentsSrc, entry.name), "utf8");
|
|
9364
8479
|
content = content.replace(/~\/\.claude\//g, pathPrefix);
|
|
9365
|
-
content = processAttribution(content, getCommitAttribution(
|
|
9366
|
-
if (isOpencode) content = convertClaudeToOpencodeFrontmatter(content);
|
|
9367
|
-
else if (isGemini) content = convertClaudeToGeminiAgent(content);
|
|
9368
|
-
else if (isCodex) content = convertClaudeToCodexMarkdown(content);
|
|
8480
|
+
content = processAttribution(content, getCommitAttribution(explicitConfigDir));
|
|
9369
8481
|
node_fs.writeFileSync(node_path.join(agentsDest, entry.name), content);
|
|
9370
8482
|
}
|
|
9371
8483
|
if (verifyInstalled(agentsDest, "agents")) spinner.succeed(chalk.green("✓") + " Installed agents");
|
|
@@ -9374,18 +8486,19 @@ async function install(isGlobal, runtime = "claude") {
|
|
|
9374
8486
|
failures.push("agents");
|
|
9375
8487
|
}
|
|
9376
8488
|
}
|
|
8489
|
+
const legacySkillsDir = node_path.join(targetDir, "agents", "skills");
|
|
8490
|
+
if (node_fs.existsSync(legacySkillsDir)) {
|
|
8491
|
+
node_fs.rmSync(legacySkillsDir, { recursive: true });
|
|
8492
|
+
console.log(` ${chalk.green("✓")} Removed legacy agents/skills/ directory`);
|
|
8493
|
+
}
|
|
9377
8494
|
const skillsSrc = node_path.join(src, "skills");
|
|
9378
8495
|
if (node_fs.existsSync(skillsSrc)) {
|
|
9379
8496
|
spinner = ora({
|
|
9380
8497
|
text: "Installing skills...",
|
|
9381
8498
|
color: "cyan"
|
|
9382
8499
|
}).start();
|
|
9383
|
-
const skillsDest = node_path.join(targetDir, "
|
|
9384
|
-
if (node_fs.existsSync(skillsDest)) for (const skill of
|
|
9385
|
-
"tdd",
|
|
9386
|
-
"systematic-debugging",
|
|
9387
|
-
"verification-before-completion"
|
|
9388
|
-
]) {
|
|
8500
|
+
const skillsDest = node_path.join(targetDir, "skills");
|
|
8501
|
+
if (node_fs.existsSync(skillsDest)) for (const skill of builtInSkills) {
|
|
9389
8502
|
const skillDir = node_path.join(skillsDest, skill);
|
|
9390
8503
|
if (node_fs.existsSync(skillDir)) node_fs.rmSync(skillDir, { recursive: true });
|
|
9391
8504
|
}
|
|
@@ -9396,15 +8509,15 @@ async function install(isGlobal, runtime = "claude") {
|
|
|
9396
8509
|
if (node_fs.existsSync(skillMd)) {
|
|
9397
8510
|
let content = node_fs.readFileSync(skillMd, "utf8");
|
|
9398
8511
|
content = content.replace(/~\/\.claude\//g, pathPrefix);
|
|
9399
|
-
content = processAttribution(content, getCommitAttribution(
|
|
8512
|
+
content = processAttribution(content, getCommitAttribution(explicitConfigDir));
|
|
9400
8513
|
node_fs.writeFileSync(skillMd, content);
|
|
9401
8514
|
}
|
|
9402
8515
|
}
|
|
9403
8516
|
const installedSkillDirs = node_fs.readdirSync(skillsDest, { withFileTypes: true }).filter((e) => e.isDirectory()).length;
|
|
9404
|
-
if (installedSkillDirs > 0) spinner.succeed(chalk.green("✓") + ` Installed ${installedSkillDirs} skills to
|
|
8517
|
+
if (installedSkillDirs > 0) spinner.succeed(chalk.green("✓") + ` Installed ${installedSkillDirs} skills to skills/`);
|
|
9405
8518
|
else {
|
|
9406
8519
|
spinner.fail("Failed to install skills");
|
|
9407
|
-
failures.push("
|
|
8520
|
+
failures.push("skills");
|
|
9408
8521
|
}
|
|
9409
8522
|
}
|
|
9410
8523
|
const changelogSrc = node_path.join(src, "..", "CHANGELOG.md");
|
|
@@ -9439,30 +8552,28 @@ async function install(isGlobal, runtime = "claude") {
|
|
|
9439
8552
|
node_fs.writeFileSync(versionDest, pkg.version);
|
|
9440
8553
|
if (verifyFileInstalled(versionDest, "VERSION")) console.log(` ${chalk.green("✓")} Wrote VERSION (${pkg.version})`);
|
|
9441
8554
|
else failures.push("VERSION");
|
|
9442
|
-
|
|
9443
|
-
|
|
9444
|
-
|
|
9445
|
-
|
|
9446
|
-
|
|
9447
|
-
|
|
9448
|
-
|
|
9449
|
-
|
|
9450
|
-
|
|
9451
|
-
|
|
9452
|
-
|
|
9453
|
-
}
|
|
9454
|
-
|
|
9455
|
-
|
|
9456
|
-
|
|
9457
|
-
|
|
9458
|
-
|
|
9459
|
-
|
|
9460
|
-
|
|
9461
|
-
|
|
9462
|
-
|
|
9463
|
-
|
|
9464
|
-
installHookFiles(targetDir, runtime, isGlobal, failures);
|
|
9465
|
-
}
|
|
8555
|
+
const pkgJsonDest = node_path.join(targetDir, "package.json");
|
|
8556
|
+
node_fs.writeFileSync(pkgJsonDest, "{\"type\":\"commonjs\"}\n");
|
|
8557
|
+
console.log(` ${chalk.green("✓")} Wrote package.json (CommonJS mode)`);
|
|
8558
|
+
const toolSrc = node_path.resolve(__dirname, "cli.cjs");
|
|
8559
|
+
const binDir = node_path.join(targetDir, "maxsim", "bin");
|
|
8560
|
+
const toolDest = node_path.join(binDir, "maxsim-tools.cjs");
|
|
8561
|
+
if (node_fs.existsSync(toolSrc)) {
|
|
8562
|
+
node_fs.mkdirSync(binDir, { recursive: true });
|
|
8563
|
+
node_fs.copyFileSync(toolSrc, toolDest);
|
|
8564
|
+
console.log(` ${chalk.green("✓")} Installed maxsim-tools.cjs`);
|
|
8565
|
+
} else {
|
|
8566
|
+
console.warn(` ${chalk.yellow("!")} cli.cjs not found at ${toolSrc} — maxsim-tools.cjs not installed`);
|
|
8567
|
+
failures.push("maxsim-tools.cjs");
|
|
8568
|
+
}
|
|
8569
|
+
const mcpSrc = node_path.resolve(__dirname, "mcp-server.cjs");
|
|
8570
|
+
const mcpDest = node_path.join(binDir, "mcp-server.cjs");
|
|
8571
|
+
if (node_fs.existsSync(mcpSrc)) {
|
|
8572
|
+
node_fs.mkdirSync(binDir, { recursive: true });
|
|
8573
|
+
node_fs.copyFileSync(mcpSrc, mcpDest);
|
|
8574
|
+
console.log(` ${chalk.green("✓")} Installed mcp-server.cjs`);
|
|
8575
|
+
} else console.warn(` ${chalk.yellow("!")} mcp-server.cjs not found — MCP server not installed`);
|
|
8576
|
+
installHookFiles(targetDir, isGlobal, failures);
|
|
9466
8577
|
const dashboardSrc = node_path.resolve(__dirname, "assets", "dashboard");
|
|
9467
8578
|
if (node_fs.existsSync(dashboardSrc)) {
|
|
9468
8579
|
let networkMode = false;
|
|
@@ -9489,12 +8600,29 @@ async function install(isGlobal, runtime = "claude") {
|
|
|
9489
8600
|
else spinner.succeed(chalk.green("✓") + " Installed dashboard (server.js not found in bundle)");
|
|
9490
8601
|
if (networkMode) applyFirewallRule(3333);
|
|
9491
8602
|
}
|
|
9492
|
-
|
|
9493
|
-
|
|
9494
|
-
|
|
9495
|
-
|
|
8603
|
+
const mcpJsonPath = isGlobal ? node_path.join(targetDir, "..", ".mcp.json") : node_path.join(process.cwd(), ".mcp.json");
|
|
8604
|
+
let mcpConfig = {};
|
|
8605
|
+
let skipMcpConfig = false;
|
|
8606
|
+
if (node_fs.existsSync(mcpJsonPath)) {
|
|
8607
|
+
node_fs.copyFileSync(mcpJsonPath, mcpJsonPath + ".bak");
|
|
8608
|
+
try {
|
|
9496
8609
|
mcpConfig = JSON.parse(node_fs.readFileSync(mcpJsonPath, "utf-8"));
|
|
9497
|
-
} catch {
|
|
8610
|
+
} catch {
|
|
8611
|
+
console.warn(` ${chalk.yellow("!")} .mcp.json is corrupted (invalid JSON). Backup saved to .mcp.json.bak`);
|
|
8612
|
+
let startFresh = true;
|
|
8613
|
+
try {
|
|
8614
|
+
startFresh = await dist_default$1({
|
|
8615
|
+
message: ".mcp.json is corrupted. Start with a fresh config? (No = abort MCP setup)",
|
|
8616
|
+
default: true
|
|
8617
|
+
});
|
|
8618
|
+
} catch {}
|
|
8619
|
+
if (!startFresh) {
|
|
8620
|
+
console.log(` ${chalk.yellow("!")} Skipping .mcp.json configuration`);
|
|
8621
|
+
skipMcpConfig = true;
|
|
8622
|
+
}
|
|
8623
|
+
}
|
|
8624
|
+
}
|
|
8625
|
+
if (!skipMcpConfig) {
|
|
9498
8626
|
const mcpServers = mcpConfig.mcpServers ?? {};
|
|
9499
8627
|
mcpServers["maxsim"] = {
|
|
9500
8628
|
command: "node",
|
|
@@ -9509,24 +8637,10 @@ async function install(isGlobal, runtime = "claude") {
|
|
|
9509
8637
|
console.error(`\n ${chalk.yellow("Installation incomplete!")} Failed: ${failures.join(", ")}`);
|
|
9510
8638
|
process.exit(1);
|
|
9511
8639
|
}
|
|
9512
|
-
writeManifest(targetDir
|
|
8640
|
+
writeManifest(targetDir);
|
|
9513
8641
|
console.log(` ${chalk.green("✓")} Wrote file manifest (${MANIFEST_NAME})`);
|
|
9514
|
-
reportLocalPatches(targetDir
|
|
9515
|
-
|
|
9516
|
-
settingsPath: null,
|
|
9517
|
-
settings: null,
|
|
9518
|
-
statuslineCommand: null,
|
|
9519
|
-
runtime
|
|
9520
|
-
};
|
|
9521
|
-
const { settingsPath, settings, statuslineCommand } = configureSettingsHooks(targetDir, runtime, isGlobal);
|
|
9522
|
-
if (isGemini) {
|
|
9523
|
-
if (!settings.experimental) settings.experimental = {};
|
|
9524
|
-
const experimental = settings.experimental;
|
|
9525
|
-
if (!experimental.enableAgents) {
|
|
9526
|
-
experimental.enableAgents = true;
|
|
9527
|
-
console.log(` ${chalk.green("✓")} Enabled experimental agents`);
|
|
9528
|
-
}
|
|
9529
|
-
}
|
|
8642
|
+
reportLocalPatches(targetDir);
|
|
8643
|
+
const { settingsPath, settings, statuslineCommand } = configureSettingsHooks(targetDir, isGlobal);
|
|
9530
8644
|
return {
|
|
9531
8645
|
settingsPath,
|
|
9532
8646
|
settings,
|
|
@@ -9535,56 +8649,27 @@ async function install(isGlobal, runtime = "claude") {
|
|
|
9535
8649
|
};
|
|
9536
8650
|
}
|
|
9537
8651
|
/**
|
|
9538
|
-
* Prompt for runtime selection (multi-select)
|
|
9539
|
-
*/
|
|
9540
|
-
async function promptRuntime() {
|
|
9541
|
-
return await dist_default$2({
|
|
9542
|
-
message: "Which runtime(s) would you like to install for?",
|
|
9543
|
-
choices: [
|
|
9544
|
-
{
|
|
9545
|
-
name: "Claude Code " + chalk.dim("(~/.claude)"),
|
|
9546
|
-
value: "claude",
|
|
9547
|
-
checked: true
|
|
9548
|
-
},
|
|
9549
|
-
{
|
|
9550
|
-
name: "OpenCode " + chalk.dim("(~/.config/opencode)") + " — open source, free models",
|
|
9551
|
-
value: "opencode"
|
|
9552
|
-
},
|
|
9553
|
-
{
|
|
9554
|
-
name: "Gemini " + chalk.dim("(~/.gemini)"),
|
|
9555
|
-
value: "gemini"
|
|
9556
|
-
},
|
|
9557
|
-
{
|
|
9558
|
-
name: "Codex " + chalk.dim("(~/.codex)"),
|
|
9559
|
-
value: "codex"
|
|
9560
|
-
}
|
|
9561
|
-
],
|
|
9562
|
-
validate: (choices) => choices.length > 0 || "Please select at least one runtime"
|
|
9563
|
-
});
|
|
9564
|
-
}
|
|
9565
|
-
/**
|
|
9566
8652
|
* Prompt for install location
|
|
9567
8653
|
*/
|
|
9568
|
-
async function promptLocation(
|
|
8654
|
+
async function promptLocation() {
|
|
9569
8655
|
if (!process.stdin.isTTY) {
|
|
9570
8656
|
console.log(chalk.yellow("Non-interactive terminal detected, defaulting to global install") + "\n");
|
|
9571
8657
|
return true;
|
|
9572
8658
|
}
|
|
9573
|
-
const
|
|
9574
|
-
const localExamples = runtimes.map((r) => `./${getDirName(r)}`).join(", ");
|
|
8659
|
+
const globalPath = getGlobalDir(explicitConfigDir).replace(node_os.homedir(), "~");
|
|
9575
8660
|
return await dist_default({
|
|
9576
8661
|
message: "Where would you like to install?",
|
|
9577
8662
|
choices: [{
|
|
9578
|
-
name: "Global " + chalk.dim(`(${
|
|
8663
|
+
name: "Global " + chalk.dim(`(${globalPath})`) + " — available in all projects",
|
|
9579
8664
|
value: "global"
|
|
9580
8665
|
}, {
|
|
9581
|
-
name: "Local " + chalk.dim(
|
|
8666
|
+
name: "Local " + chalk.dim("(./.claude)") + " — this project only",
|
|
9582
8667
|
value: "local"
|
|
9583
8668
|
}]
|
|
9584
8669
|
}) === "global";
|
|
9585
8670
|
}
|
|
9586
8671
|
/**
|
|
9587
|
-
* Prompt whether to enable Agent Teams (
|
|
8672
|
+
* Prompt whether to enable Agent Teams (experimental feature)
|
|
9588
8673
|
*/
|
|
9589
8674
|
async function promptAgentTeams() {
|
|
9590
8675
|
console.log();
|
|
@@ -9598,29 +8683,20 @@ async function promptAgentTeams() {
|
|
|
9598
8683
|
});
|
|
9599
8684
|
}
|
|
9600
8685
|
/**
|
|
9601
|
-
* Install MAXSIM for
|
|
8686
|
+
* Install MAXSIM for Claude Code
|
|
9602
8687
|
*/
|
|
9603
|
-
async function
|
|
9604
|
-
const
|
|
9605
|
-
for (const runtime of runtimes) {
|
|
9606
|
-
const result = await install(isGlobal, runtime);
|
|
9607
|
-
results.push(result);
|
|
9608
|
-
}
|
|
9609
|
-
const statuslineRuntimes = ["claude", "gemini"];
|
|
9610
|
-
const primaryStatuslineResult = results.find((r) => statuslineRuntimes.includes(r.runtime));
|
|
8688
|
+
async function installForClaude(isGlobal, isInteractive) {
|
|
8689
|
+
const result = await install(isGlobal);
|
|
9611
8690
|
let shouldInstallStatusline = false;
|
|
9612
|
-
if (
|
|
8691
|
+
if (result.settings) shouldInstallStatusline = await handleStatusline(result.settings, isInteractive, forceStatusline);
|
|
9613
8692
|
let enableAgentTeams = false;
|
|
9614
|
-
if (isInteractive
|
|
9615
|
-
|
|
9616
|
-
const
|
|
9617
|
-
|
|
9618
|
-
|
|
9619
|
-
env["CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS"] = "1";
|
|
9620
|
-
result.settings.env = env;
|
|
9621
|
-
}
|
|
9622
|
-
finishInstall(result.settingsPath, result.settings, result.statuslineCommand, useStatusline, result.runtime, isGlobal);
|
|
8693
|
+
if (isInteractive) enableAgentTeams = await promptAgentTeams();
|
|
8694
|
+
if (enableAgentTeams && result.settings) {
|
|
8695
|
+
const env = result.settings.env ?? {};
|
|
8696
|
+
env["CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS"] = "1";
|
|
8697
|
+
result.settings.env = env;
|
|
9623
8698
|
}
|
|
8699
|
+
finishInstall(result.settingsPath, result.settings, result.statuslineCommand, shouldInstallStatusline, isGlobal);
|
|
9624
8700
|
}
|
|
9625
8701
|
const subcommand = argv._[0];
|
|
9626
8702
|
(async () => {
|
|
@@ -9628,6 +8704,27 @@ const subcommand = argv._[0];
|
|
|
9628
8704
|
await runDashboardSubcommand(argv);
|
|
9629
8705
|
return;
|
|
9630
8706
|
}
|
|
8707
|
+
if (subcommand === "skill-list" || subcommand === "skill-install" || subcommand === "skill-update") {
|
|
8708
|
+
const { cmdSkillList, cmdSkillInstall, cmdSkillUpdate } = await Promise.resolve().then(() => require("./skills-BOSxYUzf.cjs"));
|
|
8709
|
+
const { CliOutput, writeOutput, CliError } = await Promise.resolve().then(() => require("./core-TFSlUjV1.cjs"));
|
|
8710
|
+
const cwd = process.cwd();
|
|
8711
|
+
try {
|
|
8712
|
+
if (subcommand === "skill-list") cmdSkillList(cwd, false);
|
|
8713
|
+
else if (subcommand === "skill-install") cmdSkillInstall(cwd, argv._[1], false);
|
|
8714
|
+
else if (subcommand === "skill-update") cmdSkillUpdate(cwd, argv._[1], false);
|
|
8715
|
+
} catch (thrown) {
|
|
8716
|
+
if (thrown instanceof CliOutput) {
|
|
8717
|
+
writeOutput(thrown);
|
|
8718
|
+
process.exit(0);
|
|
8719
|
+
}
|
|
8720
|
+
if (thrown instanceof CliError) {
|
|
8721
|
+
console.error("Error: " + thrown.message);
|
|
8722
|
+
process.exit(1);
|
|
8723
|
+
}
|
|
8724
|
+
throw thrown;
|
|
8725
|
+
}
|
|
8726
|
+
return;
|
|
8727
|
+
}
|
|
9631
8728
|
if (hasGlobal && hasLocal) {
|
|
9632
8729
|
console.error(chalk.yellow("Cannot specify both --global and --local"));
|
|
9633
8730
|
process.exit(1);
|
|
@@ -9639,20 +8736,12 @@ const subcommand = argv._[0];
|
|
|
9639
8736
|
console.error(chalk.yellow("--uninstall requires --global or --local"));
|
|
9640
8737
|
process.exit(1);
|
|
9641
8738
|
}
|
|
9642
|
-
|
|
9643
|
-
|
|
9644
|
-
} else if (selectedRuntimes.length > 0) if (!hasGlobal && !hasLocal) {
|
|
9645
|
-
const isGlobal = await promptLocation(selectedRuntimes);
|
|
9646
|
-
await installAllRuntimes(selectedRuntimes, isGlobal, true);
|
|
9647
|
-
} else await installAllRuntimes(selectedRuntimes, hasGlobal, false);
|
|
9648
|
-
else if (hasGlobal || hasLocal) await installAllRuntimes(["claude"], hasGlobal, false);
|
|
8739
|
+
uninstall(hasGlobal, explicitConfigDir);
|
|
8740
|
+
} else if (hasGlobal || hasLocal) await installForClaude(hasGlobal, false);
|
|
9649
8741
|
else if (!process.stdin.isTTY) {
|
|
9650
|
-
console.log(chalk.yellow("Non-interactive terminal detected, defaulting to
|
|
9651
|
-
await
|
|
9652
|
-
} else
|
|
9653
|
-
const runtimes = await promptRuntime();
|
|
9654
|
-
await installAllRuntimes(runtimes, await promptLocation(runtimes), true);
|
|
9655
|
-
}
|
|
8742
|
+
console.log(chalk.yellow("Non-interactive terminal detected, defaulting to global install") + "\n");
|
|
8743
|
+
await installForClaude(true, false);
|
|
8744
|
+
} else await installForClaude(await promptLocation(), true);
|
|
9656
8745
|
})().catch((err) => {
|
|
9657
8746
|
if (err instanceof Error && err.message.includes("User force closed")) {
|
|
9658
8747
|
console.log("\n" + chalk.yellow("Installation cancelled") + "\n");
|
|
@@ -9663,4 +8752,6 @@ const subcommand = argv._[0];
|
|
|
9663
8752
|
});
|
|
9664
8753
|
|
|
9665
8754
|
//#endregion
|
|
8755
|
+
exports.__commonJSMin = __commonJSMin;
|
|
8756
|
+
exports.__toESM = __toESM;
|
|
9666
8757
|
//# sourceMappingURL=install.cjs.map
|