@compforge/harness-common 0.5.1 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -27,6 +27,21 @@ view during initialize, so concurrent consumers share them and dispose before th
27
27
  Dependency graphs must be acyclic. A failed initialization permits retry only after successful cleanup;
28
28
  failed cleanup poisons that key and is reported again when the root manager is disposed.
29
29
 
30
+ `FileDataSource` declares a nonempty group of distinct `paths` that can be acquired together.
31
+ `FileClient.read` obtains the whole group once and returns one `FileReadResult` per declared path,
32
+ in order: `{ path, status: "ok", bytes }` or `{ path, status: "error", error }`. Empty files succeed;
33
+ missing and oversized files keep independent errors without discarding successful siblings.
34
+
35
+ Callers specify `maxBytes` per file, `maxTotalBytes` for all retained bytes (including in-progress
36
+ files), `timeoutMs` for the complete operation including queueing, and optional cancellation.
37
+ Cancellation, total-budget exhaustion, the group deadline and transport/protocol failures reject
38
+ the whole operation. Every read observes fresh bytes; a co-acquisition group is not an atomic
39
+ filesystem snapshot. Parsing, configuration precedence and persistence belong to consumers.
40
+ Platform implementations live in `@compforge/harness-toolbox/file`.
41
+
42
+ Version 0.5.4 replaces the single `path` and byte-only return value; single-file consumers declare
43
+ `paths: [path]` and consume the sole per-file result. There is no implicit legacy adapter.
44
+
30
45
  Service identifies a Component's runtime presence in an Environment. A Component belongs to a Repository
31
46
  on a Forge. Product is a separate business identity; consumers own its many-to-many associations
32
47
  with Components. Repository discovery and directory ownership remain consumer responsibilities.
@@ -35,7 +50,7 @@ capabilities, without duplicating these identities. For example:
35
50
 
36
51
  ```typescript
37
52
  import {
38
- conceptToMarkdown, knowledgeToMarkdown, stepToMarkdown, workflowToMarkdown,
53
+ repositoryId, conceptToMarkdown, knowledgeToMarkdown, stepToMarkdown, workflowToMarkdown,
39
54
  type Service,
40
55
  } from "@compforge/harness-common";
41
56
 
@@ -53,7 +68,7 @@ const service: Service = {
53
68
  upstream: ["gateway"],
54
69
  component: {
55
70
  name: "api",
56
- repository: { forge: { name: "github" }, path: "example/app" },
71
+ repository: { forge: { name: "github" }, path: "example/app", id() { return repositoryId(this); } },
57
72
  },
58
73
  environment: { name: "test" },
59
74
  workloads: [{
@@ -63,6 +78,10 @@ const service: Service = {
63
78
  };
64
79
  ```
65
80
 
81
+ Repository extends Identity: `id()` returns `forge.name/path`, excluding `forkedFrom`.
82
+ Use `repositoryId(this)` when implementing the method, including when restoring a Repository
83
+ from JSON; methods are not serialized.
84
+
66
85
  Service and Product accept an optional description for a short introduction, and structured
67
86
  `knowledge` for concepts, workflows, articles and dictionaries. Service knowledge covers its own
68
87
  responsibilities, while Product knowledge covers end-to-end flows. Consumers maintain this offline
package/dist/file.d.ts ADDED
@@ -0,0 +1,42 @@
1
+ import type { Client } from "./client.js";
2
+ import type { ClientManager } from "./client-manager.js";
3
+ import type { DataSource } from "./datasource.js";
4
+ export interface FileReadOptions {
5
+ /** Maximum complete size of each file; an oversized file returns an error without partial bytes. */
6
+ maxBytes: number;
7
+ /** Maximum bytes retained across the whole read, including in-progress files. */
8
+ maxTotalBytes: number;
9
+ /** One deadline for queueing and acquiring the complete group. */
10
+ timeoutMs: number;
11
+ signal?: AbortSignal;
12
+ }
13
+ export type FileReadResult = {
14
+ readonly path: string;
15
+ readonly status: "ok";
16
+ readonly bytes: Uint8Array;
17
+ } | {
18
+ readonly path: string;
19
+ readonly status: "error";
20
+ readonly error: Error;
21
+ };
22
+ /**
23
+ * @spec Each read acquires the declared group once and returns one result per path, in declaration order.
24
+ * Individual file failures do not discard other files; cancellation, the group deadline, total budget
25
+ * and transport/protocol failures reject the operation. Every read obtains fresh bytes.
26
+ * @rule Group acquisition is not an atomic filesystem snapshot. Parsing and evidence belong to consumers.
27
+ */
28
+ export interface FileClient extends Client {
29
+ read(options: FileReadOptions): Promise<readonly FileReadResult[]>;
30
+ }
31
+ /**
32
+ * A nonempty group of distinct paths that the caller declares can be acquired together.
33
+ * @why The source is the acquisition unit; grouping does not require consumers to guess transport capabilities.
34
+ * @rule clientKey identifies access and the group, not cached contents or a Service-owned alias.
35
+ * @see {@link component://../../../docs/toolbox.md}
36
+ */
37
+ export declare abstract class FileDataSource<C extends FileClient = FileClient> implements DataSource<C> {
38
+ abstract readonly paths: readonly string[];
39
+ readonly description?: string;
40
+ abstract readonly clientKey: string;
41
+ abstract createClient(clients: Pick<ClientManager, "get">, signal: AbortSignal): C;
42
+ }
package/dist/file.js ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * A nonempty group of distinct paths that the caller declares can be acquired together.
3
+ * @why The source is the acquisition unit; grouping does not require consumers to guess transport capabilities.
4
+ * @rule clientKey identifies access and the group, not cached contents or a Service-owned alias.
5
+ * @see {@link component://../../../docs/toolbox.md}
6
+ */
7
+ export class FileDataSource {
8
+ description;
9
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * An object referenced by a string identifier; the model owns its format and uniqueness scope.
3
+ * @spec The same business identity yields the same identifier; descriptive metadata is excluded.
4
+ */
5
+ export interface Identity {
6
+ id(): string;
7
+ }
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.d.ts CHANGED
@@ -13,3 +13,5 @@ export * from "./service.js";
13
13
  export * from "./execution.js";
14
14
  export type { Product } from "./product.js";
15
15
  export * from "./knowledge.js";
16
+ export type { Identity } from "./identity.js";
17
+ export * from "./file.js";
package/dist/index.js CHANGED
@@ -12,3 +12,4 @@ export * from "./environment.js";
12
12
  export * from "./service.js";
13
13
  export * from "./execution.js";
14
14
  export * from "./knowledge.js";
15
+ export * from "./file.js";
@@ -1,10 +1,11 @@
1
1
  import type { Forge } from "./forge.js";
2
+ import type { Identity } from "./identity.js";
2
3
  /**
3
4
  * A repository identified by its Forge and path within that Forge.
4
5
  * @spec forkedFrom is the direct parent path within the same Forge instance, not repository identity.
5
6
  * @see {@link component://docs/kernel.md}
6
7
  */
7
- export interface Repository {
8
+ export interface Repository extends Identity {
8
9
  readonly forge: Forge;
9
10
  readonly path: string;
10
11
  /**
@@ -13,3 +14,8 @@ export interface Repository {
13
14
  */
14
15
  readonly forkedFrom?: string | null;
15
16
  }
17
+ /**
18
+ * Derive the Repository.id() value from identity fields.
19
+ * @spec Repository identity is forge.name/path; fork provenance is excluded.
20
+ */
21
+ export declare function repositoryId(repository: Pick<Repository, "forge" | "path">): string;
@@ -1 +1,7 @@
1
- export {};
1
+ /**
2
+ * Derive the Repository.id() value from identity fields.
3
+ * @spec Repository identity is forge.name/path; fork provenance is excluded.
4
+ */
5
+ export function repositoryId(repository) {
6
+ return `${repository.forge.name}/${repository.path}`;
7
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@compforge/harness-common",
3
- "version": "0.5.1",
3
+ "version": "0.5.4",
4
4
  "description": "Execution-neutral client lifecycle and datasource contracts for harnesses",
5
5
  "type": "module",
6
6
  "scripts": {