@principles/host-runtime 0.8.2 → 0.9.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/LICENSE +73 -0
- package/NOTICE +2 -0
- package/dist/governance-signal-admission.d.ts +63 -0
- package/dist/governance-signal-admission.js +322 -53
- package/dist/host-liveness-contract.js +7 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -1
- package/dist/internalization-consumer-cycle.d.ts +12 -0
- package/dist/internalization-consumer-cycle.js +43 -1
- package/dist/intervention-evidence-ingress.d.ts +1 -1
- package/dist/product-telemetry/service.js +1 -1
- package/dist/production-pain-evidence.d.ts +59 -1
- package/dist/production-pain-evidence.js +200 -17
- package/dist/prompt-activation-deliverability.js +5 -4
- package/dist/prompt-injection-event-evidence.d.ts +1 -1
- package/dist/prompt-injection-event-evidence.js +5 -1
- package/dist/prompt-injection-projection.d.ts +14 -5
- package/dist/prompt-injection-projection.js +30 -16
- package/dist/workbuddy-worker-status.d.ts +24 -0
- package/dist/workbuddy-worker-status.js +52 -0
- package/package.json +9 -7
|
@@ -3,24 +3,32 @@ import { escapeXml } from '@principles/core/prompt-builder';
|
|
|
3
3
|
import { loadPdConfigForPlugin } from './pd-config.js';
|
|
4
4
|
import { buildActivePrinciplePromptContext, readPromptActivationCandidates, MAX_SHARED_DIAGNOSTIC_IDS } from './active-principle-prompt.js';
|
|
5
5
|
import { readWorkspaceHostKindFacts } from './host-liveness-contract.js';
|
|
6
|
-
|
|
6
|
+
/** Single host roster (review P2): every consumer derives from this list, so a
|
|
7
|
+
* new host cannot fork route-unconfirmed per-host forecasts from the routes. */
|
|
8
|
+
export const PROMPT_INJECTION_TARGET_HOSTS = ['openclaw', 'codex', 'workbuddy'];
|
|
9
|
+
/** Runtime membership test derived from the roster (rc-2): the ONE guard for
|
|
10
|
+
* "is this untrusted host-kind string a host with a known prompt-injection
|
|
11
|
+
* route". Every consumer narrows with this — never by re-typing the literals
|
|
12
|
+
* (review R1: each re-typed list forked the roster and dropped WorkBuddy). */
|
|
13
|
+
export function isPromptInjectionTargetHost(kind) {
|
|
14
|
+
return typeof kind === 'string' && PROMPT_INJECTION_TARGET_HOSTS.includes(kind);
|
|
15
|
+
}
|
|
7
16
|
export const PROMPT_INJECTION_UNIT = 'utf16_code_units';
|
|
8
17
|
/**
|
|
9
18
|
* THE one route formula (P4): Codex always injects through the shared route
|
|
10
|
-
* (codex-adapter has no flag branch);
|
|
11
|
-
*
|
|
12
|
-
*
|
|
19
|
+
* (codex-adapter has no flag branch); so does WorkBuddy (workbuddy-adapter
|
|
20
|
+
* renders through the shared runtime unconditionally — it has no legacy
|
|
21
|
+
* route); OpenClaw routes by its `abstraction_layer_v1` gate. Every consumer
|
|
22
|
+
* that needs "which route would host X take" must call this — never re-type
|
|
23
|
+
* the ternary.
|
|
13
24
|
*/
|
|
14
25
|
export function promptRouteForHost(hostKind, flagEnabled) {
|
|
15
|
-
if (hostKind === 'codex')
|
|
26
|
+
if (hostKind === 'codex' || hostKind === 'workbuddy')
|
|
16
27
|
return 'shared_render';
|
|
17
28
|
return flagEnabled ? 'shared_render' : 'legacy_trim';
|
|
18
29
|
}
|
|
19
30
|
function standardHostRoutes(flagEnabled) {
|
|
20
|
-
return
|
|
21
|
-
{ hostKind: 'openclaw', route: promptRouteForHost('openclaw', flagEnabled) },
|
|
22
|
-
{ hostKind: 'codex', route: promptRouteForHost('codex', flagEnabled) },
|
|
23
|
-
];
|
|
31
|
+
return PROMPT_INJECTION_TARGET_HOSTS.map((hostKind) => ({ hostKind, route: promptRouteForHost(hostKind, flagEnabled) }));
|
|
24
32
|
}
|
|
25
33
|
/**
|
|
26
34
|
* Resolve the effective route for this workspace. Pure read of existing
|
|
@@ -83,8 +91,8 @@ export function resolvePromptInjectionRouteDecision(input) {
|
|
|
83
91
|
perHost: standardHostRoutes(flagEnabled),
|
|
84
92
|
};
|
|
85
93
|
}
|
|
86
|
-
const knownKinds = facts.effectiveKinds.filter(
|
|
87
|
-
const unknownKinds = facts.effectiveKinds.filter((kind) => kind
|
|
94
|
+
const knownKinds = facts.effectiveKinds.filter(isPromptInjectionTargetHost);
|
|
95
|
+
const unknownKinds = facts.effectiveKinds.filter((kind) => !isPromptInjectionTargetHost(kind));
|
|
88
96
|
if (unknownKinds.length > 0) {
|
|
89
97
|
return {
|
|
90
98
|
status: 'unconfirmed',
|
|
@@ -92,7 +100,7 @@ export function resolvePromptInjectionRouteDecision(input) {
|
|
|
92
100
|
declaredHostKinds: facts.declaredKinds,
|
|
93
101
|
effectiveHostKinds: facts.effectiveKinds,
|
|
94
102
|
unconfirmedReason: `unknown_host_kind_declared: ${unknownKinds.join(', ')} has no known prompt-injection route`,
|
|
95
|
-
nextAction: 'pass an explicit target host (openclaw|codex) for this request, or remove the unknown host declaration',
|
|
103
|
+
nextAction: 'pass an explicit target host (openclaw|codex|workbuddy) for this request, or remove the unknown host declaration',
|
|
96
104
|
perHost: standardHostRoutes(flagEnabled),
|
|
97
105
|
};
|
|
98
106
|
}
|
|
@@ -117,7 +125,7 @@ export function resolvePromptInjectionRouteDecision(input) {
|
|
|
117
125
|
declaredHostKinds: facts.declaredKinds,
|
|
118
126
|
effectiveHostKinds: facts.effectiveKinds,
|
|
119
127
|
unconfirmedReason: 'no_host_facts_and_flag_off: no host declaration or host evidence exists, and the applicable hosts would take different routes',
|
|
120
|
-
nextAction: 'pass an explicit target host (openclaw|codex), or let a host run once in this workspace so it persists its declaration',
|
|
128
|
+
nextAction: 'pass an explicit target host (openclaw|codex|workbuddy), or let a host run once in this workspace so it persists its declaration',
|
|
121
129
|
perHost: standardHostRoutes(flagEnabled),
|
|
122
130
|
};
|
|
123
131
|
}
|
|
@@ -151,8 +159,8 @@ export function resolvePromptInjectionRouteDecision(input) {
|
|
|
151
159
|
flagEnabled,
|
|
152
160
|
declaredHostKinds: facts.declaredKinds,
|
|
153
161
|
effectiveHostKinds: facts.effectiveKinds,
|
|
154
|
-
unconfirmedReason: 'multi_host_routes_differ: openclaw would take the legacy list route
|
|
155
|
-
nextAction: 'pass an explicit target host (openclaw|codex) for this request, or enable abstraction_layer_v1 so
|
|
162
|
+
unconfirmedReason: 'multi_host_routes_differ: openclaw would take the legacy list route while codex/workbuddy would take the shared route under the current flag-off config',
|
|
163
|
+
nextAction: 'pass an explicit target host (openclaw|codex|workbuddy) for this request, or enable abstraction_layer_v1 so all hosts share one route',
|
|
156
164
|
perHost: standardHostRoutes(flagEnabled),
|
|
157
165
|
};
|
|
158
166
|
}
|
|
@@ -216,7 +224,13 @@ function isDiagnosticCapHit(ids) {
|
|
|
216
224
|
*/
|
|
217
225
|
export async function buildLivePromptInjectionProjection(input) {
|
|
218
226
|
const flagEnabled = computeFeatureFlagsFromConfig(loadPdConfigForPlugin(input.workspaceDir).effective).flags.abstraction_layer_v1?.enabled === true;
|
|
219
|
-
|
|
227
|
+
// Route face follows THE one route formula (review P2-2: a re-typed
|
|
228
|
+
// codex-only ternary forecast WorkBuddy as legacy_trim while its adapter
|
|
229
|
+
// renders shared unconditionally). No explicit target (console callers)
|
|
230
|
+
// keeps the flag-gated workspace default.
|
|
231
|
+
const sharedRoute = input.targetHost === undefined
|
|
232
|
+
? flagEnabled
|
|
233
|
+
: promptRouteForHost(input.targetHost, flagEnabled) === 'shared_render';
|
|
220
234
|
if (sharedRoute) {
|
|
221
235
|
const context = await buildActivePrinciplePromptContext(input);
|
|
222
236
|
const oversized = context.oversizedActivationIds ?? [];
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorkBuddy worker status-mode semantics — host-runtime authority (mirrors
|
|
3
|
+
* the Codex Slice D placement): the CLI worker --status and any health
|
|
4
|
+
* surface share ONE mode evaluation, which only depends on host-neutral
|
|
5
|
+
* inputs (governance workspace directory, .pd/config.yaml flags, install
|
|
6
|
+
* manifest registration). The WorkBuddy evaluation has NO ingestion step to
|
|
7
|
+
* gate — the hook is the only evidence producer in the WorkBuddy MVP
|
|
8
|
+
* (SPEC workbuddy-host-adapter §1 Excluded: no transcript reads).
|
|
9
|
+
*
|
|
10
|
+
* SPEC §15 worker mode, evaluated WITHOUT executing anything (no lease, no
|
|
11
|
+
* LLM). `manual_action_required` means no Companion-registered worker serves
|
|
12
|
+
* this governance workspace — manual `pd diagnose` / `pd runtime
|
|
13
|
+
* internalization run-once` is the recovery route.
|
|
14
|
+
*/
|
|
15
|
+
export type WorkbuddyWorkerMode = 'ready' | 'manual_action_required' | 'paused' | 'degraded';
|
|
16
|
+
export interface WorkbuddyWorkerStatusEvaluation {
|
|
17
|
+
readonly mode: WorkbuddyWorkerMode;
|
|
18
|
+
readonly reason?: string;
|
|
19
|
+
readonly nextAction?: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function computeWorkbuddyWorkerStatusMode(input: {
|
|
22
|
+
workspaceDir: string;
|
|
23
|
+
registeredInInstallManifest: boolean;
|
|
24
|
+
}): WorkbuddyWorkerStatusEvaluation;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WorkBuddy worker status-mode semantics — host-runtime authority (mirrors
|
|
3
|
+
* the Codex Slice D placement): the CLI worker --status and any health
|
|
4
|
+
* surface share ONE mode evaluation, which only depends on host-neutral
|
|
5
|
+
* inputs (governance workspace directory, .pd/config.yaml flags, install
|
|
6
|
+
* manifest registration). The WorkBuddy evaluation has NO ingestion step to
|
|
7
|
+
* gate — the hook is the only evidence producer in the WorkBuddy MVP
|
|
8
|
+
* (SPEC workbuddy-host-adapter §1 Excluded: no transcript reads).
|
|
9
|
+
*
|
|
10
|
+
* SPEC §15 worker mode, evaluated WITHOUT executing anything (no lease, no
|
|
11
|
+
* LLM). `manual_action_required` means no Companion-registered worker serves
|
|
12
|
+
* this governance workspace — manual `pd diagnose` / `pd runtime
|
|
13
|
+
* internalization run-once` is the recovery route.
|
|
14
|
+
*/
|
|
15
|
+
import * as fs from 'node:fs';
|
|
16
|
+
import * as path from 'node:path';
|
|
17
|
+
import { loadPdConfigForPlugin } from './pd-config.js';
|
|
18
|
+
import { computeFeatureFlagsFromConfig } from '@principles/core/runtime-v2';
|
|
19
|
+
function directoryExists(dir) {
|
|
20
|
+
try {
|
|
21
|
+
return fs.statSync(dir).isDirectory();
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function computeWorkbuddyWorkerStatusMode(input) {
|
|
28
|
+
const workspaceDir = path.resolve(input.workspaceDir);
|
|
29
|
+
if (!directoryExists(workspaceDir)) {
|
|
30
|
+
return { mode: 'degraded', reason: 'workspace_missing', nextAction: 'The governance workspace directory does not exist; run the WorkBuddy setup flow to initialize it.' };
|
|
31
|
+
}
|
|
32
|
+
const config = loadPdConfigForPlugin(workspaceDir);
|
|
33
|
+
if (!config.ok) {
|
|
34
|
+
const [first] = config.errors;
|
|
35
|
+
return { mode: 'degraded', reason: `pd_config_invalid:${first?.reason ?? 'unknown'}`, nextAction: first?.nextAction ?? 'Repair the governance workspace .pd/config.yaml.' };
|
|
36
|
+
}
|
|
37
|
+
const { flags } = computeFeatureFlagsFromConfig(config.effective);
|
|
38
|
+
if (flags['host.workbuddy']?.enabled !== true) {
|
|
39
|
+
return { mode: 'paused', reason: 'host.workbuddy_disabled', nextAction: 'Set features.host.workbuddy.enabled=true in the governance workspace .pd/config.yaml to enable WorkBuddy PD behavior.' };
|
|
40
|
+
}
|
|
41
|
+
if (flags.internalization_auto_consumer?.enabled !== true) {
|
|
42
|
+
return { mode: 'paused', reason: 'internalization_auto_consumer_disabled', nextAction: 'Automatic execution is paused; manual commands remain available: pd diagnose, pd runtime internalization run-once.' };
|
|
43
|
+
}
|
|
44
|
+
if (!input.registeredInInstallManifest) {
|
|
45
|
+
return {
|
|
46
|
+
mode: 'manual_action_required',
|
|
47
|
+
reason: 'workspace_not_in_install_manifest',
|
|
48
|
+
nextAction: `No Companion worker is registered for this governance workspace. Manual path: pd diagnose --workspace "${workspaceDir}", then pd runtime internalization run-once.`,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
return { mode: 'ready' };
|
|
52
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@principles/host-runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "Shared host-neutral orchestration for Principles Disciple MVP-Core hook paths.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -13,7 +13,9 @@
|
|
|
13
13
|
"./package.json": "./package.json"
|
|
14
14
|
},
|
|
15
15
|
"files": [
|
|
16
|
-
"dist"
|
|
16
|
+
"dist",
|
|
17
|
+
"LICENSE",
|
|
18
|
+
"NOTICE"
|
|
17
19
|
],
|
|
18
20
|
"scripts": {
|
|
19
21
|
"build": "tsc",
|
|
@@ -21,22 +23,22 @@
|
|
|
21
23
|
"lint": "eslint \"src/**/*.ts\""
|
|
22
24
|
},
|
|
23
25
|
"dependencies": {
|
|
24
|
-
"@principles/core": "^1.
|
|
25
|
-
"@principles/install-layout": "^0.
|
|
26
|
+
"@principles/core": "^1.292.1",
|
|
27
|
+
"@principles/install-layout": "^0.3.1",
|
|
26
28
|
"better-sqlite3": "^13.0.3",
|
|
27
|
-
"js-yaml": "^5.4.
|
|
29
|
+
"js-yaml": "^5.4.3"
|
|
28
30
|
},
|
|
29
31
|
"devDependencies": {
|
|
30
32
|
"@types/better-sqlite3": "^9.6.0",
|
|
31
33
|
"@types/node": "^26.4.1",
|
|
32
34
|
"@types/js-yaml": "^4.0.9",
|
|
33
35
|
"typescript": "^7.0.2",
|
|
34
|
-
"vite": "^8.3.
|
|
36
|
+
"vite": "^8.3.4",
|
|
35
37
|
"vitest": "^5.0.0"
|
|
36
38
|
},
|
|
37
39
|
"repository": {
|
|
38
40
|
"type": "git",
|
|
39
41
|
"url": "git+https://github.com/csuzngjh/principles.git"
|
|
40
42
|
},
|
|
41
|
-
"license": "
|
|
43
|
+
"license": "Apache-2.0"
|
|
42
44
|
}
|