@apexops/kernel 0.10.0-next.0

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 (110) hide show
  1. package/dist/.tsbuildinfo +1 -0
  2. package/dist/benchmark.d.ts +14 -0
  3. package/dist/benchmark.d.ts.map +1 -0
  4. package/dist/benchmark.js +29 -0
  5. package/dist/benchmark.js.map +1 -0
  6. package/dist/canonical.d.ts +10 -0
  7. package/dist/canonical.d.ts.map +1 -0
  8. package/dist/canonical.js +52 -0
  9. package/dist/canonical.js.map +1 -0
  10. package/dist/content-cache.d.ts +18 -0
  11. package/dist/content-cache.d.ts.map +1 -0
  12. package/dist/content-cache.js +94 -0
  13. package/dist/content-cache.js.map +1 -0
  14. package/dist/event-journal.d.ts +20 -0
  15. package/dist/event-journal.d.ts.map +1 -0
  16. package/dist/event-journal.js +136 -0
  17. package/dist/event-journal.js.map +1 -0
  18. package/dist/evidence-store.d.ts +42 -0
  19. package/dist/evidence-store.d.ts.map +1 -0
  20. package/dist/evidence-store.js +151 -0
  21. package/dist/evidence-store.js.map +1 -0
  22. package/dist/files.d.ts +6 -0
  23. package/dist/files.d.ts.map +1 -0
  24. package/dist/files.js +33 -0
  25. package/dist/files.js.map +1 -0
  26. package/dist/gates.d.ts +6 -0
  27. package/dist/gates.d.ts.map +1 -0
  28. package/dist/gates.js +25 -0
  29. package/dist/gates.js.map +1 -0
  30. package/dist/improvement-store.d.ts +48 -0
  31. package/dist/improvement-store.d.ts.map +1 -0
  32. package/dist/improvement-store.js +263 -0
  33. package/dist/improvement-store.js.map +1 -0
  34. package/dist/index.d.ts +18 -0
  35. package/dist/index.d.ts.map +1 -0
  36. package/dist/index.js +18 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/lease-store.d.ts +23 -0
  39. package/dist/lease-store.d.ts.map +1 -0
  40. package/dist/lease-store.js +108 -0
  41. package/dist/lease-store.js.map +1 -0
  42. package/dist/object-store.d.ts +10 -0
  43. package/dist/object-store.d.ts.map +1 -0
  44. package/dist/object-store.js +86 -0
  45. package/dist/object-store.js.map +1 -0
  46. package/dist/project-store.d.ts +30 -0
  47. package/dist/project-store.d.ts.map +1 -0
  48. package/dist/project-store.js +72 -0
  49. package/dist/project-store.js.map +1 -0
  50. package/dist/run-repository.d.ts +38 -0
  51. package/dist/run-repository.d.ts.map +1 -0
  52. package/dist/run-repository.js +151 -0
  53. package/dist/run-repository.js.map +1 -0
  54. package/dist/tasks.d.ts +14 -0
  55. package/dist/tasks.d.ts.map +1 -0
  56. package/dist/tasks.js +96 -0
  57. package/dist/tasks.js.map +1 -0
  58. package/dist/test/canonical.test.d.ts +2 -0
  59. package/dist/test/canonical.test.d.ts.map +1 -0
  60. package/dist/test/canonical.test.js +18 -0
  61. package/dist/test/canonical.test.js.map +1 -0
  62. package/dist/test/improvement-store.test.d.ts +2 -0
  63. package/dist/test/improvement-store.test.d.ts.map +1 -0
  64. package/dist/test/improvement-store.test.js +130 -0
  65. package/dist/test/improvement-store.test.js.map +1 -0
  66. package/dist/test/journal-lease.test.d.ts +2 -0
  67. package/dist/test/journal-lease.test.d.ts.map +1 -0
  68. package/dist/test/journal-lease.test.js +124 -0
  69. package/dist/test/journal-lease.test.js.map +1 -0
  70. package/dist/test/policies.test.d.ts +2 -0
  71. package/dist/test/policies.test.d.ts.map +1 -0
  72. package/dist/test/policies.test.js +115 -0
  73. package/dist/test/policies.test.js.map +1 -0
  74. package/dist/test/run-repository.test.d.ts +2 -0
  75. package/dist/test/run-repository.test.d.ts.map +1 -0
  76. package/dist/test/run-repository.test.js +100 -0
  77. package/dist/test/run-repository.test.js.map +1 -0
  78. package/dist/test/storage.test.d.ts +2 -0
  79. package/dist/test/storage.test.d.ts.map +1 -0
  80. package/dist/test/storage.test.js +41 -0
  81. package/dist/test/storage.test.js.map +1 -0
  82. package/dist/test/workflow-engine.test.d.ts +2 -0
  83. package/dist/test/workflow-engine.test.d.ts.map +1 -0
  84. package/dist/test/workflow-engine.test.js +108 -0
  85. package/dist/test/workflow-engine.test.js.map +1 -0
  86. package/dist/test/workflow.test.d.ts +2 -0
  87. package/dist/test/workflow.test.d.ts.map +1 -0
  88. package/dist/test/workflow.test.js +119 -0
  89. package/dist/test/workflow.test.js.map +1 -0
  90. package/dist/test/writer-transfer.test.d.ts +2 -0
  91. package/dist/test/writer-transfer.test.d.ts.map +1 -0
  92. package/dist/test/writer-transfer.test.js +355 -0
  93. package/dist/test/writer-transfer.test.js.map +1 -0
  94. package/dist/validator-registry.d.ts +22 -0
  95. package/dist/validator-registry.d.ts.map +1 -0
  96. package/dist/validator-registry.js +42 -0
  97. package/dist/validator-registry.js.map +1 -0
  98. package/dist/workflow-engine.d.ts +72 -0
  99. package/dist/workflow-engine.d.ts.map +1 -0
  100. package/dist/workflow-engine.js +269 -0
  101. package/dist/workflow-engine.js.map +1 -0
  102. package/dist/workflow-validator-ownership.d.ts +12 -0
  103. package/dist/workflow-validator-ownership.d.ts.map +1 -0
  104. package/dist/workflow-validator-ownership.js +163 -0
  105. package/dist/workflow-validator-ownership.js.map +1 -0
  106. package/dist/writer-transfer.d.ts +78 -0
  107. package/dist/writer-transfer.d.ts.map +1 -0
  108. package/dist/writer-transfer.js +313 -0
  109. package/dist/writer-transfer.js.map +1 -0
  110. package/package.json +39 -0
@@ -0,0 +1,48 @@
1
+ import { type ImprovementCategory, type ImprovementDecisionV1, type ImprovementObservationV1, type ImprovementPolicyV1, type ImprovementProposalV1, type ImprovementRecurrenceV1, type ImprovementSource } from "@apexops/contracts";
2
+ export interface ImprovementObservationInput {
3
+ projectId: string;
4
+ runId: string;
5
+ taskId?: string;
6
+ observedAt?: string;
7
+ source: ImprovementSource;
8
+ category: ImprovementCategory;
9
+ severity: ImprovementObservationV1["severity"];
10
+ statement: string;
11
+ evidenceRefs: string[];
12
+ }
13
+ export interface ImprovementDecisionInput {
14
+ projectId: string;
15
+ proposalId: string;
16
+ actor: string;
17
+ decision: ImprovementDecisionV1["decision"];
18
+ rationale: string;
19
+ externalRef?: string;
20
+ }
21
+ export declare class ImprovementStore {
22
+ readonly policy: ImprovementPolicyV1;
23
+ private readonly clock;
24
+ private readonly root;
25
+ private readonly observationsRoot;
26
+ private readonly proposalsRoot;
27
+ private readonly decisionsRoot;
28
+ constructor(projectRoot: string, policy: ImprovementPolicyV1, clock?: () => Date);
29
+ observe(input: ImprovementObservationInput): Promise<{
30
+ observation: ImprovementObservationV1;
31
+ deduplicated: boolean;
32
+ }>;
33
+ listObservations(): Promise<ImprovementObservationV1[]>;
34
+ scan(projectId: string): Promise<{
35
+ recurrences: ImprovementRecurrenceV1[];
36
+ proposals: ImprovementProposalV1[];
37
+ }>;
38
+ listProposals(projectId?: string): Promise<ImprovementProposalV1[]>;
39
+ decide(input: ImprovementDecisionInput): Promise<ImprovementDecisionV1>;
40
+ listDecisions(): Promise<ImprovementDecisionV1[]>;
41
+ deleteObservation(observationId: string): Promise<void>;
42
+ prune(): Promise<{
43
+ observations: number;
44
+ decisions: number;
45
+ }>;
46
+ private withDecisionStatus;
47
+ }
48
+ //# sourceMappingURL=improvement-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"improvement-store.d.ts","sourceRoot":"","sources":["../src/improvement-store.ts"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC1B,KAAK,wBAAwB,EAC7B,KAAK,mBAAmB,EACxB,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC5B,KAAK,iBAAiB,EAGvB,MAAM,oBAAoB,CAAC;AAgB5B,MAAM,WAAW,2BAA2B;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,QAAQ,EAAE,wBAAwB,CAAC,UAAU,CAAC,CAAC;IAC/C,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,qBAAqB,CAAC,UAAU,CAAC,CAAC;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAgDD,qBAAa,gBAAgB;IAQzB,QAAQ,CAAC,MAAM,EAAE,mBAAmB;IACpC,OAAO,CAAC,QAAQ,CAAC,KAAK;IARxB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IAEvC,YACE,WAAW,EAAE,MAAM,EACV,MAAM,EAAE,mBAAmB,EACnB,KAAK,GAAE,MAAM,IAAuB,EAQtD;IAEK,OAAO,CACX,KAAK,EAAE,2BAA2B,GACjC,OAAO,CAAC;QAAE,WAAW,EAAE,wBAAwB,CAAC;QAAC,YAAY,EAAE,OAAO,CAAA;KAAE,CAAC,CA4D3E;IAEK,gBAAgB,IAAI,OAAO,CAAC,wBAAwB,EAAE,CAAC,CAE5D;IAEK,IAAI,CACR,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;QAAE,WAAW,EAAE,uBAAuB,EAAE,CAAC;QAAC,SAAS,EAAE,qBAAqB,EAAE,CAAA;KAAE,CAAC,CAyDzF;IAEK,aAAa,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAKxE;IAEK,MAAM,CAAC,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAsB5E;IAEK,aAAa,IAAI,OAAO,CAAC,qBAAqB,EAAE,CAAC,CAEtD;IAEK,iBAAiB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG5D;IAEK,KAAK,IAAI,OAAO,CAAC;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAiBlE;YAEa,kBAAkB;CAIjC"}
@@ -0,0 +1,263 @@
1
+ import { readdir, readFile, rm } from "node:fs/promises";
2
+ import { join, resolve } from "node:path";
3
+ import { ImprovementDecisionV1Schema, ImprovementObservationV1Schema, ImprovementPolicyV1Schema, ImprovementProposalV1Schema, registerContractFormats, } from "@apexops/contracts";
4
+ import { Value } from "@sinclair/typebox/value";
5
+ import { sha256Json } from "./canonical.js";
6
+ import { atomicWriteJson } from "./files.js";
7
+ const INJECTION = [
8
+ /ignore (?:all|any|the) previous instructions/i,
9
+ /(?:system|developer) prompt/i,
10
+ /(?:call|invoke|execute|run) (?:the )?(?:tool|command)/i,
11
+ /(?:approve|deploy|publish|merge|create a pull request) (?:this|it|now)/i,
12
+ /<\/?(?:system|assistant|tool|developer)>/i,
13
+ ];
14
+ const SECRET_VALUE = /-----BEGIN (?:RSA |EC |OPENSSH )?PRIVATE KEY-----|\bBearer\s+[A-Za-z0-9._~+\/-]{16,}|(?:AccountKey|SharedAccessSignature)=|\b(?:secret|password|token|api[-_]?key)\s*[:=]\s*\S+/gi;
15
+ const EMAIL = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi;
16
+ async function readJson(path) {
17
+ try {
18
+ return JSON.parse(await readFile(path, "utf8"));
19
+ }
20
+ catch (error) {
21
+ if (error.code === "ENOENT")
22
+ return undefined;
23
+ throw error;
24
+ }
25
+ }
26
+ async function readDirectory(directory) {
27
+ try {
28
+ const names = (await readdir(directory)).filter((name) => name.endsWith(".json")).sort();
29
+ return await Promise.all(names.map(async (name) => JSON.parse(await readFile(join(directory, name), "utf8"))));
30
+ }
31
+ catch (error) {
32
+ if (error.code === "ENOENT")
33
+ return [];
34
+ throw error;
35
+ }
36
+ }
37
+ function sanitizedStatement(statement, maximum) {
38
+ if (statement.length === 0 || statement.length > maximum) {
39
+ throw new Error(`Observation statement must contain 1-${maximum} characters`);
40
+ }
41
+ let redactionCount = 0;
42
+ const redact = () => {
43
+ redactionCount += 1;
44
+ return "[REDACTED]";
45
+ };
46
+ const value = statement.replace(SECRET_VALUE, redact).replace(EMAIL, redact).trim();
47
+ if (value.length === 0)
48
+ throw new Error("Observation statement is empty after redaction");
49
+ return { statement: value, redactionCount };
50
+ }
51
+ function targetFor(category, allowed) {
52
+ const preferred = {
53
+ correctness: "validator",
54
+ security: "validator",
55
+ reliability: "architecture",
56
+ performance: "architecture",
57
+ usability: "documentation",
58
+ documentation: "documentation",
59
+ "capability-gap": "backlog",
60
+ };
61
+ return allowed.includes(preferred[category]) ? preferred[category] : allowed[0];
62
+ }
63
+ export class ImprovementStore {
64
+ policy;
65
+ clock;
66
+ root;
67
+ observationsRoot;
68
+ proposalsRoot;
69
+ decisionsRoot;
70
+ constructor(projectRoot, policy, clock = () => new Date()) {
71
+ this.policy = policy;
72
+ this.clock = clock;
73
+ registerContractFormats();
74
+ if (!Value.Check(ImprovementPolicyV1Schema, policy))
75
+ throw new Error("Improvement policy is invalid");
76
+ this.root = resolve(projectRoot, ".apex", "quality", "improvement");
77
+ this.observationsRoot = join(this.root, "observations");
78
+ this.proposalsRoot = join(this.root, "proposals");
79
+ this.decisionsRoot = join(this.root, "decisions");
80
+ }
81
+ async observe(input) {
82
+ if (!this.policy.allowedSources.includes(input.source))
83
+ throw new Error(`Observation source is not allowed: ${input.source}`);
84
+ if (!this.policy.allowedCategories.includes(input.category)) {
85
+ throw new Error(`Observation category is not allowed: ${input.category}`);
86
+ }
87
+ if (input.evidenceRefs.length < 1 || input.evidenceRefs.length > this.policy.limits.evidenceRefs) {
88
+ throw new Error("Observation evidence reference count is outside policy");
89
+ }
90
+ if (new Set(input.evidenceRefs).size !== input.evidenceRefs.length ||
91
+ input.evidenceRefs.some((hash) => !/^[0-9a-f]{64}$/.test(hash))) {
92
+ throw new Error("Observation evidence references must be unique SHA-256 hashes");
93
+ }
94
+ const redacted = sanitizedStatement(input.statement, this.policy.limits.statementCharacters);
95
+ const observedAt = input.observedAt ?? this.clock().toISOString();
96
+ const observedTime = Date.parse(observedAt);
97
+ if (!Number.isFinite(observedTime) || new Date(observedTime).toISOString() !== observedAt) {
98
+ throw new Error("Observation timestamp must be canonical ISO-8601");
99
+ }
100
+ if (observedTime > this.clock().getTime())
101
+ throw new Error("Observation timestamp cannot be in the future");
102
+ const disposition = INJECTION.some((pattern) => pattern.test(redacted.statement)) ? "quarantined" : "active";
103
+ const patternKey = sha256Json({ category: input.category, statement: redacted.statement.toLowerCase() });
104
+ const observationId = sha256Json({
105
+ projectId: input.projectId,
106
+ runId: input.runId,
107
+ taskId: input.taskId ?? null,
108
+ source: input.source,
109
+ category: input.category,
110
+ severity: input.severity,
111
+ statement: redacted.statement,
112
+ evidenceRefs: [...input.evidenceRefs].sort(),
113
+ });
114
+ const path = join(this.observationsRoot, `${observationId}.json`);
115
+ const existing = await readJson(path);
116
+ if (existing !== undefined)
117
+ return { observation: existing, deduplicated: true };
118
+ const observations = await this.listObservations();
119
+ if (observations.length >= this.policy.limits.observations)
120
+ throw new Error("Improvement observation limit reached");
121
+ const observation = {
122
+ schemaVersion: "1.0.0",
123
+ projectId: input.projectId,
124
+ runId: input.runId,
125
+ ...(input.taskId === undefined ? {} : { taskId: input.taskId }),
126
+ observationId,
127
+ patternKey,
128
+ observedAt,
129
+ source: input.source,
130
+ category: input.category,
131
+ severity: input.severity,
132
+ statement: redacted.statement,
133
+ evidenceRefs: [...input.evidenceRefs].sort(),
134
+ disposition,
135
+ redactionCount: redacted.redactionCount,
136
+ };
137
+ if (!Value.Check(ImprovementObservationV1Schema, observation))
138
+ throw new Error("Improvement observation is invalid");
139
+ await atomicWriteJson(path, observation, { refuseOverwrite: true });
140
+ return { observation, deduplicated: false };
141
+ }
142
+ async listObservations() {
143
+ return await readDirectory(this.observationsRoot);
144
+ }
145
+ async scan(projectId) {
146
+ const now = this.clock();
147
+ const cutoff = now.getTime() - this.policy.recurrence.windowDays * 86_400_000;
148
+ const observations = (await this.listObservations()).filter((item) => item.projectId === projectId && item.disposition === "active" && Date.parse(item.observedAt) >= cutoff);
149
+ const groups = Map.groupBy(observations, (item) => item.patternKey);
150
+ const recurrences = [];
151
+ const proposals = [];
152
+ for (const [patternKey, items] of [...groups.entries()].sort(([left], [right]) => left.localeCompare(right))) {
153
+ const runIds = [...new Set(items.map(({ runId }) => runId))].sort();
154
+ if (runIds.length < this.policy.recurrence.threshold)
155
+ continue;
156
+ const ordered = [...items].sort((left, right) => left.observedAt.localeCompare(right.observedAt));
157
+ const evidenceRefs = [...new Set(items.flatMap(({ evidenceRefs: refs }) => refs))].sort();
158
+ const recurrence = {
159
+ schemaVersion: "1.0.0",
160
+ projectId,
161
+ patternKey,
162
+ category: ordered[0].category,
163
+ detectedAt: now.toISOString(),
164
+ firstSeenAt: ordered[0].observedAt,
165
+ lastSeenAt: ordered.at(-1).observedAt,
166
+ occurrenceCount: items.length,
167
+ distinctRunCount: runIds.length,
168
+ runIds,
169
+ observationIds: ordered.map(({ observationId }) => observationId).sort(),
170
+ evidenceRefs,
171
+ confidence: runIds.length >= this.policy.recurrence.threshold + 2 ? "high" : "medium",
172
+ };
173
+ recurrences.push(recurrence);
174
+ const target = targetFor(recurrence.category, this.policy.proposalTargets);
175
+ const proposalId = sha256Json({ projectId, patternKey, target });
176
+ const path = join(this.proposalsRoot, `${proposalId}.json`);
177
+ let proposal = await readJson(path);
178
+ if (proposal === undefined) {
179
+ proposal = {
180
+ schemaVersion: "1.0.0",
181
+ projectId,
182
+ proposalId,
183
+ patternKey,
184
+ generatedAt: now.toISOString(),
185
+ target,
186
+ title: `Review recurring ${recurrence.category} observation`,
187
+ summary: `Review ${recurrence.occurrenceCount} redacted observations across ${recurrence.distinctRunCount} distinct runs through the normal human change workflow.`,
188
+ occurrenceCount: recurrence.occurrenceCount,
189
+ runIds,
190
+ evidenceRefs,
191
+ confidence: recurrence.confidence,
192
+ status: "pending",
193
+ inert: true,
194
+ };
195
+ if (!Value.Check(ImprovementProposalV1Schema, proposal))
196
+ throw new Error("Improvement proposal is invalid");
197
+ await atomicWriteJson(path, proposal, { refuseOverwrite: true });
198
+ }
199
+ proposals.push(await this.withDecisionStatus(proposal));
200
+ }
201
+ return { recurrences, proposals };
202
+ }
203
+ async listProposals(projectId) {
204
+ const proposals = await readDirectory(this.proposalsRoot);
205
+ const selected = projectId === undefined ? proposals : proposals.filter((proposal) => proposal.projectId === projectId);
206
+ return await Promise.all(selected.map(async (proposal) => await this.withDecisionStatus(proposal)));
207
+ }
208
+ async decide(input) {
209
+ const proposalPath = join(this.proposalsRoot, `${input.proposalId}.json`);
210
+ const proposal = await readJson(proposalPath);
211
+ if (proposal === undefined || proposal.projectId !== input.projectId)
212
+ throw new Error("Improvement proposal not found");
213
+ const decisionPath = join(this.decisionsRoot, `${input.proposalId}.json`);
214
+ if ((await readJson(decisionPath)) !== undefined) {
215
+ throw new Error("Improvement proposal already has a human decision");
216
+ }
217
+ const decision = {
218
+ schemaVersion: "1.0.0",
219
+ projectId: input.projectId,
220
+ proposalId: input.proposalId,
221
+ decidedAt: this.clock().toISOString(),
222
+ actor: input.actor,
223
+ decision: input.decision,
224
+ rationale: input.rationale,
225
+ ...(input.externalRef === undefined ? {} : { externalRef: input.externalRef }),
226
+ };
227
+ if (!Value.Check(ImprovementDecisionV1Schema, decision))
228
+ throw new Error("Improvement decision is invalid");
229
+ await atomicWriteJson(decisionPath, decision, { refuseOverwrite: true });
230
+ return decision;
231
+ }
232
+ async listDecisions() {
233
+ return await readDirectory(this.decisionsRoot);
234
+ }
235
+ async deleteObservation(observationId) {
236
+ if (!/^[0-9a-f]{64}$/.test(observationId))
237
+ throw new Error("Observation ID must be a SHA-256 hash");
238
+ await rm(join(this.observationsRoot, `${observationId}.json`), { force: true });
239
+ }
240
+ async prune() {
241
+ const now = this.clock().getTime();
242
+ let observationCount = 0;
243
+ for (const observation of await this.listObservations()) {
244
+ if (Date.parse(observation.observedAt) < now - this.policy.retention.observationDays * 86_400_000) {
245
+ await this.deleteObservation(observation.observationId);
246
+ observationCount += 1;
247
+ }
248
+ }
249
+ let decisionCount = 0;
250
+ for (const decision of await this.listDecisions()) {
251
+ if (Date.parse(decision.decidedAt) < now - this.policy.retention.decisionDays * 86_400_000) {
252
+ await rm(join(this.decisionsRoot, `${decision.proposalId}.json`), { force: true });
253
+ decisionCount += 1;
254
+ }
255
+ }
256
+ return { observations: observationCount, decisions: decisionCount };
257
+ }
258
+ async withDecisionStatus(proposal) {
259
+ const decision = await readJson(join(this.decisionsRoot, `${proposal.proposalId}.json`));
260
+ return decision === undefined ? proposal : { ...proposal, status: decision.decision };
261
+ }
262
+ }
263
+ //# sourceMappingURL=improvement-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"improvement-store.js","sourceRoot":"","sources":["../src/improvement-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ export * from "./canonical.js";
2
+ export * from "./benchmark.js";
3
+ export * from "./content-cache.js";
4
+ export * from "./evidence-store.js";
5
+ export * from "./event-journal.js";
6
+ export * from "./files.js";
7
+ export * from "./gates.js";
8
+ export * from "./improvement-store.js";
9
+ export * from "./lease-store.js";
10
+ export * from "./object-store.js";
11
+ export * from "./project-store.js";
12
+ export * from "./run-repository.js";
13
+ export * from "./tasks.js";
14
+ export * from "./validator-registry.js";
15
+ export * from "./workflow-engine.js";
16
+ export * from "./workflow-validator-ownership.js";
17
+ export * from "./writer-transfer.js";
18
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,wBAAwB,CAAC;AACvC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,YAAY,CAAC;AAC3B,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mCAAmC,CAAC;AAClD,cAAc,sBAAsB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,18 @@
1
+ export * from "./canonical.js";
2
+ export * from "./benchmark.js";
3
+ export * from "./content-cache.js";
4
+ export * from "./evidence-store.js";
5
+ export * from "./event-journal.js";
6
+ export * from "./files.js";
7
+ export * from "./gates.js";
8
+ export * from "./improvement-store.js";
9
+ export * from "./lease-store.js";
10
+ export * from "./object-store.js";
11
+ export * from "./project-store.js";
12
+ export * from "./run-repository.js";
13
+ export * from "./tasks.js";
14
+ export * from "./validator-registry.js";
15
+ export * from "./workflow-engine.js";
16
+ export * from "./workflow-validator-ownership.js";
17
+ export * from "./writer-transfer.js";
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,wBAAwB,CAAC;AACvC,cAAc,kBAAkB,CAAC;AACjC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC;AACpC,cAAc,YAAY,CAAC;AAC3B,cAAc,yBAAyB,CAAC;AACxC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mCAAmC,CAAC;AAClD,cAAc,sBAAsB,CAAC"}
@@ -0,0 +1,23 @@
1
+ export interface LeaseRecord {
2
+ ownerId: string;
3
+ ownerEpoch: number;
4
+ acquiredAt: string;
5
+ expiresAt: string;
6
+ }
7
+ export type Clock = () => Date;
8
+ export declare class LeaseStore {
9
+ private readonly clock;
10
+ private readonly lockPath;
11
+ private readonly path;
12
+ constructor(path: string, clock?: Clock);
13
+ acquire(ownerId: string, ttlMs: number): Promise<LeaseRecord>;
14
+ acquireAtEpoch(ownerId: string, ownerEpoch: number, ttlMs: number): Promise<LeaseRecord>;
15
+ heartbeat(ownerId: string, ownerEpoch: number, ttlMs: number): Promise<LeaseRecord>;
16
+ release(ownerId: string, ownerEpoch: number): Promise<void>;
17
+ current(): Promise<LeaseRecord | null>;
18
+ private createLease;
19
+ private requireCurrent;
20
+ private read;
21
+ private withLock;
22
+ }
23
+ //# sourceMappingURL=lease-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lease-store.d.ts","sourceRoot":"","sources":["../src/lease-store.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC;AAE/B,qBAAa,UAAU;IAMnB,OAAO,CAAC,QAAQ,CAAC,KAAK;IALxB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAE9B,YACE,IAAI,EAAE,MAAM,EACK,KAAK,GAAE,KAAwB,EAIjD;IAEK,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAWlE;IAEK,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAa7F;IAEK,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAOxF;IAEK,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAKhE;IAEK,OAAO,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAG3C;IAED,OAAO,CAAC,WAAW;YAaL,cAAc;YAWd,IAAI;YAWJ,QAAQ;CAkBvB"}
@@ -0,0 +1,108 @@
1
+ import { constants } from "node:fs";
2
+ import { mkdir, open, readFile, rm } from "node:fs/promises";
3
+ import { dirname, resolve } from "node:path";
4
+ import { atomicWriteJson } from "./files.js";
5
+ export class LeaseStore {
6
+ clock;
7
+ lockPath;
8
+ path;
9
+ constructor(path, clock = () => new Date()) {
10
+ this.clock = clock;
11
+ this.path = resolve(path);
12
+ this.lockPath = `${this.path}.lock`;
13
+ }
14
+ async acquire(ownerId, ttlMs) {
15
+ return this.withLock(async () => {
16
+ const previous = await this.read();
17
+ const now = this.clock();
18
+ if (previous !== null && Date.parse(previous.expiresAt) > now.getTime()) {
19
+ throw new Error(`Lease is held by ${previous.ownerId}`);
20
+ }
21
+ const lease = this.createLease(ownerId, (previous?.ownerEpoch ?? 0) + 1, ttlMs, now);
22
+ await atomicWriteJson(this.path, lease);
23
+ return lease;
24
+ });
25
+ }
26
+ async acquireAtEpoch(ownerId, ownerEpoch, ttlMs) {
27
+ return this.withLock(async () => {
28
+ const previous = await this.read();
29
+ const now = this.clock();
30
+ if (previous !== null && Date.parse(previous.expiresAt) > now.getTime()) {
31
+ throw new Error(`Lease is held by ${previous.ownerId}`);
32
+ }
33
+ if (!Number.isInteger(ownerEpoch) || ownerEpoch < 1)
34
+ throw new Error("Lease owner epoch must be positive");
35
+ if (previous !== null && previous.ownerEpoch > ownerEpoch)
36
+ throw new Error("Lease owner epoch cannot regress");
37
+ const lease = this.createLease(ownerId, ownerEpoch, ttlMs, now);
38
+ await atomicWriteJson(this.path, lease);
39
+ return lease;
40
+ });
41
+ }
42
+ async heartbeat(ownerId, ownerEpoch, ttlMs) {
43
+ return this.withLock(async () => {
44
+ const current = await this.requireCurrent(ownerId, ownerEpoch);
45
+ const lease = this.createLease(ownerId, current.ownerEpoch, ttlMs, this.clock(), current.acquiredAt);
46
+ await atomicWriteJson(this.path, lease);
47
+ return lease;
48
+ });
49
+ }
50
+ async release(ownerId, ownerEpoch) {
51
+ await this.withLock(async () => {
52
+ const current = await this.requireCurrent(ownerId, ownerEpoch);
53
+ await atomicWriteJson(this.path, { ...current, expiresAt: this.clock().toISOString() });
54
+ });
55
+ }
56
+ async current() {
57
+ const lease = await this.read();
58
+ return lease !== null && Date.parse(lease.expiresAt) > this.clock().getTime() ? lease : null;
59
+ }
60
+ createLease(ownerId, ownerEpoch, ttlMs, now, acquiredAt = now.toISOString()) {
61
+ if (!ownerId || !Number.isFinite(ttlMs) || ttlMs <= 0) {
62
+ throw new Error("Lease owner and positive TTL are required");
63
+ }
64
+ return { ownerId, ownerEpoch, acquiredAt, expiresAt: new Date(now.getTime() + ttlMs).toISOString() };
65
+ }
66
+ async requireCurrent(ownerId, ownerEpoch) {
67
+ const current = await this.read();
68
+ if (current === null || Date.parse(current.expiresAt) <= this.clock().getTime()) {
69
+ throw new Error("Lease has expired");
70
+ }
71
+ if (current.ownerId !== ownerId || current.ownerEpoch !== ownerEpoch) {
72
+ throw new Error("Stale lease owner or epoch");
73
+ }
74
+ return current;
75
+ }
76
+ async read() {
77
+ try {
78
+ return JSON.parse(await readFile(this.path, "utf8"));
79
+ }
80
+ catch (error) {
81
+ if (error.code === "ENOENT") {
82
+ return null;
83
+ }
84
+ throw error;
85
+ }
86
+ }
87
+ async withLock(operation) {
88
+ await mkdir(dirname(this.path), { recursive: true });
89
+ let handle;
90
+ try {
91
+ handle = await open(this.lockPath, constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY, 0o600);
92
+ }
93
+ catch (error) {
94
+ if (error.code === "EEXIST") {
95
+ throw new Error("Lease update is already in progress", { cause: error });
96
+ }
97
+ throw error;
98
+ }
99
+ try {
100
+ return await operation();
101
+ }
102
+ finally {
103
+ await handle.close();
104
+ await rm(this.lockPath, { force: true });
105
+ }
106
+ }
107
+ }
108
+ //# sourceMappingURL=lease-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lease-store.js","sourceRoot":"","sources":["../src/lease-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export declare class ObjectStore {
2
+ readonly root: string;
3
+ constructor(projectRoot: string);
4
+ putBytes(bytes: Uint8Array): Promise<string>;
5
+ putJson(value: unknown): Promise<string>;
6
+ getBytes(hash: string): Promise<Buffer>;
7
+ getJson<T>(hash: string): Promise<T>;
8
+ private pathFor;
9
+ }
10
+ //# sourceMappingURL=object-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"object-store.d.ts","sourceRoot":"","sources":["../src/object-store.ts"],"names":[],"mappings":"AAQA,qBAAa,WAAW;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,YAAY,WAAW,EAAE,MAAM,EAE9B;IAEK,QAAQ,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAejD;IAEK,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAE7C;IAEK,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAa5C;IAEK,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAEzC;YAEa,OAAO;CAkCtB"}
@@ -0,0 +1,86 @@
1
+ import { constants } from "node:fs";
2
+ import { lstat, mkdir, open, realpath } from "node:fs/promises";
3
+ import { dirname, join, relative, resolve } from "node:path";
4
+ import { canonicalJsonBytes, sha256Bytes } from "./canonical.js";
5
+ import { atomicWriteBytes } from "./files.js";
6
+ const HASH_PATTERN = /^[0-9a-f]{64}$/;
7
+ export class ObjectStore {
8
+ root;
9
+ constructor(projectRoot) {
10
+ this.root = resolve(projectRoot, ".apex", "objects", "sha256");
11
+ }
12
+ async putBytes(bytes) {
13
+ const hash = sha256Bytes(bytes);
14
+ const path = await this.pathFor(hash, true);
15
+ try {
16
+ await atomicWriteBytes(path, bytes, { refuseOverwrite: true });
17
+ }
18
+ catch (error) {
19
+ if (error.code !== "EEXIST") {
20
+ throw error;
21
+ }
22
+ }
23
+ const stored = await this.getBytes(hash);
24
+ if (!Buffer.from(stored).equals(Buffer.from(bytes))) {
25
+ throw new Error(`Object ${hash} is not immutable`);
26
+ }
27
+ return hash;
28
+ }
29
+ async putJson(value) {
30
+ return this.putBytes(canonicalJsonBytes(value));
31
+ }
32
+ async getBytes(hash) {
33
+ const path = await this.pathFor(hash, false);
34
+ const handle = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
35
+ let bytes;
36
+ try {
37
+ bytes = await handle.readFile();
38
+ }
39
+ finally {
40
+ await handle.close();
41
+ }
42
+ if (sha256Bytes(bytes) !== hash) {
43
+ throw new Error(`Object hash verification failed for ${hash}`);
44
+ }
45
+ return bytes;
46
+ }
47
+ async getJson(hash) {
48
+ return JSON.parse((await this.getBytes(hash)).toString("utf8"));
49
+ }
50
+ async pathFor(hash, create) {
51
+ if (!HASH_PATTERN.test(hash)) {
52
+ throw new Error("Invalid SHA-256 object identifier");
53
+ }
54
+ if (create) {
55
+ await mkdir(this.root, { recursive: true });
56
+ }
57
+ const root = await realpath(this.root);
58
+ if (root !== this.root) {
59
+ throw new Error("Object store root must not be a symlink");
60
+ }
61
+ const path = join(root, hash.slice(0, 2), hash.slice(2));
62
+ if (create) {
63
+ await mkdir(dirname(path), { recursive: true });
64
+ }
65
+ const parent = await realpath(dirname(path));
66
+ const relation = relative(root, parent);
67
+ if (relation.startsWith("..") || resolve(parent, hash.slice(2)) !== resolve(path)) {
68
+ throw new Error("Object path escapes the store");
69
+ }
70
+ try {
71
+ const stat = await lstat(path);
72
+ if (stat.isSymbolicLink() || !stat.isFile()) {
73
+ throw new Error("Object path must be a regular file");
74
+ }
75
+ const handle = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
76
+ await handle.close();
77
+ }
78
+ catch (error) {
79
+ if (error.code !== "ENOENT") {
80
+ throw error;
81
+ }
82
+ }
83
+ return path;
84
+ }
85
+ }
86
+ //# sourceMappingURL=object-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"object-store.js","sourceRoot":"","sources":["../src/object-store.ts"],"names":[],"mappings":"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"}