dlw-machine-setup 0.6.2 → 0.8.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 +211 -36
- package/package.json +1 -1
package/bin/installer.js
CHANGED
|
@@ -3850,7 +3850,7 @@ var import_fs6 = require("fs");
|
|
|
3850
3850
|
var import_path6 = require("path");
|
|
3851
3851
|
|
|
3852
3852
|
// src/bundles/types.ts
|
|
3853
|
-
var
|
|
3853
|
+
var SUPPORTED_SCHEMA_VERSIONS = [1, 2];
|
|
3854
3854
|
|
|
3855
3855
|
// src/utils/marker-block.ts
|
|
3856
3856
|
var import_fs5 = require("fs");
|
|
@@ -3881,11 +3881,99 @@ ${endMarker}`;
|
|
|
3881
3881
|
}
|
|
3882
3882
|
}
|
|
3883
3883
|
|
|
3884
|
+
// src/profiles/claude-code.ts
|
|
3885
|
+
var claudeCodeProfile = {
|
|
3886
|
+
agent: "claude-code",
|
|
3887
|
+
instructionsFile: "CLAUDE.md",
|
|
3888
|
+
handlers: {
|
|
3889
|
+
agent: {
|
|
3890
|
+
supported: true,
|
|
3891
|
+
destination: (name) => `.claude/agents/${name}.md`
|
|
3892
|
+
},
|
|
3893
|
+
skill: {
|
|
3894
|
+
supported: true,
|
|
3895
|
+
// Claude reads skills from a folder per skill: `.claude/skills/<name>/SKILL.md`.
|
|
3896
|
+
destination: (name) => `.claude/skills/${name}/SKILL.md`
|
|
3897
|
+
},
|
|
3898
|
+
hook: {
|
|
3899
|
+
supported: true,
|
|
3900
|
+
configFile: ".claude/settings.json",
|
|
3901
|
+
configKey: "hooks",
|
|
3902
|
+
scriptDir: ".claude/hooks"
|
|
3903
|
+
},
|
|
3904
|
+
"instructions-snippet": {
|
|
3905
|
+
supported: true
|
|
3906
|
+
}
|
|
3907
|
+
}
|
|
3908
|
+
};
|
|
3909
|
+
|
|
3910
|
+
// src/profiles/github-copilot.ts
|
|
3911
|
+
var githubCopilotProfile = {
|
|
3912
|
+
agent: "github-copilot",
|
|
3913
|
+
instructionsFile: ".github/copilot-instructions.md",
|
|
3914
|
+
handlers: {
|
|
3915
|
+
agent: {
|
|
3916
|
+
supported: true,
|
|
3917
|
+
destination: (name) => `.github/agents/${name}.agent.md`
|
|
3918
|
+
},
|
|
3919
|
+
skill: {
|
|
3920
|
+
supported: true,
|
|
3921
|
+
destination: (name) => `.github/skills/${name}/SKILL.md`
|
|
3922
|
+
},
|
|
3923
|
+
hook: {
|
|
3924
|
+
// See header docblock for the three HookHandler extensions needed
|
|
3925
|
+
// to flip this on. Until then, hook assets are skipped on Copilot.
|
|
3926
|
+
supported: false
|
|
3927
|
+
},
|
|
3928
|
+
"instructions-snippet": {
|
|
3929
|
+
supported: true
|
|
3930
|
+
}
|
|
3931
|
+
}
|
|
3932
|
+
};
|
|
3933
|
+
|
|
3934
|
+
// src/profiles/cursor.ts
|
|
3935
|
+
var cursorProfile = {
|
|
3936
|
+
agent: "cursor",
|
|
3937
|
+
instructionsFile: ".cursor/rules/instructions.mdc",
|
|
3938
|
+
handlers: {
|
|
3939
|
+
agent: { supported: false },
|
|
3940
|
+
skill: { supported: false },
|
|
3941
|
+
hook: { supported: false },
|
|
3942
|
+
"instructions-snippet": { supported: true }
|
|
3943
|
+
}
|
|
3944
|
+
};
|
|
3945
|
+
|
|
3946
|
+
// src/profiles/index.ts
|
|
3947
|
+
var PROFILES = {
|
|
3948
|
+
"claude-code": claudeCodeProfile,
|
|
3949
|
+
"github-copilot": githubCopilotProfile,
|
|
3950
|
+
"cursor": cursorProfile
|
|
3951
|
+
};
|
|
3952
|
+
function getProfile(agent) {
|
|
3953
|
+
const profile = PROFILES[agent];
|
|
3954
|
+
if (!profile) {
|
|
3955
|
+
const known = Object.keys(PROFILES).map((k) => `"${k}"`).join(", ");
|
|
3956
|
+
throw new Error(
|
|
3957
|
+
`No profile registered for agent "${agent}". Known agents: ${known}. Add src/profiles/${agent}.ts and register it in src/profiles/index.ts.`
|
|
3958
|
+
);
|
|
3959
|
+
}
|
|
3960
|
+
return profile;
|
|
3961
|
+
}
|
|
3962
|
+
|
|
3884
3963
|
// src/bundles/run-bundle.ts
|
|
3885
3964
|
var OWNER_KEY = "_bundleOwner";
|
|
3886
3965
|
async function runBundle(manifest, ctx) {
|
|
3887
3966
|
assertSchemaCompatible(manifest);
|
|
3967
|
+
assertNameValid(manifest);
|
|
3888
3968
|
assertBundleRootExists(ctx);
|
|
3969
|
+
switch (manifest.schemaVersion) {
|
|
3970
|
+
case 1:
|
|
3971
|
+
return runBundleV1(manifest, ctx);
|
|
3972
|
+
case 2:
|
|
3973
|
+
return runBundleV2(manifest, ctx);
|
|
3974
|
+
}
|
|
3975
|
+
}
|
|
3976
|
+
function runBundleV1(manifest, ctx) {
|
|
3889
3977
|
const result = {
|
|
3890
3978
|
name: manifest.name,
|
|
3891
3979
|
opsExecuted: 0,
|
|
@@ -3896,30 +3984,120 @@ async function runBundle(manifest, ctx) {
|
|
|
3896
3984
|
executeOp(op, manifest.name, ctx, result);
|
|
3897
3985
|
result.opsExecuted++;
|
|
3898
3986
|
}
|
|
3899
|
-
|
|
3900
|
-
upsertMarkerBlock(
|
|
3901
|
-
(0, import_path6.join)(ctx.projectPath, ".gitignore"),
|
|
3902
|
-
`# ${manifest.name}:start`,
|
|
3903
|
-
`# ${manifest.name}:end`,
|
|
3904
|
-
manifest.gitignore.join("\n")
|
|
3905
|
-
);
|
|
3906
|
-
result.filesTouched.push(".gitignore");
|
|
3907
|
-
}
|
|
3987
|
+
writeGitignoreBlock(manifest, ctx, result);
|
|
3908
3988
|
const snippet = manifest.instructions?.[ctx.agent];
|
|
3909
3989
|
if (snippet) {
|
|
3910
3990
|
result.instructionsSnippet = snippet;
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3991
|
+
writeInstructionsBlock(manifest.name, snippet, ctx.instructionsFile, ctx, result);
|
|
3992
|
+
}
|
|
3993
|
+
return result;
|
|
3994
|
+
}
|
|
3995
|
+
function runBundleV2(manifest, ctx) {
|
|
3996
|
+
const profile = getProfile(ctx.agent);
|
|
3997
|
+
const result = {
|
|
3998
|
+
name: manifest.name,
|
|
3999
|
+
opsExecuted: 0,
|
|
4000
|
+
filesTouched: []
|
|
4001
|
+
};
|
|
4002
|
+
const hookPatches = /* @__PURE__ */ new Map();
|
|
4003
|
+
for (const asset of manifest.assets ?? []) {
|
|
4004
|
+
runAsset(asset, profile, hookPatches, ctx, result);
|
|
4005
|
+
result.opsExecuted++;
|
|
4006
|
+
}
|
|
4007
|
+
for (const [file, patch] of hookPatches) {
|
|
4008
|
+
runMergeJson({ op: "merge-json", file, patch }, manifest.name, ctx, result);
|
|
4009
|
+
}
|
|
4010
|
+
for (const op of manifest.ops ?? []) {
|
|
4011
|
+
executeOp(op, manifest.name, ctx, result);
|
|
4012
|
+
result.opsExecuted++;
|
|
4013
|
+
}
|
|
4014
|
+
writeGitignoreBlock(manifest, ctx, result);
|
|
4015
|
+
const snippet = result.instructionsSnippet;
|
|
4016
|
+
if (snippet) {
|
|
4017
|
+
const instructionsFile = profile.instructionsFile || ctx.instructionsFile;
|
|
4018
|
+
writeInstructionsBlock(manifest.name, snippet, instructionsFile, ctx, result);
|
|
3920
4019
|
}
|
|
3921
4020
|
return result;
|
|
3922
4021
|
}
|
|
4022
|
+
function runAsset(asset, profile, hookPatches, ctx, result) {
|
|
4023
|
+
switch (asset.type) {
|
|
4024
|
+
case "agent":
|
|
4025
|
+
runAssetCopy(asset, profile.handlers.agent, ctx, result);
|
|
4026
|
+
return;
|
|
4027
|
+
case "skill":
|
|
4028
|
+
runAssetCopy(asset, profile.handlers.skill, ctx, result);
|
|
4029
|
+
return;
|
|
4030
|
+
case "hook":
|
|
4031
|
+
accumulateHook(asset, profile.handlers.hook, hookPatches, ctx, result);
|
|
4032
|
+
return;
|
|
4033
|
+
case "instructions-snippet":
|
|
4034
|
+
if (profile.handlers["instructions-snippet"].supported) {
|
|
4035
|
+
result.instructionsSnippet = asset.content;
|
|
4036
|
+
}
|
|
4037
|
+
return;
|
|
4038
|
+
}
|
|
4039
|
+
}
|
|
4040
|
+
function runAssetCopy(asset, handler, ctx, result) {
|
|
4041
|
+
if (!handler.supported || !handler.destination) return;
|
|
4042
|
+
const source = resolveBundlePath(asset.source, ctx);
|
|
4043
|
+
if (!(0, import_fs6.existsSync)(source)) return;
|
|
4044
|
+
const target = resolveProjectPath(handler.destination(asset.name), ctx);
|
|
4045
|
+
if ((0, import_fs6.statSync)(source).isDirectory()) {
|
|
4046
|
+
copyDirectory(source, target);
|
|
4047
|
+
} else {
|
|
4048
|
+
(0, import_fs6.mkdirSync)((0, import_path6.dirname)(target), { recursive: true });
|
|
4049
|
+
(0, import_fs6.copyFileSync)(source, target);
|
|
4050
|
+
}
|
|
4051
|
+
result.filesTouched.push(handler.destination(asset.name));
|
|
4052
|
+
}
|
|
4053
|
+
function accumulateHook(asset, handler, hookPatches, ctx, result) {
|
|
4054
|
+
if (!handler.supported) return;
|
|
4055
|
+
if (!handler.configFile || !handler.configKey) return;
|
|
4056
|
+
if (asset.script && handler.scriptDir) {
|
|
4057
|
+
const scriptSource = resolveBundlePath(asset.script, ctx);
|
|
4058
|
+
if ((0, import_fs6.existsSync)(scriptSource)) {
|
|
4059
|
+
const scriptName = (0, import_path6.basename)(asset.script);
|
|
4060
|
+
const scriptRelDest = `${handler.scriptDir}/${scriptName}`;
|
|
4061
|
+
const scriptDest = resolveProjectPath(scriptRelDest, ctx);
|
|
4062
|
+
(0, import_fs6.mkdirSync)((0, import_path6.dirname)(scriptDest), { recursive: true });
|
|
4063
|
+
(0, import_fs6.copyFileSync)(scriptSource, scriptDest);
|
|
4064
|
+
result.filesTouched.push(scriptRelDest);
|
|
4065
|
+
}
|
|
4066
|
+
}
|
|
4067
|
+
const command = handler.scriptDir ? asset.command.replace(/\{hookDir\}/g, handler.scriptDir) : asset.command;
|
|
4068
|
+
const entry = {
|
|
4069
|
+
hooks: [{ type: "command", command }]
|
|
4070
|
+
};
|
|
4071
|
+
if (asset.matcher) entry.matcher = asset.matcher;
|
|
4072
|
+
let patch = hookPatches.get(handler.configFile);
|
|
4073
|
+
if (!patch) {
|
|
4074
|
+
patch = {};
|
|
4075
|
+
hookPatches.set(handler.configFile, patch);
|
|
4076
|
+
}
|
|
4077
|
+
const root = patch[handler.configKey] ??= {};
|
|
4078
|
+
const events = root[asset.event] ??= [];
|
|
4079
|
+
events.push(entry);
|
|
4080
|
+
}
|
|
4081
|
+
function writeGitignoreBlock(manifest, ctx, result) {
|
|
4082
|
+
if (!manifest.gitignore?.length) return;
|
|
4083
|
+
upsertMarkerBlock(
|
|
4084
|
+
(0, import_path6.join)(ctx.projectPath, ".gitignore"),
|
|
4085
|
+
`# ${manifest.name}:start`,
|
|
4086
|
+
`# ${manifest.name}:end`,
|
|
4087
|
+
manifest.gitignore.join("\n")
|
|
4088
|
+
);
|
|
4089
|
+
result.filesTouched.push(".gitignore");
|
|
4090
|
+
}
|
|
4091
|
+
function writeInstructionsBlock(bundleName, snippet, instructionsFile, ctx, result) {
|
|
4092
|
+
if (ctx.skipInstructions) return;
|
|
4093
|
+
upsertMarkerBlock(
|
|
4094
|
+
(0, import_path6.join)(ctx.projectPath, instructionsFile),
|
|
4095
|
+
`<!-- ${bundleName}:start -->`,
|
|
4096
|
+
`<!-- ${bundleName}:end -->`,
|
|
4097
|
+
snippet
|
|
4098
|
+
);
|
|
4099
|
+
result.filesTouched.push(instructionsFile);
|
|
4100
|
+
}
|
|
3923
4101
|
function executeOp(op, owner, ctx, result) {
|
|
3924
4102
|
switch (op.op) {
|
|
3925
4103
|
case "copy":
|
|
@@ -4021,11 +4199,14 @@ function resolveProjectPath(rel, ctx) {
|
|
|
4021
4199
|
return full;
|
|
4022
4200
|
}
|
|
4023
4201
|
function assertSchemaCompatible(manifest) {
|
|
4024
|
-
if (manifest.schemaVersion
|
|
4202
|
+
if (!SUPPORTED_SCHEMA_VERSIONS.includes(manifest.schemaVersion)) {
|
|
4203
|
+
const supported = SUPPORTED_SCHEMA_VERSIONS.join(", ");
|
|
4025
4204
|
throw new Error(
|
|
4026
|
-
`Bundle "${manifest.name}" declares schemaVersion ${manifest.schemaVersion}, installer supports ${
|
|
4205
|
+
`Bundle "${manifest.name}" declares schemaVersion ${manifest.schemaVersion}, installer supports ${supported}. Upgrade the installer or re-pin the bundle.`
|
|
4027
4206
|
);
|
|
4028
4207
|
}
|
|
4208
|
+
}
|
|
4209
|
+
function assertNameValid(manifest) {
|
|
4029
4210
|
if (!manifest.name || !/^[a-z][a-z0-9-]*$/.test(manifest.name)) {
|
|
4030
4211
|
throw new Error(
|
|
4031
4212
|
`Bundle name must match /^[a-z][a-z0-9-]*$/: got "${manifest.name}"`
|
|
@@ -4039,14 +4220,8 @@ function assertBundleRootExists(ctx) {
|
|
|
4039
4220
|
}
|
|
4040
4221
|
|
|
4041
4222
|
// src/steps/resources/fetch-factory.ts
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
case "github-copilot":
|
|
4045
|
-
return { assetName: "factory-copilot.tar.gz", rootFolder: "factory-copilot" };
|
|
4046
|
-
default:
|
|
4047
|
-
return { assetName: "factory.tar.gz", rootFolder: "factory" };
|
|
4048
|
-
}
|
|
4049
|
-
}
|
|
4223
|
+
var FACTORY_ASSET_NAME = "factory.tar.gz";
|
|
4224
|
+
var FACTORY_ROOT_FOLDER = "factory";
|
|
4050
4225
|
var fetch_factory_default = defineStep({
|
|
4051
4226
|
name: "fetch-factory",
|
|
4052
4227
|
label: "Installing Factory framework",
|
|
@@ -4065,7 +4240,6 @@ var fetch_factory_default = defineStep({
|
|
|
4065
4240
|
});
|
|
4066
4241
|
async function fetchFactory(token, repo, targetDir, agent) {
|
|
4067
4242
|
const result = { success: false, filesInstalled: [] };
|
|
4068
|
-
const { assetName, rootFolder } = getFactoryAsset(agent);
|
|
4069
4243
|
let release;
|
|
4070
4244
|
try {
|
|
4071
4245
|
release = await fetchLatestRelease(token, repo);
|
|
@@ -4073,18 +4247,18 @@ async function fetchFactory(token, repo, targetDir, agent) {
|
|
|
4073
4247
|
result.failureReason = err instanceof Error ? err.message : String(err);
|
|
4074
4248
|
return result;
|
|
4075
4249
|
}
|
|
4076
|
-
const asset = release.assets.find((a) => a.name ===
|
|
4250
|
+
const asset = release.assets.find((a) => a.name === FACTORY_ASSET_NAME);
|
|
4077
4251
|
if (!asset) {
|
|
4078
|
-
result.failureReason = `${
|
|
4252
|
+
result.failureReason = `${FACTORY_ASSET_NAME} not found in release`;
|
|
4079
4253
|
return result;
|
|
4080
4254
|
}
|
|
4081
4255
|
let archive = null;
|
|
4082
4256
|
try {
|
|
4083
4257
|
archive = await downloadAndExtractAsset(token, asset, targetDir, ".temp-factory-download");
|
|
4084
4258
|
const extractedEntries = (0, import_fs7.readdirSync)(archive.extractedRoot);
|
|
4085
|
-
const extractedFolder = extractedEntries.find((e) => e.toLowerCase() ===
|
|
4259
|
+
const extractedFolder = extractedEntries.find((e) => e.toLowerCase() === FACTORY_ROOT_FOLDER.toLowerCase());
|
|
4086
4260
|
if (!extractedFolder) {
|
|
4087
|
-
result.failureReason = `No ${
|
|
4261
|
+
result.failureReason = `No ${FACTORY_ROOT_FOLDER}/ folder in archive`;
|
|
4088
4262
|
return result;
|
|
4089
4263
|
}
|
|
4090
4264
|
const extractedPath = (0, import_path7.join)(archive.extractedRoot, extractedFolder);
|
|
@@ -4219,8 +4393,8 @@ function extractFirstHeading(filePath) {
|
|
|
4219
4393
|
}
|
|
4220
4394
|
} catch {
|
|
4221
4395
|
}
|
|
4222
|
-
const
|
|
4223
|
-
return
|
|
4396
|
+
const basename2 = filePath.split(/[/\\]/).pop() ?? "";
|
|
4397
|
+
return basename2.replace(/\.md$/i, "").replace(/[-_]+/g, " ");
|
|
4224
4398
|
}
|
|
4225
4399
|
function formatPathRef(contextPath, description, agent) {
|
|
4226
4400
|
if (agent === "github-copilot") {
|
|
@@ -4471,6 +4645,7 @@ var package_default = {
|
|
|
4471
4645
|
scripts: {
|
|
4472
4646
|
dev: "tsx src/index.ts",
|
|
4473
4647
|
build: 'esbuild src/index.ts --bundle --platform=node --banner:js="#!/usr/bin/env node" --outfile=wrapper/bin/installer.js',
|
|
4648
|
+
"build:all": "npm run build",
|
|
4474
4649
|
"publish:wrapper": "cd wrapper && npm publish"
|
|
4475
4650
|
},
|
|
4476
4651
|
dependencies: {
|