dlw-machine-setup 0.5.15 → 0.5.17

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 +84 -46
  2. package/package.json +1 -1
package/bin/installer.js CHANGED
@@ -3388,6 +3388,7 @@ async function tryOrgReposList(headers, topic) {
3388
3388
  var import_fs = require("fs");
3389
3389
  var import_path = require("path");
3390
3390
  var import_os = require("os");
3391
+ var import_child_process = require("child_process");
3391
3392
  var GITHUB_CLIENT_ID = "Ov23liwpMumAhwVufZ7N";
3392
3393
  var GITHUB_DEVICE_CODE_URL = "https://github.com/login/device/code";
3393
3394
  var GITHUB_TOKEN_URL = "https://github.com/login/oauth/access_token";
@@ -3511,11 +3512,26 @@ async function authenticateWithGitHub() {
3511
3512
  console.log("You'll authenticate once, and the token will be cached for future use.\n");
3512
3513
  console.log("Requesting authorization code...");
3513
3514
  const deviceCodeData = await requestDeviceCode();
3515
+ let copied = false;
3516
+ try {
3517
+ const os = (0, import_os.platform)();
3518
+ if (os === "win32") {
3519
+ (0, import_child_process.execSync)(`echo ${deviceCodeData.user_code} | clip`, { stdio: "ignore" });
3520
+ copied = true;
3521
+ } else if (os === "darwin") {
3522
+ (0, import_child_process.execSync)(`echo "${deviceCodeData.user_code}" | pbcopy`, { stdio: "ignore" });
3523
+ copied = true;
3524
+ } else {
3525
+ (0, import_child_process.execSync)(`echo "${deviceCodeData.user_code}" | xclip -selection clipboard`, { stdio: "ignore" });
3526
+ copied = true;
3527
+ }
3528
+ } catch {
3529
+ }
3514
3530
  console.log("\n\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\u2557");
3515
3531
  console.log("\u2551 GitHub Authentication \u2551");
3516
3532
  console.log("\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\u255D\n");
3517
3533
  console.log(`1. Visit: ${deviceCodeData.verification_uri}`);
3518
- console.log(`2. Enter code: ${deviceCodeData.user_code}`);
3534
+ console.log(`2. Enter code: ${deviceCodeData.user_code}${copied ? " (copied to clipboard!)" : ""}`);
3519
3535
  console.log("\nWaiting for authentication...");
3520
3536
  console.log("(This window will continue automatically once you approve)\n");
3521
3537
  const accessToken = await pollForToken(
@@ -3631,7 +3647,7 @@ __export(steps_exports, {
3631
3647
  // src/steps/resources/fetch-contexts.ts
3632
3648
  var import_fs2 = require("fs");
3633
3649
  var import_path2 = require("path");
3634
- var import_child_process = require("child_process");
3650
+ var import_child_process2 = require("child_process");
3635
3651
  var MIN_FILE_SIZE = 1024;
3636
3652
  var fetch_contexts_default = defineStep({
3637
3653
  name: "fetch-contexts",
@@ -3640,10 +3656,20 @@ var fetch_contexts_default = defineStep({
3640
3656
  execute: async (ctx) => {
3641
3657
  const uniqueDomains = [...new Set(ctx.config.technologies.flatMap((p) => p.domains))];
3642
3658
  const domainValues = uniqueDomains.map((d) => d.toLowerCase());
3643
- const downloadResult = await fetchContexts(domainValues, ctx.token, ctx.repo, ctx.config.projectPath);
3659
+ if (!ctx.contextRepo) {
3660
+ for (const domain of domainValues) {
3661
+ ctx.installed.domainsFailed = domainValues;
3662
+ }
3663
+ return {
3664
+ status: "failed",
3665
+ detail: "Context repo not found (topic: context-data)"
3666
+ };
3667
+ }
3668
+ const downloadResult = await fetchContexts(domainValues, ctx.token, ctx.contextRepo, ctx.config.projectPath);
3644
3669
  ctx.installed.domainsInstalled = downloadResult.successful;
3645
3670
  ctx.installed.domainsFailed = downloadResult.failed;
3646
3671
  ctx.installed.failureReasons = downloadResult.failureReasons;
3672
+ ctx.installed.contextReleaseVersion = downloadResult.releaseVersion;
3647
3673
  const domainColWidth = Math.max(...domainValues.map((d) => d.length), 8) + 2;
3648
3674
  console.log("");
3649
3675
  for (const domain of domainValues) {
@@ -3667,7 +3693,7 @@ var fetch_contexts_default = defineStep({
3667
3693
  async function fetchContexts(domains, token, repo, targetDir) {
3668
3694
  const result = { successful: [], failed: [], failureReasons: {} };
3669
3695
  if (domains.length === 0) return result;
3670
- const tarCheck = (0, import_child_process.spawnSync)("tar", ["--version"], { stdio: "ignore" });
3696
+ const tarCheck = (0, import_child_process2.spawnSync)("tar", ["--version"], { stdio: "ignore" });
3671
3697
  if (tarCheck.status !== 0) {
3672
3698
  throw new Error("tar command not found. Please ensure tar is installed and available in your PATH.");
3673
3699
  }
@@ -3683,52 +3709,58 @@ async function fetchContexts(domains, token, repo, targetDir) {
3683
3709
  throw new Error(`GitHub API error (${releaseResponse.status}): ${getReadableError(releaseResponse.status)}`);
3684
3710
  }
3685
3711
  const releaseData = await releaseResponse.json();
3712
+ result.releaseVersion = releaseData.tag_name;
3713
+ const asset = releaseData.assets?.find((a) => a.name.endsWith(".tar.gz"));
3714
+ if (!asset) {
3715
+ for (const domain of domains) {
3716
+ result.failed.push(domain);
3717
+ result.failureReasons[domain] = "No tar.gz asset in release";
3718
+ }
3719
+ return result;
3720
+ }
3686
3721
  const contextsDir = (0, import_path2.join)(targetDir, "_ai-context");
3687
3722
  const tempDir = (0, import_path2.join)(targetDir, ".temp-download");
3688
3723
  try {
3689
3724
  if (!(0, import_fs2.existsSync)(contextsDir)) (0, import_fs2.mkdirSync)(contextsDir, { recursive: true });
3690
3725
  if ((0, import_fs2.existsSync)(tempDir)) (0, import_fs2.rmSync)(tempDir, { recursive: true, force: true });
3691
3726
  (0, import_fs2.mkdirSync)(tempDir, { recursive: true });
3727
+ const downloadHeaders = {
3728
+ "Accept": "application/octet-stream",
3729
+ "Authorization": `Bearer ${token}`
3730
+ };
3731
+ const response = await fetchWithRetry(asset.url, { headers: downloadHeaders });
3732
+ if (!response.ok) {
3733
+ throw new Error(`Download failed: ${getReadableError(response.status)}`);
3734
+ }
3735
+ const archivePath = (0, import_path2.join)(tempDir, asset.name);
3736
+ const arrayBuffer = await response.arrayBuffer();
3737
+ (0, import_fs2.writeFileSync)(archivePath, Buffer.from(arrayBuffer));
3738
+ const stats = (0, import_fs2.statSync)(archivePath);
3739
+ if (stats.size < MIN_FILE_SIZE) {
3740
+ throw new Error("File corrupted");
3741
+ }
3742
+ const listResult = (0, import_child_process2.spawnSync)("tar", ["-tzf", archivePath], { encoding: "utf8" });
3743
+ if (listResult.status !== 0) throw new Error("Failed to read archive contents");
3744
+ const resolvedTempDir = (0, import_path2.resolve)(tempDir);
3745
+ for (const entry of listResult.stdout.split("\n").filter(Boolean)) {
3746
+ const entryPath = (0, import_path2.resolve)((0, import_path2.join)(tempDir, entry.replace(/\/$/, "")));
3747
+ if (!entryPath.startsWith(resolvedTempDir + import_path2.sep)) {
3748
+ throw new Error(`Archive contains unsafe path: ${entry}`);
3749
+ }
3750
+ }
3751
+ const extractResult = (0, import_child_process2.spawnSync)("tar", ["-xzf", archivePath, "-C", tempDir], { stdio: "ignore" });
3752
+ if (extractResult.status !== 0) throw new Error("Archive extraction failed");
3753
+ const extractedFolders = (0, import_fs2.readdirSync)(tempDir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
3692
3754
  for (const domain of domains) {
3693
3755
  try {
3694
- const domainPath = (0, import_path2.join)(contextsDir, domain);
3695
- const archiveName = `${domain.toLowerCase()}.tar.gz`;
3696
- const asset = releaseData.assets?.find((a) => a.name === archiveName);
3697
- if (!asset) {
3756
+ const match = extractedFolders.find((f) => f.toLowerCase() === domain.toLowerCase());
3757
+ if (!match) {
3698
3758
  result.failed.push(domain);
3699
- result.failureReasons[domain] = "Not found in release";
3759
+ result.failureReasons[domain] = "Not found in archive";
3700
3760
  continue;
3701
3761
  }
3702
- const downloadHeaders = {
3703
- "Accept": "application/octet-stream",
3704
- "Authorization": `Bearer ${token}`
3705
- };
3706
- const response = await fetchWithRetry(asset.url, { headers: downloadHeaders });
3707
- if (!response.ok) {
3708
- throw new Error(`Download failed: ${getReadableError(response.status)}`);
3709
- }
3710
- const archivePath = (0, import_path2.join)(tempDir, archiveName);
3711
- const arrayBuffer = await response.arrayBuffer();
3712
- (0, import_fs2.writeFileSync)(archivePath, Buffer.from(arrayBuffer));
3713
- const stats = (0, import_fs2.statSync)(archivePath);
3714
- if (stats.size < MIN_FILE_SIZE) {
3715
- throw new Error("File corrupted");
3716
- }
3717
- const listResult = (0, import_child_process.spawnSync)("tar", ["-tzf", archivePath], { encoding: "utf8" });
3718
- if (listResult.status !== 0) throw new Error("Failed to read archive contents");
3719
- const resolvedTempDir = (0, import_path2.resolve)(tempDir);
3720
- for (const entry of listResult.stdout.split("\n").filter(Boolean)) {
3721
- const entryPath = (0, import_path2.resolve)((0, import_path2.join)(tempDir, entry.replace(/\/$/, "")));
3722
- if (!entryPath.startsWith(resolvedTempDir + import_path2.sep)) {
3723
- throw new Error(`Archive contains unsafe path: ${entry}`);
3724
- }
3725
- }
3726
- const extractResult = (0, import_child_process.spawnSync)("tar", ["-xzf", archivePath, "-C", tempDir], { stdio: "ignore" });
3727
- if (extractResult.status !== 0) throw new Error("Archive extraction failed");
3728
- const extractedEntries = (0, import_fs2.readdirSync)(tempDir);
3729
- const extractedFolder = extractedEntries.find((e) => e.toLowerCase() === domain.toLowerCase());
3730
- if (!extractedFolder) throw new Error("Extraction failed");
3731
- copyDirectory((0, import_path2.join)(tempDir, extractedFolder), domainPath);
3762
+ const domainPath = (0, import_path2.join)(contextsDir, domain);
3763
+ copyDirectory((0, import_path2.join)(tempDir, match), domainPath);
3732
3764
  result.successful.push(domain);
3733
3765
  } catch (error) {
3734
3766
  result.failed.push(domain);
@@ -3780,7 +3812,7 @@ function getReadableError(status) {
3780
3812
  // src/steps/resources/fetch-factory.ts
3781
3813
  var import_fs3 = require("fs");
3782
3814
  var import_path3 = require("path");
3783
- var import_child_process2 = require("child_process");
3815
+ var import_child_process3 = require("child_process");
3784
3816
  var MIN_FILE_SIZE2 = 1024;
3785
3817
  function getFactoryAsset(agent) {
3786
3818
  switch (agent) {
@@ -3805,7 +3837,7 @@ var fetch_factory_default = defineStep({
3805
3837
  });
3806
3838
  async function fetchFactory(token, repo, targetDir, agent) {
3807
3839
  const result = { success: false, filesInstalled: [] };
3808
- const tarCheck = (0, import_child_process2.spawnSync)("tar", ["--version"], { stdio: "ignore" });
3840
+ const tarCheck = (0, import_child_process3.spawnSync)("tar", ["--version"], { stdio: "ignore" });
3809
3841
  if (tarCheck.status !== 0) {
3810
3842
  result.failureReason = "tar command not found";
3811
3843
  return result;
@@ -3848,7 +3880,7 @@ async function fetchFactory(token, repo, targetDir, agent) {
3848
3880
  result.failureReason = "Downloaded file corrupted (too small)";
3849
3881
  return result;
3850
3882
  }
3851
- const listResult = (0, import_child_process2.spawnSync)("tar", ["-tzf", archivePath], { encoding: "utf8" });
3883
+ const listResult = (0, import_child_process3.spawnSync)("tar", ["-tzf", archivePath], { encoding: "utf8" });
3852
3884
  if (listResult.status !== 0) {
3853
3885
  result.failureReason = "Failed to read archive contents";
3854
3886
  return result;
@@ -3861,7 +3893,7 @@ async function fetchFactory(token, repo, targetDir, agent) {
3861
3893
  return result;
3862
3894
  }
3863
3895
  }
3864
- const extractResult = (0, import_child_process2.spawnSync)("tar", ["-xzf", archivePath, "-C", tempDir], { stdio: "ignore" });
3896
+ const extractResult = (0, import_child_process3.spawnSync)("tar", ["-xzf", archivePath, "-C", tempDir], { stdio: "ignore" });
3865
3897
  if (extractResult.status !== 0) {
3866
3898
  result.failureReason = "Archive extraction failed";
3867
3899
  return result;
@@ -4049,7 +4081,7 @@ var write_instructions_default = defineStep({
4049
4081
  when: (ctx) => (ctx.installed.domainsInstalled?.length ?? 0) > 0 || Object.keys(ctx.config.mcpConfig).length > 0 || ctx.installed.factoryInstalled,
4050
4082
  execute: async (ctx) => {
4051
4083
  const filteredMcpConfig = getFilteredMcpConfig(ctx);
4052
- const domains = ctx.installed.domainsInstalled;
4084
+ const domains = ctx.installed.domainsInstalled ?? [];
4053
4085
  const agent = ctx.config.agent;
4054
4086
  const projectPath = ctx.config.projectPath;
4055
4087
  const factoryInstalled = ctx.installed.factoryInstalled ?? false;
@@ -4422,7 +4454,7 @@ var update_gitignore_default = defineStep({
4422
4454
  var import_fs7 = require("fs");
4423
4455
  var import_path7 = require("path");
4424
4456
  var import_os2 = require("os");
4425
- var INSTALLER_VERSION = "0.5.15";
4457
+ var INSTALLER_VERSION = "0.5.17";
4426
4458
  var write_state_default = defineStep({
4427
4459
  name: "write-state",
4428
4460
  label: "Saving installation state",
@@ -4436,6 +4468,7 @@ var write_state_default = defineStep({
4436
4468
  installedAt: (/* @__PURE__ */ new Date()).toISOString(),
4437
4469
  installerVersion: INSTALLER_VERSION,
4438
4470
  releaseVersion: ctx.config.releaseVersion,
4471
+ contextReleaseVersion: ctx.installed.contextReleaseVersion ?? null,
4439
4472
  projectPath: ctx.config.projectPath,
4440
4473
  agent: ctx.config.agent,
4441
4474
  technologies: ctx.config.technologies.map((p) => p.id),
@@ -4542,10 +4575,14 @@ async function main() {
4542
4575
  try {
4543
4576
  const token = await getGitHubToken();
4544
4577
  console.log(" Locating repositories...");
4545
- const [repo, factoryRepo] = await Promise.all([
4578
+ const [repo, contextRepo, factoryRepo] = await Promise.all([
4546
4579
  discoverRepo(token),
4580
+ discoverRepo(token, "context-data").catch(() => null),
4547
4581
  discoverRepo(token, "factory-data").catch(() => null)
4548
4582
  ]);
4583
+ if (!contextRepo) {
4584
+ console.log(" \u26A0 Context repo not found \u2014 AI contexts will not be installed.");
4585
+ }
4549
4586
  if (!factoryRepo) {
4550
4587
  console.log(" \u26A0 Factory repo not found \u2014 Factory will not be installed.");
4551
4588
  }
@@ -4566,6 +4603,7 @@ async function main() {
4566
4603
  config,
4567
4604
  token,
4568
4605
  repo,
4606
+ contextRepo,
4569
4607
  factoryRepo,
4570
4608
  installed: {}
4571
4609
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dlw-machine-setup",
3
- "version": "0.5.15",
3
+ "version": "0.5.17",
4
4
  "description": "One-shot installer for The Machine toolchain",
5
5
  "bin": {
6
6
  "dlw-machine-setup": "bin/installer.js"