allagents 0.3.0 → 0.5.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.
Files changed (3) hide show
  1. package/README.md +21 -0
  2. package/dist/index.js +212 -49
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -60,6 +60,9 @@ bunx allagents
60
60
  allagents workspace init my-workspace
61
61
  cd my-workspace
62
62
 
63
+ # Or initialize from a remote GitHub template
64
+ allagents workspace init my-workspace --from owner/repo/path/to/template
65
+
63
66
  # Add a marketplace (or let auto-registration handle it)
64
67
  allagents plugin marketplace add anthropics/claude-plugins-official
65
68
 
@@ -71,6 +74,23 @@ allagents workspace plugin add my-plugin@someuser/their-repo
71
74
  allagents workspace sync
72
75
  ```
73
76
 
77
+ ### Initialize from Remote Template
78
+
79
+ Start a new workspace instantly from any GitHub repository containing a `workspace.yaml`:
80
+
81
+ ```bash
82
+ # From GitHub URL
83
+ allagents workspace init ~/my-project --from https://github.com/myorg/templates/tree/main/nodejs
84
+
85
+ # From shorthand
86
+ allagents workspace init ~/my-project --from myorg/templates/nodejs
87
+
88
+ # From repo root (looks for .allagents/workspace.yaml or workspace.yaml)
89
+ allagents workspace init ~/my-project --from myorg/templates
90
+ ```
91
+
92
+ This fetches the workspace configuration directly from GitHub - no cloning required.
93
+
74
94
  ## Commands
75
95
 
76
96
  ### Workspace Commands
@@ -78,6 +98,7 @@ allagents workspace sync
78
98
  ```bash
79
99
  # Initialize a new workspace from template
80
100
  allagents workspace init <path>
101
+ allagents workspace init <path> --from <source> # From local path or GitHub URL
81
102
 
82
103
  # Sync all plugins to workspace (non-destructive)
83
104
  allagents workspace sync [options]
package/dist/index.js CHANGED
@@ -11054,9 +11054,9 @@ var {
11054
11054
  } = import__.default;
11055
11055
 
11056
11056
  // src/cli/index.ts
11057
- import { readFileSync as readFileSync2 } from "node:fs";
11058
- import { dirname as dirname6, join as join11 } from "node:path";
11059
- import { fileURLToPath as fileURLToPath3 } from "node:url";
11057
+ import { readFileSync as readFileSync3 } from "node:fs";
11058
+ import { dirname as dirname7, join as join12 } from "node:path";
11059
+ import { fileURLToPath as fileURLToPath4 } from "node:url";
11060
11060
 
11061
11061
  // src/core/workspace.ts
11062
11062
  import { mkdir as mkdir5, readFile as readFile6, writeFile as writeFile4, copyFile as copyFile2 } from "node:fs/promises";
@@ -19365,14 +19365,25 @@ function parseGitHubUrl(url) {
19365
19365
  }
19366
19366
  return null;
19367
19367
  }
19368
- const subpathPattern = /^https?:\/\/(?:www\.)?github\.com\/([^/]+)\/([^/]+?)\/tree\/[^/]+\/(.+)$/;
19368
+ const subpathPattern = /^https?:\/\/(?:www\.)?github\.com\/([^/]+)\/([^/]+?)\/tree\/([^/]+)\/(.+)$/;
19369
19369
  const subpathMatch = normalized.match(subpathPattern);
19370
19370
  if (subpathMatch) {
19371
19371
  const owner = subpathMatch[1];
19372
19372
  const repo = subpathMatch[2]?.replace(/\.git$/, "");
19373
- const subpath = subpathMatch[3];
19374
- if (owner && repo && subpath) {
19375
- return { owner, repo, subpath };
19373
+ const branch = subpathMatch[3];
19374
+ const subpath = subpathMatch[4];
19375
+ if (owner && repo && branch && subpath) {
19376
+ return { owner, repo, branch, subpath };
19377
+ }
19378
+ }
19379
+ const branchPattern = /^https?:\/\/(?:www\.)?github\.com\/([^/]+)\/([^/]+?)\/tree\/([^/]+)$/;
19380
+ const branchMatch = normalized.match(branchPattern);
19381
+ if (branchMatch) {
19382
+ const owner = branchMatch[1];
19383
+ const repo = branchMatch[2]?.replace(/\.git$/, "");
19384
+ const branch = branchMatch[3];
19385
+ if (owner && repo && branch) {
19386
+ return { owner, repo, branch };
19376
19387
  }
19377
19388
  }
19378
19389
  const basicPattern = /^https?:\/\/(?:www\.)?github\.com\/([^/]+)\/([^/]+?)(?:\.git)?(?:\/.*)?$/;
@@ -19441,6 +19452,7 @@ function parseFileSource(source, baseDir = process.cwd()) {
19441
19452
  normalized: source,
19442
19453
  owner: parsed.owner,
19443
19454
  repo: parsed.repo,
19455
+ ...parsed.branch && { branch: parsed.branch },
19444
19456
  ...parsed.subpath && { filePath: parsed.subpath }
19445
19457
  };
19446
19458
  }
@@ -21060,6 +21072,130 @@ async function autoRegisterMarketplace(name) {
21060
21072
  };
21061
21073
  }
21062
21074
 
21075
+ // src/core/github-fetch.ts
21076
+ async function resolveBranchAndSubpath(owner, repo, pathAfterTree) {
21077
+ const parts = pathAfterTree.split("/");
21078
+ for (let i2 = parts.length - 1;i2 >= 1; i2--) {
21079
+ const branch = parts.slice(0, i2).join("/");
21080
+ const subpath = parts.slice(i2).join("/");
21081
+ try {
21082
+ await execa("gh", [
21083
+ "api",
21084
+ `repos/${owner}/${repo}/commits/${encodeURIComponent(branch)}`,
21085
+ "--silent"
21086
+ ]);
21087
+ return { branch, ...subpath && { subpath } };
21088
+ } catch {}
21089
+ }
21090
+ return null;
21091
+ }
21092
+ async function fetchFileFromGitHub(owner, repo, path3, branch) {
21093
+ try {
21094
+ let endpoint = `repos/${owner}/${repo}/contents/${path3}`;
21095
+ if (branch) {
21096
+ endpoint += `?ref=${encodeURIComponent(branch)}`;
21097
+ }
21098
+ const result = await execa("gh", [
21099
+ "api",
21100
+ endpoint,
21101
+ "--jq",
21102
+ ".content"
21103
+ ]);
21104
+ if (result.stdout) {
21105
+ const content = Buffer.from(result.stdout, "base64").toString("utf-8");
21106
+ return content;
21107
+ }
21108
+ return null;
21109
+ } catch {
21110
+ return null;
21111
+ }
21112
+ }
21113
+ async function fetchWorkspaceFromGitHub(url) {
21114
+ const parsed = parseGitHubUrl(url);
21115
+ if (!parsed) {
21116
+ return {
21117
+ success: false,
21118
+ error: "Invalid GitHub URL format. Expected: https://github.com/owner/repo"
21119
+ };
21120
+ }
21121
+ const { owner, repo, branch, subpath } = parsed;
21122
+ try {
21123
+ await execa("gh", ["--version"]);
21124
+ } catch {
21125
+ return {
21126
+ success: false,
21127
+ error: "gh CLI not installed. Install from: https://cli.github.com"
21128
+ };
21129
+ }
21130
+ try {
21131
+ await execa("gh", ["repo", "view", `${owner}/${repo}`, "--json", "name"]);
21132
+ } catch (error) {
21133
+ if (error instanceof Error) {
21134
+ const errorMessage = error.message.toLowerCase();
21135
+ if (errorMessage.includes("not found") || errorMessage.includes("404") || errorMessage.includes("could not resolve to a repository")) {
21136
+ return {
21137
+ success: false,
21138
+ error: `Repository not found: ${owner}/${repo}`
21139
+ };
21140
+ }
21141
+ if (errorMessage.includes("auth") || errorMessage.includes("authentication")) {
21142
+ return {
21143
+ success: false,
21144
+ error: "GitHub authentication required. Run: gh auth login"
21145
+ };
21146
+ }
21147
+ }
21148
+ return {
21149
+ success: false,
21150
+ error: `Failed to access repository: ${error instanceof Error ? error.message : String(error)}`
21151
+ };
21152
+ }
21153
+ const basePath = subpath || "";
21154
+ const pathsToTry = basePath ? [
21155
+ `${basePath}/${CONFIG_DIR}/${WORKSPACE_CONFIG_FILE}`,
21156
+ `${basePath}/${WORKSPACE_CONFIG_FILE}`
21157
+ ] : [
21158
+ `${CONFIG_DIR}/${WORKSPACE_CONFIG_FILE}`,
21159
+ WORKSPACE_CONFIG_FILE
21160
+ ];
21161
+ for (const path3 of pathsToTry) {
21162
+ const content = await fetchFileFromGitHub(owner, repo, path3, branch);
21163
+ if (content) {
21164
+ return {
21165
+ success: true,
21166
+ content
21167
+ };
21168
+ }
21169
+ }
21170
+ if (branch && subpath && !branch.includes("/")) {
21171
+ const resolved = await resolveBranchAndSubpath(owner, repo, `${branch}/${subpath}`);
21172
+ if (resolved && resolved.branch !== branch) {
21173
+ const newBasePath = resolved.subpath || "";
21174
+ const newPathsToTry = newBasePath ? [
21175
+ `${newBasePath}/${CONFIG_DIR}/${WORKSPACE_CONFIG_FILE}`,
21176
+ `${newBasePath}/${WORKSPACE_CONFIG_FILE}`
21177
+ ] : [
21178
+ `${CONFIG_DIR}/${WORKSPACE_CONFIG_FILE}`,
21179
+ WORKSPACE_CONFIG_FILE
21180
+ ];
21181
+ for (const path3 of newPathsToTry) {
21182
+ const content = await fetchFileFromGitHub(owner, repo, path3, resolved.branch);
21183
+ if (content) {
21184
+ return {
21185
+ success: true,
21186
+ content
21187
+ };
21188
+ }
21189
+ }
21190
+ }
21191
+ }
21192
+ return {
21193
+ success: false,
21194
+ error: `No workspace.yaml found in: ${owner}/${repo}${branch ? `@${branch}` : ""}${subpath ? `/${subpath}` : ""}
21195
+ Expected at: ${pathsToTry.join(" or ")}`
21196
+ };
21197
+ }
21198
+
21063
21199
  // src/core/workspace.ts
21064
21200
  async function initWorkspace(targetPath = ".", options2 = {}) {
21065
21201
  const absoluteTarget = resolve5(targetPath);
@@ -21079,48 +21215,72 @@ async function initWorkspace(targetPath = ".", options2 = {}) {
21079
21215
  let workspaceYamlContent;
21080
21216
  let sourceDir;
21081
21217
  if (options2.from) {
21082
- const fromPath = resolve5(options2.from);
21083
- if (!existsSync7(fromPath)) {
21084
- throw new Error(`Template not found: ${fromPath}`);
21085
- }
21086
- const { stat: stat2 } = await import("node:fs/promises");
21087
- const fromStat = await stat2(fromPath);
21088
- let sourceYamlPath;
21089
- if (fromStat.isDirectory()) {
21090
- const nestedPath = join8(fromPath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
21091
- const rootPath = join8(fromPath, WORKSPACE_CONFIG_FILE);
21092
- if (existsSync7(nestedPath)) {
21093
- sourceYamlPath = nestedPath;
21094
- sourceDir = fromPath;
21095
- } else if (existsSync7(rootPath)) {
21096
- sourceYamlPath = rootPath;
21097
- sourceDir = fromPath;
21098
- } else {
21099
- throw new Error(`No workspace.yaml found in: ${fromPath}
21100
- Expected at: ${nestedPath} or ${rootPath}`);
21101
- }
21102
- } else {
21103
- sourceYamlPath = fromPath;
21104
- const parentDir = dirname5(fromPath);
21105
- if (parentDir.endsWith(CONFIG_DIR)) {
21106
- sourceDir = dirname5(parentDir);
21107
- } else {
21108
- sourceDir = parentDir;
21218
+ if (isGitHubUrl(options2.from)) {
21219
+ const fetchResult = await fetchWorkspaceFromGitHub(options2.from);
21220
+ if (!fetchResult.success || !fetchResult.content) {
21221
+ throw new Error(fetchResult.error || "Failed to fetch workspace from GitHub");
21109
21222
  }
21110
- }
21111
- workspaceYamlContent = await readFile6(sourceYamlPath, "utf-8");
21112
- if (sourceDir) {
21223
+ workspaceYamlContent = fetchResult.content;
21113
21224
  const parsed2 = load(workspaceYamlContent);
21114
21225
  const workspace = parsed2?.workspace;
21115
21226
  if (workspace?.source) {
21116
21227
  const source = workspace.source;
21117
21228
  if (!isGitHubUrl(source) && !isAbsolute2(source)) {
21118
- workspace.source = resolve5(sourceDir, source);
21119
- workspaceYamlContent = dump(parsed2, { lineWidth: -1 });
21229
+ const parsedUrl = parseGitHubUrl(options2.from);
21230
+ if (parsedUrl) {
21231
+ const basePath = parsedUrl.subpath || "";
21232
+ const baseDir = basePath.replace(/\/?\.allagents\/workspace\.yaml$/, "").replace(/\/?workspace\.yaml$/, "");
21233
+ const sourcePath = baseDir ? `${baseDir}/${source}` : source;
21234
+ workspace.source = `https://github.com/${parsedUrl.owner}/${parsedUrl.repo}/tree/main/${sourcePath}`;
21235
+ workspaceYamlContent = dump(parsed2, { lineWidth: -1 });
21236
+ }
21237
+ }
21238
+ }
21239
+ console.log(`✓ Using workspace.yaml from: ${options2.from}`);
21240
+ } else {
21241
+ const fromPath = resolve5(options2.from);
21242
+ if (!existsSync7(fromPath)) {
21243
+ throw new Error(`Template not found: ${fromPath}`);
21244
+ }
21245
+ const { stat: stat2 } = await import("node:fs/promises");
21246
+ const fromStat = await stat2(fromPath);
21247
+ let sourceYamlPath;
21248
+ if (fromStat.isDirectory()) {
21249
+ const nestedPath = join8(fromPath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
21250
+ const rootPath = join8(fromPath, WORKSPACE_CONFIG_FILE);
21251
+ if (existsSync7(nestedPath)) {
21252
+ sourceYamlPath = nestedPath;
21253
+ sourceDir = fromPath;
21254
+ } else if (existsSync7(rootPath)) {
21255
+ sourceYamlPath = rootPath;
21256
+ sourceDir = fromPath;
21257
+ } else {
21258
+ throw new Error(`No workspace.yaml found in: ${fromPath}
21259
+ Expected at: ${nestedPath} or ${rootPath}`);
21260
+ }
21261
+ } else {
21262
+ sourceYamlPath = fromPath;
21263
+ const parentDir = dirname5(fromPath);
21264
+ if (parentDir.endsWith(CONFIG_DIR)) {
21265
+ sourceDir = dirname5(parentDir);
21266
+ } else {
21267
+ sourceDir = parentDir;
21120
21268
  }
21121
21269
  }
21270
+ workspaceYamlContent = await readFile6(sourceYamlPath, "utf-8");
21271
+ if (sourceDir) {
21272
+ const parsed2 = load(workspaceYamlContent);
21273
+ const workspace = parsed2?.workspace;
21274
+ if (workspace?.source) {
21275
+ const source = workspace.source;
21276
+ if (!isGitHubUrl(source) && !isAbsolute2(source)) {
21277
+ workspace.source = resolve5(sourceDir, source);
21278
+ workspaceYamlContent = dump(parsed2, { lineWidth: -1 });
21279
+ }
21280
+ }
21281
+ }
21282
+ console.log(`✓ Using workspace.yaml from: ${sourceYamlPath}`);
21122
21283
  }
21123
- console.log(`✓ Using workspace.yaml from: ${sourceYamlPath}`);
21124
21284
  } else {
21125
21285
  const defaultYamlPath = join8(defaultTemplatePath, CONFIG_DIR, WORKSPACE_CONFIG_FILE);
21126
21286
  if (!existsSync7(defaultYamlPath)) {
@@ -21747,6 +21907,9 @@ pluginCommand.command("validate <path>").description("Validate plugin structure
21747
21907
  });
21748
21908
 
21749
21909
  // src/cli/commands/update.ts
21910
+ import { readFileSync as readFileSync2 } from "node:fs";
21911
+ import { dirname as dirname6, join as join11 } from "node:path";
21912
+ import { fileURLToPath as fileURLToPath3 } from "node:url";
21750
21913
  function detectPackageManagerFromPath(scriptPath) {
21751
21914
  if (scriptPath.includes(".bun")) {
21752
21915
  return "bun";
@@ -21756,12 +21919,12 @@ function detectPackageManagerFromPath(scriptPath) {
21756
21919
  function detectPackageManager() {
21757
21920
  return detectPackageManagerFromPath(process.argv[1] ?? "");
21758
21921
  }
21759
- async function getCurrentVersion() {
21922
+ function getCurrentVersion() {
21760
21923
  try {
21761
- const { createRequire: createRequire2 } = await import("node:module");
21762
- const require2 = createRequire2(import.meta.url);
21763
- const pkg = require2("../../../package.json");
21764
- return pkg.version;
21924
+ const __dirname2 = dirname6(fileURLToPath3(import.meta.url));
21925
+ const packageJsonPath = join11(__dirname2, "..", "package.json");
21926
+ const packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf-8"));
21927
+ return packageJson.version;
21765
21928
  } catch {
21766
21929
  return "unknown";
21767
21930
  }
@@ -21780,7 +21943,7 @@ var updateCommand = new Command("update").description("Update allagents to the l
21780
21943
  } else {
21781
21944
  packageManager = detectPackageManager();
21782
21945
  }
21783
- const currentVersion = await getCurrentVersion();
21946
+ const currentVersion = getCurrentVersion();
21784
21947
  console.log(`Current version: ${currentVersion}`);
21785
21948
  console.log(`Updating allagents using ${packageManager}...
21786
21949
  `);
@@ -21815,9 +21978,9 @@ Update complete.`);
21815
21978
  });
21816
21979
 
21817
21980
  // src/cli/index.ts
21818
- var __dirname2 = dirname6(fileURLToPath3(import.meta.url));
21819
- var packageJsonPath = join11(__dirname2, "..", "package.json");
21820
- var packageJson = JSON.parse(readFileSync2(packageJsonPath, "utf-8"));
21981
+ var __dirname2 = dirname7(fileURLToPath4(import.meta.url));
21982
+ var packageJsonPath = join12(__dirname2, "..", "package.json");
21983
+ var packageJson = JSON.parse(readFileSync3(packageJsonPath, "utf-8"));
21821
21984
  var program2 = new Command;
21822
21985
  program2.name("allagents").description("CLI tool for managing multi-repo AI agent workspaces with plugin synchronization").version(packageJson.version);
21823
21986
  program2.addCommand(workspaceCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "allagents",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "CLI tool for managing multi-repo AI agent workspaces with plugin synchronization",
5
5
  "type": "module",
6
6
  "bin": {
@@ -14,7 +14,7 @@
14
14
  "docs:install": "bun install --cwd docs",
15
15
  "docs:build": "bun run --cwd docs build",
16
16
  "dev": "bun run src/cli/index.ts",
17
- "test": "bun test tests/unit/validators tests/unit/utils tests/unit/models && bun test tests/unit/core/marketplace.test.ts tests/unit/core/sync.test.ts tests/unit/core/transform-glob.test.ts && bun test tests/unit/core/plugin.test.ts",
17
+ "test": "bun test tests/unit/validators tests/unit/utils tests/unit/models && bun test tests/unit/core/marketplace.test.ts tests/unit/core/sync.test.ts tests/unit/core/transform-glob.test.ts tests/unit/core/github-fetch.test.ts && bun test tests/unit/core/plugin.test.ts",
18
18
  "test:watch": "bun test --watch",
19
19
  "test:coverage": "bun test --coverage",
20
20
  "test:integration": "bats tests/integration/*.bats",