chore: add continuity plugin package skeleton

This commit is contained in:
Eve
2026-04-24 16:45:06 +08:00
parent 82d0d94b5f
commit b3483098c1
13 changed files with 297 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
# HOOK.md
This document reserves the hook adapter contract for the continuity plugin MVP.
## Target adapter
Primary MVP integration target:
- `force-recall`
## Planned responsibilities
- derive continuity input from hook context
- invoke the plugin evaluator
- return a prompt block / gate result without duplicating continuity rules
## Current status
- contract placeholder only
- implementation deferred to later plan tasks

View File

@@ -0,0 +1,41 @@
# Continuity Plugin (MVP)
This package is the skeleton for extracting the current approved-plan continuity hard gate into an installable plugin.
## MVP status
- Task 2: package skeleton created
- Task 3: config schema contract scaffolded
- Plugin logic intentionally not implemented yet
## Layout
```text
plugins/continuity/
README.md
README.zh-TW.md
HOOK.md
package.json
examples/
src/
test/
```
## Planned public surface
- `src/config/schema.mjs`
- `src/config/defaults.mjs`
- `src/continuity/evaluator.mjs`
- `src/continuity/receipt-validator.mjs`
- `src/adapters/force-recall.mjs`
- `src/index.mjs`
## Example config
See `examples/openclaw.continuity.example.json`.
## Notes
- Current terminal states preserved by default: `waiting_user`, `blocked`, `pending_verification`
- Default receipt directory target: `state/approved-plan-continuity`
- `npm test` is reserved for the full plugin test suite defined by the implementation plan

View File

@@ -0,0 +1,41 @@
# Continuity PluginMVP
這個套件目前是把既有 approved-plan continuity hard gate 抽離成可安裝 plugin 的骨架。
## MVP 狀態
- Task 2已建立 package skeleton
- Task 3已先放入 config schema contract 骨架
- 目前刻意不實作 plugin logic
## 目錄
```text
plugins/continuity/
README.md
README.zh-TW.md
HOOK.md
package.json
examples/
src/
test/
```
## 預計公開介面
- `src/config/schema.mjs`
- `src/config/defaults.mjs`
- `src/continuity/evaluator.mjs`
- `src/continuity/receipt-validator.mjs`
- `src/adapters/force-recall.mjs`
- `src/index.mjs`
## 範例設定
請參考 `examples/openclaw.continuity.example.json`
## 備註
- 預設保留目前 terminal states`waiting_user``blocked``pending_verification`
- 預設 receipt 目錄:`state/approved-plan-continuity`
- `npm test` 先保留給後續依計畫補上的完整測試流程

View File

@@ -0,0 +1,13 @@
{
"planId": "example-plan",
"currentTask": "task-01",
"nextDerivedAction": {
"kind": "delegate",
"target": "subagent",
"task": "placeholder"
},
"dispatchedAt": "2026-04-24T16:43:00+08:00",
"dispatchRunId": "example-run",
"childSessionKey": "session-placeholder",
"replyClosureState": "pending_verification"
}

View File

@@ -0,0 +1,21 @@
{
"enabled": true,
"planMatchers": [
"approved-plan"
],
"legalTerminalStates": [
"waiting_user",
"blocked",
"pending_verification"
],
"receiptDir": "state/approved-plan-continuity",
"requireRealDispatchReceipt": true,
"allowReplyClosureWithoutDispatch": false,
"debug": false,
"adapter": {
"forceRecall": {
"enabled": true,
"injectBlockLabel": "APPROVED_PLAN_CONTINUITY_GATE"
}
}
}

View File

@@ -0,0 +1,13 @@
{
"name": "@openclaw/plugin-continuity",
"version": "0.1.0",
"private": true,
"type": "module",
"description": "Continuity plugin MVP skeleton for approved-plan dispatch gating.",
"exports": {
".": "./src/index.mjs"
},
"scripts": {
"test": "node test/continuity.config.test.mjs && node test/continuity.receipt-validator.test.mjs && node test/continuity.receipt-store.test.mjs && node test/continuity.evaluator.test.mjs && node test/continuity.plugin.test.mjs && node test/continuity.smoke.test.mjs"
}
}

View File

@@ -0,0 +1,7 @@
export function createForceRecallContinuityAdapter() {
throw new Error('Not implemented: force-recall continuity adapter contract placeholder');
}
export function runForceRecallContinuityAdapter() {
throw new Error('Not implemented: force-recall continuity adapter contract placeholder');
}

View File

@@ -0,0 +1,21 @@
export const defaultConfig = Object.freeze({
enabled: true,
planMatchers: ['approved-plan'],
legalTerminalStates: ['waiting_user', 'blocked', 'pending_verification'],
receiptDir: 'state/approved-plan-continuity',
requireRealDispatchReceipt: true,
allowReplyClosureWithoutDispatch: false,
debug: false,
adapter: {
forceRecall: {
enabled: true,
injectBlockLabel: 'APPROVED_PLAN_CONTINUITY_GATE',
},
},
});
export function cloneDefaultConfig() {
return structuredClone(defaultConfig);
}
export default defaultConfig;

View File

@@ -0,0 +1,59 @@
import defaultConfig, { cloneDefaultConfig } from './defaults.mjs';
export const continuityConfigSchema = Object.freeze({
enabled: 'boolean',
planMatchers: 'string[]',
legalTerminalStates: 'string[]',
receiptDir: 'string',
requireRealDispatchReceipt: 'boolean',
allowReplyClosureWithoutDispatch: 'boolean',
debug: 'boolean',
adapter: {
forceRecall: {
enabled: 'boolean',
injectBlockLabel: 'string',
},
},
});
function isPlainObject(value) {
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
}
export function normalizeContinuityConfig(input = {}) {
const base = cloneDefaultConfig();
if (!isPlainObject(input)) {
return base;
}
return {
...base,
...input,
planMatchers: Array.isArray(input.planMatchers) ? [...input.planMatchers] : [...base.planMatchers],
legalTerminalStates: Array.isArray(input.legalTerminalStates)
? [...input.legalTerminalStates]
: [...base.legalTerminalStates],
adapter: {
...base.adapter,
...(isPlainObject(input.adapter) ? input.adapter : {}),
forceRecall: {
...base.adapter.forceRecall,
...(isPlainObject(input.adapter?.forceRecall) ? input.adapter.forceRecall : {}),
},
},
};
}
export function validateContinuityConfig(input = {}) {
const normalizedConfig = normalizeContinuityConfig(input);
return {
ok: true,
errors: [],
normalizedConfig,
};
}
export { defaultConfig };
export default continuityConfigSchema;

View File

@@ -0,0 +1,7 @@
export function evaluateContinuity() {
throw new Error('Not implemented: continuity evaluator contract placeholder');
}
export function buildContinuityGateBlock() {
throw new Error('Not implemented: continuity gate block contract placeholder');
}

View File

@@ -0,0 +1,7 @@
export function validateReceipt() {
throw new Error('Not implemented: receipt validator contract placeholder');
}
export function isValidReceipt() {
throw new Error('Not implemented: receipt validator contract placeholder');
}

View File

@@ -0,0 +1,46 @@
import { defaultConfig, cloneDefaultConfig } from './config/defaults.mjs';
import {
continuityConfigSchema,
validateContinuityConfig,
normalizeContinuityConfig,
} from './config/schema.mjs';
import {
evaluateContinuity,
buildContinuityGateBlock,
} from './continuity/evaluator.mjs';
import {
validateReceipt,
isValidReceipt,
} from './continuity/receipt-validator.mjs';
import {
createForceRecallContinuityAdapter,
runForceRecallContinuityAdapter,
} from './adapters/force-recall.mjs';
export {
defaultConfig,
cloneDefaultConfig,
continuityConfigSchema,
validateContinuityConfig,
normalizeContinuityConfig,
evaluateContinuity,
buildContinuityGateBlock,
validateReceipt,
isValidReceipt,
createForceRecallContinuityAdapter,
runForceRecallContinuityAdapter,
};
export default {
name: '@openclaw/plugin-continuity',
defaultConfig,
continuityConfigSchema,
validateContinuityConfig,
normalizeContinuityConfig,
evaluateContinuity,
buildContinuityGateBlock,
validateReceipt,
isValidReceipt,
createForceRecallContinuityAdapter,
runForceRecallContinuityAdapter,
};

View File

@@ -0,0 +1 @@