forgeos 0.1.0-alpha.67 → 0.1.0-alpha.69

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 (67) hide show
  1. package/.agents/skills/forge-agent-fabric/SKILL.md +157 -0
  2. package/.agents/skills/forge-agent-fabric/references/managed-workflows.md +95 -0
  3. package/.agents/skills/forge-agent-fabric/references/repository-analysis.md +102 -0
  4. package/.agents/skills/forge-agent-fabric/scripts/fabric.mjs +46 -0
  5. package/.agents/skills/forge-agent-fabric/scripts/repository.mjs +44 -0
  6. package/AGENTS.md +1 -1
  7. package/CHANGELOG.md +22 -0
  8. package/README.md +12 -3
  9. package/docs/agent-fabric.md +22 -1
  10. package/docs/architecture/agent-fabric/PORTABLE_PROJECTS_PLAN.md +136 -0
  11. package/docs/architecture/agent-fabric/README.md +153 -0
  12. package/docs/architecture/agent-fabric/REPOSITORY_MANIFEST_PLAN.md +272 -0
  13. package/docs/changelog.md +32 -0
  14. package/docs/repository-agent-benchmark.md +179 -0
  15. package/docs/repository-analysis.md +139 -0
  16. package/docs/repository-context-quality.md +179 -0
  17. package/docs/repository-runtime-observation.md +82 -0
  18. package/package.json +18 -2
  19. package/schemas/forge-manifest.schema.json +385 -53
  20. package/scripts/install-agent-fabric-skill.mjs +105 -0
  21. package/src/forge/_generated/releaseManifest.json +1 -1
  22. package/src/forge/_generated/releaseManifest.ts +3 -3
  23. package/src/forge/agent-fabric/local-task-server.ts +39 -11
  24. package/src/forge/agent-fabric/managed-run-contract.ts +1 -0
  25. package/src/forge/agent-fabric/managed-run-service.ts +10 -1
  26. package/src/forge/agent-fabric/managed-run-store.ts +33 -3
  27. package/src/forge/agent-fabric/managed-workspace.ts +56 -18
  28. package/src/forge/agent-fabric/project-profile.ts +50 -0
  29. package/src/forge/agent-fabric/project-registry.ts +120 -0
  30. package/src/forge/agent-fabric/project-runtime.ts +85 -0
  31. package/src/forge/agent-fabric/repository-context.ts +83 -0
  32. package/src/forge/agent-memory/mcp.ts +95 -12
  33. package/src/forge/cair/index.ts +15 -3
  34. package/src/forge/cair/types.ts +9 -2
  35. package/src/forge/cli/commands.ts +19 -0
  36. package/src/forge/cli/fabric.ts +42 -8
  37. package/src/forge/cli/main.ts +279 -259
  38. package/src/forge/cli/parse.ts +3636 -3574
  39. package/src/forge/cli/repository.ts +151 -0
  40. package/src/forge/compiler/external-manifest/registry.ts +21 -9
  41. package/src/forge/delta/process-identity.ts +22 -16
  42. package/src/forge/repository-analysis/adapters/common.ts +72 -0
  43. package/src/forge/repository-analysis/adapters/docker.ts +185 -0
  44. package/src/forge/repository-analysis/adapters/java.ts +133 -0
  45. package/src/forge/repository-analysis/adapters/typescript.ts +350 -0
  46. package/src/forge/repository-analysis/adapters/vue.ts +71 -0
  47. package/src/forge/repository-analysis/analyze.ts +434 -0
  48. package/src/forge/repository-analysis/benchmark.ts +336 -0
  49. package/src/forge/repository-analysis/cache-gc.ts +154 -0
  50. package/src/forge/repository-analysis/check-selection.ts +123 -0
  51. package/src/forge/repository-analysis/context-node.ts +17 -0
  52. package/src/forge/repository-analysis/context.ts +456 -0
  53. package/src/forge/repository-analysis/http-resolution.ts +135 -0
  54. package/src/forge/repository-analysis/identity.ts +45 -0
  55. package/src/forge/repository-analysis/index.ts +18 -0
  56. package/src/forge/repository-analysis/nuxt-resolution.ts +188 -0
  57. package/src/forge/repository-analysis/quality.ts +60 -0
  58. package/src/forge/repository-analysis/retrieval.ts +309 -0
  59. package/src/forge/repository-analysis/runtime-artifacts.ts +195 -0
  60. package/src/forge/repository-analysis/runtime-observation.ts +316 -0
  61. package/src/forge/repository-analysis/scanner.ts +174 -0
  62. package/src/forge/repository-analysis/storage.ts +193 -0
  63. package/src/forge/repository-analysis/test-associations.ts +59 -0
  64. package/src/forge/repository-analysis/types.ts +99 -0
  65. package/src/forge/repository-manifest/index.ts +178 -0
  66. package/src/forge/repository-manifest/types.ts +63 -0
  67. package/src/forge/version.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "forgeos",
3
- "version": "0.1.0-alpha.67",
3
+ "version": "0.1.0-alpha.69",
4
4
  "description": "Agent-native application framework and compiler for building Forge apps without a mandatory dashboard.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -11,9 +11,17 @@
11
11
  "!adapters/**/*.jar",
12
12
  "bin/",
13
13
  "scripts/field-test-forgeos.mjs",
14
+ "scripts/install-agent-fabric-skill.mjs",
15
+ ".agents/skills/forge-agent-fabric/",
14
16
  "docs/cair-protocol.md",
15
17
  "docs/forge-protocol.md",
16
18
  "docs/agent-fabric.md",
19
+ "docs/repository-analysis.md",
20
+ "docs/repository-context-quality.md",
21
+ "docs/repository-agent-benchmark.md",
22
+ "docs/repository-runtime-observation.md",
23
+ "docs/architecture/agent-fabric/REPOSITORY_MANIFEST_PLAN.md",
24
+ "docs/architecture/agent-fabric/PORTABLE_PROJECTS_PLAN.md",
17
25
  "examples/go-billing/",
18
26
  "examples/java-billing/",
19
27
  "!examples/**/target/**",
@@ -50,7 +58,8 @@
50
58
  "./vue": "./src/forge/vue/index.ts",
51
59
  "./server": "./src/forge/server.ts",
52
60
  "./policy": "./src/forge/policy.ts",
53
- "./agent-fabric": "./src/forge/agent-fabric/index.ts"
61
+ "./agent-fabric": "./src/forge/agent-fabric/index.ts",
62
+ "./repository-analysis": "./src/forge/repository-analysis/index.ts"
54
63
  },
55
64
  "scripts": {
56
65
  "test": "node ./bin/forge-bun.mjs test --timeout 120000",
@@ -68,6 +77,7 @@
68
77
  "release:publish-alpha": "node scripts/publish-trusted-alpha.mjs",
69
78
  "release:publish-local-alpha": "node scripts/publish-local-alpha.mjs",
70
79
  "field:test": "node scripts/field-test-forgeos.mjs",
80
+ "fabric:install-skill": "node scripts/install-agent-fabric-skill.mjs",
71
81
  "forge": "node ./bin/forge.mjs",
72
82
  "forge:node": "node ./bin/forge.mjs",
73
83
  "forge:bun": "node ./bin/forge-bun.mjs src/forge/cli/main.ts",
@@ -107,6 +117,7 @@
107
117
  "@electric-sql/pglite": "^0.2.17",
108
118
  "@openai/codex-sdk": "0.160.0",
109
119
  "@types/react": "^19.2.17",
120
+ "@vue/compiler-sfc": "3.5.38",
110
121
  "ai": "^6.0.205",
111
122
  "jose": "^6.2.3",
112
123
  "postgres": "^3.4.5",
@@ -116,6 +127,7 @@
116
127
  "tsx": "^4.20.6",
117
128
  "typescript": "^5.7.3",
118
129
  "vue": "^3.5.38",
130
+ "yaml": "2.9.1",
119
131
  "zod": "^3.25.76"
120
132
  },
121
133
  "devDependencies": {
@@ -129,6 +141,10 @@
129
141
  "react-test-renderer": "^19.2.7"
130
142
  },
131
143
  "overrides": {
144
+ "@ai-sdk/provider-utils": "4.0.33",
145
+ "fast-uri": "3.1.8",
146
+ "nanoid": "3.3.18",
147
+ "postcss": "8.5.29",
132
148
  "read-yaml-file": "^3.0.0"
133
149
  }
134
150
  }
@@ -1,57 +1,389 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://forgeos.dev/schemas/forge-manifest.schema.json",
4
- "title": "Forge external runtime manifest",
5
- "type": "object",
6
- "required": ["forgeProtocol", "language", "service", "entries"],
7
- "properties": {
8
- "forgeProtocol": { "const": "1.0" },
9
- "language": { "type": "string", "minLength": 1 },
10
- "framework": { "type": "string", "minLength": 1 },
11
- "service": {
12
- "type": "object",
13
- "required": ["name", "transport"],
14
- "properties": {
15
- "name": { "type": "string", "minLength": 1 },
16
- "transport": { "enum": ["http", "grpc", "stdio"] },
17
- "baseUrl": { "type": "string", "minLength": 1 },
18
- "command": { "type": "string", "minLength": 1 },
19
- "health": { "type": "string", "minLength": 1 }
20
- },
21
- "additionalProperties": false
22
- },
23
- "entries": {
24
- "type": "array",
25
- "items": {
26
- "type": "object",
27
- "required": ["name", "kind"],
28
- "properties": {
29
- "name": { "type": "string", "minLength": 1 },
30
- "kind": { "enum": ["command", "query"] },
31
- "description": { "type": "string" },
32
- "path": { "type": "string", "minLength": 1 },
33
- "method": { "enum": ["GET", "POST"] },
34
- "inputSchema": {},
35
- "outputSchema": {},
36
- "policy": { "type": "string", "minLength": 1 },
37
- "tenantScoped": { "type": "boolean" },
38
- "transaction": {
39
- "enum": ["read-only", "external-managed", "forge-managed", "saga"]
40
- },
41
- "risk": { "enum": ["read", "write", "destructive", "external"] },
42
- "needsApproval": { "type": "boolean" },
43
- "effects": {
44
- "type": "array",
45
- "items": { "type": "string" }
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://forgeos.dev/schemas/forge-manifest.schema.json",
4
+ "title": "Forge external runtime manifest",
5
+ "oneOf": [
6
+ {
7
+ "$ref": "#/$defs/service"
8
+ },
9
+ {
10
+ "$ref": "#/$defs/repository"
11
+ }
12
+ ],
13
+ "$defs": {
14
+ "service": {
15
+ "type": "object",
16
+ "required": [
17
+ "forgeProtocol",
18
+ "language",
19
+ "service",
20
+ "entries"
21
+ ],
22
+ "properties": {
23
+ "forgeProtocol": {
24
+ "const": "1.0"
25
+ },
26
+ "language": {
27
+ "type": "string",
28
+ "minLength": 1
29
+ },
30
+ "framework": {
31
+ "type": "string",
32
+ "minLength": 1
33
+ },
34
+ "service": {
35
+ "type": "object",
36
+ "required": [
37
+ "name",
38
+ "transport"
39
+ ],
40
+ "properties": {
41
+ "name": {
42
+ "type": "string",
43
+ "minLength": 1
44
+ },
45
+ "transport": {
46
+ "enum": [
47
+ "http",
48
+ "grpc",
49
+ "stdio"
50
+ ]
51
+ },
52
+ "baseUrl": {
53
+ "type": "string",
54
+ "minLength": 1
55
+ },
56
+ "command": {
57
+ "type": "string",
58
+ "minLength": 1
59
+ },
60
+ "health": {
61
+ "type": "string",
62
+ "minLength": 1
63
+ },
64
+ "commandArgs": {
65
+ "type": "array",
66
+ "minItems": 1,
67
+ "prefixItems": [
68
+ {
69
+ "type": "string",
70
+ "minLength": 1
71
+ }
72
+ ],
73
+ "items": {
74
+ "type": "string"
75
+ }
76
+ }
77
+ },
78
+ "additionalProperties": false
79
+ },
80
+ "entries": {
81
+ "type": "array",
82
+ "items": {
83
+ "type": "object",
84
+ "required": [
85
+ "name",
86
+ "kind"
87
+ ],
88
+ "properties": {
89
+ "name": {
90
+ "type": "string",
91
+ "minLength": 1
92
+ },
93
+ "kind": {
94
+ "enum": [
95
+ "command",
96
+ "query"
97
+ ]
98
+ },
99
+ "description": {
100
+ "type": "string"
101
+ },
102
+ "path": {
103
+ "type": "string",
104
+ "minLength": 1
105
+ },
106
+ "method": {
107
+ "enum": [
108
+ "GET",
109
+ "POST"
110
+ ]
111
+ },
112
+ "inputSchema": {},
113
+ "outputSchema": {},
114
+ "policy": {
115
+ "type": "string",
116
+ "minLength": 1
117
+ },
118
+ "tenantScoped": {
119
+ "type": "boolean"
120
+ },
121
+ "transaction": {
122
+ "enum": [
123
+ "read-only",
124
+ "external-managed",
125
+ "forge-managed",
126
+ "saga"
127
+ ]
128
+ },
129
+ "risk": {
130
+ "enum": [
131
+ "read",
132
+ "write",
133
+ "destructive",
134
+ "external"
135
+ ]
136
+ },
137
+ "needsApproval": {
138
+ "type": "boolean"
139
+ },
140
+ "effects": {
141
+ "type": "array",
142
+ "items": {
143
+ "type": "string"
144
+ }
145
+ }
146
+ },
147
+ "additionalProperties": false
148
+ }
149
+ },
150
+ "schemas": {
151
+ "type": "object",
152
+ "additionalProperties": true
153
+ }
154
+ },
155
+ "additionalProperties": false
156
+ },
157
+ "repository": {
158
+ "type": "object",
159
+ "required": [
160
+ "forgeProtocol",
161
+ "kind",
162
+ "components"
163
+ ],
164
+ "additionalProperties": false,
165
+ "properties": {
166
+ "forgeProtocol": {
167
+ "const": "2.0"
168
+ },
169
+ "kind": {
170
+ "const": "repository"
171
+ },
172
+ "components": {
173
+ "type": "array",
174
+ "minItems": 1,
175
+ "maxItems": 1000,
176
+ "items": {
177
+ "type": "object",
178
+ "required": [
179
+ "id",
180
+ "root",
181
+ "adapters"
182
+ ],
183
+ "additionalProperties": false,
184
+ "properties": {
185
+ "id": {
186
+ "type": "string",
187
+ "pattern": "^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$"
188
+ },
189
+ "root": {
190
+ "type": "string",
191
+ "minLength": 1,
192
+ "maxLength": 4096,
193
+ "pattern": "^(?!/)(?!.*[:\\u0000-\\u001f])(?!.*\\\\)(?!.*(?:^|/)\\.\\.(?:/|$)).+$"
194
+ },
195
+ "adapters": {
196
+ "type": "array",
197
+ "minItems": 1,
198
+ "uniqueItems": true,
199
+ "items": {
200
+ "enum": [
201
+ "typescript",
202
+ "javascript",
203
+ "vue",
204
+ "nuxt",
205
+ "java",
206
+ "spring",
207
+ "maven",
208
+ "gradle",
209
+ "docker"
210
+ ]
211
+ }
212
+ },
213
+ "files": {
214
+ "type": "array",
215
+ "maxItems": 1000,
216
+ "items": {
217
+ "type": "string",
218
+ "minLength": 1,
219
+ "maxLength": 4096,
220
+ "pattern": "^(?!/)(?!.*[:\\u0000-\\u001f])(?!.*\\\\)(?!.*(?:^|/)\\.\\.(?:/|$)).+$"
221
+ }
222
+ },
223
+ "analysis": {
224
+ "type": "object",
225
+ "additionalProperties": false,
226
+ "properties": {
227
+ "aliases": {
228
+ "type": "object", "maxProperties": 100,
229
+ "propertyNames": { "type": "string", "pattern": "^(?!__proto__$|prototype$|constructor$)(?!.*(?:^|/)\\.\\.(?:/|$))[A-Za-z_$@~][A-Za-z0-9_$@~./-]{0,127}$" },
230
+ "additionalProperties": { "$ref": "#/$defs/repositoryPath" }
231
+ },
232
+ "nuxt": {
233
+ "type": "object", "additionalProperties": false,
234
+ "properties": {
235
+ "rootDir": { "$ref": "#/$defs/repositoryPath" },
236
+ "srcDir": { "$ref": "#/$defs/repositoryPath" },
237
+ "components": { "type": "array", "maxItems": 100, "items": { "$ref": "#/$defs/repositoryPath" } },
238
+ "imports": { "type": "array", "maxItems": 100, "items": { "$ref": "#/$defs/repositoryPath" } }
239
+ }
240
+ }
241
+ }
242
+ }
243
+ }
244
+ }
245
+ },
246
+ "exclude": {
247
+ "type": "array",
248
+ "maxItems": 1000,
249
+ "items": {
250
+ "type": "string",
251
+ "minLength": 1,
252
+ "maxLength": 4096,
253
+ "pattern": "^(?!/)(?!.*[:\\u0000-\\u001f])(?!.*\\\\)(?!.*(?:^|/)\\.\\.(?:/|$)).+$"
254
+ }
255
+ },
256
+ "services": {
257
+ "type": "array",
258
+ "maxItems": 1000,
259
+ "items": {
260
+ "type": "string",
261
+ "minLength": 1,
262
+ "maxLength": 4096,
263
+ "pattern": "^(?!/)(?!.*[:\\u0000-\\u001f])(?!.*\\\\)(?!.*(?:^|/)\\.\\.(?:/|$)).+$"
264
+ }
265
+ },
266
+ "checks": {
267
+ "type": "array",
268
+ "maxItems": 1000,
269
+ "items": {
270
+ "type": "object",
271
+ "required": [
272
+ "id",
273
+ "component",
274
+ "argv"
275
+ ],
276
+ "additionalProperties": false,
277
+ "properties": {
278
+ "id": {
279
+ "type": "string",
280
+ "pattern": "^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$"
281
+ },
282
+ "component": {
283
+ "type": "string",
284
+ "pattern": "^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$"
285
+ },
286
+ "argv": {
287
+ "type": "array",
288
+ "minItems": 1,
289
+ "maxItems": 1000,
290
+ "items": {
291
+ "type": "string",
292
+ "minLength": 1,
293
+ "maxLength": 4096
294
+ }
295
+ },
296
+ "cwd": { "$ref": "#/$defs/repositoryPath" },
297
+ "files": { "type": "array", "maxItems": 1000, "items": { "$ref": "#/$defs/repositoryPath" } },
298
+ "category": { "enum": ["typecheck", "test", "lint", "build", "integration", "security", "other"] },
299
+ "cost": { "enum": ["low", "medium", "high"] },
300
+ "requires": {
301
+ "type": "array", "maxItems": 32, "uniqueItems": true,
302
+ "items": { "type": "string", "pattern": "^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$" }
303
+ }
304
+ }
305
+ }
306
+ },
307
+ "httpClients": {
308
+ "type": "array", "maxItems": 1000,
309
+ "items": {
310
+ "type": "object", "additionalProperties": false,
311
+ "required": ["id", "component"],
312
+ "properties": {
313
+ "id": { "type": "string", "pattern": "^[A-Za-z_$][A-Za-z0-9_$.-]{0,79}$" },
314
+ "component": { "type": "string", "pattern": "^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$" },
315
+ "apiComponent": { "type": "string", "pattern": "^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$" },
316
+ "files": { "type": "array", "maxItems": 1000, "items": { "$ref": "#/$defs/repositoryPath" } },
317
+ "basePath": { "type": "string", "maxLength": 2048, "pattern": "^/(?!/)(?!.*(?:^|/)\\.\\.(?:/|$))[A-Za-z0-9_~!()*+,;=:@./-]*$" }
318
+ }
46
319
  }
47
320
  },
48
- "additionalProperties": false
49
- }
321
+ "runtime": {
322
+ "type": "object", "additionalProperties": false, "required": ["observations"],
323
+ "properties": { "observations": {
324
+ "type": "array", "minItems": 1, "maxItems": 32,
325
+ "items": {
326
+ "type": "object", "additionalProperties": false, "required": ["id", "component", "commands", "artifacts"],
327
+ "properties": {
328
+ "id": { "type": "string", "pattern": "^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$" },
329
+ "component": { "type": "string", "pattern": "^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$" },
330
+ "commands": { "type": "array", "minItems": 1, "maxItems": 16, "items": {
331
+ "type": "object", "additionalProperties": false, "required": ["argv"],
332
+ "properties": {
333
+ "argv": { "type": "array", "minItems": 1, "maxItems": 128, "items": { "type": "string", "minLength": 1, "maxLength": 4096, "pattern": "^[^\\u0000-\\u001f\\u007f]+$" } },
334
+ "cwd": { "$ref": "#/$defs/repositoryPath" },
335
+ "timeoutMs": { "type": "integer", "minimum": 100, "maximum": 120000 }
336
+ }
337
+ } },
338
+ "artifacts": { "type": "array", "minItems": 1, "maxItems": 32, "items": {
339
+ "type": "object", "additionalProperties": false, "required": ["path", "format"],
340
+ "properties": {
341
+ "path": { "$ref": "#/$defs/repositoryPath" },
342
+ "format": { "enum": ["nuxt-components", "nuxt-imports", "spring-mappings", "spring-beans", "docker-inspect", "http-trace", "forge-runtime"] }
343
+ }
344
+ } }
345
+ }
346
+ }
347
+ } }
348
+ },
349
+ "scenario": {
350
+ "type": "object",
351
+ "additionalProperties": false,
352
+ "properties": {
353
+ "id": {
354
+ "type": "string",
355
+ "pattern": "^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$"
356
+ },
357
+ "mode": {
358
+ "type": "string",
359
+ "pattern": "^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$"
360
+ },
361
+ "profiles": {
362
+ "type": "array",
363
+ "maxItems": 1000,
364
+ "items": {
365
+ "type": "string",
366
+ "minLength": 1,
367
+ "maxLength": 4096
368
+ }
369
+ },
370
+ "composeFiles": {
371
+ "type": "array",
372
+ "maxItems": 1000,
373
+ "items": {
374
+ "type": "string",
375
+ "minLength": 1,
376
+ "maxLength": 4096,
377
+ "pattern": "^(?!/)(?!.*[:\\u0000-\\u001f])(?!.*\\\\)(?!.*(?:^|/)\\.\\.(?:/|$)).+$"
378
+ }
379
+ }
380
+ }
381
+ }
382
+ }
50
383
  },
51
- "schemas": {
52
- "type": "object",
53
- "additionalProperties": true
384
+ "repositoryPath": {
385
+ "type": "string", "minLength": 1, "maxLength": 4096,
386
+ "pattern": "^(?!/)(?!.*[:\\u0000-\\u001f])(?!.*\\\\)(?!.*(?:^|/)\\.\\.(?:/|$)).+$"
54
387
  }
55
- },
56
- "additionalProperties": false
57
- }
388
+ }
389
+ }
@@ -0,0 +1,105 @@
1
+ #!/usr/bin/env node
2
+ import { cpSync, existsSync, lstatSync, mkdirSync, readFileSync, readlinkSync, realpathSync, readdirSync, renameSync, writeFileSync } from 'node:fs';
3
+ import { createHash, randomUUID } from 'node:crypto';
4
+ import { basename, dirname, resolve, sep } from 'node:path';
5
+ import { homedir } from 'node:os';
6
+ import { fileURLToPath } from 'node:url';
7
+
8
+ const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
9
+ function sourceInventory(directory) {
10
+ const files = [];
11
+ function visit(base, relative = '') {
12
+ for (const entry of readdirSync(base, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
13
+ if (!relative && ['runtime.json', 'installation.json'].includes(entry.name)) continue;
14
+ const name = `${relative}/${entry.name}`;
15
+ if (entry.isDirectory()) visit(resolve(base, entry.name), name);
16
+ else files.push(name.slice(1));
17
+ }
18
+ }
19
+ visit(directory);
20
+ return files;
21
+ }
22
+ function sourceDigest(directory, inventory) {
23
+ const hash = createHash('sha256');
24
+ for (const name of inventory) {
25
+ const file = resolve(directory, name);
26
+ try {
27
+ const stat = lstatSync(file);
28
+ hash.update(JSON.stringify([name, stat.isSymbolicLink() ? 'link' : 'file']));
29
+ hash.update(stat.isSymbolicLink() ? readlinkSync(file) : readFileSync(file));
30
+ } catch { return null; }
31
+ }
32
+ return hash.digest('hex');
33
+ }
34
+ function canonicalPath(path) {
35
+ try { return realpathSync(path); } catch {
36
+ const parent = dirname(path);
37
+ if (parent === path) throw new Error(`Cannot resolve destination: ${path}`);
38
+ return resolve(canonicalPath(parent), basename(path));
39
+ }
40
+ }
41
+ try {
42
+ const args = process.argv.slice(2);
43
+ const known = new Set(['--dest', '--runtime', '--dry-run', '--replace', '--help']);
44
+ const options = {};
45
+ for (let index = 0; index < args.length; index++) {
46
+ const flag = args[index];
47
+ if (!known.has(flag)) throw new Error(`Unknown option: ${flag}`);
48
+ if (flag === '--dest' || flag === '--runtime') {
49
+ if (!args[index + 1] || args[index + 1].startsWith('--')) throw new Error(`${flag} requires a path`);
50
+ options[flag] = args[++index];
51
+ } else options[flag] = true;
52
+ }
53
+ if (options['--help']) {
54
+ process.stdout.write('Install portable Agent Fabric skill: --dest <skills-root> --runtime <forge.mjs> --dry-run --replace\nDefaults: ~/.agents/skills and this package runtime. No MCP or hooks are configured.\n');
55
+ } else {
56
+ const source = resolve(packageRoot, '.agents/skills/forge-agent-fabric');
57
+ const skillsRoot = resolve(options['--dest'] || resolve(homedir(), '.agents/skills'));
58
+ const target = resolve(skillsRoot, 'forge-agent-fabric');
59
+ const runtime = realpathSync(resolve(options['--runtime'] || resolve(packageRoot, 'bin/forge.mjs')));
60
+ const marker = resolve(target, 'installation.json');
61
+ let installed = {};
62
+ let owned = false;
63
+ if (existsSync(marker)) {
64
+ try { installed = JSON.parse(readFileSync(marker, 'utf8')); owned = installed.installer === 'forgeos-agent-fabric-skill'; } catch {}
65
+ }
66
+ if (existsSync(target) && !owned && !options['--replace']) {
67
+ throw new Error(`Existing skill is not managed by this installer: ${target}. Review it and use --replace to preserve a backup and replace it.`);
68
+ }
69
+ const normalize = (path) => process.platform === 'win32' ? path.toLowerCase() : path;
70
+ const canonicalSource = normalize(canonicalPath(source));
71
+ const canonicalTarget = normalize(canonicalPath(target));
72
+ if (canonicalTarget === canonicalSource || canonicalTarget.startsWith(`${canonicalSource}${sep}`) || canonicalSource.startsWith(`${canonicalTarget}${sep}`)) {
73
+ throw new Error('Installation destination must differ from the packaged source skill.');
74
+ }
75
+ const inventory = sourceInventory(source);
76
+ const digest = sourceDigest(source, inventory);
77
+ if (!digest) throw new Error('Packaged skill contains unreadable source files.');
78
+ let existingRuntime = {};
79
+ try { existingRuntime = JSON.parse(readFileSync(resolve(target, 'runtime.json'), 'utf8')); } catch {}
80
+ const unchanged = owned && installed.sourceDigest === digest && sourceDigest(target, inventory) === digest && existingRuntime.cliPath === runtime && existingRuntime.nodeExecutable === process.execPath;
81
+ const result = { target, cliPath: runtime, nodeExecutable: process.execPath, dryRun: !!options['--dry-run'], replacesExisting: existsSync(target), unchanged };
82
+ if (!options['--dry-run'] && !unchanged) {
83
+ // Stage outside the discovery root so incomplete or backup copies are not skills.
84
+ const stagingRoot = resolve(dirname(skillsRoot), 'skill-backups');
85
+ mkdirSync(stagingRoot, { recursive: true });
86
+ const staged = resolve(stagingRoot, `forge-agent-fabric-stage-${randomUUID()}`);
87
+ cpSync(source, staged, { recursive: true, verbatimSymlinks: true });
88
+ writeFileSync(resolve(staged, 'runtime.json'), `${JSON.stringify({ cliPath: runtime, nodeExecutable: process.execPath }, null, 2)}\n`);
89
+ writeFileSync(resolve(staged, 'installation.json'), `${JSON.stringify({ installer: 'forgeos-agent-fabric-skill', version: 1, sourceDigest: digest }, null, 2)}\n`);
90
+ mkdirSync(skillsRoot, { recursive: true });
91
+ if (existsSync(target)) {
92
+ result.backup = resolve(stagingRoot, `forge-agent-fabric-backup-${randomUUID()}`);
93
+ renameSync(target, result.backup);
94
+ }
95
+ try { renameSync(staged, target); } catch (error) {
96
+ if (result.backup && !existsSync(target)) renameSync(result.backup, target);
97
+ throw error;
98
+ }
99
+ }
100
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
101
+ }
102
+ } catch (error) {
103
+ process.stderr.write(`${error.message}\n`);
104
+ process.exitCode = 1;
105
+ }
@@ -1 +1 @@
1
- {"defaultProvider":"local","diagnostics":[],"env":{"deployEnv":"FORGE_DEPLOY_ENV","deployId":"FORGE_DEPLOY_ID","publicReleaseId":"NEXT_PUBLIC_FORGE_RELEASE_ID","releaseId":"FORGE_RELEASE_ID"},"gitSha":"unknown","optionalProviders":["local","sentry-compatible","sentry","glitchtip","bugsink","otel","custom"],"packageName":"forgeos","packageVersion":"0.1.0-alpha.67","releaseId":"forgeos@0.1.0-alpha.67+unknown","schemaVersion":"0.1.0"}
1
+ {"defaultProvider":"local","diagnostics":[],"env":{"deployEnv":"FORGE_DEPLOY_ENV","deployId":"FORGE_DEPLOY_ID","publicReleaseId":"NEXT_PUBLIC_FORGE_RELEASE_ID","releaseId":"FORGE_RELEASE_ID"},"gitSha":"unknown","optionalProviders":["local","sentry-compatible","sentry","glitchtip","bugsink","otel","custom"],"packageName":"forgeos","packageVersion":"0.1.0-alpha.69","releaseId":"forgeos@0.1.0-alpha.69+unknown","schemaVersion":"0.1.0"}
@@ -1,4 +1,4 @@
1
- // @forge-generated generator=0.1.0-alpha.67 input=cad72fb61cedf1a3702763e37d3d5706a149a8719284ec9090a960aa3a4e1e61 content=ffe58b6ba6641fa97fccc9a8c5cfec32c0df3dd112985346eb3ede12613986a1
1
+ // @forge-generated generator=0.1.0-alpha.69 input=a62f6d9631d76e83840b1f77cac5b6c6e1f6da1acab63d41614e2fe47b9d5ca7 content=358bd274474845d7c2050f21c82cb785f59de808ecbe5c04b8c833969b3f1e10
2
2
  export const releaseManifest = {
3
3
  "defaultProvider": "local",
4
4
  "diagnostics": [],
@@ -19,7 +19,7 @@ export const releaseManifest = {
19
19
  "custom"
20
20
  ],
21
21
  "packageName": "forgeos",
22
- "packageVersion": "0.1.0-alpha.67",
23
- "releaseId": "forgeos@0.1.0-alpha.67+unknown",
22
+ "packageVersion": "0.1.0-alpha.69",
23
+ "releaseId": "forgeos@0.1.0-alpha.69+unknown",
24
24
  "schemaVersion": "0.1.0"
25
25
  } as const;