@haaaiawd/second-nature 0.1.8 → 0.1.10
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 +281 -69
- package/openclaw.plugin.json +1 -1
- package/package.json +2 -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 +16 -0
- 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/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 +162 -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/repositories/credential-repository.js +12 -1
- 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 +47 -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/workspace-ops-bridge.js +78 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { runHeartbeatCycle } from "../../core/second-nature/heartbeat/run-heartbeat-cycle.js";
|
|
2
|
+
export async function loadSnapshotInputsForWorkspaceHeartbeat(readModels) {
|
|
3
|
+
const status = await readModels.loadStatus();
|
|
4
|
+
const mode = status.rhythm.mode === "unknown" ? "active" : status.rhythm.mode;
|
|
5
|
+
const quietEnabledBridge = status.quiet.mode === "quiet";
|
|
6
|
+
return {
|
|
7
|
+
mode,
|
|
8
|
+
currentWindowId: status.rhythm.windowId ?? "workspace-default",
|
|
9
|
+
pendingObligations: [],
|
|
10
|
+
recentOutreachHashes: [],
|
|
11
|
+
deniedIntents: [],
|
|
12
|
+
budgets: { socialUsed: 0, socialLimit: 5 },
|
|
13
|
+
awaitingUserInput: false,
|
|
14
|
+
quietEnabledBridge,
|
|
15
|
+
deliveryCapability: { target: "none" },
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
export function createWorkspaceHeartbeatRunner(readModels) {
|
|
19
|
+
return (signal) => runHeartbeatCycle({
|
|
20
|
+
signal,
|
|
21
|
+
runtimeAvailable: true,
|
|
22
|
+
deps: {
|
|
23
|
+
loadSnapshotInputs: () => loadSnapshotInputsForWorkspaceHeartbeat(readModels),
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { StateDatabase } from "../../storage/db/index.js";
|
|
2
2
|
import type { ObservabilityDatabase } from "../../observability/db/index.js";
|
|
3
|
-
import
|
|
3
|
+
import { AppendOnlyAuditStore } from "../../observability/audit/append-only-audit-store.js";
|
|
4
|
+
import type { StatusReadModel, DailyReportReadModel, QuietReadModel, SessionDetailReadModel, CredentialReadModel, ExplainReadModel, ExplainSubjectKind } from "./types.js";
|
|
5
|
+
export type { ExplainSubjectKind } from "./types.js";
|
|
6
|
+
import type { OperatorFallbackView } from "../../storage/fallback/operator-fallback-view.js";
|
|
4
7
|
export interface CliReadModels {
|
|
5
8
|
loadStatus(scope?: string): Promise<StatusReadModel>;
|
|
6
9
|
loadDailyReport(day: string): Promise<DailyReportReadModel>;
|
|
@@ -8,13 +11,19 @@ export interface CliReadModels {
|
|
|
8
11
|
loadSession(sessionId: string): Promise<SessionDetailReadModel>;
|
|
9
12
|
loadCredential(platformId: string): Promise<CredentialReadModel>;
|
|
10
13
|
explain(subject: ExplainSubject): Promise<ExplainReadModel>;
|
|
14
|
+
/** T1.2.2 — persisted operator fallback; view status is always not_sent. */
|
|
15
|
+
loadFallbackView(ref: string): Promise<OperatorFallbackView | null>;
|
|
11
16
|
}
|
|
17
|
+
/** T1.2.1 / T1.2.2 — operator-facing read surface (subset of full CLI read models). */
|
|
18
|
+
export type OpsReadModelPort = Pick<CliReadModels, "loadStatus" | "loadDailyReport" | "loadQuiet" | "loadSession" | "loadCredential" | "explain" | "loadFallbackView">;
|
|
12
19
|
export interface ExplainSubject {
|
|
13
|
-
kind:
|
|
20
|
+
kind: ExplainSubjectKind;
|
|
14
21
|
id: string;
|
|
15
22
|
}
|
|
16
23
|
export interface CliReadModelsDeps {
|
|
17
24
|
stateDb: StateDatabase;
|
|
18
25
|
observabilityDb: ObservabilityDatabase;
|
|
26
|
+
/** When set, explain can resolve delivery/fallback/report/source_ref and enrich decision subjects from lived-experience audit envelopes (T5.3.1 / T1.2.1). */
|
|
27
|
+
livedExperienceAuditStore?: AppendOnlyAuditStore;
|
|
19
28
|
}
|
|
20
29
|
export declare function createCliReadModels(deps: CliReadModelsDeps): CliReadModels;
|
|
@@ -4,8 +4,33 @@ import { AssetRepository } from "../../storage/repositories/asset-repository.js"
|
|
|
4
4
|
import { CredentialRepository } from "../../storage/repositories/credential-repository.js";
|
|
5
5
|
import { EvidenceQueryEngine } from "../../observability/query/evidence-query-engine.js";
|
|
6
6
|
import { decisionLedger, executionAttempts } from "../../observability/db/schema/index.js";
|
|
7
|
+
import { queryExplain } from "../../observability/query/explain-query.js";
|
|
8
|
+
import { mapOperatorExplainToReadModel } from "./operator-explain-map.js";
|
|
9
|
+
import { loadOperatorFallbackRow, toOperatorFallbackView } from "../../storage/fallback/load-operator-fallback.js";
|
|
7
10
|
const INTERNAL_RUNTIME_PLATFORM_ID = "second-nature-runtime";
|
|
8
11
|
const INTERNAL_RUNTIME_TRACE_PREFIX = "sn-runtime-";
|
|
12
|
+
function toExplainQuery(subject) {
|
|
13
|
+
switch (subject.kind) {
|
|
14
|
+
case "decision":
|
|
15
|
+
return { kind: "decision", decisionId: subject.id };
|
|
16
|
+
case "fallback": {
|
|
17
|
+
const ref = subject.id.startsWith("fallback:") ? subject.id : `fallback:${subject.id}`;
|
|
18
|
+
return { kind: "fallback", fallbackRef: ref };
|
|
19
|
+
}
|
|
20
|
+
case "probe":
|
|
21
|
+
case "report":
|
|
22
|
+
return { kind: "report", reportId: subject.id };
|
|
23
|
+
case "delivery":
|
|
24
|
+
return { kind: "delivery", auditId: subject.id };
|
|
25
|
+
case "source_ref":
|
|
26
|
+
return { kind: "source_ref", sourceRefId: subject.id };
|
|
27
|
+
default:
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function isAuditOnlySubjectKind(kind) {
|
|
32
|
+
return kind === "fallback" || kind === "probe" || kind === "report" || kind === "delivery" || kind === "source_ref";
|
|
33
|
+
}
|
|
9
34
|
function buildCredentialNextStep(status) {
|
|
10
35
|
if (status === "pending_verification")
|
|
11
36
|
return "submit_verification_answer";
|
|
@@ -36,6 +61,7 @@ export function createCliReadModels(deps) {
|
|
|
36
61
|
const credentialRepository = new CredentialRepository(deps.stateDb);
|
|
37
62
|
const quietLoader = createQuietInputLoader(assetRepository);
|
|
38
63
|
const evidenceQuery = new EvidenceQueryEngine(deps.observabilityDb);
|
|
64
|
+
const auditStore = deps.livedExperienceAuditStore;
|
|
39
65
|
return {
|
|
40
66
|
async loadStatus(_scope) {
|
|
41
67
|
let recentAttempts = [];
|
|
@@ -190,7 +216,31 @@ export function createCliReadModels(deps) {
|
|
|
190
216
|
nextStep: buildCredentialNextStep(record.status),
|
|
191
217
|
};
|
|
192
218
|
},
|
|
219
|
+
async loadFallbackView(ref) {
|
|
220
|
+
const row = await loadOperatorFallbackRow(deps.stateDb, ref);
|
|
221
|
+
if (!row)
|
|
222
|
+
return null;
|
|
223
|
+
return toOperatorFallbackView(row);
|
|
224
|
+
},
|
|
193
225
|
async explain(subject) {
|
|
226
|
+
const q = toExplainQuery(subject);
|
|
227
|
+
if (auditStore && q) {
|
|
228
|
+
const op = queryExplain(q, auditStore);
|
|
229
|
+
if (isAuditOnlySubjectKind(subject.kind)) {
|
|
230
|
+
return mapOperatorExplainToReadModel(op, subject.kind);
|
|
231
|
+
}
|
|
232
|
+
if (op.relatedEventIds.length > 0) {
|
|
233
|
+
return mapOperatorExplainToReadModel(op, subject.kind);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
if (isAuditOnlySubjectKind(subject.kind)) {
|
|
237
|
+
return {
|
|
238
|
+
subjectType: subject.kind,
|
|
239
|
+
conclusion: auditStore ? "no_matching_audit_events" : "lived_experience_audit_store_unavailable",
|
|
240
|
+
keyFactors: auditStore ? [] : ["configure_lived_experience_audit_store_for_operator_explain"],
|
|
241
|
+
evidenceRefs: [],
|
|
242
|
+
};
|
|
243
|
+
}
|
|
194
244
|
const query = subject.kind === "decision" || subject.kind === "platform-selection" || subject.kind === "outreach"
|
|
195
245
|
? { decisionId: subject.id }
|
|
196
246
|
: { assetId: subject.id };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maps T5.3.1 operator explain query results into CLI ExplainReadModel (T1.2.1).
|
|
3
|
+
*/
|
|
4
|
+
import type { OperatorExplainReadModel } from "../../observability/query/explain-query.js";
|
|
5
|
+
import type { ExplainReadModel, ExplainSubjectKind } from "./types.js";
|
|
6
|
+
export declare function mapOperatorExplainToReadModel(op: OperatorExplainReadModel, subjectKind: ExplainSubjectKind): ExplainReadModel;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function mapOperatorExplainToReadModel(op, subjectKind) {
|
|
2
|
+
return {
|
|
3
|
+
subjectType: subjectKind,
|
|
4
|
+
conclusion: op.summary,
|
|
5
|
+
keyFactors: op.events.map((e) => `${e.eventId}:${e.summary}`),
|
|
6
|
+
evidenceRefs: op.relatedEventIds.map((id) => `audit_event:${id}`),
|
|
7
|
+
warnings: op.warnings.length ? op.warnings : undefined,
|
|
8
|
+
relatedAuditEventIds: op.relatedEventIds.length ? op.relatedEventIds : undefined,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
@@ -64,12 +64,16 @@ export interface CredentialReadModel {
|
|
|
64
64
|
attemptsRemaining?: number;
|
|
65
65
|
nextStep?: string;
|
|
66
66
|
}
|
|
67
|
+
export type ExplainSubjectKind = "decision" | "platform-selection" | "outreach" | "soul-change" | "fallback" | "probe" | "delivery" | "report" | "source_ref";
|
|
67
68
|
export interface ExplainReadModel {
|
|
68
|
-
subjectType:
|
|
69
|
+
subjectType: ExplainSubjectKind;
|
|
69
70
|
conclusion: string;
|
|
70
71
|
keyFactors: string[];
|
|
71
72
|
evidenceRefs: string[];
|
|
72
73
|
policyRefs?: string[];
|
|
73
74
|
requiredUserInput?: string[];
|
|
74
75
|
nextStep?: string;
|
|
76
|
+
/** Operator / lived-experience audit warnings (e.g. no user-visible contact) */
|
|
77
|
+
warnings?: string[];
|
|
78
|
+
relatedAuditEventIds?: string[];
|
|
75
79
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export type SurfaceMode = "host_safe_carrier" | "workspace_full_runtime" | "capability_probe";
|
|
2
|
+
export type RuntimeArtifactModule = "runtime_registration" | "ops_router" | "heartbeat_bridge_adapter" | "host_capability_adapter" | "probe_runner" | "read_model_adapter" | "fallback_shell";
|
|
3
|
+
export interface RuntimeArtifactBoundary {
|
|
4
|
+
surfaceMode: SurfaceMode;
|
|
5
|
+
includes: RuntimeArtifactModule[];
|
|
6
|
+
fallbackAllowed: boolean;
|
|
7
|
+
sourcePathDependencyAllowed: false;
|
|
8
|
+
}
|
|
9
|
+
export type ResolvePackagedRuntimeResult = {
|
|
10
|
+
ok: true;
|
|
11
|
+
runtimeRoot: string;
|
|
12
|
+
boundary: RuntimeArtifactBoundary;
|
|
13
|
+
resolvedModules: Partial<Record<RuntimeArtifactModule, string>>;
|
|
14
|
+
} | {
|
|
15
|
+
ok: false;
|
|
16
|
+
code: "runtime_artifact_missing" | "runtime_layout_incomplete";
|
|
17
|
+
message: string;
|
|
18
|
+
runtimeRoot: string;
|
|
19
|
+
missingPaths: string[];
|
|
20
|
+
};
|
|
21
|
+
/** Relative paths under `plugin/runtime/` that the packaging script must copy. */
|
|
22
|
+
export declare const PACKAGED_RUNTIME_REQUIRED_ENTRIES: readonly string[];
|
|
23
|
+
export declare function detectForbiddenSourcePathDependencies(sourceText: string): string[];
|
|
24
|
+
export declare function defaultRuntimeArtifactBoundary(surfaceMode?: SurfaceMode): RuntimeArtifactBoundary;
|
|
25
|
+
/**
|
|
26
|
+
* Verify packaged plugin `runtime/` tree and entrypoints required for ADR-006 closure.
|
|
27
|
+
*/
|
|
28
|
+
export declare function resolvePackagedRuntime(packageRoot: string): ResolvePackagedRuntimeResult;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Packaged runtime artifact boundary (cli-system / ADR-006).
|
|
3
|
+
*
|
|
4
|
+
* Core logic: resolve plugin-local `runtime/` layout produced by build-plugin-package;
|
|
5
|
+
* forbid dev-only imports that reach repo `src/` from published surfaces.
|
|
6
|
+
*
|
|
7
|
+
* Boundaries: filesystem checks only; does not execute host loaders.
|
|
8
|
+
*
|
|
9
|
+
* Test coverage: tests/unit/cli/runtime-artifact-boundary.test.ts
|
|
10
|
+
*/
|
|
11
|
+
import fs from "node:fs";
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
/** Relative paths under `plugin/runtime/` that the packaging script must copy. */
|
|
14
|
+
export const PACKAGED_RUNTIME_REQUIRED_ENTRIES = [
|
|
15
|
+
"cli/index.js",
|
|
16
|
+
"storage/index.js",
|
|
17
|
+
"observability/index.js",
|
|
18
|
+
"core/second-nature/index.js",
|
|
19
|
+
"core/second-nature/runtime/service-entry.js",
|
|
20
|
+
"guidance/index.js",
|
|
21
|
+
"connectors/index.js",
|
|
22
|
+
"shared/types/index.js",
|
|
23
|
+
];
|
|
24
|
+
const DEFAULT_INCLUDES = [
|
|
25
|
+
"runtime_registration",
|
|
26
|
+
"ops_router",
|
|
27
|
+
"heartbeat_bridge_adapter",
|
|
28
|
+
"read_model_adapter",
|
|
29
|
+
"fallback_shell",
|
|
30
|
+
];
|
|
31
|
+
const SOURCE_REPO_PATH_PATTERN = /(?:from\s+["']|import\s+["']|require\s*\(\s*["'])(?:\.\.\/)+src\//i;
|
|
32
|
+
export function detectForbiddenSourcePathDependencies(sourceText) {
|
|
33
|
+
const hits = [];
|
|
34
|
+
const lines = sourceText.split(/\r?\n/);
|
|
35
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
36
|
+
const line = lines[i];
|
|
37
|
+
if (SOURCE_REPO_PATH_PATTERN.test(line)) {
|
|
38
|
+
hits.push(`line ${i + 1}: ${line.trim()}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return hits;
|
|
42
|
+
}
|
|
43
|
+
export function defaultRuntimeArtifactBoundary(surfaceMode = "workspace_full_runtime") {
|
|
44
|
+
return {
|
|
45
|
+
surfaceMode,
|
|
46
|
+
includes: [...DEFAULT_INCLUDES],
|
|
47
|
+
fallbackAllowed: true,
|
|
48
|
+
sourcePathDependencyAllowed: false,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Verify packaged plugin `runtime/` tree and entrypoints required for ADR-006 closure.
|
|
53
|
+
*/
|
|
54
|
+
export function resolvePackagedRuntime(packageRoot) {
|
|
55
|
+
const runtimeRoot = path.join(packageRoot, "runtime");
|
|
56
|
+
if (!fs.existsSync(runtimeRoot) || !fs.statSync(runtimeRoot).isDirectory()) {
|
|
57
|
+
return {
|
|
58
|
+
ok: false,
|
|
59
|
+
code: "runtime_artifact_missing",
|
|
60
|
+
message: `runtime directory missing under ${packageRoot}`,
|
|
61
|
+
runtimeRoot,
|
|
62
|
+
missingPaths: [runtimeRoot],
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
const missingPaths = [];
|
|
66
|
+
for (const rel of PACKAGED_RUNTIME_REQUIRED_ENTRIES) {
|
|
67
|
+
const abs = path.join(runtimeRoot, rel);
|
|
68
|
+
if (!fs.existsSync(abs)) {
|
|
69
|
+
missingPaths.push(abs);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (missingPaths.length > 0) {
|
|
73
|
+
return {
|
|
74
|
+
ok: false,
|
|
75
|
+
code: "runtime_layout_incomplete",
|
|
76
|
+
message: "packaged runtime is missing one or more required compiled modules",
|
|
77
|
+
runtimeRoot,
|
|
78
|
+
missingPaths,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const resolvedModules = {
|
|
82
|
+
ops_router: path.join(runtimeRoot, "cli/index.js"),
|
|
83
|
+
runtime_registration: path.join(runtimeRoot, "core/second-nature/runtime/service-entry.js"),
|
|
84
|
+
heartbeat_bridge_adapter: path.join(runtimeRoot, "core/second-nature/heartbeat/index.js"),
|
|
85
|
+
read_model_adapter: path.join(runtimeRoot, "cli/read-models/index.js"),
|
|
86
|
+
fallback_shell: path.join(runtimeRoot, "cli/index.js"),
|
|
87
|
+
};
|
|
88
|
+
return {
|
|
89
|
+
ok: true,
|
|
90
|
+
runtimeRoot,
|
|
91
|
+
boundary: defaultRuntimeArtifactBoundary(),
|
|
92
|
+
resolvedModules,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
@@ -20,6 +20,8 @@ export interface ExecutionPlan {
|
|
|
20
20
|
channel: ChannelType;
|
|
21
21
|
endpointMode: "rest_json" | "a2a_envelope" | "cli_stdout" | "skill_call";
|
|
22
22
|
idempotencyKey?: string;
|
|
23
|
+
/** True when selected channel is manifest-marked degraded (cli/skill/browser). */
|
|
24
|
+
degraded?: boolean;
|
|
23
25
|
}
|
|
24
26
|
export interface ConnectorResult<T> {
|
|
25
27
|
status: "success" | "retryable_failure" | "terminal_failure";
|
|
@@ -59,6 +61,10 @@ export interface ConnectorManifestLike {
|
|
|
59
61
|
channelPriority: ChannelType[];
|
|
60
62
|
credentialTypes: string[];
|
|
61
63
|
degradedChannels?: ChannelType[];
|
|
64
|
+
sourceRefPolicy?: {
|
|
65
|
+
minSourceRefs?: number;
|
|
66
|
+
rejectInlineSensitivePayload?: boolean;
|
|
67
|
+
};
|
|
62
68
|
}
|
|
63
69
|
export interface ConnectorManifestLoader {
|
|
64
70
|
loadManifest(platformId: string): ConnectorManifestLike;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { CapabilityIntent, ConnectorRequest, ExecutionPlan } from "./contract.js";
|
|
2
|
+
export type EffectSemanticsClass = "read_only" | "side_effect" | "task_claim" | "keepalive";
|
|
3
|
+
export declare function classifyConnectorIntentEffect(intent: CapabilityIntent): EffectSemanticsClass;
|
|
4
|
+
export interface EffectCommitLedgerPort {
|
|
5
|
+
getOrCreateIntentCommitRecord(input: {
|
|
6
|
+
decisionId: string;
|
|
7
|
+
intentId: string;
|
|
8
|
+
idempotencyKey: string;
|
|
9
|
+
effectClass: string;
|
|
10
|
+
}): Promise<{
|
|
11
|
+
existing: boolean;
|
|
12
|
+
record: {
|
|
13
|
+
id: string;
|
|
14
|
+
state: string;
|
|
15
|
+
outcomeRef?: string;
|
|
16
|
+
};
|
|
17
|
+
}>;
|
|
18
|
+
}
|
|
19
|
+
/** In-memory ledger for tests and offline harnesses. */
|
|
20
|
+
export declare class InMemoryEffectCommitLedger implements EffectCommitLedgerPort {
|
|
21
|
+
private readonly byKey;
|
|
22
|
+
private key;
|
|
23
|
+
getOrCreateIntentCommitRecord(input: {
|
|
24
|
+
decisionId: string;
|
|
25
|
+
intentId: string;
|
|
26
|
+
idempotencyKey: string;
|
|
27
|
+
effectClass: string;
|
|
28
|
+
}): Promise<{
|
|
29
|
+
existing: boolean;
|
|
30
|
+
record: {
|
|
31
|
+
id: string;
|
|
32
|
+
state: string;
|
|
33
|
+
outcomeRef?: string;
|
|
34
|
+
};
|
|
35
|
+
}>;
|
|
36
|
+
/** Test seam: mark a key as already committed with replayable outcome. */
|
|
37
|
+
seedCommitted(decisionId: string, idempotencyKey: string, outcomeRef: string): void;
|
|
38
|
+
markState(decisionId: string, idempotencyKey: string, state: string): void;
|
|
39
|
+
}
|
|
40
|
+
export interface EnforceExecutionPolicyDeps {
|
|
41
|
+
effectCommitLedger?: EffectCommitLedgerPort;
|
|
42
|
+
}
|
|
43
|
+
export declare function enforceExecutionPolicy(plan: ExecutionPlan, intent: CapabilityIntent, request: ConnectorRequest, deps: EnforceExecutionPolicyDeps): Promise<{
|
|
44
|
+
skipAdapter: boolean;
|
|
45
|
+
existingOutcomeRef?: string;
|
|
46
|
+
effectCommitId?: string;
|
|
47
|
+
}>;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Side-effect idempotency + degraded-channel gate + effect commit replay (T3.2.1).
|
|
3
|
+
* Aligns with connector-system.detail §3.6 enforceExecutionPolicy.
|
|
4
|
+
*/
|
|
5
|
+
import * as crypto from "node:crypto";
|
|
6
|
+
import { ConnectorPolicyError } from "./failure-taxonomy.js";
|
|
7
|
+
const READONLY = new Set([
|
|
8
|
+
"feed.read",
|
|
9
|
+
"notification.list",
|
|
10
|
+
"work.discover",
|
|
11
|
+
]);
|
|
12
|
+
export function classifyConnectorIntentEffect(intent) {
|
|
13
|
+
if (intent === "agent.heartbeat")
|
|
14
|
+
return "keepalive";
|
|
15
|
+
if (intent === "task.claim")
|
|
16
|
+
return "task_claim";
|
|
17
|
+
if (READONLY.has(intent))
|
|
18
|
+
return "read_only";
|
|
19
|
+
return "side_effect";
|
|
20
|
+
}
|
|
21
|
+
/** In-memory ledger for tests and offline harnesses. */
|
|
22
|
+
export class InMemoryEffectCommitLedger {
|
|
23
|
+
byKey = new Map();
|
|
24
|
+
key(decisionId, idempotencyKey) {
|
|
25
|
+
return `${decisionId}::${idempotencyKey}`;
|
|
26
|
+
}
|
|
27
|
+
async getOrCreateIntentCommitRecord(input) {
|
|
28
|
+
const k = this.key(input.decisionId, input.idempotencyKey);
|
|
29
|
+
const hit = this.byKey.get(k);
|
|
30
|
+
if (hit) {
|
|
31
|
+
return { existing: true, record: hit };
|
|
32
|
+
}
|
|
33
|
+
const id = crypto.randomUUID();
|
|
34
|
+
const rec = { id, state: "planned", outcomeRef: undefined };
|
|
35
|
+
this.byKey.set(k, rec);
|
|
36
|
+
return { existing: false, record: rec };
|
|
37
|
+
}
|
|
38
|
+
/** Test seam: mark a key as already committed with replayable outcome. */
|
|
39
|
+
seedCommitted(decisionId, idempotencyKey, outcomeRef) {
|
|
40
|
+
const id = crypto.randomUUID();
|
|
41
|
+
this.byKey.set(this.key(decisionId, idempotencyKey), { id, state: "committed", outcomeRef });
|
|
42
|
+
}
|
|
43
|
+
markState(decisionId, idempotencyKey, state) {
|
|
44
|
+
const k = this.key(decisionId, idempotencyKey);
|
|
45
|
+
const cur = this.byKey.get(k);
|
|
46
|
+
if (!cur)
|
|
47
|
+
throw new Error("ledger_seed_missing");
|
|
48
|
+
this.byKey.set(k, { ...cur, state });
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export async function enforceExecutionPolicy(plan, intent, request, deps) {
|
|
52
|
+
const semantics = classifyConnectorIntentEffect(intent);
|
|
53
|
+
if ((semantics === "side_effect" || semantics === "task_claim") && !plan.idempotencyKey?.trim()) {
|
|
54
|
+
throw new ConnectorPolicyError("permanent_input_error", "side_effect_requires_idempotency_key");
|
|
55
|
+
}
|
|
56
|
+
if (plan.degraded && (semantics === "side_effect" || semantics === "task_claim")) {
|
|
57
|
+
throw new ConnectorPolicyError("semantic_rejection", "degraded_channel_not_allowed_for_side_effect");
|
|
58
|
+
}
|
|
59
|
+
if (plan.idempotencyKey && deps.effectCommitLedger) {
|
|
60
|
+
if (!request.decisionId?.trim() || !request.intentId?.trim()) {
|
|
61
|
+
throw new ConnectorPolicyError("permanent_input_error", "effect_commit_requires_decision_and_intent_id");
|
|
62
|
+
}
|
|
63
|
+
const lookup = await deps.effectCommitLedger.getOrCreateIntentCommitRecord({
|
|
64
|
+
decisionId: request.decisionId,
|
|
65
|
+
intentId: request.intentId,
|
|
66
|
+
idempotencyKey: plan.idempotencyKey,
|
|
67
|
+
effectClass: semantics,
|
|
68
|
+
});
|
|
69
|
+
if (lookup.existing && lookup.record.state === "committed") {
|
|
70
|
+
return {
|
|
71
|
+
skipAdapter: true,
|
|
72
|
+
existingOutcomeRef: lookup.record.outcomeRef,
|
|
73
|
+
effectCommitId: lookup.record.id,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (lookup.existing && (lookup.record.state === "dispatched" || lookup.record.state === "reconcile")) {
|
|
77
|
+
throw new ConnectorPolicyError("concurrency_conflict", "effect_commit_requires_reconcile");
|
|
78
|
+
}
|
|
79
|
+
return { skipAdapter: false, effectCommitId: lookup.record.id };
|
|
80
|
+
}
|
|
81
|
+
return { skipAdapter: false };
|
|
82
|
+
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export * from "./contract.js";
|
|
2
2
|
export * from "./manifest.js";
|
|
3
|
+
export * from "./map-life-evidence.js";
|
|
3
4
|
export * from "./failure-taxonomy.js";
|
|
4
5
|
export * from "./route-planner.js";
|
|
5
6
|
export * from "./channel-health.js";
|
|
6
7
|
export * from "./policy-layer.js";
|
|
8
|
+
export * from "./execution-policy.js";
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export * from "./contract.js";
|
|
2
2
|
export * from "./manifest.js";
|
|
3
|
+
export * from "./map-life-evidence.js";
|
|
3
4
|
export * from "./failure-taxonomy.js";
|
|
4
5
|
export * from "./route-planner.js";
|
|
5
6
|
export * from "./channel-health.js";
|
|
6
7
|
export * from "./policy-layer.js";
|
|
8
|
+
export * from "./execution-policy.js";
|
|
@@ -1,11 +1,64 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { type CapabilityIntent, type ChannelType } from "./contract.js";
|
|
3
|
+
declare const connectorManifestSchema: z.ZodObject<{
|
|
4
|
+
platformId: z.ZodString;
|
|
5
|
+
supportedCapabilities: z.ZodArray<z.ZodEnum<{
|
|
6
|
+
"feed.read": "feed.read";
|
|
7
|
+
"post.publish": "post.publish";
|
|
8
|
+
"comment.reply": "comment.reply";
|
|
9
|
+
"notification.list": "notification.list";
|
|
10
|
+
"message.send": "message.send";
|
|
11
|
+
"agent.register": "agent.register";
|
|
12
|
+
"agent.heartbeat": "agent.heartbeat";
|
|
13
|
+
"work.discover": "work.discover";
|
|
14
|
+
"task.claim": "task.claim";
|
|
15
|
+
}>>;
|
|
16
|
+
channelPriority: z.ZodArray<z.ZodEnum<{
|
|
17
|
+
api_rest: "api_rest";
|
|
18
|
+
api_rpc: "api_rpc";
|
|
19
|
+
a2a: "a2a";
|
|
20
|
+
mcp: "mcp";
|
|
21
|
+
cli: "cli";
|
|
22
|
+
skill: "skill";
|
|
23
|
+
browser: "browser";
|
|
24
|
+
}>>;
|
|
25
|
+
credentialTypes: z.ZodArray<z.ZodString>;
|
|
26
|
+
degradedChannels: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
27
|
+
api_rest: "api_rest";
|
|
28
|
+
api_rpc: "api_rpc";
|
|
29
|
+
a2a: "a2a";
|
|
30
|
+
mcp: "mcp";
|
|
31
|
+
cli: "cli";
|
|
32
|
+
skill: "skill";
|
|
33
|
+
browser: "browser";
|
|
34
|
+
}>>>;
|
|
35
|
+
sourceRefPolicy: z.ZodOptional<z.ZodObject<{
|
|
36
|
+
minSourceRefs: z.ZodDefault<z.ZodNumber>;
|
|
37
|
+
rejectInlineSensitivePayload: z.ZodOptional<z.ZodBoolean>;
|
|
38
|
+
}, z.core.$strip>>;
|
|
39
|
+
}, z.core.$strip>;
|
|
40
|
+
export type ConnectorManifest = z.infer<typeof connectorManifestSchema>;
|
|
3
41
|
export declare class CapabilityContractRegistry {
|
|
4
42
|
private readonly byPlatform;
|
|
5
43
|
register(manifest: ConnectorManifest): void;
|
|
6
44
|
loadManifest(platformId: string): ConnectorManifest;
|
|
45
|
+
listRegisteredPlatformIds(): string[];
|
|
7
46
|
hasCapability(platformId: string, intent: CapabilityIntent): boolean;
|
|
8
47
|
listCapabilities(platformId: string): CapabilityIntent[];
|
|
9
48
|
listChannels(platformId: string): ChannelType[];
|
|
10
49
|
}
|
|
50
|
+
/** T3.1.1 contract name for manifest-first registry. */
|
|
51
|
+
export declare const ConnectorManifestRegistry: typeof CapabilityContractRegistry;
|
|
52
|
+
export type ConnectorManifestRegistry = CapabilityContractRegistry;
|
|
53
|
+
export declare function describeConnector(registry: CapabilityContractRegistry, platformId: string): ConnectorManifest;
|
|
54
|
+
export declare function checkConnector(registry: CapabilityContractRegistry, platformId: string): {
|
|
55
|
+
ok: boolean;
|
|
56
|
+
errors: string[];
|
|
57
|
+
};
|
|
58
|
+
export declare function discoverCapabilities(registry: CapabilityContractRegistry): Array<{
|
|
59
|
+
platformId: string;
|
|
60
|
+
capabilities: CapabilityIntent[];
|
|
61
|
+
degradedChannels?: ChannelType[];
|
|
62
|
+
}>;
|
|
11
63
|
export declare function parseConnectorManifest(input: unknown): ConnectorManifest;
|
|
64
|
+
export {};
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { CAPABILITY_INTENTS, CHANNEL_TYPES } from "./contract.js";
|
|
3
|
+
const sourceRefPolicySchema = z
|
|
4
|
+
.object({
|
|
5
|
+
minSourceRefs: z.number().int().min(0).default(1),
|
|
6
|
+
rejectInlineSensitivePayload: z.boolean().optional(),
|
|
7
|
+
})
|
|
8
|
+
.optional();
|
|
3
9
|
const connectorManifestSchema = z.object({
|
|
4
10
|
platformId: z.string().min(1),
|
|
5
11
|
supportedCapabilities: z.array(z.enum(CAPABILITY_INTENTS)).min(1),
|
|
6
12
|
channelPriority: z.array(z.enum(CHANNEL_TYPES)).min(1),
|
|
7
13
|
credentialTypes: z.array(z.string().min(1)).min(1),
|
|
8
14
|
degradedChannels: z.array(z.enum(CHANNEL_TYPES)).optional(),
|
|
15
|
+
sourceRefPolicy: sourceRefPolicySchema,
|
|
9
16
|
});
|
|
10
17
|
export class CapabilityContractRegistry {
|
|
11
18
|
byPlatform = new Map();
|
|
@@ -20,6 +27,9 @@ export class CapabilityContractRegistry {
|
|
|
20
27
|
}
|
|
21
28
|
return found;
|
|
22
29
|
}
|
|
30
|
+
listRegisteredPlatformIds() {
|
|
31
|
+
return [...this.byPlatform.keys()];
|
|
32
|
+
}
|
|
23
33
|
hasCapability(platformId, intent) {
|
|
24
34
|
const manifest = this.loadManifest(platformId);
|
|
25
35
|
return manifest.supportedCapabilities.includes(intent);
|
|
@@ -31,6 +41,46 @@ export class CapabilityContractRegistry {
|
|
|
31
41
|
return [...this.loadManifest(platformId).channelPriority];
|
|
32
42
|
}
|
|
33
43
|
}
|
|
44
|
+
/** T3.1.1 contract name for manifest-first registry. */
|
|
45
|
+
export const ConnectorManifestRegistry = CapabilityContractRegistry;
|
|
46
|
+
export function describeConnector(registry, platformId) {
|
|
47
|
+
return registry.loadManifest(platformId);
|
|
48
|
+
}
|
|
49
|
+
export function checkConnector(registry, platformId) {
|
|
50
|
+
const errors = [];
|
|
51
|
+
try {
|
|
52
|
+
const manifest = registry.loadManifest(platformId);
|
|
53
|
+
if (manifest.supportedCapabilities.length === 0) {
|
|
54
|
+
errors.push("capability_list_empty");
|
|
55
|
+
}
|
|
56
|
+
if (manifest.channelPriority.length === 0) {
|
|
57
|
+
errors.push("channel_priority_empty");
|
|
58
|
+
}
|
|
59
|
+
if (manifest.credentialTypes.length === 0) {
|
|
60
|
+
errors.push("credential_types_empty");
|
|
61
|
+
}
|
|
62
|
+
const degraded = manifest.degradedChannels ?? [];
|
|
63
|
+
for (const channel of degraded) {
|
|
64
|
+
if (!manifest.channelPriority.includes(channel)) {
|
|
65
|
+
errors.push(`degraded_channel_not_in_priority:${channel}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
errors.push(error instanceof Error ? error.message : String(error));
|
|
71
|
+
}
|
|
72
|
+
return { ok: errors.length === 0, errors };
|
|
73
|
+
}
|
|
74
|
+
export function discoverCapabilities(registry) {
|
|
75
|
+
return registry.listRegisteredPlatformIds().map((platformId) => {
|
|
76
|
+
const manifest = registry.loadManifest(platformId);
|
|
77
|
+
return {
|
|
78
|
+
platformId,
|
|
79
|
+
capabilities: [...manifest.supportedCapabilities],
|
|
80
|
+
degradedChannels: manifest.degradedChannels,
|
|
81
|
+
};
|
|
82
|
+
});
|
|
83
|
+
}
|
|
34
84
|
export function parseConnectorManifest(input) {
|
|
35
85
|
return connectorManifestSchema.parse(input);
|
|
36
86
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Maps normalized connector success results to `LifeEvidenceCandidate` (T3.1.2).
|
|
3
|
+
* Returns null when evidence cannot be source-backed (no refs, wrong intent, or failure).
|
|
4
|
+
*/
|
|
5
|
+
import type { CapabilityIntent, ConnectorResult } from "./contract.js";
|
|
6
|
+
import type { LifeEvidenceCandidate, Sensitivity } from "../../storage/life-evidence/types.js";
|
|
7
|
+
/**
|
|
8
|
+
* Produce a single life-evidence candidate from a connector outcome, or null if not mappable.
|
|
9
|
+
*/
|
|
10
|
+
export declare function mapLifeEvidence(input: {
|
|
11
|
+
platformId: string;
|
|
12
|
+
intent: CapabilityIntent;
|
|
13
|
+
result: ConnectorResult<unknown>;
|
|
14
|
+
observedAt?: string;
|
|
15
|
+
sensitivityOverride?: Sensitivity;
|
|
16
|
+
}): LifeEvidenceCandidate | null;
|