@rzx/ohs 1.1.0 → 1.1.1
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/dist/frontend/index.js +13 -1
- package/dist/frontend/index.js.map +4 -4
- package/dist/index.js +338 -103
- package/dist/index.js.map +11 -10
- package/package.json +10 -10
package/dist/index.js
CHANGED
|
@@ -196887,6 +196887,18 @@ class OpenHarnessClient {
|
|
|
196887
196887
|
signal: options.signal
|
|
196888
196888
|
});
|
|
196889
196889
|
}
|
|
196890
|
+
async listSkills(options = {}) {
|
|
196891
|
+
return await this.request("/skills", {
|
|
196892
|
+
signal: options.signal
|
|
196893
|
+
});
|
|
196894
|
+
}
|
|
196895
|
+
async removeSkill(id, input, options = {}) {
|
|
196896
|
+
return await this.request(`/skills/${encodeURIComponent(id)}`, {
|
|
196897
|
+
method: "DELETE",
|
|
196898
|
+
body: input,
|
|
196899
|
+
signal: options.signal
|
|
196900
|
+
});
|
|
196901
|
+
}
|
|
196890
196902
|
async listAgentPersonas(options = {}) {
|
|
196891
196903
|
const response = await this.request("/agent-personas", {
|
|
196892
196904
|
signal: options.signal
|
|
@@ -276984,6 +276996,8 @@ function buildAgentTranscript(messages, parts) {
|
|
|
276984
276996
|
const output = [];
|
|
276985
276997
|
const attachmentsByMessageId = {};
|
|
276986
276998
|
for (const message of [...messages].sort((a, b) => a.seq - b.seq)) {
|
|
276999
|
+
if (isPresentationOnlyMessage(message))
|
|
277000
|
+
continue;
|
|
276987
277001
|
const messageParts = (byMessage.get(message.id) ?? []).sort((a, b) => a.seq - b.seq);
|
|
276988
277002
|
const attachments = attachmentsFromParts(messageParts);
|
|
276989
277003
|
if (attachments.length > 0)
|
|
@@ -277023,6 +277037,14 @@ function buildAgentTranscript(messages, parts) {
|
|
|
277023
277037
|
}
|
|
277024
277038
|
return { messages: output, attachmentsByMessageId };
|
|
277025
277039
|
}
|
|
277040
|
+
function isPresentationOnlyMessage(message) {
|
|
277041
|
+
const presentation = message.metadata.presentation;
|
|
277042
|
+
if (!presentation || typeof presentation !== "object" || Array.isArray(presentation)) {
|
|
277043
|
+
return false;
|
|
277044
|
+
}
|
|
277045
|
+
const value = presentation;
|
|
277046
|
+
return value.kind === "model_switch" && typeof value.fromModel === "string" && Boolean(value.fromModel.trim()) && typeof value.toModel === "string" && Boolean(value.toModel.trim());
|
|
277047
|
+
}
|
|
277026
277048
|
function agentMessagesToTranscript(messages) {
|
|
277027
277049
|
const output = [];
|
|
277028
277050
|
for (const message of messages) {
|
|
@@ -280509,15 +280531,39 @@ class SessionApplicationService {
|
|
|
280509
280531
|
try {
|
|
280510
280532
|
const before = this.context.events.checkpoint();
|
|
280511
280533
|
const nextModel = metadata ? readSessionRuntimeConfig({ ...existing, metadata }).model : undefined;
|
|
280512
|
-
const
|
|
280513
|
-
|
|
280514
|
-
|
|
280515
|
-
|
|
280516
|
-
|
|
280534
|
+
const modelChanged = nextModel !== undefined && nextModel !== existing.model;
|
|
280535
|
+
const session = this.context.store.transaction(() => {
|
|
280536
|
+
const updated = this.context.store.updateSession(sessionId, {
|
|
280537
|
+
title: input.title,
|
|
280538
|
+
model: nextModel,
|
|
280539
|
+
agent: input.agent,
|
|
280540
|
+
metadata
|
|
280541
|
+
});
|
|
280542
|
+
if (!modelChanged)
|
|
280543
|
+
return updated;
|
|
280544
|
+
const message = this.context.store.createMessage({
|
|
280545
|
+
sessionId,
|
|
280546
|
+
role: "system",
|
|
280547
|
+
metadata: {
|
|
280548
|
+
presentation: {
|
|
280549
|
+
kind: "model_switch",
|
|
280550
|
+
fromModel: existing.model,
|
|
280551
|
+
toModel: nextModel
|
|
280552
|
+
}
|
|
280553
|
+
}
|
|
280554
|
+
});
|
|
280555
|
+
this.context.store.upsertMessagePart({
|
|
280556
|
+
sessionId,
|
|
280557
|
+
messageId: message.id,
|
|
280558
|
+
type: "text",
|
|
280559
|
+
status: "completed",
|
|
280560
|
+
text: `模型已切换 ${existing.model} → ${nextModel}`
|
|
280561
|
+
});
|
|
280562
|
+
return updated;
|
|
280517
280563
|
});
|
|
280518
280564
|
if (runtimeConfigurationChanged)
|
|
280519
280565
|
await this.context.agentPool.close(sessionId);
|
|
280520
|
-
if (
|
|
280566
|
+
if (modelChanged) {
|
|
280521
280567
|
this.context.contextUsageCache?.invalidate(sessionId);
|
|
280522
280568
|
}
|
|
280523
280569
|
this.context.events.publishSince(before);
|
|
@@ -286913,6 +286959,148 @@ var init_default_node_application = __esm(() => {
|
|
|
286913
286959
|
init_daemon_application();
|
|
286914
286960
|
});
|
|
286915
286961
|
|
|
286962
|
+
// ../../packages/server/src/application/skill-management-service.ts
|
|
286963
|
+
import { createHash as createHash12 } from "node:crypto";
|
|
286964
|
+
import { readFile as readFile17, realpath as realpath7, stat as stat9, unlink as unlink4 } from "node:fs/promises";
|
|
286965
|
+
import {
|
|
286966
|
+
basename as basename12,
|
|
286967
|
+
dirname as dirname20,
|
|
286968
|
+
isAbsolute as isAbsolute12,
|
|
286969
|
+
join as join39,
|
|
286970
|
+
relative as relative9,
|
|
286971
|
+
resolve as resolve26,
|
|
286972
|
+
sep as sep4
|
|
286973
|
+
} from "node:path";
|
|
286974
|
+
|
|
286975
|
+
class SkillManagementService {
|
|
286976
|
+
options;
|
|
286977
|
+
personalSkillsDir;
|
|
286978
|
+
configDir;
|
|
286979
|
+
bundledSkills;
|
|
286980
|
+
constructor(options) {
|
|
286981
|
+
this.options = options;
|
|
286982
|
+
const defaultSkillsDir = getSkillsDir();
|
|
286983
|
+
this.configDir = resolve26(options.configDir ?? dirname20(defaultSkillsDir));
|
|
286984
|
+
this.personalSkillsDir = options.configDir ? join39(this.configDir, "skills") : resolve26(defaultSkillsDir);
|
|
286985
|
+
this.bundledSkills = options.bundledSkills ?? BUNDLED_SKILLS;
|
|
286986
|
+
}
|
|
286987
|
+
async list() {
|
|
286988
|
+
const warnings = [];
|
|
286989
|
+
const projects = await validProjects(this.options.projects.list(), warnings);
|
|
286990
|
+
const skills = this.bundledSkills.map((skill) => desktopSkill(skill, "bundled"));
|
|
286991
|
+
const seen = new Set;
|
|
286992
|
+
for (const project of projects) {
|
|
286993
|
+
await this.load(join39(project.root, ".agents", "skills"), "agent", skills, seen, warnings, project);
|
|
286994
|
+
await this.load(join39(project.root, ".claude", "skills"), "agent", skills, seen, warnings, project);
|
|
286995
|
+
const managed = join39(project.root, ".openharness-ts", "skills");
|
|
286996
|
+
if (key(managed) !== key(this.personalSkillsDir)) {
|
|
286997
|
+
await this.load(managed, "project", skills, seen, warnings, project);
|
|
286998
|
+
}
|
|
286999
|
+
}
|
|
287000
|
+
await this.load(this.personalSkillsDir, "personal", skills, seen, warnings);
|
|
287001
|
+
return { skills, projects: projects.map(({ info }) => info), warnings };
|
|
287002
|
+
}
|
|
287003
|
+
async remove(input) {
|
|
287004
|
+
const snapshot = await this.list();
|
|
287005
|
+
const item = snapshot.skills.find((candidate) => candidate.id === input.id);
|
|
287006
|
+
if (!item)
|
|
287007
|
+
throw new Error("找不到指定技能,请刷新后重试。");
|
|
287008
|
+
if (item.readOnly || item.source !== "project" && item.source !== "personal") {
|
|
287009
|
+
throw new Error("此技能来自只读目录,不能删除。");
|
|
287010
|
+
}
|
|
287011
|
+
const target = await this.secureTarget(item);
|
|
287012
|
+
const current = await readFile17(target, "utf8");
|
|
287013
|
+
if (current !== input.expectedContent)
|
|
287014
|
+
throw new Error("技能已在其他位置修改,请刷新后重试。");
|
|
287015
|
+
await unlink4(target);
|
|
287016
|
+
return await this.list();
|
|
287017
|
+
}
|
|
287018
|
+
async secureTarget(item) {
|
|
287019
|
+
const target = await realpath7(item.path);
|
|
287020
|
+
if (item.source === "personal") {
|
|
287021
|
+
await assertTarget(this.configDir, this.personalSkillsDir, target);
|
|
287022
|
+
return target;
|
|
287023
|
+
}
|
|
287024
|
+
if (!item.projectPath)
|
|
287025
|
+
throw new Error("技能缺少所属项目。");
|
|
287026
|
+
const project = await realpath7(item.projectPath);
|
|
287027
|
+
await assertTarget(project, join39(project, ".openharness-ts", "skills"), target);
|
|
287028
|
+
return target;
|
|
287029
|
+
}
|
|
287030
|
+
async load(directory, source, output, seen, warnings, project) {
|
|
287031
|
+
const loader = new SkillLoader(new SkillRegistry);
|
|
287032
|
+
const loaded = await loader.loadFromDirectory(directory, {
|
|
287033
|
+
source: source === "personal" ? "user" : "project",
|
|
287034
|
+
recursive: true
|
|
287035
|
+
});
|
|
287036
|
+
for (const skill of loaded) {
|
|
287037
|
+
try {
|
|
287038
|
+
const path = await realpath7(skill.path);
|
|
287039
|
+
if (seen.has(key(path)))
|
|
287040
|
+
continue;
|
|
287041
|
+
seen.add(key(path));
|
|
287042
|
+
output.push(desktopSkill({ ...skill, path }, source, project?.info));
|
|
287043
|
+
} catch {
|
|
287044
|
+
warnings.push(`无法读取技能文件:${skill.path}`);
|
|
287045
|
+
}
|
|
287046
|
+
}
|
|
287047
|
+
}
|
|
287048
|
+
}
|
|
287049
|
+
function createSkillManagementService(options) {
|
|
287050
|
+
return new SkillManagementService(options);
|
|
287051
|
+
}
|
|
287052
|
+
async function validProjects(input, warnings) {
|
|
287053
|
+
const projects = [];
|
|
287054
|
+
const seen = new Set;
|
|
287055
|
+
for (const project of input) {
|
|
287056
|
+
try {
|
|
287057
|
+
const root = await realpath7(resolve26(project.path));
|
|
287058
|
+
if (!(await stat9(root)).isDirectory() || seen.has(key(root)))
|
|
287059
|
+
continue;
|
|
287060
|
+
seen.add(key(root));
|
|
287061
|
+
projects.push({
|
|
287062
|
+
root,
|
|
287063
|
+
info: { name: project.name.trim() || basename12(root), path: root }
|
|
287064
|
+
});
|
|
287065
|
+
} catch {
|
|
287066
|
+
warnings.push(`项目不存在或不是目录:${project.path}`);
|
|
287067
|
+
}
|
|
287068
|
+
}
|
|
287069
|
+
return projects;
|
|
287070
|
+
}
|
|
287071
|
+
function desktopSkill(skill, source, project) {
|
|
287072
|
+
return {
|
|
287073
|
+
id: `skill_${createHash12("sha256").update(source).update("\x00").update(key(skill.path)).update("\x00").update(skill.name).digest("hex").slice(0, 24)}`,
|
|
287074
|
+
name: skill.name,
|
|
287075
|
+
description: skill.description,
|
|
287076
|
+
content: skill.content,
|
|
287077
|
+
path: skill.path,
|
|
287078
|
+
source,
|
|
287079
|
+
readOnly: source === "bundled" || source === "agent",
|
|
287080
|
+
...project ? { projectPath: project.path, projectName: project.name } : {}
|
|
287081
|
+
};
|
|
287082
|
+
}
|
|
287083
|
+
async function assertTarget(owner, allowed, target) {
|
|
287084
|
+
const physicalOwner = await realpath7(owner);
|
|
287085
|
+
const physicalAllowed = await realpath7(allowed);
|
|
287086
|
+
if (!within(physicalOwner, physicalAllowed))
|
|
287087
|
+
throw new Error("技能目录通过符号链接指向了允许范围之外。");
|
|
287088
|
+
if (!within(physicalAllowed, target))
|
|
287089
|
+
throw new Error("技能文件位于允许范围之外。");
|
|
287090
|
+
}
|
|
287091
|
+
function within(root, target) {
|
|
287092
|
+
const path = relative9(root, target);
|
|
287093
|
+
return path !== "" && path !== ".." && !path.startsWith(`..${sep4}`) && !isAbsolute12(path);
|
|
287094
|
+
}
|
|
287095
|
+
function key(path) {
|
|
287096
|
+
const normalized = resolve26(path);
|
|
287097
|
+
return process.platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
287098
|
+
}
|
|
287099
|
+
var init_skill_management_service = __esm(() => {
|
|
287100
|
+
init_src();
|
|
287101
|
+
init_src2();
|
|
287102
|
+
});
|
|
287103
|
+
|
|
286916
287104
|
// ../../packages/server/src/shared/observability.ts
|
|
286917
287105
|
function writeStructuredLog(event) {
|
|
286918
287106
|
console.info(JSON.stringify({ timestamp: new Date().toISOString(), ...event }));
|
|
@@ -288121,7 +288309,9 @@ function createServiceRoutes(context) {
|
|
|
288121
288309
|
if (!context.outputStyleService)
|
|
288122
288310
|
return errorResponse(501, "Output style service is not configured");
|
|
288123
288311
|
try {
|
|
288124
|
-
return jsonResponse({
|
|
288312
|
+
return jsonResponse({
|
|
288313
|
+
styles: await context.outputStyleService.list()
|
|
288314
|
+
});
|
|
288125
288315
|
} catch (error) {
|
|
288126
288316
|
return errorResponse(500, error instanceof Error ? error.message : String(error));
|
|
288127
288317
|
}
|
|
@@ -288159,7 +288349,10 @@ function createServiceRoutes(context) {
|
|
|
288159
288349
|
if (!lease)
|
|
288160
288350
|
return errorResponse(409, "Cannot uninstall plugins while session runs are active");
|
|
288161
288351
|
try {
|
|
288162
|
-
const result = await context.pluginService.uninstall({
|
|
288352
|
+
const result = await context.pluginService.uninstall({
|
|
288353
|
+
cwd,
|
|
288354
|
+
id: c.req.param("id")
|
|
288355
|
+
});
|
|
288163
288356
|
if (result.restartRuntimes)
|
|
288164
288357
|
await context.control.closeAllRuntimes();
|
|
288165
288358
|
return jsonResponse({ message: result.message });
|
|
@@ -288191,6 +288384,36 @@ function createServiceRoutes(context) {
|
|
|
288191
288384
|
} finally {
|
|
288192
288385
|
lease.release();
|
|
288193
288386
|
}
|
|
288387
|
+
}).get("/skills", async () => {
|
|
288388
|
+
if (!context.skillService)
|
|
288389
|
+
return errorResponse(501, "Skill service is not configured");
|
|
288390
|
+
try {
|
|
288391
|
+
return jsonResponse(await context.skillService.list());
|
|
288392
|
+
} catch (error) {
|
|
288393
|
+
return errorResponse(500, error instanceof Error ? error.message : String(error));
|
|
288394
|
+
}
|
|
288395
|
+
}).delete("/skills/:id", async (c) => {
|
|
288396
|
+
if (!context.skillService)
|
|
288397
|
+
return errorResponse(501, "Skill service is not configured");
|
|
288398
|
+
const lease = context.control.acquireGlobalMutation();
|
|
288399
|
+
if (!lease)
|
|
288400
|
+
return errorResponse(409, "Cannot remove skills while session runs are active");
|
|
288401
|
+
try {
|
|
288402
|
+
const body = await readJson(c);
|
|
288403
|
+
if (typeof body.expectedContent !== "string") {
|
|
288404
|
+
return errorResponse(400, "expectedContent is required");
|
|
288405
|
+
}
|
|
288406
|
+
const result = await context.skillService.remove({
|
|
288407
|
+
id: c.req.param("id"),
|
|
288408
|
+
expectedContent: body.expectedContent
|
|
288409
|
+
});
|
|
288410
|
+
await context.control.closeAllRuntimes();
|
|
288411
|
+
return jsonResponse(result);
|
|
288412
|
+
} catch (error) {
|
|
288413
|
+
return errorResponse(400, error instanceof Error ? error.message : String(error));
|
|
288414
|
+
} finally {
|
|
288415
|
+
lease.release();
|
|
288416
|
+
}
|
|
288194
288417
|
}).get("/agent-personas", async () => {
|
|
288195
288418
|
if (!context.agentPersonaService)
|
|
288196
288419
|
return errorResponse(501, "Agent persona service is not configured");
|
|
@@ -288207,7 +288430,10 @@ function createServiceRoutes(context) {
|
|
|
288207
288430
|
return errorResponse(400, "cwd is required");
|
|
288208
288431
|
const sessionId = c.req.query("sessionId") ?? undefined;
|
|
288209
288432
|
try {
|
|
288210
|
-
const listed = await context.hooksService.list({
|
|
288433
|
+
const listed = await context.hooksService.list({
|
|
288434
|
+
cwd,
|
|
288435
|
+
...sessionId ? { sessionId } : {}
|
|
288436
|
+
});
|
|
288211
288437
|
const hooks = [...listed.hooks];
|
|
288212
288438
|
if (sessionId && context.control.runtimeInspectionAvailable) {
|
|
288213
288439
|
if (!context.control.sessionExists(sessionId)) {
|
|
@@ -288263,7 +288489,13 @@ async function installLocalPlugin(context, c, link) {
|
|
|
288263
288489
|
if (!lease)
|
|
288264
288490
|
return errorResponse(409, "Cannot install plugins while session runs are active");
|
|
288265
288491
|
try {
|
|
288266
|
-
const result = await context.pluginService.installLocal({
|
|
288492
|
+
const result = await context.pluginService.installLocal({
|
|
288493
|
+
cwd,
|
|
288494
|
+
sourcePath,
|
|
288495
|
+
scope,
|
|
288496
|
+
approvedPermissions,
|
|
288497
|
+
link
|
|
288498
|
+
});
|
|
288267
288499
|
if (result.restartRuntimes)
|
|
288268
288500
|
await context.control.closeAllRuntimes();
|
|
288269
288501
|
return jsonResponse({ message: result.message });
|
|
@@ -289615,6 +289847,7 @@ class OpenHarnessHttpServer {
|
|
|
289615
289847
|
outputStyleService: this.services.outputStyle,
|
|
289616
289848
|
projectInitService: this.services.projectInit,
|
|
289617
289849
|
pluginService: this.services.plugin,
|
|
289850
|
+
skillService: this.services.skill ?? createSkillManagementService({ projects: this.application.projects }),
|
|
289618
289851
|
agentPersonaService: this.services.agentPersona,
|
|
289619
289852
|
hooksService: this.services.hooks,
|
|
289620
289853
|
control: this.application.control
|
|
@@ -289680,6 +289913,7 @@ var init_server = __esm(() => {
|
|
|
289680
289913
|
init_dist2();
|
|
289681
289914
|
init_dist3();
|
|
289682
289915
|
init_default_node_application();
|
|
289916
|
+
init_skill_management_service();
|
|
289683
289917
|
init_support2();
|
|
289684
289918
|
init_auth();
|
|
289685
289919
|
init_attachment4();
|
|
@@ -289896,10 +290130,10 @@ var init_auth_service = __esm(() => {
|
|
|
289896
290130
|
|
|
289897
290131
|
// ../../packages/output-styles/src/index.ts
|
|
289898
290132
|
import { readdirSync as readdirSync6, readFileSync as readFileSync14, mkdirSync as mkdirSync15 } from "node:fs";
|
|
289899
|
-
import { join as
|
|
290133
|
+
import { join as join40 } from "node:path";
|
|
289900
290134
|
import { homedir as homedir11 } from "node:os";
|
|
289901
290135
|
function getOutputStylesDir() {
|
|
289902
|
-
const dir =
|
|
290136
|
+
const dir = join40(homedir11(), ".openharness-ts", "output_styles");
|
|
289903
290137
|
try {
|
|
289904
290138
|
mkdirSync15(dir, { recursive: true });
|
|
289905
290139
|
} catch {}
|
|
@@ -289916,7 +290150,7 @@ function loadOutputStyles() {
|
|
|
289916
290150
|
}
|
|
289917
290151
|
for (const file of files) {
|
|
289918
290152
|
try {
|
|
289919
|
-
const content = readFileSync14(
|
|
290153
|
+
const content = readFileSync14(join40(dir, file), "utf-8");
|
|
289920
290154
|
styles.push({ name: file.replace(/\.md$/, ""), content, source: "user" });
|
|
289921
290155
|
} catch {}
|
|
289922
290156
|
}
|
|
@@ -290575,14 +290809,14 @@ var init_profile_service = __esm(() => {
|
|
|
290575
290809
|
});
|
|
290576
290810
|
|
|
290577
290811
|
// ../../packages/server/src/application/default-services/project-init-service.ts
|
|
290578
|
-
import { join as
|
|
290812
|
+
import { join as join41 } from "node:path";
|
|
290579
290813
|
function createDefaultProjectInitService() {
|
|
290580
290814
|
return {
|
|
290581
290815
|
async init({ cwd }) {
|
|
290582
290816
|
const { writeFile, mkdir, access } = await import("node:fs/promises");
|
|
290583
290817
|
const files = [
|
|
290584
290818
|
{
|
|
290585
|
-
path:
|
|
290819
|
+
path: join41(cwd, "CLAUDE.md"),
|
|
290586
290820
|
content: `# Project Rules
|
|
290587
290821
|
|
|
290588
290822
|
Add your project-specific rules and instructions here.
|
|
@@ -290590,7 +290824,7 @@ Add your project-specific rules and instructions here.
|
|
|
290590
290824
|
label: "CLAUDE.md"
|
|
290591
290825
|
},
|
|
290592
290826
|
{
|
|
290593
|
-
path:
|
|
290827
|
+
path: join41(cwd, PROJECT_CONFIG_DIR_NAME, "README.md"),
|
|
290594
290828
|
content: `# OpenHarness Config
|
|
290595
290829
|
|
|
290596
290830
|
This directory contains OpenHarness project configuration.
|
|
@@ -290598,7 +290832,7 @@ This directory contains OpenHarness project configuration.
|
|
|
290598
290832
|
label: `${PROJECT_CONFIG_DIR_NAME}/README.md`
|
|
290599
290833
|
},
|
|
290600
290834
|
{
|
|
290601
|
-
path:
|
|
290835
|
+
path: join41(cwd, PROJECT_CONFIG_DIR_NAME, "memory", "MEMORY.md"),
|
|
290602
290836
|
content: `# Memory
|
|
290603
290837
|
|
|
290604
290838
|
This file stores project memory for the AI assistant.
|
|
@@ -290607,10 +290841,10 @@ This file stores project memory for the AI assistant.
|
|
|
290607
290841
|
}
|
|
290608
290842
|
];
|
|
290609
290843
|
const dirs = [
|
|
290610
|
-
|
|
290611
|
-
|
|
290612
|
-
|
|
290613
|
-
|
|
290844
|
+
join41(cwd, PROJECT_CONFIG_DIR_NAME),
|
|
290845
|
+
join41(cwd, PROJECT_CONFIG_DIR_NAME, "memory"),
|
|
290846
|
+
join41(cwd, PROJECT_CONFIG_DIR_NAME, "plugins"),
|
|
290847
|
+
join41(cwd, PROJECT_CONFIG_DIR_NAME, "skills")
|
|
290614
290848
|
];
|
|
290615
290849
|
const lines = ["Initializing OpenHarness project...", ""];
|
|
290616
290850
|
for (const dir of dirs) {
|
|
@@ -291041,6 +291275,7 @@ var init_application = __esm(() => {
|
|
|
291041
291275
|
init_support();
|
|
291042
291276
|
init_events2();
|
|
291043
291277
|
init_project_application_service();
|
|
291278
|
+
init_skill_management_service();
|
|
291044
291279
|
init_channel3();
|
|
291045
291280
|
init_application_backup();
|
|
291046
291281
|
init_application_retention_service();
|
|
@@ -291082,7 +291317,7 @@ var init_src23 = __esm(() => {
|
|
|
291082
291317
|
});
|
|
291083
291318
|
|
|
291084
291319
|
// src/ensure-daemon.ts
|
|
291085
|
-
import { stat as
|
|
291320
|
+
import { stat as stat10 } from "node:fs/promises";
|
|
291086
291321
|
async function ensureLocalDaemon(options = {}) {
|
|
291087
291322
|
const cliPath = options.cliPath ?? process.argv[1];
|
|
291088
291323
|
if (!cliPath)
|
|
@@ -291090,7 +291325,7 @@ async function ensureLocalDaemon(options = {}) {
|
|
|
291090
291325
|
const expectedVersion = options.expectedVersion ?? VERSION;
|
|
291091
291326
|
const daemonProbeOptions = {
|
|
291092
291327
|
expectedVersion,
|
|
291093
|
-
minimumStartedAt: (await
|
|
291328
|
+
minimumStartedAt: (await stat10(cliPath)).mtimeMs
|
|
291094
291329
|
};
|
|
291095
291330
|
await Promise.resolve().then(() => init_src23());
|
|
291096
291331
|
const waitForDaemonRegistry = async (spawned) => {
|
|
@@ -370332,13 +370567,13 @@ function createMcpCommand() {
|
|
|
370332
370567
|
// src/commands/plugin.ts
|
|
370333
370568
|
init_src15();
|
|
370334
370569
|
init_src12();
|
|
370335
|
-
import { join as
|
|
370570
|
+
import { join as join47, resolve as resolve29 } from "node:path";
|
|
370336
370571
|
import { mkdtemp as mkdtemp3, rm as rm8 } from "node:fs/promises";
|
|
370337
370572
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
370338
370573
|
// ../../packages/plugin-converters/src/core/digest.ts
|
|
370339
|
-
import { createHash as
|
|
370340
|
-
import { readFile as
|
|
370341
|
-
import { join as
|
|
370574
|
+
import { createHash as createHash13 } from "node:crypto";
|
|
370575
|
+
import { readFile as readFile18, readdir as readdir9 } from "node:fs/promises";
|
|
370576
|
+
import { join as join43, relative as relative10 } from "node:path";
|
|
370342
370577
|
function stable(value) {
|
|
370343
370578
|
if (Array.isArray(value))
|
|
370344
370579
|
return `[${value.map(stable).join(",")}]`;
|
|
@@ -370347,14 +370582,14 @@ function stable(value) {
|
|
|
370347
370582
|
return JSON.stringify(value);
|
|
370348
370583
|
}
|
|
370349
370584
|
function digestValue(value) {
|
|
370350
|
-
return
|
|
370585
|
+
return createHash13("sha256").update(stable(value)).digest("hex");
|
|
370351
370586
|
}
|
|
370352
370587
|
async function files(root, dir = root) {
|
|
370353
370588
|
const out = [];
|
|
370354
370589
|
for (const entry of (await readdir9(dir, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
370355
|
-
const full =
|
|
370590
|
+
const full = join43(dir, entry.name);
|
|
370356
370591
|
if (entry.isSymbolicLink())
|
|
370357
|
-
throw new Error(`Source symlink is not allowed: ${
|
|
370592
|
+
throw new Error(`Source symlink is not allowed: ${relative10(root, full)}`);
|
|
370358
370593
|
if (entry.isDirectory())
|
|
370359
370594
|
out.push(...await files(root, full));
|
|
370360
370595
|
else if (entry.isFile())
|
|
@@ -370363,11 +370598,11 @@ async function files(root, dir = root) {
|
|
|
370363
370598
|
return out;
|
|
370364
370599
|
}
|
|
370365
370600
|
async function digestSource(root) {
|
|
370366
|
-
const hash =
|
|
370601
|
+
const hash = createHash13("sha256");
|
|
370367
370602
|
for (const file of await files(root)) {
|
|
370368
|
-
hash.update(
|
|
370603
|
+
hash.update(relative10(root, file).replaceAll("\\", "/"));
|
|
370369
370604
|
hash.update("\x00");
|
|
370370
|
-
hash.update(await
|
|
370605
|
+
hash.update(await readFile18(file));
|
|
370371
370606
|
hash.update("\x00");
|
|
370372
370607
|
}
|
|
370373
370608
|
return hash.digest("hex");
|
|
@@ -370411,22 +370646,22 @@ class ConverterRegistry {
|
|
|
370411
370646
|
}
|
|
370412
370647
|
// ../../packages/plugin-converters/src/claude-code/detector.ts
|
|
370413
370648
|
import { access as access6 } from "node:fs/promises";
|
|
370414
|
-
import { join as
|
|
370649
|
+
import { join as join44 } from "node:path";
|
|
370415
370650
|
var exists4 = async (path) => access6(path).then(() => true, () => false);
|
|
370416
370651
|
async function detectClaudeCodePlugin(root) {
|
|
370417
370652
|
const evidence = [];
|
|
370418
|
-
if (await exists4(
|
|
370653
|
+
if (await exists4(join44(root, ".claude-plugin", "plugin.json")))
|
|
370419
370654
|
evidence.push(".claude-plugin/plugin.json");
|
|
370420
370655
|
for (const name of ["skills", "commands", "agents", "hooks", ".mcp.json", "SKILL.md"])
|
|
370421
|
-
if (await exists4(
|
|
370656
|
+
if (await exists4(join44(root, name)))
|
|
370422
370657
|
evidence.push(name);
|
|
370423
|
-
if (!evidence.length || evidence.length === 1 && evidence[0] === "SKILL.md" && !await exists4(
|
|
370658
|
+
if (!evidence.length || evidence.length === 1 && evidence[0] === "SKILL.md" && !await exists4(join44(root, "SKILL.md")))
|
|
370424
370659
|
return null;
|
|
370425
370660
|
return { converterId: "claude-code", confidence: evidence.includes(".claude-plugin/plugin.json") ? 1 : 0.7, evidence };
|
|
370426
370661
|
}
|
|
370427
370662
|
// ../../packages/plugin-converters/src/claude-code/parser.ts
|
|
370428
|
-
import { access as access7, lstat as lstat6, readFile as
|
|
370429
|
-
import { basename as
|
|
370663
|
+
import { access as access7, lstat as lstat6, readFile as readFile19, readdir as readdir10 } from "node:fs/promises";
|
|
370664
|
+
import { basename as basename13, isAbsolute as isAbsolute13, join as join45, relative as relative11, resolve as resolve27 } from "node:path";
|
|
370430
370665
|
var exists5 = async (path) => access7(path).then(() => true, () => false);
|
|
370431
370666
|
async function collect(root, path, extensions) {
|
|
370432
370667
|
if (!await exists5(path))
|
|
@@ -370440,7 +370675,7 @@ async function collect(root, path, extensions) {
|
|
|
370440
370675
|
for (const entry of (await readdir10(path, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
370441
370676
|
if (entry.isSymbolicLink())
|
|
370442
370677
|
throw new Error(`Claude source symlink is not allowed: ${entry.name}`);
|
|
370443
|
-
const full =
|
|
370678
|
+
const full = join45(path, entry.name);
|
|
370444
370679
|
if (entry.isDirectory())
|
|
370445
370680
|
result.push(...await collect(root, full, extensions));
|
|
370446
370681
|
else if (!extensions || extensions.some((x) => entry.name.toLowerCase().endsWith(x)))
|
|
@@ -370450,31 +370685,31 @@ async function collect(root, path, extensions) {
|
|
|
370450
370685
|
}
|
|
370451
370686
|
var asPaths = (value) => typeof value === "string" ? [value] : Array.isArray(value) && value.every((x) => typeof x === "string") ? value : [];
|
|
370452
370687
|
function safe(root, value) {
|
|
370453
|
-
const target =
|
|
370454
|
-
const rel =
|
|
370455
|
-
if (rel.startsWith("..") ||
|
|
370688
|
+
const target = resolve27(root, value);
|
|
370689
|
+
const rel = relative11(resolve27(root), target);
|
|
370690
|
+
if (rel.startsWith("..") || isAbsolute13(rel) || target === resolve27(root))
|
|
370456
370691
|
throw new Error(`Claude component path escapes source: ${value}`);
|
|
370457
370692
|
return target;
|
|
370458
370693
|
}
|
|
370459
370694
|
async function inspectClaudeCodePlugin(rootInput) {
|
|
370460
|
-
const root =
|
|
370695
|
+
const root = resolve27(rootInput);
|
|
370461
370696
|
let manifest = {};
|
|
370462
|
-
const manifestPath =
|
|
370697
|
+
const manifestPath = join45(root, ".claude-plugin", "plugin.json");
|
|
370463
370698
|
if (await exists5(manifestPath))
|
|
370464
|
-
manifest = JSON.parse(await
|
|
370465
|
-
const name = typeof manifest.name === "string" ? manifest.name :
|
|
370699
|
+
manifest = JSON.parse(await readFile19(manifestPath, "utf8"));
|
|
370700
|
+
const name = typeof manifest.name === "string" ? manifest.name : basename13(root).toLowerCase().replace(/[^a-z0-9-]+/g, "-");
|
|
370466
370701
|
const inventory = {};
|
|
370467
|
-
const skillRoots = [
|
|
370468
|
-
if (await exists5(
|
|
370469
|
-
skillRoots.push(
|
|
370702
|
+
const skillRoots = [join45(root, "skills"), ...asPaths(manifest.skills).map((x) => safe(root, x))];
|
|
370703
|
+
if (await exists5(join45(root, "SKILL.md")))
|
|
370704
|
+
skillRoots.push(join45(root, "SKILL.md"));
|
|
370470
370705
|
inventory.skills = (await Promise.all(skillRoots.map((x) => collect(root, x, ["skill.md"])))).flat();
|
|
370471
370706
|
for (const kind of ["commands", "agents"]) {
|
|
370472
370707
|
const custom = asPaths(manifest[kind]);
|
|
370473
|
-
const roots = custom.length ? custom.map((x) => safe(root, x)) : [
|
|
370708
|
+
const roots = custom.length ? custom.map((x) => safe(root, x)) : [join45(root, kind)];
|
|
370474
370709
|
inventory[kind] = (await Promise.all(roots.map((x) => collect(root, x, [".md"])))).flat();
|
|
370475
370710
|
}
|
|
370476
|
-
const hooks =
|
|
370477
|
-
const mcp =
|
|
370711
|
+
const hooks = join45(root, "hooks", "hooks.json");
|
|
370712
|
+
const mcp = join45(root, ".mcp.json");
|
|
370478
370713
|
inventory.hooks = await exists5(hooks) ? [hooks] : [];
|
|
370479
370714
|
inventory.mcpServers = await exists5(mcp) ? [mcp] : [];
|
|
370480
370715
|
return { root, format: "claude-code", identity: { id: `converted.claude.${name}`, name, version: typeof manifest.version === "string" ? manifest.version : "0.0.0" }, inventory, diagnostics: [] };
|
|
@@ -370584,34 +370819,34 @@ function convertClaudeAgentMarkdown(content) {
|
|
|
370584
370819
|
// ../../packages/plugin-converters/src/claude-code/converter.ts
|
|
370585
370820
|
init_src12();
|
|
370586
370821
|
import { randomUUID as randomUUID27 } from "node:crypto";
|
|
370587
|
-
import { access as access8, cp as cp3, mkdir as mkdir14, readFile as
|
|
370588
|
-
import { basename as
|
|
370589
|
-
var rel = (inspection, path) =>
|
|
370822
|
+
import { access as access8, cp as cp3, mkdir as mkdir14, readFile as readFile20, rename as rename4, rm as rm7, writeFile as writeFile11 } from "node:fs/promises";
|
|
370823
|
+
import { basename as basename14, dirname as dirname21, join as join46, relative as relative12, resolve as resolve28 } from "node:path";
|
|
370824
|
+
var rel = (inspection, path) => relative12(inspection.root, path).replaceAll("\\", "/");
|
|
370590
370825
|
function componentPath(inspection, sourcePath, directory) {
|
|
370591
370826
|
const parts = rel(inspection, sourcePath).split("/");
|
|
370592
370827
|
const directoryIndex = parts.indexOf(directory);
|
|
370593
370828
|
return (directoryIndex >= 0 ? parts.slice(directoryIndex + 1) : parts).join("/");
|
|
370594
370829
|
}
|
|
370595
370830
|
async function copySkillBundle(inspection, skillFile, targetRoot) {
|
|
370596
|
-
const sourceDirectory =
|
|
370597
|
-
const relativeDirectory =
|
|
370598
|
-
const targetRelative = relativeDirectory === "" ? inspection.identity.name :
|
|
370599
|
-
const targetDirectory =
|
|
370831
|
+
const sourceDirectory = dirname21(skillFile);
|
|
370832
|
+
const relativeDirectory = relative12(inspection.root, sourceDirectory);
|
|
370833
|
+
const targetRelative = relativeDirectory === "" ? inspection.identity.name : dirname21(componentPath(inspection, skillFile, "skills"));
|
|
370834
|
+
const targetDirectory = join46(targetRoot, targetRelative === "." ? inspection.identity.name : targetRelative);
|
|
370600
370835
|
if (sourceDirectory !== inspection.root) {
|
|
370601
370836
|
await cp3(sourceDirectory, targetDirectory, { recursive: true, errorOnExist: true, force: false });
|
|
370602
370837
|
return;
|
|
370603
370838
|
}
|
|
370604
370839
|
await mkdir14(targetDirectory, { recursive: true });
|
|
370605
|
-
await cp3(skillFile,
|
|
370840
|
+
await cp3(skillFile, join46(targetDirectory, "SKILL.md"), { errorOnExist: true, force: false });
|
|
370606
370841
|
for (const resourceDirectory of ["assets", "references", "scripts"]) {
|
|
370607
|
-
const sourceResource =
|
|
370842
|
+
const sourceResource = join46(sourceDirectory, resourceDirectory);
|
|
370608
370843
|
if (await access8(sourceResource).then(() => true, () => false)) {
|
|
370609
|
-
await cp3(sourceResource,
|
|
370844
|
+
await cp3(sourceResource, join46(targetDirectory, resourceDirectory), { recursive: true, errorOnExist: true, force: false });
|
|
370610
370845
|
}
|
|
370611
370846
|
}
|
|
370612
370847
|
}
|
|
370613
370848
|
async function convertHooks(source, target) {
|
|
370614
|
-
const raw = JSON.parse(await
|
|
370849
|
+
const raw = JSON.parse(await readFile20(source, "utf8"));
|
|
370615
370850
|
const rows = raw.hooks && typeof raw.hooks === "object" ? raw.hooks : raw;
|
|
370616
370851
|
const output = {};
|
|
370617
370852
|
for (const [sourceEvent, entries] of Object.entries(rows)) {
|
|
@@ -370628,12 +370863,12 @@ async function convertHooks(source, target) {
|
|
|
370628
370863
|
}
|
|
370629
370864
|
if (!Object.keys(output).length)
|
|
370630
370865
|
return false;
|
|
370631
|
-
await mkdir14(
|
|
370866
|
+
await mkdir14(dirname21(target), { recursive: true });
|
|
370632
370867
|
await writeFile11(target, JSON.stringify(output, null, 2));
|
|
370633
370868
|
return true;
|
|
370634
370869
|
}
|
|
370635
370870
|
async function convertMcp(source, target) {
|
|
370636
|
-
const raw = JSON.parse(await
|
|
370871
|
+
const raw = JSON.parse(await readFile20(source, "utf8"));
|
|
370637
370872
|
const servers = {};
|
|
370638
370873
|
for (const [name, value] of Object.entries(raw.mcpServers ?? {})) {
|
|
370639
370874
|
if (typeof value.command === "string")
|
|
@@ -370643,7 +370878,7 @@ async function convertMcp(source, target) {
|
|
|
370643
370878
|
else
|
|
370644
370879
|
throw new Error(`Ambiguous MCP server: ${name}`);
|
|
370645
370880
|
}
|
|
370646
|
-
await mkdir14(
|
|
370881
|
+
await mkdir14(dirname21(target), { recursive: true });
|
|
370647
370882
|
await writeFile11(target, JSON.stringify({ servers }, null, 2));
|
|
370648
370883
|
}
|
|
370649
370884
|
|
|
@@ -370668,7 +370903,7 @@ class ClaudeCodePluginConverter {
|
|
|
370668
370903
|
});
|
|
370669
370904
|
}
|
|
370670
370905
|
for (const hookFile of inspection.inventory.hooks ?? []) {
|
|
370671
|
-
const raw = JSON.parse(await
|
|
370906
|
+
const raw = JSON.parse(await readFile20(hookFile, "utf8"));
|
|
370672
370907
|
const rows = raw.hooks && typeof raw.hooks === "object" ? raw.hooks : raw;
|
|
370673
370908
|
if (Object.keys(rows).some((event) => CLAUDE_HOOK_EVENT_MAP[event])) {
|
|
370674
370909
|
items.push({
|
|
@@ -370707,7 +370942,7 @@ class ClaudeCodePluginConverter {
|
|
|
370707
370942
|
throw new Error(`Blocked conversion items require approval: ${blocked.map((x) => x.id).join(", ")}`);
|
|
370708
370943
|
if (await digestSource(input.inspection.root) !== input.plan.sourceDigest)
|
|
370709
370944
|
throw new Error("Source changed after conversion planning; inspect and plan again");
|
|
370710
|
-
const output =
|
|
370945
|
+
const output = resolve28(input.output);
|
|
370711
370946
|
if (await access8(output).then(() => true, () => false))
|
|
370712
370947
|
throw new Error(`Conversion output already exists: ${output}`);
|
|
370713
370948
|
const temporary = `${output}.tmp-${randomUUID27()}`;
|
|
@@ -370717,31 +370952,31 @@ class ClaudeCodePluginConverter {
|
|
|
370717
370952
|
const components = {};
|
|
370718
370953
|
const skills = input.inspection.inventory.skills ?? [];
|
|
370719
370954
|
for (const skill of skills) {
|
|
370720
|
-
await copySkillBundle(input.inspection, skill,
|
|
370955
|
+
await copySkillBundle(input.inspection, skill, join46(temporary, "skills"));
|
|
370721
370956
|
}
|
|
370722
370957
|
const commands = input.inspection.inventory.commands ?? [];
|
|
370723
370958
|
for (const command of commands) {
|
|
370724
|
-
const name =
|
|
370725
|
-
const target =
|
|
370726
|
-
await mkdir14(
|
|
370727
|
-
await writeFile11(target, await
|
|
370959
|
+
const name = basename14(command, ".md");
|
|
370960
|
+
const target = join46(temporary, "skills", name, "SKILL.md");
|
|
370961
|
+
await mkdir14(dirname21(target), { recursive: true });
|
|
370962
|
+
await writeFile11(target, await readFile20(command, "utf8"));
|
|
370728
370963
|
}
|
|
370729
370964
|
if (skills.length || commands.length)
|
|
370730
370965
|
components.skills = ["./skills"];
|
|
370731
370966
|
const agents = input.inspection.inventory.agents ?? [];
|
|
370732
370967
|
for (const agent of agents) {
|
|
370733
|
-
const target =
|
|
370734
|
-
await mkdir14(
|
|
370735
|
-
await writeFile11(target, convertClaudeAgentMarkdown(await
|
|
370968
|
+
const target = join46(temporary, "agents", componentPath(input.inspection, agent, "agents"));
|
|
370969
|
+
await mkdir14(dirname21(target), { recursive: true });
|
|
370970
|
+
await writeFile11(target, convertClaudeAgentMarkdown(await readFile20(agent, "utf8")));
|
|
370736
370971
|
}
|
|
370737
370972
|
if (agents.length)
|
|
370738
370973
|
components.agents = ["./agents"];
|
|
370739
370974
|
const hooks = input.inspection.inventory.hooks?.[0];
|
|
370740
|
-
if (hooks && await convertHooks(hooks,
|
|
370975
|
+
if (hooks && await convertHooks(hooks, join46(temporary, "hooks.json")))
|
|
370741
370976
|
components.hooks = ["./hooks.json"];
|
|
370742
370977
|
const mcp = input.inspection.inventory.mcpServers?.[0];
|
|
370743
370978
|
if (mcp) {
|
|
370744
|
-
await convertMcp(mcp,
|
|
370979
|
+
await convertMcp(mcp, join46(temporary, "mcp.json"));
|
|
370745
370980
|
components.mcpServers = ["./mcp.json"];
|
|
370746
370981
|
}
|
|
370747
370982
|
if (!Object.keys(components).length)
|
|
@@ -370754,13 +370989,13 @@ class ClaudeCodePluginConverter {
|
|
|
370754
370989
|
metadata: { origin: "converted", sourceFormat: this.sourceFormat, converterId: this.id, converterVersion: this.version },
|
|
370755
370990
|
components
|
|
370756
370991
|
};
|
|
370757
|
-
await mkdir14(
|
|
370758
|
-
await writeFile11(
|
|
370992
|
+
await mkdir14(join46(temporary, ".openharness-plugin"));
|
|
370993
|
+
await writeFile11(join46(temporary, ".openharness-plugin", "plugin.json"), JSON.stringify(manifest, null, 2));
|
|
370759
370994
|
const report = { schemaVersion: 1, status: input.plan.items.some((x) => x.fidelity === "unsupported") ? "partial" : "success", items: input.plan.items, diagnostics: input.plan.diagnostics };
|
|
370760
|
-
await mkdir14(
|
|
370761
|
-
await writeFile11(
|
|
370762
|
-
await writeFile11(
|
|
370763
|
-
await writeFile11(
|
|
370995
|
+
await mkdir14(join46(temporary, ".openharness-conversion"));
|
|
370996
|
+
await writeFile11(join46(temporary, ".openharness-conversion", "plan.json"), JSON.stringify(input.plan, null, 2));
|
|
370997
|
+
await writeFile11(join46(temporary, ".openharness-conversion", "report.json"), JSON.stringify(report, null, 2));
|
|
370998
|
+
await writeFile11(join46(temporary, ".openharness-conversion", "provenance.json"), JSON.stringify({ sourceFormat: this.sourceFormat, sourceDigest: input.plan.sourceDigest, converterId: this.id, converterVersion: this.version, mappingVersion: CLAUDE_MAPPING_VERSION }, null, 2));
|
|
370764
370999
|
const validation = await validateNativePlugin(temporary);
|
|
370765
371000
|
if (validation.status !== "valid")
|
|
370766
371001
|
throw new Error(validation.diagnostics.map((x) => x.message).join("; "));
|
|
@@ -370856,11 +371091,11 @@ function formatPluginList(result, verbose = false) {
|
|
|
370856
371091
|
function createPluginCommand() {
|
|
370857
371092
|
const cmd = new Command3("plugin").description("Manage Native Plugins");
|
|
370858
371093
|
cmd.command("list").option("--cwd <path>").option("--verbose", "show permissions, contributions, runtime, and diagnostics").option("--json", "print the complete machine-readable response").action(async (options) => {
|
|
370859
|
-
const result = await (await client()).listPlugins({ cwd:
|
|
371094
|
+
const result = await (await client()).listPlugins({ cwd: resolve29(options.cwd ?? process.cwd()) });
|
|
370860
371095
|
console.log(options.json ? JSON.stringify(result, null, 2) : formatPluginList(result, options.verbose));
|
|
370861
371096
|
});
|
|
370862
371097
|
cmd.command("validate").argument("<path>").action(async (path) => {
|
|
370863
|
-
const result = await validateNativePlugin(
|
|
371098
|
+
const result = await validateNativePlugin(resolve29(path));
|
|
370864
371099
|
if (result.status === "valid")
|
|
370865
371100
|
console.log(`Valid Native Plugin: ${result.plugin.manifest.id}@${result.plugin.manifest.version}`);
|
|
370866
371101
|
else {
|
|
@@ -370871,7 +371106,7 @@ function createPluginCommand() {
|
|
|
370871
371106
|
});
|
|
370872
371107
|
for (const [name, link] of [["install-local", false], ["link", true]]) {
|
|
370873
371108
|
cmd.command(name).argument("<path>").option("--cwd <path>").option("--approve <permission>", "approve a requested permission", collect2, []).action(async (path, options) => {
|
|
370874
|
-
const sourcePath =
|
|
371109
|
+
const sourcePath = resolve29(path);
|
|
370875
371110
|
const validation = await validateNativePlugin(sourcePath);
|
|
370876
371111
|
if (!validation.plugin)
|
|
370877
371112
|
throw new Error(validation.diagnostics.map((item) => item.message).join("; "));
|
|
@@ -370881,7 +371116,7 @@ function createPluginCommand() {
|
|
|
370881
371116
|
if (missing.length)
|
|
370882
371117
|
throw new Error(`Explicit approval required: ${missing.join(", ")}`);
|
|
370883
371118
|
const result = await (await client()).installLocalPlugin({
|
|
370884
|
-
cwd:
|
|
371119
|
+
cwd: resolve29(options.cwd ?? process.cwd()),
|
|
370885
371120
|
sourcePath,
|
|
370886
371121
|
scope: "user",
|
|
370887
371122
|
approvedPermissions: approved,
|
|
@@ -370893,25 +371128,25 @@ function createPluginCommand() {
|
|
|
370893
371128
|
for (const action of ["enable", "disable"])
|
|
370894
371129
|
cmd.command(action).argument("<id>").option("--cwd <path>").action(async (id, options) => {
|
|
370895
371130
|
const api = await client();
|
|
370896
|
-
const input = { cwd:
|
|
371131
|
+
const input = { cwd: resolve29(options.cwd ?? process.cwd()) };
|
|
370897
371132
|
console.log((action === "enable" ? await api.enablePlugin(id, input) : await api.disablePlugin(id, input)).message);
|
|
370898
371133
|
});
|
|
370899
371134
|
cmd.command("uninstall").argument("<id>").option("--cwd <path>").action(async (id, options) => {
|
|
370900
|
-
console.log((await (await client()).uninstallPlugin(id, { cwd:
|
|
371135
|
+
console.log((await (await client()).uninstallPlugin(id, { cwd: resolve29(options.cwd ?? process.cwd()) })).message);
|
|
370901
371136
|
});
|
|
370902
371137
|
cmd.command("details").argument("<id>").option("--cwd <path>").action(async (id, options) => {
|
|
370903
|
-
const listed = await (await client()).listPlugins({ cwd:
|
|
371138
|
+
const listed = await (await client()).listPlugins({ cwd: resolve29(options.cwd ?? process.cwd()) });
|
|
370904
371139
|
const plugin = listed.plugins.find((item) => item.identity.id === id);
|
|
370905
371140
|
if (!plugin)
|
|
370906
371141
|
throw new Error(`Plugin not found: ${id}`);
|
|
370907
371142
|
console.log(JSON.stringify(plugin, null, 2));
|
|
370908
371143
|
});
|
|
370909
371144
|
cmd.command("install").argument("<source>").requiredOption("--from <converter>").option("--cwd <path>").option("--approve <item>", "approve conversion item or permission", collect2, []).action(async (source, options) => {
|
|
370910
|
-
const temporaryRoot = await mkdtemp3(
|
|
370911
|
-
const output =
|
|
371145
|
+
const temporaryRoot = await mkdtemp3(join47(tmpdir5(), "ohs-plugin-import-"));
|
|
371146
|
+
const output = join47(temporaryRoot, "native");
|
|
370912
371147
|
try {
|
|
370913
|
-
const { converter } = await createBuiltinConverterRegistry().detect(
|
|
370914
|
-
const inspection = await converter.inspect(
|
|
371148
|
+
const { converter } = await createBuiltinConverterRegistry().detect(resolve29(source), options.from);
|
|
371149
|
+
const inspection = await converter.inspect(resolve29(source));
|
|
370915
371150
|
const plan = await converter.plan(inspection, {});
|
|
370916
371151
|
await converter.convert({ inspection, plan, output, approvals: options.approve });
|
|
370917
371152
|
const validation = await validateNativePlugin(output);
|
|
@@ -370922,7 +371157,7 @@ function createPluginCommand() {
|
|
|
370922
371157
|
if (missing.length)
|
|
370923
371158
|
throw new Error(`Explicit permission approval required: ${missing.join(", ")}`);
|
|
370924
371159
|
const result = await (await client()).installLocalPlugin({
|
|
370925
|
-
cwd:
|
|
371160
|
+
cwd: resolve29(options.cwd ?? process.cwd()),
|
|
370926
371161
|
sourcePath: output,
|
|
370927
371162
|
scope: "user",
|
|
370928
371163
|
approvedPermissions: requested
|
|
@@ -370934,8 +371169,8 @@ function createPluginCommand() {
|
|
|
370934
371169
|
});
|
|
370935
371170
|
cmd.command("convert").argument("<source>").option("--from <converter>").option("--output <path>").option("--dry-run").option("--json").option("--approve <item>", "approve a blocked conversion item", collect2, []).action(async (source, options) => {
|
|
370936
371171
|
const registry = createBuiltinConverterRegistry();
|
|
370937
|
-
const { converter, detection } = await registry.detect(
|
|
370938
|
-
const inspection = await converter.inspect(
|
|
371172
|
+
const { converter, detection } = await registry.detect(resolve29(source), options.from);
|
|
371173
|
+
const inspection = await converter.inspect(resolve29(source));
|
|
370939
371174
|
const plan = await converter.plan(inspection, {});
|
|
370940
371175
|
if (options.dryRun) {
|
|
370941
371176
|
console.log(options.json ? JSON.stringify({ detection, inspection, plan }, null, 2) : plan.items.map((item) => `${item.fidelity.padEnd(11)} ${item.id}`).join(`
|
|
@@ -370944,7 +371179,7 @@ function createPluginCommand() {
|
|
|
370944
371179
|
}
|
|
370945
371180
|
if (!options.output)
|
|
370946
371181
|
throw new Error("--output is required unless --dry-run is used");
|
|
370947
|
-
const report = await converter.convert({ inspection, plan, output:
|
|
371182
|
+
const report = await converter.convert({ inspection, plan, output: resolve29(options.output), approvals: options.approve });
|
|
370948
371183
|
console.log(options.json ? JSON.stringify(report, null, 2) : `Converted ${inspection.identity.id}: ${report.status}`);
|
|
370949
371184
|
});
|
|
370950
371185
|
return cmd;
|
|
@@ -371461,7 +371696,7 @@ function createSandboxCommand() {
|
|
|
371461
371696
|
init_src3();
|
|
371462
371697
|
init_src9();
|
|
371463
371698
|
import { readFileSync as readFileSync15 } from "node:fs";
|
|
371464
|
-
import { resolve as
|
|
371699
|
+
import { resolve as resolve30 } from "node:path";
|
|
371465
371700
|
import { Command as Command8 } from "commander";
|
|
371466
371701
|
function createWorkflowCommand() {
|
|
371467
371702
|
const cmd = new Command8("workflow").description("Inspect and manage persisted workflow runs");
|
|
@@ -371618,7 +371853,7 @@ function readJsonOption(path, inlineJson) {
|
|
|
371618
371853
|
if (inlineJson)
|
|
371619
371854
|
return JSON.parse(inlineJson);
|
|
371620
371855
|
if (path)
|
|
371621
|
-
return JSON.parse(readFileSync15(
|
|
371856
|
+
return JSON.parse(readFileSync15(resolve30(path), "utf-8"));
|
|
371622
371857
|
return;
|
|
371623
371858
|
}
|
|
371624
371859
|
function parseCsv(value) {
|
|
@@ -372215,4 +372450,4 @@ program.command("doctor").description("Check environment and dependencies").acti
|
|
|
372215
372450
|
});
|
|
372216
372451
|
program.parse();
|
|
372217
372452
|
|
|
372218
|
-
//# debugId=
|
|
372453
|
+
//# debugId=A30D9095E02E07FA64756E2164756E21
|