@evomap/evolver-core 2.0.0-beta.1 → 2.0.0-beta.11

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 (137) hide show
  1. package/assets/gep/genes.jsonl +5 -0
  2. package/dist/algo/candidateAssembly.js +23 -14
  3. package/dist/algo/capabilityCandidates.d.ts +2 -0
  4. package/dist/algo/capabilityCandidates.js +5 -0
  5. package/dist/algo/conversationSniffer.d.ts +18 -0
  6. package/dist/algo/conversationSniffer.js +149 -0
  7. package/dist/algo/cycleEngine.d.ts +11 -0
  8. package/dist/algo/cycleEngine.js +14 -6
  9. package/dist/algo/cycleFailureClassifier.d.ts +1 -1
  10. package/dist/algo/cycleFailureClassifier.js +13 -5
  11. package/dist/algo/geneIntake.d.ts +14 -4
  12. package/dist/algo/geneIntake.js +37 -9
  13. package/dist/algo/geneSelection.d.ts +18 -1
  14. package/dist/algo/geneSelection.js +42 -18
  15. package/dist/algo/index.d.ts +2 -0
  16. package/dist/algo/index.js +2 -0
  17. package/dist/algo/memoryGraph.d.ts +62 -0
  18. package/dist/algo/memoryGraph.js +86 -0
  19. package/dist/algo/orchestrator.d.ts +3 -0
  20. package/dist/algo/orchestrator.js +14 -2
  21. package/dist/assetstore/assetSidecarRecords.d.ts +28 -0
  22. package/dist/assetstore/assetSidecarRecords.js +376 -0
  23. package/dist/assetstore/assetSidecarRecovery.d.ts +48 -0
  24. package/dist/assetstore/assetSidecarRecovery.js +288 -0
  25. package/dist/assetstore/assetStoreHealth.d.ts +82 -0
  26. package/dist/assetstore/assetStoreHealth.js +308 -0
  27. package/dist/assetstore/assetStoreLayout.d.ts +2 -0
  28. package/dist/assetstore/assetStoreLayout.js +6 -0
  29. package/dist/assetstore/assetStoreStorage.d.ts +42 -0
  30. package/dist/assetstore/assetStoreStorage.js +327 -0
  31. package/dist/assetstore/assetSyncLedger.d.ts +118 -0
  32. package/dist/assetstore/assetSyncLedger.js +745 -0
  33. package/dist/assetstore/index.d.ts +5 -1
  34. package/dist/assetstore/index.js +5 -1
  35. package/dist/assetstore/localJsonl.d.ts +12 -3
  36. package/dist/assetstore/localJsonl.js +131 -39
  37. package/dist/assetstore/pendingSignals.js +3 -1
  38. package/dist/assetstore/provenance.d.ts +39 -4
  39. package/dist/assetstore/provenance.js +134 -55
  40. package/dist/assetstore/provider.d.ts +40 -0
  41. package/dist/assetstore/provider.js +63 -5
  42. package/dist/assetstore/reviewFilter.js +5 -2
  43. package/dist/assetstore/reviewLedger.d.ts +14 -2
  44. package/dist/assetstore/reviewLedger.js +78 -43
  45. package/dist/assetstore/seedGenes.d.ts +3 -0
  46. package/dist/assetstore/seedGenes.js +134 -0
  47. package/dist/benchmark/antiGeneBenchmark.d.ts +2 -0
  48. package/dist/benchmark/antiGeneBenchmark.js +11 -1
  49. package/dist/benchmark/antiGeneImpact.d.ts +16 -0
  50. package/dist/benchmark/antiGeneImpact.js +34 -0
  51. package/dist/benchmark/antiGeneRollout.d.ts +2 -0
  52. package/dist/benchmark/antiGeneRollout.js +13 -1
  53. package/dist/benchmark/index.d.ts +2 -1
  54. package/dist/benchmark/index.js +2 -1
  55. package/dist/benchmark/triggerShift.d.ts +62 -0
  56. package/dist/benchmark/triggerShift.js +106 -0
  57. package/dist/events/eventArchive.d.ts +65 -0
  58. package/dist/events/eventArchive.js +343 -0
  59. package/dist/events/eventStore.js +2 -12
  60. package/dist/events/ingest.d.ts +1 -1
  61. package/dist/events/ingest.js +9 -0
  62. package/dist/events/paths.d.ts +10 -10
  63. package/dist/events/paths.js +20 -20
  64. package/dist/events/public.d.ts +3 -1
  65. package/dist/events/public.js +2 -1
  66. package/dist/events/retention.d.ts +24 -1
  67. package/dist/events/retention.js +133 -37
  68. package/dist/exec/autoExec.d.ts +6 -1
  69. package/dist/exec/autoExec.js +34 -0
  70. package/dist/exec/autonomousCycle.d.ts +2 -0
  71. package/dist/exec/autonomousCycle.js +5 -0
  72. package/dist/exec/claudeBridge.d.ts +21 -3
  73. package/dist/exec/claudeBridge.js +413 -26
  74. package/dist/exec/openPrRegistry.d.ts +8 -2
  75. package/dist/exec/openPrRegistry.js +32 -22
  76. package/dist/exec/prompt.js +9 -0
  77. package/dist/exec/runnerRegistry.d.ts +90 -18
  78. package/dist/exec/runnerRegistry.js +603 -42
  79. package/dist/exec/selfPrObfuscation.d.ts +2 -1
  80. package/dist/exec/selfPrObfuscation.js +19 -6
  81. package/dist/hub/agentDirectory.d.ts +90 -0
  82. package/dist/hub/agentDirectory.js +104 -0
  83. package/dist/hub/bindings.js +23 -3
  84. package/dist/hub/capability.d.ts +14 -2
  85. package/dist/hub/fake.d.ts +4 -2
  86. package/dist/hub/fake.js +3 -2
  87. package/dist/hub/index.d.ts +1 -0
  88. package/dist/hub/index.js +1 -0
  89. package/dist/hub/sanitize.js +3 -2
  90. package/dist/index.d.ts +2 -1
  91. package/dist/index.js +2 -1
  92. package/dist/issueReporter/index.d.ts +156 -0
  93. package/dist/issueReporter/index.js +1688 -0
  94. package/dist/mailbox/catalog.js +3 -0
  95. package/dist/mailbox/ipcServer.js +2 -2
  96. package/dist/mailbox/store.d.ts +14 -0
  97. package/dist/mailbox/store.js +44 -2
  98. package/dist/material/consumer.js +9 -6
  99. package/dist/material/index.d.ts +1 -0
  100. package/dist/material/index.js +1 -0
  101. package/dist/material/materialArchive.d.ts +81 -0
  102. package/dist/material/materialArchive.js +466 -0
  103. package/dist/material/materialStore.d.ts +1 -0
  104. package/dist/material/materialStore.js +6 -13
  105. package/dist/ops/savingsCore.js +1 -2
  106. package/dist/ops/selfUpdate.d.ts +10 -1
  107. package/dist/ops/selfUpdate.js +64 -15
  108. package/dist/personality/schema.d.ts +12 -12
  109. package/dist/schema/common.d.ts +1 -1
  110. package/dist/schema/common.js +1 -1
  111. package/dist/schema/material.d.ts +5 -5
  112. package/dist/strategy/constraintAblation.d.ts +64 -0
  113. package/dist/strategy/constraintAblation.js +3074 -0
  114. package/dist/strategy/index.d.ts +2 -1
  115. package/dist/strategy/index.js +2 -1
  116. package/dist/trace/trajectoryExport.js +2 -2
  117. package/dist/util/fetchPort.d.ts +1 -0
  118. package/dist/util/fetchPort.js +11 -0
  119. package/dist/util/fileLock.d.ts +24 -5
  120. package/dist/util/fileLock.js +288 -72
  121. package/dist/util/index.d.ts +1 -0
  122. package/dist/util/index.js +1 -0
  123. package/dist/wire/geneHints.d.ts +42 -1
  124. package/dist/wire/geneHints.js +52 -1
  125. package/dist/wire/index.d.ts +14 -2
  126. package/dist/wire/index.js +1 -1
  127. package/dist/workflow/dsl.d.ts +24 -3
  128. package/dist/workflow/dsl.js +4 -0
  129. package/dist/workflow/engine.d.ts +5 -1
  130. package/dist/workflow/engine.js +3 -0
  131. package/dist/workflow/index.d.ts +3 -1
  132. package/dist/workflow/index.js +3 -1
  133. package/dist/workflow/runtime.d.ts +110 -0
  134. package/dist/workflow/runtime.js +1298 -0
  135. package/dist/workflow/stateStore.d.ts +172 -0
  136. package/dist/workflow/stateStore.js +1044 -0
  137. package/package.json +6 -1
@@ -9,7 +9,8 @@ export declare function resetObfuscatedCache(reader?: ReadManifest): void;
9
9
  /**
10
10
  * Load the obfuscated-file set from the manifest. Returns a normalized Set, or null when the manifest is
11
11
  * missing / unreadable / structurally invalid (NOT an `obfuscate` array of literal string paths). null is the
12
- * fail-closed signal: the caller must then reject all files. Result is cached per reader.
12
+ * fail-closed signal: the caller must then reject all files. Success is cached per reader; failures retry briefly
13
+ * so startup-time transient filesystem errors do not disable self-PR until process restart.
13
14
  */
14
15
  export declare function loadObfuscatedFiles(readManifest: ReadManifest): Set<string> | null;
15
16
  /**
@@ -28,8 +28,10 @@ export function defaultReadManifest(repoRoot) {
28
28
  }
29
29
  };
30
30
  }
31
+ const MANIFEST_TRANSIENT_RETRY_MS = 5 * 60 * 1000;
31
32
  // Resettable cache keyed by the reader identity, so distinct readers (e.g. per test) don't bleed into each other.
32
- // `null` = a load was attempted and FAILED (fail-closed); a Set = the loaded obfuscate paths.
33
+ // Success is cached permanently for the reader. Failures remain fail-closed, but transient reads retry for a
34
+ // short window before stabilizing to null for the process lifetime.
33
35
  const cache = new WeakMap();
34
36
  /** Test/maintenance hook: drop any cached load for a reader (or all readers) so the load path re-runs. */
35
37
  export function resetObfuscatedCache(reader) {
@@ -40,11 +42,15 @@ export function resetObfuscatedCache(reader) {
40
42
  /**
41
43
  * Load the obfuscated-file set from the manifest. Returns a normalized Set, or null when the manifest is
42
44
  * missing / unreadable / structurally invalid (NOT an `obfuscate` array of literal string paths). null is the
43
- * fail-closed signal: the caller must then reject all files. Result is cached per reader.
45
+ * fail-closed signal: the caller must then reject all files. Success is cached per reader; failures retry briefly
46
+ * so startup-time transient filesystem errors do not disable self-PR until process restart.
44
47
  */
45
48
  export function loadObfuscatedFiles(readManifest) {
46
- if (cache.has(readManifest))
47
- return cache.get(readManifest) ?? null;
49
+ const cached = cache.get(readManifest);
50
+ if (cached?.kind === 'loaded')
51
+ return cached.files;
52
+ if (cached?.kind === 'failed' && cached.stable)
53
+ return null;
48
54
  let result;
49
55
  try {
50
56
  const raw = readManifest();
@@ -63,9 +69,16 @@ export function loadObfuscatedFiles(readManifest) {
63
69
  result = new Set(manifest.obfuscate.map((f) => normalizeManifestPath(f)).filter(Boolean));
64
70
  }
65
71
  catch {
66
- result = null; // fail-closed: an unreadable/invalid manifest rejects everything
72
+ const now = Date.now();
73
+ const firstFailedAt = cached?.kind === 'failed' ? cached.firstFailedAt : now;
74
+ cache.set(readManifest, {
75
+ kind: 'failed',
76
+ firstFailedAt,
77
+ stable: now - firstFailedAt >= MANIFEST_TRANSIENT_RETRY_MS,
78
+ });
79
+ return null; // fail-closed: an unreadable/invalid manifest rejects everything
67
80
  }
68
- cache.set(readManifest, result);
81
+ cache.set(readManifest, { kind: 'loaded', files: result });
69
82
  return result;
70
83
  }
71
84
  /**
@@ -0,0 +1,90 @@
1
+ export declare const AGENT_DIRECTORY_DEFAULT_LIMIT = 20;
2
+ export declare const AGENT_DIRECTORY_MAX_LIMIT = 50;
3
+ export declare const AGENT_DIRECTORY_DEFAULT_TIMEOUT_MS = 8000;
4
+ export declare const AGENT_DIRECTORY_MAX_TIMEOUT_MS = 30000;
5
+ export declare const AGENT_DIRECTORY_MAX_QUERY_LENGTH = 500;
6
+ export declare const AGENT_DIRECTORY_MAX_SIGNAL_COUNT = 20;
7
+ export declare const AGENT_DIRECTORY_MAX_SIGNAL_LENGTH = 64;
8
+ export declare const AGENT_DIRECTORY_MAX_CURSOR_LENGTH = 256;
9
+ export declare const AGENT_DIRECTORY_MAX_AGENT_ID_LENGTH = 128;
10
+ export type AgentAvailability = 'online' | 'busy' | 'offline' | 'unknown';
11
+ export type AgentDirectorySort = 'relevance' | 'reputation' | 'recent' | 'availability';
12
+ export type SortOrder = 'asc' | 'desc';
13
+ export interface AgentSearchRequest {
14
+ query?: string;
15
+ signals?: readonly string[];
16
+ availability?: AgentAvailability;
17
+ sort?: AgentDirectorySort;
18
+ order?: SortOrder;
19
+ cursor?: string;
20
+ limit?: number;
21
+ timeoutMs?: number;
22
+ }
23
+ export interface AgentTaskDiscoveryRequest {
24
+ title: string;
25
+ description?: string;
26
+ signals?: readonly string[];
27
+ availability?: AgentAvailability;
28
+ sort?: AgentDirectorySort;
29
+ order?: SortOrder;
30
+ cursor?: string;
31
+ limit?: number;
32
+ timeoutMs?: number;
33
+ }
34
+ export interface AgentDirectoryEntry {
35
+ agentId: string;
36
+ displayName?: string;
37
+ summary?: string;
38
+ capabilities?: string[];
39
+ domains?: string[];
40
+ score?: number;
41
+ reputation?: number;
42
+ completedTaskCount?: number;
43
+ availability?: AgentAvailability;
44
+ lastSeenAt?: number;
45
+ }
46
+ export interface AgentProfile {
47
+ agentId: string;
48
+ displayName?: string;
49
+ summary?: string;
50
+ capabilities?: string[];
51
+ domains?: string[];
52
+ reputation?: number;
53
+ completedTaskCount?: number;
54
+ availability?: AgentAvailability;
55
+ lastSeenAt?: number;
56
+ }
57
+ export interface AgentDirectoryPage {
58
+ items: AgentDirectoryEntry[];
59
+ nextCursor?: string;
60
+ hasMore: boolean;
61
+ }
62
+ export type AgentDirectoryFailureCode = 'capability_unavailable' | 'permission_denied' | 'hub_unavailable' | 'timeout' | 'invalid_request' | 'invalid_response';
63
+ export interface AgentDirectoryFailure {
64
+ code: AgentDirectoryFailureCode;
65
+ retryable: boolean;
66
+ message?: string;
67
+ }
68
+ export type AgentDirectoryResult<T> = {
69
+ ok: true;
70
+ value: T;
71
+ } | {
72
+ ok: false;
73
+ error: AgentDirectoryFailure;
74
+ };
75
+ export interface AgentDirectoryCapability {
76
+ search(request: AgentSearchRequest): Promise<AgentDirectoryResult<AgentDirectoryPage>>;
77
+ getProfile(agentId: string, options?: {
78
+ timeoutMs?: number;
79
+ }): Promise<AgentDirectoryResult<AgentProfile | null>>;
80
+ discoverForTask(request: AgentTaskDiscoveryRequest): Promise<AgentDirectoryResult<AgentDirectoryPage>>;
81
+ }
82
+ export declare class AgentDirectoryInputError extends Error {
83
+ readonly code = "invalid_request";
84
+ }
85
+ export declare function normalizeAgentSearchRequest(input: AgentSearchRequest): Required<Pick<AgentSearchRequest, 'limit' | 'timeoutMs' | 'sort' | 'order'>> & AgentSearchRequest;
86
+ export declare function normalizeAgentTaskDiscoveryRequest(input: AgentTaskDiscoveryRequest): AgentTaskDiscoveryRequest & Required<Pick<AgentTaskDiscoveryRequest, 'limit' | 'timeoutMs' | 'sort' | 'order'>>;
87
+ export declare function normalizeAgentId(value: string): string;
88
+ export declare function normalizeAgentDirectoryTimeout(value: number | undefined): number;
89
+ export declare function capabilityUnavailable(message?: string): AgentDirectoryResult<never>;
90
+ export declare function unsupportedAgentDirectoryCapability(message?: string): AgentDirectoryCapability;
@@ -0,0 +1,104 @@
1
+ export const AGENT_DIRECTORY_DEFAULT_LIMIT = 20;
2
+ export const AGENT_DIRECTORY_MAX_LIMIT = 50;
3
+ export const AGENT_DIRECTORY_DEFAULT_TIMEOUT_MS = 8_000;
4
+ export const AGENT_DIRECTORY_MAX_TIMEOUT_MS = 30_000;
5
+ export const AGENT_DIRECTORY_MAX_QUERY_LENGTH = 500;
6
+ export const AGENT_DIRECTORY_MAX_SIGNAL_COUNT = 20;
7
+ export const AGENT_DIRECTORY_MAX_SIGNAL_LENGTH = 64;
8
+ export const AGENT_DIRECTORY_MAX_CURSOR_LENGTH = 256;
9
+ export const AGENT_DIRECTORY_MAX_AGENT_ID_LENGTH = 128;
10
+ export class AgentDirectoryInputError extends Error {
11
+ code = 'invalid_request';
12
+ }
13
+ export function normalizeAgentSearchRequest(input) {
14
+ const query = optionalText(input.query, 'query', AGENT_DIRECTORY_MAX_QUERY_LENGTH);
15
+ const signals = normalizeSignals(input.signals);
16
+ const availability = input.availability ? enumValue(input.availability, ['online', 'busy', 'offline', 'unknown'], 'availability') : undefined;
17
+ if (!query && signals.length === 0)
18
+ throw new AgentDirectoryInputError('query_or_signals_required');
19
+ return {
20
+ ...(query ? { query } : {}),
21
+ ...(signals.length > 0 ? { signals } : {}),
22
+ ...(availability ? { availability } : {}),
23
+ ...(input.cursor ? { cursor: requiredText(input.cursor, 'cursor', AGENT_DIRECTORY_MAX_CURSOR_LENGTH) } : {}),
24
+ limit: boundedInteger(input.limit, AGENT_DIRECTORY_DEFAULT_LIMIT, 1, AGENT_DIRECTORY_MAX_LIMIT, 'limit'),
25
+ timeoutMs: boundedInteger(input.timeoutMs, AGENT_DIRECTORY_DEFAULT_TIMEOUT_MS, 100, AGENT_DIRECTORY_MAX_TIMEOUT_MS, 'timeout_ms'),
26
+ sort: input.sort ? enumValue(input.sort, ['relevance', 'reputation', 'recent', 'availability'], 'sort') : 'relevance',
27
+ order: input.order ? enumValue(input.order, ['asc', 'desc'], 'order') : 'desc',
28
+ };
29
+ }
30
+ export function normalizeAgentTaskDiscoveryRequest(input) {
31
+ const title = requiredText(input.title, 'title', AGENT_DIRECTORY_MAX_QUERY_LENGTH);
32
+ const description = optionalText(input.description, 'description', AGENT_DIRECTORY_MAX_QUERY_LENGTH);
33
+ const search = normalizeAgentSearchRequest({
34
+ query: [title, description].filter(Boolean).join('\n'),
35
+ signals: input.signals,
36
+ availability: input.availability,
37
+ sort: input.sort,
38
+ order: input.order,
39
+ cursor: input.cursor,
40
+ limit: input.limit,
41
+ timeoutMs: input.timeoutMs,
42
+ });
43
+ return { ...search, title, ...(description ? { description } : {}) };
44
+ }
45
+ export function normalizeAgentId(value) {
46
+ return requiredText(value, 'agent_id', AGENT_DIRECTORY_MAX_AGENT_ID_LENGTH);
47
+ }
48
+ export function normalizeAgentDirectoryTimeout(value) {
49
+ return boundedInteger(value, AGENT_DIRECTORY_DEFAULT_TIMEOUT_MS, 100, AGENT_DIRECTORY_MAX_TIMEOUT_MS, 'timeout_ms');
50
+ }
51
+ export function capabilityUnavailable(message = 'agent_directory_not_supported') {
52
+ return { ok: false, error: { code: 'capability_unavailable', retryable: false, message } };
53
+ }
54
+ export function unsupportedAgentDirectoryCapability(message) {
55
+ return {
56
+ search: async () => capabilityUnavailable(message),
57
+ getProfile: async () => capabilityUnavailable(message),
58
+ discoverForTask: async () => capabilityUnavailable(message),
59
+ };
60
+ }
61
+ function normalizeSignals(input) {
62
+ if (input === undefined)
63
+ return [];
64
+ if (!Array.isArray(input))
65
+ throw new AgentDirectoryInputError('signals_must_be_array');
66
+ if (input.length > AGENT_DIRECTORY_MAX_SIGNAL_COUNT)
67
+ throw new AgentDirectoryInputError('too_many_signals');
68
+ const out = [];
69
+ for (const value of input) {
70
+ if (typeof value !== 'string')
71
+ throw new AgentDirectoryInputError('signal_must_be_string');
72
+ const signal = requiredText(value, 'signal', AGENT_DIRECTORY_MAX_SIGNAL_LENGTH);
73
+ if (!out.includes(signal))
74
+ out.push(signal);
75
+ }
76
+ return out;
77
+ }
78
+ function optionalText(value, field, maxLength) {
79
+ if (value === undefined)
80
+ return undefined;
81
+ return requiredText(value, field, maxLength);
82
+ }
83
+ function requiredText(value, field, maxLength) {
84
+ if (typeof value !== 'string')
85
+ throw new AgentDirectoryInputError(`${field}_must_be_string`);
86
+ const text = value.trim();
87
+ if (!text)
88
+ throw new AgentDirectoryInputError(`${field}_required`);
89
+ if (text.length > maxLength)
90
+ throw new AgentDirectoryInputError(`${field}_too_long`);
91
+ return text;
92
+ }
93
+ function boundedInteger(value, fallback, min, max, field) {
94
+ if (value === undefined)
95
+ return fallback;
96
+ if (!Number.isInteger(value) || value < min || value > max)
97
+ throw new AgentDirectoryInputError(`${field}_out_of_range`);
98
+ return value;
99
+ }
100
+ function enumValue(value, allowed, field) {
101
+ if (!allowed.includes(value))
102
+ throw new AgentDirectoryInputError(`${field}_invalid`);
103
+ return value;
104
+ }
@@ -19,7 +19,7 @@ function envelopeToAgentEvent(e) {
19
19
  const stableId = e.type === 'proxy_trace' && e.idempotencyKey ? e.idempotencyKey : e.id;
20
20
  return {
21
21
  id: stableId,
22
- type: e.type,
22
+ type: e.type === 'dm_outbound' ? 'dm' : e.type,
23
23
  payload: e.payload,
24
24
  priority: 'medium',
25
25
  createdAt: e.createdAt,
@@ -59,10 +59,20 @@ export function makeHubBindings(cap, options = {}) {
59
59
  throw new PublishRejectedError(r.status, r.terminal ?? true, r.reason);
60
60
  return r;
61
61
  }
62
- case 'task_claim': return cap.task.claim(String(e.payload.taskId ?? ''));
62
+ case 'task_claim': {
63
+ const p = e.payload;
64
+ return cap.task.claim(firstString(p.taskId, p.task_id) ?? '');
65
+ }
63
66
  case 'task_complete': {
64
67
  const p = e.payload;
65
- return cap.task.complete(String(p.claimId ?? ''), p.result);
68
+ const taskId = firstString(p.taskId, p.task_id);
69
+ const assetId = firstString(p.assetId, p.asset_id);
70
+ const claimId = firstString(p.claimId, p.claim_id);
71
+ if (!claimId) {
72
+ throw new PublishRejectedError('invalid_task_complete', true, 'claim_id is required because task claim handles are opaque');
73
+ }
74
+ const context = taskId && assetId ? { taskId, assetId } : undefined;
75
+ return cap.task.complete(claimId, p.result, context);
66
76
  }
67
77
  default:
68
78
  // 其余 outbound(atp_*/heartbeat/...) 走 mailbox.push
@@ -87,4 +97,14 @@ export function makeHubBindings(cap, options = {}) {
87
97
  };
88
98
  },
89
99
  };
100
+ }
101
+ function firstString(...values) {
102
+ for (const value of values) {
103
+ if (typeof value !== 'string')
104
+ continue;
105
+ const trimmed = value.trim();
106
+ if (trimmed)
107
+ return trimmed;
108
+ }
109
+ return undefined;
90
110
  }
@@ -1,5 +1,6 @@
1
1
  import type { AssetRecord, AssetKind, SearchQuery, PutResult } from '../assetstore/provider.js';
2
2
  import type { Envelope } from '../mailbox/envelope.js';
3
+ import type { AgentDirectoryCapability } from './agentDirectory.js';
3
4
  /** publish 投递回执. hub 侧做 gate(经济/治理/RBAC 全在 hub), core 只读 status+reason. */
4
5
  export interface PublishReceipt {
5
6
  /** hub 返回的回执 id(公版=AgentEvent/decision id; 私有=审计 id). */
@@ -34,6 +35,15 @@ export interface TaskEvent {
34
35
  priority: 'high' | 'medium' | 'low';
35
36
  createdAt: number;
36
37
  }
38
+ /**
39
+ * Explicit task identity needed by hubs whose completion wire does not use their
40
+ * adapter-specific claim handle. claimId remains opaque and must never be parsed
41
+ * to recover either field.
42
+ */
43
+ export interface TaskCompleteContext {
44
+ taskId: string;
45
+ assetId: string;
46
+ }
37
47
  /** Proactive Hub question that a runtime may submit for ecosystem help. */
38
48
  export interface HubQuestion {
39
49
  question: string;
@@ -153,7 +163,7 @@ export interface RecipeCapability {
153
163
  get(recipeId: string): Promise<RecipeFetchReceipt>;
154
164
  express(recipeId: string, request?: RecipeExpressRequest): Promise<RecipeExpressionReceipt>;
155
165
  }
156
- export type HubCapabilityName = 'publish' | 'fetch' | 'search' | 'task' | 'mailbox' | 'auth' | 'audit' | 'air_gap' | 'tenant_isolation' | 'marketplace' | 'economy' | 'questions' | 'recipes';
166
+ export type HubCapabilityName = 'publish' | 'fetch' | 'search' | 'task' | 'mailbox' | 'auth' | 'audit' | 'air_gap' | 'tenant_isolation' | 'marketplace' | 'economy' | 'questions' | 'recipes' | 'agent_directory';
157
167
  /** hub 能力清单(可选). core 据此动态适配 UI/行为, "按需耦合". */
158
168
  export interface HubManifest {
159
169
  capabilities: HubCapabilityName[] | string[];
@@ -232,7 +242,7 @@ export interface HubCapability {
232
242
  claim(taskId: string): Promise<{
233
243
  claimId: string;
234
244
  }>;
235
- complete(claimId: string, result: unknown): Promise<{
245
+ complete(claimId: string, result: unknown, context?: TaskCompleteContext): Promise<{
236
246
  status: 'completed';
237
247
  }>;
238
248
  subscribe(filter: unknown): AsyncIterable<TaskEvent>;
@@ -243,6 +253,8 @@ export interface HubCapability {
243
253
  };
244
254
  /** Optional recipe/DNA seam. Recipe creation is draft-first; publishing remains explicit. */
245
255
  recipes?: RecipeCapability;
256
+ /** Optional agent discovery seam. Missing means the adapter does not support directory/profile discovery. */
257
+ agentDirectory?: AgentDirectoryCapability;
246
258
  /** mailbox 队列. poll/ack/push/status 四端点解耦(公版 /a2a/mailbox/*). */
247
259
  mailbox: {
248
260
  poll(): Promise<MailboxPollResult>;
@@ -1,4 +1,4 @@
1
- import type { HubCapability, PublishReceipt, AgentEvent, TaskEvent, AuthProvider, HubQuery, AssetRecord } from './capability.js';
1
+ import type { HubCapability, PublishReceipt, AgentEvent, TaskEvent, AuthProvider, HubQuery, AssetRecord, TaskCompleteContext } from './capability.js';
2
2
  export interface FakeHubOptions {
3
3
  /** 脚本化 publish gate: 返回 reject/quarantine 以测 PublishReceipt 终态路径. */
4
4
  publishGate?: (asset: AssetRecord) => Pick<PublishReceipt, 'status' | 'reason' | 'terminal'>;
@@ -20,8 +20,10 @@ export declare class FakeHubCapability implements HubCapability {
20
20
  readonly completed: Array<{
21
21
  claimId: string;
22
22
  result: unknown;
23
+ context?: TaskCompleteContext;
23
24
  }>;
24
25
  readonly auth: AuthProvider;
26
+ agentDirectory?: import('./agentDirectory.js').AgentDirectoryCapability;
25
27
  nextPollAfterMs: number | undefined;
26
28
  constructor(opts?: FakeHubOptions);
27
29
  /** 测试注入: 排一条 inbound 事件供 poll 拉. */
@@ -33,7 +35,7 @@ export declare class FakeHubCapability implements HubCapability {
33
35
  claim: (taskId: string) => Promise<{
34
36
  claimId: string;
35
37
  }>;
36
- complete: (claimId: string, result: unknown) => Promise<{
38
+ complete: (claimId: string, result: unknown, context?: TaskCompleteContext) => Promise<{
37
39
  status: "completed";
38
40
  }>;
39
41
  subscribe: (filter: unknown) => AsyncIterable<TaskEvent>;
package/dist/hub/fake.js CHANGED
@@ -19,6 +19,7 @@ export class FakeHubCapability {
19
19
  claims = [];
20
20
  completed = [];
21
21
  auth = fakeAuth;
22
+ agentDirectory;
22
23
  nextPollAfterMs;
23
24
  constructor(opts = {}) {
24
25
  this.opts = opts;
@@ -42,8 +43,8 @@ export class FakeHubCapability {
42
43
  this.claims.push({ taskId, claimId });
43
44
  return { claimId };
44
45
  },
45
- complete: async (claimId, result) => {
46
- this.completed.push({ claimId, result });
46
+ complete: async (claimId, result, context) => {
47
+ this.completed.push({ claimId, result, ...(context ? { context } : {}) });
47
48
  return { status: 'completed' };
48
49
  },
49
50
  subscribe: async function* () {
@@ -1,4 +1,5 @@
1
1
  export * from './capability.js';
2
+ export * from './agentDirectory.js';
2
3
  export * from './fake.js';
3
4
  export * from './bindings.js';
4
5
  export * from './sanitize.js';
package/dist/hub/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from './capability.js';
2
+ export * from './agentDirectory.js';
2
3
  export * from './fake.js';
3
4
  export * from './bindings.js';
4
5
  export * from './sanitize.js';
@@ -16,11 +16,12 @@ const REDACT_PATTERNS = [
16
16
  /api[_-]?key[=:]\s*["']?[A-Za-z0-9-._~+/]{16,}["']?/gi,
17
17
  /secret[=:]\s*["']?[A-Za-z0-9-._~+/]{16,}["']?/gi,
18
18
  /password[=:]\s*["']?[^\s"',;)}\]]{6,}["']?/gi,
19
- // GitHub tokens (ghp_, gho_, ghu_, ghs_, github_pat_)
19
+ // GitHub tokens (ghp_, gho_, ghu_, ghs_, ghr_, github_pat_)
20
20
  /ghp_[A-Za-z0-9]{36,}/g,
21
21
  /gho_[A-Za-z0-9]{36,}/g,
22
22
  /ghu_[A-Za-z0-9]{36,}/g,
23
23
  /ghs_[A-Za-z0-9]{36,}/g,
24
+ /ghr_[A-Za-z0-9]{36,}/g,
24
25
  /github_pat_[A-Za-z0-9_]{22,}/g,
25
26
  // AWS access keys
26
27
  /AKIA[0-9A-Z]{16}/g,
@@ -139,7 +140,7 @@ const LEAK_SCANNERS = [
139
140
  { type: 'api_key', pattern: /sk-proj-[A-Za-z0-9-_]{20,}/g, suggest: 'process.env.OPENAI_API_KEY' },
140
141
  { type: 'api_key', pattern: /sk-ant-[A-Za-z0-9-_]{20,}/g, suggest: 'process.env.ANTHROPIC_API_KEY' },
141
142
  { type: 'api_key', pattern: /AKIA[0-9A-Z]{16}/g, suggest: 'process.env.AWS_ACCESS_KEY_ID' },
142
- { type: 'github_token', pattern: /ghp_[A-Za-z0-9]{36,}/g, suggest: 'process.env.GITHUB_TOKEN' },
143
+ { type: 'github_token', pattern: /gh(?:p|o|u|s|r)_[A-Za-z0-9]{36,}/g, suggest: 'process.env.GITHUB_TOKEN' },
143
144
  { type: 'github_token', pattern: /github_pat_[A-Za-z0-9_]{22,}/g, suggest: 'process.env.GITHUB_TOKEN' },
144
145
  { type: 'npm_token', pattern: /npm_[A-Za-z0-9]{36,}/g, suggest: 'process.env.NPM_TOKEN' },
145
146
  { type: 'slack_token', pattern: /xox[baprsv]-[A-Za-z0-9-]{10,}/g, suggest: 'process.env.SLACK_TOKEN' },
package/dist/index.d.ts CHANGED
@@ -24,4 +24,5 @@ export * as hub from './hub/index.js';
24
24
  export * as shadow from './shadow/index.js';
25
25
  export * as ops from './ops/index.js';
26
26
  export * as util from './util/index.js';
27
- export * as trace from './trace/index.js';
27
+ export * as trace from './trace/index.js';
28
+ export * as issueReporter from './issueReporter/index.js';
package/dist/index.js CHANGED
@@ -24,4 +24,5 @@ export * as hub from './hub/index.js';
24
24
  export * as shadow from './shadow/index.js';
25
25
  export * as ops from './ops/index.js';
26
26
  export * as util from './util/index.js';
27
- export * as trace from './trace/index.js';
27
+ export * as trace from './trace/index.js';
28
+ export * as issueReporter from './issueReporter/index.js';
@@ -0,0 +1,156 @@
1
+ import { type EnvFingerprint } from '../bootstrap/envFingerprint.js';
2
+ export type IssueReportSource = 'cycle_failure' | 'doctor' | 'review' | 'event';
3
+ export type IssueDraftStatus = 'draft' | 'rejected' | 'submitted';
4
+ export declare function isIssueReportSource(value: unknown): value is IssueReportSource;
5
+ export interface IssueReportInput {
6
+ source: IssueReportSource;
7
+ errorClass: string;
8
+ cycleIds?: readonly string[];
9
+ eventIds?: readonly string[];
10
+ traceIds?: readonly string[];
11
+ reproductionSteps?: readonly string[];
12
+ diagnosticCodes?: readonly string[];
13
+ failureClass?: string;
14
+ version?: string;
15
+ platform?: string;
16
+ arch?: string;
17
+ }
18
+ export interface IssueDraft {
19
+ schemaVersion: 1;
20
+ fingerprint: string;
21
+ status: IssueDraftStatus;
22
+ createdAt: string;
23
+ updatedAt: string;
24
+ title: string;
25
+ body: string;
26
+ source: IssueReportSource;
27
+ errorClass: string;
28
+ cycleIds: string[];
29
+ eventIds: string[];
30
+ traceRefs: string[];
31
+ github?: {
32
+ issueNumber: number;
33
+ url: string;
34
+ };
35
+ }
36
+ export interface IssueReporterOptions {
37
+ rootDir: string;
38
+ workspaceScope?: string;
39
+ now?: () => Date;
40
+ env?: Record<string, string | undefined>;
41
+ envFingerprint?: Partial<EnvFingerprint>;
42
+ dedupWindowMs?: number;
43
+ rateLimitWindowMs?: number;
44
+ maxSubmissionsPerWindow?: number;
45
+ logger?: (entry: IssueReporterLogEntry) => void;
46
+ }
47
+ export interface IssueReporterLogEntry {
48
+ fingerprint: string;
49
+ status: 'draft_created' | 'duplicate' | 'rejected' | 'submitted' | 'submission_failed' | 'rate_limited';
50
+ errorClass?: 'approval_required' | 'rate_limited' | 'transport_error' | 'invalid_response' | 'unsafe_draft' | 'local_finalize_error' | 'quota_persistence_error';
51
+ }
52
+ export interface GithubIssueTransport {
53
+ listOpenIssues(input: {
54
+ repo: string;
55
+ page: number;
56
+ perPage: number;
57
+ }): Promise<{
58
+ issues: Array<{
59
+ number: number;
60
+ url: string;
61
+ body: string;
62
+ isPullRequest: boolean;
63
+ }>;
64
+ hasNextPage: boolean;
65
+ }>;
66
+ createIssue(input: {
67
+ repo: string;
68
+ title: string;
69
+ body: string;
70
+ }): Promise<{
71
+ number: number;
72
+ url: string;
73
+ }>;
74
+ }
75
+ export declare class GithubIssueTransportError extends Error {
76
+ readonly outcome: 'not_created' | 'ambiguous';
77
+ constructor(outcome: 'not_created' | 'ambiguous');
78
+ }
79
+ export interface SubmitIssueOptions {
80
+ repo: string;
81
+ approved: boolean;
82
+ approvalSource?: 'human' | 'operator_policy';
83
+ transport: GithubIssueTransport;
84
+ }
85
+ export type DraftResult = {
86
+ status: 'created';
87
+ draft: IssueDraft;
88
+ } | {
89
+ status: 'duplicate';
90
+ draft: IssueDraft;
91
+ };
92
+ export type SubmitResult = {
93
+ status: 'submitted';
94
+ draft: IssueDraft;
95
+ errorClass?: 'local_finalize_error' | 'quota_persistence_error';
96
+ } | {
97
+ status: 'already_submitted';
98
+ draft: IssueDraft;
99
+ } | {
100
+ status: 'approval_required';
101
+ draft: IssueDraft;
102
+ } | {
103
+ status: 'rejected';
104
+ draft: IssueDraft;
105
+ } | {
106
+ status: 'rate_limited';
107
+ draft: IssueDraft;
108
+ errorClass?: 'issue_report_submission_in_flight' | 'issue_report_submission_ambiguous';
109
+ } | {
110
+ status: 'failed';
111
+ draft: IssueDraft;
112
+ errorClass: 'transport_error' | 'invalid_response' | 'unsafe_draft' | 'local_finalize_error';
113
+ };
114
+ export type IssueDraftConflictErrorClass = 'issue_report_submission_in_flight' | 'issue_report_submission_ambiguous';
115
+ export declare class IssueDraftConflictError extends Error {
116
+ readonly errorClass: IssueDraftConflictErrorClass;
117
+ constructor(errorClass: IssueDraftConflictErrorClass);
118
+ }
119
+ export declare function createIssueDraft(input: IssueReportInput, options: IssueReporterOptions): DraftResult;
120
+ export declare function rejectIssueDraft(draft: IssueDraft, options: IssueReporterOptions): IssueDraft;
121
+ export declare function submitIssueDraft(draft: IssueDraft, submit: SubmitIssueOptions, options: IssueReporterOptions): Promise<SubmitResult>;
122
+ export type IssueDraftLookupResult = {
123
+ status: 'found';
124
+ draft: IssueDraft;
125
+ } | {
126
+ status: 'missing' | 'invalid';
127
+ };
128
+ export declare function lookupIssueDraft(rootDir: string, fingerprint: string): IssueDraftLookupResult;
129
+ export declare function loadIssueDraft(rootDir: string, fingerprint: string): IssueDraft | null;
130
+ export type IssueSubmissionResolution = {
131
+ outcome: 'not_created' | 'abandoned';
132
+ } | {
133
+ outcome: 'submitted';
134
+ issueNumber: number;
135
+ url: string;
136
+ repo: string;
137
+ };
138
+ export declare function resolveIssueSubmission(fingerprint: string, resolution: IssueSubmissionResolution, options: IssueReporterOptions): IssueDraft;
139
+ export interface IssueReportEvent {
140
+ type: string;
141
+ eventId?: string;
142
+ payload?: Record<string, unknown>;
143
+ }
144
+ export interface IssueReportDoctorCheck {
145
+ name: string;
146
+ status: 'pass' | 'warn' | 'fail';
147
+ }
148
+ export interface IssueReportReviewRecord {
149
+ assetId: string;
150
+ state: 'quarantined' | 'approved' | 'rejected';
151
+ }
152
+ export declare function issueReportInputFromCycle(events: readonly IssueReportEvent[], cycleId: string): IssueReportInput | null;
153
+ export declare function issueReportInputFromDoctor(checks: readonly IssueReportDoctorCheck[]): IssueReportInput | null;
154
+ export declare function issueReportInputFromReview(record: IssueReportReviewRecord): IssueReportInput | null;
155
+ export declare function issueReportInputFromEvent(event: IssueReportEvent): IssueReportInput | null;
156
+ export declare function createIssueDraftForEventBestEffort(event: IssueReportEvent, options: IssueReporterOptions): DraftResult | null;