create-principles-disciple 1.77.0 → 1.78.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/console/dist/server/config/feature-flags.d.ts +25 -0
- package/console/dist/server/config/feature-flags.js +101 -0
- package/console/dist/server/index.js +16 -0
- package/console/dist/server/models/FeedbackReportConsoleModel.d.ts +49 -0
- package/console/dist/server/models/FeedbackReportConsoleModel.js +242 -0
- package/console/dist/server/routes/feedback-reports.d.ts +18 -0
- package/console/dist/server/routes/feedback-reports.js +165 -0
- package/console/dist/ui/App.js +2 -1
- package/console/dist/ui/api.d.ts +26 -2
- package/console/dist/ui/api.js +18 -1
- package/console/dist/ui/components/app-sidebar.js +2 -1
- package/console/dist/ui/components/error-boundary.js +9 -2
- package/console/dist/ui/i18n/en.json +67 -1
- package/console/dist/ui/i18n/zh-CN.json +67 -1
- package/console/dist/ui/pages/ReportProblemPage.d.ts +1 -0
- package/console/dist/ui/pages/ReportProblemPage.js +186 -0
- package/console/dist/ui/pages/ReportProblemValidators.d.ts +51 -0
- package/console/dist/ui/pages/ReportProblemValidators.js +114 -0
- package/console/dist/web/assets/app.css +18 -0
- package/console/dist/web/assets/app.js +1047 -125
- package/console/package.json +1 -0
- package/core/dist/runtime-v2/__tests__/architecture-regression.test.js +23 -1
- package/core/dist/runtime-v2/__tests__/architecture-regression.test.js.map +1 -1
- package/core/dist/runtime-v2/__tests__/feedback/create-report.test.d.ts +2 -0
- package/core/dist/runtime-v2/__tests__/feedback/create-report.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/feedback/create-report.test.js +402 -0
- package/core/dist/runtime-v2/__tests__/feedback/create-report.test.js.map +1 -0
- package/core/dist/runtime-v2/__tests__/feedback/privacy-preview.test.d.ts +2 -0
- package/core/dist/runtime-v2/__tests__/feedback/privacy-preview.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/feedback/privacy-preview.test.js +128 -0
- package/core/dist/runtime-v2/__tests__/feedback/privacy-preview.test.js.map +1 -0
- package/core/dist/runtime-v2/__tests__/feedback/redact-sensitive.test.d.ts +2 -0
- package/core/dist/runtime-v2/__tests__/feedback/redact-sensitive.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/feedback/redact-sensitive.test.js +231 -0
- package/core/dist/runtime-v2/__tests__/feedback/redact-sensitive.test.js.map +1 -0
- package/core/dist/runtime-v2/__tests__/feedback/render-github-url.test.d.ts +2 -0
- package/core/dist/runtime-v2/__tests__/feedback/render-github-url.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/feedback/render-github-url.test.js +102 -0
- package/core/dist/runtime-v2/__tests__/feedback/render-github-url.test.js.map +1 -0
- package/core/dist/runtime-v2/__tests__/feedback/render-markdown.test.d.ts +2 -0
- package/core/dist/runtime-v2/__tests__/feedback/render-markdown.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/__tests__/feedback/render-markdown.test.js +130 -0
- package/core/dist/runtime-v2/__tests__/feedback/render-markdown.test.js.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/prompt-activation-reader-contract.test.d.ts +2 -0
- package/core/dist/runtime-v2/activation/__tests__/prompt-activation-reader-contract.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/activation/__tests__/prompt-activation-reader-contract.test.js +343 -0
- package/core/dist/runtime-v2/activation/__tests__/prompt-activation-reader-contract.test.js.map +1 -0
- package/core/dist/runtime-v2/activation/index.d.ts +2 -0
- package/core/dist/runtime-v2/activation/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/index.js +1 -0
- package/core/dist/runtime-v2/activation/index.js.map +1 -1
- package/core/dist/runtime-v2/activation/prompt-activation-reader-contract.d.ts +34 -0
- package/core/dist/runtime-v2/activation/prompt-activation-reader-contract.d.ts.map +1 -0
- package/core/dist/runtime-v2/activation/prompt-activation-reader-contract.js +109 -0
- package/core/dist/runtime-v2/activation/prompt-activation-reader-contract.js.map +1 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js +13 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/feature-flag-contract.test.js.map +1 -1
- package/core/dist/runtime-v2/feature-flags/__tests__/plugin-surface-registry.test.d.ts +2 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/plugin-surface-registry.test.d.ts.map +1 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/plugin-surface-registry.test.js +141 -0
- package/core/dist/runtime-v2/feature-flags/__tests__/plugin-surface-registry.test.js.map +1 -0
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.d.ts.map +1 -1
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js +4 -1
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js.map +1 -1
- package/core/dist/runtime-v2/feature-flags/index.d.ts +2 -0
- package/core/dist/runtime-v2/feature-flags/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/feature-flags/index.js +1 -0
- package/core/dist/runtime-v2/feature-flags/index.js.map +1 -1
- package/core/dist/runtime-v2/feature-flags/plugin-surface-registry.d.ts +25 -0
- package/core/dist/runtime-v2/feature-flags/plugin-surface-registry.d.ts.map +1 -0
- package/core/dist/runtime-v2/feature-flags/plugin-surface-registry.js +233 -0
- package/core/dist/runtime-v2/feature-flags/plugin-surface-registry.js.map +1 -0
- package/core/dist/runtime-v2/feedback/create-report.d.ts +14 -0
- package/core/dist/runtime-v2/feedback/create-report.d.ts.map +1 -0
- package/core/dist/runtime-v2/feedback/create-report.js +257 -0
- package/core/dist/runtime-v2/feedback/create-report.js.map +1 -0
- package/core/dist/runtime-v2/feedback/feedback-types.d.ts +120 -0
- package/core/dist/runtime-v2/feedback/feedback-types.d.ts.map +1 -0
- package/core/dist/runtime-v2/feedback/feedback-types.js +243 -0
- package/core/dist/runtime-v2/feedback/feedback-types.js.map +1 -0
- package/core/dist/runtime-v2/feedback/index.d.ts +9 -0
- package/core/dist/runtime-v2/feedback/index.d.ts.map +1 -0
- package/core/dist/runtime-v2/feedback/index.js +11 -0
- package/core/dist/runtime-v2/feedback/index.js.map +1 -0
- package/core/dist/runtime-v2/feedback/internal-guards.d.ts +2 -0
- package/core/dist/runtime-v2/feedback/internal-guards.d.ts.map +1 -0
- package/core/dist/runtime-v2/feedback/internal-guards.js +6 -0
- package/core/dist/runtime-v2/feedback/internal-guards.js.map +1 -0
- package/core/dist/runtime-v2/feedback/privacy-preview.d.ts +14 -0
- package/core/dist/runtime-v2/feedback/privacy-preview.d.ts.map +1 -0
- package/core/dist/runtime-v2/feedback/privacy-preview.js +128 -0
- package/core/dist/runtime-v2/feedback/privacy-preview.js.map +1 -0
- package/core/dist/runtime-v2/feedback/redact-sensitive.d.ts +37 -0
- package/core/dist/runtime-v2/feedback/redact-sensitive.d.ts.map +1 -0
- package/core/dist/runtime-v2/feedback/redact-sensitive.js +272 -0
- package/core/dist/runtime-v2/feedback/redact-sensitive.js.map +1 -0
- package/core/dist/runtime-v2/feedback/render-github-url.d.ts +21 -0
- package/core/dist/runtime-v2/feedback/render-github-url.d.ts.map +1 -0
- package/core/dist/runtime-v2/feedback/render-github-url.js +57 -0
- package/core/dist/runtime-v2/feedback/render-github-url.js.map +1 -0
- package/core/dist/runtime-v2/feedback/render-markdown.d.ts +12 -0
- package/core/dist/runtime-v2/feedback/render-markdown.d.ts.map +1 -0
- package/core/dist/runtime-v2/feedback/render-markdown.js +166 -0
- package/core/dist/runtime-v2/feedback/render-markdown.js.map +1 -0
- package/core/dist/runtime-v2/feedback/safe-stringify.d.ts +6 -0
- package/core/dist/runtime-v2/feedback/safe-stringify.d.ts.map +1 -0
- package/core/dist/runtime-v2/feedback/safe-stringify.js +115 -0
- package/core/dist/runtime-v2/feedback/safe-stringify.js.map +1 -0
- package/core/dist/runtime-v2/index.d.ts +6 -1
- package/core/dist/runtime-v2/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/index.js +10 -1
- package/core/dist/runtime-v2/index.js.map +1 -1
- package/core/package.json +4 -0
- package/package.json +1 -1
- package/plugin/dist/commands/context.js +5 -5
- package/plugin/dist/commands/strategy.d.ts +0 -1
- package/plugin/dist/commands/strategy.js +0 -14
- package/plugin/dist/core/runtime-v2-prompt-activation-reader.d.ts +4 -13
- package/plugin/dist/core/runtime-v2-prompt-activation-reader.js +36 -74
- package/plugin/dist/core/surface-guard.d.ts +27 -0
- package/plugin/dist/core/surface-guard.js +82 -0
- package/plugin/dist/hooks/prompt.js +20 -143
- package/plugin/dist/i18n/commands.js +2 -14
- package/plugin/dist/index.d.ts +27 -0
- package/plugin/dist/index.js +174 -55
- package/plugin/dist/service/correction-observer-service.d.ts +11 -0
- package/plugin/dist/service/correction-observer-service.js +172 -0
- package/plugin/dist/service/evolution-worker.js +1 -110
- package/plugin/dist/types.d.ts +2 -2
- package/plugin/dist/types.js +3 -3
- package/plugin/templates/langs/en/core/BOOTSTRAP.md +4 -18
- package/plugin/templates/langs/en/skills/bootstrap-tools/SKILL.md +1 -1
- package/plugin/templates/langs/en/skills/init-strategy/SKILL.md +1 -1
- package/plugin/templates/langs/en/skills/pd-mentor/SKILL.md +8 -23
- package/plugin/templates/langs/zh/core/BOOTSTRAP.md +2 -15
- package/plugin/templates/langs/zh/skills/bootstrap-tools/SKILL.md +1 -1
- package/plugin/templates/langs/zh/skills/init-strategy/SKILL.md +1 -1
- package/plugin/templates/langs/zh/skills/pd-mentor/SKILL.md +7 -22
- package/plugin/templates/langs/en/skills/ai-sprint-orchestration/EXAMPLES.md +0 -63
- package/plugin/templates/langs/en/skills/ai-sprint-orchestration/REFERENCE.md +0 -136
- package/plugin/templates/langs/en/skills/ai-sprint-orchestration/SKILL.md +0 -67
- package/plugin/templates/langs/en/skills/ai-sprint-orchestration/references/agent-registry.json +0 -143
- package/plugin/templates/langs/en/skills/ai-sprint-orchestration/references/specs/bugfix-complex-template.json +0 -107
- package/plugin/templates/langs/en/skills/ai-sprint-orchestration/references/specs/feature-complex-template.json +0 -107
- package/plugin/templates/langs/en/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal-verify.json +0 -95
- package/plugin/templates/langs/en/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal.json +0 -98
- package/plugin/templates/langs/en/skills/ai-sprint-orchestration/references/workflow-v1-acceptance-checklist.md +0 -58
- package/plugin/templates/langs/en/skills/ai-sprint-orchestration/references/workflow-v1.4-work-unit-handoff.md +0 -190
- package/plugin/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/archive.mjs +0 -310
- package/plugin/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/contract-enforcement.mjs +0 -683
- package/plugin/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/decision.mjs +0 -604
- package/plugin/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/state-store.mjs +0 -32
- package/plugin/templates/langs/en/skills/ai-sprint-orchestration/scripts/lib/task-specs.mjs +0 -707
- package/plugin/templates/langs/en/skills/ai-sprint-orchestration/scripts/run.mjs +0 -3455
- package/plugin/templates/langs/en/skills/evolve-system/SKILL.md +0 -46
- package/plugin/templates/langs/en/skills/manage-okr/SKILL.md +0 -96
- package/plugin/templates/langs/en/skills/pd-daily/SKILL.md +0 -199
- package/plugin/templates/langs/en/skills/pd-grooming/SKILL.md +0 -46
- package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/EXAMPLES.md +0 -63
- package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/REFERENCE.md +0 -136
- package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/SKILL.md +0 -67
- package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/references/agent-registry.json +0 -143
- package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/bugfix-complex-template.json +0 -107
- package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/feature-complex-template.json +0 -107
- package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/nocturnal-trinity-quality-enhancement.json +0 -111
- package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal-verify.json +0 -95
- package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/references/specs/workflow-validation-minimal.json +0 -98
- package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/references/workflow-v1-acceptance-checklist.md +0 -58
- package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/references/workflow-v1.4-work-unit-handoff.md +0 -190
- package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/runtime/.gitignore +0 -2
- package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/archive.mjs +0 -310
- package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/contract-enforcement.mjs +0 -683
- package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/decision.mjs +0 -604
- package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/state-store.mjs +0 -32
- package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/scripts/lib/task-specs.mjs +0 -707
- package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/scripts/run.mjs +0 -3455
- package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/test/archive.test.mjs +0 -230
- package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/test/contract-enforcement.test.mjs +0 -672
- package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/test/decision.test.mjs +0 -1321
- package/plugin/templates/langs/zh/skills/ai-sprint-orchestration/test/run.test.mjs +0 -1435
- package/plugin/templates/langs/zh/skills/evolve-system/SKILL.md +0 -46
- package/plugin/templates/langs/zh/skills/manage-okr/SKILL.md +0 -109
- package/plugin/templates/langs/zh/skills/pd-daily/SKILL.md +0 -283
- package/plugin/templates/langs/zh/skills/pd-grooming/SKILL.md +0 -46
package/plugin/dist/index.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import * as path from 'path';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as yaml from 'js-yaml';
|
|
4
|
+
import { computeEffectiveFlags, DEFAULT_FEATURE_FLAGS } from '@principles/core/runtime-v2';
|
|
2
5
|
import { classifyTask } from './core/local-worker-routing.js';
|
|
3
6
|
import { completeShadowObservation, recordShadowRouting } from './core/shadow-observation-registry.js';
|
|
4
7
|
import { getCommandDescription } from './i18n/commands.js';
|
|
@@ -10,7 +13,7 @@ import { handleBeforeReset, handleBeforeCompaction, handleAfterCompaction } from
|
|
|
10
13
|
import { handleLlmOutput } from './hooks/llm.js';
|
|
11
14
|
import { handleSubagentEnded } from './hooks/subagent.js';
|
|
12
15
|
import * as TrajectoryCollector from './hooks/trajectory-collector.js';
|
|
13
|
-
import { handleInitStrategy
|
|
16
|
+
import { handleInitStrategy } from './commands/strategy.js';
|
|
14
17
|
import { handleBootstrapTools, handleResearchTools } from './commands/capabilities.js';
|
|
15
18
|
import { handleThinkingOs } from './commands/thinking-os.js';
|
|
16
19
|
import { handlePainCommand, handlePainReportCommand } from './commands/pain.js';
|
|
@@ -27,6 +30,7 @@ import { handleExportCommand } from './commands/export.js';
|
|
|
27
30
|
import { handleSamplesCommand } from './commands/samples.js';
|
|
28
31
|
import { handleWorkflowDebugCommand } from './commands/workflow-debug.js';
|
|
29
32
|
import { EvolutionWorkerService } from './service/evolution-worker.js';
|
|
33
|
+
import { CorrectionObserverService } from './service/correction-observer-service.js';
|
|
30
34
|
import { TrajectoryService } from './service/trajectory-service.js';
|
|
31
35
|
import { PDTaskService } from './core/pd-task-service.js';
|
|
32
36
|
import { CentralSyncService } from './service/central-sync-service.js';
|
|
@@ -39,6 +43,7 @@ import { resolveCommandWorkspaceDir, resolveToolHookWorkspaceDirSafe } from './u
|
|
|
39
43
|
import { computeRuntimeShadowTaskFingerprint, PD_LOCAL_PROFILES } from './utils/shadow-fingerprint.js';
|
|
40
44
|
import { validateWorkspaceDir } from './core/workspace-dir-validation.js';
|
|
41
45
|
import { resolveWorkspaceDirFromApi } from './core/path-resolver.js';
|
|
46
|
+
import { checkSurfaceGuard, guardHook, guardService } from './core/surface-guard.js';
|
|
42
47
|
// Track started workspaces — one-time init + evolution worker per workspace
|
|
43
48
|
const startedWorkspaces = new Set();
|
|
44
49
|
const HOOK_WORKSPACE_RESOLUTION_NEXT_ACTION = 'verify gateway plugin activation and hook workspace binding; ' +
|
|
@@ -46,6 +51,89 @@ const HOOK_WORKSPACE_RESOLUTION_NEXT_ACTION = 'verify gateway plugin activation
|
|
|
46
51
|
// Map from childSessionKey → shadowObservationId
|
|
47
52
|
// Used to complete shadow observations when subagent ends
|
|
48
53
|
const pendingShadowObservations = new Map();
|
|
54
|
+
// ── Feature Flag Loader (plugin I/O boundary) ─────────────────────────────
|
|
55
|
+
// Reads workspace feature-flags.yaml and checks a specific flag.
|
|
56
|
+
// Returns the flag definition with effective enabled state.
|
|
57
|
+
const DANGEROUS_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
|
|
58
|
+
function isRecord(value) {
|
|
59
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
60
|
+
}
|
|
61
|
+
function loadFeatureFlagFromWorkspace(workspaceDir, flagId, logger) {
|
|
62
|
+
const configPath = path.join(workspaceDir, '.pd', 'feature-flags.yaml');
|
|
63
|
+
if (!fs.existsSync(configPath)) {
|
|
64
|
+
const flags = computeEffectiveFlags({}, DEFAULT_FEATURE_FLAGS, configPath);
|
|
65
|
+
const flag = flags.flags[flagId];
|
|
66
|
+
return { enabled: flag?.enabled ?? false, source: 'defaults' };
|
|
67
|
+
}
|
|
68
|
+
let raw;
|
|
69
|
+
try {
|
|
70
|
+
raw = fs.readFileSync(configPath, 'utf8');
|
|
71
|
+
}
|
|
72
|
+
catch (e) {
|
|
73
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
74
|
+
logger?.warn?.(`[PD:FeatureFlags] Feature flags unreadable: ${msg} — using defaults`);
|
|
75
|
+
const flags = computeEffectiveFlags({}, DEFAULT_FEATURE_FLAGS, configPath);
|
|
76
|
+
const flag = flags.flags[flagId];
|
|
77
|
+
return { enabled: flag?.enabled ?? false, source: 'defaults' };
|
|
78
|
+
}
|
|
79
|
+
let parsed;
|
|
80
|
+
try {
|
|
81
|
+
parsed = yaml.load(raw, { schema: yaml.JSON_SCHEMA });
|
|
82
|
+
}
|
|
83
|
+
catch (e) {
|
|
84
|
+
const parseMsg = e instanceof Error ? e.message : String(e);
|
|
85
|
+
logger?.warn?.(`[PD:FeatureFlags] Feature flags YAML parse error: ${parseMsg} — using defaults`);
|
|
86
|
+
const flags = computeEffectiveFlags({}, DEFAULT_FEATURE_FLAGS, configPath);
|
|
87
|
+
const flag = flags.flags[flagId];
|
|
88
|
+
return { enabled: flag?.enabled ?? false, source: 'defaults' };
|
|
89
|
+
}
|
|
90
|
+
if (!isRecord(parsed)) {
|
|
91
|
+
logger?.warn?.(`[PD:FeatureFlags] Feature flags not a mapping — using defaults`);
|
|
92
|
+
const flags = computeEffectiveFlags({}, DEFAULT_FEATURE_FLAGS, configPath);
|
|
93
|
+
const flag = flags.flags[flagId];
|
|
94
|
+
return { enabled: flag?.enabled ?? false, source: 'defaults' };
|
|
95
|
+
}
|
|
96
|
+
// parsed is now narrowed to Record<string, unknown> by isRecord guard
|
|
97
|
+
const parsedRecord = Object.create(null);
|
|
98
|
+
for (const key of Object.keys(parsed)) {
|
|
99
|
+
if (DANGEROUS_KEYS.has(key))
|
|
100
|
+
continue;
|
|
101
|
+
if (Object.hasOwn(parsed, key)) {
|
|
102
|
+
parsedRecord[key] = parsed[key];
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const flags = computeEffectiveFlags(parsedRecord, DEFAULT_FEATURE_FLAGS, configPath);
|
|
106
|
+
const flag = flags.flags[flagId];
|
|
107
|
+
return { enabled: flag?.enabled ?? false, source: flags.source };
|
|
108
|
+
}
|
|
109
|
+
export function shouldStartEvolutionWorker(workspaceDir, logger) {
|
|
110
|
+
const flag = loadFeatureFlagFromWorkspace(workspaceDir, 'evolution_worker', logger);
|
|
111
|
+
if (flag.enabled) {
|
|
112
|
+
return { shouldStart: true, flagSource: flag.source, disabledInfo: null };
|
|
113
|
+
}
|
|
114
|
+
const disabledInfo = JSON.stringify({
|
|
115
|
+
reason: 'mvp_quiet_per_adr0014',
|
|
116
|
+
nextAction: 'set evolution_worker.enabled=true in .pd/feature-flags.yaml to enable',
|
|
117
|
+
featureFlag: 'evolution_worker',
|
|
118
|
+
boundedContext: 'legacy_evolution_worker',
|
|
119
|
+
flagSource: flag.source,
|
|
120
|
+
});
|
|
121
|
+
return { shouldStart: false, flagSource: flag.source, disabledInfo };
|
|
122
|
+
}
|
|
123
|
+
export function shouldStartCorrectionObserver(workspaceDir, logger) {
|
|
124
|
+
const flag = loadFeatureFlagFromWorkspace(workspaceDir, 'correction_observer', logger);
|
|
125
|
+
if (flag.enabled) {
|
|
126
|
+
return { shouldStart: true, flagSource: flag.source, disabledInfo: null };
|
|
127
|
+
}
|
|
128
|
+
const disabledInfo = JSON.stringify({
|
|
129
|
+
reason: 'correction_observer_disabled',
|
|
130
|
+
nextAction: 'set correction_observer.enabled=true in .pd/feature-flags.yaml to enable',
|
|
131
|
+
featureFlag: 'correction_observer',
|
|
132
|
+
boundedContext: 'correction_observer_service',
|
|
133
|
+
flagSource: flag.source,
|
|
134
|
+
});
|
|
135
|
+
return { shouldStart: false, flagSource: flag.source, disabledInfo };
|
|
136
|
+
}
|
|
49
137
|
const plugin = {
|
|
50
138
|
name: "Principles Disciple",
|
|
51
139
|
description: "Evolutionary programming agent framework with strategic guardrails and reflection loops.",
|
|
@@ -67,9 +155,21 @@ const plugin = {
|
|
|
67
155
|
}
|
|
68
156
|
}, 1000);
|
|
69
157
|
healthCheckTimer.unref(); // Don't keep process alive for health check
|
|
158
|
+
// ── MVP Surface Guard (PRI-289): Verify surface classification ──
|
|
159
|
+
const surfaceGuard = checkSurfaceGuard();
|
|
160
|
+
if (!surfaceGuard.passed) {
|
|
161
|
+
for (const violation of surfaceGuard.violations) {
|
|
162
|
+
api.logger.error(`[PD:surface-guard] VIOLATION: ${violation}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
api.logger.info(`[PD:surface-guard] Core surfaces: ${surfaceGuard.enabledCoreSurfaces.join(', ')}`);
|
|
166
|
+
api.logger.info(`[PD:surface-guard] Disabled non-core surfaces: ${surfaceGuard.disabledNonCoreSurfaces.length}`);
|
|
167
|
+
for (const warning of surfaceGuard.warnings) {
|
|
168
|
+
api.logger.warn(`[PD:surface-guard] ${warning}`);
|
|
169
|
+
}
|
|
70
170
|
const language = api.pluginConfig?.language || 'en';
|
|
71
171
|
// ── Hook: Prompt Building ──
|
|
72
|
-
api.on('before_prompt_build', async (event, ctx) => {
|
|
172
|
+
api.on('before_prompt_build', guardHook('hook:before_prompt_build', api.logger, async (event, ctx) => {
|
|
73
173
|
const workspaceDir = resolveToolHookWorkspaceDirSafe(ctx, api, 'before_prompt_build');
|
|
74
174
|
if (!workspaceDir) {
|
|
75
175
|
api.logger.error(`[PD:before_prompt_build] workspaceDir resolution failed. ` +
|
|
@@ -87,16 +187,39 @@ const plugin = {
|
|
|
87
187
|
ensureWorkspaceTemplates(api, workspaceDir, language);
|
|
88
188
|
SystemLogger.log(workspaceDir, 'SYSTEM_BOOT', `Principles Disciple online. Language: ${language}`);
|
|
89
189
|
// ── Start EvolutionWorker for THIS workspace ──
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
190
|
+
// Gated behind evolution_worker feature flag (MVP-Quiet, default OFF per ADR-0014).
|
|
191
|
+
const gate = shouldStartEvolutionWorker(workspaceDir, api.logger);
|
|
192
|
+
if (gate.shouldStart) {
|
|
193
|
+
EvolutionWorkerService.api = api;
|
|
194
|
+
EvolutionWorkerService.start({
|
|
195
|
+
config: api.config,
|
|
196
|
+
workspaceDir,
|
|
197
|
+
stateDir: path.join(workspaceDir, '.state'),
|
|
198
|
+
logger: api.logger,
|
|
199
|
+
});
|
|
200
|
+
api.logger.info(`[PD] EvolutionWorker started for workspace: ${workspaceDir} (flag source: ${gate.flagSource})`);
|
|
201
|
+
}
|
|
202
|
+
else {
|
|
203
|
+
// Structured observability per ERR-002: no silent skip
|
|
204
|
+
api.logger.info(`[PD] EvolutionWorker NOT started for workspace: ${workspaceDir}. ${gate.disabledInfo}`);
|
|
205
|
+
SystemLogger.log(workspaceDir, 'EVOLUTION_WORKER_DISABLED', gate.disabledInfo ?? '');
|
|
206
|
+
}
|
|
207
|
+
// ── Start CorrectionObserver for THIS workspace ──
|
|
208
|
+
// MVP-Core per ADR-0014 amendment, independently owned (PRI-293).
|
|
209
|
+
const corrGate = shouldStartCorrectionObserver(workspaceDir, api.logger);
|
|
210
|
+
if (corrGate.shouldStart) {
|
|
211
|
+
CorrectionObserverService.start({
|
|
212
|
+
config: api.config,
|
|
213
|
+
workspaceDir,
|
|
214
|
+
stateDir: path.join(workspaceDir, '.state'),
|
|
215
|
+
logger: api.logger,
|
|
216
|
+
});
|
|
217
|
+
api.logger.info(`[PD] CorrectionObserver started for workspace: ${workspaceDir} (flag source: ${corrGate.flagSource})`);
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
api.logger.info(`[PD] CorrectionObserver NOT started for workspace: ${workspaceDir}. ${corrGate.disabledInfo}`);
|
|
221
|
+
SystemLogger.log(workspaceDir, 'CORRECTION_OBSERVER_DISABLED', corrGate.disabledInfo ?? '');
|
|
222
|
+
}
|
|
100
223
|
}
|
|
101
224
|
const result = await handleBeforePromptBuild(event, { ...ctx, api: api, workspaceDir });
|
|
102
225
|
// Record success
|
|
@@ -114,9 +237,9 @@ const plugin = {
|
|
|
114
237
|
});
|
|
115
238
|
api.logger.error(`[PD] Error in before_prompt_build: ${String(err)}`);
|
|
116
239
|
}
|
|
117
|
-
});
|
|
240
|
+
}));
|
|
118
241
|
// ── Hook: Security Gate ──
|
|
119
|
-
api.on('before_tool_call', (event, ctx) => {
|
|
242
|
+
api.on('before_tool_call', guardHook('hook:before_tool_call', api.logger, (event, ctx) => {
|
|
120
243
|
const workspaceDir = resolveToolHookWorkspaceDirSafe(ctx, api, 'before_tool_call');
|
|
121
244
|
if (!workspaceDir) {
|
|
122
245
|
api.logger.error(`[PD:before_tool_call] workspaceDir resolution failed. ` +
|
|
@@ -142,9 +265,9 @@ const plugin = {
|
|
|
142
265
|
}, { flushImmediately: true });
|
|
143
266
|
api.logger.error(`[PD] Error in before_tool_call: ${String(err)}`);
|
|
144
267
|
}
|
|
145
|
-
});
|
|
268
|
+
}));
|
|
146
269
|
// ── Hook: Pain & Trust ──
|
|
147
|
-
api.on('after_tool_call', (event, ctx) => {
|
|
270
|
+
api.on('after_tool_call', guardHook('hook:after_tool_call', api.logger, (event, ctx) => {
|
|
148
271
|
const workspaceDir = resolveToolHookWorkspaceDirSafe(ctx, api, 'after_tool_call');
|
|
149
272
|
if (!workspaceDir) {
|
|
150
273
|
api.logger.error(`[PD:after_tool_call] workspaceDir resolution failed. ` +
|
|
@@ -169,9 +292,9 @@ const plugin = {
|
|
|
169
292
|
}, { flushImmediately: true });
|
|
170
293
|
api.logger.error(`[PD:EmpathyObserver] Error in after_tool_call: ${String(err)}`);
|
|
171
294
|
}
|
|
172
|
-
});
|
|
295
|
+
}));
|
|
173
296
|
// ── Hook: LLM Analysis ──
|
|
174
|
-
api.on('llm_output', (event, ctx) => {
|
|
297
|
+
api.on('llm_output', guardHook('hook:llm_output', api.logger, (event, ctx) => {
|
|
175
298
|
const workspaceDir = resolveToolHookWorkspaceDirSafe(ctx, api, 'llm_output');
|
|
176
299
|
if (!workspaceDir) {
|
|
177
300
|
api.logger.error(`[PD:llm_output] workspaceDir resolution failed. ` +
|
|
@@ -196,10 +319,10 @@ const plugin = {
|
|
|
196
319
|
});
|
|
197
320
|
api.logger.error(`[PD] Error in llm_output: ${String(err)}`);
|
|
198
321
|
}
|
|
199
|
-
});
|
|
322
|
+
}));
|
|
200
323
|
// ── Hook: Trajectory Collection (Behavior Evolution Phase 0) ──
|
|
201
324
|
// Note: after_tool_call and llm_output are safe to collect
|
|
202
|
-
api.on('after_tool_call', (event, ctx) => {
|
|
325
|
+
api.on('after_tool_call', guardHook('hook:after_tool_call.trajectory', api.logger, (event, ctx) => {
|
|
203
326
|
try {
|
|
204
327
|
const workspaceDir = resolveToolHookWorkspaceDirSafe(ctx, api, 'trajectory.after_tool_call');
|
|
205
328
|
if (!workspaceDir)
|
|
@@ -210,8 +333,8 @@ const plugin = {
|
|
|
210
333
|
catch (_err) {
|
|
211
334
|
// Non-critical: don't log, just skip
|
|
212
335
|
}
|
|
213
|
-
});
|
|
214
|
-
api.on('llm_output', (event, ctx) => {
|
|
336
|
+
}));
|
|
337
|
+
api.on('llm_output', guardHook('hook:llm_output.trajectory', api.logger, (event, ctx) => {
|
|
215
338
|
try {
|
|
216
339
|
const workspaceDir = resolveToolHookWorkspaceDirSafe(ctx, api, 'trajectory.llm_output');
|
|
217
340
|
if (!workspaceDir)
|
|
@@ -222,9 +345,9 @@ const plugin = {
|
|
|
222
345
|
catch (_err) {
|
|
223
346
|
// Non-critical: don't log, just skip
|
|
224
347
|
}
|
|
225
|
-
});
|
|
348
|
+
}));
|
|
226
349
|
// ── Hook: Subagent Loop Closure ──
|
|
227
|
-
api.on('subagent_spawning', (event, _ctx) => {
|
|
350
|
+
api.on('subagent_spawning', guardHook('hook:subagent_spawning', api.logger, (event, _ctx) => {
|
|
228
351
|
try {
|
|
229
352
|
// FIX (B): Never fall back to '.' — fail-fast with ERROR log if workspaceDir cannot be resolved.
|
|
230
353
|
// For subagent hooks, we use event.agentId as the target agent for workspace resolution.
|
|
@@ -262,8 +385,8 @@ const plugin = {
|
|
|
262
385
|
api.logger.error(`[PD] Error in subagent_spawning shadow routing: ${String(err)}`);
|
|
263
386
|
return { status: 'ok' }; // Don't block spawn on shadow observation errors
|
|
264
387
|
}
|
|
265
|
-
});
|
|
266
|
-
api.on('subagent_ended', (event, ctx) => {
|
|
388
|
+
}));
|
|
389
|
+
api.on('subagent_ended', guardHook('hook:subagent_ended', api.logger, (event, ctx) => {
|
|
267
390
|
try {
|
|
268
391
|
// FIX (B): Never fall back to '.' — fail-fast with ERROR log if workspaceDir cannot be resolved.
|
|
269
392
|
const workspaceDir = resolveWorkspaceDirFromApi(api, undefined);
|
|
@@ -297,9 +420,9 @@ const plugin = {
|
|
|
297
420
|
catch (err) {
|
|
298
421
|
api.logger.error(`[PD] Error in subagent_ended: ${String(err)}`);
|
|
299
422
|
}
|
|
300
|
-
});
|
|
423
|
+
}));
|
|
301
424
|
// ── Hook: Lifecycle ──
|
|
302
|
-
api.on('before_reset', (event, ctx) => {
|
|
425
|
+
api.on('before_reset', guardHook('hook:before_reset', api.logger, (event, ctx) => {
|
|
303
426
|
const workspaceDir = resolveToolHookWorkspaceDirSafe(ctx, api, 'before_reset');
|
|
304
427
|
if (!workspaceDir) {
|
|
305
428
|
api.logger.error(`[PD:before_reset] workspaceDir resolution failed. ` +
|
|
@@ -308,8 +431,8 @@ const plugin = {
|
|
|
308
431
|
return;
|
|
309
432
|
}
|
|
310
433
|
return handleBeforeReset(event, { ...ctx, workspaceDir });
|
|
311
|
-
});
|
|
312
|
-
api.on('before_compaction', (event, ctx) => {
|
|
434
|
+
}));
|
|
435
|
+
api.on('before_compaction', guardHook('hook:before_compaction', api.logger, (event, ctx) => {
|
|
313
436
|
const workspaceDir = resolveToolHookWorkspaceDirSafe(ctx, api, 'before_compaction');
|
|
314
437
|
if (!workspaceDir) {
|
|
315
438
|
api.logger.error(`[PD:before_compaction] workspaceDir resolution failed. ` +
|
|
@@ -318,8 +441,8 @@ const plugin = {
|
|
|
318
441
|
return;
|
|
319
442
|
}
|
|
320
443
|
return handleBeforeCompaction(event, { ...ctx, workspaceDir });
|
|
321
|
-
});
|
|
322
|
-
api.on('after_compaction', (event, ctx) => {
|
|
444
|
+
}));
|
|
445
|
+
api.on('after_compaction', guardHook('hook:after_compaction', api.logger, (event, ctx) => {
|
|
323
446
|
const workspaceDir = resolveToolHookWorkspaceDirSafe(ctx, api, 'after_compaction');
|
|
324
447
|
if (!workspaceDir) {
|
|
325
448
|
api.logger.error(`[PD:after_compaction] workspaceDir resolution failed. ` +
|
|
@@ -328,17 +451,28 @@ const plugin = {
|
|
|
328
451
|
return;
|
|
329
452
|
}
|
|
330
453
|
return handleAfterCompaction(event, { ...ctx, workspaceDir });
|
|
331
|
-
});
|
|
454
|
+
}));
|
|
332
455
|
// ── Service: Background Evolution Worker ──
|
|
333
456
|
try {
|
|
334
457
|
EvolutionWorkerService.api = api;
|
|
335
|
-
api.
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
api.
|
|
458
|
+
const guardedEvolutionWorker = guardService('service:evolution-worker', EvolutionWorkerService, api.logger);
|
|
459
|
+
if (guardedEvolutionWorker)
|
|
460
|
+
api.registerService(guardedEvolutionWorker);
|
|
461
|
+
const guardedCorrectionObserver = guardService('service:correction-observer', CorrectionObserverService, api.logger);
|
|
462
|
+
if (guardedCorrectionObserver)
|
|
463
|
+
api.registerService(guardedCorrectionObserver);
|
|
464
|
+
const guardedTrajectory = guardService('service:trajectory', TrajectoryService, api.logger);
|
|
465
|
+
if (guardedTrajectory)
|
|
466
|
+
api.registerService(guardedTrajectory);
|
|
467
|
+
const guardedPdTask = guardService('service:pd-task', PDTaskService, api.logger);
|
|
468
|
+
if (guardedPdTask)
|
|
469
|
+
api.registerService(guardedPdTask);
|
|
470
|
+
const guardedCentralSync = guardService('service:central-sync', CentralSyncService, api.logger);
|
|
471
|
+
if (guardedCentralSync)
|
|
472
|
+
api.registerService(guardedCentralSync);
|
|
339
473
|
}
|
|
340
474
|
catch (err) {
|
|
341
|
-
api.logger.error(`[PD] Failed to register
|
|
475
|
+
api.logger.error(`[PD] Failed to register services: ${String(err)}`);
|
|
342
476
|
}
|
|
343
477
|
// ── Slash Commands ──
|
|
344
478
|
// Register command with optional short alias
|
|
@@ -359,20 +493,9 @@ const plugin = {
|
|
|
359
493
|
}
|
|
360
494
|
};
|
|
361
495
|
registerCommandWithAlias('pd-init', 'pdi', getCommandDescription('pd-init', language), (ctx) => handleInitStrategy(ctx));
|
|
362
|
-
registerCommandWithAlias('pd-okr', 'pdk', getCommandDescription('pd-okr', language), (ctx) => handleManageOkr(ctx));
|
|
363
496
|
registerCommandWithAlias('pd-bootstrap', 'pdb', getCommandDescription('pd-bootstrap', language), (ctx) => handleBootstrapTools(ctx));
|
|
364
497
|
registerCommandWithAlias('pd-research', 'pdr', getCommandDescription('pd-research', language), (ctx) => handleResearchTools(ctx));
|
|
365
498
|
registerCommandWithAlias('pd-thinking', 'pdt', getCommandDescription('pd-thinking', language), (ctx) => handleThinkingOs(ctx), { acceptsArgs: true });
|
|
366
|
-
registerCommandWithAlias('pd-daily', 'pdd', getCommandDescription('pd-daily', language), () => ({
|
|
367
|
-
text: language === 'zh'
|
|
368
|
-
? "请执行 pd-daily 技能来配置并发送进化日报。系统将引导你完成配置流程,包括发送时间、渠道和报告风格偏好。"
|
|
369
|
-
: "Please execute the pd-daily skill to configure and send your daily evolution report. The system will guide you through the configuration process."
|
|
370
|
-
}));
|
|
371
|
-
registerCommandWithAlias('pd-grooming', 'pdg', getCommandDescription('pd-grooming', language), () => ({
|
|
372
|
-
text: language === 'zh'
|
|
373
|
-
? "请执行 pd-grooming 技能来执行大扫除。例如输入: '执行 pd-grooming 技能'"
|
|
374
|
-
: "Please execute the pd-grooming skill to clean up. For example: 'Execute pd-grooming skill'"
|
|
375
|
-
}));
|
|
376
499
|
registerCommandWithAlias('pd-help', 'pdh', getCommandDescription('pd-help', language), () => {
|
|
377
500
|
if (language === 'zh') {
|
|
378
501
|
return { text: `
|
|
@@ -388,10 +511,7 @@ const plugin = {
|
|
|
388
511
|
## 状态查询
|
|
389
512
|
| 短命令 | 长命令 | 用途 |
|
|
390
513
|
|--------|--------|------|
|
|
391
|
-
| \`/pdk\` | \`/pd-okr\` | OKR 目标管理 |
|
|
392
514
|
| \`/pdt\` | \`/pd-thinking\` | 思维模型管理 |
|
|
393
|
-
| \`/pdd\` | \`/pd-daily\` | 进化日报 |
|
|
394
|
-
| \`/pdg\` | \`/pd-grooming\` | 工作区清理 |
|
|
395
515
|
|
|
396
516
|
## 其他命令
|
|
397
517
|
| 命令 | 用途 |
|
|
@@ -420,10 +540,7 @@ const plugin = {
|
|
|
420
540
|
## Status
|
|
421
541
|
| Short | Full | Purpose |
|
|
422
542
|
|-------|------|---------|
|
|
423
|
-
| \`/pdk\` | \`/pd-okr\` | OKR goal management |
|
|
424
543
|
| \`/pdt\` | \`/pd-thinking\` | Mental model management |
|
|
425
|
-
| \`/pdd\` | \`/pd-daily\` | Evolution report |
|
|
426
|
-
| \`/pdg\` | \`/pd-grooming\` | Workspace cleanup |
|
|
427
544
|
|
|
428
545
|
## Other Commands
|
|
429
546
|
| Command | Purpose |
|
|
@@ -685,4 +802,6 @@ const plugin = {
|
|
|
685
802
|
}
|
|
686
803
|
};
|
|
687
804
|
export { PrincipleTreeLedgerAdapter } from './core/principle-tree-ledger-adapter.js';
|
|
805
|
+
/* istanbul ignore next — test exports for evolution worker gate */
|
|
806
|
+
export { loadFeatureFlagFromWorkspace, isRecord };
|
|
688
807
|
export default plugin;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { OpenClawPluginServiceContext, PluginLogger } from '../openclaw-sdk.js';
|
|
2
|
+
import { WorkspaceContext } from '../core/workspace-context.js';
|
|
3
|
+
import { CorrectionObserver } from '@principles/core/runtime-v2';
|
|
4
|
+
export interface CorrectionObserverServiceShape {
|
|
5
|
+
id: string;
|
|
6
|
+
start: (ctx: OpenClawPluginServiceContext) => void;
|
|
7
|
+
stop?: (ctx: OpenClawPluginServiceContext) => void;
|
|
8
|
+
}
|
|
9
|
+
export declare function resolveCorrectionObserver(wctx: WorkspaceContext, logger?: Pick<PluginLogger, 'info' | 'warn' | 'error' | 'debug'>): CorrectionObserver | null;
|
|
10
|
+
export declare function runCorrectionObserverCycle(wctx: WorkspaceContext, logger: PluginLogger): Promise<void>;
|
|
11
|
+
export declare const CorrectionObserverService: CorrectionObserverServiceShape;
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { WorkspaceContext } from '../core/workspace-context.js';
|
|
2
|
+
import { TrajectoryRegistry } from '../core/trajectory.js';
|
|
3
|
+
import { CorrectionCueLearner } from '../core/correction-cue-learner.js';
|
|
4
|
+
import { WorkflowFunnelLoader, PiAiRuntimeAdapter, CorrectionObserver, AgentScheduler, } from '@principles/core/runtime-v2';
|
|
5
|
+
import { KeywordOptimizationService } from './keyword-optimization-service.js';
|
|
6
|
+
import { SystemLogger } from '../core/system-logger.js';
|
|
7
|
+
let correctionObserverTimeoutId = null;
|
|
8
|
+
let correctionObserverStopped = false;
|
|
9
|
+
const startedWorkspaces = new Set();
|
|
10
|
+
const CORRECTION_OBSERVER_INTERVAL_MS = 15 * 60 * 1000;
|
|
11
|
+
const CORRECTION_OBSERVER_INITIAL_DELAY_MS = 10_000;
|
|
12
|
+
const CORRECTION_OBSERVER_MAX_RECENT_SESSIONS = 20;
|
|
13
|
+
const CORRECTION_OBSERVER_MAX_PAYLOAD_SESSIONS = 5;
|
|
14
|
+
export function resolveCorrectionObserver(wctx, logger) {
|
|
15
|
+
try {
|
|
16
|
+
const loader = new WorkflowFunnelLoader(wctx.stateDir);
|
|
17
|
+
const funnel = loader.getFunnel('pd-correction-observer');
|
|
18
|
+
const policy = funnel?.policy;
|
|
19
|
+
if (!policy || policy.runtimeKind !== 'pi-ai') {
|
|
20
|
+
logger?.debug?.('[PD:CorrectionObserver] workflows.yaml pd-correction-observer policy not found. Falling back to environment variables.');
|
|
21
|
+
const provider = process.env.PD_CORRECTION_PROVIDER || 'anthropic';
|
|
22
|
+
const model = process.env.PD_CORRECTION_MODEL || 'anthropic/claude-3-5-sonnet';
|
|
23
|
+
const apiKeyEnv = process.env.PD_CORRECTION_API_KEY_ENV || 'ANTHROPIC_API_KEY';
|
|
24
|
+
const baseUrl = process.env.PD_CORRECTION_BASE_URL;
|
|
25
|
+
if (!process.env[apiKeyEnv]) {
|
|
26
|
+
logger?.debug?.(`[PD:CorrectionObserver] API key env ${apiKeyEnv} is not set. Periodic optimization disabled.`);
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
const adapter = new PiAiRuntimeAdapter({
|
|
30
|
+
provider,
|
|
31
|
+
model,
|
|
32
|
+
apiKeyEnv,
|
|
33
|
+
baseUrl,
|
|
34
|
+
workspace: wctx.workspaceDir,
|
|
35
|
+
});
|
|
36
|
+
return new CorrectionObserver({ runtimeAdapter: adapter });
|
|
37
|
+
}
|
|
38
|
+
const adapter = new PiAiRuntimeAdapter({
|
|
39
|
+
provider: String(policy.provider),
|
|
40
|
+
model: String(policy.model),
|
|
41
|
+
apiKeyEnv: String(policy.apiKeyEnv),
|
|
42
|
+
maxRetries: policy.maxRetries,
|
|
43
|
+
timeoutMs: policy.timeoutMs ?? 30_000,
|
|
44
|
+
baseUrl: policy.baseUrl,
|
|
45
|
+
workspace: wctx.workspaceDir,
|
|
46
|
+
});
|
|
47
|
+
return new CorrectionObserver({ runtimeAdapter: adapter }, { timeoutMs: policy.timeoutMs });
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
logger?.warn?.(`[PD:CorrectionObserver] Failed to resolve CorrectionObserver: ${String(err)}`);
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export async function runCorrectionObserverCycle(wctx, logger) {
|
|
55
|
+
try {
|
|
56
|
+
const observer = resolveCorrectionObserver(wctx, logger);
|
|
57
|
+
if (!observer) {
|
|
58
|
+
logger?.info?.('[PD:CorrectionObserver] Observer not resolved (no API key or config). Skipping cycle.');
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
logger?.info?.('[PD:CorrectionObserver] Observer resolved. Initiating periodic optimization...');
|
|
62
|
+
const db = TrajectoryRegistry.get(wctx.workspaceDir);
|
|
63
|
+
const recentSessions = db.listRecentSessions({ limit: CORRECTION_OBSERVER_MAX_RECENT_SESSIONS });
|
|
64
|
+
const recentSessionIds = recentSessions.map(s => s.sessionId);
|
|
65
|
+
if (recentSessionIds.length === 0) {
|
|
66
|
+
logger?.info?.('[PD:CorrectionObserver] No recent sessions found. Skipping correction optimization.');
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const recentMessages = [];
|
|
70
|
+
for (const sId of recentSessionIds.slice(0, CORRECTION_OBSERVER_MAX_PAYLOAD_SESSIONS)) {
|
|
71
|
+
try {
|
|
72
|
+
const turns = db.listUserTurnsForSession(sId);
|
|
73
|
+
for (const t of turns) {
|
|
74
|
+
if (t.rawExcerpt) {
|
|
75
|
+
recentMessages.push(t.rawExcerpt);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
catch (turnErr) {
|
|
80
|
+
logger?.warn?.(`[PD:CorrectionObserver] Failed to load user turns for session ${sId}: ${String(turnErr)}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const learner = CorrectionCueLearner.get(wctx.stateDir);
|
|
84
|
+
const keywords = learner.getStore().keywords;
|
|
85
|
+
const keywordStoreSummary = {
|
|
86
|
+
totalKeywords: keywords.length,
|
|
87
|
+
terms: keywords.map(k => ({
|
|
88
|
+
term: k.term,
|
|
89
|
+
weight: k.weight,
|
|
90
|
+
hitCount: k.hitCount ?? 0,
|
|
91
|
+
truePositiveCount: k.truePositiveCount ?? 0,
|
|
92
|
+
falsePositiveCount: k.falsePositiveCount ?? 0,
|
|
93
|
+
})),
|
|
94
|
+
};
|
|
95
|
+
const optimizationService = KeywordOptimizationService.get(wctx.stateDir, wctx.workspaceDir, logger);
|
|
96
|
+
const trajectoryHistory = await optimizationService.buildTrajectoryHistory(recentSessionIds);
|
|
97
|
+
const payload = {
|
|
98
|
+
parentSessionId: 'correction-observer-service',
|
|
99
|
+
workspaceDir: wctx.workspaceDir,
|
|
100
|
+
keywordStoreSummary,
|
|
101
|
+
recentMessages,
|
|
102
|
+
trajectoryHistory,
|
|
103
|
+
};
|
|
104
|
+
const scheduler = new AgentScheduler();
|
|
105
|
+
scheduler.register({
|
|
106
|
+
agentId: 'correction-observer',
|
|
107
|
+
mode: 'realtime',
|
|
108
|
+
runner: observer,
|
|
109
|
+
});
|
|
110
|
+
logger?.info?.(`[PD:CorrectionObserver] Dispatching with ${trajectoryHistory.length} trajectory events, ${recentMessages.length} recent messages.`);
|
|
111
|
+
const result = await scheduler.dispatch('correction-observer', payload);
|
|
112
|
+
logger?.info?.(`[PD:CorrectionObserver] Completed: updated=${result.updated}, summary="${result.summary}"`);
|
|
113
|
+
if (result.updated) {
|
|
114
|
+
optimizationService.applyResult(result);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
const errMsg = `Correction observer cycle failed: ${String(err)}`;
|
|
119
|
+
logger?.warn?.(`[PD:CorrectionObserver] ${errMsg}`);
|
|
120
|
+
SystemLogger.log(wctx.workspaceDir, 'CORRECTION_OBSERVER_CYCLE_FAILED', errMsg);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
export const CorrectionObserverService = {
|
|
124
|
+
id: 'principles-correction-observer',
|
|
125
|
+
start(ctx) {
|
|
126
|
+
const workspaceDir = ctx?.workspaceDir;
|
|
127
|
+
const logger = ctx?.logger || console;
|
|
128
|
+
if (!workspaceDir) {
|
|
129
|
+
if (logger)
|
|
130
|
+
logger.warn('[PD:CorrectionObserver] workspaceDir not found in service config. Correction observer disabled.');
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
if (startedWorkspaces.has(workspaceDir)) {
|
|
134
|
+
if (logger)
|
|
135
|
+
logger.info(`[PD:CorrectionObserver] Already started for workspace: ${workspaceDir}. Skipping duplicate start.`);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
startedWorkspaces.add(workspaceDir);
|
|
139
|
+
correctionObserverStopped = false;
|
|
140
|
+
const wctx = WorkspaceContext.fromHookContext({ workspaceDir, ...ctx.config });
|
|
141
|
+
if (logger)
|
|
142
|
+
logger.info(`[PD:CorrectionObserver] Starting with workspaceDir=${wctx.workspaceDir}, stateDir=${wctx.stateDir}`);
|
|
143
|
+
const interval = CORRECTION_OBSERVER_INTERVAL_MS;
|
|
144
|
+
async function runCycle() {
|
|
145
|
+
if (correctionObserverStopped)
|
|
146
|
+
return;
|
|
147
|
+
await runCorrectionObserverCycle(wctx, logger);
|
|
148
|
+
if (correctionObserverStopped)
|
|
149
|
+
return;
|
|
150
|
+
correctionObserverTimeoutId = setTimeout(runCycle, interval);
|
|
151
|
+
correctionObserverTimeoutId.unref();
|
|
152
|
+
}
|
|
153
|
+
correctionObserverTimeoutId = setTimeout(() => {
|
|
154
|
+
void runCycle().catch((err) => {
|
|
155
|
+
if (logger)
|
|
156
|
+
logger.error(`[PD:CorrectionObserver] Startup cycle failed: ${String(err)}`);
|
|
157
|
+
if (correctionObserverStopped)
|
|
158
|
+
return;
|
|
159
|
+
correctionObserverTimeoutId = setTimeout(runCycle, interval);
|
|
160
|
+
correctionObserverTimeoutId.unref();
|
|
161
|
+
});
|
|
162
|
+
}, CORRECTION_OBSERVER_INITIAL_DELAY_MS);
|
|
163
|
+
correctionObserverTimeoutId.unref();
|
|
164
|
+
},
|
|
165
|
+
stop(_ctx) {
|
|
166
|
+
correctionObserverStopped = true;
|
|
167
|
+
startedWorkspaces.clear();
|
|
168
|
+
if (correctionObserverTimeoutId)
|
|
169
|
+
clearTimeout(correctionObserverTimeoutId);
|
|
170
|
+
correctionObserverTimeoutId = null;
|
|
171
|
+
},
|
|
172
|
+
};
|