pactive 0.0.0-stage → 0.0.2-alpha.1
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/.opcteam-plugin/plugin.json +12 -0
- package/BREAKING-CHANGES.md +55 -0
- package/LICENSE +14 -0
- package/README.md +172 -2
- package/agents/pactive-observer.md +35 -0
- package/bin/pactive.mjs +439 -0
- package/commands/pactive.md +46 -0
- package/dsh/cordis.patch.yml +10 -0
- package/dsh/index.js +285 -0
- package/hooks/hooks.json +54 -0
- package/hooks/post-tool-use.mjs +19 -0
- package/hooks/session-end.mjs +19 -0
- package/hooks/session-start.mjs +20 -0
- package/hooks/stop.mjs +55 -0
- package/hooks/user-prompt-submit.mjs +34 -0
- package/mcp/server.mjs +155 -0
- package/mcp/tools/_core.mjs +254 -0
- package/mcp/tools/definitions.mjs +173 -0
- package/package.json +51 -4
- package/pi/extension.ts +420 -0
- package/pi/skills/pactive/SKILL.md +47 -0
- package/skills/pactive/SKILL.md +47 -0
- package/src/core/activity.mjs +67 -0
- package/src/core/config.mjs +84 -0
- package/src/core/doctor.mjs +143 -0
- package/src/core/errors.mjs +8 -0
- package/src/core/guard.mjs +95 -0
- package/src/core/identity.mjs +35 -0
- package/src/core/idle.mjs +53 -0
- package/src/core/index.mjs +13 -0
- package/src/core/lineage.mjs +72 -0
- package/src/core/lock.mjs +71 -0
- package/src/core/mailbox.mjs +162 -0
- package/src/core/paths.mjs +47 -0
- package/src/core/scheduler.mjs +89 -0
- package/src/core/state.mjs +189 -0
- package/src/hosts/dsh/index.mjs +128 -0
- package/src/hosts/errors.mjs +24 -0
- package/src/hosts/opcteam/index.mjs +77 -0
- package/src/hosts/pi/index.mjs +82 -0
- package/src/hosts/shared/index.mjs +64 -0
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Pactive core access for the OPCteam / DSH host surfaces.
|
|
3
|
+
*
|
|
4
|
+
* `src/core/index.mjs` is produced by the parallel core worker. It is loaded
|
|
5
|
+
* **lazily by relative path** so a missing (not yet built) core degrades into
|
|
6
|
+
* a readable error instead of breaking plugin load.
|
|
7
|
+
*
|
|
8
|
+
* unverified: the frozen host contract (docs/team/task-cards/ACTI-CONTRACT.md, historical file name)
|
|
9
|
+
* freezes the **export names** of core, but not the argument shapes of
|
|
10
|
+
* `loadState` / `saveState` / `mutateState`. Every call below therefore tries
|
|
11
|
+
* the plausible shapes in order and falls back to an explicit read/compute/write
|
|
12
|
+
* path. Re-check this module once `src/core/index.mjs` lands and delete the
|
|
13
|
+
* shapes that turned out to be wrong.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { pathToFileURL } from "node:url";
|
|
17
|
+
|
|
18
|
+
/** Relative candidates, resolved against this file's location (<pkg>/mcp/tools/). */
|
|
19
|
+
const CORE_CANDIDATES = [
|
|
20
|
+
"../../src/core/index.mjs", // <pkg>/src/core/index.mjs
|
|
21
|
+
"../src/core/index.mjs", // <pkg>/hooks/ → <pkg>/src/core/index.mjs
|
|
22
|
+
"../../../src/core/index.mjs",
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
let cachedCore = null;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Load the core module.
|
|
29
|
+
* @param {Record<string, string|undefined>} [env]
|
|
30
|
+
* @returns {Promise<any>}
|
|
31
|
+
*/
|
|
32
|
+
export async function loadCore(env = process.env) {
|
|
33
|
+
if (cachedCore) return cachedCore;
|
|
34
|
+
const explicit = env.PACTIVE_CORE_MODULE;
|
|
35
|
+
const candidates = explicit ? [explicit, ...CORE_CANDIDATES] : CORE_CANDIDATES;
|
|
36
|
+
const tried = [];
|
|
37
|
+
for (const candidate of candidates) {
|
|
38
|
+
const href = candidate.startsWith("/")
|
|
39
|
+
? pathToFileURL(candidate).href
|
|
40
|
+
: new URL(candidate, import.meta.url).href;
|
|
41
|
+
tried.push(href);
|
|
42
|
+
try {
|
|
43
|
+
const mod = await import(href);
|
|
44
|
+
if (mod && typeof mod.resolvePaths === "function") {
|
|
45
|
+
cachedCore = mod;
|
|
46
|
+
return mod;
|
|
47
|
+
}
|
|
48
|
+
} catch {
|
|
49
|
+
/* try the next candidate */
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
throw new Error(
|
|
53
|
+
`pactive: core module not found (tried: ${tried.join(", ")}). ` +
|
|
54
|
+
`Build src/core before using this surface; set PACTIVE_CORE_MODULE to override.`,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** @param {unknown} err */
|
|
59
|
+
export function errorText(err) {
|
|
60
|
+
return String(err?.message ?? err);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Read the persisted state, tolerating the two plausible loadState shapes.
|
|
65
|
+
* @returns {Promise<any|null>}
|
|
66
|
+
*/
|
|
67
|
+
export async function readState(core, paths) {
|
|
68
|
+
for (const args of [[paths.stateFile], [paths]]) {
|
|
69
|
+
try {
|
|
70
|
+
const state = await core.loadState(...args);
|
|
71
|
+
if (state && typeof state === "object") return state;
|
|
72
|
+
} catch {
|
|
73
|
+
/* next shape */
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Persist the state, tolerating the plausible saveState shapes.
|
|
81
|
+
* @returns {Promise<boolean>}
|
|
82
|
+
*/
|
|
83
|
+
export async function writeState(core, paths, state) {
|
|
84
|
+
const shapes = [
|
|
85
|
+
[paths.stateFile, state],
|
|
86
|
+
[state, paths.stateFile],
|
|
87
|
+
[state],
|
|
88
|
+
];
|
|
89
|
+
let last;
|
|
90
|
+
for (const args of shapes) {
|
|
91
|
+
try {
|
|
92
|
+
await core.saveState(...args);
|
|
93
|
+
return true;
|
|
94
|
+
} catch (err) {
|
|
95
|
+
last = err;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
throw last instanceof Error ? last : new Error(String(last));
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Mutate the state through core (locking + atomic write) with a verified
|
|
103
|
+
* fallback. `fn` MUST be pure: it may be evaluated twice (verification).
|
|
104
|
+
*
|
|
105
|
+
* @param {any} core
|
|
106
|
+
* @param {any} paths
|
|
107
|
+
* @param {(state:any)=>any} fn
|
|
108
|
+
* @returns {Promise<any>} the new state
|
|
109
|
+
*/
|
|
110
|
+
export async function mutateState(core, paths, fn) {
|
|
111
|
+
const before = (await readState(core, paths)) ?? core.defaultState();
|
|
112
|
+
const shapes = [
|
|
113
|
+
[fn, paths],
|
|
114
|
+
[paths, fn],
|
|
115
|
+
[fn],
|
|
116
|
+
];
|
|
117
|
+
let last;
|
|
118
|
+
for (const args of shapes) {
|
|
119
|
+
try {
|
|
120
|
+
const out = await core.mutateState(...args);
|
|
121
|
+
const after = await readState(core, paths);
|
|
122
|
+
if (after) {
|
|
123
|
+
const wanted = fn(before);
|
|
124
|
+
if (JSON.stringify(after) !== JSON.stringify(wanted)) {
|
|
125
|
+
// core wrote somewhere else than this host's state file → write explicitly.
|
|
126
|
+
await writeState(core, paths, wanted);
|
|
127
|
+
return wanted;
|
|
128
|
+
}
|
|
129
|
+
return after;
|
|
130
|
+
}
|
|
131
|
+
return out ?? fn(before);
|
|
132
|
+
} catch (err) {
|
|
133
|
+
last = err;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const after = fn(before);
|
|
137
|
+
try {
|
|
138
|
+
await writeState(core, paths, after);
|
|
139
|
+
} catch (err) {
|
|
140
|
+
throw new Error(`pactive: state write failed (${errorText(err)})`);
|
|
141
|
+
}
|
|
142
|
+
return after;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** Normalize a core call that may return either the state or `{ state, ... }`. */
|
|
146
|
+
export function pickState(out, fallback) {
|
|
147
|
+
if (out && typeof out === "object" && out.state && typeof out.state === "object") return out.state;
|
|
148
|
+
if (out && typeof out === "object" && Array.isArray(out.tasks)) return out;
|
|
149
|
+
return fallback;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Parse a human `when` into a schedule spec.
|
|
154
|
+
* Accepts: `10m` / `2h` / `30s` (in), `18:30` / ISO 8601 (at), `every 1h` (every).
|
|
155
|
+
* @returns {{kind:"in"|"at"|"every", when:string, at:number|null}|null}
|
|
156
|
+
*/
|
|
157
|
+
export function parseWhen(when, now = Date.now()) {
|
|
158
|
+
const text = typeof when === "string" ? when.trim() : "";
|
|
159
|
+
if (text === "") return { kind: "in", when: "10m", at: null };
|
|
160
|
+
const every = /^every\s+(.+)$/i.exec(text);
|
|
161
|
+
if (every) return { kind: "every", when: every[1].trim(), at: null };
|
|
162
|
+
const duration = /^(\d+)\s*(s|sec|m|min|h|hour|d|day)$/i.exec(text);
|
|
163
|
+
if (duration) {
|
|
164
|
+
const unit = duration[2].toLowerCase();
|
|
165
|
+
const factor = unit.startsWith("s") ? 1000 : unit.startsWith("m") ? 60000 : unit.startsWith("h") ? 3600000 : 86400000;
|
|
166
|
+
return { kind: "in", when: text, at: now + Number(duration[1]) * factor };
|
|
167
|
+
}
|
|
168
|
+
const clock = /^(\d{1,2}):(\d{2})$/.exec(text);
|
|
169
|
+
if (clock) {
|
|
170
|
+
const at = new Date(now);
|
|
171
|
+
at.setHours(Number(clock[1]), Number(clock[2]), 0, 0);
|
|
172
|
+
if (at.getTime() <= now) at.setDate(at.getDate() + 1);
|
|
173
|
+
return { kind: "at", when: text, at: at.getTime() };
|
|
174
|
+
}
|
|
175
|
+
const iso = Date.parse(text);
|
|
176
|
+
if (!Number.isNaN(iso)) return { kind: "at", when: text, at: iso };
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
/* ------------------------------------------------------------------ *
|
|
180
|
+
* OPCteam hook runtime helpers (shared by hooks/*.mjs)
|
|
181
|
+
* ------------------------------------------------------------------ */
|
|
182
|
+
|
|
183
|
+
const MAX_STDIN_BYTES = 2 * 1024 * 1024;
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Read the hook payload from stdin. Never throws: a broken payload must not
|
|
187
|
+
* break the host session.
|
|
188
|
+
* @returns {Promise<Record<string, any>>}
|
|
189
|
+
*/
|
|
190
|
+
export async function readStdinJson(stream = process.stdin) {
|
|
191
|
+
let raw = "";
|
|
192
|
+
try {
|
|
193
|
+
for await (const chunk of stream) {
|
|
194
|
+
raw += chunk;
|
|
195
|
+
if (raw.length > MAX_STDIN_BYTES) break;
|
|
196
|
+
}
|
|
197
|
+
} catch {
|
|
198
|
+
return {};
|
|
199
|
+
}
|
|
200
|
+
if (raw.trim() === "") return {};
|
|
201
|
+
try {
|
|
202
|
+
const parsed = JSON.parse(raw);
|
|
203
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
204
|
+
} catch {
|
|
205
|
+
return {};
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Write the hook decision to stdout (the host reads it as JSON).
|
|
211
|
+
* @param {Record<string, any>} output
|
|
212
|
+
*/
|
|
213
|
+
export function writeHookOutput(output) {
|
|
214
|
+
try {
|
|
215
|
+
process.stdout.write(JSON.stringify(output ?? {}) + "\n");
|
|
216
|
+
} catch {
|
|
217
|
+
/* stdout closed */
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Mark an activity kind on the host's persisted state.
|
|
223
|
+
* @param {"user"|"agent"|"session-start"|"session-end"|"tool"} kind
|
|
224
|
+
* @param {{hostKind?: string, env?: Record<string,string|undefined>, now?: number}} [options]
|
|
225
|
+
*/
|
|
226
|
+
export async function markActivity(kind, options = {}) {
|
|
227
|
+
const env = options.env ?? process.env;
|
|
228
|
+
const now = options.now ?? Date.now();
|
|
229
|
+
const hostKind = options.hostKind ?? "opcteam";
|
|
230
|
+
const core = await loadCore(env);
|
|
231
|
+
const paths = core.resolvePaths(hostKind, env);
|
|
232
|
+
const state = await mutateState(core, paths, (current) => {
|
|
233
|
+
const next = core.markActivity(current, kind, now);
|
|
234
|
+
return next && typeof next === "object" ? next : current;
|
|
235
|
+
});
|
|
236
|
+
return { ok: true, kind, state, stateFile: paths.stateFile, now };
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Flip the control flag (control returned to the human).
|
|
241
|
+
* @param {{hostKind?: string, env?: Record<string,string|undefined>, now?: number}} [options]
|
|
242
|
+
*/
|
|
243
|
+
export async function markControlReturned(options = {}) {
|
|
244
|
+
const env = options.env ?? process.env;
|
|
245
|
+
const now = options.now ?? Date.now();
|
|
246
|
+
const hostKind = options.hostKind ?? "opcteam";
|
|
247
|
+
const core = await loadCore(env);
|
|
248
|
+
const paths = core.resolvePaths(hostKind, env);
|
|
249
|
+
const state = await mutateState(core, paths, (current) => {
|
|
250
|
+
const next = core.markControlReturned(current, now);
|
|
251
|
+
return next && typeof next === "object" ? next : current;
|
|
252
|
+
});
|
|
253
|
+
return { ok: true, state, stateFile: paths.stateFile, now };
|
|
254
|
+
}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool surface of the `pactive` OPCteam plugin (stdio JSON-RPC server).
|
|
3
|
+
*
|
|
4
|
+
* Tools: pactive_status / pactive_schedule / pactive_tell / pactive_history.
|
|
5
|
+
* Zero third-party dependencies — the schemas are plain JSON Schema.
|
|
6
|
+
*
|
|
7
|
+
* unverified: mailbox.send / ledger.tail argument shapes come from the frozen
|
|
8
|
+
* contract's export names only; the exact message envelope is not frozen yet.
|
|
9
|
+
* The calls below send the most plausible envelope and report the raw core
|
|
10
|
+
* result so a mismatch is visible instead of being swallowed.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
errorText,
|
|
15
|
+
loadCore,
|
|
16
|
+
mutateState,
|
|
17
|
+
parseWhen,
|
|
18
|
+
pickState,
|
|
19
|
+
readState,
|
|
20
|
+
} from "./_core.mjs";
|
|
21
|
+
|
|
22
|
+
const HOST_KIND = "opcteam";
|
|
23
|
+
|
|
24
|
+
const obj = (properties, required) => ({
|
|
25
|
+
type: "object",
|
|
26
|
+
properties,
|
|
27
|
+
...(required && required.length > 0 ? { required } : {}),
|
|
28
|
+
additionalProperties: false,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const str = (description) => ({ type: "string", description });
|
|
32
|
+
|
|
33
|
+
/** @type {Array<{name:string, description:string, inputSchema:object}>} */
|
|
34
|
+
export const TOOL_DEFINITIONS = [
|
|
35
|
+
{
|
|
36
|
+
name: "pactive_status",
|
|
37
|
+
description:
|
|
38
|
+
"Pactive 主动机制状态:空闲判定与 reason、护栏四闸门、定时任务数、最近活动。只读。",
|
|
39
|
+
inputSchema: obj({}, []),
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: "pactive_schedule",
|
|
43
|
+
description:
|
|
44
|
+
"登记一个定时任务(真正落盘)。when 支持时长(10m)、时刻(18:30)、ISO 时间、every 1h。",
|
|
45
|
+
inputSchema: obj(
|
|
46
|
+
{
|
|
47
|
+
prompt: str("任务正文(到点注入给会话的内容)"),
|
|
48
|
+
when: str("触发时间:时长 / 时刻 / ISO 8601 / every <时长>;缺省 10m"),
|
|
49
|
+
},
|
|
50
|
+
["prompt"],
|
|
51
|
+
),
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: "pactive_tell",
|
|
55
|
+
description:
|
|
56
|
+
"给同机另一个会话投递一条消息。对端离线时进入 outbox 排队,不伪装成功。",
|
|
57
|
+
inputSchema: obj(
|
|
58
|
+
{
|
|
59
|
+
to: str("目标会话的 agentId 或名字"),
|
|
60
|
+
body: str("消息正文"),
|
|
61
|
+
kind: str("消息语义:notify(默认)| ask | task"),
|
|
62
|
+
},
|
|
63
|
+
["to", "body"],
|
|
64
|
+
),
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: "pactive_history",
|
|
68
|
+
description: "读取 Pactive 事件账本尾部(触发→投递→回应→结账),用于追溯主动行为。",
|
|
69
|
+
inputSchema: obj({ limit: { type: "integer", description: "返回条数,默认 20" } }, []),
|
|
70
|
+
},
|
|
71
|
+
];
|
|
72
|
+
|
|
73
|
+
/** @param {string} name */
|
|
74
|
+
export function findTool(name) {
|
|
75
|
+
return TOOL_DEFINITIONS.find((tool) => tool.name === name);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function json(text, isError = false) {
|
|
79
|
+
return { content: [{ type: "text", text: typeof text === "string" ? text : JSON.stringify(text, null, 2) }], isError };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Run one tool.
|
|
84
|
+
* @param {string} name
|
|
85
|
+
* @param {Record<string, any>} args
|
|
86
|
+
* @param {{env?: Record<string,string|undefined>, now?: number}} [options]
|
|
87
|
+
*/
|
|
88
|
+
export async function runTool(name, args = {}, options = {}) {
|
|
89
|
+
const env = options.env ?? process.env;
|
|
90
|
+
const now = options.now ?? Date.now();
|
|
91
|
+
let core;
|
|
92
|
+
try {
|
|
93
|
+
core = await loadCore(env);
|
|
94
|
+
} catch (err) {
|
|
95
|
+
return json(`ERROR CORE_UNAVAILABLE: ${errorText(err)}`, true);
|
|
96
|
+
}
|
|
97
|
+
const paths = core.resolvePaths(HOST_KIND, env);
|
|
98
|
+
|
|
99
|
+
try {
|
|
100
|
+
switch (name) {
|
|
101
|
+
case "pactive_status": {
|
|
102
|
+
const state = (await readState(core, paths)) ?? core.defaultState();
|
|
103
|
+
const policy = state.policy ?? {};
|
|
104
|
+
const idle = core.evaluateIdle ? core.evaluateIdle(state, now, policy) : { idle: false, reason: "requires-action" };
|
|
105
|
+
const guard = core.checkGuard ? core.checkGuard(state, now) : { pass: false, reason: "requires-action" };
|
|
106
|
+
const tasks = core.schedule?.list ? core.schedule.list(state) : (state.tasks ?? []);
|
|
107
|
+
const activity = core.getActivity ? core.getActivity(state) : null;
|
|
108
|
+
return json({
|
|
109
|
+
host: HOST_KIND,
|
|
110
|
+
now,
|
|
111
|
+
enabled: state.idle?.enabled ?? false,
|
|
112
|
+
idle,
|
|
113
|
+
guard,
|
|
114
|
+
tasks: Array.isArray(tasks) ? tasks.length : 0,
|
|
115
|
+
activity,
|
|
116
|
+
stateFile: paths.stateFile,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
case "pactive_schedule": {
|
|
121
|
+
const prompt = typeof args.prompt === "string" ? args.prompt.trim() : "";
|
|
122
|
+
if (prompt === "") return json("ERROR INVALID_ARGUMENT: prompt 必填", true);
|
|
123
|
+
const spec = parseWhen(args.when, now);
|
|
124
|
+
if (!spec) return json(`ERROR INVALID_ARGUMENT: 无法解析 when(${String(args.when)})`, true);
|
|
125
|
+
const next = await mutateState(core, paths, (state) => {
|
|
126
|
+
const out = core.schedule.add(state, { ...spec, prompt, content: prompt, owner: state.identity?.agentId }, now);
|
|
127
|
+
return pickState(out, state);
|
|
128
|
+
});
|
|
129
|
+
const tasks = core.schedule?.list ? core.schedule.list(next) : (next.tasks ?? []);
|
|
130
|
+
const created = Array.isArray(tasks) ? tasks[tasks.length - 1] : null;
|
|
131
|
+
return json({
|
|
132
|
+
ok: true,
|
|
133
|
+
taskId: created?.id ?? created?.taskId ?? null,
|
|
134
|
+
dueAt: created?.dueAt ?? spec.at ?? null,
|
|
135
|
+
kind: spec.kind,
|
|
136
|
+
when: spec.when,
|
|
137
|
+
tasks: Array.isArray(tasks) ? tasks.length : 0,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
case "pactive_tell": {
|
|
142
|
+
const to = typeof args.to === "string" ? args.to.trim() : "";
|
|
143
|
+
const body = typeof args.body === "string" ? args.body.trim() : "";
|
|
144
|
+
if (to === "" || body === "") return json("ERROR INVALID_ARGUMENT: to 与 body 必填", true);
|
|
145
|
+
const kind = typeof args.kind === "string" && args.kind !== "" ? args.kind : "notify";
|
|
146
|
+
let receipt;
|
|
147
|
+
const next = await mutateState(core, paths, (state) => {
|
|
148
|
+
const out = core.mailbox.send(state, { to, body, kind, from: state.identity?.agentId ?? HOST_KIND }, now);
|
|
149
|
+
receipt = out;
|
|
150
|
+
return pickState(out, state);
|
|
151
|
+
});
|
|
152
|
+
return json({
|
|
153
|
+
ok: receipt?.ok ?? true,
|
|
154
|
+
state: receipt?.state ?? receipt?.status ?? "accepted",
|
|
155
|
+
reason: receipt?.reason ?? null,
|
|
156
|
+
outboxId: receipt?.outboxId ?? receipt?.id ?? null,
|
|
157
|
+
peers: Object.keys(next.peers ?? {}).length,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
case "pactive_history": {
|
|
162
|
+
const limit = Number.isInteger(args.limit) ? args.limit : 20;
|
|
163
|
+
const events = core.ledger?.tail ? core.ledger.tail(paths.ledgerFile, limit) : [];
|
|
164
|
+
return json({ count: Array.isArray(events) ? events.length : 0, events });
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
default:
|
|
168
|
+
return json(`ERROR UNKNOWN_TOOL: ${name}`, true);
|
|
169
|
+
}
|
|
170
|
+
} catch (err) {
|
|
171
|
+
return json(`ERROR ${err?.code ?? "INTERNAL"}: ${errorText(err)}`, true);
|
|
172
|
+
}
|
|
173
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,53 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pactive",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.0.2-alpha.1",
|
|
4
|
+
"description": "Pactive:跨 Pi / OPCteam / DSH 的主动能力运行时(idle 判定默认关闭、人工闸门、事件账本)。专有软件:使用条款见包内 LICENSE(发行物含 Pi 扩展源码 pi/extension.ts)。",
|
|
5
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"pactive": "bin/pactive.mjs"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": "./src/core/index.mjs",
|
|
12
|
+
"./pi": "./pi/extension.ts",
|
|
13
|
+
"./dsh": "./dsh/index.js"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"bin/",
|
|
17
|
+
"src/",
|
|
18
|
+
"pi/",
|
|
19
|
+
"skills/",
|
|
20
|
+
".opcteam-plugin/",
|
|
21
|
+
"hooks/",
|
|
22
|
+
"mcp/",
|
|
23
|
+
"commands/",
|
|
24
|
+
"agents/",
|
|
25
|
+
"dsh/",
|
|
26
|
+
"README.md",
|
|
27
|
+
"LICENSE",
|
|
28
|
+
"BREAKING-CHANGES.md"
|
|
29
|
+
],
|
|
30
|
+
"pi": {
|
|
31
|
+
"extensions": [
|
|
32
|
+
"./pi/extension.ts"
|
|
33
|
+
],
|
|
34
|
+
"skills": [
|
|
35
|
+
"./pi/skills/pactive"
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
"dsh": {
|
|
39
|
+
"bundle": {
|
|
40
|
+
"patch": "./dsh/cordis.patch.yml"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=22.19.0"
|
|
45
|
+
},
|
|
46
|
+
"publishConfig": {
|
|
47
|
+
"access": "public"
|
|
48
|
+
},
|
|
49
|
+
"repository": {
|
|
50
|
+
"type": "git",
|
|
51
|
+
"url": "git+https://github.com/shark2202/z-agents.git"
|
|
52
|
+
}
|
|
53
|
+
}
|