chore: add continuity plugin package skeleton
This commit is contained in:
20
plugins/continuity/HOOK.md
Normal file
20
plugins/continuity/HOOK.md
Normal 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
|
||||||
41
plugins/continuity/README.md
Normal file
41
plugins/continuity/README.md
Normal 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
|
||||||
41
plugins/continuity/README.zh-TW.md
Normal file
41
plugins/continuity/README.zh-TW.md
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# Continuity Plugin(MVP)
|
||||||
|
|
||||||
|
這個套件目前是把既有 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` 先保留給後續依計畫補上的完整測試流程
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
21
plugins/continuity/examples/openclaw.continuity.example.json
Normal file
21
plugins/continuity/examples/openclaw.continuity.example.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
plugins/continuity/package.json
Normal file
13
plugins/continuity/package.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
7
plugins/continuity/src/adapters/force-recall.mjs
Normal file
7
plugins/continuity/src/adapters/force-recall.mjs
Normal 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');
|
||||||
|
}
|
||||||
21
plugins/continuity/src/config/defaults.mjs
Normal file
21
plugins/continuity/src/config/defaults.mjs
Normal 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;
|
||||||
59
plugins/continuity/src/config/schema.mjs
Normal file
59
plugins/continuity/src/config/schema.mjs
Normal 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;
|
||||||
7
plugins/continuity/src/continuity/evaluator.mjs
Normal file
7
plugins/continuity/src/continuity/evaluator.mjs
Normal 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');
|
||||||
|
}
|
||||||
7
plugins/continuity/src/continuity/receipt-validator.mjs
Normal file
7
plugins/continuity/src/continuity/receipt-validator.mjs
Normal 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');
|
||||||
|
}
|
||||||
46
plugins/continuity/src/index.mjs
Normal file
46
plugins/continuity/src/index.mjs
Normal 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,
|
||||||
|
};
|
||||||
1
plugins/continuity/test/.gitkeep
Normal file
1
plugins/continuity/test/.gitkeep
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
Reference in New Issue
Block a user