pi-harness-runtime 1.1.18 → 1.1.26
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/harness/e2e/auto-test-loop.ts +94 -29
- package/harness/e2e/tools-detector.ts +20 -17
- package/harness/index.ts +20 -3
- package/harness/loop-runtime.ts +49 -13
- package/harness/skill-sync.test.ts +57 -0
- package/harness/skill-sync.ts +247 -0
- package/harness/ssh-hang-recovery.ts +280 -0
- package/package.json +1 -1
- package/packages/a2a-adapter/package.json +1 -1
- package/packages/architecture-generator/package.json +1 -1
- package/packages/auth/package.json +1 -1
- package/packages/autonomous-refactor/package.json +1 -1
- package/packages/autonomous-runtime/package.json +1 -1
- package/packages/cache-strategy/package.json +1 -1
- package/packages/capability-registry/package.json +1 -1
- package/packages/checkpoint/package.json +1 -1
- package/packages/cli-plugin-sdk/package.json +1 -1
- package/packages/clipboard/package.json +1 -1
- package/packages/clipboard-plugin/package.json +1 -1
- package/packages/code-generation/package.json +1 -1
- package/packages/code-review/package.json +1 -1
- package/packages/codex-adapter/package.json +1 -1
- package/packages/config-capture/package.json +1 -1
- package/packages/context-compiler/package.json +1 -1
- package/packages/context-discovery/package.json +1 -1
- package/packages/context-manager/package.json +1 -1
- package/packages/cookie-sanitizer/package.json +1 -1
- package/packages/cost-optimizer/package.json +1 -1
- package/packages/dependency-analyzer/package.json +1 -1
- package/packages/django-plugin/package.json +1 -1
- package/packages/doc-generator/package.json +1 -1
- package/packages/evaluation-engine/package.json +1 -1
- package/packages/evaluation-runner/package.json +1 -1
- package/packages/event-bus/package.json +1 -1
- package/packages/event-store/package.json +1 -1
- package/packages/experience-replay/package.json +1 -1
- package/packages/feedback-collector/package.json +1 -1
- package/packages/file-copy-helper/package.json +1 -1
- package/packages/framework-detector/package.json +1 -1
- package/packages/framework-plugin-sdk/package.json +1 -1
- package/packages/frappe-plugin/package.json +1 -1
- package/packages/generic-web-plugin/package.json +1 -1
- package/packages/health-monitor/package.json +1 -1
- package/packages/intent-analyzer/package.json +1 -1
- package/packages/knowledge-graph/package.json +1 -1
- package/packages/knowledge-retrieval/package.json +1 -1
- package/packages/laravel-plugin/package.json +1 -1
- package/packages/learning-engine/package.json +1 -1
- package/packages/mcp-adapter/package.json +1 -1
- package/packages/memory-engine/package.json +1 -1
- package/packages/milestone-manager/package.json +1 -1
- package/packages/model-registry/package.json +1 -1
- package/packages/nextjs-plugin/package.json +1 -1
- package/packages/notification/package.json +1 -1
- package/packages/observability/package.json +1 -1
- package/packages/okf-indexer/package.json +1 -1
- package/packages/performance-optimizer/package.json +1 -1
- package/packages/privilege-broker/package.json +1 -1
- package/packages/project-analyzer/package.json +1 -1
- package/packages/project-bootstrap/package.json +1 -1
- package/packages/projection-engine/package.json +1 -1
- package/packages/prompt-compiler/package.json +1 -1
- package/packages/prompt-versioning/package.json +1 -1
- package/packages/provider-adapter-sdk/package.json +1 -1
- package/packages/provider-router/package.json +1 -1
- package/packages/provider-selector/package.json +1 -1
- package/packages/providers/package.json +1 -1
- package/packages/quota-manager/package.json +1 -1
- package/packages/rate-limiter/package.json +1 -1
- package/packages/react-vite-plugin/package.json +1 -1
- package/packages/release-manager/package.json +1 -1
- package/packages/requirement-compiler/package.json +1 -1
- package/packages/runtime/package.json +1 -1
- package/packages/scheduler/package.json +1 -1
- package/packages/scheduler-adapter/package.json +1 -1
- package/packages/session/package.json +1 -1
- package/packages/session-api/package.json +1 -1
- package/packages/session-export/package.json +1 -1
- package/packages/shared-context/package.json +1 -1
- package/packages/skill-mcp-client/package.json +28 -0
- package/packages/skill-mcp-client/src/client.ts +171 -0
- package/packages/skill-mcp-client/src/errors.ts +75 -0
- package/packages/skill-mcp-client/src/index.ts +13 -0
- package/packages/skill-mcp-client/src/types.ts +123 -0
- package/packages/skill-registry/package.json +1 -1
- package/packages/sprint-planner/package.json +1 -1
- package/packages/subscription-engine/package.json +1 -1
- package/packages/task-compiler/package.json +1 -1
- package/packages/tencentdb-memory/package.json +1 -1
- package/packages/tencentdb-sync/package.json +1 -1
- package/packages/test-data-generator/package.json +1 -1
- package/packages/test-generator/package.json +1 -1
- package/packages/todo-bd-sync/package.json +1 -1
- package/packages/token-estimation/package.json +1 -1
- package/packages/token-optimizer/package.json +1 -1
- package/packages/tui/package.json +1 -1
- package/packages/types/package.json +1 -1
- package/packages/workflow-events/package.json +1 -1
- package/packages/workspace-scanner/package.json +1 -1
- package/packages/worktree/package.json +1 -1
- package/packages/write-review/package.json +1 -1
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill MCP Client Implementation (RFC-0106)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { fetch } from "undici";
|
|
6
|
+
import type {
|
|
7
|
+
ListSkillsParams,
|
|
8
|
+
ListSkillsResult,
|
|
9
|
+
GetSkillParams,
|
|
10
|
+
GetSkillResult,
|
|
11
|
+
SyncSkillsParams,
|
|
12
|
+
SyncSkillsResult,
|
|
13
|
+
SkillVersionsResult,
|
|
14
|
+
HealthResult,
|
|
15
|
+
MCPRequest,
|
|
16
|
+
MCPResponse,
|
|
17
|
+
} from "./types.js";
|
|
18
|
+
import { SkillAPIError } from "./errors.js";
|
|
19
|
+
import { ErrorCodes } from "./types.js";
|
|
20
|
+
|
|
21
|
+
const DEFAULT_TIMEOUT_MS = 10000;
|
|
22
|
+
const DEFAULT_MAX_RESULTS = 20;
|
|
23
|
+
|
|
24
|
+
export interface SkillMCPClientConfig {
|
|
25
|
+
/** Server URL (e.g., https://api.skills.example.com) */
|
|
26
|
+
serverUrl: string;
|
|
27
|
+
/** API key for authentication */
|
|
28
|
+
apiKey?: string;
|
|
29
|
+
/** Default max results per request */
|
|
30
|
+
maxResults?: number;
|
|
31
|
+
/** Request timeout in ms */
|
|
32
|
+
timeoutMs?: number;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* MCP Client for Skills SaaS backend
|
|
37
|
+
*/
|
|
38
|
+
export class SkillMCPClient {
|
|
39
|
+
private config: Required<SkillMCPClientConfig>;
|
|
40
|
+
|
|
41
|
+
constructor(config: SkillMCPClientConfig) {
|
|
42
|
+
this.config = {
|
|
43
|
+
serverUrl: config.serverUrl.replace(/\/$/, ""),
|
|
44
|
+
apiKey: config.apiKey ?? "",
|
|
45
|
+
maxResults: config.maxResults ?? DEFAULT_MAX_RESULTS,
|
|
46
|
+
timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Make MCP request to server
|
|
52
|
+
*/
|
|
53
|
+
private async request<T>(
|
|
54
|
+
method: string,
|
|
55
|
+
params: Record<string, unknown> = {},
|
|
56
|
+
): Promise<T> {
|
|
57
|
+
const headers: Record<string, string> = {
|
|
58
|
+
"Content-Type": "application/json",
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
if (this.config.apiKey) {
|
|
62
|
+
headers["Authorization"] = `Bearer ${this.config.apiKey}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const response = await fetch(`${this.config.serverUrl}/mcp`, {
|
|
66
|
+
method: "POST",
|
|
67
|
+
headers,
|
|
68
|
+
body: JSON.stringify({
|
|
69
|
+
jsonrpc: "2.0",
|
|
70
|
+
id: crypto.randomUUID(),
|
|
71
|
+
method,
|
|
72
|
+
params,
|
|
73
|
+
} satisfies MCPRequest),
|
|
74
|
+
signal: AbortSignal.timeout(this.config.timeoutMs),
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
if (!response.ok) {
|
|
78
|
+
throw new SkillAPIError(
|
|
79
|
+
`HTTP ${response.status}: ${response.statusText}`,
|
|
80
|
+
response.status,
|
|
81
|
+
method,
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const data = (await response.json()) as MCPResponse<T>;
|
|
86
|
+
|
|
87
|
+
if (data.error) {
|
|
88
|
+
throw new SkillAPIError(data.error.message, data.error.code, method);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (!data.result) {
|
|
92
|
+
throw new SkillAPIError(
|
|
93
|
+
"No result in response",
|
|
94
|
+
ErrorCodes.INVALID_REQUEST,
|
|
95
|
+
method,
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return data.result;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* List available skills
|
|
104
|
+
*/
|
|
105
|
+
async listSkills(params?: ListSkillsParams): Promise<ListSkillsResult> {
|
|
106
|
+
return this.request<ListSkillsResult>("skills.list", {
|
|
107
|
+
...params,
|
|
108
|
+
limit: params?.limit ?? this.config.maxResults,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Get a skill's full prompt
|
|
114
|
+
*/
|
|
115
|
+
async getSkill(params: GetSkillParams): Promise<GetSkillResult> {
|
|
116
|
+
if (!params.id && !params.slug) {
|
|
117
|
+
throw new SkillAPIError(
|
|
118
|
+
"Either 'id' or 'slug' is required",
|
|
119
|
+
ErrorCodes.INVALID_PARAMS,
|
|
120
|
+
"skills.get",
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
return this.request<GetSkillResult>(
|
|
124
|
+
"skills.get",
|
|
125
|
+
params as Record<string, unknown>,
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Sync all skills for the user's tier (bulk download)
|
|
131
|
+
*/
|
|
132
|
+
async syncSkills(params?: SyncSkillsParams): Promise<SyncSkillsResult> {
|
|
133
|
+
return this.request<SyncSkillsResult>(
|
|
134
|
+
"skills.sync",
|
|
135
|
+
(params ?? {}) as Record<string, unknown>,
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Get version history for a skill
|
|
141
|
+
*/
|
|
142
|
+
async getSkillVersions(
|
|
143
|
+
skillId: string,
|
|
144
|
+
limit = 10,
|
|
145
|
+
): Promise<SkillVersionsResult> {
|
|
146
|
+
return this.request<SkillVersionsResult>("skills.versions", {
|
|
147
|
+
id: skillId,
|
|
148
|
+
limit,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* List all categories
|
|
154
|
+
*/
|
|
155
|
+
async listCategories(): Promise<{
|
|
156
|
+
categories: Array<{
|
|
157
|
+
slug: string;
|
|
158
|
+
displayName: string;
|
|
159
|
+
skillCount: number;
|
|
160
|
+
}>;
|
|
161
|
+
}> {
|
|
162
|
+
return this.request("categories.list");
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Health check
|
|
167
|
+
*/
|
|
168
|
+
async healthCheck(): Promise<HealthResult> {
|
|
169
|
+
return this.request<HealthResult>("health.check");
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill API Error Classes (RFC-0106)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { ErrorCodes } from "./types.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Error thrown when Skills API request fails
|
|
9
|
+
*/
|
|
10
|
+
export class SkillAPIError extends Error {
|
|
11
|
+
constructor(
|
|
12
|
+
message: string,
|
|
13
|
+
public readonly code: number,
|
|
14
|
+
public readonly method?: string,
|
|
15
|
+
public readonly data?: unknown,
|
|
16
|
+
) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = "SkillAPIError";
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Check if this is an auth error
|
|
23
|
+
*/
|
|
24
|
+
isAuthError(): boolean {
|
|
25
|
+
return this.code === ErrorCodes.UNAUTHORIZED;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Check if this is a tier restriction error
|
|
30
|
+
*/
|
|
31
|
+
isTierRestricted(): boolean {
|
|
32
|
+
return this.code === ErrorCodes.TIER_RESTRICTED;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Check if this is a rate limit error
|
|
37
|
+
*/
|
|
38
|
+
isRateLimited(): boolean {
|
|
39
|
+
return this.code === ErrorCodes.RATE_LIMITED;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Check if this is a not found error
|
|
44
|
+
*/
|
|
45
|
+
isNotFound(): boolean {
|
|
46
|
+
return this.code === ErrorCodes.NOT_FOUND;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Error thrown when cache operations fail
|
|
52
|
+
*/
|
|
53
|
+
export class SkillCacheError extends Error {
|
|
54
|
+
constructor(
|
|
55
|
+
message: string,
|
|
56
|
+
public readonly cause?: Error,
|
|
57
|
+
) {
|
|
58
|
+
super(message);
|
|
59
|
+
this.name = "SkillCacheError";
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Error thrown when skill validation fails
|
|
65
|
+
*/
|
|
66
|
+
export class SkillValidationError extends Error {
|
|
67
|
+
constructor(
|
|
68
|
+
message: string,
|
|
69
|
+
public readonly skillId?: string,
|
|
70
|
+
public readonly issues?: string[],
|
|
71
|
+
) {
|
|
72
|
+
super(message);
|
|
73
|
+
this.name = "SkillValidationError";
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill MCP Client (RFC-0106)
|
|
3
|
+
*
|
|
4
|
+
* Client for connecting pi-harness-runtime to Skills SaaS backend.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export { SkillMCPClient, type SkillMCPClientConfig } from "./client.js";
|
|
8
|
+
export {
|
|
9
|
+
SkillAPIError,
|
|
10
|
+
SkillCacheError,
|
|
11
|
+
SkillValidationError,
|
|
12
|
+
} from "./errors.js";
|
|
13
|
+
export * from "./types.js";
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill MCP Client Types (RFC-0106)
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface SkillInfo {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
slug: string;
|
|
9
|
+
description: string;
|
|
10
|
+
version: string;
|
|
11
|
+
tier: "free" | "pro" | "enterprise";
|
|
12
|
+
tags: string[];
|
|
13
|
+
category: string;
|
|
14
|
+
updatedAt: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface CategoryInfo {
|
|
18
|
+
slug: string;
|
|
19
|
+
displayName: string;
|
|
20
|
+
skillCount: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface GetSkillResult {
|
|
24
|
+
id: string;
|
|
25
|
+
name: string;
|
|
26
|
+
slug: string;
|
|
27
|
+
description: string;
|
|
28
|
+
version: string;
|
|
29
|
+
tier: "free" | "pro" | "enterprise";
|
|
30
|
+
tags: string[];
|
|
31
|
+
category: CategoryInfo;
|
|
32
|
+
updatedAt: string;
|
|
33
|
+
prompt: string;
|
|
34
|
+
changelog?: string;
|
|
35
|
+
previousVersions?: string[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface SyncSkillsResult {
|
|
39
|
+
skills: GetSkillResult[];
|
|
40
|
+
syncedAt: string;
|
|
41
|
+
nextSyncDue?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export interface SkillVersion {
|
|
45
|
+
version: string;
|
|
46
|
+
changelog: string;
|
|
47
|
+
releasedAt: string;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface SkillVersionsResult {
|
|
51
|
+
skillId: string;
|
|
52
|
+
currentVersion: string;
|
|
53
|
+
versions: SkillVersion[];
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface HealthResult {
|
|
57
|
+
status: "ok" | "degraded";
|
|
58
|
+
version: string;
|
|
59
|
+
databaseLatencyMs: number;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface ListSkillsParams {
|
|
63
|
+
category?: string;
|
|
64
|
+
tier?: "free" | "pro" | "enterprise";
|
|
65
|
+
tags?: string[];
|
|
66
|
+
search?: string;
|
|
67
|
+
limit?: number;
|
|
68
|
+
offset?: number;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface ListSkillsResult {
|
|
72
|
+
skills: SkillInfo[];
|
|
73
|
+
total: number;
|
|
74
|
+
categories: CategoryInfo[];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface GetSkillParams {
|
|
78
|
+
id?: string;
|
|
79
|
+
slug?: string;
|
|
80
|
+
version?: string;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface SyncSkillsParams {
|
|
84
|
+
categories?: string[];
|
|
85
|
+
forceRefresh?: boolean;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface SkillVersionsParams {
|
|
89
|
+
id: string;
|
|
90
|
+
limit?: number;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// MCP JSON-RPC types
|
|
94
|
+
export interface MCPRequest {
|
|
95
|
+
jsonrpc: "2.0";
|
|
96
|
+
id: string;
|
|
97
|
+
method: string;
|
|
98
|
+
params?: Record<string, unknown>;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface MCPResponse<T = unknown> {
|
|
102
|
+
jsonrpc: "2.0";
|
|
103
|
+
id: string;
|
|
104
|
+
result?: T;
|
|
105
|
+
error?: {
|
|
106
|
+
code: number;
|
|
107
|
+
message: string;
|
|
108
|
+
data?: unknown;
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// Error codes
|
|
113
|
+
export const ErrorCodes = {
|
|
114
|
+
INVALID_REQUEST: -32600,
|
|
115
|
+
INVALID_PARAMS: -32602,
|
|
116
|
+
METHOD_NOT_FOUND: -32601,
|
|
117
|
+
UNAUTHORIZED: -32001,
|
|
118
|
+
TIER_RESTRICTED: -32002,
|
|
119
|
+
NOT_FOUND: -32003,
|
|
120
|
+
RATE_LIMITED: -32004,
|
|
121
|
+
} as const;
|
|
122
|
+
|
|
123
|
+
export type ErrorCode = (typeof ErrorCodes)[keyof typeof ErrorCodes];
|