@compforge/harness-common

中文文档
0.5.15发布于 2026/11/06TypeScriptES Module零依赖近 30 天下载 3091

Execution-neutral client lifecycle and datasource contracts for harnesses

原始使用文档
文档目录8 节
  1. Structured knowledge
  2. Upgrade to 0.4
  3. Upgrade to 0.5
  4. Resource inventory
  5. PullRequest
  6. Portable values
  7. Component tools and Depot
  8. Endpoint

Harness Common for TypeScript

Execution-neutral service topology, client lifecycle, environment context and datasource contracts, shared by harnesses and toolbox clients. No database drivers, Kubernetes adapters, Doctor concepts or business configuration live here.

import { ClientManager, type DataSource } from "@compforge/harness-common";

const clients = new ClientManager();
try {
  const client = await clients.get(source); // source implements DataSource<Client>
  // Borrow the initialized client; the root execution owns cleanup.
} finally {
  await clients.dispose();
}

A ClientProvider clientKey identifies the complete configuration and access policy. Equal keys share client initialization, not query results. Use clientKey to hash configuration without exposing credentials. ServiceDataSource associates a shared Service (or a consumer extension) with a source without changing its key. DataSource extends ClientProvider with data-access semantics; accessible concrete environments implement ClientProvider directly. Both use the same manager. EnvironmentContext binds an Environment (or a consumer extension), a get-only client view and monotonic deadlineMs (performance.now()). It needs no fixture and owns neither disposal nor cancellation; forward remainingMs into operations. Providers receive a get-only ClientManager view and the root AbortSignal. Acquire dependencies through that view during initialize, so concurrent consumers share them and dispose before their dependencies. Dependency graphs must be acyclic. A failed initialization permits retry only after successful cleanup; failed cleanup poisons that key and is reported again when the root manager is disposed.

Use clients.create({ createClient }) for a fresh caller-owned client. The caller may dispose it as soon as its work finishes; dependencies acquired through get remain available to other clients until root disposal. The root also disposes created clients as an idempotent safety net. Use get when callers should share the client itself; borrowers must not dispose those shared instances. Neither API constructs anything before it is called.

FileDataSource declares a nonempty group of distinct paths that can be acquired together. FileClient.read obtains the whole group once and returns one FileReadResult per declared path, in order: { path, status: "ok", bytes } or { path, status: "error", error }. Empty files succeed; missing and oversized files keep independent errors without discarding successful siblings.

Callers specify maxBytes per file, maxTotalBytes for all retained bytes (including in-progress files), timeoutMs for the complete operation including queueing, and optional cancellation. Cancellation, total-budget exhaustion, the group deadline and transport/protocol failures reject the whole operation. Every read observes fresh bytes; a co-acquisition group is not an atomic filesystem snapshot. Parsing, configuration precedence and persistence belong to consumers. Platform implementations live in @compforge/harness-toolbox/file.

Version 0.5.4 replaces the single path and byte-only return value; single-file consumers declare paths: [path] and consume the sole per-file result. There is no implicit legacy adapter.

Service identifies a Component's runtime presence in an Environment. A Component belongs to a Repository on a Forge. Product is a separate business identity; consumers own its many-to-many associations with Components. Repository discovery and directory ownership remain consumer responsibilities. A Service explicitly declares zero or more Workloads. Consumers extend Service with business capabilities, without duplicating these identities. For example:

import {
  repositoryId, conceptToMarkdown, knowledgeToMarkdown, stepToMarkdown, workflowToMarkdown,
  type Service,
} from "@compforge/harness-common";

const service: Service = {
  name: "chat",
  knowledge: {
    markdown() { return knowledgeToMarkdown(this); },
    concepts: [{ id: "conversation", name: "Conversation", description: "Contains Messages; each Message may have multiple execution Attempts.",
      markdown() { return conceptToMarkdown(this); } }],
    workflows: [{ markdown() { return workflowToMarkdown(this); }, id: "reply", title: "Reply", summary: "Accept and answer a message.", steps: [
      { id: "execute", title: "Execute", description: "Execute an attempt and persist its response.",
        markdown() { return stepToMarkdown(this); } },
    ] }],
  },
  upstream: ["gateway"],
  component: {
    name: "api",
    repository: { forge: { name: "github" }, path: "example/app", id() { return repositoryId(this); } },
  },
  environment: { name: "test" },
  workloads: [{
    name: "web", platform: "kubernetes",
    location: { kind: "resource", resource_kind: "Deployment", name: "api-server" },
  }],
};

Repository extends Identity: id() returns forge.name/path, excluding forkedFrom. Use repositoryId(this) when implementing the method, including when restoring a Repository from JSON; methods are not serialized.

Service and Product accept an optional description for a short introduction, and structured knowledge for concepts, workflows, articles and dictionaries. Service knowledge covers its own responsibilities, while Product knowledge covers end-to-end flows. Consumers maintain this offline metadata; it does not change identity, execute a workflow or prove runtime state.

Service upstream lists the canonical names of Services that call it, resolved in the consumer's catalog. Omission means the relationship is undeclared; [] declares no upstream callers. This describes architecture; runtime traces determine which calls actually occurred.

Environment carries identity and an optional local/SSH Host declaration, not a connection. HostEnvironment describes a target running directly on that host. Concrete accessible environments, such as toolbox's KubernetesEnvironment, additionally implement ClientProvider. A Host declaration alone does not add SSH support to a client. Service and EnvironmentContext preserve the concrete environment's access type.

Workload describes a logical runtime carrier and its resource, Kubernetes Service or labels location. WorkloadInstance records an observed Pod incarnation with environment and UID identity. These contracts perform no discovery or I/O; callers resolve declarations in their selected environment. Container selection affects access routing, not Pod identity. See the shared model.

Python's corresponding package is sdks/python/common (harness-common). Languages keep idiomatic APIs and independently versioned packages; they need not implement every model in lockstep.

Development: bun install, make lint, make test. Published artifacts are Node-compatible ESM and declarations.

Structured knowledge

Product and Service accept an optional knowledge declaration. Knowledge groups Concept, Workflow (with parent-scoped Step records), Article (with Section records), and typed Dictionary<Entry> collections. All eight content interfaces extend Markdown, whose markdown(): string method returns an I/O-free representation. Declarations remain ordinary objects; methods can delegate to the shared converters below. KnowledgeSource describes provenance and does not carry this rendering contract.

JSON preserves the content fields, but not methods. Consumers own source validation, method restoration, distribution and version selection. Parsing JSON or asserting a type does not create a callable Knowledge object; restore methods on each content object before exposing it through these interfaces.

IDs are unique per kind within the owner, and per child collection within its parent. Step parentId expresses inclusion; sibling order follows the array even when a parent appears after its child. validateKnowledge rejects duplicate/empty IDs, unknown parents and parent cycles before references are exposed. Dictionary entry IDs are unique, while names and domain keys such as error codes may repeat. source.version describes the published definitions independently of a containing distribution's version.

knowledge.ts also provides deterministic, I/O-free Markdown projections: knowledgeToMarkdown, conceptToMarkdown, workflowToMarkdown, stepToMarkdown, articleToMarkdown, sectionToMarkdown, dictionaryToMarkdown and entryToMarkdown. Dictionary entries retain their typed domain fields; implement Entry.markdown() to include these fields. The shared entryToMarkdown uses name, description and aliases. Generated headings and ordered steps use compact spacing; authored paragraphs and code blocks retain their content. Terminal presentation, exact lookup, search, source loading and vector indexes belong to consumers.

Upgrade to 0.4

Move the removed Product/Service concepts and workflows string fields into knowledge.concepts and knowledge.workflows. Use Concept records for domain objects and Workflow/Step records for business processes. Knowledge remains optional.

Upgrade to 0.5

Implement markdown() on Knowledge and each contained Concept, Workflow, Step, Article, Section, Dictionary and Entry. For example:

import { conceptToMarkdown, type Concept } from "@compforge/harness-common";

const concept: Concept = {
  id: "carrier",
  name: "Carrier",
  description: "Infrastructure capacity.",
  markdown() { return conceptToMarkdown(this); },
};

console.log(concept.markdown());

Existing ...ToMarkdown functions remain available as shared implementations. Each parent calls its children's markdown() methods: Knowledge groups concepts, workflows, articles and dictionaries; Article renders Sections; Dictionary renders Entries; Workflow numbers and indents Steps according to parentId. Parents preserve child output instead of rebuilding it from the child's fields. Helpers never call the receiver's own method, so markdown() { return knowledgeToMarkdown(this); } does not recurse.

Default headings follow the composition tree: Knowledge categories use level 1; Concepts, Workflows, Articles and Dictionaries use level 2; Sections and Entries use level 3. Steps return a bold title and body, with numbering supplied by Workflow. Standalone output uses the same format. Custom methods own their heading choices; parents do not rewrite headings or code blocks in child output.

Move KnowledgeMarkdownOptions.renderEntry or dictionaryToMarkdown renderer callbacks into each Entry's markdown() method. These callback arguments are removed in 0.5; a custom Entry now renders consistently when shown alone or through its Dictionary and Knowledge.

Resource inventory

Resource declares a collection held by a running Service; ServiceResource records manages/uses relationships without duplicating identity. ResourceSnapshot retains typed instances, unit-bearing measurements, independently known totals and complete/partial/unavailable coverage. Discovery and rendering remain consumer-owned. See the shared contract.

PullRequest

PullRequest identifies a PR/MR by its target Repository and repository-local number. State, branches, source repository, revisions and provider timestamps are optional facts. See the shared contract for identity and unknown-state semantics. Forge access and polling remain consumer/toolkit responsibilities.

Portable values

Value, ValueCodec, Summary, and JSON normalization are producer-owned data contracts. Use serializeValue to preserve immutable JSON and reading hints, and deserializeValue with an explicit matching codec to restore runtime behavior. Encoding and decoding are pure. Doctor and its Plugins import these contracts directly from @compforge/harness-common; Observation identity, evidence and rendering remain with their consumers.

Component tools and Depot

Component optionally declares tools and one logical depot. Tool describes a development tool and an optional declared version/constraint. Depot.bins groups Bin declarations with repository-relative paths and dependencies, output or cache kinds. Metadata does not change Component identity, prove physical existence or authorize deletion. Discovery, preparation, usage protection and reclamation belong to consumers. See the shared contract.

Endpoint

Endpoint describes a network access address: optional lowercase scheme, host, explicit port, and optional secure. It is independent of the Service, DataSource or resource behind that address. IPv6 hosts are unbracketed. Credentials, paths, query parameters, execution adapters and timeouts are not part of this contract.

Optional id and description identify and describe the dependency within its consumer. Optional workload carries the complete consumer Workload declaration from which the address is accessed and probed, including platform, location, namespace and container. Consumers resolve instances directly from this declaration without looking up a name in a Service catalog. A declaration does not discover instances or grant access. Protocol probing can consume the address fields alone.

secure: true requires encrypted transport; the protocol determines whether it uses direct TLS or protocol-specific negotiation. Omission makes no encryption requirement. HTTPS/WSS/TLS endpoints require secure: true. This declaration does not assert connectivity, trust-policy approval or authorization. Toolbox owns URL projection, validation and network probing.

版本与发布记录

@compforge/harness-common 共发布 20 个版本,首次发布于 2026/09/16;过去 12 个月发布了 20 个版本。

版本发布日期距今
0.5.15latest2026/11/064 天前
0.5.142026/11/064 天前
0.5.132026/11/064 天前
0.5.122026/11/055 天前
0.5.112026/11/055 天前
0.5.102026/11/046 天前

关于 @compforge/harness-common 的常见问题

@compforge/harness-common 是什么?

Execution-neutral client lifecycle and datasource contracts for harnesses

如何安装 @compforge/harness-common?

在项目目录运行 npm install @compforge/harness-common,或使用 pnpm add / yarn add / bun add。

@compforge/harness-common 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@compforge/harness-common 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@compforge/harness-common 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@compforge/harness-common 可以商用吗?

@compforge/harness-common 使用 未声明 许可。package.json 没有声明许可证。没有许可证的代码默认保留全部权利,商用前请联系作者或查看仓库中的 LICENSE 文件。以上为概括,不构成法律意见,请以许可原文为准。

@compforge/harness-common 的下载量有多少?

根据 npm 官方下载统计,@compforge/harness-common 在 2026/10/11 – 2026/11/09 这 30 天内被下载 3,091 次,日均约 103 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@compforge/harness-common 还在维护吗?

最新版本 0.5.15 发布于 2026/11/06(4 天前);至今共发布 20 个版本,其中过去 12 个月发布了 20 个;首次发布于 2026/09/16。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。