onlymcp 0.9.1 → 0.10.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 (48) hide show
  1. package/dist/apiClient.d.ts +99 -7
  2. package/dist/apiClient.js +58 -2
  3. package/dist/apiClient.js.map +1 -1
  4. package/dist/auth/deviceLogin.js +5 -1
  5. package/dist/auth/deviceLogin.js.map +1 -1
  6. package/dist/bin/cli.js +204 -24
  7. package/dist/bin/cli.js.map +1 -1
  8. package/dist/bin/mcp.js +16 -2
  9. package/dist/bin/mcp.js.map +1 -1
  10. package/dist/export/unpack.d.ts +33 -0
  11. package/dist/export/unpack.js +54 -0
  12. package/dist/export/unpack.js.map +1 -0
  13. package/dist/identity.d.ts +25 -0
  14. package/dist/identity.js +106 -0
  15. package/dist/identity.js.map +1 -0
  16. package/dist/import/collect.d.ts +14 -1
  17. package/dist/import/collect.js +25 -3
  18. package/dist/import/collect.js.map +1 -1
  19. package/dist/import/frontmatter.d.ts +31 -5
  20. package/dist/import/frontmatter.js +64 -22
  21. package/dist/import/frontmatter.js.map +1 -1
  22. package/dist/import/plan.d.ts +22 -1
  23. package/dist/import/plan.js +66 -19
  24. package/dist/import/plan.js.map +1 -1
  25. package/dist/import/prune.d.ts +46 -0
  26. package/dist/import/prune.js +61 -0
  27. package/dist/import/prune.js.map +1 -0
  28. package/dist/import/upload.js +10 -1
  29. package/dist/import/upload.js.map +1 -1
  30. package/dist/install.d.ts +7 -0
  31. package/dist/install.js +6 -2
  32. package/dist/install.js.map +1 -1
  33. package/dist/instructions.d.ts +3 -1
  34. package/dist/instructions.js +19 -2
  35. package/dist/instructions.js.map +1 -1
  36. package/dist/memorySync.d.ts +28 -0
  37. package/dist/memorySync.js +56 -0
  38. package/dist/memorySync.js.map +1 -0
  39. package/dist/paths.d.ts +12 -0
  40. package/dist/paths.js +34 -8
  41. package/dist/paths.js.map +1 -1
  42. package/dist/stubs.d.ts +1 -0
  43. package/dist/stubs.js +83 -11
  44. package/dist/stubs.js.map +1 -1
  45. package/dist/tools/memoryGraph.d.ts +69 -0
  46. package/dist/tools/memoryGraph.js +123 -0
  47. package/dist/tools/memoryGraph.js.map +1 -0
  48. package/package.json +3 -2
@@ -4,11 +4,40 @@ export declare class ApiError extends Error {
4
4
  readonly status: number;
5
5
  constructor(code: string, params?: Record<string, unknown>, status?: number);
6
6
  }
7
- export type SkillListItem = {
7
+ /**
8
+ * Herkunft und Bearbeitbarkeit, wie jede Liste des Servers sie mitschickt
9
+ * (teams/scope.ts). Der Client braucht sie fuer `--prune`: geloescht wird nur,
10
+ * was diesem Konto allein gehoert.
11
+ */
12
+ export type Scoped = {
13
+ scope: 'personal' | 'team';
14
+ teamName: string | null;
15
+ isOwn: boolean;
16
+ canEdit: boolean;
17
+ archivedAt: string | null;
18
+ };
19
+ /** Die Sammlung, aus der ein Skill stammt (Paket 03 Aufgabe 11). */
20
+ export type SkillCollection = {
21
+ key: string;
22
+ kind: string;
23
+ label: string;
24
+ };
25
+ export type SkillProvenance = {
26
+ description?: string;
27
+ sourcePath?: string;
28
+ collection?: {
29
+ key: string;
30
+ kind: string;
31
+ label?: string;
32
+ } | null;
33
+ };
34
+ export type SkillListItem = Scoped & {
8
35
  name: string;
36
+ description: string;
37
+ collection: SkillCollection | null;
9
38
  updatedAt: string;
10
39
  };
11
- export type AgentListItem = {
40
+ export type AgentListItem = Scoped & {
12
41
  name: string;
13
42
  description: string;
14
43
  model: string | null;
@@ -29,17 +58,36 @@ export type MemoryFile = {
29
58
  path: string;
30
59
  content: string;
31
60
  frontmatter: Record<string, unknown>;
32
- links: string[];
61
+ links: {
62
+ resolved: string[];
63
+ unresolved: string[];
64
+ };
33
65
  updatedAt: string;
34
66
  updatedByDevice: string | null;
35
67
  };
36
- export type MemoryListItem = {
68
+ export type SearchHit = {
69
+ kind: 'memory' | 'skill' | 'agent';
70
+ id: string;
71
+ name: string;
72
+ path: string | null;
73
+ snippet: string;
74
+ scope: 'personal' | 'team';
75
+ teamId: string | null;
76
+ };
77
+ export type TreeEntry = {
78
+ kind: 'folder' | 'file';
37
79
  path: string;
38
- updatedAt: string;
80
+ name: string;
81
+ type: string | null;
82
+ updatedAt: string | null;
39
83
  scope: 'personal' | 'team';
40
84
  teamName: string | null;
41
85
  canEdit: boolean;
42
86
  };
87
+ export type MemoryListItem = Scoped & {
88
+ path: string;
89
+ updatedAt: string;
90
+ };
43
91
  export type Connection = {
44
92
  id: string;
45
93
  name: string;
@@ -97,6 +145,8 @@ export declare class ApiClient {
97
145
  plan: {
98
146
  name: string;
99
147
  };
148
+ /** Optional, weil eine aeltere API sie nicht schickt. Fehlt sie, gilt an. */
149
+ brainvaultMode?: boolean;
100
150
  }>;
101
151
  listSkills(): Promise<{
102
152
  skills: SkillListItem[];
@@ -104,10 +154,19 @@ export declare class ApiClient {
104
154
  getSkill(name: string): Promise<{
105
155
  name: string;
106
156
  body: string;
157
+ description: string;
158
+ collection: SkillCollection | null;
159
+ sourcePath: string | null;
107
160
  updatedAt: string;
108
161
  files: SkillFileMeta[];
109
162
  }>;
110
- putSkill(name: string, body: string): Promise<{
163
+ /**
164
+ * Die Herkunft ist optional und wird WEGGELASSEN, nicht auf leer gesetzt,
165
+ * wenn es keine gibt: ein fehlendes Feld heisst serverseitig "nicht
166
+ * anfassen" (Spec 5, Regel 1). Ein `description: ''` mitzuschicken loeschte
167
+ * die Beschreibung, die ein frueherer Import geschrieben hat.
168
+ */
169
+ putSkill(name: string, body: string, provenance?: SkillProvenance): Promise<{
111
170
  name: string;
112
171
  updatedAt: string;
113
172
  }>;
@@ -130,7 +189,13 @@ export declare class ApiClient {
130
189
  name: string;
131
190
  updatedAt: string;
132
191
  }>;
133
- getAgent(name: string): Promise<AgentListItem & {
192
+ getAgent(name: string): Promise<Scoped & {
193
+ name: string;
194
+ description: string;
195
+ model: string | null;
196
+ tools: string[];
197
+ updatedAt: string;
198
+ } & {
134
199
  body: string;
135
200
  }>;
136
201
  readMemory(path: string): Promise<MemoryFile>;
@@ -139,6 +204,33 @@ export declare class ApiClient {
139
204
  listMemory(): Promise<{
140
205
  files: MemoryListItem[];
141
206
  }>;
207
+ searchContent(q: string, opts?: {
208
+ types?: string[];
209
+ limit?: number;
210
+ }): Promise<{
211
+ hits: SearchHit[];
212
+ }>;
213
+ memoryTree(scope?: string): Promise<{
214
+ nodes: TreeEntry[];
215
+ }>;
216
+ moveMemory(from: string, to: string, updateLinks?: boolean): Promise<{
217
+ from: string;
218
+ to: string;
219
+ rewritten: number;
220
+ skipped: number;
221
+ }>;
222
+ /**
223
+ * Das Export-Archiv, als ROHE Antwort.
224
+ *
225
+ * Geht bewusst nicht durch `call`: das dort ist ein JSON-Client, und ein
226
+ * Archiv von zwei Gigabyte durch `res.json()` zu schicken waere genau der
227
+ * Fehler, den die Route auf ihrer Seite vermeidet. Der Aufrufer bekommt den
228
+ * Strom und entscheidet, ob er ihn in eine Datei giesst oder auspackt.
229
+ */
230
+ exportArchive(opts?: {
231
+ scope?: string;
232
+ types?: string[];
233
+ }): Promise<Response>;
142
234
  deleteMemory(path: string): Promise<void>;
143
235
  deleteSkill(name: string): Promise<void>;
144
236
  deleteSkillFile(name: string, path: string): Promise<void>;
package/dist/apiClient.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { identityHeaders } from './identity.js';
1
2
  export class ApiError extends Error {
2
3
  code;
3
4
  params;
@@ -21,9 +22,12 @@ export class ApiClient {
21
22
  const tok = this.token();
22
23
  if (!tok)
23
24
  throw new ApiError('errors.NOT_LOGGED_IN');
25
+ // Wer anruft, steht in den Koepfen - sonst schickt Node 'node' und das
26
+ // Geraet heisst in der Liste genau so. Siehe identity.ts.
24
27
  const res = await fetch(`${this.baseUrl}${path}`, {
25
28
  ...init,
26
29
  headers: {
30
+ ...(await identityHeaders()),
27
31
  ...(init.headers ?? {}),
28
32
  authorization: `Bearer ${tok}`,
29
33
  'content-type': 'application/json',
@@ -46,8 +50,14 @@ export class ApiClient {
46
50
  getSkill(name) {
47
51
  return this.call(`/api/skills/${encodeURIComponent(name)}`);
48
52
  }
49
- putSkill(name, body) {
50
- return this.call(`/api/skills/${encodeURIComponent(name)}`, { method: 'PUT', body: JSON.stringify({ body }) });
53
+ /**
54
+ * Die Herkunft ist optional und wird WEGGELASSEN, nicht auf leer gesetzt,
55
+ * wenn es keine gibt: ein fehlendes Feld heisst serverseitig "nicht
56
+ * anfassen" (Spec 5, Regel 1). Ein `description: ''` mitzuschicken loeschte
57
+ * die Beschreibung, die ein frueherer Import geschrieben hat.
58
+ */
59
+ putSkill(name, body, provenance = {}) {
60
+ return this.call(`/api/skills/${encodeURIComponent(name)}`, { method: 'PUT', body: JSON.stringify({ body, ...provenance }) });
51
61
  }
52
62
  // Der Pfad wird Segment fuer Segment kodiert, genau wie bei readMemory:
53
63
  // encodeURIComponent ueber die ganze Zeichenkette machte aus jedem
@@ -89,6 +99,52 @@ export class ApiClient {
89
99
  listMemory() {
90
100
  return this.call('/api/memory');
91
101
  }
102
+ // --- Suchen, Baum und Verschieben (Paket 03 Aufgabe 14) -----------------
103
+ searchContent(q, opts = {}) {
104
+ const query = new URLSearchParams({ q });
105
+ if (opts.types?.length)
106
+ query.set('types', opts.types.join(','));
107
+ if (opts.limit)
108
+ query.set('limit', String(opts.limit));
109
+ return this.call(`/api/search?${query.toString()}`);
110
+ }
111
+ memoryTree(scope = 'all') {
112
+ return this.call(`/api/memory/tree?scope=${encodeURIComponent(scope)}`);
113
+ }
114
+ moveMemory(from, to, updateLinks = true) {
115
+ return this.call('/api/memory/move', {
116
+ method: 'POST',
117
+ body: JSON.stringify({ from, to, updateLinks }),
118
+ });
119
+ }
120
+ // --- Der Weg nach draussen ---------------------------------------------
121
+ /**
122
+ * Das Export-Archiv, als ROHE Antwort.
123
+ *
124
+ * Geht bewusst nicht durch `call`: das dort ist ein JSON-Client, und ein
125
+ * Archiv von zwei Gigabyte durch `res.json()` zu schicken waere genau der
126
+ * Fehler, den die Route auf ihrer Seite vermeidet. Der Aufrufer bekommt den
127
+ * Strom und entscheidet, ob er ihn in eine Datei giesst oder auspackt.
128
+ */
129
+ async exportArchive(opts = {}) {
130
+ const tok = this.token();
131
+ if (!tok)
132
+ throw new ApiError('errors.NOT_LOGGED_IN');
133
+ const query = new URLSearchParams();
134
+ if (opts.scope)
135
+ query.set('scope', opts.scope);
136
+ if (opts.types?.length)
137
+ query.set('types', opts.types.join(','));
138
+ const tail = query.size > 0 ? `?${query.toString()}` : '';
139
+ const res = await fetch(`${this.baseUrl}/api/export${tail}`, {
140
+ headers: { ...(await identityHeaders()), authorization: `Bearer ${tok}` },
141
+ });
142
+ if (!res.ok) {
143
+ const body = (await res.json().catch(() => ({})));
144
+ throw new ApiError(body.code ?? 'errors.UNKNOWN', body.params ?? {}, res.status);
145
+ }
146
+ return res;
147
+ }
92
148
  deleteMemory(path) {
93
149
  return this.call(this.memoryUrl(path), { method: 'DELETE' });
94
150
  }
@@ -1 +1 @@
1
- {"version":3,"file":"apiClient.js","sourceRoot":"","sources":["../src/apiClient.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,QAAS,SAAQ,KAAK;IAEtB;IACA;IACA;IAHX,YACW,IAAY,EACZ,SAAkC,EAAE,EACpC,SAAS,CAAC;QAEnB,KAAK,CAAC,IAAI,CAAC,CAAC;QAJH,SAAI,GAAJ,IAAI,CAAQ;QACZ,WAAM,GAAN,MAAM,CAA8B;QACpC,WAAM,GAAN,MAAM,CAAI;QAGnB,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF;AAwED,MAAM,OAAO,SAAS;IAED;IACA;IAFnB,YACmB,OAAe,EACf,KAA0B;QAD1B,YAAO,GAAP,OAAO,CAAQ;QACf,UAAK,GAAL,KAAK,CAAqB;IAC1C,CAAC;IAEI,KAAK,CAAC,IAAI,CAAI,IAAY,EAAE,OAAoB,EAAE;QACxD,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,GAAG;YAAE,MAAM,IAAI,QAAQ,CAAC,sBAAsB,CAAC,CAAC;QACrD,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,EAAE;YAChD,GAAG,IAAI;YACP,OAAO,EAAE;gBACP,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;gBACvB,aAAa,EAAE,UAAU,GAAG,EAAE;gBAC9B,cAAc,EAAE,kBAAkB;aACnC;SACF,CAAC,CAAC;QACH,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,SAAc,CAAC;QAC9C,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAChD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,gBAAgB,EAAE,IAAI,CAAC,MAAM,IAAI,EAAE,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;QACnF,CAAC;QACD,OAAO,IAAS,CAAC;IACnB,CAAC;IAED,KAAK;QACH,OAAO,IAAI,CAAC,IAAI,CAAwD,SAAS,CAAC,CAAC;IACrF,CAAC;IACD,UAAU;QACR,OAAO,IAAI,CAAC,IAAI,CAA8B,aAAa,CAAC,CAAC;IAC/D,CAAC;IACD,QAAQ,CAAC,IAAY;QACnB,OAAO,IAAI,CAAC,IAAI,CACd,eAAe,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAC1C,CAAC;IACJ,CAAC;IACD,QAAQ,CAAC,IAAY,EAAE,IAAY;QACjC,OAAO,IAAI,CAAC,IAAI,CACd,eAAe,kBAAkB,CAAC,IAAI,CAAC,EAAE,EACzC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,CAClD,CAAC;IACJ,CAAC;IAED,wEAAwE;IACxE,mEAAmE;IACnE,4EAA4E;IAC5E,8BAA8B;IACtB,YAAY,CAAC,IAAY,EAAE,IAAY;QAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC/D,OAAO,eAAe,kBAAkB,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC;IACjE,CAAC;IACD,YAAY,CAAC,IAAY,EAAE,IAAY;QACrC,OAAO,IAAI,CAAC,IAAI,CAAY,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC;IAC7D,CAAC;IACD,YAAY,CAAC,IAAY,EAAE,IAAY,EAAE,OAAe,EAAE,WAAyB,MAAM;QACvF,OAAO,IAAI,CAAC,IAAI,CACd,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,EAC7B,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAC/D,CAAC;IACJ,CAAC;IACD,UAAU;QACR,OAAO,IAAI,CAAC,IAAI,CAA8B,aAAa,CAAC,CAAC;IAC/D,CAAC;IACD,QAAQ,CAAC,IAAY,EAAE,CAAyE;QAC9F,OAAO,IAAI,CAAC,IAAI,CACd,eAAe,kBAAkB,CAAC,IAAI,CAAC,EAAE,EACzC,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAC3C,CAAC;IACJ,CAAC;IACD,QAAQ,CAAC,IAAY;QACnB,OAAO,IAAI,CAAC,IAAI,CACd,eAAe,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAC1C,CAAC;IACJ,CAAC;IACD,UAAU,CAAC,IAAY;QACrB,OAAO,IAAI,CAAC,IAAI,CAAa,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;IACrD,CAAC;IACD,WAAW,CAAC,IAAY,EAAE,OAAe,EAAE,WAAoB;QAC7D,OAAO,IAAI,CAAC,IAAI,CACd,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EACpB,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,EAAE,CAClE,CAAC;IACJ,CAAC;IAED,2EAA2E;IAC3E,EAAE;IACF,4EAA4E;IAC5E,2EAA2E;IAC3E,2DAA2D;IAEnD,SAAS,CAAC,IAAY;QAC5B,OAAO,eAAe,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IAC5E,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC,IAAI,CAA8B,aAAa,CAAC,CAAC;IAC/D,CAAC;IACD,YAAY,CAAC,IAAY;QACvB,OAAO,IAAI,CAAC,IAAI,CAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IACrE,CAAC;IACD,WAAW,CAAC,IAAY;QACtB,OAAO,IAAI,CAAC,IAAI,CAAO,eAAe,kBAAkB,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC1F,CAAC;IACD,eAAe,CAAC,IAAY,EAAE,IAAY;QACxC,OAAO,IAAI,CAAC,IAAI,CAAO,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC9E,CAAC;IACD,WAAW,CAAC,IAAY;QACtB,OAAO,IAAI,CAAC,IAAI,CAAO,eAAe,kBAAkB,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC1F,CAAC;IAED,0EAA0E;IAE1E,eAAe;QACb,OAAO,IAAI,CAAC,IAAI,CAAgC,sBAAsB,CAAC,CAAC;IAC1E,CAAC;IACD,gBAAgB,CAAC,KAAsB;QACrC,OAAO,IAAI,CAAC,IAAI,CAA6B,sBAAsB,EAAE;YACnE,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;SAC5B,CAAC,CAAC;IACL,CAAC;IACD,gBAAgB,CAAC,EAAU,EAAE,KAAuD;QAClF,OAAO,IAAI,CAAC,IAAI,CAA6B,wBAAwB,EAAE,EAAE,EAAE;YACzE,MAAM,EAAE,OAAO;YACf,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;SAC5B,CAAC,CAAC;IACL,CAAC;IACD,gBAAgB,CAAC,EAAU;QACzB,OAAO,IAAI,CAAC,IAAI,CAAkB,wBAAwB,EAAE,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;IACxF,CAAC;IACD,gBAAgB,CAAC,EAAU;QACzB,OAAO,IAAI,CAAC,IAAI,CAAiC,wBAAwB,EAAE,eAAe,CAAC,CAAC;IAC9F,CAAC;IACD,gBAAgB,CAAC,EAAU,EAAE,KAAa,EAAE,OAAgB;QAC1D,OAAO,IAAI,CAAC,IAAI,CACd,wBAAwB,EAAE,iBAAiB,KAAK,EAAE,EAClD,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CACvD,CAAC;IACJ,CAAC;CACF"}
1
+ {"version":3,"file":"apiClient.js","sourceRoot":"","sources":["../src/apiClient.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { ApiError } from '../apiClient.js';
2
+ import { identityHeaders } from '../identity.js';
2
3
  const defaultDeps = {
3
4
  sleep: (ms) => new Promise((r) => setTimeout(r, ms)),
4
5
  };
@@ -6,9 +7,12 @@ export async function pollForToken(baseUrl, deviceCode, intervalSeconds, deps =
6
7
  let interval = intervalSeconds;
7
8
  for (;;) {
8
9
  await deps.sleep(interval * 1000);
10
+ // Diese Anfrage ist die, die die Sitzung erzeugt - hier entscheidet sich,
11
+ // wie das Geraet in der Liste heissen wird. Ohne die Koepfe schickt Node
12
+ // 'node', und genau das stand vorher dort.
9
13
  const res = await fetch(`${baseUrl}/api/auth/device/token`, {
10
14
  method: 'POST',
11
- headers: { 'content-type': 'application/json' },
15
+ headers: { ...(await identityHeaders()), 'content-type': 'application/json' },
12
16
  body: JSON.stringify({
13
17
  grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
14
18
  device_code: deviceCode,
@@ -1 +1 @@
1
- {"version":3,"file":"deviceLogin.js","sourceRoot":"","sources":["../../src/auth/deviceLogin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAI3C,MAAM,WAAW,GAAS;IACxB,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;CACrD,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAAe,EACf,UAAkB,EAClB,eAAuB,EACvB,OAAa,WAAW;IAExB,IAAI,QAAQ,GAAG,eAAe,CAAC;IAC/B,SAAS,CAAC;QACR,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;QAClC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,wBAAwB,EAAE;YAC1D,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,UAAU,EAAE,8CAA8C;gBAC1D,WAAW,EAAE,UAAU;gBACvB,SAAS,EAAE,aAAa;aACzB,CAAC;SACH,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAChD,IAAI,IAAI,CAAC,YAAY;YAAE,OAAO,IAAI,CAAC,YAAsB,CAAC;QAC1D,QAAQ,IAAI,CAAC,KAAK,EAAE,CAAC;YACnB,KAAK,uBAAuB;gBAC1B,MAAM;YACR,KAAK,WAAW;gBACd,QAAQ,IAAI,CAAC,CAAC;gBACd,MAAM;YACR,KAAK,eAAe;gBAClB,MAAM,IAAI,QAAQ,CAAC,6BAA6B,CAAC,CAAC;YACpD,KAAK,eAAe;gBAClB,MAAM,IAAI,QAAQ,CAAC,4BAA4B,CAAC,CAAC;YACnD;gBACE,MAAM,IAAI,QAAQ,CAAC,4BAA4B,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"deviceLogin.js","sourceRoot":"","sources":["../../src/auth/deviceLogin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAIjD,MAAM,WAAW,GAAS;IACxB,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;CACrD,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,OAAe,EACf,UAAkB,EAClB,eAAuB,EACvB,OAAa,WAAW;IAExB,IAAI,QAAQ,GAAG,eAAe,CAAC;IAC/B,SAAS,CAAC;QACR,MAAM,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;QAClC,0EAA0E;QAC1E,yEAAyE;QACzE,2CAA2C;QAC3C,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,wBAAwB,EAAE;YAC1D,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,GAAG,CAAC,MAAM,eAAe,EAAE,CAAC,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC7E,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,UAAU,EAAE,8CAA8C;gBAC1D,WAAW,EAAE,UAAU;gBACvB,SAAS,EAAE,aAAa;aACzB,CAAC;SACH,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAChD,IAAI,IAAI,CAAC,YAAY;YAAE,OAAO,IAAI,CAAC,YAAsB,CAAC;QAC1D,QAAQ,IAAI,CAAC,KAAK,EAAE,CAAC;YACnB,KAAK,uBAAuB;gBAC1B,MAAM;YACR,KAAK,WAAW;gBACd,QAAQ,IAAI,CAAC,CAAC;gBACd,MAAM;YACR,KAAK,eAAe;gBAClB,MAAM,IAAI,QAAQ,CAAC,6BAA6B,CAAC,CAAC;YACpD,KAAK,eAAe;gBAClB,MAAM,IAAI,QAAQ,CAAC,4BAA4B,CAAC,CAAC;YACnD;gBACE,MAAM,IAAI,QAAQ,CAAC,4BAA4B,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;QAC5E,CAAC;IACH,CAAC;AACH,CAAC"}
package/dist/bin/cli.js CHANGED
@@ -5,7 +5,9 @@ import open from 'open';
5
5
  import QRCode from 'qrcode';
6
6
  import { createRequire } from 'node:module';
7
7
  import { homedir } from 'node:os';
8
- import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
8
+ import { appendFileSync, createWriteStream, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
9
+ import { pipeline } from 'node:stream/promises';
10
+ import { Readable } from 'node:stream';
9
11
  import { dirname, join } from 'node:path';
10
12
  import { ApiClient } from '../apiClient.js';
11
13
  import { Keyring } from '../auth/keyring.js';
@@ -17,6 +19,10 @@ import { writeStubs } from '../stubs.js';
17
19
  import { collect } from '../import/collect.js';
18
20
  import { buildImportPlan } from '../import/plan.js';
19
21
  import { countPlan, runUpload } from '../import/upload.js';
22
+ import { countTargets, isEmpty, planPrune, runPrune } from '../import/prune.js';
23
+ import { syncMemoryToDisk } from '../memorySync.js';
24
+ import { unpackArchive } from '../export/unpack.js';
25
+ import { deviceLabel } from '../identity.js';
20
26
  const baseUrl = process.env.ONLYMCP_API_URL ?? 'https://only-mcp.com';
21
27
  // Die Version kommt aus der package.json und steht nicht ein zweites Mal hier
22
28
  // als Literal: sonst meldet `onlymcp --version` nach der ersten
@@ -65,6 +71,11 @@ program
65
71
  .description('Dieses Geraet mit OnlyMCP verbinden')
66
72
  .action(async () => {
67
73
  intro('OnlyMCP');
74
+ // Einmal ehrlich sagen, was mitgeht, BEVOR es mitgeht. Die beiden Werte
75
+ // stehen nachher in der Geraeteliste dieses Kontos, sonst nirgends - aber
76
+ // wer sie nicht schicken will, soll das erfahren, solange er noch abbrechen
77
+ // kann.
78
+ log.info(`Dieses Geraet meldet sich als: ${await deviceLabel()}`);
68
79
  const res = await fetch(`${baseUrl}/api/auth/device/code`, {
69
80
  method: 'POST',
70
81
  headers: { 'content-type': 'application/json' },
@@ -86,11 +97,28 @@ program
86
97
  Keyring.save(token);
87
98
  s.stop('Verbunden');
88
99
  const api = new ApiClient(baseUrl, () => Keyring.read());
89
- let counts = { skills: 0, agents: 0, files: 0 };
90
- for (const dir of stubDirs())
91
- counts = await writeStubs(api, dir);
100
+ const counts = await writeStubsEverywhere(api);
92
101
  outro(`${counts.skills} Skills, ${counts.agents} Agents, ${counts.files} Dateien bereit`);
93
102
  });
103
+ /**
104
+ * Stubs in jeden Ordner, den ein Client auf diesem Geraet liest.
105
+ *
106
+ * Gezaehlt wird ueber alle Ordner zusammen, nicht der letzte: bis Aufgabe 12
107
+ * ueberschrieb die Schleife ihr Ergebnis bei jedem Durchlauf und meldete
108
+ * deshalb die Zahlen des zuletzt beschriebenen Ordners als Gesamtzahl.
109
+ */
110
+ async function writeStubsEverywhere(api) {
111
+ const total = { skills: 0, agents: 0, files: 0, kept: [] };
112
+ for (const dir of stubDirs()) {
113
+ const c = await writeStubs(api, dir);
114
+ total.skills += c.skills;
115
+ total.agents += c.agents;
116
+ total.files += c.files;
117
+ for (const k of c.kept)
118
+ total.kept.push(`${dir}/${k}`);
119
+ }
120
+ return total;
121
+ }
94
122
  program
95
123
  .command('logout')
96
124
  .description('Anmeldung und Cache auf diesem Geraet loeschen')
@@ -108,12 +136,37 @@ program
108
136
  program
109
137
  .command('sync')
110
138
  .description('Stub-Dateien neu schreiben')
111
- .action(async () => {
139
+ .option('--memory <dir>', 'Memory zusaetzlich als Dateien in diesen Ordner schreiben')
140
+ .action(async (opts) => {
112
141
  const api = new ApiClient(baseUrl, () => Keyring.read());
113
- let counts = { skills: 0, agents: 0, files: 0 };
114
- for (const dir of stubDirs())
115
- counts = await writeStubs(api, dir);
142
+ const counts = await writeStubsEverywhere(api);
116
143
  log.success(`${counts.skills} Skills, ${counts.agents} Agents, ${counts.files} Dateien`);
144
+ if (counts.kept.length > 0) {
145
+ // Stubs liegen in denselben Ordnern, aus denen importiert wird. Was
146
+ // dort schon stand und kein Stub war, bleibt stehen - aber nicht
147
+ // stillschweigend, sonst sucht jemand einen Stub, der nie geschrieben
148
+ // wurde. Gekuerzt, weil ein Geraet mit 270 eigenen Agent-Dateien sonst
149
+ // 270 Zeilen bekaeme und die Erfolgsmeldung aus dem Bild schoebe.
150
+ log.warn([
151
+ `Unberuehrt gelassen, weil dort schon etwas Eigenes liegt (${counts.kept.length})`,
152
+ ...counts.kept.slice(0, 10).map((k) => ` ${k}`),
153
+ ...(counts.kept.length > 10 ? [` ... und ${counts.kept.length - 10} weitere`] : []),
154
+ ].join('\n'));
155
+ }
156
+ if (!opts.memory)
157
+ return;
158
+ const m = await syncMemoryToDisk(api, opts.memory);
159
+ log.success(`${m.written} Memory-Dateien nach ${opts.memory}`);
160
+ if (m.collisions.length > 0) {
161
+ log.warn(['Team-Dateien mit einem Pfad, den eine eigene Datei schon hat', ...m.collisions.map((p) => ` ${p}`)].join('\n'));
162
+ }
163
+ if (m.refused.length > 0) {
164
+ log.warn(['Pfade abgelehnt', ...m.refused.map((p) => ` ${p}`)].join('\n'));
165
+ }
166
+ if (m.failures.length > 0) {
167
+ log.error([`${m.failures.length} fehlgeschlagen`, ...m.failures.map((f) => ` ${f.what} ${f.code}`)].join('\n'));
168
+ process.exitCode = 1;
169
+ }
117
170
  });
118
171
  program
119
172
  .command('install')
@@ -207,6 +260,12 @@ function printPlan(plan, roots) {
207
260
  byReason.set(s.reason, (byReason.get(s.reason) ?? 0) + 1);
208
261
  log.message(['Uebersprungen', ...[...byReason].map(([reason, n]) => ` ${String(n).padStart(4)} ${reason}`)].join('\n'));
209
262
  }
263
+ if (plan.noDescription.length > 0) {
264
+ // Gehen trotzdem hoch. Gemeldet, weil die Liste im Dashboard und die
265
+ // Stubs auf jedem Geraet von der Beschreibung leben und ein Skill ohne
266
+ // sie dort als blosser Name steht.
267
+ log.warn(['Ohne description im Kopf der SKILL.md', ...plan.noDescription.map((n) => ` ${n}`)].join('\n'));
268
+ }
210
269
  if (plan.flagged.length > 0) {
211
270
  log.warn([
212
271
  'Zurueckgehalten wegen moeglicher Zugangsdaten (nichts davon geht raus)',
@@ -220,7 +279,7 @@ function printPlan(plan, roots) {
220
279
  program
221
280
  .command('import')
222
281
  .description('Bestehende lokale Skills, Agents und Memory nach OnlyMCP holen')
223
- .option('--skills <dir>', 'Ordner mit Skill-Unterordnern')
282
+ .option('--skills <dir>', 'Ordner mit Skill-Unterordnern oder ein Plugin-Cache')
224
283
  .option('--agents <dir>', 'Ordner mit Agent-Dateien')
225
284
  // --memory hat mit Absicht keine Vorgabe. Skills und Agents liegen an einem
226
285
  // bekannten Pfad, an dem nur Skills und Agents liegen. Ein Memory-Ordner
@@ -229,6 +288,10 @@ program
229
288
  .option('--memory <dir>', 'Ordner mit Memory-Dateien (keine Vorgabe)')
230
289
  .option('--dry-run', 'Nur zeigen, was hochginge, und beenden')
231
290
  .option('--yes', 'Ohne Rueckfrage hochladen')
291
+ // --prune loescht im Konto. Es hat deshalb bewusst KEINE Abkuerzung ueber
292
+ // --yes: die Liste wird immer gezeigt und immer einzeln bestaetigt, auch
293
+ // wenn der Upload selbst unbeaufsichtigt laeuft.
294
+ .option('--prune', 'Was im Konto steht und in der Quelle fehlt, nach Rueckfrage loeschen')
232
295
  .action(async (opts) => {
233
296
  // Dieselbe Testschleuse wie in install.ts und paths.ts.
234
297
  const home = process.env.ONLYMCP_HOME ?? homedir();
@@ -247,7 +310,7 @@ program
247
310
  existsSync(roots.agents) ? collect(roots.agents) : Promise.resolve([]),
248
311
  roots.memory && existsSync(roots.memory) ? collect(roots.memory) : Promise.resolve([]),
249
312
  ]);
250
- plan = buildImportPlan({ skills, agents, memory });
313
+ plan = buildImportPlan({ skills, agents, memory }, { skillsRoot: roots.skills });
251
314
  }
252
315
  catch (e) {
253
316
  s.stop('Abgebrochen');
@@ -262,11 +325,13 @@ program
262
325
  memory: roots.memory && existsSync(roots.memory) ? roots.memory : undefined,
263
326
  });
264
327
  const total = countPlan(plan);
265
- if (total === 0) {
328
+ // Mit --prune gibt es auch dann etwas zu tun, wenn nichts hochgeht: genau
329
+ // ein leerer Quellordner ist der Fall, in dem am meisten geloescht wuerde.
330
+ if (total === 0 && !opts.prune) {
266
331
  outro('Nichts zu tun.');
267
332
  return;
268
333
  }
269
- if (opts.dryRun) {
334
+ if (opts.dryRun && !opts.prune) {
270
335
  outro('Nichts hochgeladen (--dry-run).');
271
336
  return;
272
337
  }
@@ -283,7 +348,7 @@ program
283
348
  process.exitCode = 1;
284
349
  return;
285
350
  }
286
- if (!opts.yes) {
351
+ if (total > 0 && !opts.yes && !opts.dryRun) {
287
352
  if (!process.stdin.isTTY) {
288
353
  // Ohne Terminal gibt es keine Rueckfrage, also auch keinen Upload.
289
354
  // Wer das automatisieren will, sagt --yes und hat den Plan vorher mit
@@ -323,23 +388,138 @@ program
323
388
  skills: clear(skills),
324
389
  agents: clear(agents),
325
390
  memory: clear(memory),
391
+ }, { skillsRoot: roots.skills });
392
+ }
393
+ }
394
+ }
395
+ if (total > 0 && !opts.dryRun) {
396
+ const up = spinner();
397
+ up.start('Lade hoch');
398
+ const result = await runUpload(api, plan, (done, all, label) => {
399
+ up.message(`${done}/${all} ${label}`);
400
+ });
401
+ up.stop('Fertig');
402
+ log.success(`${result.skills} Skills, ${result.skillFiles} Skill-Dateien, ` +
403
+ `${result.agents} Agents, ${result.memory} Memory-Dateien`);
404
+ if (result.failures.length > 0) {
405
+ log.error([`${result.failures.length} fehlgeschlagen`, ...result.failures.map((f) => ` ${f.what} ${f.code}`)].join('\n'));
406
+ process.exitCode = 1;
407
+ }
408
+ }
409
+ if (opts.prune) {
410
+ // Verglichen wird nur, was auch gelesen wurde. Ohne --memory sagt ein
411
+ // Import gar nichts ueber Memory aus, und "steht im Konto, fehlt in der
412
+ // Quelle" waere dort keine Aussage, sondern ein Unfall.
413
+ const covered = {
414
+ skills: existsSync(roots.skills),
415
+ agents: existsSync(roots.agents),
416
+ memory: Boolean(roots.memory && existsSync(roots.memory)),
417
+ };
418
+ const targets = await planPrune(api, plan, covered);
419
+ if (isEmpty(targets)) {
420
+ log.info('Nichts zu loeschen: das Konto haelt nichts, was die Quelle nicht kennt.');
421
+ }
422
+ else {
423
+ // Vollstaendig aufgezaehlt, nicht gezaehlt. Eine Zahl zu bestaetigen
424
+ // heisst, etwas zu bestaetigen, das man nicht gesehen hat.
425
+ log.warn([
426
+ 'Wuerde geloescht (nur Eigenes, nichts aus einem Team, nichts Archiviertes)',
427
+ ...targets.skills.map((n) => ` Skill ${n}`),
428
+ ...targets.agents.map((n) => ` Agent ${n}`),
429
+ ...targets.memory.map((p) => ` Memory ${p}`),
430
+ ].join('\n'));
431
+ if (opts.dryRun) {
432
+ log.info('Nichts geloescht (--dry-run).');
433
+ }
434
+ else if (!process.stdin.isTTY) {
435
+ // Kein --yes-Durchgriff: geloescht wird nur von Hand.
436
+ log.error('Kein Terminal fuer die Rueckfrage. Nichts geloescht.');
437
+ process.exitCode = 1;
438
+ }
439
+ else {
440
+ const go = await confirm({
441
+ message: `${countTargets(targets)} Eintraege im Konto loeschen?`,
442
+ initialValue: false,
326
443
  });
444
+ if (isCancel(go) || !go) {
445
+ log.info('Nichts geloescht.');
446
+ }
447
+ else {
448
+ const pruned = await runPrune(api, targets);
449
+ log.success(`${pruned.deleted} geloescht`);
450
+ if (pruned.failures.length > 0) {
451
+ log.error([
452
+ `${pruned.failures.length} fehlgeschlagen`,
453
+ ...pruned.failures.map((f) => ` ${f.what} ${f.code}`),
454
+ ].join('\n'));
455
+ process.exitCode = 1;
456
+ }
457
+ }
327
458
  }
328
459
  }
329
460
  }
330
- const up = spinner();
331
- up.start('Lade hoch');
332
- const result = await runUpload(api, plan, (done, all, label) => {
333
- up.message(`${done}/${all} ${label}`);
334
- });
335
- up.stop('Fertig');
336
- log.success(`${result.skills} Skills, ${result.skillFiles} Skill-Dateien, ` +
337
- `${result.agents} Agents, ${result.memory} Memory-Dateien`);
338
- if (result.failures.length > 0) {
339
- log.error([`${result.failures.length} fehlgeschlagen`, ...result.failures.map((f) => ` ${f.what} ${f.code}`)].join('\n'));
461
+ outro(opts.dryRun ? 'Nichts geaendert (--dry-run).' : 'Danach: onlymcp sync auf jedem Geraet.');
462
+ });
463
+ program
464
+ .command('export')
465
+ .description('Alles aus dem Konto holen: Memory, Skills, Agents, Verbindungen')
466
+ .option('--out <dir>', 'Archiv in diesen Ordner entpacken')
467
+ .option('--zip <file>', 'Archiv als Datei behalten')
468
+ .option('--scope <scope>', 'personal, all oder team:<id>', 'all')
469
+ .option('--types <list>', 'memory,skills,agents,connections')
470
+ .action(async (opts) => {
471
+ // Genau eines von beiden. Beides hiesse zweimal herunterladen, keines
472
+ // hiesse, die teuerste Leseoperation des Produkts ins Nichts zu schicken.
473
+ if ((opts.out ? 1 : 0) + (opts.zip ? 1 : 0) !== 1) {
474
+ log.error('Entweder --out <ordner> oder --zip <datei>, nicht beides und nicht keines.');
475
+ process.exitCode = 1;
476
+ return;
477
+ }
478
+ intro('OnlyMCP Export');
479
+ const api = new ApiClient(baseUrl, () => Keyring.read());
480
+ const s = spinner();
481
+ s.start('Hole das Archiv');
482
+ let res;
483
+ try {
484
+ res = await api.exportArchive({
485
+ scope: opts.scope,
486
+ types: opts.types?.split(',').map((t) => t.trim()).filter((t) => t !== ''),
487
+ });
488
+ }
489
+ catch (e) {
490
+ s.stop('Abgebrochen');
491
+ log.error(e instanceof Error ? e.message : String(e));
492
+ log.info('Nicht angemeldet? Zuerst: onlymcp login');
493
+ process.exitCode = 1;
494
+ return;
495
+ }
496
+ if (opts.zip) {
497
+ // In die Datei geschrieben, waehrend es ankommt. Ein Konto mit zwei
498
+ // Gigabyte soll nicht erst zwei Gigabyte Arbeitsspeicher kosten.
499
+ mkdirSync(dirname(opts.zip), { recursive: true });
500
+ await pipeline(Readable.fromWeb(res.body), createWriteStream(opts.zip));
501
+ s.stop('Fertig');
502
+ outro(`Archiv: ${opts.zip}`);
503
+ return;
504
+ }
505
+ const bytes = new Uint8Array(await res.arrayBuffer());
506
+ const result = await unpackArchive(bytes, opts.out);
507
+ s.stop('Fertig');
508
+ log.success(`${result.written} Dateien in ${opts.out}`);
509
+ if (result.refused.length > 0) {
510
+ log.warn(['Nicht geschrieben, unzulaessiger Pfad im Archiv', ...result.refused.map((p) => ` ${p}`)].join('\n'));
511
+ }
512
+ if (result.failed.length > 0) {
513
+ // Auf Windows der Normalfall fuer einen Skill mit Namensraum: der
514
+ // Doppelpunkt ist dort kein zulaessiges Zeichen in einem Ordnernamen.
515
+ log.warn([
516
+ 'Nicht geschrieben, der Dateiname geht auf diesem System nicht',
517
+ ...result.failed.map((f) => ` ${f.path} ${f.reason}`),
518
+ 'Mit --zip <datei> bleibt das Archiv unveraendert erhalten.',
519
+ ].join('\n'));
340
520
  process.exitCode = 1;
341
521
  }
342
- outro('Danach: onlymcp sync auf jedem Geraet.');
522
+ outro(`Zurueckspielen: onlymcp import --skills ${opts.out}/skills --agents ${opts.out}/agents --memory ${opts.out}/memory`);
343
523
  });
344
524
  await program.parseAsync();
345
525
  //# sourceMappingURL=cli.js.map