@haaaiawd/second-nature 0.1.22 → 0.1.24

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.
Files changed (79) hide show
  1. package/openclaw.plugin.json +1 -1
  2. package/package.json +1 -1
  3. package/runtime/cli/commands/connector-init.d.ts +19 -0
  4. package/runtime/cli/commands/connector-init.js +168 -0
  5. package/runtime/cli/commands/connector-status.d.ts +12 -0
  6. package/runtime/cli/commands/connector-status.js +156 -0
  7. package/runtime/cli/commands/index.js +40 -0
  8. package/runtime/cli/index.js +52 -0
  9. package/runtime/cli/ops/ops-router.d.ts +5 -0
  10. package/runtime/cli/ops/ops-router.js +34 -0
  11. package/runtime/cli/ops/workspace-heartbeat-runner.js +22 -0
  12. package/runtime/connectors/agent-network/agent-world/adapter.d.ts +11 -0
  13. package/runtime/connectors/agent-network/agent-world/adapter.js +58 -0
  14. package/runtime/connectors/agent-network/agent-world/index.d.ts +2 -0
  15. package/runtime/connectors/agent-network/agent-world/index.js +2 -0
  16. package/runtime/connectors/agent-network/agent-world/manifest.d.ts +2 -0
  17. package/runtime/connectors/agent-network/agent-world/manifest.js +7 -0
  18. package/runtime/connectors/base/manifest.d.ts +13 -0
  19. package/runtime/connectors/base/manifest.js +47 -0
  20. package/runtime/connectors/manifest/manifest-parser.d.ts +16 -0
  21. package/runtime/connectors/manifest/manifest-parser.js +35 -0
  22. package/runtime/connectors/manifest/manifest-schema.d.ts +145 -0
  23. package/runtime/connectors/manifest/manifest-schema.js +51 -0
  24. package/runtime/connectors/registry/dynamic-connector-registry.d.ts +29 -0
  25. package/runtime/connectors/registry/dynamic-connector-registry.js +123 -0
  26. package/runtime/connectors/registry/index.d.ts +3 -0
  27. package/runtime/connectors/registry/index.js +3 -0
  28. package/runtime/connectors/registry/manifest-scanner.d.ts +9 -0
  29. package/runtime/connectors/registry/manifest-scanner.js +29 -0
  30. package/runtime/connectors/registry/trust-policy.d.ts +13 -0
  31. package/runtime/connectors/registry/trust-policy.js +37 -0
  32. package/runtime/connectors/services/connector-executor-adapter.js +49 -0
  33. package/runtime/core/second-nature/heartbeat/heartbeat-loop.d.ts +3 -0
  34. package/runtime/core/second-nature/heartbeat/heartbeat-loop.js +52 -1
  35. package/runtime/core/second-nature/heartbeat/snapshot-builder.d.ts +3 -0
  36. package/runtime/core/second-nature/orchestrator/goal-priority.d.ts +19 -0
  37. package/runtime/core/second-nature/orchestrator/goal-priority.js +67 -0
  38. package/runtime/core/second-nature/orchestrator/intent-planner.js +8 -0
  39. package/runtime/core/second-nature/orchestrator/narrative-update.d.ts +27 -0
  40. package/runtime/core/second-nature/orchestrator/narrative-update.js +107 -0
  41. package/runtime/core/second-nature/types.d.ts +4 -0
  42. package/runtime/guidance/draft-narrative-outreach.d.ts +36 -0
  43. package/runtime/guidance/draft-narrative-outreach.js +84 -0
  44. package/runtime/guidance/index.d.ts +1 -0
  45. package/runtime/guidance/index.js +1 -0
  46. package/runtime/guidance/outreach-draft-schema.d.ts +3 -3
  47. package/runtime/observability/connector-inventory-ledger.d.ts +45 -0
  48. package/runtime/observability/connector-inventory-ledger.js +72 -0
  49. package/runtime/observability/db/index.js +13 -0
  50. package/runtime/observability/db/schema/connector-inventory.d.ts +174 -0
  51. package/runtime/observability/db/schema/connector-inventory.js +15 -0
  52. package/runtime/observability/db/schema/index.d.ts +1 -0
  53. package/runtime/observability/db/schema/index.js +1 -0
  54. package/runtime/storage/chronicle/session-chronicle-store.d.ts +42 -0
  55. package/runtime/storage/chronicle/session-chronicle-store.js +66 -0
  56. package/runtime/storage/db/index.js +75 -0
  57. package/runtime/storage/db/schema/agent-goal.d.ts +235 -0
  58. package/runtime/storage/db/schema/agent-goal.js +19 -0
  59. package/runtime/storage/db/schema/index.d.ts +5 -0
  60. package/runtime/storage/db/schema/index.js +5 -0
  61. package/runtime/storage/db/schema/memory-store.d.ts +199 -0
  62. package/runtime/storage/db/schema/memory-store.js +18 -0
  63. package/runtime/storage/db/schema/narrative-state.d.ts +195 -0
  64. package/runtime/storage/db/schema/narrative-state.js +16 -0
  65. package/runtime/storage/db/schema/relationship-memory.d.ts +174 -0
  66. package/runtime/storage/db/schema/relationship-memory.js +14 -0
  67. package/runtime/storage/db/schema/session-chronicle.d.ts +199 -0
  68. package/runtime/storage/db/schema/session-chronicle.js +18 -0
  69. package/runtime/storage/goal/agent-goal-store.d.ts +57 -0
  70. package/runtime/storage/goal/agent-goal-store.js +109 -0
  71. package/runtime/storage/index.d.ts +5 -0
  72. package/runtime/storage/index.js +5 -0
  73. package/runtime/storage/memory-store/memory-store-lifecycle.d.ts +70 -0
  74. package/runtime/storage/memory-store/memory-store-lifecycle.js +113 -0
  75. package/runtime/storage/narrative/narrative-state-store.d.ts +40 -0
  76. package/runtime/storage/narrative/narrative-state-store.js +79 -0
  77. package/runtime/storage/relationship/relationship-memory-store.d.ts +42 -0
  78. package/runtime/storage/relationship/relationship-memory-store.js +76 -0
  79. package/workspace-ops-bridge.js +1 -0
@@ -0,0 +1,58 @@
1
+ export function createAgentWorldRunner(input) {
2
+ const { apiClient } = input;
3
+ return {
4
+ async run(plan, request) {
5
+ const started = Date.now();
6
+ try {
7
+ const apiKey = request.payload?.apiKey ?? "";
8
+ if (!apiKey) {
9
+ return {
10
+ platformId: request.platformId,
11
+ channel: plan.channel,
12
+ latencyMs: Date.now() - started,
13
+ success: false,
14
+ error: {
15
+ code: "auth_failure",
16
+ detail: "api_key_required_for_agent_world",
17
+ },
18
+ };
19
+ }
20
+ let result;
21
+ if (plan.intent === "feed.read") {
22
+ result = await apiClient.readFeed(request.payload, String(apiKey));
23
+ }
24
+ else if (plan.intent === "work.discover") {
25
+ result = await apiClient.discoverWork(request.payload, String(apiKey));
26
+ }
27
+ else if (plan.intent === "task.claim") {
28
+ result = await apiClient.claimTask(request.payload, String(apiKey));
29
+ }
30
+ else {
31
+ throw { code: "protocol_mismatch", detail: `unsupported agent-world intent: ${plan.intent}` };
32
+ }
33
+ return {
34
+ platformId: request.platformId,
35
+ channel: plan.channel,
36
+ latencyMs: Date.now() - started,
37
+ degraded: plan.channel === "skill",
38
+ success: true,
39
+ payload: {
40
+ capability: request.intent,
41
+ channel: plan.channel,
42
+ data: result,
43
+ },
44
+ };
45
+ }
46
+ catch (error) {
47
+ return {
48
+ platformId: request.platformId,
49
+ channel: plan.channel,
50
+ latencyMs: Date.now() - started,
51
+ degraded: plan.channel === "skill",
52
+ success: false,
53
+ error,
54
+ };
55
+ }
56
+ },
57
+ };
58
+ }
@@ -0,0 +1,2 @@
1
+ export { agentWorldManifest } from "./manifest.js";
2
+ export { createAgentWorldRunner, type AgentWorldApiClient } from "./adapter.js";
@@ -0,0 +1,2 @@
1
+ export { agentWorldManifest } from "./manifest.js";
2
+ export { createAgentWorldRunner } from "./adapter.js";
@@ -0,0 +1,2 @@
1
+ import type { ConnectorManifest } from "../../base/manifest.js";
2
+ export declare const agentWorldManifest: ConnectorManifest;
@@ -0,0 +1,7 @@
1
+ export const agentWorldManifest = {
2
+ platformId: "agent-world",
3
+ supportedCapabilities: ["feed.read", "work.discover", "task.claim"],
4
+ channelPriority: ["api_rest", "a2a", "skill"],
5
+ credentialTypes: ["api_key"],
6
+ degradedChannels: ["skill"],
7
+ };
@@ -38,6 +38,11 @@ declare const connectorManifestSchema: z.ZodObject<{
38
38
  }, z.core.$strip>>;
39
39
  }, z.core.$strip>;
40
40
  export type ConnectorManifest = z.infer<typeof connectorManifestSchema>;
41
+ export interface ResolvedConnectorCapability {
42
+ platformId: string;
43
+ intent: CapabilityIntent;
44
+ source: "namespace" | "v5_explicit" | "unambiguous_default";
45
+ }
41
46
  export declare class CapabilityContractRegistry {
42
47
  private readonly byPlatform;
43
48
  register(manifest: ConnectorManifest): void;
@@ -46,6 +51,14 @@ export declare class CapabilityContractRegistry {
46
51
  hasCapability(platformId: string, intent: CapabilityIntent): boolean;
47
52
  listCapabilities(platformId: string): CapabilityIntent[];
48
53
  listChannels(platformId: string): ChannelType[];
54
+ /**
55
+ * Resolve a capability string that may be namespaced (`platformId:capability`)
56
+ * or a bare v5 capability. Returns the platform + intent pair.
57
+ * If bare capability and no explicit platform is provided, only succeeds when
58
+ * exactly one registered platform supports it (unambiguous_default).
59
+ */
60
+ resolveCapability(intentWithNamespace: string, explicitPlatformId?: string): ResolvedConnectorCapability;
61
+ findPlatformsForIntent(intent: CapabilityIntent): string[];
49
62
  }
50
63
  /** T3.1.1 contract name for manifest-first registry. */
51
64
  export declare const ConnectorManifestRegistry: typeof CapabilityContractRegistry;
@@ -40,6 +40,53 @@ export class CapabilityContractRegistry {
40
40
  listChannels(platformId) {
41
41
  return [...this.loadManifest(platformId).channelPriority];
42
42
  }
43
+ /**
44
+ * Resolve a capability string that may be namespaced (`platformId:capability`)
45
+ * or a bare v5 capability. Returns the platform + intent pair.
46
+ * If bare capability and no explicit platform is provided, only succeeds when
47
+ * exactly one registered platform supports it (unambiguous_default).
48
+ */
49
+ resolveCapability(intentWithNamespace, explicitPlatformId) {
50
+ const colonIndex = intentWithNamespace.indexOf(":");
51
+ if (colonIndex >= 0) {
52
+ const platformId = intentWithNamespace.slice(0, colonIndex);
53
+ const intent = intentWithNamespace.slice(colonIndex + 1);
54
+ if (!CAPABILITY_INTENTS.includes(intent)) {
55
+ throw new Error(`capability_not_recognized:${intent}`);
56
+ }
57
+ if (!this.byPlatform.has(platformId)) {
58
+ throw new Error(`platform_not_found:${platformId}`);
59
+ }
60
+ return { platformId, intent, source: "namespace" };
61
+ }
62
+ const intent = intentWithNamespace;
63
+ if (!CAPABILITY_INTENTS.includes(intent)) {
64
+ throw new Error(`capability_not_recognized:${intent}`);
65
+ }
66
+ if (explicitPlatformId) {
67
+ if (!this.byPlatform.has(explicitPlatformId)) {
68
+ throw new Error(`platform_not_found:${explicitPlatformId}`);
69
+ }
70
+ return { platformId: explicitPlatformId, intent, source: "v5_explicit" };
71
+ }
72
+ const platforms = this.findPlatformsForIntent(intent);
73
+ if (platforms.length === 0) {
74
+ throw new Error(`no_platform_supports_capability:${intent}`);
75
+ }
76
+ if (platforms.length > 1) {
77
+ throw new Error(`ambiguous_capability:${intent}:${platforms.join(",")}`);
78
+ }
79
+ return { platformId: platforms[0], intent, source: "unambiguous_default" };
80
+ }
81
+ findPlatformsForIntent(intent) {
82
+ const result = [];
83
+ for (const [platformId, manifest] of this.byPlatform) {
84
+ if (manifest.supportedCapabilities.includes(intent)) {
85
+ result.push(platformId);
86
+ }
87
+ }
88
+ return result;
89
+ }
43
90
  }
44
91
  /** T3.1.1 contract name for manifest-first registry. */
45
92
  export const ConnectorManifestRegistry = CapabilityContractRegistry;
@@ -0,0 +1,16 @@
1
+ import { type ConnectorManifestV6, type ConnectorManifestValidationError } from "./manifest-schema.js";
2
+ export interface ParseManifestResult {
3
+ ok: true;
4
+ manifest: ConnectorManifestV6;
5
+ }
6
+ export interface ParseManifestFailure {
7
+ ok: false;
8
+ errors: string[];
9
+ }
10
+ export type ParseManifestOutput = ParseManifestResult | ParseManifestFailure;
11
+ /**
12
+ * Safe YAML parse + zod validation for connector manifest v6.
13
+ * Uses JSON_SCHEMA to block custom YAML tags/object constructors.
14
+ */
15
+ export declare function parseConnectorManifestV6(yamlText: string, path?: string): ParseManifestOutput;
16
+ export declare function toValidationError(path: string, output: ParseManifestFailure): ConnectorManifestValidationError[];
@@ -0,0 +1,35 @@
1
+ import yaml from "js-yaml";
2
+ import { connectorManifestV6Schema, } from "./manifest-schema.js";
3
+ /**
4
+ * Safe YAML parse + zod validation for connector manifest v6.
5
+ * Uses JSON_SCHEMA to block custom YAML tags/object constructors.
6
+ */
7
+ export function parseConnectorManifestV6(yamlText, path) {
8
+ let raw;
9
+ try {
10
+ raw = yaml.load(yamlText, { schema: yaml.JSON_SCHEMA });
11
+ }
12
+ catch (error) {
13
+ return {
14
+ ok: false,
15
+ errors: [
16
+ error instanceof Error ? `yaml_parse_error:${error.message}` : `yaml_parse_error:${String(error)}`,
17
+ ],
18
+ };
19
+ }
20
+ if (raw === null || typeof raw !== "object") {
21
+ return { ok: false, errors: ["yaml_parse_error:parsed_content_is_null_or_not_object"] };
22
+ }
23
+ const parsed = connectorManifestV6Schema.safeParse(raw);
24
+ if (!parsed.success) {
25
+ const errors = parsed.error.issues.map((issue) => {
26
+ const pathStr = issue.path.join(".");
27
+ return `schema_validation_error:${pathStr}:${issue.message}`;
28
+ });
29
+ return { ok: false, errors };
30
+ }
31
+ return { ok: true, manifest: parsed.data };
32
+ }
33
+ export function toValidationError(path, output) {
34
+ return output.errors.map((message) => ({ path, message }));
35
+ }
@@ -0,0 +1,145 @@
1
+ import { z } from "zod";
2
+ export declare const connectorRunnerKindSchema: z.ZodEnum<{
3
+ skill: "skill";
4
+ browser: "browser";
5
+ declarative_http: "declarative_http";
6
+ declarative_a2a: "declarative_a2a";
7
+ declarative_mcp: "declarative_mcp";
8
+ cli_descriptor: "cli_descriptor";
9
+ custom_adapter: "custom_adapter";
10
+ }>;
11
+ export type ConnectorRunnerKind = z.infer<typeof connectorRunnerKindSchema>;
12
+ export declare const connectorTrustStatusSchema: z.ZodEnum<{
13
+ blocked: "blocked";
14
+ declarative_trusted: "declarative_trusted";
15
+ custom_adapter_pending_trust: "custom_adapter_pending_trust";
16
+ trusted_custom_adapter: "trusted_custom_adapter";
17
+ }>;
18
+ export type ConnectorTrustStatus = z.infer<typeof connectorTrustStatusSchema>;
19
+ export declare const capabilityDeclarationSchema: z.ZodObject<{
20
+ id: z.ZodString;
21
+ channel: z.ZodOptional<z.ZodString>;
22
+ description: z.ZodOptional<z.ZodString>;
23
+ }, z.core.$strip>;
24
+ export type ConnectorCapabilityDeclaration = z.infer<typeof capabilityDeclarationSchema>;
25
+ export declare const runnerDeclarationSchema: z.ZodObject<{
26
+ kind: z.ZodEnum<{
27
+ skill: "skill";
28
+ browser: "browser";
29
+ declarative_http: "declarative_http";
30
+ declarative_a2a: "declarative_a2a";
31
+ declarative_mcp: "declarative_mcp";
32
+ cli_descriptor: "cli_descriptor";
33
+ custom_adapter: "custom_adapter";
34
+ }>;
35
+ entrypoint: z.ZodOptional<z.ZodString>;
36
+ config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
37
+ }, z.core.$strip>;
38
+ export type ConnectorRunnerDeclaration = z.infer<typeof runnerDeclarationSchema>;
39
+ export declare const credentialRequirementSchema: z.ZodObject<{
40
+ type: z.ZodString;
41
+ required: z.ZodDefault<z.ZodBoolean>;
42
+ description: z.ZodOptional<z.ZodString>;
43
+ }, z.core.$strip>;
44
+ export type CredentialRequirementDeclaration = z.infer<typeof credentialRequirementSchema>;
45
+ export declare const sourceRefPolicySchema: z.ZodObject<{
46
+ minSourceRefs: z.ZodDefault<z.ZodNumber>;
47
+ rejectInlineSensitivePayload: z.ZodOptional<z.ZodBoolean>;
48
+ }, z.core.$strip>;
49
+ export type SourceRefPolicyDeclaration = z.infer<typeof sourceRefPolicySchema>;
50
+ export declare const trustDeclarationSchema: z.ZodObject<{
51
+ status: z.ZodOptional<z.ZodEnum<{
52
+ blocked: "blocked";
53
+ declarative_trusted: "declarative_trusted";
54
+ custom_adapter_pending_trust: "custom_adapter_pending_trust";
55
+ trusted_custom_adapter: "trusted_custom_adapter";
56
+ }>>;
57
+ override: z.ZodOptional<z.ZodBoolean>;
58
+ reason: z.ZodOptional<z.ZodString>;
59
+ }, z.core.$strip>;
60
+ export type ConnectorTrustDeclaration = z.infer<typeof trustDeclarationSchema>;
61
+ export declare const connectorManifestV6Schema: z.ZodObject<{
62
+ schemaVersion: z.ZodLiteral<"sn.connector.v1">;
63
+ platformId: z.ZodString;
64
+ displayName: z.ZodString;
65
+ family: z.ZodEnum<{
66
+ custom: "custom";
67
+ social_community: "social_community";
68
+ agent_network: "agent_network";
69
+ work_platform: "work_platform";
70
+ }>;
71
+ capabilities: z.ZodArray<z.ZodObject<{
72
+ id: z.ZodString;
73
+ channel: z.ZodOptional<z.ZodString>;
74
+ description: z.ZodOptional<z.ZodString>;
75
+ }, z.core.$strip>>;
76
+ runner: z.ZodObject<{
77
+ kind: z.ZodEnum<{
78
+ skill: "skill";
79
+ browser: "browser";
80
+ declarative_http: "declarative_http";
81
+ declarative_a2a: "declarative_a2a";
82
+ declarative_mcp: "declarative_mcp";
83
+ cli_descriptor: "cli_descriptor";
84
+ custom_adapter: "custom_adapter";
85
+ }>;
86
+ entrypoint: z.ZodOptional<z.ZodString>;
87
+ config: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
88
+ }, z.core.$strip>;
89
+ credentials: z.ZodArray<z.ZodObject<{
90
+ type: z.ZodString;
91
+ required: z.ZodDefault<z.ZodBoolean>;
92
+ description: z.ZodOptional<z.ZodString>;
93
+ }, z.core.$strip>>;
94
+ sourceRefPolicy: z.ZodObject<{
95
+ minSourceRefs: z.ZodDefault<z.ZodNumber>;
96
+ rejectInlineSensitivePayload: z.ZodOptional<z.ZodBoolean>;
97
+ }, z.core.$strip>;
98
+ trust: z.ZodOptional<z.ZodObject<{
99
+ status: z.ZodOptional<z.ZodEnum<{
100
+ blocked: "blocked";
101
+ declarative_trusted: "declarative_trusted";
102
+ custom_adapter_pending_trust: "custom_adapter_pending_trust";
103
+ trusted_custom_adapter: "trusted_custom_adapter";
104
+ }>>;
105
+ override: z.ZodOptional<z.ZodBoolean>;
106
+ reason: z.ZodOptional<z.ZodString>;
107
+ }, z.core.$strip>>;
108
+ }, z.core.$strip>;
109
+ export type ConnectorManifestV6 = z.infer<typeof connectorManifestV6Schema>;
110
+ export interface ConnectorConflict {
111
+ platformId: string;
112
+ existingSource: "built_in" | "workspace";
113
+ attemptedSource: "built_in" | "workspace";
114
+ reason: string;
115
+ }
116
+ export interface ConnectorManifestValidationError {
117
+ platformId?: string;
118
+ path: string;
119
+ message: string;
120
+ }
121
+ export interface ConnectorInventoryEntry {
122
+ platformId: string;
123
+ source: "built_in" | "workspace";
124
+ manifestPath?: string;
125
+ trustStatus: ConnectorTrustStatus;
126
+ executable: boolean;
127
+ capabilities: string[];
128
+ validationErrors: string[];
129
+ conflict?: ConnectorConflict;
130
+ }
131
+ export interface ConnectorReloadResult {
132
+ scanned: number;
133
+ registered: number;
134
+ skipped: number;
135
+ conflicts: ConnectorConflict[];
136
+ validationErrors: ConnectorManifestValidationError[];
137
+ }
138
+ export interface ConnectorRegistrySnapshot {
139
+ readonly entries: ReadonlyMap<string, ConnectorInventoryEntry>;
140
+ readonly builtInEntries: ReadonlyMap<string, ConnectorInventoryEntry>;
141
+ readonly dynamicEntries: ReadonlyMap<string, ConnectorInventoryEntry>;
142
+ readonly conflicts: readonly ConnectorConflict[];
143
+ readonly validationErrors: readonly ConnectorManifestValidationError[];
144
+ readonly createdAt: string;
145
+ }
@@ -0,0 +1,51 @@
1
+ import { z } from "zod";
2
+ export const connectorRunnerKindSchema = z.enum([
3
+ "declarative_http",
4
+ "declarative_a2a",
5
+ "declarative_mcp",
6
+ "cli_descriptor",
7
+ "custom_adapter",
8
+ "skill",
9
+ "browser",
10
+ ]);
11
+ export const connectorTrustStatusSchema = z.enum([
12
+ "declarative_trusted",
13
+ "custom_adapter_pending_trust",
14
+ "trusted_custom_adapter",
15
+ "blocked",
16
+ ]);
17
+ export const capabilityDeclarationSchema = z.object({
18
+ id: z.string().min(1),
19
+ channel: z.string().optional(),
20
+ description: z.string().optional(),
21
+ });
22
+ export const runnerDeclarationSchema = z.object({
23
+ kind: connectorRunnerKindSchema,
24
+ entrypoint: z.string().optional(),
25
+ config: z.record(z.string(), z.unknown()).optional(),
26
+ });
27
+ export const credentialRequirementSchema = z.object({
28
+ type: z.string().min(1),
29
+ required: z.boolean().default(true),
30
+ description: z.string().optional(),
31
+ });
32
+ export const sourceRefPolicySchema = z.object({
33
+ minSourceRefs: z.number().int().min(0).default(1),
34
+ rejectInlineSensitivePayload: z.boolean().optional(),
35
+ });
36
+ export const trustDeclarationSchema = z.object({
37
+ status: connectorTrustStatusSchema.optional(),
38
+ override: z.boolean().optional(),
39
+ reason: z.string().optional(),
40
+ });
41
+ export const connectorManifestV6Schema = z.object({
42
+ schemaVersion: z.literal("sn.connector.v1"),
43
+ platformId: z.string().min(1),
44
+ displayName: z.string().min(1),
45
+ family: z.enum(["social_community", "agent_network", "work_platform", "custom"]),
46
+ capabilities: z.array(capabilityDeclarationSchema).min(1),
47
+ runner: runnerDeclarationSchema,
48
+ credentials: z.array(credentialRequirementSchema),
49
+ sourceRefPolicy: sourceRefPolicySchema,
50
+ trust: trustDeclarationSchema.optional(),
51
+ });
@@ -0,0 +1,29 @@
1
+ import { type ConnectorManifestV6, type ConnectorInventoryEntry, type ConnectorReloadResult, type ConnectorRegistrySnapshot } from "../manifest/manifest-schema.js";
2
+ export interface RegistrySnapshotStore {
3
+ getActive(): ConnectorRegistrySnapshot;
4
+ swap(snapshot: ConnectorRegistrySnapshot): void;
5
+ }
6
+ export declare function createRegistrySnapshotStore(initial?: ConnectorRegistrySnapshot): RegistrySnapshotStore;
7
+ export interface DynamicConnectorRegistryOptions {
8
+ builtInManifests?: ConnectorManifestV6[];
9
+ snapshotStore: RegistrySnapshotStore;
10
+ }
11
+ /**
12
+ * DynamicConnectorRegistry scans workspace manifests, validates, classifies trust,
13
+ * merges built-in entries, applies fail-closed conflict policy, and publishes
14
+ * immutable registry snapshots.
15
+ */
16
+ export declare class DynamicConnectorRegistry {
17
+ private readonly builtInManifests;
18
+ private readonly snapshotStore;
19
+ constructor(options: DynamicConnectorRegistryOptions);
20
+ /**
21
+ * Reload connectors from workspace root.
22
+ * Scans `.second-nature/connectors/{platformId}/manifest.yaml`, validates,
23
+ * classifies trust, and atomically swaps the active registry snapshot.
24
+ */
25
+ reloadConnectors(workspaceRoot: string): ConnectorReloadResult;
26
+ getActiveRegistrySnapshot(): ConnectorRegistrySnapshot;
27
+ listConnectors(): ConnectorInventoryEntry[];
28
+ describeConnector(platformId: string): ConnectorInventoryEntry | undefined;
29
+ }
@@ -0,0 +1,123 @@
1
+ import path from "node:path";
2
+ import { parseConnectorManifestV6, toValidationError } from "../manifest/manifest-parser.js";
3
+ import { classifyTrust, isExecutable } from "./trust-policy.js";
4
+ import { scanConnectorManifests } from "./manifest-scanner.js";
5
+ export function createRegistrySnapshotStore(initial) {
6
+ let active = initial ??
7
+ buildSnapshot(new Map(), new Map(), [], [], new Date().toISOString());
8
+ return {
9
+ getActive() {
10
+ return active;
11
+ },
12
+ swap(snapshot) {
13
+ active = snapshot;
14
+ },
15
+ };
16
+ }
17
+ function buildSnapshot(builtIn, dynamic, conflicts, validationErrors, createdAt) {
18
+ const entries = new Map();
19
+ for (const [k, v] of builtIn)
20
+ entries.set(k, v);
21
+ for (const [k, v] of dynamic)
22
+ entries.set(k, v);
23
+ return Object.freeze({
24
+ entries,
25
+ builtInEntries: builtIn,
26
+ dynamicEntries: dynamic,
27
+ conflicts: Object.freeze([...conflicts]),
28
+ validationErrors: Object.freeze([...validationErrors]),
29
+ createdAt,
30
+ });
31
+ }
32
+ function manifestToInventoryEntry(manifest, source, manifestPath) {
33
+ const trustStatus = classifyTrust(manifest);
34
+ return {
35
+ platformId: manifest.platformId,
36
+ source,
37
+ manifestPath,
38
+ trustStatus,
39
+ executable: isExecutable(trustStatus),
40
+ capabilities: manifest.capabilities.map((c) => c.id),
41
+ validationErrors: [],
42
+ };
43
+ }
44
+ /**
45
+ * DynamicConnectorRegistry scans workspace manifests, validates, classifies trust,
46
+ * merges built-in entries, applies fail-closed conflict policy, and publishes
47
+ * immutable registry snapshots.
48
+ */
49
+ export class DynamicConnectorRegistry {
50
+ builtInManifests;
51
+ snapshotStore;
52
+ constructor(options) {
53
+ this.builtInManifests = options.builtInManifests ?? [];
54
+ this.snapshotStore = options.snapshotStore;
55
+ }
56
+ /**
57
+ * Reload connectors from workspace root.
58
+ * Scans `.second-nature/connectors/{platformId}/manifest.yaml`, validates,
59
+ * classifies trust, and atomically swaps the active registry snapshot.
60
+ */
61
+ reloadConnectors(workspaceRoot) {
62
+ const scannedFiles = scanConnectorManifests(workspaceRoot);
63
+ const scanned = scannedFiles.length;
64
+ const builtInMap = new Map();
65
+ for (const manifest of this.builtInManifests) {
66
+ builtInMap.set(manifest.platformId, manifestToInventoryEntry(manifest, "built_in"));
67
+ }
68
+ const dynamicMap = new Map();
69
+ const conflicts = [];
70
+ const validationErrors = [];
71
+ let registered = 0;
72
+ let skipped = 0;
73
+ for (const file of scannedFiles) {
74
+ const parseResult = parseConnectorManifestV6(file.content, file.path);
75
+ if (!parseResult.ok) {
76
+ validationErrors.push(...toValidationError(file.path, parseResult));
77
+ skipped++;
78
+ continue;
79
+ }
80
+ const manifest = parseResult.manifest;
81
+ const manifestPath = path.relative(workspaceRoot, file.path);
82
+ // Duplicate platformId without override -> fail-closed
83
+ if (builtInMap.has(manifest.platformId) || dynamicMap.has(manifest.platformId)) {
84
+ const existing = builtInMap.get(manifest.platformId) ?? dynamicMap.get(manifest.platformId);
85
+ const allowOverride = manifest.trust?.override === true;
86
+ const isTrustedSource = existing.source === "built_in";
87
+ if (!allowOverride || isTrustedSource) {
88
+ conflicts.push({
89
+ platformId: manifest.platformId,
90
+ existingSource: existing.source,
91
+ attemptedSource: "workspace",
92
+ reason: allowOverride
93
+ ? "override_rejected_trusted_source"
94
+ : "duplicate_platform_id_without_override",
95
+ });
96
+ skipped++;
97
+ continue;
98
+ }
99
+ }
100
+ const entry = manifestToInventoryEntry(manifest, "workspace", manifestPath);
101
+ dynamicMap.set(manifest.platformId, entry);
102
+ registered++;
103
+ }
104
+ const snapshot = buildSnapshot(builtInMap, dynamicMap, conflicts, validationErrors, new Date().toISOString());
105
+ this.snapshotStore.swap(snapshot);
106
+ return {
107
+ scanned,
108
+ registered,
109
+ skipped,
110
+ conflicts,
111
+ validationErrors,
112
+ };
113
+ }
114
+ getActiveRegistrySnapshot() {
115
+ return this.snapshotStore.getActive();
116
+ }
117
+ listConnectors() {
118
+ return [...this.snapshotStore.getActive().entries.values()];
119
+ }
120
+ describeConnector(platformId) {
121
+ return this.snapshotStore.getActive().entries.get(platformId);
122
+ }
123
+ }
@@ -0,0 +1,3 @@
1
+ export { DynamicConnectorRegistry, createRegistrySnapshotStore, type RegistrySnapshotStore, type DynamicConnectorRegistryOptions, } from "./dynamic-connector-registry.js";
2
+ export { scanConnectorManifests, type ManifestScanResult } from "./manifest-scanner.js";
3
+ export { classifyTrust, isExecutable } from "./trust-policy.js";
@@ -0,0 +1,3 @@
1
+ export { DynamicConnectorRegistry, createRegistrySnapshotStore, } from "./dynamic-connector-registry.js";
2
+ export { scanConnectorManifests } from "./manifest-scanner.js";
3
+ export { classifyTrust, isExecutable } from "./trust-policy.js";
@@ -0,0 +1,9 @@
1
+ export interface ManifestScanResult {
2
+ path: string;
3
+ content: string;
4
+ }
5
+ /**
6
+ * Enumerate `.second-nature/connectors/{platformId}/manifest.yaml` under workspace root.
7
+ * Does not execute any code; only reads file paths and contents.
8
+ */
9
+ export declare function scanConnectorManifests(workspaceRoot: string): ManifestScanResult[];
@@ -0,0 +1,29 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ /**
4
+ * Enumerate `.second-nature/connectors/{platformId}/manifest.yaml` under workspace root.
5
+ * Does not execute any code; only reads file paths and contents.
6
+ */
7
+ export function scanConnectorManifests(workspaceRoot) {
8
+ const connectorsDir = path.join(workspaceRoot, ".second-nature", "connectors");
9
+ if (!fs.existsSync(connectorsDir)) {
10
+ return [];
11
+ }
12
+ const results = [];
13
+ const entries = fs.readdirSync(connectorsDir, { withFileTypes: true });
14
+ for (const entry of entries) {
15
+ if (!entry.isDirectory())
16
+ continue;
17
+ const manifestPath = path.join(connectorsDir, entry.name, "manifest.yaml");
18
+ if (!fs.existsSync(manifestPath))
19
+ continue;
20
+ try {
21
+ const content = fs.readFileSync(manifestPath, "utf-8");
22
+ results.push({ path: manifestPath, content });
23
+ }
24
+ catch {
25
+ // Skip unreadable files; validation layer will not see them
26
+ }
27
+ }
28
+ return results;
29
+ }
@@ -0,0 +1,13 @@
1
+ import { type ConnectorManifestV6, type ConnectorTrustStatus } from "../manifest/manifest-schema.js";
2
+ /**
3
+ * Classify manifest runner into trust status per v6 trust decision tree.
4
+ * declarative_http/a2a/mcp -> declarative_trusted
5
+ * cli_descriptor -> declarative_trusted (P0 conditional; dry-run/read path优先)
6
+ * custom_adapter/skill/browser -> custom_adapter_pending_trust
7
+ * explicit blocked/trusted_custom_adapter in manifest.trust respected.
8
+ */
9
+ export declare function classifyTrust(manifest: ConnectorManifestV6): ConnectorTrustStatus;
10
+ /**
11
+ * Determine whether a connector entry is executable based on trust status.
12
+ */
13
+ export declare function isExecutable(trustStatus: ConnectorTrustStatus): boolean;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Classify manifest runner into trust status per v6 trust decision tree.
3
+ * declarative_http/a2a/mcp -> declarative_trusted
4
+ * cli_descriptor -> declarative_trusted (P0 conditional; dry-run/read path优先)
5
+ * custom_adapter/skill/browser -> custom_adapter_pending_trust
6
+ * explicit blocked/trusted_custom_adapter in manifest.trust respected.
7
+ */
8
+ export function classifyTrust(manifest) {
9
+ if (manifest.trust?.status === "blocked") {
10
+ return "blocked";
11
+ }
12
+ if (manifest.trust?.status === "trusted_custom_adapter") {
13
+ return "trusted_custom_adapter";
14
+ }
15
+ const kind = manifest.runner.kind;
16
+ switch (kind) {
17
+ case "declarative_http":
18
+ case "declarative_a2a":
19
+ case "declarative_mcp":
20
+ case "cli_descriptor":
21
+ return "declarative_trusted";
22
+ case "custom_adapter":
23
+ case "skill":
24
+ case "browser":
25
+ return "custom_adapter_pending_trust";
26
+ default: {
27
+ // Exhaustive check; unknown runner kind is blocked for safety
28
+ return "blocked";
29
+ }
30
+ }
31
+ }
32
+ /**
33
+ * Determine whether a connector entry is executable based on trust status.
34
+ */
35
+ export function isExecutable(trustStatus) {
36
+ return trustStatus === "declarative_trusted" || trustStatus === "trusted_custom_adapter";
37
+ }