@innominatum/agentforge-cli 1.0.1 → 1.0.6

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.
@@ -0,0 +1,36 @@
1
+ name: Publish Package to npmjs
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ # Alternatively, you can uncomment the following to publish whenever you push to main
7
+ # push:
8
+ # branches:
9
+ # - main
10
+
11
+ jobs:
12
+ build-and-publish:
13
+ runs-on: ubuntu-latest
14
+ env:
15
+ FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
16
+ permissions:
17
+ contents: read
18
+ id-token: write # Required for NPM Trusted Publishing (OIDC)
19
+ steps:
20
+ - name: Checkout code
21
+ uses: actions/checkout@v4
22
+
23
+ - name: Setup Node.js
24
+ uses: actions/setup-node@v4
25
+ with:
26
+ node-version: '20.x'
27
+ registry-url: 'https://registry.npmjs.org'
28
+
29
+ - name: Install dependencies
30
+ run: npm ci
31
+
32
+ - name: Build TypeScript code
33
+ run: npm run build
34
+
35
+ - name: Publish to NPM
36
+ run: npm publish --access public --provenance
package/README.md CHANGED
@@ -8,6 +8,14 @@ A powerful command-line interface to scaffold, manage, build, and deploy AI Agen
8
8
 
9
9
  ## Installation & Local Development
10
10
 
11
+ ### Global Installation (Recommended)
12
+ You can install the AgentForge CLI globally directly from NPM:
13
+
14
+ ```bash
15
+ npm install -g @innominatum/agentforge-cli
16
+ ```
17
+
18
+ ### Local Development
11
19
  Since you are modifying or maintaining the CLI source code, you should install and use it globally on your local machine using NPM's symlink feature:
12
20
 
13
21
  1. Clone this repository and navigate to its folder.
@@ -63,10 +71,23 @@ If you add a new command or change how the CLI works:
63
71
 
64
72
  ## NPM Publishing (Maintainers)
65
73
 
66
- When this CLI is ready for public release, ensure the following steps are taken:
67
- 1. Update the `version` in `package.json` (e.g., `"version": "1.0.1"`).
68
- 2. Ensure the `name` is correctly set to `"agentforge-cli"`.
69
- 3. Verify that the `"bin"` property is pointing to `"./dist/index.js"`.
70
- 4. Run `npm run build` to ensure the `dist/` directory is fully updated.
71
- 5. Login to your npm account using `npm login`.
72
- 6. Publish the package using `npm publish`.
74
+ ### Manual Publishing
75
+ When this CLI is ready for a new release:
76
+ 1. Update the `version` in `package.json` (e.g., from `"1.0.1"` to `"1.0.2"`).
77
+ 2. Run `npm run build` to ensure the `dist/` directory is fully updated.
78
+ 3. Login to your npm account using `npm login`.
79
+ 4. Publish the package using `npm publish --access public` (you will be prompted for your 2FA security key).
80
+
81
+ ### Automated Publishing (Trusted Publishing / OIDC)
82
+ To fully automate your CI/CD pipeline securely without using any hardcoded NPM tokens or bypassing 2FA, NPM provides "Trusted Publishing" with GitHub Actions:
83
+
84
+ 1. Go to the NPM website and navigate to the `@innominatum/agentforge-cli` package.
85
+ 2. Go to **Settings** > **Publishing Access**.
86
+ 3. Under **Trusted Publishers**, click **Add Publisher** > **GitHub Actions**.
87
+ 4. Fill in the repository details:
88
+ - **GitHub Organization/User:** `Innominatum-pt`
89
+ - **GitHub Repository:** `agentforge-cli`
90
+ - **Workflow file (optional):** `publish.yml`
91
+ 5. Click **Add Publisher**.
92
+
93
+ Once configured, the `.github/workflows/publish.yml` workflow provided in this repository will automatically securely authenticate via OIDC and publish your package whenever you create a new GitHub Release.
package/dist/index.js CHANGED
@@ -285,6 +285,19 @@ async function getConfig() {
285
285
  }
286
286
  return config;
287
287
  }
288
+ async function resolveAgentId(slug, config) {
289
+ try {
290
+ const listResponse = await axios_1.default.get(`${config.goclaw.api_url}/v1/agents`, {
291
+ headers: { Authorization: `Bearer ${config.goclaw.token}`, "X-GoClaw-User-Id": config.goclaw.username || "system" }
292
+ });
293
+ const agents = listResponse.data.agents || [];
294
+ const agent = agents.find((a) => a.agent_key === slug);
295
+ return agent ? agent.id : null;
296
+ }
297
+ catch (error) {
298
+ return null;
299
+ }
300
+ }
288
301
  const deployCmd = program
289
302
  .command("deploy")
290
303
  .description("Faz o deploy de entidades para a plataforma GoClaw");
@@ -336,7 +349,8 @@ deployCmd
336
349
  }
337
350
  }
338
351
  });
339
- async function deployContextFiles(slug, config) {
352
+ async function deployContextFiles(slug, config, resolvedId) {
353
+ const agentId = resolvedId || (await resolveAgentId(slug, config)) || slug;
340
354
  const basePath = getWorkspaceRoot();
341
355
  const agentPath = path_1.default.join(basePath, "agents", slug);
342
356
  if (!(await fs_extra_1.default.pathExists(agentPath))) {
@@ -363,7 +377,7 @@ async function deployContextFiles(slug, config) {
363
377
  }, ["context_files"]);
364
378
  const form = new form_data_1.default();
365
379
  form.append("file", fs_extra_1.default.createReadStream(tarPath));
366
- const url = `${config.goclaw.api_url}/v1/agents/${slug}/import?include=context_files`;
380
+ const url = `${config.goclaw.api_url}/v1/agents/${agentId}/import?include=context_files`;
367
381
  await axios_1.default.post(url, form, {
368
382
  headers: {
369
383
  ...form.getHeaders(),
@@ -417,20 +431,8 @@ deployCmd
417
431
  const agentConfig = await fs_extra_1.default.readJson(agentJsonPath);
418
432
  console.log(`🚀 Atualizando configuração do agente "${slug}"...`);
419
433
  try {
420
- let exists = true;
421
- try {
422
- await axios_1.default.get(`${config.goclaw.api_url}/v1/agents/${slug}`, {
423
- headers: { Authorization: `Bearer ${config.goclaw.token}`, "X-GoClaw-User-Id": config.goclaw.username || "system" }
424
- });
425
- }
426
- catch (e) {
427
- if (e.response && e.response.status === 404) {
428
- exists = false;
429
- }
430
- else {
431
- throw e;
432
- }
433
- }
434
+ const agentId = await resolveAgentId(slug, config);
435
+ const exists = agentId !== null;
434
436
  if (!exists) {
435
437
  await axios_1.default.post(`${config.goclaw.api_url}/v1/agents`, agentConfig, {
436
438
  headers: { Authorization: `Bearer ${config.goclaw.token}`, "X-GoClaw-User-Id": config.goclaw.username || "system" }
@@ -438,13 +440,13 @@ deployCmd
438
440
  console.log("✅ Agente criado com sucesso.");
439
441
  }
440
442
  else {
441
- await axios_1.default.put(`${config.goclaw.api_url}/v1/agents/${slug}`, agentConfig, {
443
+ await axios_1.default.put(`${config.goclaw.api_url}/v1/agents/${agentId}`, agentConfig, {
442
444
  headers: { Authorization: `Bearer ${config.goclaw.token}`, "X-GoClaw-User-Id": config.goclaw.username || "system" }
443
445
  });
444
446
  console.log("✅ Configurações do agente atualizadas.");
445
447
  }
446
448
  console.log(`🚀 Sincronizando arquivos de contexto...`);
447
- await deployContextFiles(slug, config);
449
+ await deployContextFiles(slug, config, agentId);
448
450
  console.log("✅ Deploy completo concluído!");
449
451
  }
450
452
  catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@innominatum/agentforge-cli",
3
- "version": "1.0.1",
3
+ "version": "1.0.6",
4
4
  "description": "A powerful command-line interface to scaffold, manage, build, and deploy AI Agents and Skills for the GoClaw platform.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -16,6 +16,9 @@
16
16
  "type": "git",
17
17
  "url": "git+https://github.com/Innominatum-pt/agentforge-cli.git"
18
18
  },
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
19
22
  "keywords": [
20
23
  "ai",
21
24
  "agents",
@@ -49,4 +52,4 @@
49
52
  "tsx": "^4.21.0",
50
53
  "typescript": "^6.0.3"
51
54
  }
52
- }
55
+ }
package/src/index.ts CHANGED
@@ -297,6 +297,19 @@ async function getConfig() {
297
297
  return config;
298
298
  }
299
299
 
300
+ async function resolveAgentId(slug: string, config: any): Promise<string | null> {
301
+ try {
302
+ const listResponse = await axios.get(`${config.goclaw.api_url}/v1/agents`, {
303
+ headers: { Authorization: `Bearer ${config.goclaw.token}`, "X-GoClaw-User-Id": config.goclaw.username || "system" }
304
+ });
305
+ const agents = listResponse.data.agents || [];
306
+ const agent = agents.find((a: any) => a.agent_key === slug);
307
+ return agent ? agent.id : null;
308
+ } catch (error) {
309
+ return null;
310
+ }
311
+ }
312
+
300
313
  const deployCmd = program
301
314
  .command("deploy")
302
315
  .description("Faz o deploy de entidades para a plataforma GoClaw");
@@ -354,7 +367,8 @@ deployCmd
354
367
  }
355
368
  });
356
369
 
357
- async function deployContextFiles(slug: string, config: any) {
370
+ async function deployContextFiles(slug: string, config: any, resolvedId?: string | null) {
371
+ const agentId = resolvedId || (await resolveAgentId(slug, config)) || slug;
358
372
  const basePath = getWorkspaceRoot();
359
373
  const agentPath = path.join(basePath, "agents", slug);
360
374
  if (!(await fs.pathExists(agentPath))) {
@@ -388,7 +402,7 @@ async function deployContextFiles(slug: string, config: any) {
388
402
  const form = new FormData();
389
403
  form.append("file", fs.createReadStream(tarPath));
390
404
 
391
- const url = `${config.goclaw.api_url}/v1/agents/${slug}/import?include=context_files`;
405
+ const url = `${config.goclaw.api_url}/v1/agents/${agentId}/import?include=context_files`;
392
406
  await axios.post(url, form, {
393
407
  headers: {
394
408
  ...form.getHeaders(),
@@ -446,18 +460,8 @@ deployCmd
446
460
  console.log(`🚀 Atualizando configuração do agente "${slug}"...`);
447
461
 
448
462
  try {
449
- let exists = true;
450
- try {
451
- await axios.get(`${config.goclaw.api_url}/v1/agents/${slug}`, {
452
- headers: { Authorization: `Bearer ${config.goclaw.token}`, "X-GoClaw-User-Id": config.goclaw.username || "system" }
453
- });
454
- } catch (e: any) {
455
- if (e.response && e.response.status === 404) {
456
- exists = false;
457
- } else {
458
- throw e;
459
- }
460
- }
463
+ const agentId = await resolveAgentId(slug, config);
464
+ const exists = agentId !== null;
461
465
 
462
466
  if (!exists) {
463
467
  await axios.post(`${config.goclaw.api_url}/v1/agents`, agentConfig, {
@@ -465,14 +469,14 @@ deployCmd
465
469
  });
466
470
  console.log("✅ Agente criado com sucesso.");
467
471
  } else {
468
- await axios.put(`${config.goclaw.api_url}/v1/agents/${slug}`, agentConfig, {
472
+ await axios.put(`${config.goclaw.api_url}/v1/agents/${agentId}`, agentConfig, {
469
473
  headers: { Authorization: `Bearer ${config.goclaw.token}`, "X-GoClaw-User-Id": config.goclaw.username || "system" }
470
474
  });
471
475
  console.log("✅ Configurações do agente atualizadas.");
472
476
  }
473
477
 
474
478
  console.log(`🚀 Sincronizando arquivos de contexto...`);
475
- await deployContextFiles(slug, config);
479
+ await deployContextFiles(slug, config, agentId);
476
480
 
477
481
  console.log("✅ Deploy completo concluído!");
478
482
  } catch (error: any) {