@11agents/cli 0.1.4 → 0.1.5

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/README.md CHANGED
@@ -27,6 +27,16 @@ export ELEVENAGENTS_SERVER="http://localhost:8082"
27
27
 
28
28
  On startup, the CLI prints its current version and target server to stderr. It also checks npm for a newer `@11agents/cli` package and prints an upgrade command when one is available.
29
29
 
30
+ Project-scoped MCP and knowledge-base sync tokens can be stored in `~/.11agents/credentials`:
31
+
32
+ ```yaml
33
+ # tokens:
34
+ flatkey: gtm_xxxxxxxxxxxxxxxxxxxx
35
+ voc-ai: gtm_yyyyyyyyyyyyyyyyyyyy
36
+ ```
37
+
38
+ When syncing a project knowledge base, the CLI chooses tokens in this order: explicit tool/command token, matching project token from `~/.11agents/credentials`, `GTM_SWARM_TOKEN`, then the daemon control token as a compatibility fallback.
39
+
30
40
  ## Runtime Pool
31
41
 
32
42
  Scan local AI runtimes:
@@ -95,7 +105,7 @@ Run the local MCP server over stdio:
95
105
  11agents mcp start
96
106
  ```
97
107
 
98
- Configure your MCP client to run that command and pass the project token when calling tools. The server exposes:
108
+ Configure your MCP client to run that command. The server automatically reads matching project tokens from `~/.11agents/credentials`; a tool-call token can still be passed explicitly when needed. The server exposes:
99
109
 
100
110
  - `knowledge_sync` — pull/push the project knowledge base between cloud and `~/.11agents/<project>/knowledge_base/`.
101
111
 
package/bin/11agents.js CHANGED
@@ -38,6 +38,7 @@ Environment:
38
38
  GTM_WRITES_TOKEN control-plane token for runtime registration
39
39
  ELEVENAGENTS_MACHINE stable machine key, defaults to hostname
40
40
  GTM_SWARM_TOKEN project swarm token for push/node commands
41
+ ~/.11agents/credentials project token map for MCP knowledge sync
41
42
 
42
43
  Runtime task workspace:
43
44
  Daemon project headquarters live under ~/.11agents/<project>/.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@11agents/cli",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "11agents local runtime and telemetry CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -9,6 +9,7 @@ import { pathToFileURL } from 'node:url'
9
9
  import { fileURLToPath } from 'node:url'
10
10
  import { flag } from '../args.js'
11
11
  import { getControlConfig, requestJson } from '../client.js'
12
+ import { resolveProjectToken } from '../credentials.js'
12
13
  import { syncKnowledge } from './knowledge.js'
13
14
  import { buildRuntimeScan } from '../runtime-scan.js'
14
15
  import { handleMcpRequest } from '../mcp.js'
@@ -206,6 +207,11 @@ function compactJson(value) {
206
207
  }
207
208
 
208
209
  async function mcpKnowledgeSync(flags = {}, deps = {}) {
210
+ const token = await resolveProjectToken(flags.project, {
211
+ homeDir: deps.homeDir,
212
+ token: flags.projectToken,
213
+ fallbackToken: flags.token,
214
+ })
209
215
  const result = await handleMcpRequest({
210
216
  method: 'tools/call',
211
217
  params: {
@@ -214,7 +220,7 @@ async function mcpKnowledgeSync(flags = {}, deps = {}) {
214
220
  project: flags.project,
215
221
  mode: flags.mode,
216
222
  server: flags.server,
217
- token: flags.token,
223
+ token,
218
224
  },
219
225
  },
220
226
  }, deps)
@@ -259,6 +265,13 @@ function projectDirForTask(task, flags = {}, deps) {
259
265
  return buildRuntimeProjectDir(projectSlugForTask(task, flags), { homeDir: deps.homeDir })
260
266
  }
261
267
 
268
+ async function projectSyncToken(project, flags = {}, deps = {}) {
269
+ return resolveProjectToken(project, {
270
+ homeDir: deps.homeDir,
271
+ fallbackToken: flags.token,
272
+ })
273
+ }
274
+
262
275
  async function writeFileIfMissing(filePath, content) {
263
276
  try {
264
277
  await writeFile(filePath, content, { flag: 'wx' })
@@ -663,14 +676,16 @@ async function claimAndRunRuntimeTasks(registration, flags, deps, handlerModule,
663
676
 
664
677
  deps.log(JSON.stringify({ claimed: runtimeTask.id, runtime_id: runtime.id }, null, 2))
665
678
  if (runtimeTask.workspace?.slug) {
679
+ const token = await projectSyncToken(runtimeTask.workspace.slug, flags, deps)
680
+ const syncConfig = { ...config, token }
666
681
  await runWithDaemonRetry('sync knowledge base', () => (
667
682
  deps.syncKnowledge({
668
683
  project: runtimeTask.workspace.slug,
669
684
  mode: 'pull',
670
685
  server: flags.server,
671
- token: flags.token,
686
+ token,
672
687
  }, {
673
- requestJson: (apiPath, options = {}) => deps.requestJson(apiPath, { ...options, config }),
688
+ requestJson: (apiPath, options = {}) => deps.requestJson(apiPath, { ...options, config: syncConfig }),
674
689
  log: () => {},
675
690
  })
676
691
  ), deps, retryState)
@@ -692,14 +707,16 @@ async function claimAndRunRuntimeTasks(registration, flags, deps, handlerModule,
692
707
 
693
708
  if (runtimeTask.workspace?.slug) {
694
709
  const syncBack = knowledgeDeepOrganizeSpec(runtimeTask) ? deps.mcpKnowledgeSync : deps.syncKnowledge
710
+ const token = await projectSyncToken(runtimeTask.workspace.slug, flags, deps)
711
+ const syncConfig = { ...config, token }
695
712
  await runWithDaemonRetry('sync knowledge base back to cloud', () => (
696
713
  syncBack({
697
714
  project: runtimeTask.workspace.slug,
698
715
  mode: 'push',
699
716
  server: flags.server,
700
- token: flags.token,
717
+ token,
701
718
  }, {
702
- requestJson: (apiPath, options = {}) => deps.requestJson(apiPath, { ...options, config }),
719
+ requestJson: (apiPath, options = {}) => deps.requestJson(apiPath, { ...options, config: syncConfig }),
703
720
  log: () => {},
704
721
  })
705
722
  ), deps, retryState)
@@ -0,0 +1,70 @@
1
+ import { readFile } from 'node:fs/promises'
2
+ import os from 'node:os'
3
+ import path from 'node:path'
4
+
5
+ function slugify(value) {
6
+ return String(value || 'project')
7
+ .trim()
8
+ .toLowerCase()
9
+ .replace(/[^a-z0-9]+/g, '-')
10
+ .replace(/^-|-$/g, '') || 'project'
11
+ }
12
+
13
+ function cleanHeader(value) {
14
+ return String(value || '').trim().replace(/^#\s*/, '').trim()
15
+ }
16
+
17
+ export function parseCredentials(content = '') {
18
+ const tokens = {}
19
+ let inTokens = false
20
+
21
+ for (const rawLine of String(content).split(/\r?\n/)) {
22
+ const line = rawLine.trim()
23
+ if (!line) continue
24
+
25
+ const header = cleanHeader(line)
26
+ if (/^tokens\s*:\s*$/.test(header)) {
27
+ inTokens = true
28
+ continue
29
+ }
30
+ if (line.startsWith('#')) continue
31
+
32
+ const match = line.match(/^([^:#]+):\s*(.+)$/)
33
+ if (!match) {
34
+ inTokens = false
35
+ continue
36
+ }
37
+ if (!inTokens && Object.keys(tokens).length === 0) inTokens = true
38
+ if (!inTokens) continue
39
+
40
+ const project = slugify(match[1])
41
+ const token = match[2].trim()
42
+ if (project && token) tokens[project] = token
43
+ }
44
+
45
+ return { tokens }
46
+ }
47
+
48
+ export async function readCredentials({ homeDir = os.homedir() } = {}) {
49
+ try {
50
+ return parseCredentials(await readFile(path.join(homeDir, '.11agents', 'credentials'), 'utf8'))
51
+ } catch (error) {
52
+ if (error?.code === 'ENOENT') return { tokens: {} }
53
+ throw error
54
+ }
55
+ }
56
+
57
+ export async function resolveProjectToken(project, {
58
+ homeDir = os.homedir(),
59
+ token = '',
60
+ fallbackToken = '',
61
+ env = process.env,
62
+ } = {}) {
63
+ if (token) return token
64
+
65
+ const credentials = await readCredentials({ homeDir })
66
+ const projectToken = credentials.tokens[slugify(project)]
67
+ if (projectToken) return projectToken
68
+
69
+ return env.GTM_SWARM_TOKEN || fallbackToken || ''
70
+ }
package/src/mcp.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { syncKnowledge } from './commands/knowledge.js'
2
2
  import { requestJson } from './client.js'
3
+ import { resolveProjectToken } from './credentials.js'
3
4
 
4
5
  const TOOLS = [
5
6
  {
@@ -45,16 +46,20 @@ export async function handleMcpRequest(request, deps = {}) {
45
46
  const name = request?.params?.name
46
47
  const args = toolArgs(request)
47
48
  if (name === 'knowledge_sync') {
49
+ const token = await resolveProjectToken(args.project, {
50
+ homeDir: deps.homeDir,
51
+ token: args.token,
52
+ })
48
53
  const result = await syncKnowledge({
49
54
  project: args.project,
50
55
  mode: args.mode,
51
56
  server: args.server,
52
- token: args.token,
57
+ token,
53
58
  }, {
54
59
  ...deps,
55
60
  requestJson: (apiPath, options = {}) => (deps.requestJson || requestJson)(apiPath, {
56
61
  ...options,
57
- config: { token: args.token || '', server: args.server || 'https://app.11agents.ai' },
62
+ config: { token, server: args.server || 'https://app.11agents.ai' },
58
63
  }),
59
64
  })
60
65
  return textResult(result)