principles-disciple 1.11.0 → 1.13.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/CHANGELOG.md +26 -0
- package/README.md +66 -0
- package/esbuild.config.js +1 -1
- package/openclaw.plugin.json +4 -4
- package/package.json +2 -3
- package/run-nocturnal.mjs +30 -0
- package/scripts/db-migrate.mjs +170 -0
- package/scripts/sync-plugin.mjs +250 -6
- package/src/commands/archive-impl.ts +136 -0
- package/src/commands/capabilities.ts +4 -2
- package/src/commands/context.ts +5 -1
- package/src/commands/disable-impl.ts +151 -0
- package/src/commands/evolution-status.ts +64 -19
- package/src/commands/export.ts +8 -6
- package/src/commands/focus.ts +8 -20
- package/src/commands/nocturnal-review.ts +5 -7
- package/src/commands/nocturnal-rollout.ts +1 -12
- package/src/commands/nocturnal-train.ts +21 -47
- package/src/commands/pain.ts +10 -5
- package/src/commands/principle-rollback.ts +4 -2
- package/src/commands/promote-impl.ts +274 -0
- package/src/commands/rollback-impl.ts +234 -0
- package/src/commands/rollback.ts +6 -3
- package/src/commands/samples.ts +2 -0
- package/src/commands/thinking-os.ts +3 -4
- package/src/commands/workflow-debug.ts +2 -1
- package/src/config/errors.ts +1 -0
- package/src/core/AGENTS.md +34 -0
- package/src/core/adaptive-thresholds.ts +4 -3
- package/src/core/code-implementation-storage.ts +241 -0
- package/src/core/config.ts +5 -2
- package/src/core/control-ui-db.ts +29 -10
- package/src/core/detection-funnel.ts +12 -7
- package/src/core/diagnostician-task-store.ts +156 -0
- package/src/core/dictionary.ts +4 -4
- package/src/core/empathy-keyword-matcher.ts +7 -3
- package/src/core/empathy-types.ts +13 -2
- package/src/core/event-log.ts +14 -6
- package/src/core/evolution-engine.ts +27 -31
- package/src/core/evolution-logger.ts +3 -2
- package/src/core/evolution-reducer.ts +110 -31
- package/src/core/evolution-types.ts +10 -0
- package/src/core/external-training-contract.ts +1 -0
- package/src/core/focus-history.ts +38 -24
- package/src/core/hygiene/tracker.ts +10 -6
- package/src/core/init.ts +5 -2
- package/src/core/migration.ts +3 -3
- package/src/core/model-deployment-registry.ts +6 -4
- package/src/core/model-training-registry.ts +5 -3
- package/src/core/nocturnal-arbiter.ts +13 -14
- package/src/core/nocturnal-artifact-lineage.ts +117 -0
- package/src/core/nocturnal-artificer.ts +257 -0
- package/src/core/nocturnal-candidate-scoring.ts +4 -2
- package/src/core/nocturnal-compliance.ts +67 -19
- package/src/core/nocturnal-dataset.ts +95 -2
- package/src/core/nocturnal-executability.ts +2 -3
- package/src/core/nocturnal-export.ts +6 -3
- package/src/core/nocturnal-rule-implementation-validator.ts +245 -0
- package/src/core/nocturnal-trajectory-extractor.ts +10 -3
- package/src/core/nocturnal-trinity.ts +319 -61
- package/src/core/pain-context-extractor.ts +29 -15
- package/src/core/pain.ts +7 -5
- package/src/core/path-resolver.ts +16 -15
- package/src/core/paths.ts +2 -1
- package/src/core/pd-task-reconciler.ts +463 -0
- package/src/core/pd-task-service.ts +42 -0
- package/src/core/pd-task-store.ts +77 -0
- package/src/core/pd-task-types.ts +128 -0
- package/src/core/principle-internalization/deprecated-readiness.ts +91 -0
- package/src/core/principle-internalization/internalization-routing-policy.ts +208 -0
- package/src/core/principle-internalization/lifecycle-metrics.ts +149 -0
- package/src/core/principle-internalization/lifecycle-read-model.ts +243 -0
- package/src/core/principle-internalization/lifecycle-refresh.ts +11 -0
- package/src/core/principle-internalization/principle-lifecycle-service.ts +167 -0
- package/src/core/principle-training-state.ts +95 -370
- package/src/core/principle-tree-ledger.ts +733 -0
- package/src/core/principle-tree-migration.ts +195 -0
- package/src/core/profile.ts +3 -1
- package/src/core/promotion-gate.ts +14 -18
- package/src/core/replay-engine.ts +562 -0
- package/src/core/risk-calculator.ts +6 -4
- package/src/core/rule-host-helpers.ts +39 -0
- package/src/core/rule-host-types.ts +82 -0
- package/src/core/rule-host.ts +245 -0
- package/src/core/rule-implementation-runtime.ts +38 -0
- package/src/core/schema/db-types.ts +16 -0
- package/src/core/schema/index.ts +26 -0
- package/src/core/schema/migration-runner.ts +207 -0
- package/src/core/schema/migrations/001-init-trajectory.ts +211 -0
- package/src/core/schema/migrations/002-init-central.ts +122 -0
- package/src/core/schema/migrations/003-init-workflow.ts +55 -0
- package/src/core/schema/migrations/004-add-thinking-and-gfi.ts +74 -0
- package/src/core/schema/migrations/index.ts +31 -0
- package/src/core/schema/schema-definitions.ts +650 -0
- package/src/core/session-tracker.ts +6 -4
- package/src/core/shadow-observation-registry.ts +6 -3
- package/src/core/system-logger.ts +2 -2
- package/src/core/thinking-models.ts +182 -46
- package/src/core/thinking-os-parser.ts +156 -0
- package/src/core/training-program.ts +7 -7
- package/src/core/trajectory.ts +42 -36
- package/src/core/workspace-context.ts +77 -11
- package/src/core/workspace-dir-validation.ts +152 -0
- package/src/hooks/AGENTS.md +31 -0
- package/src/hooks/bash-risk.ts +3 -1
- package/src/hooks/edit-verification.ts +9 -5
- package/src/hooks/gate-block-helper.ts +5 -1
- package/src/hooks/gate.ts +152 -5
- package/src/hooks/gfi-gate.ts +9 -2
- package/src/hooks/lifecycle-routing.ts +124 -0
- package/src/hooks/lifecycle.ts +12 -12
- package/src/hooks/llm.ts +17 -109
- package/src/hooks/message-sanitize.ts +5 -3
- package/src/hooks/pain.ts +19 -15
- package/src/hooks/progressive-trust-gate.ts +7 -1
- package/src/hooks/prompt.ts +169 -60
- package/src/hooks/subagent.ts +5 -4
- package/src/hooks/thinking-checkpoint.ts +2 -0
- package/src/hooks/trajectory-collector.ts +15 -12
- package/src/http/principles-console-route.ts +31 -68
- package/src/i18n/commands.ts +2 -2
- package/src/index.ts +130 -40
- package/src/service/central-database.ts +131 -43
- package/src/service/central-health-service.ts +47 -0
- package/src/service/central-overview-service.ts +135 -0
- package/src/service/central-sync-service.ts +87 -0
- package/src/service/control-ui-query-service.ts +46 -36
- package/src/service/event-log-auditor.ts +261 -0
- package/src/service/evolution-query-service.ts +23 -22
- package/src/service/evolution-worker.ts +565 -261
- package/src/service/health-query-service.ts +213 -36
- package/src/service/nocturnal-runtime.ts +8 -4
- package/src/service/nocturnal-service.ts +503 -59
- package/src/service/nocturnal-target-selector.ts +5 -7
- package/src/service/runtime-summary-service.ts +2 -1
- package/src/service/subagent-workflow/deep-reflect-workflow-manager.ts +25 -336
- package/src/service/subagent-workflow/dynamic-timeout.ts +30 -0
- package/src/service/subagent-workflow/empathy-observer-workflow-manager.ts +48 -386
- package/src/service/subagent-workflow/index.ts +2 -0
- package/src/service/subagent-workflow/nocturnal-workflow-manager.ts +169 -284
- package/src/service/subagent-workflow/runtime-direct-driver.ts +114 -16
- package/src/service/subagent-workflow/subagent-error-utils.ts +25 -0
- package/src/service/subagent-workflow/types.ts +9 -4
- package/src/service/subagent-workflow/workflow-manager-base.ts +573 -0
- package/src/service/subagent-workflow/workflow-store.ts +71 -11
- package/src/service/trajectory-service.ts +2 -1
- package/src/tools/critique-prompt.ts +1 -1
- package/src/tools/deep-reflect.ts +175 -209
- package/src/tools/model-index.ts +2 -1
- package/src/types/event-types.ts +2 -2
- package/src/types/principle-tree-schema.ts +29 -23
- package/src/utils/file-lock.ts +5 -3
- package/src/utils/io.ts +5 -2
- package/src/utils/nlp.ts +5 -46
- package/src/utils/node-vm-polyfill.ts +11 -0
- package/src/utils/plugin-logger.ts +2 -0
- package/src/utils/retry.ts +572 -0
- package/src/utils/subagent-probe.ts +1 -1
- package/templates/langs/en/core/AGENTS.md +0 -13
- package/templates/langs/en/core/SOUL.md +1 -31
- package/templates/langs/en/core/TOOLS.md +0 -4
- package/templates/langs/en/principles/THINKING_OS.md +77 -0
- package/templates/langs/en/skills/admin/SKILL.md +0 -1
- package/templates/langs/en/skills/evolution-framework-update/SKILL.md +1 -1
- package/templates/langs/en/skills/pd-diagnostician/SKILL.md +18 -5
- package/templates/langs/zh/core/AGENTS.md +0 -22
- package/templates/langs/zh/core/SOUL.md +1 -31
- package/templates/langs/zh/core/TOOLS.md +0 -4
- package/templates/langs/zh/principles/THINKING_OS.md +77 -0
- package/templates/langs/zh/skills/admin/SKILL.md +0 -1
- package/templates/langs/zh/skills/evolution-framework-update/SKILL.md +1 -1
- package/templates/langs/zh/skills/pd-diagnostician/SKILL.md +25 -4
- package/tests/commands/evolution-status.test.ts +119 -0
- package/tests/commands/implementation-lifecycle.test.ts +362 -0
- package/tests/core/code-implementation-storage.test.ts +398 -0
- package/tests/core/evolution-reducer.detector-metadata.test.ts +28 -28
- package/tests/core/nocturnal-artifact-lineage.test.ts +53 -0
- package/tests/core/nocturnal-artificer.test.ts +241 -0
- package/tests/core/nocturnal-compliance-p-principles.test.ts +133 -0
- package/tests/core/nocturnal-rule-implementation-validator.test.ts +127 -0
- package/tests/core/pd-task-store.test.ts +126 -0
- package/tests/core/principle-internalization/deprecated-readiness.test.ts +193 -0
- package/tests/core/principle-internalization/internalization-routing-policy.test.ts +212 -0
- package/tests/core/principle-internalization/lifecycle-metrics.test.ts +350 -0
- package/tests/core/principle-internalization/principle-lifecycle-service.test.ts +211 -0
- package/tests/core/principle-training-state.test.ts +228 -1
- package/tests/core/principle-tree-ledger.test.ts +423 -0
- package/tests/core/regression-v1-9-1.test.ts +265 -0
- package/tests/core/replay-engine.test.ts +234 -0
- package/tests/core/rule-host-helpers.test.ts +120 -0
- package/tests/core/rule-host.test.ts +389 -0
- package/tests/core/rule-implementation-runtime.test.ts +64 -0
- package/tests/core/workspace-context.test.ts +53 -0
- package/tests/core/workspace-dir-validation.test.ts +272 -0
- package/tests/hooks/gate-rule-host-pipeline.test.ts +385 -0
- package/tests/hooks/pain.test.ts +74 -10
- package/tests/hooks/prompt.test.ts +63 -1
- package/tests/integration/principle-lifecycle.e2e.test.ts +197 -0
- package/tests/integration/tool-hooks-workspace-dir.e2e.test.ts +211 -0
- package/tests/service/data-endpoints-regression.test.ts +834 -0
- package/tests/service/evolution-worker.test.ts +0 -123
- package/tests/service/nocturnal-service-code-candidate.test.ts +330 -0
- package/tests/utils/nlp.test.ts +1 -19
- package/tests/utils/retry.test.ts +327 -0
- package/ui/src/App.tsx +1 -1
- package/ui/src/api.ts +4 -0
- package/ui/src/charts.tsx +366 -0
- package/ui/src/components/WorkspaceConfig.tsx +107 -75
- package/ui/src/i18n/ui.ts +89 -31
- package/ui/src/pages/EvolutionPage.tsx +1 -1
- package/ui/src/pages/OverviewPage.tsx +441 -81
- package/ui/src/pages/ThinkingModelsPage.tsx +287 -69
- package/ui/src/styles.css +43 -0
- package/ui/src/types.ts +17 -1
- package/src/agents/nocturnal-dreamer.md +0 -152
- package/src/agents/nocturnal-philosopher.md +0 -138
- package/src/agents/nocturnal-reflector.md +0 -126
- package/src/agents/nocturnal-scribe.md +0 -164
- package/templates/workspace/.principles/00-kernel.md +0 -51
- package/templates/workspace/.principles/DECISION_POLICY.json +0 -44
- package/templates/workspace/.principles/PRINCIPLES.md +0 -20
- package/templates/workspace/.principles/PROFILE.json +0 -54
- package/templates/workspace/.principles/PROFILE.schema.json +0 -56
- package/templates/workspace/.principles/THINKING_OS.md +0 -64
- package/templates/workspace/.principles/THINKING_OS_ARCHIVE.md +0 -7
- package/templates/workspace/.principles/THINKING_OS_CANDIDATES.md +0 -9
- package/templates/workspace/.principles/models/_INDEX.md +0 -27
- package/templates/workspace/.principles/models/first_principles.md +0 -62
- package/templates/workspace/.principles/models/marketing_4p.md +0 -52
- package/templates/workspace/.principles/models/porter_five.md +0 -63
- package/templates/workspace/.principles/models/swot.md +0 -60
- package/templates/workspace/.principles/models/user_story_map.md +0 -63
- package/templates/workspace/.state/WORKBOARD.json +0 -4
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Archive Implementation Command — CLI `/pd-archive-impl`
|
|
3
|
+
* ========================================================
|
|
4
|
+
*
|
|
5
|
+
* PURPOSE: Permanently archive an implementation (disabled -> archived,
|
|
6
|
+
* active -> archived, or candidate -> archived).
|
|
7
|
+
*
|
|
8
|
+
* Used for permanent cleanup of implementations that are no longer relevant.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { WorkspaceContext } from '../core/workspace-context.js';
|
|
12
|
+
import { refreshPrincipleLifecycle } from '../core/principle-internalization/lifecycle-refresh.js';
|
|
13
|
+
import {
|
|
14
|
+
loadLedger,
|
|
15
|
+
transitionImplementationState,
|
|
16
|
+
updateImplementation,
|
|
17
|
+
} from '../core/principle-tree-ledger.js';
|
|
18
|
+
import type { Implementation, ImplementationLifecycleState } from '../types/principle-tree-schema.js';
|
|
19
|
+
import type { PluginCommandContext, PluginCommandResult } from '../openclaw-sdk.js';
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Get all implementations from the ledger.
|
|
23
|
+
*/
|
|
24
|
+
function getAllImplementations(stateDir: string): Implementation[] {
|
|
25
|
+
const ledger = loadLedger(stateDir);
|
|
26
|
+
return Object.values(ledger.tree.implementations);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Valid archive transitions: disabled -> archived, active -> archived, candidate -> archived
|
|
31
|
+
*/
|
|
32
|
+
function canArchive(state: ImplementationLifecycleState): boolean {
|
|
33
|
+
return ['disabled', 'active', 'candidate'].includes(state);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Handle the /pd-archive-impl command.
|
|
38
|
+
*
|
|
39
|
+
* Usage:
|
|
40
|
+
* /pd-archive-impl <implId> - Archive an implementation
|
|
41
|
+
* /pd-archive-impl list - List archivable implementations
|
|
42
|
+
*/
|
|
43
|
+
export function handleArchiveImplCommand(ctx: PluginCommandContext): PluginCommandResult {
|
|
44
|
+
const workspaceDir = (ctx.config?.workspaceDir as string) || process.cwd();
|
|
45
|
+
const {stateDir} = WorkspaceContext.fromHookContext({ ...ctx, workspaceDir });
|
|
46
|
+
const lang = (ctx.config?.language as string) || 'en';
|
|
47
|
+
const isZh = lang === 'zh';
|
|
48
|
+
|
|
49
|
+
const args = (ctx.args || '').trim().split(/\s+/);
|
|
50
|
+
const subcommand = args[0] || '';
|
|
51
|
+
|
|
52
|
+
// Subcommand: list
|
|
53
|
+
if (subcommand === 'list') {
|
|
54
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define -- Reason: Mutual recursion between helper functions - reordering would break logical grouping
|
|
55
|
+
return _handleListArchivable(stateDir, isZh);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Archive by ID
|
|
59
|
+
const targetId = subcommand;
|
|
60
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define -- Reason: Mutual recursion between helper functions - reordering would break logical grouping
|
|
61
|
+
return _handleArchiveImpl(workspaceDir, stateDir, targetId, isZh);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function _handleListArchivable(
|
|
65
|
+
stateDir: string,
|
|
66
|
+
isZh: boolean
|
|
67
|
+
): PluginCommandResult {
|
|
68
|
+
const allImpls = getAllImplementations(stateDir);
|
|
69
|
+
const archivable = allImpls.filter(
|
|
70
|
+
(impl) => canArchive(impl.lifecycleState || 'candidate')
|
|
71
|
+
);
|
|
72
|
+
|
|
73
|
+
if (archivable.length === 0) {
|
|
74
|
+
return {
|
|
75
|
+
text: isZh
|
|
76
|
+
? '\n\u2139\ufe0f \u6ca1\u6709\u53ef\u5f52\u6863\u7684\u5b9e\u73b0\u3002'
|
|
77
|
+
: '\n\u2139\ufe0f No implementations available to archive.',
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
let output = isZh ? '\n\ud83d\udccb \u53ef\u5f52\u6863\u5b9e\u73b0\n' : '\n\ud83d\udccb Available Implementations to Archive\n';
|
|
82
|
+
output += `${'='.repeat(50)}\n`;
|
|
83
|
+
|
|
84
|
+
for (const impl of archivable) {
|
|
85
|
+
const stateLabel = impl.lifecycleState || 'candidate';
|
|
86
|
+
output += ` ${impl.id}\n`;
|
|
87
|
+
output += ` Rule: ${impl.ruleId} | State: ${stateLabel}\n\n`;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
output += isZh
|
|
91
|
+
? '\u7528\u6cd5: /pd-archive-impl <implId>'
|
|
92
|
+
: 'Usage: /pd-archive-impl <implId>';
|
|
93
|
+
|
|
94
|
+
return { text: output };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// eslint-disable-next-line @typescript-eslint/max-params -- Reason: Command handler signature must match OpenClaw plugin interface - breaking API change to options objects would affect public contracts
|
|
98
|
+
function _handleArchiveImpl(
|
|
99
|
+
workspaceDir: string,
|
|
100
|
+
stateDir: string,
|
|
101
|
+
implId: string,
|
|
102
|
+
isZh: boolean
|
|
103
|
+
): PluginCommandResult {
|
|
104
|
+
const allImpls = getAllImplementations(stateDir);
|
|
105
|
+
const target = allImpls.find((i) => i.id === implId);
|
|
106
|
+
|
|
107
|
+
if (!target) {
|
|
108
|
+
return {
|
|
109
|
+
text: isZh
|
|
110
|
+
? `\u274c \u672a\u627e\u5230\u5b9e\u73b0: ${implId}`
|
|
111
|
+
: `\u274c Implementation not found: ${implId}`,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const currentState = target.lifecycleState || 'candidate';
|
|
116
|
+
|
|
117
|
+
if (!canArchive(currentState)) {
|
|
118
|
+
return {
|
|
119
|
+
text: isZh
|
|
120
|
+
? `\u274c \u5b9e\u73b0 ${implId} \u4e0d\u80fd\u4ece ${currentState} \u5f52\u6863\u3002\u5df2\u5f52\u6863\u7684\u5b9e\u73b0\u4e0d\u80fd\u518d\u6b21\u5f52\u6863\u3002`
|
|
121
|
+
: `\u274c Implementation ${implId} cannot be archived from state: ${currentState}. Archived implementations cannot be archived again.`,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
transitionImplementationState(stateDir, implId, 'archived');
|
|
126
|
+
updateImplementation(stateDir, implId, {
|
|
127
|
+
archivedAt: new Date().toISOString(),
|
|
128
|
+
});
|
|
129
|
+
refreshPrincipleLifecycle(workspaceDir, stateDir);
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
text: isZh
|
|
133
|
+
? `\n\u2705 \u5b9e\u73b0\u5df2\u5f52\u6863: ${implId}\n \u72b6\u6001: ${currentState} -> archived`
|
|
134
|
+
: `\n\u2705 Implementation archived: ${implId}\n State: ${currentState} -> archived`,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
@@ -13,16 +13,18 @@ const TOOLS_TO_SCAN = [
|
|
|
13
13
|
{ name: 'shellcheck', cmd: ['shellcheck', '--version'] },
|
|
14
14
|
];
|
|
15
15
|
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Reason: third-party API execSync returns dynamic output - type structure unknown at call site
|
|
16
17
|
function scanEnvironment(wctx: WorkspaceContext): any {
|
|
17
18
|
const tools: Record<string, { available: boolean; version?: string }> = {};
|
|
18
19
|
|
|
19
20
|
for (const tool of TOOLS_TO_SCAN) {
|
|
20
21
|
try {
|
|
21
|
-
const
|
|
22
|
+
const [versionLine] = execSync(tool.cmd.join(' '), { stdio: ['ignore', 'pipe', 'ignore'] }).toString().split('\n');
|
|
22
23
|
tools[tool.name] = {
|
|
23
24
|
available: true,
|
|
24
|
-
version:
|
|
25
|
+
version: versionLine.trim(),
|
|
25
26
|
};
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars -- Reason: catch parameter intentionally unused - we only care that the command failed
|
|
26
28
|
} catch (_e) {
|
|
27
29
|
tools[tool.name] = { available: false };
|
|
28
30
|
}
|
package/src/commands/context.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
3
|
import type { PluginCommandContext, PluginCommandResult } from '../openclaw-sdk.js';
|
|
4
|
-
import { ContextInjectionConfig
|
|
4
|
+
import type { ContextInjectionConfig} from '../types.js';
|
|
5
|
+
import { defaultContextConfig } from '../types.js';
|
|
5
6
|
import { loadContextInjectionConfig } from '../hooks/prompt.js';
|
|
6
7
|
|
|
7
8
|
/**
|
|
@@ -97,6 +98,7 @@ function showStatus(workspaceDir: string, isZh: boolean): string {
|
|
|
97
98
|
/**
|
|
98
99
|
* Toggle a boolean setting
|
|
99
100
|
*/
|
|
101
|
+
// eslint-disable-next-line @typescript-eslint/max-params -- Reason: Command handler signature requires specific params - refactoring would break public API contract
|
|
100
102
|
function toggleSetting(
|
|
101
103
|
workspaceDir: string,
|
|
102
104
|
key: 'thinkingOs' | 'reflectionLog',
|
|
@@ -211,6 +213,7 @@ function applyPreset(
|
|
|
211
213
|
preset: 'minimal' | 'standard' | 'full',
|
|
212
214
|
isZh: boolean
|
|
213
215
|
): string {
|
|
216
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations -- Reason: assigned in switch block immediately after declaration
|
|
214
217
|
let config: ContextInjectionConfig;
|
|
215
218
|
|
|
216
219
|
switch (preset) {
|
|
@@ -311,6 +314,7 @@ export function handleContextCommand(ctx: PluginCommandContext): PluginCommandRe
|
|
|
311
314
|
// Detect language from context
|
|
312
315
|
const isZh = (ctx.config?.language as string) === 'zh';
|
|
313
316
|
|
|
317
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations -- Reason: assigned in switch block immediately after declaration
|
|
314
318
|
let result: string;
|
|
315
319
|
|
|
316
320
|
switch (subCommand) {
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Disable Implementation Command — CLI `/pd-disable-impl`
|
|
3
|
+
* ========================================================
|
|
4
|
+
*
|
|
5
|
+
* PURPOSE: Manually disable an active implementation (e.g., regression in production).
|
|
6
|
+
*
|
|
7
|
+
* FLOW:
|
|
8
|
+
* 1. List active implementations
|
|
9
|
+
* 2. Select target, ask for reason
|
|
10
|
+
* 3. Transition active -> disabled (or candidate -> disabled)
|
|
11
|
+
* 4. Record disabledAt, disabledBy, disabledReason
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { WorkspaceContext } from '../core/workspace-context.js';
|
|
15
|
+
import { refreshPrincipleLifecycle } from '../core/principle-internalization/lifecycle-refresh.js';
|
|
16
|
+
import {
|
|
17
|
+
loadLedger,
|
|
18
|
+
transitionImplementationState,
|
|
19
|
+
updateImplementation,
|
|
20
|
+
getAllowedTransitions,
|
|
21
|
+
} from '../core/principle-tree-ledger.js';
|
|
22
|
+
import type { Implementation, ImplementationLifecycleState } from '../types/principle-tree-schema.js';
|
|
23
|
+
import type { PluginCommandContext, PluginCommandResult } from '../openclaw-sdk.js';
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Get all implementations from the ledger.
|
|
27
|
+
*/
|
|
28
|
+
function getAllImplementations(stateDir: string): Implementation[] {
|
|
29
|
+
const ledger = loadLedger(stateDir);
|
|
30
|
+
return Object.values(ledger.tree.implementations);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function _handleListActive(
|
|
34
|
+
stateDir: string,
|
|
35
|
+
isZh: boolean
|
|
36
|
+
): PluginCommandResult {
|
|
37
|
+
const allImpls = getAllImplementations(stateDir);
|
|
38
|
+
const activeImpls = allImpls.filter(
|
|
39
|
+
(impl) => impl.lifecycleState === 'active' || impl.lifecycleState === 'candidate'
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
if (activeImpls.length === 0) {
|
|
43
|
+
return {
|
|
44
|
+
text: isZh
|
|
45
|
+
? '\n\u2139\ufe0f \u6ca1\u6709\u53ef\u7981\u7528\u7684\u5b9e\u73b0\u3002'
|
|
46
|
+
: '\n\u2139\ufe0f No implementations available to disable.',
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let output = isZh
|
|
51
|
+
? '\n\ud83d\udccb \u53ef\u7981\u7528\u5b9e\u73b0\n'
|
|
52
|
+
: '\n\ud83d\udccb Available Implementations to Disable\n';
|
|
53
|
+
output += `${'='.repeat(50)}\n`;
|
|
54
|
+
|
|
55
|
+
for (const impl of activeImpls) {
|
|
56
|
+
const stateLabel = impl.lifecycleState || 'candidate';
|
|
57
|
+
output += ` ${impl.id}\n`;
|
|
58
|
+
output += ` Rule: ${impl.ruleId} | State: ${stateLabel} | Version: ${impl.version}\n`;
|
|
59
|
+
if (impl.disabledReason) {
|
|
60
|
+
output += ` Previous reason: ${impl.disabledReason}\n`;
|
|
61
|
+
}
|
|
62
|
+
output += '\n';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
output += isZh
|
|
66
|
+
? `\u7528\u6cd5: /pd-disable-impl <implId> --reason "\u539f\u56e0"`
|
|
67
|
+
: `Usage: /pd-disable-impl <implId> --reason "reason"`;
|
|
68
|
+
|
|
69
|
+
return { text: output };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/max-params -- Reason: Command handler signature must match OpenClaw plugin interface - breaking API change to options objects would affect public contracts
|
|
73
|
+
function _handleDisableImpl(
|
|
74
|
+
workspaceDir: string,
|
|
75
|
+
stateDir: string,
|
|
76
|
+
implId: string,
|
|
77
|
+
reason: string | null,
|
|
78
|
+
isZh: boolean,
|
|
79
|
+
sessionId?: string,
|
|
80
|
+
): PluginCommandResult {
|
|
81
|
+
const allImpls = getAllImplementations(stateDir);
|
|
82
|
+
const target = allImpls.find((i) => i.id === implId);
|
|
83
|
+
|
|
84
|
+
if (!target) {
|
|
85
|
+
return {
|
|
86
|
+
text: isZh
|
|
87
|
+
? `\u274c \u672a\u627e\u5230\u5b9e\u73b0: ${implId}`
|
|
88
|
+
: `\u274c Implementation not found: ${implId}`,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const currentState = target.lifecycleState || 'candidate';
|
|
93
|
+
|
|
94
|
+
// Validate: active -> disabled or candidate -> disabled
|
|
95
|
+
if (currentState !== 'active' && currentState !== 'candidate') {
|
|
96
|
+
const allowed = getAllowedTransitions(currentState as ImplementationLifecycleState);
|
|
97
|
+
return {
|
|
98
|
+
text: isZh
|
|
99
|
+
? `\u274c \u5b9e\u73b0 ${implId} \u5f53\u524d\u72b6\u6001: ${currentState}\n\u5141\u8bb8\u8fc7\u6e21: ${allowed.join(', ') || '\u65e0\u8fc7\u6e21'}`
|
|
100
|
+
: `\u274c Implementation ${implId} is in state: ${currentState}\nAllowed transitions: ${allowed.join(', ') || 'none'}`,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const reasonText = reason || (isZh ? '\u7528\u6237\u624b\u52a8\u7981\u7528' : 'User manual disable');
|
|
105
|
+
|
|
106
|
+
transitionImplementationState(stateDir, implId, 'disabled');
|
|
107
|
+
updateImplementation(stateDir, implId, {
|
|
108
|
+
disabledAt: new Date().toISOString(),
|
|
109
|
+
disabledBy: sessionId || 'manual',
|
|
110
|
+
disabledReason: reasonText,
|
|
111
|
+
});
|
|
112
|
+
refreshPrincipleLifecycle(workspaceDir, stateDir);
|
|
113
|
+
|
|
114
|
+
return {
|
|
115
|
+
text: isZh
|
|
116
|
+
? `\n\u2705 \u5b9e\u73b0\u5df2\u7981\u7528: ${implId}\n \u72b6\u6001: ${currentState} -> disabled\n \u539f\u56e0: ${reasonText}`
|
|
117
|
+
: `\n\u2705 Implementation disabled: ${implId}\n State: ${currentState} -> disabled\n Reason: ${reasonText}`,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Handle the /pd-disable-impl command.
|
|
123
|
+
*
|
|
124
|
+
* Usage:
|
|
125
|
+
* /pd-disable-impl list - List active implementations
|
|
126
|
+
* /pd-disable-impl <implId> - Disable an implementation
|
|
127
|
+
* /pd-disable-impl <implId> --reason "<reason>" - Disable with reason
|
|
128
|
+
*/
|
|
129
|
+
export function handleDisableImplCommand(ctx: PluginCommandContext): PluginCommandResult {
|
|
130
|
+
const workspaceDir = (ctx.config?.workspaceDir as string) || process.cwd();
|
|
131
|
+
const {stateDir} = WorkspaceContext.fromHookContext({ ...ctx, workspaceDir });
|
|
132
|
+
const lang = (ctx.config?.language as string) || 'en';
|
|
133
|
+
const isZh = lang === 'zh';
|
|
134
|
+
|
|
135
|
+
const args = (ctx.args || '').trim();
|
|
136
|
+
|
|
137
|
+
// Parse args: [implId] [--reason "..."]
|
|
138
|
+
const parts = args.split(/\s+/);
|
|
139
|
+
const subcommand = parts[0] || '';
|
|
140
|
+
const implId = subcommand === 'list' ? '' : subcommand;
|
|
141
|
+
const reasonMatch = (/--reason\s+"([^"]+)"/.exec(args)) || (/--reason\s+(\S+)/.exec(args));
|
|
142
|
+
const reason = reasonMatch ? reasonMatch[1] : null;
|
|
143
|
+
|
|
144
|
+
// Subcommand: list
|
|
145
|
+
if (subcommand === 'list' || subcommand === '') {
|
|
146
|
+
return _handleListActive(stateDir, isZh);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Disable
|
|
150
|
+
return _handleDisableImpl(workspaceDir, stateDir, implId, reason, isZh, ctx.sessionId);
|
|
151
|
+
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import { EvolutionReducerImpl } from '../core/evolution-reducer.js';
|
|
1
|
+
import type { EvolutionReducerImpl } from '../core/evolution-reducer.js';
|
|
2
|
+
import type { InternalizationRouteRecommendation } from '../core/principle-internalization/internalization-routing-policy.js';
|
|
3
|
+
import { WorkspaceContext } from '../core/workspace-context.js';
|
|
2
4
|
import { normalizeLanguage } from '../i18n/commands.js';
|
|
3
|
-
import { RuntimeSummaryService } from '../service/runtime-summary-service.js';
|
|
4
5
|
import type { PluginCommandContext } from '../openclaw-sdk.js';
|
|
6
|
+
import { RuntimeSummaryService } from '../service/runtime-summary-service.js';
|
|
5
7
|
|
|
6
8
|
function formatNumber(value: number | null): string {
|
|
7
9
|
if (value === null || Number.isNaN(value)) {
|
|
@@ -11,7 +13,7 @@ function formatNumber(value: number | null): string {
|
|
|
11
13
|
}
|
|
12
14
|
|
|
13
15
|
function formatSources(
|
|
14
|
-
sources:
|
|
16
|
+
sources: { source: string; score?: number }[],
|
|
15
17
|
): string {
|
|
16
18
|
if (sources.length === 0) {
|
|
17
19
|
return '--';
|
|
@@ -21,17 +23,36 @@ function formatSources(
|
|
|
21
23
|
.map((source) =>
|
|
22
24
|
source.score === undefined
|
|
23
25
|
? source.source
|
|
24
|
-
: `${source.source}(${formatNumber(source.score)})
|
|
26
|
+
: `${source.source}(${formatNumber(source.score)})`,
|
|
25
27
|
)
|
|
26
28
|
.join(', ');
|
|
27
29
|
}
|
|
28
30
|
|
|
31
|
+
function formatRouteRecommendations(
|
|
32
|
+
recommendations: InternalizationRouteRecommendation[],
|
|
33
|
+
emptyLabel: string,
|
|
34
|
+
): string {
|
|
35
|
+
if (recommendations.length === 0) {
|
|
36
|
+
return emptyLabel;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return recommendations
|
|
40
|
+
.slice(0, 3)
|
|
41
|
+
.map(
|
|
42
|
+
(recommendation) =>
|
|
43
|
+
`${recommendation.principleId}:${recommendation.route}@${formatNumber(recommendation.confidence)}`,
|
|
44
|
+
)
|
|
45
|
+
.join(', ');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// eslint-disable-next-line @typescript-eslint/max-params -- Reason: Command handler signature must match OpenClaw plugin interface - breaking API change to options objects would affect public contracts
|
|
29
49
|
function buildEnglishOutput(
|
|
30
50
|
workspaceDir: string,
|
|
31
51
|
sessionId: string | null,
|
|
32
52
|
warnings: string[],
|
|
33
53
|
stats: ReturnType<EvolutionReducerImpl['getStats']>,
|
|
34
|
-
summary: ReturnType<typeof RuntimeSummaryService.getSummary
|
|
54
|
+
summary: ReturnType<typeof RuntimeSummaryService.getSummary>,
|
|
55
|
+
recommendations: InternalizationRouteRecommendation[],
|
|
35
56
|
): string {
|
|
36
57
|
const lines: string[] = [
|
|
37
58
|
'Evolution Status',
|
|
@@ -47,7 +68,7 @@ function buildEnglishOutput(
|
|
|
47
68
|
'Evolution',
|
|
48
69
|
`- Queue: pending ${summary.evolution.queue.pending}, in_progress ${summary.evolution.queue.inProgress}, completed ${summary.evolution.queue.completed} (${summary.evolution.dataQuality})`,
|
|
49
70
|
`- Legacy Directive File: ${summary.phase3.legacyDirectiveFilePresent ? 'present' : 'missing'} (compatibility-only display artifact)`,
|
|
50
|
-
|
|
71
|
+
'- Note: Legacy directive file is NOT a truth source for Phase 3 eligibility. Queue is the only authoritative execution truth source.',
|
|
51
72
|
`- Active Evolution Task: ${summary.evolution.directive.taskPreview ?? '--'}`,
|
|
52
73
|
`- Phase 3: ready ${summary.phase3.phase3ShadowEligible ? 'yes' : 'no'}, queueTruthReady ${summary.phase3.queueTruthReady ? 'yes' : 'no'}, eligible ${summary.phase3.evolutionEligible}, reference_only ${summary.phase3.evolutionReferenceOnly}, rejected ${summary.phase3.evolutionRejected}${summary.phase3.evolutionReferenceOnlyReasons.length > 0 ? ` (reference ${summary.phase3.evolutionReferenceOnlyReasons.slice(0, 2).join(', ')})` : ''}${summary.phase3.evolutionRejectedReasons.length > 0 ? ` (${summary.phase3.evolutionRejectedReasons.slice(0, 3).join(', ')})` : ''}`,
|
|
53
74
|
`- Phase 3 Legacy Directive File: ${summary.phase3.directiveStatus} (${summary.phase3.directiveIgnoredReason})`,
|
|
@@ -58,6 +79,7 @@ function buildEnglishOutput(
|
|
|
58
79
|
`- active principles: ${stats.activeCount}`,
|
|
59
80
|
`- deprecated principles: ${stats.deprecatedCount}`,
|
|
60
81
|
`- last promoted: ${stats.lastPromotedAt ?? 'none'}`,
|
|
82
|
+
`- internalization routes: ${formatRouteRecommendations(recommendations, '--')}`,
|
|
61
83
|
'',
|
|
62
84
|
'Metadata',
|
|
63
85
|
`- workspace: ${workspaceDir}`,
|
|
@@ -75,30 +97,32 @@ function buildEnglishOutput(
|
|
|
75
97
|
return lines.join('\n');
|
|
76
98
|
}
|
|
77
99
|
|
|
100
|
+
// eslint-disable-next-line @typescript-eslint/max-params -- Reason: Command handler signature must match OpenClaw plugin interface - breaking API change to options objects would affect public contracts
|
|
78
101
|
function buildChineseOutput(
|
|
79
102
|
workspaceDir: string,
|
|
80
103
|
sessionId: string | null,
|
|
81
104
|
warnings: string[],
|
|
82
105
|
stats: ReturnType<EvolutionReducerImpl['getStats']>,
|
|
83
|
-
summary: ReturnType<typeof RuntimeSummaryService.getSummary
|
|
106
|
+
summary: ReturnType<typeof RuntimeSummaryService.getSummary>,
|
|
107
|
+
recommendations: InternalizationRouteRecommendation[],
|
|
84
108
|
): string {
|
|
85
109
|
const lines: string[] = [
|
|
86
110
|
'进化状态',
|
|
87
111
|
'================',
|
|
88
112
|
'',
|
|
89
113
|
'控制面',
|
|
90
|
-
`- 会话 GFI: 当前 ${formatNumber(summary.gfi.current)},峰值 ${formatNumber(summary.gfi.peak)}
|
|
114
|
+
`- 会话 GFI: 当前 ${formatNumber(summary.gfi.current)},峰值 ${formatNumber(summary.gfi.peak)} (${summary.gfi.dataQuality})`,
|
|
91
115
|
`- GFI 来源: ${formatSources(summary.gfi.sources)}`,
|
|
92
|
-
`- Pain Flag: ${summary.pain.activeFlag ? 'active' : 'inactive'}${summary.pain.activeFlagSource ?
|
|
116
|
+
`- Pain Flag: ${summary.pain.activeFlag ? 'active' : 'inactive'}${summary.pain.activeFlagSource ? ` (${summary.pain.activeFlagSource})` : ''}`,
|
|
93
117
|
`- 最近 Pain 信号: ${summary.pain.lastSignal ? `${summary.pain.lastSignal.source}${summary.pain.lastSignal.reason ? ` - ${summary.pain.lastSignal.reason}` : ''}` : '--'}`,
|
|
94
|
-
`- Gate 事件: block ${formatNumber(summary.gate.recentBlocks)},bypass ${formatNumber(summary.gate.recentBypasses)}
|
|
118
|
+
`- Gate 事件: block ${formatNumber(summary.gate.recentBlocks)},bypass ${formatNumber(summary.gate.recentBypasses)} (${summary.gate.dataQuality})`,
|
|
95
119
|
'',
|
|
96
120
|
'进化',
|
|
97
|
-
`- 队列: pending ${summary.evolution.queue.pending},in_progress ${summary.evolution.queue.inProgress},completed ${summary.evolution.queue.completed}
|
|
98
|
-
`- Legacy Directive File: ${summary.phase3.legacyDirectiveFilePresent ? 'present' : 'missing'}
|
|
99
|
-
|
|
100
|
-
`-
|
|
101
|
-
`- Phase 3: ready ${summary.phase3.phase3ShadowEligible ? 'yes' : 'no'},queueTruthReady ${summary.phase3.queueTruthReady ? 'yes' : 'no'},eligible ${summary.phase3.evolutionEligible},reference_only ${summary.phase3.evolutionReferenceOnly},rejected ${summary.phase3.evolutionRejected}${summary.phase3.evolutionReferenceOnlyReasons.length > 0 ?
|
|
121
|
+
`- 队列: pending ${summary.evolution.queue.pending},in_progress ${summary.evolution.queue.inProgress},completed ${summary.evolution.queue.completed} (${summary.evolution.dataQuality})`,
|
|
122
|
+
`- Legacy Directive File: ${summary.phase3.legacyDirectiveFilePresent ? 'present' : 'missing'}(仅兼容展示)`,
|
|
123
|
+
'- 注意:Legacy directive file 不是 Phase 3 合格性的真实来源,队列才是唯一权威的执行真相。',
|
|
124
|
+
`- 当前进化任务: ${summary.evolution.directive.taskPreview ?? '--'}`,
|
|
125
|
+
`- Phase 3: ready ${summary.phase3.phase3ShadowEligible ? 'yes' : 'no'},queueTruthReady ${summary.phase3.queueTruthReady ? 'yes' : 'no'},eligible ${summary.phase3.evolutionEligible},reference_only ${summary.phase3.evolutionReferenceOnly},rejected ${summary.phase3.evolutionRejected}${summary.phase3.evolutionReferenceOnlyReasons.length > 0 ? ` (reference ${summary.phase3.evolutionReferenceOnlyReasons.slice(0, 2).join(', ')})` : ''}${summary.phase3.evolutionRejectedReasons.length > 0 ? ` (${summary.phase3.evolutionRejectedReasons.slice(0, 3).join(', ')})` : ''}`,
|
|
102
126
|
`- Phase 3 Legacy Directive File: ${summary.phase3.directiveStatus} (${summary.phase3.directiveIgnoredReason})`,
|
|
103
127
|
'',
|
|
104
128
|
'原则统计',
|
|
@@ -107,10 +131,11 @@ function buildChineseOutput(
|
|
|
107
131
|
`- 生效原则: ${stats.activeCount}`,
|
|
108
132
|
`- 已废弃原则: ${stats.deprecatedCount}`,
|
|
109
133
|
`- 最近晋升: ${stats.lastPromotedAt ?? '无'}`,
|
|
134
|
+
`- 内化路由: ${formatRouteRecommendations(recommendations, '--')}`,
|
|
110
135
|
'',
|
|
111
136
|
'元数据',
|
|
112
137
|
`- 工作区: ${workspaceDir}`,
|
|
113
|
-
`- Session: ${sessionId ?? '--'}
|
|
138
|
+
`- Session: ${sessionId ?? '--'} (${summary.metadata.selectedSessionReason})`,
|
|
114
139
|
`- 生成时间: ${summary.metadata.generatedAt}`,
|
|
115
140
|
];
|
|
116
141
|
|
|
@@ -127,20 +152,40 @@ function buildChineseOutput(
|
|
|
127
152
|
export function handleEvolutionStatusCommand(ctx: PluginCommandContext): { text: string } {
|
|
128
153
|
const workspaceDir = (ctx.config?.workspaceDir as string) || process.cwd();
|
|
129
154
|
const sessionId = (ctx as { sessionId?: string | null }).sessionId ?? null;
|
|
130
|
-
|
|
155
|
+
// #207/#210: Use WorkspaceContext to get evolutionReducer with stateDir
|
|
156
|
+
const wctx = WorkspaceContext.fromHookContext({ workspaceDir });
|
|
157
|
+
const reducer = wctx.evolutionReducer;
|
|
131
158
|
const stats = reducer.getStats();
|
|
132
159
|
const summary = RuntimeSummaryService.getSummary(workspaceDir, { sessionId });
|
|
160
|
+
const recommendations = WorkspaceContext.fromHookContext({ workspaceDir })
|
|
161
|
+
.principleLifecycle
|
|
162
|
+
.recomputeAll()
|
|
163
|
+
.map((assessment) => assessment.routeRecommendation);
|
|
133
164
|
const rawLang = (ctx.config?.language as string) || 'en';
|
|
134
165
|
const lang = normalizeLanguage(rawLang);
|
|
135
166
|
const warnings = summary.metadata.warnings.slice(0, 12);
|
|
136
167
|
|
|
137
168
|
if (lang === 'zh') {
|
|
138
169
|
return {
|
|
139
|
-
text: buildChineseOutput(
|
|
170
|
+
text: buildChineseOutput(
|
|
171
|
+
workspaceDir,
|
|
172
|
+
summary.metadata.sessionId,
|
|
173
|
+
warnings,
|
|
174
|
+
stats,
|
|
175
|
+
summary,
|
|
176
|
+
recommendations,
|
|
177
|
+
),
|
|
140
178
|
};
|
|
141
179
|
}
|
|
142
180
|
|
|
143
181
|
return {
|
|
144
|
-
text: buildEnglishOutput(
|
|
182
|
+
text: buildEnglishOutput(
|
|
183
|
+
workspaceDir,
|
|
184
|
+
summary.metadata.sessionId,
|
|
185
|
+
warnings,
|
|
186
|
+
stats,
|
|
187
|
+
summary,
|
|
188
|
+
recommendations,
|
|
189
|
+
),
|
|
145
190
|
};
|
|
146
191
|
}
|
package/src/commands/export.ts
CHANGED
|
@@ -42,14 +42,16 @@ export function handleExportCommand(ctx: PluginCommandContext): PluginCommandRes
|
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
|
|
46
|
+
|
|
45
47
|
return {
|
|
46
48
|
text: zh
|
|
47
|
-
? `已导出 ORPO 决策点样本到 ${result.manifest!.exportPath},` +
|
|
48
|
-
`共 ${result.manifest!.sampleCount} 条,模型家族: ${result.manifest!.targetModelFamily},` +
|
|
49
|
-
`数据集指纹: ${result.manifest!.datasetFingerprint.substring(0, 16)}...`
|
|
50
|
-
: `Exported ORPO decision-point samples to ${result.manifest!.exportPath}, ` +
|
|
51
|
-
`${result.manifest!.sampleCount} samples, target: ${result.manifest!.targetModelFamily}, ` +
|
|
52
|
-
`dataset fingerprint: ${result.manifest!.datasetFingerprint.substring(0, 16)}...`,
|
|
49
|
+
? `已导出 ORPO 决策点样本到 ${result.manifest!.exportPath},` + // eslint-disable-line @typescript-eslint/no-non-null-assertion -- Reason: caller guarantees manifest exists via success check
|
|
50
|
+
`共 ${result.manifest!.sampleCount} 条,模型家族: ${result.manifest!.targetModelFamily},` + // eslint-disable-line @typescript-eslint/no-non-null-assertion -- Reason: caller guarantees manifest exists via success check
|
|
51
|
+
`数据集指纹: ${result.manifest!.datasetFingerprint.substring(0, 16)}...` // eslint-disable-line @typescript-eslint/no-non-null-assertion -- Reason: caller guarantees manifest exists via success check
|
|
52
|
+
: `Exported ORPO decision-point samples to ${result.manifest!.exportPath}, ` + // eslint-disable-line @typescript-eslint/no-non-null-assertion -- Reason: caller guarantees manifest exists via success check
|
|
53
|
+
`${result.manifest!.sampleCount} samples, target: ${result.manifest!.targetModelFamily}, ` + // eslint-disable-line @typescript-eslint/no-non-null-assertion -- Reason: caller guarantees manifest exists via success check
|
|
54
|
+
`dataset fingerprint: ${result.manifest!.datasetFingerprint.substring(0, 16)}...`, // eslint-disable-line @typescript-eslint/no-non-null-assertion -- Reason: caller guarantees manifest exists via success check
|
|
53
55
|
};
|
|
54
56
|
}
|
|
55
57
|
|
package/src/commands/focus.ts
CHANGED
|
@@ -10,7 +10,6 @@
|
|
|
10
10
|
|
|
11
11
|
import * as fs from 'fs';
|
|
12
12
|
import * as path from 'path';
|
|
13
|
-
import { randomUUID } from 'node:crypto';
|
|
14
13
|
import type { PluginCommandContext, PluginCommandResult, OpenClawPluginApi } from '../openclaw-sdk.js';
|
|
15
14
|
import { WorkspaceContext } from '../core/workspace-context.js';
|
|
16
15
|
import {
|
|
@@ -24,19 +23,6 @@ import {
|
|
|
24
23
|
cleanupStaleInfo,
|
|
25
24
|
} from '../core/focus-history.js';
|
|
26
25
|
|
|
27
|
-
/**
|
|
28
|
-
* 清理 Markdown 代码块围栏
|
|
29
|
-
* 移除开头的 ```lang 和结尾的 ```
|
|
30
|
-
*/
|
|
31
|
-
function stripMarkdownFence(content: string): string {
|
|
32
|
-
let result = content.trim();
|
|
33
|
-
// 移除开头的代码块标记(如 ```markdown, ```text 等)
|
|
34
|
-
result = result.replace(/^```[\w]*\n?/, '');
|
|
35
|
-
// 移除结尾的代码块标记
|
|
36
|
-
result = result.replace(/\n?```$/, '');
|
|
37
|
-
return result.trim();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
26
|
/**
|
|
41
27
|
* 获取工作区目录
|
|
42
28
|
*/
|
|
@@ -295,6 +281,7 @@ async function compressFocus(
|
|
|
295
281
|
cleanupHistory(focusPath);
|
|
296
282
|
|
|
297
283
|
// 5. 压缩内容
|
|
284
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations -- assigned in both try and catch blocks
|
|
298
285
|
let compressedContent: string;
|
|
299
286
|
try {
|
|
300
287
|
compressedContent = compressFocusContent(oldContent, workspaceDir);
|
|
@@ -305,10 +292,9 @@ async function compressFocus(
|
|
|
305
292
|
}
|
|
306
293
|
|
|
307
294
|
// 6. 更新版本号和日期
|
|
308
|
-
const
|
|
309
|
-
const
|
|
310
|
-
const
|
|
311
|
-
const today = new Date().toISOString().split('T')[0];
|
|
295
|
+
const [majorVersion] = oldVersion.split('.');
|
|
296
|
+
const newVersion = `${(parseInt(majorVersion, 10) || 1) + 1}`;
|
|
297
|
+
const [today] = new Date().toISOString().split('T');
|
|
312
298
|
const newContent = compressedContent
|
|
313
299
|
.replace(/\*\*版本\*\*:\s*v[\d.]+/i, `**版本**: v${newVersion}`)
|
|
314
300
|
.replace(/\*\*更新\*\*:\s*\d{4}-\d{2}-\d{2}/, `**更新**: ${today}`);
|
|
@@ -398,7 +384,7 @@ function rollbackFocus(workspaceDir: string, index: number, isZh: boolean): stri
|
|
|
398
384
|
// 恢复历史版本
|
|
399
385
|
const restoredVersion = extractVersion(historyContent);
|
|
400
386
|
const restoredDate = extractDate(historyContent);
|
|
401
|
-
const today = new Date().toISOString().split('T')
|
|
387
|
+
const [today] = new Date().toISOString().split('T');
|
|
402
388
|
|
|
403
389
|
// 获取最大版本号(从当前文件或历史文件中)
|
|
404
390
|
let maxVersion = parseFloat(restoredVersion) || 1;
|
|
@@ -491,6 +477,7 @@ export async function handleFocusCommand(
|
|
|
491
477
|
// 检测语言(与 context.ts 保持一致)
|
|
492
478
|
const isZh = (ctx.config?.language as string) === 'zh';
|
|
493
479
|
|
|
480
|
+
// eslint-disable-next-line @typescript-eslint/init-declarations -- assigned in all switch cases
|
|
494
481
|
let result: string;
|
|
495
482
|
|
|
496
483
|
switch (subCommand) {
|
|
@@ -506,7 +493,7 @@ export async function handleFocusCommand(
|
|
|
506
493
|
result = await compressFocus(workspaceDir, isZh, api);
|
|
507
494
|
break;
|
|
508
495
|
case 'rollback':
|
|
509
|
-
case 'rb':
|
|
496
|
+
case 'rb': {
|
|
510
497
|
const index = parseInt(args[1], 10);
|
|
511
498
|
if (isNaN(index)) {
|
|
512
499
|
result = isZh
|
|
@@ -516,6 +503,7 @@ export async function handleFocusCommand(
|
|
|
516
503
|
result = rollbackFocus(workspaceDir, index, isZh);
|
|
517
504
|
}
|
|
518
505
|
break;
|
|
506
|
+
}
|
|
519
507
|
case 'help':
|
|
520
508
|
case '--help':
|
|
521
509
|
case '-h':
|