@haaaiawd/second-nature 0.1.27 → 0.1.29

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 (157) hide show
  1. package/SKILL.md +35 -33
  2. package/agent-inner-guide.md +144 -124
  3. package/index.js +76 -1
  4. package/openclaw.plugin.json +2 -2
  5. package/package.json +2 -1
  6. package/runtime/cli/commands/connector-behavior.d.ts +20 -0
  7. package/runtime/cli/commands/connector-behavior.js +160 -0
  8. package/runtime/cli/commands/index.js +8 -0
  9. package/runtime/cli/index.js +9 -2
  10. package/runtime/cli/ops/manual-run-dispatcher.d.ts +79 -0
  11. package/runtime/cli/ops/manual-run-dispatcher.js +110 -0
  12. package/runtime/cli/ops/ops-router.d.ts +45 -4
  13. package/runtime/cli/ops/ops-router.js +543 -2
  14. package/runtime/cli/read-models/index.js +35 -18
  15. package/runtime/cli/read-models/types.d.ts +1 -0
  16. package/runtime/connectors/agent-network/agent-world/adapter.d.ts +1 -0
  17. package/runtime/connectors/agent-network/agent-world/adapter.js +2 -2
  18. package/runtime/connectors/base/contract.d.ts +4 -1
  19. package/runtime/connectors/base/contract.js +5 -1
  20. package/runtime/connectors/base/effect-commit-ledger-sqlite.d.ts +31 -0
  21. package/runtime/connectors/base/effect-commit-ledger-sqlite.js +86 -0
  22. package/runtime/connectors/base/failure-taxonomy.js +5 -0
  23. package/runtime/connectors/base/manifest-v7.d.ts +151 -0
  24. package/runtime/connectors/base/manifest-v7.js +170 -0
  25. package/runtime/connectors/base/manifest.d.ts +67 -77
  26. package/runtime/connectors/base/manifest.js +7 -7
  27. package/runtime/connectors/base/route-planner.js +11 -8
  28. package/runtime/connectors/base/structured-unavailable-reason.d.ts +59 -0
  29. package/runtime/connectors/base/structured-unavailable-reason.js +113 -0
  30. package/runtime/connectors/base/wet-probe-runner.d.ts +40 -0
  31. package/runtime/connectors/base/wet-probe-runner.js +132 -0
  32. package/runtime/connectors/manifest/manifest-schema.d.ts +4 -0
  33. package/runtime/connectors/manifest/manifest-schema.js +2 -0
  34. package/runtime/connectors/services/connector-executor-adapter.d.ts +1 -0
  35. package/runtime/connectors/services/connector-executor-adapter.js +132 -26
  36. package/runtime/core/second-nature/body/behavior-promotion/behavior-promotion-loop.d.ts +45 -0
  37. package/runtime/core/second-nature/body/behavior-promotion/behavior-promotion-loop.js +132 -0
  38. package/runtime/core/second-nature/body/circuit-breaker/circuit-breaker-manager.d.ts +60 -0
  39. package/runtime/core/second-nature/body/circuit-breaker/circuit-breaker-manager.js +174 -0
  40. package/runtime/core/second-nature/body/probe-signal-adapter.d.ts +38 -0
  41. package/runtime/core/second-nature/body/probe-signal-adapter.js +60 -0
  42. package/runtime/core/second-nature/body/tool-affordance/affordance-assembler.d.ts +51 -0
  43. package/runtime/core/second-nature/body/tool-affordance/affordance-assembler.js +129 -0
  44. package/runtime/core/second-nature/body/tool-affordance/affordance-context-scope.d.ts +30 -0
  45. package/runtime/core/second-nature/body/tool-affordance/affordance-context-scope.js +92 -0
  46. package/runtime/core/second-nature/body/tool-experience/experience-writer.d.ts +34 -0
  47. package/runtime/core/second-nature/body/tool-experience/experience-writer.js +67 -0
  48. package/runtime/core/second-nature/body/tool-experience/pain-signal-query.d.ts +37 -0
  49. package/runtime/core/second-nature/body/tool-experience/pain-signal-query.js +62 -0
  50. package/runtime/core/second-nature/heartbeat/decision-trace-emitter.d.ts +29 -0
  51. package/runtime/core/second-nature/heartbeat/decision-trace-emitter.js +28 -0
  52. package/runtime/core/second-nature/heartbeat/embodied-context-assembler.d.ts +54 -0
  53. package/runtime/core/second-nature/heartbeat/embodied-context-assembler.js +164 -0
  54. package/runtime/core/second-nature/heartbeat/goal-lifecycle-policy.d.ts +37 -0
  55. package/runtime/core/second-nature/heartbeat/goal-lifecycle-policy.js +61 -0
  56. package/runtime/core/second-nature/heartbeat/idle-curiosity-policy.d.ts +37 -0
  57. package/runtime/core/second-nature/heartbeat/idle-curiosity-policy.js +60 -0
  58. package/runtime/core/second-nature/heartbeat/index.d.ts +4 -0
  59. package/runtime/core/second-nature/heartbeat/index.js +5 -0
  60. package/runtime/core/second-nature/heartbeat/run-heartbeat-cycle-v7.d.ts +63 -0
  61. package/runtime/core/second-nature/heartbeat/run-heartbeat-cycle-v7.js +118 -0
  62. package/runtime/core/second-nature/orchestrator/downstream-intent-orchestrator.d.ts +41 -0
  63. package/runtime/core/second-nature/orchestrator/downstream-intent-orchestrator.js +43 -0
  64. package/runtime/core/second-nature/orchestrator/effect-dispatcher.d.ts +2 -1
  65. package/runtime/core/second-nature/orchestrator/effect-dispatcher.js +2 -0
  66. package/runtime/core/second-nature/orchestrator/hard-guard-evaluator.d.ts +31 -0
  67. package/runtime/core/second-nature/orchestrator/hard-guard-evaluator.js +102 -0
  68. package/runtime/core/second-nature/orchestrator/index.d.ts +5 -0
  69. package/runtime/core/second-nature/orchestrator/index.js +7 -0
  70. package/runtime/core/second-nature/quiet/claim-synthesizer.d.ts +53 -0
  71. package/runtime/core/second-nature/quiet/claim-synthesizer.js +153 -0
  72. package/runtime/core/second-nature/quiet/daily-diary-writer.d.ts +29 -0
  73. package/runtime/core/second-nature/quiet/daily-diary-writer.js +92 -0
  74. package/runtime/core/second-nature/quiet/index.d.ts +5 -0
  75. package/runtime/core/second-nature/quiet/index.js +5 -0
  76. package/runtime/core/second-nature/quiet/run-source-backed-quiet.js +19 -12
  77. package/runtime/core/second-nature/types.d.ts +2 -0
  78. package/runtime/guidance/channel-feedback-ingestion-service.d.ts +88 -0
  79. package/runtime/guidance/channel-feedback-ingestion-service.js +231 -0
  80. package/runtime/guidance/guidance-draft-service.d.ts +60 -0
  81. package/runtime/guidance/guidance-draft-service.js +80 -0
  82. package/runtime/guidance/index.d.ts +3 -0
  83. package/runtime/guidance/index.js +3 -0
  84. package/runtime/guidance/outreach-draft-schema.d.ts +8 -8
  85. package/runtime/guidance/outreach-strategy-selector.d.ts +77 -0
  86. package/runtime/guidance/outreach-strategy-selector.js +211 -0
  87. package/runtime/observability/audit/append-only-audit-store.d.ts +20 -2
  88. package/runtime/observability/audit/append-only-audit-store.js +32 -6
  89. package/runtime/observability/audit/audit-envelope.d.ts +2 -1
  90. package/runtime/observability/audit/audit-envelope.js +8 -7
  91. package/runtime/observability/audit/audit-family-registry.json +66 -0
  92. package/runtime/observability/audit/family-registry.d.ts +43 -0
  93. package/runtime/observability/audit/family-registry.js +70 -0
  94. package/runtime/observability/index.d.ts +6 -1
  95. package/runtime/observability/index.js +6 -1
  96. package/runtime/observability/redaction/policy.d.ts +24 -3
  97. package/runtime/observability/redaction/policy.js +74 -0
  98. package/runtime/observability/services/heartbeat-digest-assembler.d.ts +152 -0
  99. package/runtime/observability/services/heartbeat-digest-assembler.js +248 -0
  100. package/runtime/observability/services/lived-experience-audit.js +6 -6
  101. package/runtime/observability/services/narrative-timeline-query-service.d.ts +136 -0
  102. package/runtime/observability/services/narrative-timeline-query-service.js +169 -0
  103. package/runtime/observability/services/restore-audit-service.d.ts +74 -0
  104. package/runtime/observability/services/restore-audit-service.js +79 -0
  105. package/runtime/observability/services/runtime-secret-anchor-view.d.ts +77 -0
  106. package/runtime/observability/services/runtime-secret-anchor-view.js +168 -0
  107. package/runtime/observability/services/self-health-snapshot.d.ts +92 -0
  108. package/runtime/observability/services/self-health-snapshot.js +251 -0
  109. package/runtime/shared/types/goal.d.ts +62 -0
  110. package/runtime/shared/types/goal.js +20 -0
  111. package/runtime/shared/types/index.d.ts +3 -0
  112. package/runtime/shared/types/index.js +3 -0
  113. package/runtime/shared/types/source-ref.d.ts +14 -0
  114. package/runtime/shared/types/source-ref.js +1 -0
  115. package/runtime/shared/types/v7-entities.d.ts +206 -0
  116. package/runtime/shared/types/v7-entities.js +27 -0
  117. package/runtime/storage/db/index.js +3 -0
  118. package/runtime/storage/db/migration-runner.d.ts +30 -0
  119. package/runtime/storage/db/migration-runner.js +93 -0
  120. package/runtime/storage/db/migrations/index.d.ts +5 -0
  121. package/runtime/storage/db/migrations/index.js +13 -0
  122. package/runtime/storage/db/migrations/v7-001-foundation.d.ts +13 -0
  123. package/runtime/storage/db/migrations/v7-001-foundation.js +144 -0
  124. package/runtime/storage/db/migrations/v7-002-effect-commit-ledger.d.ts +8 -0
  125. package/runtime/storage/db/migrations/v7-002-effect-commit-ledger.js +27 -0
  126. package/runtime/storage/db/migrations/v7-003-circuit-breaker.d.ts +7 -0
  127. package/runtime/storage/db/migrations/v7-003-circuit-breaker.js +26 -0
  128. package/runtime/storage/db/migrations/v7-004-behavior-promotion.d.ts +7 -0
  129. package/runtime/storage/db/migrations/v7-004-behavior-promotion.js +26 -0
  130. package/runtime/storage/db/schema/agent-goal.d.ts +38 -0
  131. package/runtime/storage/db/schema/agent-goal.js +2 -0
  132. package/runtime/storage/db/transaction-utils.d.ts +14 -0
  133. package/runtime/storage/db/transaction-utils.js +29 -0
  134. package/runtime/storage/db/write-queue.d.ts +38 -0
  135. package/runtime/storage/db/write-queue.js +97 -0
  136. package/runtime/storage/quiet/persist-quiet-artifact.js +2 -1
  137. package/runtime/storage/services/diary-dream-store.d.ts +35 -0
  138. package/runtime/storage/services/diary-dream-store.js +165 -0
  139. package/runtime/storage/services/embodied-context-state-port.d.ts +77 -0
  140. package/runtime/storage/services/embodied-context-state-port.js +115 -0
  141. package/runtime/storage/services/goal-lifecycle-store.d.ts +42 -0
  142. package/runtime/storage/services/goal-lifecycle-store.js +181 -0
  143. package/runtime/storage/services/history-digest-store.d.ts +33 -0
  144. package/runtime/storage/services/history-digest-store.js +140 -0
  145. package/runtime/storage/services/identity-profile-store.d.ts +25 -0
  146. package/runtime/storage/services/identity-profile-store.js +81 -0
  147. package/runtime/storage/services/interaction-snapshot-projector.d.ts +15 -0
  148. package/runtime/storage/services/interaction-snapshot-projector.js +35 -0
  149. package/runtime/storage/services/restore-snapshot-store.d.ts +52 -0
  150. package/runtime/storage/services/restore-snapshot-store.js +193 -0
  151. package/runtime/storage/services/runtime-secret-anchor-store.d.ts +26 -0
  152. package/runtime/storage/services/runtime-secret-anchor-store.js +82 -0
  153. package/runtime/storage/services/tool-experience-store.d.ts +25 -0
  154. package/runtime/storage/services/tool-experience-store.js +116 -0
  155. package/runtime/storage/services/write-validation-gate.d.ts +46 -0
  156. package/runtime/storage/services/write-validation-gate.js +200 -0
  157. package/workspace-ops-bridge.js +16 -1
@@ -1,77 +1,67 @@
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>;
41
- export interface ResolvedConnectorCapability {
42
- platformId: string;
43
- intent: CapabilityIntent;
44
- source: "namespace" | "v5_explicit" | "unambiguous_default";
45
- }
46
- export declare class CapabilityContractRegistry {
47
- private readonly byPlatform;
48
- register(manifest: ConnectorManifest): void;
49
- loadManifest(platformId: string): ConnectorManifest;
50
- listRegisteredPlatformIds(): string[];
51
- hasCapability(platformId: string, intent: CapabilityIntent): boolean;
52
- listCapabilities(platformId: string): CapabilityIntent[];
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[];
62
- }
63
- /** T3.1.1 contract name for manifest-first registry. */
64
- export declare const ConnectorManifestRegistry: typeof CapabilityContractRegistry;
65
- export type ConnectorManifestRegistry = CapabilityContractRegistry;
66
- export declare function describeConnector(registry: CapabilityContractRegistry, platformId: string): ConnectorManifest;
67
- export declare function checkConnector(registry: CapabilityContractRegistry, platformId: string): {
68
- ok: boolean;
69
- errors: string[];
70
- };
71
- export declare function discoverCapabilities(registry: CapabilityContractRegistry): Array<{
72
- platformId: string;
73
- capabilities: CapabilityIntent[];
74
- degradedChannels?: ChannelType[];
75
- }>;
76
- export declare function parseConnectorManifest(input: unknown): ConnectorManifest;
77
- export {};
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.ZodString>;
6
+ channelPriority: z.ZodArray<z.ZodEnum<{
7
+ skill: "skill";
8
+ api_rest: "api_rest";
9
+ api_rpc: "api_rpc";
10
+ a2a: "a2a";
11
+ mcp: "mcp";
12
+ cli: "cli";
13
+ browser: "browser";
14
+ }>>;
15
+ credentialTypes: z.ZodArray<z.ZodString>;
16
+ degradedChannels: z.ZodOptional<z.ZodArray<z.ZodEnum<{
17
+ skill: "skill";
18
+ api_rest: "api_rest";
19
+ api_rpc: "api_rpc";
20
+ a2a: "a2a";
21
+ mcp: "mcp";
22
+ cli: "cli";
23
+ browser: "browser";
24
+ }>>>;
25
+ sourceRefPolicy: z.ZodOptional<z.ZodObject<{
26
+ minSourceRefs: z.ZodDefault<z.ZodNumber>;
27
+ rejectInlineSensitivePayload: z.ZodOptional<z.ZodBoolean>;
28
+ }, z.core.$strip>>;
29
+ }, z.core.$strip>;
30
+ export type ConnectorManifest = z.infer<typeof connectorManifestSchema>;
31
+ export interface ResolvedConnectorCapability {
32
+ platformId: string;
33
+ intent: CapabilityIntent;
34
+ source: "namespace" | "v5_explicit" | "unambiguous_default";
35
+ }
36
+ export declare class CapabilityContractRegistry {
37
+ private readonly byPlatform;
38
+ register(manifest: ConnectorManifest): void;
39
+ loadManifest(platformId: string): ConnectorManifest;
40
+ listRegisteredPlatformIds(): string[];
41
+ hasCapability(platformId: string, intent: CapabilityIntent): boolean;
42
+ listCapabilities(platformId: string): CapabilityIntent[];
43
+ listChannels(platformId: string): ChannelType[];
44
+ /**
45
+ * Resolve a capability string that may be namespaced (`platformId:capability`)
46
+ * or a bare v5 capability. Returns the platform + intent pair.
47
+ * If bare capability and no explicit platform is provided, only succeeds when
48
+ * exactly one registered platform supports it (unambiguous_default).
49
+ */
50
+ resolveCapability(intentWithNamespace: string, explicitPlatformId?: string): ResolvedConnectorCapability;
51
+ findPlatformsForIntent(intent: CapabilityIntent): string[];
52
+ }
53
+ /** T3.1.1 contract name for manifest-first registry. */
54
+ export declare const ConnectorManifestRegistry: typeof CapabilityContractRegistry;
55
+ export type ConnectorManifestRegistry = CapabilityContractRegistry;
56
+ export declare function describeConnector(registry: CapabilityContractRegistry, platformId: string): ConnectorManifest;
57
+ export declare function checkConnector(registry: CapabilityContractRegistry, platformId: string): {
58
+ ok: boolean;
59
+ errors: string[];
60
+ };
61
+ export declare function discoverCapabilities(registry: CapabilityContractRegistry): Array<{
62
+ platformId: string;
63
+ capabilities: CapabilityIntent[];
64
+ degradedChannels?: ChannelType[];
65
+ }>;
66
+ export declare function parseConnectorManifest(input: unknown): ConnectorManifest;
67
+ export {};
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { CAPABILITY_INTENTS, CHANNEL_TYPES } from "./contract.js";
2
+ import { CHANNEL_TYPES } from "./contract.js";
3
3
  const sourceRefPolicySchema = z
4
4
  .object({
5
5
  minSourceRefs: z.number().int().min(0).default(1),
@@ -8,9 +8,9 @@ const sourceRefPolicySchema = z
8
8
  .optional();
9
9
  const connectorManifestSchema = z.object({
10
10
  platformId: z.string().min(1),
11
- supportedCapabilities: z.array(z.enum(CAPABILITY_INTENTS)).min(1),
11
+ supportedCapabilities: z.array(z.string().min(1).regex(/^[a-zA-Z0-9_.:-]+$/)).min(1),
12
12
  channelPriority: z.array(z.enum(CHANNEL_TYPES)).min(1),
13
- credentialTypes: z.array(z.string().min(1)).min(1),
13
+ credentialTypes: z.array(z.string().min(1)),
14
14
  degradedChannels: z.array(z.enum(CHANNEL_TYPES)).optional(),
15
15
  sourceRefPolicy: sourceRefPolicySchema,
16
16
  });
@@ -51,8 +51,8 @@ export class CapabilityContractRegistry {
51
51
  if (colonIndex >= 0) {
52
52
  const platformId = intentWithNamespace.slice(0, colonIndex);
53
53
  const intent = intentWithNamespace.slice(colonIndex + 1);
54
- if (!CAPABILITY_INTENTS.includes(intent)) {
55
- throw new Error(`capability_not_recognized:${intent}`);
54
+ if (!intent) {
55
+ throw new Error("capability_not_recognized:");
56
56
  }
57
57
  if (!this.byPlatform.has(platformId)) {
58
58
  throw new Error(`platform_not_found:${platformId}`);
@@ -60,8 +60,8 @@ export class CapabilityContractRegistry {
60
60
  return { platformId, intent, source: "namespace" };
61
61
  }
62
62
  const intent = intentWithNamespace;
63
- if (!CAPABILITY_INTENTS.includes(intent)) {
64
- throw new Error(`capability_not_recognized:${intent}`);
63
+ if (!intent) {
64
+ throw new Error("capability_not_recognized:");
65
65
  }
66
66
  if (explicitPlatformId) {
67
67
  if (!this.byPlatform.has(explicitPlatformId)) {
@@ -72,15 +72,18 @@ export class ConnectorRoutePlanner {
72
72
  if (cooldown.blocked) {
73
73
  throw new ConnectorPolicyError("cooldown_blocked", "platform_or_intent_cooldown_blocked", cooldown.retryAfterMs);
74
74
  }
75
- const credential = await this.statePort.loadCredentialState(request.platformId);
76
- if (credential.status === "missing" || credential.status === "revoked" || credential.status === "failed") {
77
- throw new ConnectorPolicyError("auth_failure", "credential_unavailable_for_route");
78
- }
79
- if (credential.status === "expired") {
80
- throw new ConnectorPolicyError("credential_expired", "credential_expired_for_route");
81
- }
82
75
  const channels = [...manifest.channelPriority];
83
- const byCredential = chooseByCredentialState(channels, credential);
76
+ let byCredential;
77
+ if (manifest.credentialTypes.length > 0) {
78
+ const credential = await this.statePort.loadCredentialState(request.platformId);
79
+ if (credential.status === "missing" || credential.status === "revoked" || credential.status === "failed") {
80
+ throw new ConnectorPolicyError("auth_failure", "credential_unavailable_for_route");
81
+ }
82
+ if (credential.status === "expired") {
83
+ throw new ConnectorPolicyError("credential_expired", "credential_expired_for_route");
84
+ }
85
+ byCredential = chooseByCredentialState(channels, credential);
86
+ }
84
87
  const preferred = choosePreferred(channels, request.preferredChannel);
85
88
  const selected = byCredential ?? preferred ?? chooseHealthy(channels, request.platformId, this.channelHealth);
86
89
  if (!selected) {
@@ -0,0 +1,59 @@
1
+ /**
2
+ * StructuredUnavailableReason Builder — T-CS.C.3
3
+ *
4
+ * Core logic: Every unavailable-connector scenario MUST return a machine-
5
+ * readable reason code. No silent failures allowed.
6
+ *
7
+ * Reason codes:
8
+ * - credentials_missing → credential not found for platform
9
+ * - not_registered → connector manifest not in registry
10
+ * - trust_denied → credential verification failed
11
+ * - circuit_open → circuit breaker is open (cooldown blocked)
12
+ * - platform_error → platform returned 5xx / transport failure
13
+ * - probe_failed → wet probe returned non-2xx
14
+ * - probe_policy_denied → strict idempotencyClass blocked probe (DR-006)
15
+ *
16
+ * Dependencies:
17
+ * - `FailureClass` from `./failure-taxonomy.js`
18
+ *
19
+ * Boundary:
20
+ * - All builder methods are pure; no side effects.
21
+ * - `build()` validates that code and message are present.
22
+ *
23
+ * Test coverage: tests/unit/connectors/structured-unavailable-reason.test.ts
24
+ */
25
+ import type { FailureClass } from "./failure-taxonomy.js";
26
+ export type UnavailableReasonCode = "credentials_missing" | "not_registered" | "trust_denied" | "circuit_open" | "platform_error" | "probe_failed" | "probe_policy_denied";
27
+ export interface StructuredUnavailableReason {
28
+ code: UnavailableReasonCode;
29
+ message: string;
30
+ platformId?: string;
31
+ capabilityId?: string;
32
+ failureClass?: FailureClass;
33
+ retryAfterMs?: number;
34
+ timestamp: string;
35
+ }
36
+ export declare class UnavailableReasonBuilder {
37
+ private code?;
38
+ private message?;
39
+ private platformId?;
40
+ private capabilityId?;
41
+ private failureClass?;
42
+ private retryAfterMs?;
43
+ static for(code: UnavailableReasonCode, message: string): UnavailableReasonBuilder;
44
+ withPlatformId(platformId: string): this;
45
+ withCapabilityId(capabilityId: string): this;
46
+ withFailureClass(failureClass: FailureClass): this;
47
+ withRetryAfterMs(ms: number): this;
48
+ build(): StructuredUnavailableReason;
49
+ }
50
+ /**
51
+ * Convenience factory for common unavailable scenarios.
52
+ */
53
+ export declare function unavailableCredentialsMissing(platformId: string): StructuredUnavailableReason;
54
+ export declare function unavailableNotRegistered(platformId: string): StructuredUnavailableReason;
55
+ export declare function unavailableTrustDenied(platformId: string): StructuredUnavailableReason;
56
+ export declare function unavailableCircuitOpen(platformId: string, retryAfterMs?: number): StructuredUnavailableReason;
57
+ export declare function unavailablePlatformError(platformId: string, failureClass?: FailureClass): StructuredUnavailableReason;
58
+ export declare function unavailableProbeFailed(platformId: string, capabilityId: string): StructuredUnavailableReason;
59
+ export declare function unavailableProbePolicyDenied(platformId: string, capabilityId: string): StructuredUnavailableReason;
@@ -0,0 +1,113 @@
1
+ /**
2
+ * StructuredUnavailableReason Builder — T-CS.C.3
3
+ *
4
+ * Core logic: Every unavailable-connector scenario MUST return a machine-
5
+ * readable reason code. No silent failures allowed.
6
+ *
7
+ * Reason codes:
8
+ * - credentials_missing → credential not found for platform
9
+ * - not_registered → connector manifest not in registry
10
+ * - trust_denied → credential verification failed
11
+ * - circuit_open → circuit breaker is open (cooldown blocked)
12
+ * - platform_error → platform returned 5xx / transport failure
13
+ * - probe_failed → wet probe returned non-2xx
14
+ * - probe_policy_denied → strict idempotencyClass blocked probe (DR-006)
15
+ *
16
+ * Dependencies:
17
+ * - `FailureClass` from `./failure-taxonomy.js`
18
+ *
19
+ * Boundary:
20
+ * - All builder methods are pure; no side effects.
21
+ * - `build()` validates that code and message are present.
22
+ *
23
+ * Test coverage: tests/unit/connectors/structured-unavailable-reason.test.ts
24
+ */
25
+ export class UnavailableReasonBuilder {
26
+ code;
27
+ message;
28
+ platformId;
29
+ capabilityId;
30
+ failureClass;
31
+ retryAfterMs;
32
+ static for(code, message) {
33
+ const b = new UnavailableReasonBuilder();
34
+ b.code = code;
35
+ b.message = message;
36
+ return b;
37
+ }
38
+ withPlatformId(platformId) {
39
+ this.platformId = platformId;
40
+ return this;
41
+ }
42
+ withCapabilityId(capabilityId) {
43
+ this.capabilityId = capabilityId;
44
+ return this;
45
+ }
46
+ withFailureClass(failureClass) {
47
+ this.failureClass = failureClass;
48
+ return this;
49
+ }
50
+ withRetryAfterMs(ms) {
51
+ this.retryAfterMs = ms;
52
+ return this;
53
+ }
54
+ build() {
55
+ if (!this.code) {
56
+ throw new Error("UnavailableReasonBuilder: code is required");
57
+ }
58
+ if (!this.message) {
59
+ throw new Error("UnavailableReasonBuilder: message is required");
60
+ }
61
+ return {
62
+ code: this.code,
63
+ message: this.message,
64
+ platformId: this.platformId,
65
+ capabilityId: this.capabilityId,
66
+ failureClass: this.failureClass,
67
+ retryAfterMs: this.retryAfterMs,
68
+ timestamp: new Date().toISOString(),
69
+ };
70
+ }
71
+ }
72
+ /**
73
+ * Convenience factory for common unavailable scenarios.
74
+ */
75
+ export function unavailableCredentialsMissing(platformId) {
76
+ return UnavailableReasonBuilder.for("credentials_missing", `No active credential found for platform ${platformId}`)
77
+ .withPlatformId(platformId)
78
+ .build();
79
+ }
80
+ export function unavailableNotRegistered(platformId) {
81
+ return UnavailableReasonBuilder.for("not_registered", `Connector manifest not registered for platform ${platformId}`)
82
+ .withPlatformId(platformId)
83
+ .build();
84
+ }
85
+ export function unavailableTrustDenied(platformId) {
86
+ return UnavailableReasonBuilder.for("trust_denied", `Credential verification failed for platform ${platformId}`)
87
+ .withPlatformId(platformId)
88
+ .build();
89
+ }
90
+ export function unavailableCircuitOpen(platformId, retryAfterMs) {
91
+ const b = UnavailableReasonBuilder.for("circuit_open", `Circuit breaker open for platform ${platformId}`).withPlatformId(platformId);
92
+ if (retryAfterMs !== undefined)
93
+ b.withRetryAfterMs(retryAfterMs);
94
+ return b.build();
95
+ }
96
+ export function unavailablePlatformError(platformId, failureClass) {
97
+ const b = UnavailableReasonBuilder.for("platform_error", `Platform error for ${platformId}`).withPlatformId(platformId);
98
+ if (failureClass)
99
+ b.withFailureClass(failureClass);
100
+ return b.build();
101
+ }
102
+ export function unavailableProbeFailed(platformId, capabilityId) {
103
+ return UnavailableReasonBuilder.for("probe_failed", `Wet probe failed for ${platformId}:${capabilityId}`)
104
+ .withPlatformId(platformId)
105
+ .withCapabilityId(capabilityId)
106
+ .build();
107
+ }
108
+ export function unavailableProbePolicyDenied(platformId, capabilityId) {
109
+ return UnavailableReasonBuilder.for("probe_policy_denied", `Probe blocked by policy (strict idempotencyClass) for ${platformId}:${capabilityId}`)
110
+ .withPlatformId(platformId)
111
+ .withCapabilityId(capabilityId)
112
+ .build();
113
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * WetProbeRunner — T-CS.C.2
3
+ *
4
+ * Core logic: Performs real HTTP GET against a connector's safe probe endpoint.
5
+ * Double-verifies `safe_for_probe` before issuing the request:
6
+ * 1. IdempotencyClass check: `strict` side-effects are rejected with
7
+ * `probe_policy_denied` (DR-006).
8
+ * 2. Endpoint validation: only `safeEndpoint` from probeConfig is allowed.
9
+ *
10
+ * Returns a CapabilityProbeResult containing capabilityId, actualStatus,
11
+ * httpStatus, and sampleResponseRef.
12
+ *
13
+ * Dependencies:
14
+ * - `CapabilityContractRegistryV7` from `./manifest-v7.js`
15
+ * - `CapabilityProbeResult` from `../../shared/types/v7-entities.js`
16
+ * - `ProbeActualStatus` from `../../shared/types/v7-entities.js`
17
+ *
18
+ * Boundary:
19
+ * - Never probes endpoints not explicitly marked safe.
20
+ * - Never probes capabilities with idempotencyClass = "strict".
21
+ * - HTTP layer is injectable (`httpGet`) for testability.
22
+ *
23
+ * Test coverage: tests/unit/connectors/wet-probe-runner.test.ts
24
+ */
25
+ import type { CapabilityContractRegistryV7 } from "./manifest-v7.js";
26
+ import type { CapabilityProbeResult } from "../../shared/types/v7-entities.js";
27
+ export type HttpGetFn = (url: string) => Promise<{
28
+ status: number;
29
+ body?: string;
30
+ }>;
31
+ export interface WetProbeResult {
32
+ probeResult: CapabilityProbeResult;
33
+ httpStatus: number;
34
+ }
35
+ export interface WetProbeRunner {
36
+ runWetProbe(platformId: string, capabilityId: string, registry: CapabilityContractRegistryV7, options?: {
37
+ httpGet?: HttpGetFn;
38
+ }): Promise<WetProbeResult>;
39
+ }
40
+ export declare function createWetProbeRunner(): WetProbeRunner;
@@ -0,0 +1,132 @@
1
+ /**
2
+ * WetProbeRunner — T-CS.C.2
3
+ *
4
+ * Core logic: Performs real HTTP GET against a connector's safe probe endpoint.
5
+ * Double-verifies `safe_for_probe` before issuing the request:
6
+ * 1. IdempotencyClass check: `strict` side-effects are rejected with
7
+ * `probe_policy_denied` (DR-006).
8
+ * 2. Endpoint validation: only `safeEndpoint` from probeConfig is allowed.
9
+ *
10
+ * Returns a CapabilityProbeResult containing capabilityId, actualStatus,
11
+ * httpStatus, and sampleResponseRef.
12
+ *
13
+ * Dependencies:
14
+ * - `CapabilityContractRegistryV7` from `./manifest-v7.js`
15
+ * - `CapabilityProbeResult` from `../../shared/types/v7-entities.js`
16
+ * - `ProbeActualStatus` from `../../shared/types/v7-entities.js`
17
+ *
18
+ * Boundary:
19
+ * - Never probes endpoints not explicitly marked safe.
20
+ * - Never probes capabilities with idempotencyClass = "strict".
21
+ * - HTTP layer is injectable (`httpGet`) for testability.
22
+ *
23
+ * Test coverage: tests/unit/connectors/wet-probe-runner.test.ts
24
+ */
25
+ const PROBE_POLICY_DENIED = {
26
+ probeResult: {
27
+ probeResultId: "probe_policy_denied",
28
+ capabilityId: "",
29
+ connectorId: "",
30
+ actualStatus: "unavailable",
31
+ probeConfigRef: "policy:denied",
32
+ createdAt: new Date().toISOString(),
33
+ },
34
+ httpStatus: 0,
35
+ };
36
+ function resolveProbeConfig(registry, platformId, capabilityId) {
37
+ const resolved = registry.resolveCapability(`${platformId}:${capabilityId}`);
38
+ if (!resolved)
39
+ return undefined;
40
+ const probeConfig = resolved.probeConfig;
41
+ if (!probeConfig)
42
+ return undefined;
43
+ return {
44
+ safeEndpoint: probeConfig.safeEndpoint,
45
+ idempotencyClass: probeConfig.idempotencyClass,
46
+ };
47
+ }
48
+ function actualStatusFromHttpStatus(status) {
49
+ if (status >= 200 && status < 300)
50
+ return "available";
51
+ if (status === 429 || status === 503)
52
+ return "degraded";
53
+ return "unavailable";
54
+ }
55
+ export function createWetProbeRunner() {
56
+ const defaultHttpGet = async (url) => {
57
+ const response = await fetch(url, { method: "GET" });
58
+ const body = await response.text().catch(() => undefined);
59
+ return { status: response.status, body };
60
+ };
61
+ return {
62
+ async runWetProbe(platformId, capabilityId, registry, options = {}) {
63
+ const httpGet = options.httpGet ?? defaultHttpGet;
64
+ // 1. Resolve capability and probe config
65
+ const config = resolveProbeConfig(registry, platformId, capabilityId);
66
+ if (!config) {
67
+ return {
68
+ ...PROBE_POLICY_DENIED,
69
+ probeResult: {
70
+ ...PROBE_POLICY_DENIED.probeResult,
71
+ probeResultId: `probe_no_config:${capabilityId}`,
72
+ capabilityId,
73
+ connectorId: platformId,
74
+ actualStatus: "unavailable",
75
+ probeConfigRef: "registry:missing",
76
+ createdAt: new Date().toISOString(),
77
+ },
78
+ httpStatus: 0,
79
+ };
80
+ }
81
+ // 2. DR-006: strict side-effect → probe_policy_denied
82
+ if (config.idempotencyClass === "strict") {
83
+ return {
84
+ ...PROBE_POLICY_DENIED,
85
+ probeResult: {
86
+ ...PROBE_POLICY_DENIED.probeResult,
87
+ probeResultId: `probe_policy_denied:${capabilityId}`,
88
+ capabilityId,
89
+ connectorId: platformId,
90
+ actualStatus: "unavailable",
91
+ probeConfigRef: config.safeEndpoint,
92
+ createdAt: new Date().toISOString(),
93
+ },
94
+ httpStatus: 0,
95
+ };
96
+ }
97
+ // 3. Execute HTTP GET against safe endpoint
98
+ try {
99
+ const response = await httpGet(config.safeEndpoint);
100
+ const actualStatus = actualStatusFromHttpStatus(response.status);
101
+ return {
102
+ probeResult: {
103
+ probeResultId: `probe:${platformId}:${capabilityId}:${Date.now()}`,
104
+ capabilityId,
105
+ connectorId: platformId,
106
+ actualStatus,
107
+ httpStatus: response.status,
108
+ sampleResponseRef: response.body
109
+ ? `probe:body:${Buffer.from(response.body).toString("base64").slice(0, 64)}`
110
+ : undefined,
111
+ probeConfigRef: config.safeEndpoint,
112
+ createdAt: new Date().toISOString(),
113
+ },
114
+ httpStatus: response.status,
115
+ };
116
+ }
117
+ catch {
118
+ return {
119
+ probeResult: {
120
+ probeResultId: `probe_error:${platformId}:${capabilityId}:${Date.now()}`,
121
+ capabilityId,
122
+ connectorId: platformId,
123
+ actualStatus: "unavailable",
124
+ probeConfigRef: config.safeEndpoint,
125
+ createdAt: new Date().toISOString(),
126
+ },
127
+ httpStatus: 0,
128
+ };
129
+ }
130
+ },
131
+ };
132
+ }
@@ -20,6 +20,8 @@ export declare const capabilityDeclarationSchema: z.ZodObject<{
20
20
  id: z.ZodString;
21
21
  channel: z.ZodOptional<z.ZodString>;
22
22
  description: z.ZodOptional<z.ZodString>;
23
+ sourceRefs: z.ZodOptional<z.ZodArray<z.ZodString>>;
24
+ observedCount: z.ZodOptional<z.ZodNumber>;
23
25
  }, z.core.$strip>;
24
26
  export type ConnectorCapabilityDeclaration = z.infer<typeof capabilityDeclarationSchema>;
25
27
  export declare const runnerDeclarationSchema: z.ZodObject<{
@@ -72,6 +74,8 @@ export declare const connectorManifestV6Schema: z.ZodObject<{
72
74
  id: z.ZodString;
73
75
  channel: z.ZodOptional<z.ZodString>;
74
76
  description: z.ZodOptional<z.ZodString>;
77
+ sourceRefs: z.ZodOptional<z.ZodArray<z.ZodString>>;
78
+ observedCount: z.ZodOptional<z.ZodNumber>;
75
79
  }, z.core.$strip>>;
76
80
  runner: z.ZodObject<{
77
81
  kind: z.ZodEnum<{
@@ -18,6 +18,8 @@ export const capabilityDeclarationSchema = z.object({
18
18
  id: z.string().min(1),
19
19
  channel: z.string().optional(),
20
20
  description: z.string().optional(),
21
+ sourceRefs: z.array(z.string().min(1)).optional(),
22
+ observedCount: z.number().int().positive().optional(),
21
23
  });
22
24
  export const runnerDeclarationSchema = z.object({
23
25
  kind: connectorRunnerKindSchema,
@@ -12,5 +12,6 @@ import type { StateDatabase } from "../../storage/db/index.js";
12
12
  export interface ConnectorExecutorAdapterOptions {
13
13
  stateDb: StateDatabase;
14
14
  observabilityDb: ObservabilityDatabase;
15
+ workspaceRoot?: string;
15
16
  }
16
17
  export declare function createConnectorExecutorAdapter(options: ConnectorExecutorAdapterOptions): ConnectorExecutor;