pi-harness-runtime 1.1.387 → 1.1.388
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/AGENTS.md +9 -4
- package/index.ts +20 -18
- package/package.json +1 -1
- package/packages/a2a-adapter/package.json +1 -1
- package/packages/agent-policy/package.json +1 -1
- package/packages/architecture-generator/package.json +1 -1
- package/packages/auth/package.json +1 -1
- package/packages/autonomous-refactor/package.json +1 -1
- package/packages/autonomous-runtime/package.json +1 -1
- package/packages/cache-strategy/package.json +1 -1
- package/packages/capability-registry/package.json +1 -1
- package/packages/checkpoint/package.json +1 -1
- package/packages/cli-plugin-sdk/package.json +1 -1
- package/packages/clipboard/package.json +1 -1
- package/packages/clipboard-plugin/package.json +1 -1
- package/packages/code-generation/package.json +1 -1
- package/packages/code-review/package.json +1 -1
- package/packages/codex-adapter/package.json +1 -1
- package/packages/codex-watcher/package.json +1 -1
- package/packages/config-capture/package.json +1 -1
- package/packages/connection-runtime/package.json +1 -1
- package/packages/context-compiler/package.json +1 -1
- package/packages/context-discovery/package.json +1 -1
- package/packages/context-manager/package.json +1 -1
- package/packages/contracts/dist/workspace-env-format.d.ts +71 -0
- package/packages/contracts/dist/workspace-env-format.js +120 -0
- package/packages/contracts/dist/workspace-env.d.ts +7 -30
- package/packages/contracts/dist/workspace-env.js +18 -57
- package/packages/contracts/package.json +1 -1
- package/packages/contracts/src/workspace-env-format.ts +165 -0
- package/packages/contracts/src/workspace-env.ts +27 -99
- package/packages/contracts/test/workspace-env.test.ts +144 -0
- package/packages/cookie-sanitizer/package.json +1 -1
- package/packages/cost-optimizer/package.json +1 -1
- package/packages/dependency-analyzer/package.json +1 -1
- package/packages/django-plugin/package.json +1 -1
- package/packages/doc-generator/package.json +1 -1
- package/packages/durable-review/package.json +1 -1
- package/packages/e2e-tester/package.json +1 -1
- package/packages/evaluation-engine/package.json +1 -1
- package/packages/evaluation-runner/package.json +1 -1
- package/packages/event-bus/package.json +1 -1
- package/packages/event-sink/package.json +1 -1
- package/packages/event-store/package.json +1 -1
- package/packages/experience-replay/package.json +1 -1
- package/packages/feedback-collector/package.json +1 -1
- package/packages/file-copy-helper/package.json +1 -1
- package/packages/framework-detector/package.json +1 -1
- package/packages/framework-plugin-sdk/package.json +1 -1
- package/packages/frappe-plugin/package.json +1 -1
- package/packages/generic-web-plugin/package.json +1 -1
- package/packages/health-monitor/package.json +1 -1
- package/packages/intent-analyzer/package.json +1 -1
- package/packages/jev-judge/package.json +1 -1
- package/packages/knowledge-graph/package.json +1 -1
- package/packages/knowledge-retrieval/package.json +1 -1
- package/packages/laravel-plugin/package.json +1 -1
- package/packages/learning-engine/package.json +1 -1
- package/packages/mcp-adapter/package.json +1 -1
- package/packages/memory-engine/package.json +1 -1
- package/packages/milestone-manager/package.json +1 -1
- package/packages/model-registry/package.json +1 -1
- package/packages/nextjs-plugin/package.json +1 -1
- package/packages/notification/package.json +1 -1
- package/packages/observability/package.json +1 -1
- package/packages/okf-indexer/package.json +1 -1
- package/packages/paperclip-integration/package.json +1 -1
- package/packages/performance-optimizer/package.json +1 -1
- package/packages/permission-mode/package.json +1 -1
- package/packages/privilege-broker/package.json +1 -1
- package/packages/project-analyzer/package.json +1 -1
- package/packages/project-bootstrap/package.json +1 -1
- package/packages/projection-engine/package.json +1 -1
- package/packages/prompt-compiler/package.json +1 -1
- package/packages/prompt-versioning/package.json +1 -1
- package/packages/provider-adapter-sdk/package.json +1 -1
- package/packages/provider-router/package.json +1 -1
- package/packages/provider-selector/package.json +1 -1
- package/packages/providers/package.json +1 -1
- package/packages/qdrant-skills/package.json +1 -1
- package/packages/quota-manager/package.json +1 -1
- package/packages/rate-limiter/package.json +1 -1
- package/packages/react-vite-plugin/package.json +1 -1
- package/packages/relay/dist/index.d.ts +3 -0
- package/packages/relay/dist/index.js +3 -0
- package/packages/relay/dist/relay-endpoint.d.ts +94 -0
- package/packages/relay/dist/relay-endpoint.js +239 -0
- package/packages/relay/package.json +1 -1
- package/packages/relay/src/index.ts +17 -0
- package/packages/relay/src/relay-endpoint.ts +304 -0
- package/packages/relay/test/relay-endpoint.test.ts +278 -0
- package/packages/release-manager/package.json +1 -1
- package/packages/requirement-compiler/package.json +1 -1
- package/packages/runtime/package.json +1 -1
- package/packages/scheduler/package.json +1 -1
- package/packages/scheduler-adapter/package.json +1 -1
- package/packages/session/package.json +1 -1
- package/packages/session-api/package.json +1 -1
- package/packages/session-export/package.json +1 -1
- package/packages/shared-context/package.json +1 -1
- package/packages/skill-mcp-client/package.json +1 -1
- package/packages/skill-registry/package.json +1 -1
- package/packages/skills/package.json +1 -1
- package/packages/sprint-planner/package.json +1 -1
- package/packages/subscription-engine/package.json +1 -1
- package/packages/task-compiler/package.json +1 -1
- package/packages/telegram/package.json +1 -1
- package/packages/tencentdb-memory/package.json +1 -1
- package/packages/tencentdb-sync/package.json +1 -1
- package/packages/test-data-generator/package.json +1 -1
- package/packages/test-generator/package.json +1 -1
- package/packages/todo-bd-sync/package.json +1 -1
- package/packages/token-estimation/package.json +1 -1
- package/packages/token-optimizer/package.json +1 -1
- package/packages/trajectory/package.json +1 -1
- package/packages/tui/package.json +1 -1
- package/packages/tui/test/harness-footer.test.ts +1 -1
- package/packages/types/package.json +1 -1
- package/packages/voice-api/package.json +1 -1
- package/packages/webmcp-tester/package.json +1 -1
- package/packages/wiki/package.json +1 -1
- package/packages/workflow-events/package.json +1 -1
- package/packages/workspace-scanner/package.json +1 -1
- package/packages/worktree/package.json +1 -1
- package/packages/write-review/package.json +1 -1
- package/scripts/relay-client.ts +24 -4
- package/scripts/unified-webhook-server.ts +29 -22
package/AGENTS.md
CHANGED
|
@@ -502,16 +502,21 @@ bun run build && bun run start # Server deployment
|
|
|
502
502
|
|
|
503
503
|
**This info is shown in UI and delivered to agent context:**
|
|
504
504
|
```
|
|
505
|
-
Workspace:
|
|
505
|
+
Workspace: DEVELOPMENT | dev server: running | build: not running (script available) | RAM: 10/16
|
|
506
506
|
```
|
|
507
507
|
|
|
508
|
+
The mode words are exactly what the detector emits: `DEVELOPMENT`, `PRODUCTION`,
|
|
509
|
+
`TEST` or `UNKNOWN` (with its reason, e.g. `UNKNOWN (no explicit NODE_ENV)`).
|
|
510
|
+
A dev/build script is a CAPABILITY, not a state: `not running (script available)`
|
|
511
|
+
means the script exists, not that a server runs.
|
|
512
|
+
|
|
508
513
|
**IMPORTANT Rules:**
|
|
509
514
|
|
|
510
515
|
| State | Action |
|
|
511
516
|
|-------|--------|
|
|
512
|
-
| `Workspace: UNKNOWN` | Explicitly ask user before build |
|
|
513
|
-
| `Workspace:
|
|
514
|
-
| `Workspace:
|
|
517
|
+
| `Workspace: UNKNOWN (…)` | Explicitly ask user before build |
|
|
518
|
+
| `Workspace: DEVELOPMENT` | Use `dev` mode, don't auto-build |
|
|
519
|
+
| `Workspace: PRODUCTION` | Build allowed, but confirm with user |
|
|
515
520
|
| `Low RAM` | Never run parallel build + dev |
|
|
516
521
|
| `Dev server running` | Reuse it, don't restart |
|
|
517
522
|
|
package/index.ts
CHANGED
|
@@ -58,6 +58,7 @@ import { aggregateWindows } from "./windows.ts";
|
|
|
58
58
|
// Relay client for streaming callbacks (t3code-style two-way communication)
|
|
59
59
|
import { RelayClient } from "./packages/relay/src/client.js";
|
|
60
60
|
import type { CallbackPayload } from "./packages/relay/src/types.js";
|
|
61
|
+
import { describeRelayEndpoint, resolveRelayEndpoint } from "./packages/relay/src/relay-endpoint.js";
|
|
61
62
|
import { renderStatus } from "./renderer.ts";
|
|
62
63
|
import {
|
|
63
64
|
JobStateMachine,
|
|
@@ -1559,32 +1560,33 @@ function setRelayTelegramAdapter(adapter: any) {
|
|
|
1559
1560
|
* to the adapter for proper greeting verification and handling.
|
|
1560
1561
|
*/
|
|
1561
1562
|
async function initRelayStream(): Promise<void> {
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
// Check for relay WebSocket URL
|
|
1566
|
-
const relayWsUrlPath = join(keysDir, "relay-ws-url.txt");
|
|
1567
|
-
const relayTokenPath = join(keysDir, "relay-auth-token.txt");
|
|
1563
|
+
// Use the OS home directory - the relay server resolves its key files
|
|
1564
|
+
// the same way, so both sides always look in the same place.
|
|
1565
|
+
const keysDir = join(homedir(), ".pi-harness-runtime", "keys");
|
|
1568
1566
|
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1567
|
+
// Resolve the relay endpoint from the SAME sources the relay server uses
|
|
1568
|
+
// (env -> dedicated key file -> the telegram webhook url/secret), so the
|
|
1569
|
+
// client and the server always agree on the URL and the token.
|
|
1570
|
+
// The token value is never logged - only the source it came from.
|
|
1571
|
+
const endpoint = resolveRelayEndpoint({ keysDir });
|
|
1573
1572
|
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1573
|
+
if (!endpoint.url || !endpoint.token) {
|
|
1574
|
+
logToFile(
|
|
1575
|
+
"[RelayStream]",
|
|
1576
|
+
`Relay endpoint not configured - skipping streaming (${endpoint.missing.join("; ")})`,
|
|
1577
|
+
);
|
|
1579
1578
|
return;
|
|
1580
1579
|
}
|
|
1581
1580
|
|
|
1582
|
-
logToFile(
|
|
1581
|
+
logToFile(
|
|
1582
|
+
"[RelayStream]",
|
|
1583
|
+
`Connecting to relay at ${endpoint.url} (${describeRelayEndpoint(endpoint)})`,
|
|
1584
|
+
);
|
|
1583
1585
|
|
|
1584
1586
|
_relayClient = new RelayClient(
|
|
1585
1587
|
{
|
|
1586
|
-
serverUrl:
|
|
1587
|
-
token:
|
|
1588
|
+
serverUrl: endpoint.url,
|
|
1589
|
+
token: endpoint.token,
|
|
1588
1590
|
// Keep retrying in the background: the relay server may not be up
|
|
1589
1591
|
// yet when the harness starts.
|
|
1590
1592
|
retryOnConnectFailure: true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-harness/capability-registry",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.388",
|
|
4
4
|
"description": "Capability Registry for pi-harness-runtime — tracks model capabilities and enables capability-based routing",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace environment formatting helpers.
|
|
3
|
+
*
|
|
4
|
+
* Split out of workspace-env.ts so the wording can be unit tested without the
|
|
5
|
+
* node:sqlite dependency (bun 1.3.x has no node:sqlite module).
|
|
6
|
+
*
|
|
7
|
+
* Wording rules:
|
|
8
|
+
* - The mode is only reported when it is EXPLICIT (NODE_ENV). An unknown mode
|
|
9
|
+
* is always shown with its reason, never as a bare word next to a dev
|
|
10
|
+
* server state that could be read as proof of the mode.
|
|
11
|
+
* - A dev/build script is a CAPABILITY, not a state. The status line says
|
|
12
|
+
* "not running (script available)" so it cannot be mistaken for a running
|
|
13
|
+
* server or for evidence about the workspace mode.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Workspace mode with explicit states
|
|
17
|
+
*/
|
|
18
|
+
export type WorkspaceMode = "development" | "production" | "test" | "unknown";
|
|
19
|
+
/**
|
|
20
|
+
* Evidence source for mode detection
|
|
21
|
+
*/
|
|
22
|
+
export interface EnvEvidence {
|
|
23
|
+
source: "process.env" | ".env file" | "package.json" | "command" | "detection";
|
|
24
|
+
key: string;
|
|
25
|
+
value: string;
|
|
26
|
+
timestamp: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Workspace environment result
|
|
30
|
+
*/
|
|
31
|
+
export interface WorkspaceEnvResult {
|
|
32
|
+
workspacePath: string;
|
|
33
|
+
mode: WorkspaceMode;
|
|
34
|
+
evidence: EnvEvidence[];
|
|
35
|
+
hasDevScript: boolean;
|
|
36
|
+
hasBuildScript: boolean;
|
|
37
|
+
packageManager: string | null;
|
|
38
|
+
devServerRunning: boolean;
|
|
39
|
+
buildServerRunning: boolean;
|
|
40
|
+
ramTotalGb: number | null;
|
|
41
|
+
ramAvailableGb: number | null;
|
|
42
|
+
ramEffectiveLimitGb: number | null;
|
|
43
|
+
lowRamWarning: boolean;
|
|
44
|
+
buildAllowed: boolean;
|
|
45
|
+
detectedAt: number;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Human readable mode label.
|
|
49
|
+
*
|
|
50
|
+
* "unknown" always carries the reason: the mode can only be proven by an
|
|
51
|
+
* explicit NODE_ENV (process env or .env file). When a NODE_ENV IS present
|
|
52
|
+
* but names a mode this detector does not know ("staging"), the label says
|
|
53
|
+
* exactly that instead of claiming there is no NODE_ENV at all.
|
|
54
|
+
*/
|
|
55
|
+
export declare function describeWorkspaceMode(env: WorkspaceEnvResult): string;
|
|
56
|
+
/**
|
|
57
|
+
* Describe a dev/build server as a state.
|
|
58
|
+
*
|
|
59
|
+
* "not running (script available)" means the script EXISTS, i.e. a server
|
|
60
|
+
* could be started. It is not evidence that a server is running and not
|
|
61
|
+
* evidence about the workspace mode.
|
|
62
|
+
*/
|
|
63
|
+
export declare function describeServerState(running: boolean, hasScript: boolean): string;
|
|
64
|
+
/**
|
|
65
|
+
* One line status for the footer / status bar.
|
|
66
|
+
*/
|
|
67
|
+
export declare function formatEnvStatusLine(env: WorkspaceEnvResult): string;
|
|
68
|
+
/**
|
|
69
|
+
* Multi line description for the agent context.
|
|
70
|
+
*/
|
|
71
|
+
export declare function formatEnvForAgentResult(env: WorkspaceEnvResult): string;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace environment formatting helpers.
|
|
3
|
+
*
|
|
4
|
+
* Split out of workspace-env.ts so the wording can be unit tested without the
|
|
5
|
+
* node:sqlite dependency (bun 1.3.x has no node:sqlite module).
|
|
6
|
+
*
|
|
7
|
+
* Wording rules:
|
|
8
|
+
* - The mode is only reported when it is EXPLICIT (NODE_ENV). An unknown mode
|
|
9
|
+
* is always shown with its reason, never as a bare word next to a dev
|
|
10
|
+
* server state that could be read as proof of the mode.
|
|
11
|
+
* - A dev/build script is a CAPABILITY, not a state. The status line says
|
|
12
|
+
* "not running (script available)" so it cannot be mistaken for a running
|
|
13
|
+
* server or for evidence about the workspace mode.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Human readable mode label.
|
|
17
|
+
*
|
|
18
|
+
* "unknown" always carries the reason: the mode can only be proven by an
|
|
19
|
+
* explicit NODE_ENV (process env or .env file). When a NODE_ENV IS present
|
|
20
|
+
* but names a mode this detector does not know ("staging"), the label says
|
|
21
|
+
* exactly that instead of claiming there is no NODE_ENV at all.
|
|
22
|
+
*/
|
|
23
|
+
export function describeWorkspaceMode(env) {
|
|
24
|
+
if (env.mode !== "unknown") {
|
|
25
|
+
return env.mode.toUpperCase();
|
|
26
|
+
}
|
|
27
|
+
const nodeEnv = env.evidence.find((e) => e.key === "NODE_ENV" && (e.source === "process.env" || e.source === ".env file"));
|
|
28
|
+
if (nodeEnv) {
|
|
29
|
+
return `UNKNOWN (NODE_ENV=${nodeEnv.value} is not a known mode)`;
|
|
30
|
+
}
|
|
31
|
+
return "UNKNOWN (no explicit NODE_ENV)";
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Describe a dev/build server as a state.
|
|
35
|
+
*
|
|
36
|
+
* "not running (script available)" means the script EXISTS, i.e. a server
|
|
37
|
+
* could be started. It is not evidence that a server is running and not
|
|
38
|
+
* evidence about the workspace mode.
|
|
39
|
+
*/
|
|
40
|
+
export function describeServerState(running, hasScript) {
|
|
41
|
+
if (running)
|
|
42
|
+
return "running";
|
|
43
|
+
if (hasScript)
|
|
44
|
+
return "not running (script available)";
|
|
45
|
+
return "no script";
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* One line status for the footer / status bar.
|
|
49
|
+
*/
|
|
50
|
+
export function formatEnvStatusLine(env) {
|
|
51
|
+
const mode = describeWorkspaceMode(env);
|
|
52
|
+
const devStatus = describeServerState(env.devServerRunning, env.hasDevScript);
|
|
53
|
+
const buildStatus = describeServerState(env.buildServerRunning, env.hasBuildScript);
|
|
54
|
+
let status = `Workspace: ${mode} | dev server: ${devStatus} | build: ${buildStatus}`;
|
|
55
|
+
const ramStr = formatRam(env);
|
|
56
|
+
if (ramStr) {
|
|
57
|
+
status += ` | RAM: ${ramStr}`;
|
|
58
|
+
}
|
|
59
|
+
return status;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* RAM segment of the status line.
|
|
63
|
+
*
|
|
64
|
+
* Both values are optional - an unreadable /proc must never produce a
|
|
65
|
+
* "7.7/null" line.
|
|
66
|
+
*/
|
|
67
|
+
function formatRam(env) {
|
|
68
|
+
const total = env.ramTotalGb;
|
|
69
|
+
const available = env.ramAvailableGb;
|
|
70
|
+
if (total === null && available === null)
|
|
71
|
+
return "";
|
|
72
|
+
if (total === null)
|
|
73
|
+
return `${available}GB available`;
|
|
74
|
+
if (available === null)
|
|
75
|
+
return `${total}GB total`;
|
|
76
|
+
return `${available}/${total}`;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* RAM segment for the agent block.
|
|
80
|
+
*/
|
|
81
|
+
function formatRamForAgent(env) {
|
|
82
|
+
const total = env.ramTotalGb;
|
|
83
|
+
const available = env.ramAvailableGb;
|
|
84
|
+
if (total !== null && available !== null)
|
|
85
|
+
return `${available}/${total}GB available`;
|
|
86
|
+
if (total !== null)
|
|
87
|
+
return `${total}GB total`;
|
|
88
|
+
return `${available}GB available`;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Multi line description for the agent context.
|
|
92
|
+
*/
|
|
93
|
+
export function formatEnvForAgentResult(env) {
|
|
94
|
+
let message = `[Workspace Environment]\n`;
|
|
95
|
+
message += `Mode: ${describeWorkspaceMode(env)}\n`;
|
|
96
|
+
if (env.evidence.length > 0) {
|
|
97
|
+
const sources = env.evidence.map((e) => `${e.source}:${e.value}`).join(", ");
|
|
98
|
+
message += `Evidence: ${sources}\n`;
|
|
99
|
+
}
|
|
100
|
+
message += `Dev script: ${env.hasDevScript ? "yes" : "no"}\n`;
|
|
101
|
+
message += `Build script: ${env.hasBuildScript ? "yes" : "no"}\n`;
|
|
102
|
+
if (env.devServerRunning) {
|
|
103
|
+
message += `Dev server: running\n`;
|
|
104
|
+
}
|
|
105
|
+
if (env.buildServerRunning) {
|
|
106
|
+
message += `Build server: running\n`;
|
|
107
|
+
}
|
|
108
|
+
if (env.ramTotalGb !== null || env.ramAvailableGb !== null) {
|
|
109
|
+
message += `RAM: ${formatRamForAgent(env)}\n`;
|
|
110
|
+
if (env.lowRamWarning) {
|
|
111
|
+
message += `WARNING: Low RAM - avoid parallel build + dev\n`;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
message += `\n`;
|
|
115
|
+
message += `Build allowed: ${env.buildAllowed ? "yes" : "no - requires explicit request"}\n`;
|
|
116
|
+
if (env.mode === "unknown") {
|
|
117
|
+
message += `\nNOTE: Environment unknown - a dev/build script only means a server CAN be started, it does not establish the workspace mode. Explicitly ask the user before build.\n`;
|
|
118
|
+
}
|
|
119
|
+
return message;
|
|
120
|
+
}
|
|
@@ -9,38 +9,15 @@
|
|
|
9
9
|
* Stores detected environment in SQLite for agent reference.
|
|
10
10
|
* Uses synchronous directory creation and exception-safe operations.
|
|
11
11
|
*/
|
|
12
|
+
import { describeServerState, describeWorkspaceMode, formatEnvForAgentResult } from "./workspace-env-format.js";
|
|
13
|
+
import type { EnvEvidence, WorkspaceEnvResult, WorkspaceMode } from "./workspace-env-format.js";
|
|
12
14
|
/**
|
|
13
|
-
*
|
|
15
|
+
* The mode/evidence types and every human readable rendering of the workspace
|
|
16
|
+
* environment live in workspace-env-format.ts. They are re-exported here so
|
|
17
|
+
* the existing import paths keep working.
|
|
14
18
|
*/
|
|
15
|
-
export
|
|
16
|
-
|
|
17
|
-
* Evidence source for mode detection
|
|
18
|
-
*/
|
|
19
|
-
export interface EnvEvidence {
|
|
20
|
-
source: "process.env" | ".env file" | "package.json" | "command" | "detection";
|
|
21
|
-
key: string;
|
|
22
|
-
value: string;
|
|
23
|
-
timestamp: number;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Workspace environment result
|
|
27
|
-
*/
|
|
28
|
-
export interface WorkspaceEnvResult {
|
|
29
|
-
workspacePath: string;
|
|
30
|
-
mode: WorkspaceMode;
|
|
31
|
-
evidence: EnvEvidence[];
|
|
32
|
-
hasDevScript: boolean;
|
|
33
|
-
hasBuildScript: boolean;
|
|
34
|
-
packageManager: string | null;
|
|
35
|
-
devServerRunning: boolean;
|
|
36
|
-
buildServerRunning: boolean;
|
|
37
|
-
ramTotalGb: number | null;
|
|
38
|
-
ramAvailableGb: number | null;
|
|
39
|
-
ramEffectiveLimitGb: number | null;
|
|
40
|
-
lowRamWarning: boolean;
|
|
41
|
-
buildAllowed: boolean;
|
|
42
|
-
detectedAt: number;
|
|
43
|
-
}
|
|
19
|
+
export { describeServerState, describeWorkspaceMode, formatEnvForAgentResult, };
|
|
20
|
+
export type { EnvEvidence, WorkspaceEnvResult, WorkspaceMode };
|
|
44
21
|
/**
|
|
45
22
|
* Detect and store workspace environment
|
|
46
23
|
*/
|
|
@@ -13,6 +13,7 @@ import { DatabaseSync } from "node:sqlite";
|
|
|
13
13
|
import { existsSync, readFileSync, mkdirSync } from "fs";
|
|
14
14
|
import { join } from "path";
|
|
15
15
|
import { platform, totalmem, freemem } from "os";
|
|
16
|
+
import { describeServerState, describeWorkspaceMode, formatEnvForAgentResult, formatEnvStatusLine as formatStatusLine, } from "./workspace-env-format.js";
|
|
16
17
|
const STORE_DIR = join(process.env.HOME || "/home/frappe", ".pi-harness-runtime");
|
|
17
18
|
/**
|
|
18
19
|
* Ensure store directory exists synchronously
|
|
@@ -56,6 +57,12 @@ function initDatabase() {
|
|
|
56
57
|
`);
|
|
57
58
|
return db;
|
|
58
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* The mode/evidence types and every human readable rendering of the workspace
|
|
62
|
+
* environment live in workspace-env-format.ts. They are re-exported here so
|
|
63
|
+
* the existing import paths keep working.
|
|
64
|
+
*/
|
|
65
|
+
export { describeServerState, describeWorkspaceMode, formatEnvForAgentResult, };
|
|
59
66
|
/**
|
|
60
67
|
* Parse dotenv file without loading secrets
|
|
61
68
|
* Returns only NODE_ENV value, ignoring comments and other vars
|
|
@@ -143,31 +150,22 @@ function determineMode(processEnv, dotenvNodeEnv, evidence) {
|
|
|
143
150
|
// Explicit process.env takes highest priority (for build processes)
|
|
144
151
|
if (processEnv) {
|
|
145
152
|
const env = processEnv.toLowerCase();
|
|
153
|
+
// The evidence is recorded for EVERY value, including one that names
|
|
154
|
+
// no known mode ("staging"): the label then says which NODE_ENV could
|
|
155
|
+
// not be interpreted instead of claiming there is none.
|
|
156
|
+
evidence.push({
|
|
157
|
+
source: "process.env",
|
|
158
|
+
key: "NODE_ENV",
|
|
159
|
+
value: env,
|
|
160
|
+
timestamp: Date.now(),
|
|
161
|
+
});
|
|
146
162
|
if (env === "production") {
|
|
147
|
-
evidence.push({
|
|
148
|
-
source: "process.env",
|
|
149
|
-
key: "NODE_ENV",
|
|
150
|
-
value: env,
|
|
151
|
-
timestamp: Date.now(),
|
|
152
|
-
});
|
|
153
163
|
return "production";
|
|
154
164
|
}
|
|
155
165
|
if (env === "development" || env === "dev") {
|
|
156
|
-
evidence.push({
|
|
157
|
-
source: "process.env",
|
|
158
|
-
key: "NODE_ENV",
|
|
159
|
-
value: env,
|
|
160
|
-
timestamp: Date.now(),
|
|
161
|
-
});
|
|
162
166
|
return "development";
|
|
163
167
|
}
|
|
164
168
|
if (env === "test") {
|
|
165
|
-
evidence.push({
|
|
166
|
-
source: "process.env",
|
|
167
|
-
key: "NODE_ENV",
|
|
168
|
-
value: env,
|
|
169
|
-
timestamp: Date.now(),
|
|
170
|
-
});
|
|
171
169
|
return "test";
|
|
172
170
|
}
|
|
173
171
|
}
|
|
@@ -385,48 +383,11 @@ export function revalidateWorkspaceEnv(workspacePath) {
|
|
|
385
383
|
* Format workspace env as agent-readable message
|
|
386
384
|
*/
|
|
387
385
|
export function formatEnvForAgent(workspacePath) {
|
|
388
|
-
|
|
389
|
-
let message = `[Workspace Environment]\n`;
|
|
390
|
-
message += `Mode: ${env.mode.toUpperCase()}\n`;
|
|
391
|
-
if (env.evidence.length > 0) {
|
|
392
|
-
const sources = env.evidence.map((e) => `${e.source}:${e.value}`).join(", ");
|
|
393
|
-
message += `Evidence: ${sources}\n`;
|
|
394
|
-
}
|
|
395
|
-
message += `Dev script: ${env.hasDevScript ? "yes" : "no"}\n`;
|
|
396
|
-
message += `Build script: ${env.hasBuildScript ? "yes" : "no"}\n`;
|
|
397
|
-
if (env.devServerRunning) {
|
|
398
|
-
message += `Dev server: running\n`;
|
|
399
|
-
}
|
|
400
|
-
if (env.buildServerRunning) {
|
|
401
|
-
message += `Build server: running\n`;
|
|
402
|
-
}
|
|
403
|
-
if (env.ramTotalGb !== null) {
|
|
404
|
-
const ramStr = env.ramAvailableGb !== null
|
|
405
|
-
? `${env.ramAvailableGb}/${env.ramTotalGb}GB available`
|
|
406
|
-
: `${env.ramTotalGb}GB total`;
|
|
407
|
-
message += `RAM: ${ramStr}\n`;
|
|
408
|
-
if (env.lowRamWarning) {
|
|
409
|
-
message += `WARNING: Low RAM - avoid parallel build + dev\n`;
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
message += `\n`;
|
|
413
|
-
message += `Build allowed: ${env.buildAllowed ? "yes" : "no - requires explicit request"}\n`;
|
|
414
|
-
if (env.mode === "unknown") {
|
|
415
|
-
message += `\nNOTE: Environment unknown. Explicitly ask user before build.\n`;
|
|
416
|
-
}
|
|
417
|
-
return message;
|
|
386
|
+
return formatEnvForAgentResult(getWorkspaceEnv(workspacePath));
|
|
418
387
|
}
|
|
419
388
|
/**
|
|
420
389
|
* Format workspace env as compact status line for UI
|
|
421
390
|
*/
|
|
422
391
|
export function formatEnvStatusLine(env) {
|
|
423
|
-
|
|
424
|
-
const devStatus = env.devServerRunning ? "running" : (env.hasDevScript ? "available" : "none");
|
|
425
|
-
const buildStatus = env.buildServerRunning ? "running" : (env.hasBuildScript ? "explicit request" : "none");
|
|
426
|
-
const ramStr = env.ramAvailableGb !== null ? `${env.ramAvailableGb}/${env.ramTotalGb}` : "";
|
|
427
|
-
let status = `Workspace: ${mode} | dev server: ${devStatus} | build: ${buildStatus}`;
|
|
428
|
-
if (ramStr) {
|
|
429
|
-
status += ` | RAM: ${ramStr}`;
|
|
430
|
-
}
|
|
431
|
-
return status;
|
|
392
|
+
return formatStatusLine(env);
|
|
432
393
|
}
|