@akira-tl/forgerelay 1.2.5 → 1.3.1
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/CHANGELOG.md +26 -0
- package/README.md +2 -2
- package/dist/cli/config/domains/context-cli.js +86 -0
- package/dist/cli/config/domains/domain-cli.js +468 -0
- package/dist/cli/config/general.js +174 -0
- package/dist/cli/config/inspect.js +29 -26
- package/dist/cli/config/migrate.js +6 -22
- package/dist/cli/config/scope.js +35 -0
- package/dist/cli/connect/relay.js +284 -0
- package/dist/cli/core/command-tree.js +68 -0
- package/dist/cli/core/serve-options.js +71 -0
- package/dist/cli/init/setup-config.js +26 -0
- package/dist/cli/init.js +37 -8
- package/dist/cli/maintenance-prune.js +1 -1
- package/dist/cli/maintenance.js +6 -6
- package/dist/cli/mcp/external-mcp.js +29 -17
- package/dist/cli/mcp/status.js +2 -2
- package/dist/cli/system/status.js +35 -0
- package/dist/cli.js +132 -272
- package/dist/mcp/operations/external-mcp/external-mcp-oauth.js +2 -2
- package/dist/mcp/server/core/schemas.js +2 -10
- package/dist/mcp/server/operations/runtime/operation-runtime.js +11 -7
- package/dist/runtime/config/config.js +30 -29
- package/dist/runtime/config/definition/general-config.js +18 -3
- package/dist/runtime/config/resolution/resolver.js +7 -4
- package/dist/runtime/config/user-config.js +6 -6
- package/dist/runtime/config/validation/paths.js +12 -0
- package/dist/subagents/profiles.js +37 -0
- package/dist/workspaces/bootstrap.js +31 -14
- package/dist/workspaces/context.js +159 -7
- package/dist/workspaces/relay/auth/cli-test-support.js +22 -0
- package/dist/workspaces/resources/context-sources.js +29 -0
- package/dist/workspaces/resources/resource-monitor.js +29 -6
- package/dist/workspaces/resources/skills.js +15 -10
- package/dist/workspaces/sessions.js +20 -2
- package/dist/workspaces/state/project-context.js +34 -8
- package/dist/workspaces.js +5 -2
- package/docs/chatgpt-coding-workflow.md +23 -20
- package/docs/configuration.md +40 -27
- package/docs/gotchas.md +8 -6
- package/docs/roadmap.md +1 -1
- package/package.json +2 -2
- package/schemas/v1/config.project-local.schema.json +74 -0
- package/schemas/v1/config.project.schema.json +74 -0
- package/schemas/v1/config.user.schema.json +57 -2
- package/scripts/ci/config-v2-product-acceptance.mjs +17 -12
- package/scripts/debug/runtime.mjs +19 -3
- package/scripts/debug/runtime.test.mjs +3 -0
- package/scripts/debug/serve.mjs +2 -2
|
@@ -5,6 +5,80 @@
|
|
|
5
5
|
"$schema": {
|
|
6
6
|
"description": "Editor-only JSON Schema URL. Ignored by ForgeRelay resolution.",
|
|
7
7
|
"type": "string"
|
|
8
|
+
},
|
|
9
|
+
"systemInstructionsPath": {
|
|
10
|
+
"description": "Selected system-level Agent instruction file consumed by ForgeRelay.",
|
|
11
|
+
"type": "string",
|
|
12
|
+
"minLength": 1,
|
|
13
|
+
"default": "~/.agents/AGENTS.md",
|
|
14
|
+
"x-forgerelay-scopes": [
|
|
15
|
+
"runtime",
|
|
16
|
+
"project-local",
|
|
17
|
+
"project",
|
|
18
|
+
"user",
|
|
19
|
+
"built-in"
|
|
20
|
+
],
|
|
21
|
+
"x-forgerelay-merge": "replace",
|
|
22
|
+
"x-forgerelay-reload": "hot",
|
|
23
|
+
"x-forgerelay-sensitivity": "public",
|
|
24
|
+
"x-forgerelay-interpolation": "none",
|
|
25
|
+
"x-forgerelay-execution-effect": "none",
|
|
26
|
+
"x-forgerelay-runtime-override": {
|
|
27
|
+
"env": "FORGERELAY_SYSTEM_INSTRUCTIONS_PATH"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"instructionNames": {
|
|
31
|
+
"description": "Project instruction basenames discovered hierarchically within a Workspace.",
|
|
32
|
+
"type": "array",
|
|
33
|
+
"items": {
|
|
34
|
+
"type": "string",
|
|
35
|
+
"minLength": 1
|
|
36
|
+
},
|
|
37
|
+
"default": [
|
|
38
|
+
"AGENTS.md"
|
|
39
|
+
],
|
|
40
|
+
"x-forgerelay-scopes": [
|
|
41
|
+
"runtime",
|
|
42
|
+
"project-local",
|
|
43
|
+
"project",
|
|
44
|
+
"user",
|
|
45
|
+
"built-in"
|
|
46
|
+
],
|
|
47
|
+
"x-forgerelay-merge": "replace",
|
|
48
|
+
"x-forgerelay-reload": "hot",
|
|
49
|
+
"x-forgerelay-sensitivity": "public",
|
|
50
|
+
"x-forgerelay-interpolation": "none",
|
|
51
|
+
"x-forgerelay-execution-effect": "none",
|
|
52
|
+
"x-forgerelay-runtime-override": {
|
|
53
|
+
"env": "FORGERELAY_INSTRUCTION_NAMES"
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"skillPaths": {
|
|
57
|
+
"description": "Ordered Agent Skill source directories; explicit higher-precedence lists replace lower-precedence lists.",
|
|
58
|
+
"type": "array",
|
|
59
|
+
"items": {
|
|
60
|
+
"type": "string",
|
|
61
|
+
"minLength": 1
|
|
62
|
+
},
|
|
63
|
+
"default": [
|
|
64
|
+
"~/.agents/skills",
|
|
65
|
+
"./.agents/skills"
|
|
66
|
+
],
|
|
67
|
+
"x-forgerelay-scopes": [
|
|
68
|
+
"runtime",
|
|
69
|
+
"project-local",
|
|
70
|
+
"project",
|
|
71
|
+
"user",
|
|
72
|
+
"built-in"
|
|
73
|
+
],
|
|
74
|
+
"x-forgerelay-merge": "replace",
|
|
75
|
+
"x-forgerelay-reload": "hot",
|
|
76
|
+
"x-forgerelay-sensitivity": "public",
|
|
77
|
+
"x-forgerelay-interpolation": "none",
|
|
78
|
+
"x-forgerelay-execution-effect": "none",
|
|
79
|
+
"x-forgerelay-runtime-override": {
|
|
80
|
+
"env": "FORGERELAY_SKILL_PATHS"
|
|
81
|
+
}
|
|
8
82
|
}
|
|
9
83
|
},
|
|
10
84
|
"additionalProperties": false,
|
|
@@ -370,11 +370,14 @@
|
|
|
370
370
|
"x-forgerelay-computed-default": "~/.codex"
|
|
371
371
|
},
|
|
372
372
|
"systemInstructionsPath": {
|
|
373
|
-
"description": "
|
|
373
|
+
"description": "Selected system-level Agent instruction file consumed by ForgeRelay.",
|
|
374
374
|
"type": "string",
|
|
375
375
|
"minLength": 1,
|
|
376
|
+
"default": "~/.agents/AGENTS.md",
|
|
376
377
|
"x-forgerelay-scopes": [
|
|
377
378
|
"runtime",
|
|
379
|
+
"project-local",
|
|
380
|
+
"project",
|
|
378
381
|
"user",
|
|
379
382
|
"built-in"
|
|
380
383
|
],
|
|
@@ -385,8 +388,60 @@
|
|
|
385
388
|
"x-forgerelay-execution-effect": "none",
|
|
386
389
|
"x-forgerelay-runtime-override": {
|
|
387
390
|
"env": "FORGERELAY_SYSTEM_INSTRUCTIONS_PATH"
|
|
391
|
+
}
|
|
392
|
+
},
|
|
393
|
+
"instructionNames": {
|
|
394
|
+
"description": "Project instruction basenames discovered hierarchically within a Workspace.",
|
|
395
|
+
"type": "array",
|
|
396
|
+
"items": {
|
|
397
|
+
"type": "string",
|
|
398
|
+
"minLength": 1
|
|
399
|
+
},
|
|
400
|
+
"default": [
|
|
401
|
+
"AGENTS.md"
|
|
402
|
+
],
|
|
403
|
+
"x-forgerelay-scopes": [
|
|
404
|
+
"runtime",
|
|
405
|
+
"project-local",
|
|
406
|
+
"project",
|
|
407
|
+
"user",
|
|
408
|
+
"built-in"
|
|
409
|
+
],
|
|
410
|
+
"x-forgerelay-merge": "replace",
|
|
411
|
+
"x-forgerelay-reload": "hot",
|
|
412
|
+
"x-forgerelay-sensitivity": "public",
|
|
413
|
+
"x-forgerelay-interpolation": "none",
|
|
414
|
+
"x-forgerelay-execution-effect": "none",
|
|
415
|
+
"x-forgerelay-runtime-override": {
|
|
416
|
+
"env": "FORGERELAY_INSTRUCTION_NAMES"
|
|
417
|
+
}
|
|
418
|
+
},
|
|
419
|
+
"skillPaths": {
|
|
420
|
+
"description": "Ordered Agent Skill source directories; explicit higher-precedence lists replace lower-precedence lists.",
|
|
421
|
+
"type": "array",
|
|
422
|
+
"items": {
|
|
423
|
+
"type": "string",
|
|
424
|
+
"minLength": 1
|
|
388
425
|
},
|
|
389
|
-
"
|
|
426
|
+
"default": [
|
|
427
|
+
"~/.agents/skills",
|
|
428
|
+
"./.agents/skills"
|
|
429
|
+
],
|
|
430
|
+
"x-forgerelay-scopes": [
|
|
431
|
+
"runtime",
|
|
432
|
+
"project-local",
|
|
433
|
+
"project",
|
|
434
|
+
"user",
|
|
435
|
+
"built-in"
|
|
436
|
+
],
|
|
437
|
+
"x-forgerelay-merge": "replace",
|
|
438
|
+
"x-forgerelay-reload": "hot",
|
|
439
|
+
"x-forgerelay-sensitivity": "public",
|
|
440
|
+
"x-forgerelay-interpolation": "none",
|
|
441
|
+
"x-forgerelay-execution-effect": "none",
|
|
442
|
+
"x-forgerelay-runtime-override": {
|
|
443
|
+
"env": "FORGERELAY_SKILL_PATHS"
|
|
444
|
+
}
|
|
390
445
|
},
|
|
391
446
|
"commandShell": {
|
|
392
447
|
"description": "Recorded command-shell preference for ForgeRelay command and Hook execution.",
|
|
@@ -87,25 +87,30 @@ async function acceptFreshInit({ installedCli, root, home }) {
|
|
|
87
87
|
});
|
|
88
88
|
|
|
89
89
|
let output = "";
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
const promptsToAccept = [
|
|
91
|
+
"Where are your projects located?",
|
|
92
|
+
"Which system instruction file should ForgeRelay load?",
|
|
93
|
+
"Which project instruction filenames should ForgeRelay discover?",
|
|
94
|
+
"Which Skill directories should ForgeRelay scan?",
|
|
95
|
+
"How should clients reach this ForgeRelay instance?",
|
|
96
|
+
];
|
|
97
|
+
const answered = new Set();
|
|
92
98
|
child.onData((data) => {
|
|
93
99
|
output += data;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
modeAnswered = true;
|
|
101
|
-
child.write("\r");
|
|
100
|
+
for (const prompt of promptsToAccept) {
|
|
101
|
+
if (!answered.has(prompt) && output.includes(prompt)) {
|
|
102
|
+
answered.add(prompt);
|
|
103
|
+
child.write("\r");
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
102
106
|
}
|
|
103
107
|
});
|
|
104
108
|
|
|
105
109
|
const exitCode = await waitForPtyExit(child, 20_000);
|
|
106
110
|
assert.equal(exitCode, 0, scrubTerminal(output));
|
|
107
|
-
|
|
108
|
-
|
|
111
|
+
for (const prompt of promptsToAccept) {
|
|
112
|
+
assert.equal(answered.has(prompt), true, `packaged init did not ask: ${prompt}`);
|
|
113
|
+
}
|
|
109
114
|
for (const unexpected of [
|
|
110
115
|
"Which local port should ForgeRelay use?",
|
|
111
116
|
"Which command shell should Agent commands and Hooks use?",
|
|
@@ -40,7 +40,23 @@ export function interactiveDebugUrls(configDir) {
|
|
|
40
40
|
: 7677;
|
|
41
41
|
const displayHost = host.includes(":") && !host.startsWith("[") ? `[${host}]` : host;
|
|
42
42
|
const baseUrl = `http://${displayHost}:${port}`;
|
|
43
|
-
|
|
43
|
+
const publicBaseUrl = Array.isArray(config.publicBaseUrl) ? config.publicBaseUrl[0] : config.publicBaseUrl;
|
|
44
|
+
const routeBasePath = publicBasePath(publicBaseUrl);
|
|
45
|
+
return {
|
|
46
|
+
baseUrl,
|
|
47
|
+
healthUrl: `${baseUrl}${routeBasePath}/healthz`,
|
|
48
|
+
mcpUrl: `${baseUrl}/mcp`,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function publicBasePath(value) {
|
|
53
|
+
if (typeof value !== "string" || !value.trim()) return "";
|
|
54
|
+
try {
|
|
55
|
+
const pathname = new URL(value).pathname.replace(/\/+$/, "");
|
|
56
|
+
return pathname === "/" ? "" : pathname;
|
|
57
|
+
} catch {
|
|
58
|
+
return "";
|
|
59
|
+
}
|
|
44
60
|
}
|
|
45
61
|
|
|
46
62
|
function interactiveDebugOwnerToken(configDir) {
|
|
@@ -66,7 +82,7 @@ export function createInteractiveDebugEnvironment({
|
|
|
66
82
|
} = {}) {
|
|
67
83
|
const configDir = interactiveDebugConfigDir({ env, home });
|
|
68
84
|
const ownerToken = interactiveDebugOwnerToken(configDir);
|
|
69
|
-
const { baseUrl, mcpUrl } = interactiveDebugUrls(configDir);
|
|
85
|
+
const { baseUrl, healthUrl, mcpUrl } = interactiveDebugUrls(configDir);
|
|
70
86
|
const productConfigDir = env.FORGERELAY_DEBUG_PRODUCT_CONFIG_DIR
|
|
71
87
|
? resolve(env.FORGERELAY_DEBUG_PRODUCT_CONFIG_DIR.startsWith("~/")
|
|
72
88
|
? join(home, env.FORGERELAY_DEBUG_PRODUCT_CONFIG_DIR.slice(2))
|
|
@@ -99,7 +115,7 @@ export function createInteractiveDebugEnvironment({
|
|
|
99
115
|
debugEnv.FORGERELAY_SKILLS = productSkillsEnabled;
|
|
100
116
|
}
|
|
101
117
|
|
|
102
|
-
return { ownerToken, configDir, baseUrl, mcpUrl, env: debugEnv };
|
|
118
|
+
return { ownerToken, configDir, baseUrl, healthUrl, mcpUrl, env: debugEnv };
|
|
103
119
|
}
|
|
104
120
|
|
|
105
121
|
export function createDebugEnvironment({
|
|
@@ -52,9 +52,11 @@ test("interactive debug uses one dedicated persisted config under ~/.forgerelay/
|
|
|
52
52
|
assert.equal(result.configDir, configDir);
|
|
53
53
|
assert.equal(result.env.FORGERELAY_CONFIG_DIR, configDir);
|
|
54
54
|
assert.equal(result.baseUrl, "http://127.0.0.1:7677");
|
|
55
|
+
assert.equal(result.healthUrl, "http://127.0.0.1:7677/forgerelay/debug/healthz");
|
|
55
56
|
assert.equal(result.mcpUrl, "http://127.0.0.1:7677/mcp");
|
|
56
57
|
assert.deepEqual(interactiveDebugUrls(configDir), {
|
|
57
58
|
baseUrl: "http://127.0.0.1:7677",
|
|
59
|
+
healthUrl: "http://127.0.0.1:7677/forgerelay/debug/healthz",
|
|
58
60
|
mcpUrl: "http://127.0.0.1:7677/mcp",
|
|
59
61
|
});
|
|
60
62
|
assert.equal(result.env.HOST, undefined);
|
|
@@ -100,6 +102,7 @@ test("interactive debug config directory may be explicitly relocated without fal
|
|
|
100
102
|
assert.equal(result.ownerToken, "custom-debug-password-123456");
|
|
101
103
|
assert.equal(result.env.FORGERELAY_CONFIG_DIR, customDir);
|
|
102
104
|
assert.equal(result.baseUrl, "http://127.0.0.1:6768");
|
|
105
|
+
assert.equal(result.healthUrl, "http://127.0.0.1:6768/healthz");
|
|
103
106
|
assert.equal(result.mcpUrl, "http://127.0.0.1:6768/mcp");
|
|
104
107
|
assert.equal(result.env.FORGERELAY_SKILL_PATHS, join(productConfigDir, "skills"));
|
|
105
108
|
});
|
package/scripts/debug/serve.mjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { createInteractiveDebugEnvironment, repoRoot } from "./runtime.mjs";
|
|
3
3
|
|
|
4
|
-
const { configDir,
|
|
4
|
+
const { configDir, healthUrl, mcpUrl, env } = createInteractiveDebugEnvironment();
|
|
5
5
|
|
|
6
6
|
console.error("[forgerelay:debug] local debug server");
|
|
7
7
|
console.error(`[forgerelay:debug] debug config: ${configDir}/config.json`);
|
|
8
|
-
console.error(`[forgerelay:debug] health: ${
|
|
8
|
+
console.error(`[forgerelay:debug] health: ${healthUrl}`);
|
|
9
9
|
console.error(`[forgerelay:debug] MCP: ${mcpUrl}`);
|
|
10
10
|
console.error(`[forgerelay:debug] Owner password loaded from ${configDir}/auth.json`);
|
|
11
11
|
console.error("[forgerelay:debug] all runtime state is under .forgerelay-debug/");
|