@haaaiawd/second-nature 0.1.7 → 0.1.9
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/index.js +429 -96
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/runtime/cli/commands/index.d.ts +2 -0
- package/runtime/cli/commands/index.js +61 -6
- package/runtime/cli/explain/explain-surface-subject.d.ts +8 -0
- package/runtime/cli/explain/explain-surface-subject.js +9 -0
- package/runtime/cli/explain/format-explanation.d.ts +2 -0
- package/runtime/cli/explain/format-explanation.js +2 -0
- package/runtime/cli/explain/resolve-subject.js +15 -0
- package/runtime/cli/host-capability/classify-delivery.d.ts +14 -0
- package/runtime/cli/host-capability/classify-delivery.js +20 -0
- package/runtime/cli/host-capability/probe-host-capability.d.ts +2 -0
- package/runtime/cli/host-capability/probe-host-capability.js +58 -0
- package/runtime/cli/host-capability/record-host-capability.d.ts +6 -0
- package/runtime/cli/host-capability/record-host-capability.js +14 -0
- package/runtime/cli/host-capability/types.d.ts +71 -0
- package/runtime/cli/host-capability/types.js +6 -0
- package/runtime/cli/host-smoke/run-host-smoke.d.ts +2 -0
- package/runtime/cli/host-smoke/run-host-smoke.js +40 -0
- package/runtime/cli/host-smoke/types.d.ts +35 -0
- package/runtime/cli/host-smoke/types.js +6 -0
- package/runtime/cli/index.js +18 -0
- package/runtime/cli/ops/heartbeat-surface.d.ts +35 -0
- package/runtime/cli/ops/heartbeat-surface.js +71 -0
- package/runtime/cli/ops/ops-router.d.ts +16 -0
- package/runtime/cli/ops/ops-router.js +83 -0
- package/runtime/cli/ops/show-operator-fallback.d.ts +13 -0
- package/runtime/cli/ops/show-operator-fallback.js +22 -0
- package/runtime/cli/ops/workspace-heartbeat-runner.d.ts +10 -0
- package/runtime/cli/ops/workspace-heartbeat-runner.js +26 -0
- package/runtime/cli/read-models/index.d.ts +11 -2
- package/runtime/cli/read-models/index.js +50 -0
- package/runtime/cli/read-models/operator-explain-map.d.ts +6 -0
- package/runtime/cli/read-models/operator-explain-map.js +10 -0
- package/runtime/cli/read-models/types.d.ts +5 -1
- package/runtime/cli/runtime/runtime-artifact-boundary.d.ts +28 -0
- package/runtime/cli/runtime/runtime-artifact-boundary.js +94 -0
- package/runtime/connectors/base/contract.d.ts +6 -0
- package/runtime/connectors/base/execution-policy.d.ts +47 -0
- package/runtime/connectors/base/execution-policy.js +82 -0
- package/runtime/connectors/base/index.d.ts +2 -0
- package/runtime/connectors/base/index.js +2 -0
- package/runtime/connectors/base/manifest.d.ts +55 -2
- package/runtime/connectors/base/manifest.js +50 -0
- package/runtime/connectors/base/map-life-evidence.d.ts +16 -0
- package/runtime/connectors/base/map-life-evidence.js +79 -0
- package/runtime/connectors/base/policy-layer.d.ts +2 -0
- package/runtime/connectors/base/policy-layer.js +20 -35
- package/runtime/connectors/base/route-planner.js +1 -0
- package/runtime/connectors/index.d.ts +1 -0
- package/runtime/connectors/index.js +1 -0
- package/runtime/connectors/near-real/near-real-connector-smoke.d.ts +19 -0
- package/runtime/connectors/near-real/near-real-connector-smoke.js +152 -0
- package/runtime/core/second-nature/heartbeat/heartbeat-executor.js +2 -0
- package/runtime/core/second-nature/heartbeat/heartbeat-loop.d.ts +37 -16
- package/runtime/core/second-nature/heartbeat/heartbeat-loop.js +95 -29
- package/runtime/core/second-nature/heartbeat/index.d.ts +4 -1
- package/runtime/core/second-nature/heartbeat/index.js +4 -1
- package/runtime/core/second-nature/heartbeat/run-heartbeat-cycle.d.ts +21 -0
- package/runtime/core/second-nature/heartbeat/run-heartbeat-cycle.js +35 -0
- package/runtime/core/second-nature/heartbeat/runtime-snapshot.d.ts +28 -0
- package/runtime/core/second-nature/heartbeat/runtime-snapshot.js +35 -0
- package/runtime/core/second-nature/heartbeat/signal.d.ts +9 -2
- package/runtime/core/second-nature/heartbeat/snapshot-builder.d.ts +19 -1
- package/runtime/core/second-nature/index.d.ts +8 -0
- package/runtime/core/second-nature/index.js +8 -0
- package/runtime/core/second-nature/orchestrator/effect-dispatcher.d.ts +1 -1
- package/runtime/core/second-nature/orchestrator/effect-dispatcher.js +9 -4
- package/runtime/core/second-nature/orchestrator/guard-layer.d.ts +6 -0
- package/runtime/core/second-nature/orchestrator/guard-layer.js +76 -20
- package/runtime/core/second-nature/orchestrator/intent-planner.d.ts +10 -0
- package/runtime/core/second-nature/orchestrator/intent-planner.js +135 -28
- package/runtime/core/second-nature/orchestrator/lease-manager.d.ts +1 -1
- package/runtime/core/second-nature/orchestrator/lease-manager.js +1 -1
- package/runtime/core/second-nature/outreach/build-outreach-draft-request.d.ts +6 -0
- package/runtime/core/second-nature/outreach/build-outreach-draft-request.js +63 -0
- package/runtime/core/second-nature/outreach/delivery-target.d.ts +26 -0
- package/runtime/core/second-nature/outreach/delivery-target.js +70 -0
- package/runtime/core/second-nature/outreach/dispatch-user-outreach.d.ts +38 -0
- package/runtime/core/second-nature/outreach/dispatch-user-outreach.js +119 -0
- package/runtime/core/second-nature/outreach/judge-input-from-snapshot.d.ts +7 -0
- package/runtime/core/second-nature/outreach/judge-input-from-snapshot.js +45 -0
- package/runtime/core/second-nature/outreach/judge-outreach.d.ts +40 -0
- package/runtime/core/second-nature/outreach/judge-outreach.js +121 -0
- package/runtime/core/second-nature/quiet/run-source-backed-quiet.d.ts +21 -0
- package/runtime/core/second-nature/quiet/run-source-backed-quiet.js +123 -0
- package/runtime/core/second-nature/rhythm/planner-rhythm-window.d.ts +15 -0
- package/runtime/core/second-nature/rhythm/planner-rhythm-window.js +52 -0
- package/runtime/core/second-nature/rhythm/policy-bridge.d.ts +19 -0
- package/runtime/core/second-nature/rhythm/policy-bridge.js +34 -0
- package/runtime/core/second-nature/types.d.ts +16 -2
- package/runtime/guidance/draft-outreach-message.d.ts +7 -0
- package/runtime/guidance/draft-outreach-message.js +42 -0
- package/runtime/guidance/evidence-guidance.d.ts +40 -0
- package/runtime/guidance/evidence-guidance.js +52 -0
- package/runtime/guidance/index.d.ts +3 -0
- package/runtime/guidance/index.js +3 -0
- package/runtime/guidance/outreach-draft-schema.d.ts +228 -0
- package/runtime/guidance/outreach-draft-schema.js +80 -0
- package/runtime/observability/audit/append-only-audit-store.d.ts +14 -0
- package/runtime/observability/audit/append-only-audit-store.js +21 -0
- package/runtime/observability/audit/audit-envelope.d.ts +51 -0
- package/runtime/observability/audit/audit-envelope.js +130 -0
- package/runtime/observability/audit/verify-audit-hash-chain.d.ts +23 -0
- package/runtime/observability/audit/verify-audit-hash-chain.js +83 -0
- package/runtime/observability/db/index.js +11 -0
- package/runtime/observability/db/schema/host-capability-reports.d.ts +180 -0
- package/runtime/observability/db/schema/host-capability-reports.js +12 -0
- package/runtime/observability/db/schema/index.d.ts +1 -0
- package/runtime/observability/db/schema/index.js +1 -0
- package/runtime/observability/index.d.ts +7 -0
- package/runtime/observability/index.js +7 -0
- package/runtime/observability/query/explain-query.d.ts +48 -0
- package/runtime/observability/query/explain-query.js +114 -0
- package/runtime/observability/query/export-audit-bundle.d.ts +22 -0
- package/runtime/observability/query/export-audit-bundle.js +27 -0
- package/runtime/observability/services/decision-ledger.d.ts +1 -1
- package/runtime/observability/services/decision-ledger.js +4 -0
- package/runtime/observability/services/execution-telemetry.d.ts +0 -1
- package/runtime/observability/services/governance-audit.d.ts +14 -0
- package/runtime/observability/services/governance-audit.js +25 -1
- package/runtime/observability/services/governance-plane-recorder.d.ts +47 -0
- package/runtime/observability/services/governance-plane-recorder.js +55 -0
- package/runtime/observability/services/lived-experience-audit.d.ts +97 -0
- package/runtime/observability/services/lived-experience-audit.js +161 -0
- package/runtime/storage/bootstrap/native-sqlite-probe.d.ts +7 -0
- package/runtime/storage/bootstrap/native-sqlite-probe.js +28 -0
- package/runtime/storage/bootstrap/repair-gate.d.ts +17 -0
- package/runtime/storage/bootstrap/repair-gate.js +71 -0
- package/runtime/storage/bootstrap/storage-mode-smoke.d.ts +38 -0
- package/runtime/storage/bootstrap/storage-mode-smoke.js +85 -0
- package/runtime/storage/db/index.js +49 -0
- package/runtime/storage/db/schema/delivery-attempts.d.ts +199 -0
- package/runtime/storage/db/schema/delivery-attempts.js +13 -0
- package/runtime/storage/db/schema/index.d.ts +3 -0
- package/runtime/storage/db/schema/index.js +3 -0
- package/runtime/storage/db/schema/life-evidence-index.d.ts +161 -0
- package/runtime/storage/db/schema/life-evidence-index.js +11 -0
- package/runtime/storage/db/schema/operator-fallback-artifacts.d.ts +161 -0
- package/runtime/storage/db/schema/operator-fallback-artifacts.js +11 -0
- package/runtime/storage/db/schema/policies.d.ts +17 -0
- package/runtime/storage/db/schema/policies.js +1 -0
- package/runtime/storage/delivery/query-delivery-attempts.d.ts +3 -0
- package/runtime/storage/delivery/query-delivery-attempts.js +32 -0
- package/runtime/storage/delivery/types.d.ts +27 -0
- package/runtime/storage/delivery/types.js +1 -0
- package/runtime/storage/delivery/write-delivery-attempt.d.ts +6 -0
- package/runtime/storage/delivery/write-delivery-attempt.js +36 -0
- package/runtime/storage/fallback/load-operator-fallback.d.ts +14 -0
- package/runtime/storage/fallback/load-operator-fallback.js +47 -0
- package/runtime/storage/fallback/operator-fallback-types.d.ts +9 -0
- package/runtime/storage/fallback/operator-fallback-types.js +1 -0
- package/runtime/storage/fallback/operator-fallback-view.d.ts +11 -0
- package/runtime/storage/fallback/operator-fallback-view.js +1 -0
- package/runtime/storage/fallback/write-operator-fallback.d.ts +6 -0
- package/runtime/storage/fallback/write-operator-fallback.js +21 -0
- package/runtime/storage/index.d.ts +21 -0
- package/runtime/storage/index.js +14 -0
- package/runtime/storage/life-evidence/append-life-evidence.d.ts +7 -0
- package/runtime/storage/life-evidence/append-life-evidence.js +64 -0
- package/runtime/storage/life-evidence/types.d.ts +45 -0
- package/runtime/storage/life-evidence/types.js +6 -0
- package/runtime/storage/quiet/persist-quiet-artifact.d.ts +7 -0
- package/runtime/storage/quiet/persist-quiet-artifact.js +22 -0
- package/runtime/storage/quiet/quiet-artifact-types.d.ts +18 -0
- package/runtime/storage/quiet/quiet-artifact-types.js +1 -0
- package/runtime/storage/quiet/quiet-artifact-writer.d.ts +15 -0
- package/runtime/storage/quiet/quiet-artifact-writer.js +56 -0
- package/runtime/storage/rhythm/rhythm-policy-snapshot.d.ts +10 -0
- package/runtime/storage/rhythm/rhythm-policy-snapshot.js +34 -0
- package/runtime/storage/services/credential-vault.d.ts +5 -0
- package/runtime/storage/services/credential-vault.js +46 -9
- package/runtime/storage/snapshots/continuity-snapshot.d.ts +9 -0
- package/runtime/storage/snapshots/continuity-snapshot.js +41 -0
- package/runtime/storage/snapshots/life-evidence-snapshot.d.ts +6 -0
- package/runtime/storage/snapshots/life-evidence-snapshot.js +114 -0
- package/runtime/storage/snapshots/types.d.ts +58 -0
- package/runtime/storage/snapshots/types.js +1 -0
- package/runtime/storage/state-api.js +11 -4
- package/runtime/storage/user-interest/load-user-interest-snapshot.d.ts +2 -0
- package/runtime/storage/user-interest/load-user-interest-snapshot.js +150 -0
- package/runtime/storage/user-interest/types.d.ts +25 -0
- package/runtime/storage/user-interest/types.js +1 -0
package/index.js
CHANGED
|
@@ -1,125 +1,432 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Host-safe Second Nature plugin surface.
|
|
3
|
+
*
|
|
4
|
+
* Core logic:
|
|
5
|
+
* - keep register(api) synchronous so OpenClaw captures services/command/tool before return
|
|
6
|
+
* - avoid importing CLI/runtime DB modules at module-evaluation time because the packaged
|
|
7
|
+
* runtime graph currently contains async sql.js bootstrap that breaks vm sandbox loading
|
|
8
|
+
* - expose a minimal in-memory activation spine so status/lifecycle stay truthful even when
|
|
9
|
+
* the full workspace runtime is not loaded inside the host
|
|
10
|
+
*
|
|
11
|
+
* Dependencies:
|
|
12
|
+
* - only imports runtime lifecycle/service modules that are synchronous at load time
|
|
13
|
+
*
|
|
14
|
+
* Boundaries:
|
|
15
|
+
* - read-only operator flows stay available through command/tool surface
|
|
16
|
+
* - structured mutating flows such as policy set / credential verify remain unavailable here
|
|
17
|
+
* - full evidence-backed workspace runtime can be reintroduced later behind a host-safe boundary
|
|
18
|
+
*
|
|
19
|
+
* Test coverage:
|
|
20
|
+
* - tests/integration/cli/plugin-runtime-registration.test.ts
|
|
21
|
+
* - tests/integration/cli/plugin-packaging-walkthrough.test.ts
|
|
22
|
+
*/
|
|
5
23
|
import { startRuntimeService, } from "./runtime/core/second-nature/runtime/service-entry.js";
|
|
6
24
|
import { getLifecycleState, recordRegistration, } from "./runtime/core/second-nature/runtime/lifecycle-service.js";
|
|
7
|
-
const INTERNAL_RUNTIME_PLATFORM_ID = "second-nature-runtime";
|
|
8
25
|
const INTERNAL_RUNTIME_TRACE_PREFIX = "sn-runtime-";
|
|
9
|
-
const
|
|
26
|
+
const HOST_SAFE_LIMITATION_MESSAGE = "Host-safe plugin package keeps synchronous register/load semantics, but mutating workspace runtime flows remain unavailable here.";
|
|
10
27
|
let activationSpine = null;
|
|
11
|
-
function
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
28
|
+
function trimRuntimeEvidence(spine) {
|
|
29
|
+
if (spine.runtimeEvidence.length > 12) {
|
|
30
|
+
spine.runtimeEvidence.splice(0, spine.runtimeEvidence.length - 12);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function latestRuntimeEvidence(spine) {
|
|
34
|
+
return spine.runtimeEvidence[spine.runtimeEvidence.length - 1];
|
|
35
|
+
}
|
|
36
|
+
function createUnavailableActionError(code, message, requiredUserInput, nextStep) {
|
|
37
|
+
return {
|
|
38
|
+
ok: false,
|
|
39
|
+
error: {
|
|
40
|
+
code,
|
|
41
|
+
message,
|
|
42
|
+
requiredUserInput,
|
|
43
|
+
nextStep,
|
|
44
|
+
},
|
|
45
|
+
message: HOST_SAFE_LIMITATION_MESSAGE,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
function parseExplainSubject(subjectRaw) {
|
|
49
|
+
const trimmed = subjectRaw.trim();
|
|
50
|
+
if (!trimmed) {
|
|
51
|
+
throw new Error("explain_subject_invalid");
|
|
52
|
+
}
|
|
53
|
+
const separatorIndex = trimmed.indexOf(":");
|
|
54
|
+
if (separatorIndex === -1) {
|
|
55
|
+
throw new Error("explain_subject_requires_id");
|
|
56
|
+
}
|
|
57
|
+
const kind = trimmed.slice(0, separatorIndex).trim();
|
|
58
|
+
const id = trimmed.slice(separatorIndex + 1).trim();
|
|
59
|
+
if (!id) {
|
|
60
|
+
throw new Error("explain_subject_requires_id");
|
|
61
|
+
}
|
|
62
|
+
switch (kind) {
|
|
63
|
+
case "decision":
|
|
64
|
+
return { subjectType: "decision", subjectId: id };
|
|
65
|
+
case "platform":
|
|
66
|
+
case "platform-selection":
|
|
67
|
+
return { subjectType: "platform-selection", subjectId: id };
|
|
68
|
+
case "outreach":
|
|
69
|
+
return { subjectType: "outreach", subjectId: id };
|
|
70
|
+
case "soul":
|
|
71
|
+
case "soul-change":
|
|
72
|
+
return { subjectType: "soul-change", subjectId: id };
|
|
73
|
+
case "fallback":
|
|
74
|
+
return { subjectType: "fallback", subjectId: id };
|
|
75
|
+
case "probe":
|
|
76
|
+
return { subjectType: "probe", subjectId: id };
|
|
77
|
+
case "report":
|
|
78
|
+
return { subjectType: "report", subjectId: id };
|
|
79
|
+
case "delivery":
|
|
80
|
+
return { subjectType: "delivery", subjectId: id };
|
|
81
|
+
case "source":
|
|
82
|
+
case "source_ref":
|
|
83
|
+
return { subjectType: "source_ref", subjectId: id };
|
|
84
|
+
default:
|
|
85
|
+
throw new Error("explain_subject_unsupported");
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function buildStatusPayload(spine) {
|
|
89
|
+
const runtimeEvidence = latestRuntimeEvidence(spine);
|
|
90
|
+
const updatedAt = runtimeEvidence?.createdAt ?? new Date(spine.lifecycleState.lastChangedAt).toISOString();
|
|
91
|
+
return {
|
|
92
|
+
ok: true,
|
|
93
|
+
data: {
|
|
94
|
+
runtime: {
|
|
95
|
+
host: "openclaw-plugin",
|
|
96
|
+
serviceStatus: spine.runtimeHandle.ready ? "running" : "idle",
|
|
97
|
+
updatedAt,
|
|
98
|
+
},
|
|
99
|
+
rhythm: {
|
|
100
|
+
mode: "active",
|
|
101
|
+
windowId: undefined,
|
|
102
|
+
},
|
|
103
|
+
quiet: {
|
|
104
|
+
mode: "unknown",
|
|
105
|
+
lastEvent: runtimeEvidence?.traceId,
|
|
106
|
+
interrupted: undefined,
|
|
107
|
+
},
|
|
108
|
+
connectors: [],
|
|
109
|
+
credentials: [],
|
|
110
|
+
risk: {
|
|
111
|
+
level: "low",
|
|
112
|
+
flags: [],
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function buildQuietPayload(scope) {
|
|
118
|
+
return {
|
|
119
|
+
ok: true,
|
|
120
|
+
data: {
|
|
121
|
+
scope,
|
|
122
|
+
mode: "unknown",
|
|
123
|
+
sourceCount: 0,
|
|
124
|
+
reportCount: 0,
|
|
125
|
+
recentJournalCount: 0,
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function buildReportPayload(day) {
|
|
130
|
+
return {
|
|
131
|
+
ok: true,
|
|
132
|
+
data: {
|
|
133
|
+
day: day && day.trim() ? day : new Date().toISOString().slice(0, 10),
|
|
134
|
+
summary: "",
|
|
135
|
+
highlights: [],
|
|
136
|
+
sourceRefs: [],
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
function buildSessionPayload(sessionId) {
|
|
141
|
+
if (!sessionId) {
|
|
142
|
+
return {
|
|
17
143
|
ok: false,
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
144
|
+
error: {
|
|
145
|
+
code: "MISSING_SESSION_ID",
|
|
146
|
+
message: "session show requires sessionId",
|
|
147
|
+
requiredUserInput: ["session_id"],
|
|
148
|
+
nextStep: "reinvoke_session_with_session_id",
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
return {
|
|
153
|
+
ok: true,
|
|
154
|
+
data: {
|
|
155
|
+
requestedSessionId: sessionId,
|
|
156
|
+
traceId: sessionId,
|
|
157
|
+
decisionCount: 0,
|
|
158
|
+
attemptCount: 0,
|
|
159
|
+
governanceCount: 0,
|
|
160
|
+
keyFactors: [],
|
|
161
|
+
evidenceRefs: [],
|
|
162
|
+
},
|
|
163
|
+
};
|
|
22
164
|
}
|
|
23
|
-
function
|
|
24
|
-
const commands = createFallbackCommands();
|
|
165
|
+
function buildCredentialPayload(platformId) {
|
|
25
166
|
return {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
167
|
+
ok: true,
|
|
168
|
+
data: {
|
|
169
|
+
platformId: platformId && platformId.trim() ? platformId : "unknown",
|
|
170
|
+
status: "missing",
|
|
171
|
+
nextStep: "provide_credential_context",
|
|
29
172
|
},
|
|
30
173
|
};
|
|
31
174
|
}
|
|
32
|
-
function
|
|
33
|
-
if (
|
|
34
|
-
return
|
|
175
|
+
function buildExplainPayload(spine, subjectRaw) {
|
|
176
|
+
if (!subjectRaw?.trim()) {
|
|
177
|
+
return {
|
|
178
|
+
ok: false,
|
|
179
|
+
error: {
|
|
180
|
+
code: "MISSING_EXPLAIN_SUBJECT",
|
|
181
|
+
message: "explain requires subject",
|
|
182
|
+
requiredUserInput: ["subject"],
|
|
183
|
+
nextStep: "reinvoke_explain_with_subject",
|
|
184
|
+
},
|
|
185
|
+
};
|
|
35
186
|
}
|
|
187
|
+
let subject;
|
|
36
188
|
try {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
189
|
+
subject = parseExplainSubject(subjectRaw);
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
const code = error.message;
|
|
193
|
+
if (code === "explain_subject_requires_id") {
|
|
194
|
+
return createUnavailableActionError("EXPLAIN_SUBJECT_REQUIRES_ID", "subject must include identifier", ["subject"], "reinvoke_explain_with_supported_subject");
|
|
195
|
+
}
|
|
196
|
+
if (code === "explain_subject_unsupported") {
|
|
197
|
+
return createUnavailableActionError("EXPLAIN_SUBJECT_UNSUPPORTED", "supported subjects include decision:, platform:, outreach:, soul:, fallback:, delivery:, probe:, report:, source:", ["subject"], "reinvoke_explain_with_supported_subject");
|
|
198
|
+
}
|
|
199
|
+
return createUnavailableActionError("EXPLAIN_SUBJECT_INVALID", "invalid explain subject", ["subject"], "reinvoke_explain_with_supported_subject");
|
|
200
|
+
}
|
|
201
|
+
const runtimeEvidence = latestRuntimeEvidence(spine);
|
|
202
|
+
return {
|
|
203
|
+
ok: true,
|
|
204
|
+
data: {
|
|
205
|
+
subjectType: subject.subjectType,
|
|
206
|
+
conclusion: "Plugin surface is loaded in host-safe mode with a minimal activation spine.",
|
|
207
|
+
keyFactors: [
|
|
208
|
+
"synchronous_register",
|
|
209
|
+
`subject:${subject.subjectId}`,
|
|
210
|
+
runtimeEvidence?.capability ?? "runtime.activate",
|
|
211
|
+
],
|
|
212
|
+
evidenceRefs: [
|
|
213
|
+
runtimeEvidence?.traceId ?? `${INTERNAL_RUNTIME_TRACE_PREFIX}none`,
|
|
214
|
+
`subject:${subjectRaw.trim()}`,
|
|
215
|
+
"host_safe_mode",
|
|
216
|
+
],
|
|
217
|
+
nextStep: "use full workspace runtime for evidence-backed explain details",
|
|
218
|
+
},
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
async function buildStorageSmokePayload(input) {
|
|
222
|
+
try {
|
|
223
|
+
const mod = await import("./runtime/storage/bootstrap/storage-mode-smoke.js");
|
|
224
|
+
const runRepairFixture = Boolean(input?.runRepairFixture);
|
|
225
|
+
const workspaceRoot = typeof input?.workspaceRoot === "string" ? input.workspaceRoot : undefined;
|
|
226
|
+
const data = await mod.runStorageModeSmoke({ runRepairFixture, workspaceRoot });
|
|
227
|
+
return { ok: true, data };
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
return {
|
|
231
|
+
ok: false,
|
|
232
|
+
message: error instanceof Error ? error.message : String(error),
|
|
233
|
+
error: {
|
|
234
|
+
code: "STORAGE_SMOKE_LOAD_FAILED",
|
|
235
|
+
message: "Could not load packaged storage-mode smoke module",
|
|
236
|
+
nextStep: "rebuild_plugin_runtime_package",
|
|
237
|
+
},
|
|
47
238
|
};
|
|
48
|
-
return activationSpine;
|
|
49
239
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
240
|
+
}
|
|
241
|
+
function buildFallbackHostSafePayload(ref) {
|
|
242
|
+
if (!ref?.trim()) {
|
|
243
|
+
return {
|
|
244
|
+
ok: false,
|
|
245
|
+
error: {
|
|
246
|
+
code: "MISSING_FALLBACK_REF",
|
|
247
|
+
message: "fallback requires ref (e.g. fallback:…)",
|
|
248
|
+
requiredUserInput: ["ref"],
|
|
249
|
+
nextStep: "reinvoke_with_ref",
|
|
250
|
+
},
|
|
56
251
|
};
|
|
57
|
-
return activationSpine;
|
|
58
252
|
}
|
|
253
|
+
return createUnavailableActionError("HOST_SAFE_FALLBACK_VIEW_UNAVAILABLE", "Operator fallback view requires workspace state database; host-safe plugin cannot read persisted fallback artifacts.", ["ref"], "run_workspace_second_nature_cli_or_full_runtime_package");
|
|
59
254
|
}
|
|
60
|
-
function
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
255
|
+
function buildHeartbeatCheckPayload(spine, input) {
|
|
256
|
+
const runtimeEvidence = latestRuntimeEvidence(spine);
|
|
257
|
+
const updatedAt = runtimeEvidence?.createdAt ?? new Date(spine.lifecycleState.lastChangedAt).toISOString();
|
|
258
|
+
const timestamp = typeof input?.timestamp === "string" && input.timestamp.trim().length > 0 ? input.timestamp : updatedAt;
|
|
259
|
+
return {
|
|
260
|
+
ok: true,
|
|
261
|
+
status: "heartbeat_ok",
|
|
262
|
+
heartbeat: "HEARTBEAT_OK",
|
|
263
|
+
scope: "rhythm",
|
|
264
|
+
trigger: "heartbeat_bridge",
|
|
265
|
+
reasons: ["host_safe_bridge_ready"],
|
|
266
|
+
nextAction: "continue",
|
|
267
|
+
message: "Host-safe heartbeat bridge acknowledged the round. No additional action is required from this surface.",
|
|
268
|
+
data: {
|
|
269
|
+
runtime: {
|
|
270
|
+
host: "openclaw-plugin",
|
|
271
|
+
serviceStatus: spine.runtimeHandle.ready ? "running" : "idle",
|
|
272
|
+
updatedAt,
|
|
273
|
+
},
|
|
274
|
+
surface: {
|
|
275
|
+
tool: "second_nature_ops",
|
|
276
|
+
command: "second-nature heartbeat_check",
|
|
277
|
+
},
|
|
278
|
+
bridge: {
|
|
279
|
+
timestamp,
|
|
280
|
+
sessionContextProvided: typeof input?.sessionContext === "string" && input.sessionContext.trim().length > 0,
|
|
281
|
+
heartbeatChecklistProvided: typeof input?.heartbeatChecklist === "string" && input.heartbeatChecklist.trim().length > 0,
|
|
282
|
+
serviceEntryMode: "runtime_carrier_only",
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
function createHostSafeRouter(spine) {
|
|
288
|
+
const notImplemented = async (command) => ({
|
|
289
|
+
ok: false,
|
|
290
|
+
command,
|
|
291
|
+
message: HOST_SAFE_LIMITATION_MESSAGE,
|
|
292
|
+
});
|
|
293
|
+
const commands = [
|
|
294
|
+
{
|
|
295
|
+
name: "status",
|
|
296
|
+
description: "Show aggregated Second Nature status",
|
|
297
|
+
execute: async () => buildStatusPayload(spine),
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
name: "policy",
|
|
301
|
+
description: "Write or inspect policy state",
|
|
302
|
+
execute: async (input) => {
|
|
303
|
+
const action = typeof input?.action === "string" ? input.action : "show";
|
|
304
|
+
if (action === "set") {
|
|
305
|
+
return createUnavailableActionError("HOST_SAFE_POLICY_SET_UNAVAILABLE", "policy set is unavailable in the host-safe plugin package", ["social_daily_limit", "quiet_enabled"], "run_workspace_runtime_or_reinstall_full_build");
|
|
306
|
+
}
|
|
307
|
+
return notImplemented("policy");
|
|
308
|
+
},
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
name: "credential",
|
|
312
|
+
description: "Inspect or recover credential state",
|
|
313
|
+
execute: async (input) => {
|
|
314
|
+
const action = typeof input?.action === "string" ? input.action : "show";
|
|
315
|
+
if (action === "verify") {
|
|
316
|
+
return createUnavailableActionError("HOST_SAFE_CREDENTIAL_VERIFY_UNAVAILABLE", "credential verify is unavailable in the host-safe plugin package", ["verification_answer"], "run_workspace_runtime_or_reinstall_full_build");
|
|
317
|
+
}
|
|
318
|
+
const platformId = typeof input?.platformId === "string" ? input.platformId : undefined;
|
|
319
|
+
return buildCredentialPayload(platformId);
|
|
320
|
+
},
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
name: "quiet",
|
|
324
|
+
description: "Inspect Quiet lifecycle state",
|
|
325
|
+
execute: async (input) => {
|
|
326
|
+
const scope = typeof input?.scope === "string" ? input.scope : undefined;
|
|
327
|
+
return buildQuietPayload(scope);
|
|
328
|
+
},
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
name: "report",
|
|
332
|
+
description: "Show daily report artifacts",
|
|
333
|
+
execute: async (input) => {
|
|
334
|
+
const day = typeof input?.day === "string" ? input.day : undefined;
|
|
335
|
+
return buildReportPayload(day);
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
name: "session",
|
|
340
|
+
description: "Inspect continuity session details",
|
|
341
|
+
execute: async (input) => {
|
|
342
|
+
const sessionId = typeof input?.sessionId === "string" ? input.sessionId : undefined;
|
|
343
|
+
return buildSessionPayload(sessionId);
|
|
344
|
+
},
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
name: "audit",
|
|
348
|
+
description: "Inspect audit and evidence views",
|
|
349
|
+
execute: async () => notImplemented("audit"),
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
name: "explain",
|
|
353
|
+
description: "Answer why-question explain requests",
|
|
354
|
+
execute: async (input) => {
|
|
355
|
+
const subject = typeof input?.subject === "string" ? input.subject : undefined;
|
|
356
|
+
return buildExplainPayload(spine, subject);
|
|
357
|
+
},
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
name: "heartbeat_check",
|
|
361
|
+
description: "Acknowledge the shipping heartbeat bridge round",
|
|
362
|
+
execute: async (input) => buildHeartbeatCheckPayload(spine, input),
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
name: "fallback",
|
|
366
|
+
description: "Operator-visible delivery fallback view (full workspace runtime required)",
|
|
367
|
+
execute: async (input) => {
|
|
368
|
+
const ref = typeof input?.ref === "string" ? input.ref.trim() : undefined;
|
|
369
|
+
return buildFallbackHostSafePayload(ref);
|
|
370
|
+
},
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
name: "storage_smoke",
|
|
374
|
+
description: "T4.1.4 storage mode smoke report (sql.js vs native probe)",
|
|
375
|
+
execute: async (input) => buildStorageSmokePayload(input),
|
|
376
|
+
},
|
|
377
|
+
];
|
|
378
|
+
return {
|
|
379
|
+
commands,
|
|
380
|
+
resolve(name) {
|
|
381
|
+
return commands.find((command) => command.name === name);
|
|
382
|
+
},
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
function createActivationSpine() {
|
|
386
|
+
const spine = {
|
|
387
|
+
router: undefined,
|
|
388
|
+
runtimeHandle: startRuntimeService({ workspaceRoot: process.cwd() }),
|
|
389
|
+
lifecycleState: getLifecycleState(),
|
|
390
|
+
serviceStartRecorded: false,
|
|
391
|
+
runtimeEvidence: [],
|
|
392
|
+
};
|
|
393
|
+
spine.router = createHostSafeRouter(spine);
|
|
66
394
|
return spine;
|
|
67
395
|
}
|
|
68
|
-
function
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
if (!decisionLedger || !executionTelemetry) {
|
|
72
|
-
return;
|
|
396
|
+
function ensureActivationSpine() {
|
|
397
|
+
if (activationSpine) {
|
|
398
|
+
return activationSpine;
|
|
73
399
|
}
|
|
400
|
+
activationSpine = createActivationSpine();
|
|
401
|
+
return activationSpine;
|
|
402
|
+
}
|
|
403
|
+
function recordRuntimeEvidence(spine, origin) {
|
|
74
404
|
if (origin === "service_start" && spine.serviceStartRecorded) {
|
|
75
405
|
return;
|
|
76
406
|
}
|
|
77
407
|
if (origin === "service_start") {
|
|
78
408
|
spine.serviceStartRecorded = true;
|
|
79
409
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
: "
|
|
90
|
-
void (async () => {
|
|
91
|
-
await decisionLedger.recordHeartbeatDecision({
|
|
92
|
-
id: decisionId,
|
|
93
|
-
tickId,
|
|
94
|
-
traceId,
|
|
95
|
-
intentId,
|
|
96
|
-
runtimeScope: "rhythm",
|
|
97
|
-
triggerSource: "heartbeat_bridge",
|
|
98
|
-
decisionStatus: "heartbeat_ok",
|
|
99
|
-
reasons: [
|
|
100
|
-
`origin:${origin}`,
|
|
101
|
-
`phase:${spine.lifecycleState.phase}`,
|
|
102
|
-
`registrations:${spine.lifecycleState.registerCount}`,
|
|
103
|
-
],
|
|
104
|
-
mode: "active",
|
|
105
|
-
createdAt: now,
|
|
106
|
-
});
|
|
107
|
-
await executionTelemetry.startAttempt({
|
|
108
|
-
traceId,
|
|
109
|
-
decisionId,
|
|
110
|
-
intentId,
|
|
111
|
-
platformId: INTERNAL_RUNTIME_PLATFORM_ID,
|
|
112
|
-
capability,
|
|
113
|
-
channel: INTERNAL_RUNTIME_CHANNEL,
|
|
114
|
-
status: "started",
|
|
115
|
-
startedAt: now,
|
|
116
|
-
});
|
|
117
|
-
await executionTelemetry.completeAttempt(traceId, "succeeded", "committed");
|
|
118
|
-
})().catch(() => {
|
|
119
|
-
if (origin === "service_start") {
|
|
120
|
-
spine.serviceStartRecorded = false;
|
|
121
|
-
}
|
|
410
|
+
spine.runtimeEvidence.push({
|
|
411
|
+
traceId: `${INTERNAL_RUNTIME_TRACE_PREFIX}${origin}-${spine.lifecycleState.registerCount}-${Date.now()}`,
|
|
412
|
+
capability: origin === "register"
|
|
413
|
+
? spine.lifecycleState.registerCount === 1
|
|
414
|
+
? "runtime.activate"
|
|
415
|
+
: "runtime.reload"
|
|
416
|
+
: "runtime.heartbeat",
|
|
417
|
+
origin,
|
|
418
|
+
createdAt: new Date().toISOString(),
|
|
419
|
+
status: "succeeded",
|
|
122
420
|
});
|
|
421
|
+
trimRuntimeEvidence(spine);
|
|
422
|
+
}
|
|
423
|
+
function refreshRegistrationState() {
|
|
424
|
+
const spine = ensureActivationSpine();
|
|
425
|
+
spine.runtimeHandle = startRuntimeService({ workspaceRoot: process.cwd() });
|
|
426
|
+
spine.lifecycleState = recordRegistration();
|
|
427
|
+
spine.serviceStartRecorded = false;
|
|
428
|
+
recordRuntimeEvidence(spine, "register");
|
|
429
|
+
return spine;
|
|
123
430
|
}
|
|
124
431
|
function parseCommandInput(rawArgs) {
|
|
125
432
|
const tokens = rawArgs?.trim().split(/\s+/).filter(Boolean) ?? [];
|
|
@@ -176,12 +483,37 @@ function parseCommandInput(rawArgs) {
|
|
|
176
483
|
command,
|
|
177
484
|
input: rest[0] ? { platformId: rest[0] } : undefined,
|
|
178
485
|
};
|
|
486
|
+
case "heartbeat_check":
|
|
487
|
+
return {
|
|
488
|
+
ok: true,
|
|
489
|
+
command,
|
|
490
|
+
input: rest.length > 0
|
|
491
|
+
? {
|
|
492
|
+
timestamp: rest[0],
|
|
493
|
+
sessionContext: rest.length > 1 ? rest.slice(1).join(" ") : undefined,
|
|
494
|
+
}
|
|
495
|
+
: undefined,
|
|
496
|
+
};
|
|
179
497
|
case "explain":
|
|
180
498
|
return {
|
|
181
499
|
ok: true,
|
|
182
500
|
command,
|
|
183
501
|
input: rest.length > 0 ? { subject: rest.join(" ") } : undefined,
|
|
184
502
|
};
|
|
503
|
+
case "fallback":
|
|
504
|
+
return {
|
|
505
|
+
ok: true,
|
|
506
|
+
command,
|
|
507
|
+
input: rest.length > 0 ? { ref: rest.join(" ") } : undefined,
|
|
508
|
+
};
|
|
509
|
+
case "storage_smoke": {
|
|
510
|
+
const wantRepair = rest[0] === "repair" || rest.includes("--repair");
|
|
511
|
+
return {
|
|
512
|
+
ok: true,
|
|
513
|
+
command,
|
|
514
|
+
input: wantRepair ? { runRepairFixture: true } : undefined,
|
|
515
|
+
};
|
|
516
|
+
}
|
|
185
517
|
default:
|
|
186
518
|
return {
|
|
187
519
|
ok: true,
|
|
@@ -221,7 +553,6 @@ export default {
|
|
|
221
553
|
name: "Second Nature",
|
|
222
554
|
description: "Registers command/tool/service surface with load-reload lifecycle semantics.",
|
|
223
555
|
register(api) {
|
|
224
|
-
const spine = refreshRegistrationState();
|
|
225
556
|
const runtimeService = createRuntimeService();
|
|
226
557
|
const lifecycleService = createLifecycleService();
|
|
227
558
|
api.registerService(runtimeService);
|
|
@@ -231,6 +562,7 @@ export default {
|
|
|
231
562
|
description: "Route Agent-facing operational commands for Second Nature.",
|
|
232
563
|
acceptsArgs: true,
|
|
233
564
|
handler: async (ctx) => {
|
|
565
|
+
const spine = ensureActivationSpine();
|
|
234
566
|
const parsed = parseCommandInput(ctx.args);
|
|
235
567
|
if (!parsed.ok) {
|
|
236
568
|
return {
|
|
@@ -262,6 +594,7 @@ export default {
|
|
|
262
594
|
required: ["command"],
|
|
263
595
|
},
|
|
264
596
|
async execute(_id, params) {
|
|
597
|
+
const spine = ensureActivationSpine();
|
|
265
598
|
const resolved = spine.router.resolve(params.command);
|
|
266
599
|
if (!resolved) {
|
|
267
600
|
return {
|
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ActionBridge } from "../action-bridge.js";
|
|
2
|
+
import type { OpsRouter } from "../ops/ops-router.js";
|
|
2
3
|
import type { CliReadModels } from "../read-models/index.js";
|
|
3
4
|
export interface CliCommandDefinition {
|
|
4
5
|
name: string;
|
|
@@ -8,5 +9,6 @@ export interface CliCommandDefinition {
|
|
|
8
9
|
export interface CliCommandDeps {
|
|
9
10
|
readModels: CliReadModels;
|
|
10
11
|
actionBridge: ActionBridge;
|
|
12
|
+
opsRouter: OpsRouter;
|
|
11
13
|
}
|
|
12
14
|
export declare function createCliCommands(deps: CliCommandDeps): CliCommandDefinition[];
|