dlw-machine-setup 0.8.6 → 0.8.7

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.
Files changed (2) hide show
  1. package/bin/installer.js +59 -13
  2. package/package.json +1 -1
package/bin/installer.js CHANGED
@@ -3905,6 +3905,9 @@ ${endMarker}`;
3905
3905
  var claudeCodeProfile = {
3906
3906
  agent: "claude-code",
3907
3907
  instructionsFile: "CLAUDE.md",
3908
+ // Claude exposes a top-level `statusLine` setting in settings.json.
3909
+ // Bundles gate statusline-related ops with `when: 'statusline-supported'`.
3910
+ statusLineSupported: true,
3908
3911
  handlers: {
3909
3912
  agent: {
3910
3913
  supported: true,
@@ -3940,6 +3943,9 @@ var claudeCodeProfile = {
3940
3943
  var githubCopilotProfile = {
3941
3944
  agent: "github-copilot",
3942
3945
  instructionsFile: ".github/copilot-instructions.md",
3946
+ // No statusLine equivalent in Copilot CLI — drops Factory's statusline
3947
+ // op via the `statusline-supported` capability gate.
3948
+ statusLineSupported: false,
3943
3949
  handlers: {
3944
3950
  agent: {
3945
3951
  supported: true,
@@ -3957,12 +3963,35 @@ var githubCopilotProfile = {
3957
3963
  destination: (name) => `.github/skills/${name}/SKILL.md`
3958
3964
  },
3959
3965
  hook: {
3960
- // Hooks are Claude-only by policy (see plan doc). The bundle's
3961
- // hook-related ops are gated with `when: 'hooks-supported'`, so
3962
- // Copilot installs ship no hook events, no hook scripts, and no
3963
- // statusLine setting. Phase 4 (Copilot hook implementation) was
3964
- // canceled this is the permanent final state.
3965
- supported: false
3966
+ supported: true,
3967
+ scriptDir: ".github/hooks",
3968
+ configFile: ".github/hooks/hooks.json",
3969
+ configKey: "hooks",
3970
+ // Copilot's hooks.json requires a top-level { "version": 1 }.
3971
+ // Merged into the patch root once per install.
3972
+ configRoot: { version: 1 },
3973
+ mapEvent: (event) => {
3974
+ const map = {
3975
+ SessionStart: "sessionStart",
3976
+ SessionEnd: "sessionEnd",
3977
+ UserPromptSubmit: "userPromptSubmitted",
3978
+ PreToolUse: "preToolUse",
3979
+ PostToolUse: "postToolUse"
3980
+ };
3981
+ return map[event] ?? null;
3982
+ },
3983
+ // Copilot's cross-platform shape. We use the same `node <script>`
3984
+ // command for both shells — node is the same binary regardless of
3985
+ // shell, and Copilot picks `bash` or `powershell` based on the
3986
+ // host OS at runtime. The script's `matcher` is intentionally
3987
+ // dropped: Copilot has no per-tool matcher. Hooks that need
3988
+ // matcher semantics filter inline (Factory's hooks already do).
3989
+ buildHookEntry: (_asset, command) => ({
3990
+ type: "command",
3991
+ bash: command,
3992
+ powershell: command,
3993
+ timeoutSec: 30
3994
+ })
3966
3995
  },
3967
3996
  "instructions-snippet": {
3968
3997
  supported: true
@@ -4057,7 +4086,8 @@ function runBundleV2(manifest, ctx) {
4057
4086
  }
4058
4087
  for (const op of manifest.ops ?? []) {
4059
4088
  if (op.when === "hooks-supported" && !profile.handlers.hook.supported) continue;
4060
- executeOp(op, manifest.name, ctx, result);
4089
+ if (op.when === "statusline-supported" && !profile.statusLineSupported) continue;
4090
+ executeOp(substituteHookDir(op, profile), manifest.name, ctx, result);
4061
4091
  result.opsExecuted++;
4062
4092
  }
4063
4093
  writeGitignoreBlock(manifest, ctx, result);
@@ -4107,6 +4137,8 @@ function runAssetCopy(asset, handler, ctx, result) {
4107
4137
  function accumulateHook(asset, handler, hookPatches, ctx, result) {
4108
4138
  if (!handler.supported) return;
4109
4139
  if (!handler.configFile || !handler.configKey) return;
4140
+ const eventName = handler.mapEvent ? handler.mapEvent(asset.event) : asset.event;
4141
+ if (eventName === null) return;
4110
4142
  if (asset.script && handler.scriptDir) {
4111
4143
  const scriptSource = resolveBundlePath(asset.script, ctx);
4112
4144
  if ((0, import_fs6.existsSync)(scriptSource)) {
@@ -4119,19 +4151,33 @@ function accumulateHook(asset, handler, hookPatches, ctx, result) {
4119
4151
  }
4120
4152
  }
4121
4153
  const command = handler.scriptDir ? asset.command.replace(/\{hookDir\}/g, handler.scriptDir) : asset.command;
4122
- const entry = {
4123
- hooks: [{ type: "command", command }]
4124
- };
4125
- if (asset.matcher) entry.matcher = asset.matcher;
4154
+ const entry = handler.buildHookEntry ? handler.buildHookEntry(asset, command) : (() => {
4155
+ const e = {
4156
+ hooks: [{ type: "command", command }]
4157
+ };
4158
+ if (asset.matcher) e.matcher = asset.matcher;
4159
+ return e;
4160
+ })();
4126
4161
  let patch = hookPatches.get(handler.configFile);
4127
4162
  if (!patch) {
4128
- patch = {};
4163
+ patch = handler.configRoot ? { ...handler.configRoot } : {};
4129
4164
  hookPatches.set(handler.configFile, patch);
4130
4165
  }
4131
4166
  const root = patch[handler.configKey] ??= {};
4132
- const events = root[asset.event] ??= [];
4167
+ const events = root[eventName] ??= [];
4133
4168
  events.push(entry);
4134
4169
  }
4170
+ function substituteHookDir(op, profile) {
4171
+ const scriptDir = profile.handlers.hook.scriptDir;
4172
+ if (!scriptDir) return op;
4173
+ if (op.op === "copy") {
4174
+ return { ...op, to: op.to.replace(/\{hookDir\}/g, scriptDir) };
4175
+ }
4176
+ if (op.op === "merge-json") {
4177
+ return { ...op, file: op.file.replace(/\{hookDir\}/g, scriptDir) };
4178
+ }
4179
+ return op;
4180
+ }
4135
4181
  function writeGitignoreBlock(manifest, ctx, result) {
4136
4182
  if (!manifest.gitignore?.length) return;
4137
4183
  upsertMarkerBlock(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dlw-machine-setup",
3
- "version": "0.8.6",
3
+ "version": "0.8.7",
4
4
  "description": "One-shot installer for The Machine toolchain",
5
5
  "bin": {
6
6
  "dlw-machine-setup": "bin/installer.js"