dlw-machine-setup 0.5.17 → 0.6.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/bin/installer.js +497 -232
- package/package.json +1 -1
package/bin/installer.js
CHANGED
|
@@ -2753,13 +2753,13 @@ var PromisePolyfill = class extends Promise {
|
|
|
2753
2753
|
// Available starting from Node 22
|
|
2754
2754
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers
|
|
2755
2755
|
static withResolver() {
|
|
2756
|
-
let
|
|
2756
|
+
let resolve5;
|
|
2757
2757
|
let reject;
|
|
2758
2758
|
const promise = new Promise((res, rej) => {
|
|
2759
|
-
|
|
2759
|
+
resolve5 = res;
|
|
2760
2760
|
reject = rej;
|
|
2761
2761
|
});
|
|
2762
|
-
return { promise, resolve:
|
|
2762
|
+
return { promise, resolve: resolve5, reject };
|
|
2763
2763
|
}
|
|
2764
2764
|
};
|
|
2765
2765
|
|
|
@@ -2776,7 +2776,7 @@ function createPrompt(view) {
|
|
|
2776
2776
|
output
|
|
2777
2777
|
});
|
|
2778
2778
|
const screen = new ScreenManager(rl);
|
|
2779
|
-
const { promise, resolve:
|
|
2779
|
+
const { promise, resolve: resolve5, reject } = PromisePolyfill.withResolver();
|
|
2780
2780
|
const cancel = () => reject(new CancelPromptError());
|
|
2781
2781
|
if (signal) {
|
|
2782
2782
|
const abort = () => reject(new AbortPromptError({ cause: signal.reason }));
|
|
@@ -2800,7 +2800,7 @@ function createPrompt(view) {
|
|
|
2800
2800
|
cycle(() => {
|
|
2801
2801
|
try {
|
|
2802
2802
|
const nextView = view(config, (value) => {
|
|
2803
|
-
setImmediate(() =>
|
|
2803
|
+
setImmediate(() => resolve5(value));
|
|
2804
2804
|
});
|
|
2805
2805
|
const [content, bottomContent] = typeof nextView === "string" ? [nextView] : nextView;
|
|
2806
2806
|
screen.render(content, bottomContent);
|
|
@@ -3244,9 +3244,9 @@ ${page}${helpTipBottom}${choiceDescription}${import_ansi_escapes3.default.cursor
|
|
|
3244
3244
|
});
|
|
3245
3245
|
|
|
3246
3246
|
// src/index.ts
|
|
3247
|
-
var
|
|
3247
|
+
var import_fs9 = require("fs");
|
|
3248
3248
|
var import_readline = require("readline");
|
|
3249
|
-
var
|
|
3249
|
+
var import_path9 = require("path");
|
|
3250
3250
|
|
|
3251
3251
|
// src/utils/fetch.ts
|
|
3252
3252
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
@@ -3283,7 +3283,7 @@ async function fetchWithRetry(url, options = {}, maxRetries = DEFAULT_MAX_RETRIE
|
|
|
3283
3283
|
}
|
|
3284
3284
|
if (attempt < maxRetries) {
|
|
3285
3285
|
const delay = retryDelayMs * Math.pow(2, attempt - 1);
|
|
3286
|
-
await new Promise((
|
|
3286
|
+
await new Promise((resolve5) => setTimeout(resolve5, delay));
|
|
3287
3287
|
}
|
|
3288
3288
|
}
|
|
3289
3289
|
throw lastError || new Error("Failed after maximum retries");
|
|
@@ -3451,7 +3451,7 @@ async function pollForToken(deviceCode, interval) {
|
|
|
3451
3451
|
const maxAttempts = 60;
|
|
3452
3452
|
let attempts = 0;
|
|
3453
3453
|
while (attempts < maxAttempts) {
|
|
3454
|
-
await new Promise((
|
|
3454
|
+
await new Promise((resolve5) => setTimeout(resolve5, interval * 1e3));
|
|
3455
3455
|
const response = await fetchWithTimeout(GITHUB_TOKEN_URL, {
|
|
3456
3456
|
method: "POST",
|
|
3457
3457
|
headers: {
|
|
@@ -3577,6 +3577,31 @@ function buildMCPConfiguration(selectedItems, baseMcpServers, allMcpServers) {
|
|
|
3577
3577
|
return config;
|
|
3578
3578
|
}
|
|
3579
3579
|
|
|
3580
|
+
// src/utils/agent-targets.ts
|
|
3581
|
+
var AGENT_TARGETS = {
|
|
3582
|
+
"claude-code": {
|
|
3583
|
+
instructions: "CLAUDE.md",
|
|
3584
|
+
mcpConfig: ".mcp.json",
|
|
3585
|
+
mcpRootKey: "mcpServers",
|
|
3586
|
+
mcpDir: null
|
|
3587
|
+
},
|
|
3588
|
+
"github-copilot": {
|
|
3589
|
+
instructions: ".github/copilot-instructions.md",
|
|
3590
|
+
mcpConfig: ".vscode/mcp.json",
|
|
3591
|
+
mcpRootKey: "servers",
|
|
3592
|
+
mcpDir: ".vscode"
|
|
3593
|
+
},
|
|
3594
|
+
"cursor": {
|
|
3595
|
+
instructions: ".cursor/rules/instructions.mdc",
|
|
3596
|
+
mcpConfig: ".cursor/mcp.json",
|
|
3597
|
+
mcpRootKey: "mcpServers",
|
|
3598
|
+
mcpDir: ".cursor"
|
|
3599
|
+
}
|
|
3600
|
+
};
|
|
3601
|
+
function getAgentTarget(agent) {
|
|
3602
|
+
return AGENT_TARGETS[agent] ?? AGENT_TARGETS["claude-code"];
|
|
3603
|
+
}
|
|
3604
|
+
|
|
3580
3605
|
// src/utils/mod.ts
|
|
3581
3606
|
async function loadWizardOptions(token, repo) {
|
|
3582
3607
|
const remote = await fetchWizardOptions(token, repo);
|
|
@@ -3638,6 +3663,7 @@ var steps_exports = {};
|
|
|
3638
3663
|
__export(steps_exports, {
|
|
3639
3664
|
fetchContexts: () => fetch_contexts_default,
|
|
3640
3665
|
fetchFactory: () => fetch_factory_default,
|
|
3666
|
+
runMcpInstallCommands: () => run_mcp_install_commands_default,
|
|
3641
3667
|
updateGitignore: () => update_gitignore_default,
|
|
3642
3668
|
writeInstructions: () => write_instructions_default,
|
|
3643
3669
|
writeMcpConfig: () => write_mcp_config_default,
|
|
@@ -3810,9 +3836,204 @@ function getReadableError(status) {
|
|
|
3810
3836
|
}
|
|
3811
3837
|
|
|
3812
3838
|
// src/steps/resources/fetch-factory.ts
|
|
3839
|
+
var import_fs4 = require("fs");
|
|
3840
|
+
var import_path4 = require("path");
|
|
3841
|
+
var import_child_process3 = require("child_process");
|
|
3842
|
+
|
|
3843
|
+
// src/bundles/run-bundle.ts
|
|
3813
3844
|
var import_fs3 = require("fs");
|
|
3814
3845
|
var import_path3 = require("path");
|
|
3815
|
-
|
|
3846
|
+
|
|
3847
|
+
// src/bundles/types.ts
|
|
3848
|
+
var SCHEMA_VERSION = 1;
|
|
3849
|
+
|
|
3850
|
+
// src/bundles/run-bundle.ts
|
|
3851
|
+
var OWNER_KEY = "_bundleOwner";
|
|
3852
|
+
async function runBundle(manifest, ctx) {
|
|
3853
|
+
assertSchemaCompatible(manifest);
|
|
3854
|
+
assertBundleRootExists(ctx);
|
|
3855
|
+
const result = {
|
|
3856
|
+
name: manifest.name,
|
|
3857
|
+
opsExecuted: 0,
|
|
3858
|
+
filesTouched: []
|
|
3859
|
+
};
|
|
3860
|
+
const ops = manifest.targets?.[ctx.agent] ?? [];
|
|
3861
|
+
for (const op of ops) {
|
|
3862
|
+
executeOp(op, manifest.name, ctx, result);
|
|
3863
|
+
result.opsExecuted++;
|
|
3864
|
+
}
|
|
3865
|
+
if (manifest.gitignore?.length) {
|
|
3866
|
+
upsertMarkerBlock(
|
|
3867
|
+
(0, import_path3.join)(ctx.projectPath, ".gitignore"),
|
|
3868
|
+
`# ${manifest.name}:start`,
|
|
3869
|
+
`# ${manifest.name}:end`,
|
|
3870
|
+
manifest.gitignore.join("\n")
|
|
3871
|
+
);
|
|
3872
|
+
result.filesTouched.push(".gitignore");
|
|
3873
|
+
}
|
|
3874
|
+
const snippet = manifest.instructions?.[ctx.agent];
|
|
3875
|
+
if (snippet) {
|
|
3876
|
+
result.instructionsSnippet = snippet;
|
|
3877
|
+
if (!ctx.skipInstructions) {
|
|
3878
|
+
upsertMarkerBlock(
|
|
3879
|
+
(0, import_path3.join)(ctx.projectPath, ctx.instructionsFile),
|
|
3880
|
+
`<!-- ${manifest.name}:start -->`,
|
|
3881
|
+
`<!-- ${manifest.name}:end -->`,
|
|
3882
|
+
snippet
|
|
3883
|
+
);
|
|
3884
|
+
result.filesTouched.push(ctx.instructionsFile);
|
|
3885
|
+
}
|
|
3886
|
+
}
|
|
3887
|
+
return result;
|
|
3888
|
+
}
|
|
3889
|
+
function executeOp(op, owner, ctx, result) {
|
|
3890
|
+
switch (op.op) {
|
|
3891
|
+
case "copy":
|
|
3892
|
+
return runCopy(op, ctx, result);
|
|
3893
|
+
case "merge-json":
|
|
3894
|
+
return runMergeJson(op, owner, ctx, result);
|
|
3895
|
+
default: {
|
|
3896
|
+
const unknown = op.op;
|
|
3897
|
+
throw new Error(
|
|
3898
|
+
`Bundle "${owner}" uses unknown op "${unknown}". Installer supports: copy, merge-json. Upgrade the installer or check the bundle's schemaVersion.`
|
|
3899
|
+
);
|
|
3900
|
+
}
|
|
3901
|
+
}
|
|
3902
|
+
}
|
|
3903
|
+
function runCopy(op, ctx, result) {
|
|
3904
|
+
const source = resolveBundlePath(op.from, ctx);
|
|
3905
|
+
const target = resolveProjectPath(op.to, ctx);
|
|
3906
|
+
if (!(0, import_fs3.existsSync)(source)) return;
|
|
3907
|
+
if ((0, import_fs3.statSync)(source).isDirectory()) {
|
|
3908
|
+
copyDirectory2(source, target);
|
|
3909
|
+
} else {
|
|
3910
|
+
(0, import_fs3.mkdirSync)((0, import_path3.dirname)(target), { recursive: true });
|
|
3911
|
+
(0, import_fs3.copyFileSync)(source, target);
|
|
3912
|
+
}
|
|
3913
|
+
result.filesTouched.push(op.to);
|
|
3914
|
+
}
|
|
3915
|
+
function runMergeJson(op, owner, ctx, result) {
|
|
3916
|
+
const filePath = resolveProjectPath(op.file, ctx);
|
|
3917
|
+
const existing = readJsonOrEmpty(filePath);
|
|
3918
|
+
const stripped = stripOwnedEntries(existing, owner);
|
|
3919
|
+
const tagged = tagEntries(op.patch, owner);
|
|
3920
|
+
const merged = deepMerge2(stripped, tagged);
|
|
3921
|
+
(0, import_fs3.mkdirSync)((0, import_path3.dirname)(filePath), { recursive: true });
|
|
3922
|
+
(0, import_fs3.writeFileSync)(filePath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
3923
|
+
result.filesTouched.push(op.file);
|
|
3924
|
+
}
|
|
3925
|
+
function readJsonOrEmpty(path) {
|
|
3926
|
+
if (!(0, import_fs3.existsSync)(path)) return {};
|
|
3927
|
+
try {
|
|
3928
|
+
return JSON.parse((0, import_fs3.readFileSync)(path, "utf-8"));
|
|
3929
|
+
} catch {
|
|
3930
|
+
return {};
|
|
3931
|
+
}
|
|
3932
|
+
}
|
|
3933
|
+
function isPlainObject2(v) {
|
|
3934
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
3935
|
+
}
|
|
3936
|
+
function tagEntries(value, owner) {
|
|
3937
|
+
if (Array.isArray(value)) {
|
|
3938
|
+
return value.map(
|
|
3939
|
+
(item) => isPlainObject2(item) ? { ...item, [OWNER_KEY]: owner } : item
|
|
3940
|
+
);
|
|
3941
|
+
}
|
|
3942
|
+
if (isPlainObject2(value)) {
|
|
3943
|
+
return Object.fromEntries(
|
|
3944
|
+
Object.entries(value).map(([k, v]) => [k, tagEntries(v, owner)])
|
|
3945
|
+
);
|
|
3946
|
+
}
|
|
3947
|
+
return value;
|
|
3948
|
+
}
|
|
3949
|
+
function stripOwnedEntries(value, owner) {
|
|
3950
|
+
if (Array.isArray(value)) {
|
|
3951
|
+
return value.filter((item) => !(isPlainObject2(item) && item[OWNER_KEY] === owner)).map((item) => stripOwnedEntries(item, owner));
|
|
3952
|
+
}
|
|
3953
|
+
if (isPlainObject2(value)) {
|
|
3954
|
+
return Object.fromEntries(
|
|
3955
|
+
Object.entries(value).map(([k, v]) => [k, stripOwnedEntries(v, owner)])
|
|
3956
|
+
);
|
|
3957
|
+
}
|
|
3958
|
+
return value;
|
|
3959
|
+
}
|
|
3960
|
+
function deepMerge2(a, b) {
|
|
3961
|
+
if (isPlainObject2(a) && isPlainObject2(b)) {
|
|
3962
|
+
const out = { ...a };
|
|
3963
|
+
for (const [k, v] of Object.entries(b)) {
|
|
3964
|
+
out[k] = k in a ? deepMerge2(a[k], v) : v;
|
|
3965
|
+
}
|
|
3966
|
+
return out;
|
|
3967
|
+
}
|
|
3968
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
3969
|
+
return [...a, ...b];
|
|
3970
|
+
}
|
|
3971
|
+
return b;
|
|
3972
|
+
}
|
|
3973
|
+
function upsertMarkerBlock(filePath, startMarker, endMarker, body) {
|
|
3974
|
+
const block = `${startMarker}
|
|
3975
|
+
${body}
|
|
3976
|
+
${endMarker}`;
|
|
3977
|
+
(0, import_fs3.mkdirSync)((0, import_path3.dirname)(filePath), { recursive: true });
|
|
3978
|
+
if (!(0, import_fs3.existsSync)(filePath)) {
|
|
3979
|
+
(0, import_fs3.writeFileSync)(filePath, block + "\n", "utf-8");
|
|
3980
|
+
return;
|
|
3981
|
+
}
|
|
3982
|
+
const existing = (0, import_fs3.readFileSync)(filePath, "utf-8");
|
|
3983
|
+
const s = existing.indexOf(startMarker);
|
|
3984
|
+
const e = existing.indexOf(endMarker);
|
|
3985
|
+
if (s !== -1 && e !== -1 && e > s) {
|
|
3986
|
+
const updated = existing.slice(0, s) + block + existing.slice(e + endMarker.length);
|
|
3987
|
+
(0, import_fs3.writeFileSync)(filePath, updated, "utf-8");
|
|
3988
|
+
} else {
|
|
3989
|
+
const joiner = existing.endsWith("\n") ? "\n" : "\n\n";
|
|
3990
|
+
(0, import_fs3.writeFileSync)(filePath, existing + joiner + block + "\n", "utf-8");
|
|
3991
|
+
}
|
|
3992
|
+
}
|
|
3993
|
+
function resolveBundlePath(rel, ctx) {
|
|
3994
|
+
const base = (0, import_path3.resolve)(ctx.bundleRoot);
|
|
3995
|
+
const full = (0, import_path3.resolve)((0, import_path3.join)(base, rel));
|
|
3996
|
+
if (full !== base && !full.startsWith(base + import_path3.sep)) {
|
|
3997
|
+
throw new Error(`Bundle op "from" escapes bundle root: ${rel}`);
|
|
3998
|
+
}
|
|
3999
|
+
return full;
|
|
4000
|
+
}
|
|
4001
|
+
function resolveProjectPath(rel, ctx) {
|
|
4002
|
+
const base = (0, import_path3.resolve)(ctx.projectPath);
|
|
4003
|
+
const full = (0, import_path3.resolve)((0, import_path3.join)(base, rel));
|
|
4004
|
+
if (full !== base && !full.startsWith(base + import_path3.sep)) {
|
|
4005
|
+
throw new Error(`Bundle op "to" escapes project path: ${rel}`);
|
|
4006
|
+
}
|
|
4007
|
+
return full;
|
|
4008
|
+
}
|
|
4009
|
+
function assertSchemaCompatible(manifest) {
|
|
4010
|
+
if (manifest.schemaVersion !== SCHEMA_VERSION) {
|
|
4011
|
+
throw new Error(
|
|
4012
|
+
`Bundle "${manifest.name}" declares schemaVersion ${manifest.schemaVersion}, installer supports ${SCHEMA_VERSION}. Upgrade the installer or re-pin the bundle.`
|
|
4013
|
+
);
|
|
4014
|
+
}
|
|
4015
|
+
if (!manifest.name || !/^[a-z][a-z0-9-]*$/.test(manifest.name)) {
|
|
4016
|
+
throw new Error(
|
|
4017
|
+
`Bundle name must match /^[a-z][a-z0-9-]*$/: got "${manifest.name}"`
|
|
4018
|
+
);
|
|
4019
|
+
}
|
|
4020
|
+
}
|
|
4021
|
+
function assertBundleRootExists(ctx) {
|
|
4022
|
+
if (!(0, import_fs3.existsSync)(ctx.bundleRoot) || !(0, import_fs3.statSync)(ctx.bundleRoot).isDirectory()) {
|
|
4023
|
+
throw new Error(`Bundle root not found or not a directory: ${ctx.bundleRoot}`);
|
|
4024
|
+
}
|
|
4025
|
+
}
|
|
4026
|
+
function copyDirectory2(source, target) {
|
|
4027
|
+
if (!(0, import_fs3.existsSync)(target)) (0, import_fs3.mkdirSync)(target, { recursive: true });
|
|
4028
|
+
for (const entry of (0, import_fs3.readdirSync)(source, { withFileTypes: true })) {
|
|
4029
|
+
const s = (0, import_path3.join)(source, entry.name);
|
|
4030
|
+
const t = (0, import_path3.join)(target, entry.name);
|
|
4031
|
+
if (entry.isDirectory()) copyDirectory2(s, t);
|
|
4032
|
+
else (0, import_fs3.copyFileSync)(s, t);
|
|
4033
|
+
}
|
|
4034
|
+
}
|
|
4035
|
+
|
|
4036
|
+
// src/steps/resources/fetch-factory.ts
|
|
3816
4037
|
var MIN_FILE_SIZE2 = 1024;
|
|
3817
4038
|
function getFactoryAsset(agent) {
|
|
3818
4039
|
switch (agent) {
|
|
@@ -3829,10 +4050,17 @@ var fetch_factory_default = defineStep({
|
|
|
3829
4050
|
execute: async (ctx) => {
|
|
3830
4051
|
const result = await fetchFactory(ctx.token, ctx.factoryRepo, ctx.config.projectPath, ctx.config.agent);
|
|
3831
4052
|
ctx.installed.factoryInstalled = result.success;
|
|
4053
|
+
ctx.installed.factoryBundleManaged = result.bundleManaged ?? false;
|
|
4054
|
+
if (result.instructionsSnippet) {
|
|
4055
|
+
const stash = ctx.installed.bundleInstructions ?? {};
|
|
4056
|
+
stash["factory"] = result.instructionsSnippet;
|
|
4057
|
+
ctx.installed.bundleInstructions = stash;
|
|
4058
|
+
}
|
|
3832
4059
|
if (!result.success) {
|
|
3833
4060
|
return { status: "failed", detail: result.failureReason };
|
|
3834
4061
|
}
|
|
3835
|
-
|
|
4062
|
+
const tag = result.bundleManaged ? " (bundle)" : "";
|
|
4063
|
+
return { status: "success", message: result.filesInstalled.join(", ") + tag };
|
|
3836
4064
|
}
|
|
3837
4065
|
});
|
|
3838
4066
|
async function fetchFactory(token, repo, targetDir, agent) {
|
|
@@ -3861,10 +4089,10 @@ async function fetchFactory(token, repo, targetDir, agent) {
|
|
|
3861
4089
|
result.failureReason = `${assetName} not found in release`;
|
|
3862
4090
|
return result;
|
|
3863
4091
|
}
|
|
3864
|
-
const tempDir = (0,
|
|
4092
|
+
const tempDir = (0, import_path4.join)(targetDir, ".temp-factory-download");
|
|
3865
4093
|
try {
|
|
3866
|
-
if ((0,
|
|
3867
|
-
(0,
|
|
4094
|
+
if ((0, import_fs4.existsSync)(tempDir)) (0, import_fs4.rmSync)(tempDir, { recursive: true, force: true });
|
|
4095
|
+
(0, import_fs4.mkdirSync)(tempDir, { recursive: true });
|
|
3868
4096
|
const response = await fetchWithRetry(asset.url, {
|
|
3869
4097
|
headers: { "Accept": "application/octet-stream", "Authorization": `Bearer ${token}` }
|
|
3870
4098
|
});
|
|
@@ -3872,10 +4100,10 @@ async function fetchFactory(token, repo, targetDir, agent) {
|
|
|
3872
4100
|
result.failureReason = `Download failed (${response.status})`;
|
|
3873
4101
|
return result;
|
|
3874
4102
|
}
|
|
3875
|
-
const archivePath = (0,
|
|
4103
|
+
const archivePath = (0, import_path4.join)(tempDir, assetName);
|
|
3876
4104
|
const arrayBuffer = await response.arrayBuffer();
|
|
3877
|
-
(0,
|
|
3878
|
-
const stats = (0,
|
|
4105
|
+
(0, import_fs4.writeFileSync)(archivePath, Buffer.from(arrayBuffer));
|
|
4106
|
+
const stats = (0, import_fs4.statSync)(archivePath);
|
|
3879
4107
|
if (stats.size < MIN_FILE_SIZE2) {
|
|
3880
4108
|
result.failureReason = "Downloaded file corrupted (too small)";
|
|
3881
4109
|
return result;
|
|
@@ -3885,10 +4113,10 @@ async function fetchFactory(token, repo, targetDir, agent) {
|
|
|
3885
4113
|
result.failureReason = "Failed to read archive contents";
|
|
3886
4114
|
return result;
|
|
3887
4115
|
}
|
|
3888
|
-
const resolvedTempDir = (0,
|
|
4116
|
+
const resolvedTempDir = (0, import_path4.resolve)(tempDir);
|
|
3889
4117
|
for (const entry of listResult.stdout.split("\n").filter(Boolean)) {
|
|
3890
|
-
const entryPath = (0,
|
|
3891
|
-
if (!entryPath.startsWith(resolvedTempDir +
|
|
4118
|
+
const entryPath = (0, import_path4.resolve)((0, import_path4.join)(tempDir, entry.replace(/\/$/, "")));
|
|
4119
|
+
if (!entryPath.startsWith(resolvedTempDir + import_path4.sep)) {
|
|
3892
4120
|
result.failureReason = `Archive contains unsafe path: ${entry}`;
|
|
3893
4121
|
return result;
|
|
3894
4122
|
}
|
|
@@ -3898,14 +4126,17 @@ async function fetchFactory(token, repo, targetDir, agent) {
|
|
|
3898
4126
|
result.failureReason = "Archive extraction failed";
|
|
3899
4127
|
return result;
|
|
3900
4128
|
}
|
|
3901
|
-
const extractedEntries = (0,
|
|
4129
|
+
const extractedEntries = (0, import_fs4.readdirSync)(tempDir);
|
|
3902
4130
|
const extractedFolder = extractedEntries.find((e) => e.toLowerCase() === rootFolder.toLowerCase());
|
|
3903
4131
|
if (!extractedFolder) {
|
|
3904
4132
|
result.failureReason = `No ${rootFolder}/ folder in archive`;
|
|
3905
4133
|
return result;
|
|
3906
4134
|
}
|
|
3907
|
-
const extractedPath = (0,
|
|
3908
|
-
|
|
4135
|
+
const extractedPath = (0, import_path4.join)(tempDir, extractedFolder);
|
|
4136
|
+
const manifestPath = (0, import_path4.join)(extractedPath, "install.json");
|
|
4137
|
+
if ((0, import_fs4.existsSync)(manifestPath)) {
|
|
4138
|
+
await installViaBundle(manifestPath, extractedPath, targetDir, agent, result);
|
|
4139
|
+
} else if (agent === "github-copilot") {
|
|
3909
4140
|
installCopilotFactory(extractedPath, targetDir, result);
|
|
3910
4141
|
} else {
|
|
3911
4142
|
installClaudeFactory(extractedPath, targetDir, result);
|
|
@@ -3914,53 +4145,73 @@ async function fetchFactory(token, repo, targetDir, agent) {
|
|
|
3914
4145
|
} catch (error) {
|
|
3915
4146
|
result.failureReason = error instanceof Error ? error.message : String(error);
|
|
3916
4147
|
} finally {
|
|
3917
|
-
if ((0,
|
|
4148
|
+
if ((0, import_fs4.existsSync)(tempDir)) {
|
|
3918
4149
|
try {
|
|
3919
|
-
(0,
|
|
4150
|
+
(0, import_fs4.rmSync)(tempDir, { recursive: true, force: true });
|
|
3920
4151
|
} catch {
|
|
3921
4152
|
}
|
|
3922
4153
|
}
|
|
3923
4154
|
}
|
|
3924
4155
|
return result;
|
|
3925
4156
|
}
|
|
4157
|
+
async function installViaBundle(manifestPath, extractedPath, targetDir, agent, result) {
|
|
4158
|
+
let manifest;
|
|
4159
|
+
try {
|
|
4160
|
+
manifest = JSON.parse((0, import_fs4.readFileSync)(manifestPath, "utf-8"));
|
|
4161
|
+
} catch (e) {
|
|
4162
|
+
throw new Error(`install.json is not valid JSON: ${e instanceof Error ? e.message : String(e)}`);
|
|
4163
|
+
}
|
|
4164
|
+
const target = getAgentTarget(agent);
|
|
4165
|
+
const runResult = await runBundle(manifest, {
|
|
4166
|
+
bundleRoot: extractedPath,
|
|
4167
|
+
projectPath: targetDir,
|
|
4168
|
+
agent,
|
|
4169
|
+
instructionsFile: target.instructions,
|
|
4170
|
+
skipInstructions: true
|
|
4171
|
+
// write-instructions.ts commits the snippet for correct ordering
|
|
4172
|
+
});
|
|
4173
|
+
result.bundleManaged = true;
|
|
4174
|
+
result.instructionsSnippet = runResult.instructionsSnippet;
|
|
4175
|
+
result.filesInstalled = runResult.filesTouched;
|
|
4176
|
+
}
|
|
3926
4177
|
function installClaudeFactory(extractedPath, targetDir, result) {
|
|
3927
|
-
const claudeDir = (0,
|
|
3928
|
-
const factoryDir = (0,
|
|
3929
|
-
const agentsSrc = (0,
|
|
3930
|
-
if ((0,
|
|
3931
|
-
|
|
4178
|
+
const claudeDir = (0, import_path4.join)(targetDir, ".claude");
|
|
4179
|
+
const factoryDir = (0, import_path4.join)(targetDir, "factory");
|
|
4180
|
+
const agentsSrc = (0, import_path4.join)(extractedPath, "agents");
|
|
4181
|
+
if ((0, import_fs4.existsSync)(agentsSrc)) {
|
|
4182
|
+
copyDirectory3(agentsSrc, (0, import_path4.join)(claudeDir, "agents"));
|
|
3932
4183
|
result.filesInstalled.push(".claude/agents/");
|
|
3933
4184
|
}
|
|
3934
|
-
const hooksSrc = (0,
|
|
3935
|
-
if ((0,
|
|
3936
|
-
|
|
4185
|
+
const hooksSrc = (0, import_path4.join)(extractedPath, "hooks");
|
|
4186
|
+
if ((0, import_fs4.existsSync)(hooksSrc)) {
|
|
4187
|
+
copyDirectory3(hooksSrc, (0, import_path4.join)(claudeDir, "hooks"));
|
|
3937
4188
|
result.filesInstalled.push(".claude/hooks/");
|
|
3938
4189
|
}
|
|
3939
|
-
const skillsSrc = (0,
|
|
3940
|
-
if ((0,
|
|
3941
|
-
|
|
4190
|
+
const skillsSrc = (0, import_path4.join)(extractedPath, "skills");
|
|
4191
|
+
if ((0, import_fs4.existsSync)(skillsSrc)) {
|
|
4192
|
+
copyDirectory3(skillsSrc, (0, import_path4.join)(claudeDir, "skills"));
|
|
3942
4193
|
result.filesInstalled.push(".claude/skills/");
|
|
3943
4194
|
}
|
|
3944
|
-
const workflowSrc = (0,
|
|
3945
|
-
if ((0,
|
|
3946
|
-
|
|
4195
|
+
const workflowSrc = (0, import_path4.join)(extractedPath, "workflow");
|
|
4196
|
+
if ((0, import_fs4.existsSync)(workflowSrc)) {
|
|
4197
|
+
copyDirectory3(workflowSrc, (0, import_path4.join)(factoryDir, "workflow"));
|
|
3947
4198
|
result.filesInstalled.push("factory/workflow/");
|
|
3948
4199
|
}
|
|
3949
|
-
const utilsSrc = (0,
|
|
3950
|
-
if ((0,
|
|
3951
|
-
|
|
4200
|
+
const utilsSrc = (0, import_path4.join)(extractedPath, "utils");
|
|
4201
|
+
if ((0, import_fs4.existsSync)(utilsSrc)) {
|
|
4202
|
+
copyDirectory3(utilsSrc, (0, import_path4.join)(factoryDir, "utils"));
|
|
3952
4203
|
result.filesInstalled.push("factory/utils/");
|
|
3953
4204
|
}
|
|
3954
|
-
const docsSrc = (0,
|
|
3955
|
-
if ((0,
|
|
3956
|
-
|
|
4205
|
+
const docsSrc = (0, import_path4.join)(extractedPath, "docs");
|
|
4206
|
+
if ((0, import_fs4.existsSync)(docsSrc)) {
|
|
4207
|
+
copyDirectory3(docsSrc, (0, import_path4.join)(factoryDir, "docs"));
|
|
3957
4208
|
result.filesInstalled.push("factory/docs/");
|
|
3958
4209
|
}
|
|
3959
|
-
const rootEntries = (0,
|
|
4210
|
+
const rootEntries = (0, import_fs4.readdirSync)(extractedPath, { withFileTypes: true });
|
|
3960
4211
|
for (const entry of rootEntries) {
|
|
3961
4212
|
if (entry.isFile()) {
|
|
3962
|
-
if (!(0,
|
|
3963
|
-
(0,
|
|
4213
|
+
if (!(0, import_fs4.existsSync)(factoryDir)) (0, import_fs4.mkdirSync)(factoryDir, { recursive: true });
|
|
4214
|
+
(0, import_fs4.copyFileSync)((0, import_path4.join)(extractedPath, entry.name), (0, import_path4.join)(factoryDir, entry.name));
|
|
3964
4215
|
result.filesInstalled.push(`factory/${entry.name}`);
|
|
3965
4216
|
}
|
|
3966
4217
|
}
|
|
@@ -3968,9 +4219,9 @@ function installClaudeFactory(extractedPath, targetDir, result) {
|
|
|
3968
4219
|
result.filesInstalled.push(".claude/settings.json");
|
|
3969
4220
|
}
|
|
3970
4221
|
function installCopilotFactory(extractedPath, targetDir, result) {
|
|
3971
|
-
const factoryDir = (0,
|
|
3972
|
-
|
|
3973
|
-
const entries = (0,
|
|
4222
|
+
const factoryDir = (0, import_path4.join)(targetDir, "factory");
|
|
4223
|
+
copyDirectory3(extractedPath, factoryDir);
|
|
4224
|
+
const entries = (0, import_fs4.readdirSync)(extractedPath, { withFileTypes: true });
|
|
3974
4225
|
for (const entry of entries) {
|
|
3975
4226
|
if (entry.isDirectory()) {
|
|
3976
4227
|
result.filesInstalled.push(`factory/${entry.name}/`);
|
|
@@ -3980,11 +4231,11 @@ function installCopilotFactory(extractedPath, targetDir, result) {
|
|
|
3980
4231
|
}
|
|
3981
4232
|
}
|
|
3982
4233
|
function configureSettings(claudeDir) {
|
|
3983
|
-
const settingsPath = (0,
|
|
4234
|
+
const settingsPath = (0, import_path4.join)(claudeDir, "settings.json");
|
|
3984
4235
|
let settings = {};
|
|
3985
|
-
if ((0,
|
|
4236
|
+
if ((0, import_fs4.existsSync)(settingsPath)) {
|
|
3986
4237
|
try {
|
|
3987
|
-
settings = JSON.parse((0,
|
|
4238
|
+
settings = JSON.parse((0, import_fs4.readFileSync)(settingsPath, "utf8"));
|
|
3988
4239
|
} catch {
|
|
3989
4240
|
}
|
|
3990
4241
|
}
|
|
@@ -4035,26 +4286,26 @@ function configureSettings(claudeDir) {
|
|
|
4035
4286
|
if (!hasMonitor) settings.hooks.UserPromptSubmit.push(contextMonitorHook);
|
|
4036
4287
|
}
|
|
4037
4288
|
settings.statusLine = { type: "command", command: "node .claude/hooks/factory-statusline.cjs" };
|
|
4038
|
-
if (!(0,
|
|
4039
|
-
(0,
|
|
4289
|
+
if (!(0, import_fs4.existsSync)(claudeDir)) (0, import_fs4.mkdirSync)(claudeDir, { recursive: true });
|
|
4290
|
+
(0, import_fs4.writeFileSync)(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
4040
4291
|
}
|
|
4041
|
-
function
|
|
4042
|
-
if (!(0,
|
|
4043
|
-
const entries = (0,
|
|
4292
|
+
function copyDirectory3(source, target) {
|
|
4293
|
+
if (!(0, import_fs4.existsSync)(target)) (0, import_fs4.mkdirSync)(target, { recursive: true });
|
|
4294
|
+
const entries = (0, import_fs4.readdirSync)(source, { withFileTypes: true });
|
|
4044
4295
|
for (const entry of entries) {
|
|
4045
|
-
const sourcePath = (0,
|
|
4046
|
-
const targetPath = (0,
|
|
4296
|
+
const sourcePath = (0, import_path4.join)(source, entry.name);
|
|
4297
|
+
const targetPath = (0, import_path4.join)(target, entry.name);
|
|
4047
4298
|
if (entry.isDirectory()) {
|
|
4048
|
-
|
|
4299
|
+
copyDirectory3(sourcePath, targetPath);
|
|
4049
4300
|
} else {
|
|
4050
|
-
(0,
|
|
4301
|
+
(0, import_fs4.copyFileSync)(sourcePath, targetPath);
|
|
4051
4302
|
}
|
|
4052
4303
|
}
|
|
4053
4304
|
}
|
|
4054
4305
|
|
|
4055
4306
|
// src/steps/setup/write-instructions.ts
|
|
4056
|
-
var
|
|
4057
|
-
var
|
|
4307
|
+
var import_fs5 = require("fs");
|
|
4308
|
+
var import_path5 = require("path");
|
|
4058
4309
|
|
|
4059
4310
|
// src/steps/shared.ts
|
|
4060
4311
|
function getFilteredMcpConfig(ctx) {
|
|
@@ -4078,65 +4329,45 @@ var red = (text) => `\x1B[31m${text}\x1B[0m`;
|
|
|
4078
4329
|
var write_instructions_default = defineStep({
|
|
4079
4330
|
name: "write-instructions",
|
|
4080
4331
|
label: "Writing instruction file",
|
|
4081
|
-
when: (ctx) => (ctx.installed.domainsInstalled?.length ?? 0) > 0 || Object.keys(ctx.config.mcpConfig).length > 0 || ctx.installed.factoryInstalled,
|
|
4332
|
+
when: (ctx) => (ctx.installed.domainsInstalled?.length ?? 0) > 0 || Object.keys(ctx.config.mcpConfig).length > 0 || ctx.installed.factoryInstalled || Object.keys(ctx.installed.bundleInstructions ?? {}).length > 0,
|
|
4082
4333
|
execute: async (ctx) => {
|
|
4083
4334
|
const filteredMcpConfig = getFilteredMcpConfig(ctx);
|
|
4084
4335
|
const domains = ctx.installed.domainsInstalled ?? [];
|
|
4085
4336
|
const agent = ctx.config.agent;
|
|
4086
4337
|
const projectPath = ctx.config.projectPath;
|
|
4087
4338
|
const factoryInstalled = ctx.installed.factoryInstalled ?? false;
|
|
4088
|
-
const
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
upsertBlock((0, import_path4.join)(githubDir, "copilot-instructions.md"), content);
|
|
4098
|
-
break;
|
|
4099
|
-
}
|
|
4100
|
-
case "cursor": {
|
|
4101
|
-
const cursorDir = (0, import_path4.join)(projectPath, ".cursor", "rules");
|
|
4102
|
-
if (!(0, import_fs4.existsSync)(cursorDir)) (0, import_fs4.mkdirSync)(cursorDir, { recursive: true });
|
|
4103
|
-
const filePath = (0, import_path4.join)(cursorDir, "instructions.mdc");
|
|
4104
|
-
if (!(0, import_fs4.existsSync)(filePath)) {
|
|
4105
|
-
(0, import_fs4.writeFileSync)(filePath, `---
|
|
4339
|
+
const factoryBundleManaged = ctx.installed.factoryBundleManaged ?? false;
|
|
4340
|
+
const includeFactorySection = factoryInstalled && !factoryBundleManaged;
|
|
4341
|
+
const content = buildCombinedInstructions(domains, filteredMcpConfig, agent, projectPath, includeFactorySection);
|
|
4342
|
+
const target = getAgentTarget(agent);
|
|
4343
|
+
const filePath = (0, import_path5.join)(projectPath, target.instructions);
|
|
4344
|
+
const fileDir = (0, import_path5.dirname)(filePath);
|
|
4345
|
+
if (!(0, import_fs5.existsSync)(fileDir)) (0, import_fs5.mkdirSync)(fileDir, { recursive: true });
|
|
4346
|
+
if (agent === "cursor" && !(0, import_fs5.existsSync)(filePath)) {
|
|
4347
|
+
(0, import_fs5.writeFileSync)(filePath, `---
|
|
4106
4348
|
description: AI development instructions from One-Shot Installer
|
|
4107
4349
|
alwaysApply: true
|
|
4108
4350
|
---
|
|
4109
4351
|
|
|
4110
4352
|
`, "utf-8");
|
|
4111
|
-
}
|
|
4112
|
-
upsertBlock(filePath, content);
|
|
4113
|
-
break;
|
|
4114
|
-
}
|
|
4115
4353
|
}
|
|
4116
|
-
|
|
4354
|
+
upsertBlock(filePath, content);
|
|
4355
|
+
const bundleSnippets = ctx.installed.bundleInstructions ?? {};
|
|
4356
|
+
for (const bundleName of Object.keys(bundleSnippets).sort()) {
|
|
4357
|
+
upsertBundleBlock(filePath, bundleName, bundleSnippets[bundleName]);
|
|
4358
|
+
}
|
|
4359
|
+
return { status: "success", message: target.instructions };
|
|
4117
4360
|
}
|
|
4118
4361
|
});
|
|
4119
|
-
function getInstructionFilePath(agent) {
|
|
4120
|
-
switch (agent) {
|
|
4121
|
-
case "claude-code":
|
|
4122
|
-
return "CLAUDE.md";
|
|
4123
|
-
case "github-copilot":
|
|
4124
|
-
return ".github/copilot-instructions.md";
|
|
4125
|
-
case "cursor":
|
|
4126
|
-
return ".cursor/rules/instructions.mdc";
|
|
4127
|
-
default:
|
|
4128
|
-
return "CLAUDE.md";
|
|
4129
|
-
}
|
|
4130
|
-
}
|
|
4131
4362
|
function upsertBlock(filePath, block) {
|
|
4132
4363
|
const marked = `${MARKER_START}
|
|
4133
4364
|
${block}
|
|
4134
4365
|
${MARKER_END}`;
|
|
4135
|
-
if (!(0,
|
|
4136
|
-
(0,
|
|
4366
|
+
if (!(0, import_fs5.existsSync)(filePath)) {
|
|
4367
|
+
(0, import_fs5.writeFileSync)(filePath, marked, "utf-8");
|
|
4137
4368
|
return;
|
|
4138
4369
|
}
|
|
4139
|
-
const existing = (0,
|
|
4370
|
+
const existing = (0, import_fs5.readFileSync)(filePath, "utf-8");
|
|
4140
4371
|
const start = existing.indexOf(MARKER_START);
|
|
4141
4372
|
const end = existing.indexOf(MARKER_END);
|
|
4142
4373
|
const hasStart = start !== -1;
|
|
@@ -4161,23 +4392,44 @@ ${MARKER_END}`;
|
|
|
4161
4392
|
}
|
|
4162
4393
|
if (hasStart && hasEnd) {
|
|
4163
4394
|
const updated = existing.slice(0, start) + marked + existing.slice(end + MARKER_END.length);
|
|
4164
|
-
(0,
|
|
4395
|
+
(0, import_fs5.writeFileSync)(filePath, updated, "utf-8");
|
|
4165
4396
|
} else {
|
|
4166
4397
|
const separator = existing.endsWith("\n") ? "\n" : "\n\n";
|
|
4167
|
-
(0,
|
|
4398
|
+
(0, import_fs5.writeFileSync)(filePath, existing + separator + marked, "utf-8");
|
|
4399
|
+
}
|
|
4400
|
+
}
|
|
4401
|
+
function upsertBundleBlock(filePath, bundleName, snippet) {
|
|
4402
|
+
const startMarker = `<!-- ${bundleName}:start -->`;
|
|
4403
|
+
const endMarker = `<!-- ${bundleName}:end -->`;
|
|
4404
|
+
const block = `${startMarker}
|
|
4405
|
+
${snippet}
|
|
4406
|
+
${endMarker}`;
|
|
4407
|
+
if (!(0, import_fs5.existsSync)(filePath)) {
|
|
4408
|
+
(0, import_fs5.writeFileSync)(filePath, block + "\n", "utf-8");
|
|
4409
|
+
return;
|
|
4410
|
+
}
|
|
4411
|
+
const existing = (0, import_fs5.readFileSync)(filePath, "utf-8");
|
|
4412
|
+
const s = existing.indexOf(startMarker);
|
|
4413
|
+
const e = existing.indexOf(endMarker);
|
|
4414
|
+
if (s !== -1 && e !== -1 && e > s) {
|
|
4415
|
+
const updated = existing.slice(0, s) + block + existing.slice(e + endMarker.length);
|
|
4416
|
+
(0, import_fs5.writeFileSync)(filePath, updated, "utf-8");
|
|
4417
|
+
} else {
|
|
4418
|
+
const separator = existing.endsWith("\n") ? "\n" : "\n\n";
|
|
4419
|
+
(0, import_fs5.writeFileSync)(filePath, existing + separator + block + "\n", "utf-8");
|
|
4168
4420
|
}
|
|
4169
4421
|
}
|
|
4170
4422
|
function collectMdFiles(dir) {
|
|
4171
|
-
if (!(0,
|
|
4172
|
-
const entries = (0,
|
|
4423
|
+
if (!(0, import_fs5.existsSync)(dir)) return [];
|
|
4424
|
+
const entries = (0, import_fs5.readdirSync)(dir, { recursive: true });
|
|
4173
4425
|
return entries.filter((entry) => {
|
|
4174
|
-
const fullPath = (0,
|
|
4175
|
-
return entry.endsWith(".md") && (0,
|
|
4426
|
+
const fullPath = (0, import_path5.join)(dir, entry);
|
|
4427
|
+
return entry.endsWith(".md") && (0, import_fs5.statSync)(fullPath).isFile();
|
|
4176
4428
|
}).map((entry) => entry.replace(/\\/g, "/")).sort();
|
|
4177
4429
|
}
|
|
4178
4430
|
function extractFirstHeading(filePath) {
|
|
4179
4431
|
try {
|
|
4180
|
-
const content = (0,
|
|
4432
|
+
const content = (0, import_fs5.readFileSync)(filePath, "utf-8");
|
|
4181
4433
|
const withoutFrontmatter = content.replace(/^---[\s\S]*?---\s*/, "");
|
|
4182
4434
|
const match = withoutFrontmatter.match(/^#\s+(.+)/m);
|
|
4183
4435
|
if (match) {
|
|
@@ -4195,16 +4447,16 @@ function formatPathRef(contextPath, description, agent) {
|
|
|
4195
4447
|
return `- \`${contextPath}\` \u2014 ${description}`;
|
|
4196
4448
|
}
|
|
4197
4449
|
function resolveDomainFolder(domain, contextsDir) {
|
|
4198
|
-
if ((0,
|
|
4450
|
+
if ((0, import_fs5.existsSync)(contextsDir)) {
|
|
4199
4451
|
try {
|
|
4200
|
-
const entries = (0,
|
|
4452
|
+
const entries = (0, import_fs5.readdirSync)(contextsDir);
|
|
4201
4453
|
const match = entries.find((e) => e.toLowerCase() === domain.toLowerCase());
|
|
4202
|
-
if (match) return { folderName: match, folderPath: (0,
|
|
4454
|
+
if (match) return { folderName: match, folderPath: (0, import_path5.join)(contextsDir, match) };
|
|
4203
4455
|
} catch {
|
|
4204
4456
|
}
|
|
4205
4457
|
}
|
|
4206
4458
|
const fallback = domain.toUpperCase();
|
|
4207
|
-
return { folderName: fallback, folderPath: (0,
|
|
4459
|
+
return { folderName: fallback, folderPath: (0, import_path5.join)(contextsDir, fallback) };
|
|
4208
4460
|
}
|
|
4209
4461
|
function buildContextRefsSection(domains, agent, contextsDir) {
|
|
4210
4462
|
const lines2 = [
|
|
@@ -4216,34 +4468,34 @@ function buildContextRefsSection(domains, agent, contextsDir) {
|
|
|
4216
4468
|
let hasAnyFiles = false;
|
|
4217
4469
|
for (const domain of domains) {
|
|
4218
4470
|
const { folderName, folderPath: domainPath } = resolveDomainFolder(domain, contextsDir);
|
|
4219
|
-
if (!(0,
|
|
4471
|
+
if (!(0, import_fs5.existsSync)(domainPath)) continue;
|
|
4220
4472
|
const domainFiles = [];
|
|
4221
|
-
const ctxInstructions = (0,
|
|
4222
|
-
if ((0,
|
|
4473
|
+
const ctxInstructions = (0, import_path5.join)(domainPath, "context-instructions.md");
|
|
4474
|
+
if ((0, import_fs5.existsSync)(ctxInstructions)) {
|
|
4223
4475
|
const desc = extractFirstHeading(ctxInstructions);
|
|
4224
4476
|
domainFiles.push(formatPathRef(`_ai-context/${folderName}/context-instructions.md`, desc, agent));
|
|
4225
4477
|
}
|
|
4226
|
-
const instructionsMd = (0,
|
|
4227
|
-
if ((0,
|
|
4478
|
+
const instructionsMd = (0, import_path5.join)(domainPath, "core", "instructions.md");
|
|
4479
|
+
if ((0, import_fs5.existsSync)(instructionsMd)) {
|
|
4228
4480
|
const desc = extractFirstHeading(instructionsMd);
|
|
4229
4481
|
domainFiles.push(formatPathRef(`_ai-context/${folderName}/core/instructions.md`, `${desc} (start here)`, agent));
|
|
4230
4482
|
}
|
|
4231
|
-
const coreDir = (0,
|
|
4232
|
-
if ((0,
|
|
4483
|
+
const coreDir = (0, import_path5.join)(domainPath, "core");
|
|
4484
|
+
if ((0, import_fs5.existsSync)(coreDir)) {
|
|
4233
4485
|
const coreFiles = collectMdFiles(coreDir).filter((f) => f !== "instructions.md" && !f.startsWith("instructions/"));
|
|
4234
4486
|
for (const file of coreFiles) {
|
|
4235
|
-
const desc = extractFirstHeading((0,
|
|
4487
|
+
const desc = extractFirstHeading((0, import_path5.join)(coreDir, file));
|
|
4236
4488
|
domainFiles.push(formatPathRef(`_ai-context/${folderName}/core/${file}`, desc, agent));
|
|
4237
4489
|
}
|
|
4238
4490
|
}
|
|
4239
|
-
const refDir = (0,
|
|
4240
|
-
if ((0,
|
|
4491
|
+
const refDir = (0, import_path5.join)(domainPath, "reference");
|
|
4492
|
+
if ((0, import_fs5.existsSync)(refDir)) {
|
|
4241
4493
|
const refFiles = collectMdFiles(refDir);
|
|
4242
4494
|
if (refFiles.length > 0) {
|
|
4243
4495
|
domainFiles.push(``);
|
|
4244
4496
|
domainFiles.push(`**Reference & cheat sheets:**`);
|
|
4245
4497
|
for (const file of refFiles) {
|
|
4246
|
-
const desc = extractFirstHeading((0,
|
|
4498
|
+
const desc = extractFirstHeading((0, import_path5.join)(refDir, file));
|
|
4247
4499
|
domainFiles.push(formatPathRef(`_ai-context/${folderName}/reference/${file}`, desc, agent));
|
|
4248
4500
|
}
|
|
4249
4501
|
}
|
|
@@ -4321,7 +4573,7 @@ function buildFactorySection(agent) {
|
|
|
4321
4573
|
].join("\n");
|
|
4322
4574
|
}
|
|
4323
4575
|
function buildCombinedInstructions(domains, mcpConfig, agent, projectPath, factoryInstalled) {
|
|
4324
|
-
const contextsDir = (0,
|
|
4576
|
+
const contextsDir = (0, import_path5.join)(projectPath, "_ai-context");
|
|
4325
4577
|
const lines2 = [`# AI Development Instructions`, ``, `> Generated by One-Shot Installer`, ``];
|
|
4326
4578
|
lines2.push(buildContextRefsSection(domains, agent, contextsDir));
|
|
4327
4579
|
if (Object.keys(mcpConfig).length > 0) lines2.push(buildMCPSection(mcpConfig));
|
|
@@ -4330,8 +4582,8 @@ function buildCombinedInstructions(domains, mcpConfig, agent, projectPath, facto
|
|
|
4330
4582
|
}
|
|
4331
4583
|
|
|
4332
4584
|
// src/steps/setup/write-mcp-config.ts
|
|
4333
|
-
var
|
|
4334
|
-
var
|
|
4585
|
+
var import_fs6 = require("fs");
|
|
4586
|
+
var import_path6 = require("path");
|
|
4335
4587
|
var red2 = (text) => `\x1B[31m${text}\x1B[0m`;
|
|
4336
4588
|
var write_mcp_config_default = defineStep({
|
|
4337
4589
|
name: "write-mcp-config",
|
|
@@ -4339,23 +4591,23 @@ var write_mcp_config_default = defineStep({
|
|
|
4339
4591
|
when: (ctx) => Object.keys(ctx.config.mcpConfig).length > 0,
|
|
4340
4592
|
execute: async (ctx) => {
|
|
4341
4593
|
const filteredMcpConfig = getFilteredMcpConfig(ctx);
|
|
4342
|
-
const target =
|
|
4343
|
-
const mcpJsonPath = (0,
|
|
4344
|
-
if (target.
|
|
4345
|
-
const dir = (0,
|
|
4346
|
-
if (!(0,
|
|
4594
|
+
const target = getAgentTarget(ctx.config.agent);
|
|
4595
|
+
const mcpJsonPath = (0, import_path6.join)(ctx.config.projectPath, target.mcpConfig);
|
|
4596
|
+
if (target.mcpDir) {
|
|
4597
|
+
const dir = (0, import_path6.join)(ctx.config.projectPath, target.mcpDir);
|
|
4598
|
+
if (!(0, import_fs6.existsSync)(dir)) (0, import_fs6.mkdirSync)(dir, { recursive: true });
|
|
4347
4599
|
}
|
|
4348
4600
|
let existingFile = {};
|
|
4349
|
-
if ((0,
|
|
4601
|
+
if ((0, import_fs6.existsSync)(mcpJsonPath)) {
|
|
4350
4602
|
try {
|
|
4351
|
-
existingFile = JSON.parse((0,
|
|
4603
|
+
existingFile = JSON.parse((0, import_fs6.readFileSync)(mcpJsonPath, "utf-8"));
|
|
4352
4604
|
} catch {
|
|
4353
4605
|
const box = [
|
|
4354
4606
|
"",
|
|
4355
4607
|
red2(" \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557"),
|
|
4356
4608
|
red2(" \u2551 \u26A0 MCP CONFIG HAS INVALID JSON \u2551"),
|
|
4357
4609
|
red2(" \u2551 \u2551"),
|
|
4358
|
-
red2(` \u2551 ${target.
|
|
4610
|
+
red2(` \u2551 ${target.mcpConfig} could not be parsed.`.padEnd(52) + "\u2551"),
|
|
4359
4611
|
red2(" \u2551 Existing MCP servers may be lost. \u2551"),
|
|
4360
4612
|
red2(" \u2551 Check the file after installation completes. \u2551"),
|
|
4361
4613
|
red2(" \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"),
|
|
@@ -4365,16 +4617,16 @@ var write_mcp_config_default = defineStep({
|
|
|
4365
4617
|
}
|
|
4366
4618
|
}
|
|
4367
4619
|
const addedServers = [];
|
|
4368
|
-
const existingServers = existingFile[target.
|
|
4620
|
+
const existingServers = existingFile[target.mcpRootKey] ?? {};
|
|
4369
4621
|
const newServers = {};
|
|
4370
4622
|
for (const [serverName, serverConfig] of Object.entries(filteredMcpConfig)) {
|
|
4371
|
-
const { description, useWhen, active, ...mcpFields } = serverConfig;
|
|
4623
|
+
const { description, useWhen, active, installCommand, ...mcpFields } = serverConfig;
|
|
4372
4624
|
newServers[serverName] = mcpFields;
|
|
4373
4625
|
addedServers.push(serverName);
|
|
4374
4626
|
}
|
|
4375
4627
|
const mergedServers = { ...existingServers, ...newServers };
|
|
4376
|
-
const outputFile = { ...existingFile, [target.
|
|
4377
|
-
(0,
|
|
4628
|
+
const outputFile = { ...existingFile, [target.mcpRootKey]: mergedServers };
|
|
4629
|
+
(0, import_fs6.writeFileSync)(mcpJsonPath, JSON.stringify(outputFile, null, 2), "utf-8");
|
|
4378
4630
|
ctx.installed.mcpServersAdded = addedServers;
|
|
4379
4631
|
return {
|
|
4380
4632
|
status: "success",
|
|
@@ -4382,24 +4634,73 @@ var write_mcp_config_default = defineStep({
|
|
|
4382
4634
|
};
|
|
4383
4635
|
}
|
|
4384
4636
|
});
|
|
4385
|
-
|
|
4386
|
-
|
|
4387
|
-
|
|
4388
|
-
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
|
|
4637
|
+
|
|
4638
|
+
// src/steps/setup/run-mcp-install-commands.ts
|
|
4639
|
+
var import_child_process4 = require("child_process");
|
|
4640
|
+
var run_mcp_install_commands_default = defineStep({
|
|
4641
|
+
name: "run-mcp-install-commands",
|
|
4642
|
+
label: "Registering MCP servers with Claude Code",
|
|
4643
|
+
when: (ctx) => {
|
|
4644
|
+
if (ctx.config.agent !== "claude-code") return false;
|
|
4645
|
+
const filtered = getFilteredMcpConfig(ctx);
|
|
4646
|
+
return Object.values(filtered).some((s) => typeof s.installCommand === "string" && s.installCommand.length > 0);
|
|
4647
|
+
},
|
|
4648
|
+
execute: async (ctx) => {
|
|
4649
|
+
if (!isClaudeCliAvailable()) {
|
|
4650
|
+
return {
|
|
4651
|
+
status: "skipped",
|
|
4652
|
+
detail: "`claude` CLI not found on PATH \u2014 skipping CLI registration (project .mcp.json was still written)"
|
|
4653
|
+
};
|
|
4654
|
+
}
|
|
4655
|
+
const filtered = getFilteredMcpConfig(ctx);
|
|
4656
|
+
const succeeded = [];
|
|
4657
|
+
const failed = [];
|
|
4658
|
+
for (const [name, cfg] of Object.entries(filtered)) {
|
|
4659
|
+
const cmd = cfg.installCommand;
|
|
4660
|
+
if (typeof cmd !== "string" || cmd.length === 0) continue;
|
|
4661
|
+
const result = (0, import_child_process4.spawnSync)(cmd, {
|
|
4662
|
+
shell: true,
|
|
4663
|
+
stdio: "pipe",
|
|
4664
|
+
encoding: "utf-8",
|
|
4665
|
+
cwd: ctx.config.projectPath
|
|
4666
|
+
});
|
|
4667
|
+
if (result.status === 0) {
|
|
4668
|
+
succeeded.push(name);
|
|
4669
|
+
} else {
|
|
4670
|
+
const stderr = (result.stderr ?? "").trim();
|
|
4671
|
+
const reason = stderr.length > 0 ? stderr.split("\n")[0] : `exit ${result.status}`;
|
|
4672
|
+
failed.push({ name, reason });
|
|
4673
|
+
}
|
|
4674
|
+
}
|
|
4675
|
+
ctx.installed.mcpInstallCommandsRun = { succeeded, failed };
|
|
4676
|
+
if (failed.length === 0) {
|
|
4677
|
+
return {
|
|
4678
|
+
status: "success",
|
|
4679
|
+
message: succeeded.length > 0 ? succeeded.join(", ") : void 0
|
|
4680
|
+
};
|
|
4681
|
+
}
|
|
4682
|
+
const failedSummary = failed.map((f) => `${f.name} (${f.reason})`).join("; ");
|
|
4683
|
+
if (succeeded.length === 0) {
|
|
4684
|
+
return { status: "failed", detail: failedSummary };
|
|
4685
|
+
}
|
|
4686
|
+
return {
|
|
4687
|
+
status: "success",
|
|
4688
|
+
message: `${succeeded.join(", ")}; failed: ${failed.map((f) => f.name).join(", ")}`,
|
|
4689
|
+
detail: `Some registrations failed: ${failedSummary}`
|
|
4690
|
+
};
|
|
4394
4691
|
}
|
|
4692
|
+
});
|
|
4693
|
+
function isClaudeCliAvailable() {
|
|
4694
|
+
const check2 = (0, import_child_process4.spawnSync)("claude --version", { shell: true, stdio: "ignore" });
|
|
4695
|
+
return check2.status === 0;
|
|
4395
4696
|
}
|
|
4396
4697
|
|
|
4397
4698
|
// src/steps/setup/update-gitignore.ts
|
|
4398
|
-
var
|
|
4399
|
-
var
|
|
4699
|
+
var import_fs7 = require("fs");
|
|
4700
|
+
var import_path7 = require("path");
|
|
4400
4701
|
var MARKER_START2 = "# one-shot-installer:start";
|
|
4401
4702
|
var MARKER_END2 = "# one-shot-installer:end";
|
|
4402
|
-
var
|
|
4703
|
+
var CORE_GITIGNORE_ENTRIES = [
|
|
4403
4704
|
"# One-Shot installer generated files",
|
|
4404
4705
|
".one-shot-state.json",
|
|
4405
4706
|
".mcp.json",
|
|
@@ -4411,8 +4712,9 @@ var GITIGNORE_ENTRIES = [
|
|
|
4411
4712
|
".claude/agents/",
|
|
4412
4713
|
".claude/agent-memory/",
|
|
4413
4714
|
".claude/plans/",
|
|
4414
|
-
".claude/settings.local.json"
|
|
4415
|
-
|
|
4715
|
+
".claude/settings.local.json"
|
|
4716
|
+
];
|
|
4717
|
+
var LEGACY_FACTORY_GITIGNORE_ENTRIES = [
|
|
4416
4718
|
"# Factory runtime state (generated by workflow, not committed)",
|
|
4417
4719
|
"factory/STATE.md",
|
|
4418
4720
|
"factory/PROJECT.md",
|
|
@@ -4430,40 +4732,45 @@ var update_gitignore_default = defineStep({
|
|
|
4430
4732
|
name: "update-gitignore",
|
|
4431
4733
|
label: "Updating .gitignore",
|
|
4432
4734
|
execute: async (ctx) => {
|
|
4433
|
-
const gitignorePath = (0,
|
|
4434
|
-
const
|
|
4435
|
-
|
|
4436
|
-
|
|
4735
|
+
const gitignorePath = (0, import_path7.join)(ctx.config.projectPath, ".gitignore");
|
|
4736
|
+
const factoryInstalled = ctx.installed.factoryInstalled ?? false;
|
|
4737
|
+
const factoryBundleManaged = ctx.installed.factoryBundleManaged ?? false;
|
|
4738
|
+
const includeLegacyFactory = factoryInstalled && !factoryBundleManaged;
|
|
4739
|
+
const entries = includeLegacyFactory ? [...CORE_GITIGNORE_ENTRIES, "", ...LEGACY_FACTORY_GITIGNORE_ENTRIES] : CORE_GITIGNORE_ENTRIES;
|
|
4740
|
+
const block = [MARKER_START2, ...entries, MARKER_END2].join("\n");
|
|
4741
|
+
if (!(0, import_fs7.existsSync)(gitignorePath)) {
|
|
4742
|
+
(0, import_fs7.writeFileSync)(gitignorePath, block + "\n", "utf-8");
|
|
4437
4743
|
return { status: "success" };
|
|
4438
4744
|
}
|
|
4439
|
-
const existing = (0,
|
|
4745
|
+
const existing = (0, import_fs7.readFileSync)(gitignorePath, "utf-8");
|
|
4440
4746
|
const start = existing.indexOf(MARKER_START2);
|
|
4441
4747
|
const end = existing.indexOf(MARKER_END2);
|
|
4442
4748
|
if (start !== -1 && end !== -1 && end > start) {
|
|
4443
4749
|
const updated = existing.slice(0, start) + block + existing.slice(end + MARKER_END2.length);
|
|
4444
|
-
(0,
|
|
4750
|
+
(0, import_fs7.writeFileSync)(gitignorePath, updated, "utf-8");
|
|
4445
4751
|
} else {
|
|
4446
4752
|
const separator = existing.endsWith("\n") ? "\n" : "\n\n";
|
|
4447
|
-
(0,
|
|
4753
|
+
(0, import_fs7.writeFileSync)(gitignorePath, existing + separator + block + "\n", "utf-8");
|
|
4448
4754
|
}
|
|
4449
4755
|
return { status: "success" };
|
|
4450
4756
|
}
|
|
4451
4757
|
});
|
|
4452
4758
|
|
|
4453
4759
|
// src/steps/setup/write-state.ts
|
|
4454
|
-
var
|
|
4455
|
-
var
|
|
4760
|
+
var import_fs8 = require("fs");
|
|
4761
|
+
var import_path8 = require("path");
|
|
4456
4762
|
var import_os2 = require("os");
|
|
4457
|
-
var INSTALLER_VERSION = "0.
|
|
4763
|
+
var INSTALLER_VERSION = "0.6.0";
|
|
4458
4764
|
var write_state_default = defineStep({
|
|
4459
4765
|
name: "write-state",
|
|
4460
4766
|
label: "Saving installation state",
|
|
4461
4767
|
execute: async (ctx) => {
|
|
4462
|
-
const statePath = (0,
|
|
4768
|
+
const statePath = (0, import_path8.join)(ctx.config.projectPath, ".one-shot-state.json");
|
|
4463
4769
|
const mcpServersAdded = ctx.installed.mcpServersAdded ?? [];
|
|
4464
4770
|
const filteredMcpConfig = Object.fromEntries(
|
|
4465
4771
|
Object.entries(ctx.config.mcpConfig).filter(([name]) => mcpServersAdded.includes(name))
|
|
4466
4772
|
);
|
|
4773
|
+
const target = getAgentTarget(ctx.config.agent);
|
|
4467
4774
|
const state = {
|
|
4468
4775
|
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4469
4776
|
installerVersion: INSTALLER_VERSION,
|
|
@@ -4477,65 +4784,19 @@ var write_state_default = defineStep({
|
|
|
4477
4784
|
mcpConfigs: filteredMcpConfig,
|
|
4478
4785
|
factoryInstalled: ctx.installed.factoryInstalled ?? false,
|
|
4479
4786
|
files: {
|
|
4480
|
-
instructions:
|
|
4481
|
-
mcpConfig:
|
|
4787
|
+
instructions: target.instructions,
|
|
4788
|
+
mcpConfig: target.mcpConfig,
|
|
4482
4789
|
contexts: "_ai-context/",
|
|
4483
4790
|
factory: ctx.installed.factoryInstalled ? "factory/" : null,
|
|
4484
|
-
globalConfig: (0,
|
|
4791
|
+
globalConfig: (0, import_path8.join)((0, import_os2.homedir)(), ".one-shot-installer")
|
|
4485
4792
|
}
|
|
4486
4793
|
};
|
|
4487
|
-
(0,
|
|
4794
|
+
(0, import_fs8.writeFileSync)(statePath, JSON.stringify(state, null, 2), "utf-8");
|
|
4488
4795
|
return { status: "success" };
|
|
4489
4796
|
}
|
|
4490
4797
|
});
|
|
4491
|
-
function getInstructionFilePath2(agent) {
|
|
4492
|
-
switch (agent) {
|
|
4493
|
-
case "claude-code":
|
|
4494
|
-
return "CLAUDE.md";
|
|
4495
|
-
case "github-copilot":
|
|
4496
|
-
return ".github/copilot-instructions.md";
|
|
4497
|
-
case "cursor":
|
|
4498
|
-
return ".cursor/rules/instructions.mdc";
|
|
4499
|
-
default:
|
|
4500
|
-
return "CLAUDE.md";
|
|
4501
|
-
}
|
|
4502
|
-
}
|
|
4503
|
-
function getMCPConfigPath(agent) {
|
|
4504
|
-
switch (agent) {
|
|
4505
|
-
case "claude-code":
|
|
4506
|
-
return ".mcp.json";
|
|
4507
|
-
case "cursor":
|
|
4508
|
-
return ".cursor/mcp.json";
|
|
4509
|
-
case "github-copilot":
|
|
4510
|
-
default:
|
|
4511
|
-
return ".vscode/mcp.json";
|
|
4512
|
-
}
|
|
4513
|
-
}
|
|
4514
4798
|
|
|
4515
4799
|
// src/index.ts
|
|
4516
|
-
function getInstructionFilePath3(agent) {
|
|
4517
|
-
switch (agent) {
|
|
4518
|
-
case "claude-code":
|
|
4519
|
-
return "CLAUDE.md";
|
|
4520
|
-
case "github-copilot":
|
|
4521
|
-
return ".github/copilot-instructions.md";
|
|
4522
|
-
case "cursor":
|
|
4523
|
-
return ".cursor/rules/instructions.mdc";
|
|
4524
|
-
default:
|
|
4525
|
-
return "CLAUDE.md";
|
|
4526
|
-
}
|
|
4527
|
-
}
|
|
4528
|
-
function getMCPConfigPath2(agent) {
|
|
4529
|
-
switch (agent) {
|
|
4530
|
-
case "claude-code":
|
|
4531
|
-
return ".mcp.json";
|
|
4532
|
-
case "cursor":
|
|
4533
|
-
return ".cursor/mcp.json";
|
|
4534
|
-
case "github-copilot":
|
|
4535
|
-
default:
|
|
4536
|
-
return ".vscode/mcp.json";
|
|
4537
|
-
}
|
|
4538
|
-
}
|
|
4539
4800
|
function formatMCPCommand(server) {
|
|
4540
4801
|
if (server.url) return server.url;
|
|
4541
4802
|
if (server.command) return `${server.command} ${(server.args ?? []).join(" ")}`.trimEnd();
|
|
@@ -4545,27 +4806,27 @@ var dim = (text) => `\x1B[2m${text}\x1B[0m`;
|
|
|
4545
4806
|
var yellow = (text) => `\x1B[33m${text}\x1B[0m`;
|
|
4546
4807
|
var green = (text) => `\x1B[32m${text}\x1B[0m`;
|
|
4547
4808
|
function detectMarkerFileMode(filePath, markerStart) {
|
|
4548
|
-
if (!(0,
|
|
4549
|
-
const content = (0,
|
|
4809
|
+
if (!(0, import_fs9.existsSync)(filePath)) return green("create");
|
|
4810
|
+
const content = (0, import_fs9.readFileSync)(filePath, "utf-8");
|
|
4550
4811
|
if (content.includes(markerStart)) return yellow("update");
|
|
4551
4812
|
return yellow("append");
|
|
4552
4813
|
}
|
|
4553
4814
|
function detectMCPFileMode(filePath) {
|
|
4554
|
-
if (!(0,
|
|
4815
|
+
if (!(0, import_fs9.existsSync)(filePath)) return green("create");
|
|
4555
4816
|
return yellow("merge");
|
|
4556
4817
|
}
|
|
4557
4818
|
function detectContextMode(projectPath, domain) {
|
|
4558
|
-
const contextDir = (0,
|
|
4559
|
-
const contextDirLower = (0,
|
|
4560
|
-
if ((0,
|
|
4819
|
+
const contextDir = (0, import_path9.join)(projectPath, "_ai-context", domain.toUpperCase());
|
|
4820
|
+
const contextDirLower = (0, import_path9.join)(projectPath, "_ai-context", domain);
|
|
4821
|
+
if ((0, import_fs9.existsSync)(contextDir) || (0, import_fs9.existsSync)(contextDirLower)) return yellow("overwrite");
|
|
4561
4822
|
return green("create");
|
|
4562
4823
|
}
|
|
4563
4824
|
function waitForEnter() {
|
|
4564
4825
|
const rl = (0, import_readline.createInterface)({ input: process.stdin, output: process.stdout });
|
|
4565
|
-
return new Promise((
|
|
4826
|
+
return new Promise((resolve5) => {
|
|
4566
4827
|
rl.question(" Press Enter to close...", () => {
|
|
4567
4828
|
rl.close();
|
|
4568
|
-
|
|
4829
|
+
resolve5();
|
|
4569
4830
|
});
|
|
4570
4831
|
});
|
|
4571
4832
|
}
|
|
@@ -4648,17 +4909,20 @@ async function collectInputs(options, releaseVersion, factoryAvailable = false)
|
|
|
4648
4909
|
mcpConfig["azure-devops"].args = mcpConfig["azure-devops"].args?.map(
|
|
4649
4910
|
(arg) => arg === "__AZURE_ORG__" ? azureDevOpsOrg : arg
|
|
4650
4911
|
);
|
|
4912
|
+
if (mcpConfig["azure-devops"].installCommand) {
|
|
4913
|
+
mcpConfig["azure-devops"].installCommand = mcpConfig["azure-devops"].installCommand.replace(/__AZURE_ORG__/g, azureDevOpsOrg);
|
|
4914
|
+
}
|
|
4651
4915
|
}
|
|
4652
4916
|
}
|
|
4653
4917
|
const projectInput = await esm_default4({
|
|
4654
4918
|
message: "Project directory:",
|
|
4655
|
-
default: (0,
|
|
4919
|
+
default: (0, import_path9.resolve)(process.cwd())
|
|
4656
4920
|
});
|
|
4657
4921
|
return {
|
|
4658
4922
|
technologies: selectedTechnologies,
|
|
4659
4923
|
agent,
|
|
4660
4924
|
azureDevOpsOrg,
|
|
4661
|
-
projectPath: (0,
|
|
4925
|
+
projectPath: (0, import_path9.resolve)(projectInput),
|
|
4662
4926
|
baseMcpServers: options.baseMcpServers,
|
|
4663
4927
|
mcpConfig,
|
|
4664
4928
|
releaseVersion,
|
|
@@ -4668,12 +4932,13 @@ async function collectInputs(options, releaseVersion, factoryAvailable = false)
|
|
|
4668
4932
|
async function previewAndConfirm(config, options) {
|
|
4669
4933
|
const technologyNames = config.technologies.length > 0 ? config.technologies.map((p) => p.name.replace(/ Developer$/, "")).join(", ") : "None";
|
|
4670
4934
|
const agentDisplay = options.agents.find((a) => a.value === config.agent)?.name ?? config.agent;
|
|
4671
|
-
const
|
|
4672
|
-
const
|
|
4935
|
+
const target = getAgentTarget(config.agent);
|
|
4936
|
+
const instructionFile = target.instructions;
|
|
4937
|
+
const mcpConfigFile = target.mcpConfig;
|
|
4673
4938
|
const serverEntries = Object.entries(config.mcpConfig);
|
|
4674
|
-
const instructionFilePath = (0,
|
|
4675
|
-
const mcpConfigFilePath = (0,
|
|
4676
|
-
const gitignorePath = (0,
|
|
4939
|
+
const instructionFilePath = (0, import_path9.join)(config.projectPath, instructionFile);
|
|
4940
|
+
const mcpConfigFilePath = (0, import_path9.join)(config.projectPath, mcpConfigFile);
|
|
4941
|
+
const gitignorePath = (0, import_path9.join)(config.projectPath, ".gitignore");
|
|
4677
4942
|
const instructionMode = detectMarkerFileMode(instructionFilePath, "<!-- one-shot-installer:start -->");
|
|
4678
4943
|
const mcpMode = detectMCPFileMode(mcpConfigFilePath);
|
|
4679
4944
|
const gitignoreMode = detectMarkerFileMode(gitignorePath, "# one-shot-installer:start");
|
|
@@ -4699,7 +4964,7 @@ async function previewAndConfirm(config, options) {
|
|
|
4699
4964
|
console.log(` ${mcpConfigFile.padEnd(domainColWidth + 14)}${mcpMode}`);
|
|
4700
4965
|
console.log(` ${".gitignore".padEnd(domainColWidth + 14)}${gitignoreMode}`);
|
|
4701
4966
|
if (config.installFactory) {
|
|
4702
|
-
const factoryExists = (0,
|
|
4967
|
+
const factoryExists = (0, import_fs9.existsSync)((0, import_path9.join)(config.projectPath, "factory"));
|
|
4703
4968
|
const factoryMode = factoryExists ? yellow("overwrite") : green("create");
|
|
4704
4969
|
console.log(` ${"factory/".padEnd(domainColWidth + 14)}${factoryMode}`);
|
|
4705
4970
|
}
|