create-principles-disciple 1.146.8 → 1.147.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.
- package/_release/product-identity.json +1 -1
- package/codex-adapter/dist/ingestion/explicit-owner-statement.d.ts +6 -0
- package/codex-adapter/dist/ingestion/explicit-owner-statement.js +6 -0
- package/codex-adapter/dist/pd-hook.js +5 -2
- package/codex-adapter/dist/worker/workspace-worker.d.ts +13 -1
- package/codex-adapter/dist/worker/workspace-worker.js +26 -3
- package/codex-adapter/package.json +1 -1
- package/console/dist/server/models/ExaminerEvidenceModel.d.ts +159 -0
- package/console/dist/server/models/ExaminerEvidenceModel.js +274 -0
- package/console/dist/server/models/ReceiptsConsoleModel.js +15 -1
- package/console/dist/server/routes/examiner-executor.d.ts +40 -4
- package/console/dist/server/routes/examiner-executor.js +54 -45
- package/console/dist/server/routes/examiner-runs.d.ts +196 -0
- package/console/dist/server/routes/examiner-runs.js +938 -0
- package/console/dist/server/routes/examiner-study-inputs.d.ts +147 -0
- package/console/dist/server/routes/examiner-study-inputs.js +263 -0
- package/console/dist/server/routes/examiner.d.ts +26 -17
- package/console/dist/server/routes/examiner.js +261 -12
- package/console/dist/types.d.ts +1 -0
- package/console/dist/web/assets/app.css +92 -0
- package/console/dist/web/assets/app.js +38 -32
- package/console/lab/lib/challenge-openclaw-host.mjs +17 -0
- package/console/lab/lib/challenge-runner.mjs +9 -0
- package/console/lab/lib/examiner-study.mjs +55 -0
- package/core/dist/runtime-v2/index.d.ts +2 -2
- package/core/dist/runtime-v2/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/index.js +1 -1
- package/core/dist/runtime-v2/index.js.map +1 -1
- package/core/dist/runtime-v2/pain-ingress-payload.d.ts +13 -1
- package/core/dist/runtime-v2/pain-ingress-payload.d.ts.map +1 -1
- package/core/dist/runtime-v2/pain-ingress-payload.js +21 -2
- package/core/dist/runtime-v2/pain-ingress-payload.js.map +1 -1
- package/core/dist/runtime-v2/pain-ingress.d.ts.map +1 -1
- package/core/dist/runtime-v2/pain-ingress.js +3 -0
- package/core/dist/runtime-v2/pain-ingress.js.map +1 -1
- package/core/dist/runtime-v2/signal-collector/confidence-gate.d.ts +35 -0
- package/core/dist/runtime-v2/signal-collector/confidence-gate.d.ts.map +1 -0
- package/core/dist/runtime-v2/signal-collector/confidence-gate.js +48 -0
- package/core/dist/runtime-v2/signal-collector/confidence-gate.js.map +1 -0
- package/core/dist/runtime-v2/signal-collector/index.d.ts +1 -0
- package/core/dist/runtime-v2/signal-collector/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/signal-collector/index.js +1 -0
- package/core/dist/runtime-v2/signal-collector/index.js.map +1 -1
- package/core/dist/runtime-v2/signal-collector/keyword-stage.d.ts +4 -6
- package/core/dist/runtime-v2/signal-collector/keyword-stage.d.ts.map +1 -1
- package/core/dist/runtime-v2/signal-collector/keyword-stage.js +100 -9
- package/core/dist/runtime-v2/signal-collector/keyword-stage.js.map +1 -1
- package/core/dist/runtime-v2/store/context/sqlite-context-assembler.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/context/sqlite-context-assembler.js +8 -4
- package/core/dist/runtime-v2/store/context/sqlite-context-assembler.js.map +1 -1
- package/core/package.json +1 -1
- package/dist/installer.d.ts.map +1 -1
- package/dist/installer.js +52 -1
- package/dist/installer.js.map +1 -1
- package/dist/installers/mcp-registration-conflict.d.ts +35 -0
- package/dist/installers/mcp-registration-conflict.d.ts.map +1 -0
- package/dist/installers/mcp-registration-conflict.js +559 -0
- package/dist/installers/mcp-registration-conflict.js.map +1 -0
- package/dist/installers/openclaw-host-installer.d.ts.map +1 -1
- package/dist/installers/openclaw-host-installer.js +20 -0
- package/dist/installers/openclaw-host-installer.js.map +1 -1
- package/dist/installers/workbuddy-host-installer.d.ts.map +1 -1
- package/dist/installers/workbuddy-host-installer.js +124 -2
- package/dist/installers/workbuddy-host-installer.js.map +1 -1
- package/dist/mcp-server-layout-compat.d.ts +18 -0
- package/dist/mcp-server-layout-compat.d.ts.map +1 -0
- package/dist/mcp-server-layout-compat.js +22 -0
- package/dist/mcp-server-layout-compat.js.map +1 -0
- package/host-runtime/dist/governance-signal-admission.d.ts +147 -4
- package/host-runtime/dist/governance-signal-admission.js +1065 -60
- package/host-runtime/dist/index.d.ts +2 -0
- package/host-runtime/dist/index.js +2 -0
- package/host-runtime/dist/signal-classifier.d.ts +46 -0
- package/host-runtime/dist/signal-classifier.js +167 -0
- package/host-runtime/dist/signal-stage2-cycle.d.ts +42 -0
- package/host-runtime/dist/signal-stage2-cycle.js +184 -0
- package/host-runtime/package.json +1 -1
- package/install-layout/dist/index.d.ts +15 -0
- package/install-layout/dist/index.js +10 -0
- package/install-layout/package.json +1 -1
- package/package.json +9 -7
- package/pd-cli/dist/commands/health-codex.d.ts.map +1 -1
- package/pd-cli/dist/commands/health-codex.js +12 -0
- package/pd-cli/dist/commands/health-codex.js.map +1 -1
- package/pd-cli/dist/commands/health-mcp.d.ts +74 -0
- package/pd-cli/dist/commands/health-mcp.d.ts.map +1 -0
- package/pd-cli/dist/commands/health-mcp.js +723 -0
- package/pd-cli/dist/commands/health-mcp.js.map +1 -0
- package/pd-cli/dist/commands/health.d.ts +2 -0
- package/pd-cli/dist/commands/health.d.ts.map +1 -1
- package/pd-cli/dist/commands/health.js +11 -6
- package/pd-cli/dist/commands/health.js.map +1 -1
- package/pd-mcp-server/dist/budget.d.ts +15 -0
- package/pd-mcp-server/dist/budget.js +19 -0
- package/pd-mcp-server/dist/deadline.d.ts +75 -0
- package/pd-mcp-server/dist/deadline.js +136 -0
- package/pd-mcp-server/dist/envelope.d.ts +52 -0
- package/pd-mcp-server/dist/envelope.js +63 -0
- package/pd-mcp-server/dist/index.d.ts +10 -0
- package/pd-mcp-server/dist/index.js +76 -0
- package/pd-mcp-server/dist/logging.d.ts +12 -0
- package/pd-mcp-server/dist/logging.js +42 -0
- package/pd-mcp-server/dist/server.d.ts +90 -0
- package/pd-mcp-server/dist/server.js +178 -0
- package/pd-mcp-server/dist/version.d.ts +13 -0
- package/pd-mcp-server/dist/version.js +13 -0
- package/pd-mcp-server/dist/workspace.d.ts +23 -0
- package/pd-mcp-server/dist/workspace.js +77 -0
- package/pd-mcp-server/package.json +49 -0
- package/plugin/dist/bundle.js +414 -412
- package/plugin/dist/core/mcp-binding.d.ts +41 -0
- package/plugin/dist/index.d.ts +33 -0
- package/plugin/dist/openclaw.plugin.json +10 -1
- package/plugin/dist/utils/workspace-resolver.d.ts +17 -0
- package/plugin/openclaw.plugin.json +10 -1
- package/plugin/package.json +2 -1
- package/release-manager/dist/installer.js +52 -1
- package/release-manager/dist/installers/mcp-registration-conflict.js +559 -0
- package/release-manager/dist/installers/openclaw-host-installer.js +20 -0
- package/release-manager/dist/installers/workbuddy-host-installer.js +124 -2
- package/release-manager/dist/mcp-server-layout-compat.js +22 -0
- package/release-manager/package.json +7 -5
- package/workbuddy-adapter/dist/pd-hook.js +28 -5
- package/workbuddy-adapter/dist/worker/workspace-worker.d.ts +6 -1
- package/workbuddy-adapter/dist/worker/workspace-worker.js +24 -3
- package/workbuddy-adapter/package.json +1 -1
- package/workbuddy-adapter/plugin/.codebuddy-plugin/plugin.json +2 -2
- package/workbuddy-adapter/plugin/.mcp.json +10 -0
- package/workbuddy-adapter/plugin/mcp/launcher.cjs +347 -0
|
@@ -48,6 +48,8 @@ import * as yaml from 'js-yaml';
|
|
|
48
48
|
import semver from 'semver';
|
|
49
49
|
import { getInstallLayoutPaths, getWorkbuddyWorkspaceDir, installManifestHostsForPersist, mergeInstallManifestWorkspaces, parseInstallManifest, INSTALL_LAYOUT_VERSION, } from '@principles/install-layout';
|
|
50
50
|
import { atomicReplaceTextFile, errnoCode } from '../utils/config-file-io.js';
|
|
51
|
+
import { checkMcpRegistrationConflict } from './mcp-registration-conflict.js';
|
|
52
|
+
import { resolveMcpServerDir, resolveMcpServerEntry } from '../mcp-server-layout-compat.js';
|
|
51
53
|
import { getHomeDir, generateConfigYamlContent, getConfigYamlPath, resolveDefaultModelForProvider, isValidHttpBaseUrl } from '../mvp-config.js';
|
|
52
54
|
// Type-only import from @principles/core — erased at compile time; this
|
|
53
55
|
// package ships self-contained without @principles/core (PRI-625/PRI-669).
|
|
@@ -67,6 +69,7 @@ const WORKBUDDY_REQUIRED_SKILLS = ['pd-cli-operator', 'pd-pain-signal', 'pd-revi
|
|
|
67
69
|
const WORKBUDDY_PAYLOAD_FILES = [
|
|
68
70
|
path.join('.codebuddy-plugin', 'plugin.json'),
|
|
69
71
|
path.join('hooks', 'hooks.json'),
|
|
72
|
+
path.join('mcp', 'launcher.cjs'),
|
|
70
73
|
path.join('scripts', 'wrapper.cjs'),
|
|
71
74
|
path.join('scripts', 'pd-control.cjs'),
|
|
72
75
|
...WORKBUDDY_REQUIRED_SKILLS.map((skill) => path.join('skills', skill, 'SKILL.md')),
|
|
@@ -84,6 +87,59 @@ const GOVERNANCE_INIT_TIMEOUT_MS = 180_000;
|
|
|
84
87
|
function isRecord(value) {
|
|
85
88
|
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
86
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Atomic replace for the binding file (same discipline as the OpenClaw plugin
|
|
92
|
+
* writer and `$pd-control setup`): a reader must never observe a truncated
|
|
93
|
+
* binding. No generic config subsystem — one helper next to its only use.
|
|
94
|
+
*/
|
|
95
|
+
function writeFileAtomicSync(file, contents) {
|
|
96
|
+
const temp = path.join(path.dirname(file), `.${path.basename(file)}.${process.pid}.tmp`);
|
|
97
|
+
try {
|
|
98
|
+
writeFileSync(temp, contents, 'utf-8');
|
|
99
|
+
renameSync(temp, file);
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
try {
|
|
103
|
+
rmSync(temp, { force: true });
|
|
104
|
+
}
|
|
105
|
+
catch {
|
|
106
|
+
/* best-effort cleanup of our own temp file */
|
|
107
|
+
}
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Cache-binding comparison for the idempotent path. `writtenAt` is a
|
|
113
|
+
* per-install timestamp, so comparing raw bytes would force a cache refresh
|
|
114
|
+
* on every run; comparing the rest proves the launcher will read the same
|
|
115
|
+
* workspace/entry/versions the marketplace copy declares. Absent on both
|
|
116
|
+
* sides is a match (no MCP payload); absent on one side is drift.
|
|
117
|
+
*/
|
|
118
|
+
function mcpBindingMatches(sourceDir, cacheDir) {
|
|
119
|
+
const bindingFile = 'mcp-binding.json';
|
|
120
|
+
const read = (dir) => {
|
|
121
|
+
const file = path.join(dir, bindingFile);
|
|
122
|
+
if (!existsSync(file))
|
|
123
|
+
return undefined;
|
|
124
|
+
try {
|
|
125
|
+
const parsed = JSON.parse(readFileSync(file, 'utf-8'));
|
|
126
|
+
if (!isRecord(parsed))
|
|
127
|
+
return null;
|
|
128
|
+
const { writtenAt: _writtenAt, ...rest } = parsed;
|
|
129
|
+
return rest;
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
const source = read(sourceDir);
|
|
136
|
+
const cached = read(cacheDir);
|
|
137
|
+
if (source === undefined && cached === undefined)
|
|
138
|
+
return true;
|
|
139
|
+
if (source === undefined || cached === undefined || source === null || cached === null)
|
|
140
|
+
return false;
|
|
141
|
+
return JSON.stringify(source) === JSON.stringify(cached);
|
|
142
|
+
}
|
|
87
143
|
/** Native v2 stores scope records as an array; old PD installs used one object. */
|
|
88
144
|
function userInstalledPluginRecord(value) {
|
|
89
145
|
const records = Array.isArray(value) ? value : [value];
|
|
@@ -1087,6 +1143,47 @@ function materializeMarketplace(marketplaceRoot, pluginDir) {
|
|
|
1087
1143
|
// sources that escape it ("Path escapes marketplace root", frozen facts).
|
|
1088
1144
|
cpSync(pluginDir, path.join(marketplaceRoot, WORKBUDDY_PLUGIN_NAME), { recursive: true });
|
|
1089
1145
|
}
|
|
1146
|
+
/**
|
|
1147
|
+
* Gate 4 (PRI-1071): write the launcher binding into the marketplace payload
|
|
1148
|
+
* copy — the frozen governance workspace (getWorkbuddyWorkspaceDir SSoT) and
|
|
1149
|
+
* the canonical installed MCP server entry. Written only when the server
|
|
1150
|
+
* component exists (an older runtime without it stays honestly absent; the
|
|
1151
|
+
* launcher then fails closed with binding_missing — equally recoverable by
|
|
1152
|
+
* re-running the installer). A failure degrades to a structured note (G4-07:
|
|
1153
|
+
* MCP unavailability must not break the WorkBuddy host install).
|
|
1154
|
+
*/
|
|
1155
|
+
function writeWorkbuddyMcpBinding(marketplaceRoot, homeDir) {
|
|
1156
|
+
try {
|
|
1157
|
+
const layout = getInstallLayoutPaths(homeDir);
|
|
1158
|
+
// Gate 4 P2: the launcher validates serverEntry against this recorded
|
|
1159
|
+
// runtime root + the Install Layout SSoT component dir, so the binding
|
|
1160
|
+
// cannot point the host at arbitrary JavaScript.
|
|
1161
|
+
const serverEntry = resolveMcpServerEntry(layout);
|
|
1162
|
+
if (!existsSync(serverEntry))
|
|
1163
|
+
return { ok: false, reason: 'mcp_server_component_missing' };
|
|
1164
|
+
let mcpServerVersion = 'unknown';
|
|
1165
|
+
try {
|
|
1166
|
+
const manifest = JSON.parse(readFileSync(path.join(resolveMcpServerDir(layout), 'package.json'), 'utf-8'));
|
|
1167
|
+
if (typeof manifest.version === 'string')
|
|
1168
|
+
mcpServerVersion = manifest.version;
|
|
1169
|
+
}
|
|
1170
|
+
catch { /* version stays unknown (rc-3: never coerce) */ }
|
|
1171
|
+
const binding = {
|
|
1172
|
+
schemaVersion: 'pd.mcp-binding.v1',
|
|
1173
|
+
host: 'workbuddy',
|
|
1174
|
+
workspaceDir: getWorkbuddyWorkspaceDir(homeDir),
|
|
1175
|
+
runtimeDir: layout.runtimeDir,
|
|
1176
|
+
serverEntry,
|
|
1177
|
+
versions: { mcpServer: mcpServerVersion },
|
|
1178
|
+
writtenAt: new Date().toISOString(),
|
|
1179
|
+
};
|
|
1180
|
+
writeFileAtomicSync(path.join(marketplaceRoot, WORKBUDDY_PLUGIN_NAME, 'mcp-binding.json'), JSON.stringify(binding, null, 2) + '\n');
|
|
1181
|
+
return { ok: true };
|
|
1182
|
+
}
|
|
1183
|
+
catch (error) {
|
|
1184
|
+
return { ok: false, reason: `write_failed:${error instanceof Error ? error.message.slice(0, 120) : String(error).slice(0, 120)}` };
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1090
1187
|
export class WorkBuddyHostInstaller {
|
|
1091
1188
|
hostId = 'workbuddy';
|
|
1092
1189
|
deps;
|
|
@@ -1209,6 +1306,26 @@ export class WorkBuddyHostInstaller {
|
|
|
1209
1306
|
};
|
|
1210
1307
|
}
|
|
1211
1308
|
const { payload } = payloadFind;
|
|
1309
|
+
// 3b. SPEC §7.5/§11.3: a same-name user-level MCP server must stop the
|
|
1310
|
+
// install BEFORE any marketplace/cache/registration write. The check is
|
|
1311
|
+
// read-only and leaves the offending file untouched.
|
|
1312
|
+
const mcpConflict = checkMcpRegistrationConflict('workbuddy', {
|
|
1313
|
+
homeDir: this.deps.homeDir(),
|
|
1314
|
+
workbuddyConfigDir: p.configDir,
|
|
1315
|
+
// Ownership is proven by the payload PD ships OR by launcher content
|
|
1316
|
+
// stamps — never by the `mcp/launcher.cjs` file NAME alone.
|
|
1317
|
+
pdLauncherRoots: [payload.pluginDir],
|
|
1318
|
+
});
|
|
1319
|
+
if (!mcpConflict.ok) {
|
|
1320
|
+
return {
|
|
1321
|
+
success: false,
|
|
1322
|
+
hostId: this.hostId,
|
|
1323
|
+
configPath: p.settingsPath,
|
|
1324
|
+
configAction: 'skipped',
|
|
1325
|
+
reason: mcpConflict.reason,
|
|
1326
|
+
nextAction: mcpConflict.nextAction,
|
|
1327
|
+
};
|
|
1328
|
+
}
|
|
1212
1329
|
// 4. Materialize the PD-owned marketplace (source stays inside its root).
|
|
1213
1330
|
try {
|
|
1214
1331
|
materializeMarketplace(p.marketplaceRoot, payload.pluginDir);
|
|
@@ -1223,6 +1340,10 @@ export class WorkBuddyHostInstaller {
|
|
|
1223
1340
|
nextAction: `Check permissions under ${path.dirname(p.marketplaceRoot)} and re-run the installer.`,
|
|
1224
1341
|
};
|
|
1225
1342
|
}
|
|
1343
|
+
// 4b. Gate 4 (PRI-1071): bind the pd-recall MCP launcher to the frozen
|
|
1344
|
+
// governance workspace. Degrades to a note — the host install itself is
|
|
1345
|
+
// unaffected when the MCP component is missing or the write fails.
|
|
1346
|
+
const mcpBinding = writeWorkbuddyMcpBinding(p.marketplaceRoot, this.deps.homeDir());
|
|
1226
1347
|
// 5. Register: engine commands first; observable direct-write fallback.
|
|
1227
1348
|
const registration = this.registerPlugin(details, payload.version);
|
|
1228
1349
|
if (!registration.ok) {
|
|
@@ -1328,7 +1449,7 @@ export class WorkBuddyHostInstaller {
|
|
|
1328
1449
|
keywordPainEnabled: !governanceDefaults.keywordExplicitOff,
|
|
1329
1450
|
configPath: governanceDefaults.configPath,
|
|
1330
1451
|
},
|
|
1331
|
-
reason: `Registered ${WORKBUDDY_PLUGIN_KEY} via ${registration.mode}${registration.mode === 'engine' ? '' : ` (engine unreachable: ${registration.engineNote})`}. Governance workspace initialized at ${p.governanceDir}${governance.dbInit === 'skipped' ? ` (${governance.note})` : ''}.${profileNote}${governanceDefaultsNote}`,
|
|
1452
|
+
reason: `Registered ${WORKBUDDY_PLUGIN_KEY} via ${registration.mode}${registration.mode === 'engine' ? '' : ` (engine unreachable: ${registration.engineNote})`}. Governance workspace initialized at ${p.governanceDir}${governance.dbInit === 'skipped' ? ` (${governance.note})` : ''}.${profileNote}${governanceDefaultsNote}${mcpBinding.ok ? ' pd-recall MCP binding written.' : ` pd-recall MCP binding skipped (${mcpBinding.reason ?? 'unknown'}).`}`,
|
|
1332
1453
|
// PRI-1063 copy (single-line flat-key flow mapping) carried over from
|
|
1333
1454
|
// main; the "Existing workspaces retain their prior settings" sentence is
|
|
1334
1455
|
// deliberately dropped — PRI-1064 turns governance ON for those
|
|
@@ -1497,7 +1618,8 @@ export class WorkBuddyHostInstaller {
|
|
|
1497
1618
|
return false;
|
|
1498
1619
|
const sourceDir = path.join(p.marketplaceRoot, WORKBUDDY_PLUGIN_NAME);
|
|
1499
1620
|
try {
|
|
1500
|
-
|
|
1621
|
+
const filesMatch = WORKBUDDY_PAYLOAD_FILES.every((file) => readFileSync(path.join(sourceDir, file)).equals(readFileSync(path.join(cacheDir, file))));
|
|
1622
|
+
return filesMatch && mcpBindingMatches(sourceDir, cacheDir);
|
|
1501
1623
|
}
|
|
1502
1624
|
catch {
|
|
1503
1625
|
return false;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import * as path from 'node:path';
|
|
2
|
+
/**
|
|
3
|
+
* Temporary twin of install-layout's MCP component path API.
|
|
4
|
+
*
|
|
5
|
+
* The registry only publishes install-layout 0.4.0, which predates
|
|
6
|
+
* `mcpServerDir` / `getMcpServerEntry`. The npx-parity gate installs the
|
|
7
|
+
* packed installer ALONE and resolves that published dependency, so a static
|
|
8
|
+
* import of the new exports crashes at module load (PRI-669 defect class:
|
|
9
|
+
* the installer dist must never import an interface the registry lacks).
|
|
10
|
+
*
|
|
11
|
+
* Retirement condition: the registry serves the install-layout version whose
|
|
12
|
+
* d.ts declares `mcpServerDir` (this PR adds the changeset that publishes
|
|
13
|
+
* it). Then switch both call sites back to the shared exports and delete
|
|
14
|
+
* this file — the same two-step as the #2047 → #2058 manifest-host twin.
|
|
15
|
+
*/
|
|
16
|
+
export function resolveMcpServerDir(layout) {
|
|
17
|
+
return path.join(layout.runtimeDir, 'pd-mcp-server');
|
|
18
|
+
}
|
|
19
|
+
export function resolveMcpServerEntry(layout) {
|
|
20
|
+
return path.join(resolveMcpServerDir(layout), 'dist', 'index.js');
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=mcp-server-layout-compat.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-principles-disciple",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.147.0",
|
|
4
4
|
"description": "Interactive CLI installer for Principles Disciple OpenClaw plugin",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"host-runtime",
|
|
27
27
|
"codex-adapter",
|
|
28
28
|
"workbuddy-adapter",
|
|
29
|
+
"pd-mcp-server",
|
|
29
30
|
"install-layout",
|
|
30
31
|
"release-manager",
|
|
31
32
|
"trust/root.json",
|
|
@@ -36,13 +37,14 @@
|
|
|
36
37
|
],
|
|
37
38
|
"scripts": {
|
|
38
39
|
"build": "tsc",
|
|
40
|
+
"build:deps": "npm run build --workspace=@principles/core && npm run build --workspace=@principles/install-layout && node scripts/mcp-server-build.mjs",
|
|
39
41
|
"dev": "tsc --watch",
|
|
40
42
|
"bundle": "node scripts/bundle-plugin.mjs",
|
|
41
|
-
"build:release-asset": "node scripts/build-self-contained-release.mjs",
|
|
43
|
+
"build:release-asset": "npm run build:deps && node scripts/build-self-contained-release.mjs",
|
|
42
44
|
"generate:release-locks": "node scripts/generate-release-locks.mjs",
|
|
43
45
|
"check:release-locks": "node scripts/check-release-locks.mjs",
|
|
44
|
-
"prepack": "npm run build && npm run bundle",
|
|
45
|
-
"prepublishOnly": "npm run build && npm run bundle",
|
|
46
|
+
"prepack": "npm run build:deps && npm run build && npm run bundle",
|
|
47
|
+
"prepublishOnly": "npm run build:deps && npm run build && npm run bundle",
|
|
46
48
|
"test": "vitest run",
|
|
47
49
|
"test:fast": "vitest run --exclude tests/smoke-packaged-install.test.ts --exclude tests/release-asset-smoke.test.ts --exclude tests/release-upgrade-gate.test.ts --exclude tests/release-junction-lifecycle.test.ts",
|
|
48
50
|
"test:smoke:packaged": "vitest run tests/smoke-packaged-install.test.ts",
|
|
@@ -96,6 +98,6 @@
|
|
|
96
98
|
"directory": "packages/create-principles-disciple"
|
|
97
99
|
},
|
|
98
100
|
"pd": {
|
|
99
|
-
"bundledPluginVersion": "2.2.
|
|
101
|
+
"bundledPluginVersion": "2.2.13"
|
|
100
102
|
}
|
|
101
103
|
}
|
|
@@ -37,7 +37,7 @@ import path from 'node:path';
|
|
|
37
37
|
import process from 'node:process';
|
|
38
38
|
import { pathToFileURL, fileURLToPath } from 'node:url';
|
|
39
39
|
import { appendEventLogLine, redactTelemetryString, isRuleHostEvaluatedEventData } from '@principles/core/runtime-v2';
|
|
40
|
-
import { createProductionHostRuntime, createWorkbuddyRuleContextProvider, loadPdConfigForPlugin, parseOwnerStatementPrefix,
|
|
40
|
+
import { createProductionHostRuntime, createWorkbuddyRuleContextProvider, loadPdConfigForPlugin, parseOwnerStatementPrefix, assessWorkbuddyCorrectionCandidate, resolveSharedCorrectionKeywordStoreForDetection, admitTrustedWorkbuddyLiveCorrection, ensureGovernanceDiagnosticianTask } from '@principles/host-runtime';
|
|
41
41
|
import { computeFeatureFlagsFromConfig } from '@principles/core/runtime-v2';
|
|
42
42
|
import { WorkBuddyHooksHostAdapter } from './host-adapter.js';
|
|
43
43
|
import { WORKBUDDY_TOOL_SEMANTICS } from './tool-semantics.js';
|
|
@@ -280,9 +280,10 @@ export async function processWorkbuddyHookInvocation(rawStdin, channelEventName,
|
|
|
280
280
|
typeof prompt === 'string' && !explicitReserved) {
|
|
281
281
|
// AUDIT-P3-01: 预检与 admitTrustedWorkbuddyLiveCorrection 内部使用同一份
|
|
282
282
|
// 共享 live 词库(seed ∪ learned)——预检不会漏掉学习词,也不会比准入
|
|
283
|
-
// 更宽。startsWith
|
|
284
|
-
|
|
285
|
-
|
|
283
|
+
// 更宽。startsWith 预过滤保持(SPEC P-5);歧义候选只落 pending,
|
|
284
|
+
// 同步 hook 内零 LLM。
|
|
285
|
+
const matched = assessWorkbuddyCorrectionCandidate(prompt, event.context.sessionId, resolveSharedCorrectionKeywordStoreForDetection(resolution.workspaceDir));
|
|
286
|
+
if (matched.kind !== 'none') {
|
|
286
287
|
const admitted = admitTrustedWorkbuddyLiveCorrection({
|
|
287
288
|
workspaceDir: resolution.workspaceDir,
|
|
288
289
|
rawEvent: parsed,
|
|
@@ -321,13 +322,35 @@ export async function processWorkbuddyHookInvocation(rawStdin, channelEventName,
|
|
|
321
322
|
catch { /* Evidence-log failure must not block the prompt. */ }
|
|
322
323
|
}
|
|
323
324
|
}
|
|
325
|
+
else if (outcome.disposition === 'pending_llm_review') {
|
|
326
|
+
// Ambiguous Stage-1 candidate persisted for the worker's
|
|
327
|
+
// bounded Stage-2 step. No Pain, no task, no quota consumed.
|
|
328
|
+
try {
|
|
329
|
+
appendEventLogLine(path.join(resolution.workspaceDir, '.state'), {
|
|
330
|
+
ts: new Date().toISOString(),
|
|
331
|
+
type: 'workbuddy_keyword_pending_review',
|
|
332
|
+
category: 'detected',
|
|
333
|
+
sessionId: event.context.sessionId,
|
|
334
|
+
data: { hostKind: 'workbuddy', outcome: outcome.disposition, duplicate: outcome.duplicate },
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
catch { /* Evidence-log failure must not block the prompt. */ }
|
|
338
|
+
}
|
|
339
|
+
else if (outcome.disposition === 'abandoned') {
|
|
340
|
+
// P1 review round 3: an automatic correction needs REAL
|
|
341
|
+
// persisted behavior evidence. WorkBuddy has no observation
|
|
342
|
+
// store, so the shared ingress correctly settles as
|
|
343
|
+
// observation_only — no Pain, no task, no quota, and no
|
|
344
|
+
// fabricated `pain_event:` trace.
|
|
345
|
+
autoDiagnostics.push(diagnostic('skipped', 'workbuddy_keyword_observation_only:' + outcome.reason, 'No persisted behavior evidence exists for this automatic correction; no Pain was created.'));
|
|
346
|
+
}
|
|
324
347
|
else if (outcome.disposition === 'rate_limited') {
|
|
325
348
|
autoDiagnostics.push(diagnostic('degraded', 'workbuddy_keyword_rate_limited', 'Per-session strong signal limit reached; no new Pain was created.'));
|
|
326
349
|
}
|
|
327
350
|
}
|
|
328
351
|
}
|
|
329
352
|
}
|
|
330
|
-
else if (matched.reason === 'prompt_too_large') {
|
|
353
|
+
else if (matched.reason === 'prompt_too_large' && matched.kind === 'none') {
|
|
331
354
|
autoDiagnostics.push(diagnostic('degraded', 'workbuddy_keyword_prompt_too_large', 'Oversized prompt was not scanned or persisted as a keyword signal.'));
|
|
332
355
|
}
|
|
333
356
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AdmitBareHostPainsResult, type InternalizationConsumerCycleOutcome, type ConsumerCycleLogger, type ReconcileGovernanceContinuationResult } from '@principles/host-runtime';
|
|
1
|
+
import { type AdmitBareHostPainsResult, type InternalizationConsumerCycleOutcome, type ConsumerCycleLogger, type ReconcileGovernanceContinuationResult, type SignalLlmClassifier, type Stage2CorrectionCycleReport } from '@principles/host-runtime';
|
|
2
2
|
export type WorkbuddyWorkerMode = 'ready' | 'manual_action_required' | 'paused' | 'degraded';
|
|
3
3
|
export interface WorkbuddyWorkerCycleStepReport {
|
|
4
4
|
readonly reconcile: ReconcileGovernanceContinuationResult;
|
|
@@ -17,6 +17,8 @@ export interface WorkbuddyWorkerCycleStepReport {
|
|
|
17
17
|
readonly nextAction?: string;
|
|
18
18
|
} | null;
|
|
19
19
|
readonly downstream: InternalizationConsumerCycleOutcome | null;
|
|
20
|
+
/** Phase B Stage-2 review step (always last, ≤2 candidates / ≤60s aggregate). */
|
|
21
|
+
readonly stage2?: Stage2CorrectionCycleReport;
|
|
20
22
|
}
|
|
21
23
|
export interface WorkbuddyWorkerCycleResult {
|
|
22
24
|
readonly workspaceDir: string;
|
|
@@ -32,6 +34,9 @@ export interface WorkbuddyWorkerCycleOptions {
|
|
|
32
34
|
readonly emitEvent?: (event: string, payloadJson: string) => void;
|
|
33
35
|
/** Cap on diagnostician candidates inspected per cycle (default 5). */
|
|
34
36
|
readonly diagnosticianCandidateLimit?: number;
|
|
37
|
+
/** Stage-2 classifier injection (tests); undefined = resolve from config. */
|
|
38
|
+
readonly stage2Classifier?: SignalLlmClassifier | null;
|
|
39
|
+
readonly stage2AggregateBudgetMs?: number;
|
|
35
40
|
}
|
|
36
41
|
/**
|
|
37
42
|
* Run ONE bounded worker cycle for a canonical governance workspace. Never
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
import fs from 'node:fs';
|
|
34
34
|
import path from 'node:path';
|
|
35
35
|
import { computeFeatureFlagsFromConfig, createRuntimeStateHandle, createPainSignalBridge, isRetryWaitBackoffElapsed, PrincipleTreeLedgerAdapter, resolveDiagnosticianCapability, } from '@principles/core/runtime-v2';
|
|
36
|
-
import { admitBareHostPains, loadPdConfigForPlugin, loadFeatureFlagFromConfig, reconcileGovernanceContinuation, runInternalizationConsumerCycle, saveHostToolDeclaration, } from '@principles/host-runtime';
|
|
36
|
+
import { admitBareHostPains, loadPdConfigForPlugin, loadFeatureFlagFromConfig, reconcileGovernanceContinuation, runInternalizationConsumerCycle, runStage2CorrectionCycle, createSignalClassifierForWorkspace, saveHostToolDeclaration, } from '@principles/host-runtime';
|
|
37
37
|
import { WORKBUDDY_TOOL_SEMANTICS, WORKBUDDY_TOOL_SEMANTIC_MAPPINGS } from '../tool-semantics.js';
|
|
38
38
|
const WORKER_OWNER = 'companion-worker';
|
|
39
39
|
const DEFAULT_DIAG_CANDIDATE_LIMIT = 5;
|
|
@@ -205,16 +205,37 @@ export async function runWorkbuddyWorkspaceWorkerCycle(options) {
|
|
|
205
205
|
toolSemantics: WORKBUDDY_TOOL_SEMANTICS,
|
|
206
206
|
hostKinds: ['workbuddy'],
|
|
207
207
|
});
|
|
208
|
+
// Step 7 (SPEC v0.3.1 §2) — Stage-2 correction review, ALWAYS last.
|
|
209
|
+
const stage2Resolution = options.stage2Classifier === undefined
|
|
210
|
+
? createSignalClassifierForWorkspace(workspaceDir)
|
|
211
|
+
: null;
|
|
212
|
+
const stage2Classifier = options.stage2Classifier !== undefined
|
|
213
|
+
? options.stage2Classifier
|
|
214
|
+
: (stage2Resolution?.ok === true ? stage2Resolution.classifier : null);
|
|
215
|
+
const stage2ClassifierState = options.stage2Classifier === null
|
|
216
|
+
? 'disabled'
|
|
217
|
+
: stage2Classifier === null
|
|
218
|
+
? (stage2Resolution !== null && !stage2Resolution.ok && stage2Resolution.readiness === 'disabled' ? 'disabled' : 'unavailable')
|
|
219
|
+
: 'used';
|
|
220
|
+
const stage2 = await runStage2CorrectionCycle({
|
|
221
|
+
workspaceDir,
|
|
222
|
+
classifier: stage2Classifier,
|
|
223
|
+
classifierState: stage2ClassifierState,
|
|
224
|
+
...(options.stage2AggregateBudgetMs !== undefined ? { aggregateBudgetMs: options.stage2AggregateBudgetMs } : {}),
|
|
225
|
+
...(options.now !== undefined ? { now: options.now } : {}),
|
|
226
|
+
onEvent: emitEvent,
|
|
227
|
+
});
|
|
208
228
|
const degradedReason = !reconcile.ok ? `reconcile:${reconcile.reason ?? 'failed'}`
|
|
209
229
|
: !admission.ok ? `admission:${admission.reason ?? 'failed'}`
|
|
210
230
|
: diagnostician?.status === 'failed' && diagnostician.errorCategory !== 'lease_conflict' ? `diagnostician_failed:${diagnostician.message ?? 'max_attempts_exceeded'}`
|
|
211
231
|
: diagnostician?.status === 'degraded' ? `diagnostician_degraded:${diagnostician.message ?? 'unknown'}`
|
|
212
232
|
: downstream.skipReason === 'runtime_config_error' || downstream.skipReason === 'cycle_error' || downstream.skipReason === 'config_malformed' ? `downstream:${downstream.skipReason}`
|
|
213
|
-
:
|
|
233
|
+
: !stage2.ok ? `stage2:${stage2.reason ?? 'failed'}`
|
|
234
|
+
: undefined;
|
|
214
235
|
return {
|
|
215
236
|
...base,
|
|
216
237
|
mode: degradedReason !== undefined ? 'degraded' : 'ready',
|
|
217
238
|
...(degradedReason !== undefined ? { reason: degradedReason, nextAction: 'Inspect the governance workspace .pd/config.yaml runtime profile and the per-step report above; the worker retries automatically on the next cycle.' } : {}),
|
|
218
|
-
report: { reconcile, admission, diagnostician, downstream },
|
|
239
|
+
report: { reconcile, admission, diagnostician, downstream, stage2 },
|
|
219
240
|
};
|
|
220
241
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@principles/workbuddy-adapter",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "WorkBuddy host adapter for Principles Disciple — implements the HostAdapter interface for WorkBuddy's Git Bash command-hook model (ADR-0020 third host, SPEC workbuddy-host-adapter v0.3.0).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "principles-disciple",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "Principles Disciple — Owner-governed behavior internalization for AI agents (WorkBuddy host adapter, ADR-0020 third host). Requires explicit setup and host.workbuddy feature enablement; inactive until then.",
|
|
3
|
+
"version": "0.2.2",
|
|
4
|
+
"description": "Principles Disciple — Owner-governed behavior internalization for AI agents (WorkBuddy host adapter, ADR-0020 third host). Requires explicit setup and host.workbuddy feature enablement; inactive until then. Ships the read-only pd-recall MCP server (Gate 4).",
|
|
5
5
|
"defaultEnabled": false
|
|
6
6
|
}
|