@harmonyos-arkts/opencode-plugin 0.0.19 → 0.0.20-beta
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 +1 -1
- package/dist/index.js +180 -160
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
- **HarmonyOS设计专家**:为HarmonyOS应用和原子化服务创建详细的PRD设计文档
|
|
9
9
|
- **HarmonyOS开发专家**:根据设计文档遵循HarmonyOS规范实现功能
|
|
10
10
|
- **HarmonyOS构建**:使用harmonyos-hvigor技能构建项目并确保编译成功
|
|
11
|
-
- **HarmonyOS文档查询**:通过 `harmony-doc`
|
|
11
|
+
- **HarmonyOS文档查询**:通过 `harmony-doc-search` 搜索华为官方开发者文档(关键词越精简越准确),通过 `harmony-doc-view` 查看文档全文(支持分页)
|
|
12
12
|
|
|
13
13
|
## 快速开始
|
|
14
14
|
|
package/dist/index.js
CHANGED
|
@@ -31913,6 +31913,8 @@ function createHmAgent() {
|
|
|
31913
31913
|
doom_loop: "ask",
|
|
31914
31914
|
"skillSearch": "allow",
|
|
31915
31915
|
ascf_build: "deny",
|
|
31916
|
+
"harmony-doc-search": "allow",
|
|
31917
|
+
"harmony-doc-view": "allow",
|
|
31916
31918
|
skill: {
|
|
31917
31919
|
"*": "deny",
|
|
31918
31920
|
"harmonyos-atomic-dev": "allow",
|
|
@@ -31944,7 +31946,9 @@ function createDesignAgent() {
|
|
|
31944
31946
|
"*": "deny",
|
|
31945
31947
|
"harmonyos-prd-design": "allow"
|
|
31946
31948
|
},
|
|
31947
|
-
"skillSearch": "deny"
|
|
31949
|
+
"skillSearch": "deny",
|
|
31950
|
+
"harmony-doc-search": "deny",
|
|
31951
|
+
"harmony-doc-view": "deny"
|
|
31948
31952
|
},
|
|
31949
31953
|
metadata: void 0
|
|
31950
31954
|
};
|
|
@@ -31967,6 +31971,8 @@ function createHmDevelopmentAgent() {
|
|
|
31967
31971
|
temperature: 0.3,
|
|
31968
31972
|
permission: {
|
|
31969
31973
|
"skillSearch": "allow",
|
|
31974
|
+
"harmony-doc-search": "allow",
|
|
31975
|
+
"harmony-doc-view": "allow",
|
|
31970
31976
|
skill: {
|
|
31971
31977
|
"*": "deny",
|
|
31972
31978
|
"harmonyos-atomic-dev": "allow",
|
|
@@ -44871,8 +44877,10 @@ function createHmTemplateTool(managers) {
|
|
|
44871
44877
|
return tool({
|
|
44872
44878
|
description: "Create an empty HarmonyOS project template. Supports three modes: 'application' (full app), 'module' (sub-module), 'atomic' (atomic service). Defaults to the current working directory unless the user specifies a different directory.",
|
|
44873
44879
|
args: {
|
|
44874
|
-
filePath: tool.schema.string().describe(
|
|
44875
|
-
|
|
44880
|
+
filePath: tool.schema.string().describe(
|
|
44881
|
+
"Absolute path of the target directory where the template will be created. Defaults to the current working directory if not specified."
|
|
44882
|
+
),
|
|
44883
|
+
mode: tool.schema.string().describe("Template type: 'application' (\u5E94\u7528), 'module' (\u6A21\u5757), or 'atomic' (\u5143\u670D\u52A1).")
|
|
44876
44884
|
},
|
|
44877
44885
|
execute: async (args, context) => {
|
|
44878
44886
|
try {
|
|
@@ -45376,6 +45384,117 @@ function convert_search_result(searchResults, prefix) {
|
|
|
45376
45384
|
});
|
|
45377
45385
|
}
|
|
45378
45386
|
|
|
45387
|
+
// src/tools/skill-search/skill-search-tool.ts
|
|
45388
|
+
function skillSearchTool(_managers) {
|
|
45389
|
+
return tool({
|
|
45390
|
+
description: "Search for relevant documents within the harmonyos-atomic-dev skill directory by keywords. Returns the top K most relevant document snippets from the skill directory, ranked by keyword match frequency. Results include experience_file_path (best practices), ets_file_path (code examples), and sdk_file_path (SDK API info). QUERY TIPS: Decompose your intent into short space-separated keywords for best results. Include: 1) Kit or component name (e.g. ScanKit, AdsKit, ShareKit), 2) specific API or method names (e.g. scanBarcode, loadAd, ShareController), 3) feature keywords (e.g. \u626B\u7801, \u5E7F\u544A\u52A0\u8F7D, \u5206\u4EAB). Example: 'ScanKit \u626B\u7801 scanBarcode startScanForResult' instead of '\u5E2E\u6211\u5B9E\u73B0\u4E00\u4E2A\u626B\u7801\u529F\u80FD'.",
|
|
45391
|
+
args: {
|
|
45392
|
+
skill_path: tool.schema.string().describe(
|
|
45393
|
+
"Absolute path to the harmonyos-atomic-dev skill directory. IMPORTANT: this path should not contain any prefix or suffix like 'file://' or 'SKILL.md'."
|
|
45394
|
+
),
|
|
45395
|
+
query: tool.schema.string().describe(
|
|
45396
|
+
"A decomposed requirement or intent describing what you want to find, broken down into searchable keywords separated by spaces."
|
|
45397
|
+
),
|
|
45398
|
+
topK: tool.schema.number().describe("Maximum number of top-ranked documents to return. Actual results may be fewer depending on query relevance.").min(1).max(3).default(3)
|
|
45399
|
+
},
|
|
45400
|
+
execute: async (args, context) => {
|
|
45401
|
+
try {
|
|
45402
|
+
const results = await searchSkill(args.skill_path, args.query, args.topK);
|
|
45403
|
+
if (results.length === 0) {
|
|
45404
|
+
return "No relative items found in the skill directory.";
|
|
45405
|
+
}
|
|
45406
|
+
const info = results.map((r) => {
|
|
45407
|
+
const lines = [];
|
|
45408
|
+
lines.push(`score ${r.score.toFixed(4)}`);
|
|
45409
|
+
if (r.experience_file_path) lines.push(`- experience path: ${r.experience_file_path}`);
|
|
45410
|
+
if (r.ets_file_path) lines.push(`- sample code path: ${r.ets_file_path}`);
|
|
45411
|
+
if (r.sdk_file_path) lines.push(`- sdk info path: ${r.sdk_file_path}`);
|
|
45412
|
+
return lines.join("\n");
|
|
45413
|
+
}).join("\n\n");
|
|
45414
|
+
return `## Results
|
|
45415
|
+
|
|
45416
|
+
${info}`;
|
|
45417
|
+
} catch (e) {
|
|
45418
|
+
return `Error: ${e instanceof Error ? e.message : String(e)}`;
|
|
45419
|
+
}
|
|
45420
|
+
}
|
|
45421
|
+
});
|
|
45422
|
+
}
|
|
45423
|
+
|
|
45424
|
+
// src/tools/html-preview/html-preview-tool.ts
|
|
45425
|
+
import { access } from "fs/promises";
|
|
45426
|
+
import path7 from "path";
|
|
45427
|
+
import { fileURLToPath as fileURLToPath2, pathToFileURL } from "url";
|
|
45428
|
+
var PROTOTYPE_HTML_FILENAME = "prototype.html";
|
|
45429
|
+
function toFileUrl(filePath) {
|
|
45430
|
+
return pathToFileURL(path7.resolve(filePath)).href;
|
|
45431
|
+
}
|
|
45432
|
+
async function fileExists(filePath) {
|
|
45433
|
+
try {
|
|
45434
|
+
await access(filePath);
|
|
45435
|
+
return true;
|
|
45436
|
+
} catch {
|
|
45437
|
+
return false;
|
|
45438
|
+
}
|
|
45439
|
+
}
|
|
45440
|
+
function resolvePrototypePath(directory, input) {
|
|
45441
|
+
const trimmed = input.trim();
|
|
45442
|
+
if (!trimmed) {
|
|
45443
|
+
throw new Error("filePath is required");
|
|
45444
|
+
}
|
|
45445
|
+
if (trimmed.startsWith("file://")) {
|
|
45446
|
+
return fileURLToPath2(trimmed);
|
|
45447
|
+
}
|
|
45448
|
+
return path7.isAbsolute(trimmed) ? trimmed : path7.resolve(directory, trimmed);
|
|
45449
|
+
}
|
|
45450
|
+
async function resolvePrototypePreview(directory, filePathInput) {
|
|
45451
|
+
const filePath = resolvePrototypePath(directory, filePathInput);
|
|
45452
|
+
if (!await fileExists(filePath)) {
|
|
45453
|
+
throw new Error(
|
|
45454
|
+
`Prototype HTML not found: ${filePath}. Pass the exact local path where ${PROTOTYPE_HTML_FILENAME} was written.`
|
|
45455
|
+
);
|
|
45456
|
+
}
|
|
45457
|
+
return { url: toFileUrl(filePath), filePath };
|
|
45458
|
+
}
|
|
45459
|
+
function htmlPreviewTool(_managers) {
|
|
45460
|
+
return tool({
|
|
45461
|
+
description: "Send the UX prototype preview to the frontend. Call this immediately after writing prototype.html. You MUST pass filePath with the exact local path of the written file so the frontend can locate and preview it.",
|
|
45462
|
+
args: {
|
|
45463
|
+
filePath: tool.schema.string().describe(
|
|
45464
|
+
"Local path to prototype.html. Use the same path from the write step, e.g. prototype.html, /Users/yanqing/coding/your-project/prototype.html, or file:///.../prototype.html."
|
|
45465
|
+
),
|
|
45466
|
+
title: tool.schema.optional(tool.schema.string().describe("Title shown in the preview panel."))
|
|
45467
|
+
},
|
|
45468
|
+
execute: async (args, context) => {
|
|
45469
|
+
try {
|
|
45470
|
+
log("[html_preview]", { filePath: args.filePath, title: args.title });
|
|
45471
|
+
const { url: url3, filePath } = await resolvePrototypePreview(context.directory, args.filePath);
|
|
45472
|
+
const title = args.title?.trim() || "Prototype Preview";
|
|
45473
|
+
const metadata = {
|
|
45474
|
+
url: url3,
|
|
45475
|
+
filePath,
|
|
45476
|
+
fileName: path7.basename(filePath),
|
|
45477
|
+
title
|
|
45478
|
+
};
|
|
45479
|
+
context.metadata({
|
|
45480
|
+
title,
|
|
45481
|
+
metadata: {
|
|
45482
|
+
htmlPreview: metadata
|
|
45483
|
+
}
|
|
45484
|
+
});
|
|
45485
|
+
return [
|
|
45486
|
+
"Prototype preview sent to frontend.",
|
|
45487
|
+
`Title: ${title}`,
|
|
45488
|
+
`Local path: ${filePath}`,
|
|
45489
|
+
`Preview URL: ${url3}`
|
|
45490
|
+
].join("\n");
|
|
45491
|
+
} catch (e) {
|
|
45492
|
+
return `Error: ${e instanceof Error ? e.message : String(e)}`;
|
|
45493
|
+
}
|
|
45494
|
+
}
|
|
45495
|
+
});
|
|
45496
|
+
}
|
|
45497
|
+
|
|
45379
45498
|
// src/tools/harmony-doc/api-client.ts
|
|
45380
45499
|
var BASE_URL = "https://svc-drcn.developer.huawei.com/community/servlet";
|
|
45381
45500
|
var HEADERS = {
|
|
@@ -45578,159 +45697,6 @@ function formatUpdateTime(utcTimeStr) {
|
|
|
45578
45697
|
return `${y}-${m}-${d} ${h}:${min}`;
|
|
45579
45698
|
}
|
|
45580
45699
|
|
|
45581
|
-
// src/tools/skill-search/skill-search-tool.ts
|
|
45582
|
-
function skillSearchTool(managers) {
|
|
45583
|
-
return tool({
|
|
45584
|
-
description: "Search HarmonyOS development knowledge across BOTH local skill documents AND official Huawei documentation. Returns two sections: (1) Local Skill Results \u2014 file paths to curated code examples, best practices, and SDK API info from the harmonyos-atomic-dev skill directory; (2) Official Documentation \u2014 search results from developer.huawei.com with titles, URLs, breadcrumbs, and excerpts. Use this tool for any HarmonyOS API, component, Kit, or development pattern lookup. After reviewing results, read local skill files for code patterns and use harmony-doc-view to read full official documents by URL. IMPORTANT: This tool already searches official documentation \u2014 do NOT also call harmony-doc-view for the same purpose. Only use harmony-doc-view to read a specific document page from the URLs listed below. Each scenario only supports ONE tool call. Do NOT call this tool multiple times.",
|
|
45585
|
-
args: {
|
|
45586
|
-
skill_path: tool.schema.string().describe("The COMPLETE absolute filesystem path to the harmonyos-atomic-dev skill directory (e.g. '/home/user/.opencode/skills/harmonyos-atomic-dev'). Do NOT pass just the skill name 'harmonyos-atomic-dev' \u2014 you MUST resolve and provide the full absolute path. Do NOT include any prefix like 'file://' or suffix like 'SKILL.md' or 'index.json'."),
|
|
45587
|
-
query: tool.schema.string().describe("A decomposed requirement or intent describing what you want to find, broken down into searchable keywords separated by spaces. QUERY TIPS: For best results, decompose your intent into short space-separated keywords instead of long sentences. Include: 1) Kit or component name (e.g. ScanKit, AdsKit, ShareKit), 2) specific API or method names (e.g. scanBarcode, loadAd, ShareController), 3) feature keywords (e.g. \u626B\u7801, \u5E7F\u544A\u52A0\u8F7D, \u5206\u4EAB). Example: 'ScanKit \u626B\u7801 scanBarcode startScanForResult' instead of '\u5E2E\u6211\u5B9E\u73B0\u4E00\u4E2A\u626B\u7801\u529F\u80FD'."),
|
|
45588
|
-
topK: tool.schema.number().describe("Maximum number of top-ranked documents to return. Actual results may be fewer depending on query relevance.").min(1).max(3).default(3)
|
|
45589
|
-
},
|
|
45590
|
-
execute: async (args, context) => {
|
|
45591
|
-
const [localResults, docResults] = await Promise.all([
|
|
45592
|
-
searchSkill(args.skill_path, args.query, args.topK).catch(
|
|
45593
|
-
(e) => new Error(`Local search failed: ${e instanceof Error ? e.message : String(e)}`)
|
|
45594
|
-
),
|
|
45595
|
-
searchDocs(args.query, 5).catch(
|
|
45596
|
-
(e) => new Error(`Doc search failed: ${e instanceof Error ? e.message : String(e)}`)
|
|
45597
|
-
)
|
|
45598
|
-
]);
|
|
45599
|
-
const parts = [];
|
|
45600
|
-
if (localResults instanceof Error) {
|
|
45601
|
-
parts.push(`## Local Skill Results
|
|
45602
|
-
|
|
45603
|
-
${localResults.message}`);
|
|
45604
|
-
} else if (localResults.length === 0) {
|
|
45605
|
-
parts.push("## Local Skill Results\n\nNo matching skill documents found.");
|
|
45606
|
-
} else {
|
|
45607
|
-
const localInfo = localResults.map((r) => {
|
|
45608
|
-
const lines = [];
|
|
45609
|
-
lines.push(`score ${r.score.toFixed(4)}`);
|
|
45610
|
-
if (r.experience_file_path) lines.push(`- experience path: ${r.experience_file_path}`);
|
|
45611
|
-
if (r.ets_file_path) lines.push(`- sample code path: ${r.ets_file_path}`);
|
|
45612
|
-
if (r.sdk_file_path) lines.push(`- sdk info path: ${r.sdk_file_path}`);
|
|
45613
|
-
return lines.join("\n");
|
|
45614
|
-
}).join("\n\n");
|
|
45615
|
-
parts.push(`## Local Skill Results
|
|
45616
|
-
|
|
45617
|
-
${localInfo}`);
|
|
45618
|
-
}
|
|
45619
|
-
if (docResults instanceof Error) {
|
|
45620
|
-
parts.push(`## Official Documentation
|
|
45621
|
-
|
|
45622
|
-
${docResults.message}`);
|
|
45623
|
-
} else if (docResults.length === 0) {
|
|
45624
|
-
parts.push("## Official Documentation\n\nNo matching official documents found.");
|
|
45625
|
-
} else {
|
|
45626
|
-
const docInfo = docResults.map((r, i) => {
|
|
45627
|
-
const lines = [];
|
|
45628
|
-
let title = r.title;
|
|
45629
|
-
if (r.subsection && r.subsection !== r.title) {
|
|
45630
|
-
title += ` #${r.subsection}`;
|
|
45631
|
-
}
|
|
45632
|
-
lines.push(`${i + 1}. **${title}**`);
|
|
45633
|
-
let displayUrl = r.url;
|
|
45634
|
-
if (r.anchorId) {
|
|
45635
|
-
displayUrl += `#${r.anchorId}`;
|
|
45636
|
-
}
|
|
45637
|
-
lines.push(` URL: ${displayUrl}`);
|
|
45638
|
-
if (r.excerpt) {
|
|
45639
|
-
const suffix = r.excerptTruncated ? "..." : "";
|
|
45640
|
-
lines.push(` ${r.excerpt}${suffix}`);
|
|
45641
|
-
}
|
|
45642
|
-
if (r.breadcrumb.length > 0) {
|
|
45643
|
-
lines.push(` \u6765\u81EA: ${r.breadcrumb.join(" > ")}`);
|
|
45644
|
-
}
|
|
45645
|
-
return lines.join("\n");
|
|
45646
|
-
}).join("\n\n");
|
|
45647
|
-
parts.push(
|
|
45648
|
-
`## Official Documentation
|
|
45649
|
-
|
|
45650
|
-
${docInfo}
|
|
45651
|
-
|
|
45652
|
-
Use harmony-doc-view with a URL above to read any official document in full.`
|
|
45653
|
-
);
|
|
45654
|
-
}
|
|
45655
|
-
return parts.join("\n\n");
|
|
45656
|
-
}
|
|
45657
|
-
});
|
|
45658
|
-
}
|
|
45659
|
-
|
|
45660
|
-
// src/tools/html-preview/html-preview-tool.ts
|
|
45661
|
-
import { access } from "fs/promises";
|
|
45662
|
-
import path7 from "path";
|
|
45663
|
-
import { fileURLToPath as fileURLToPath2, pathToFileURL } from "url";
|
|
45664
|
-
var PROTOTYPE_HTML_FILENAME = "prototype.html";
|
|
45665
|
-
function toFileUrl(filePath) {
|
|
45666
|
-
return pathToFileURL(path7.resolve(filePath)).href;
|
|
45667
|
-
}
|
|
45668
|
-
async function fileExists(filePath) {
|
|
45669
|
-
try {
|
|
45670
|
-
await access(filePath);
|
|
45671
|
-
return true;
|
|
45672
|
-
} catch {
|
|
45673
|
-
return false;
|
|
45674
|
-
}
|
|
45675
|
-
}
|
|
45676
|
-
function resolvePrototypePath(directory, input) {
|
|
45677
|
-
const trimmed = input.trim();
|
|
45678
|
-
if (!trimmed) {
|
|
45679
|
-
throw new Error("filePath is required");
|
|
45680
|
-
}
|
|
45681
|
-
if (trimmed.startsWith("file://")) {
|
|
45682
|
-
return fileURLToPath2(trimmed);
|
|
45683
|
-
}
|
|
45684
|
-
return path7.isAbsolute(trimmed) ? trimmed : path7.resolve(directory, trimmed);
|
|
45685
|
-
}
|
|
45686
|
-
async function resolvePrototypePreview(directory, filePathInput) {
|
|
45687
|
-
const filePath = resolvePrototypePath(directory, filePathInput);
|
|
45688
|
-
if (!await fileExists(filePath)) {
|
|
45689
|
-
throw new Error(
|
|
45690
|
-
`Prototype HTML not found: ${filePath}. Pass the exact local path where ${PROTOTYPE_HTML_FILENAME} was written.`
|
|
45691
|
-
);
|
|
45692
|
-
}
|
|
45693
|
-
return { url: toFileUrl(filePath), filePath };
|
|
45694
|
-
}
|
|
45695
|
-
function htmlPreviewTool(_managers) {
|
|
45696
|
-
return tool({
|
|
45697
|
-
description: "Send the UX prototype preview to the frontend. Call this immediately after writing prototype.html. You MUST pass filePath with the exact local path of the written file so the frontend can locate and preview it.",
|
|
45698
|
-
args: {
|
|
45699
|
-
filePath: tool.schema.string().describe("Local path to prototype.html. Use the same path from the write step, e.g. prototype.html, /Users/yanqing/coding/your-project/prototype.html, or file:///.../prototype.html."),
|
|
45700
|
-
title: tool.schema.optional(
|
|
45701
|
-
tool.schema.string().describe("Optional title shown in the preview panel")
|
|
45702
|
-
)
|
|
45703
|
-
},
|
|
45704
|
-
execute: async (args, context) => {
|
|
45705
|
-
try {
|
|
45706
|
-
log("[html_preview]", { filePath: args.filePath, title: args.title });
|
|
45707
|
-
const { url: url3, filePath } = await resolvePrototypePreview(context.directory, args.filePath);
|
|
45708
|
-
const title = args.title?.trim() || "Prototype Preview";
|
|
45709
|
-
const metadata = {
|
|
45710
|
-
url: url3,
|
|
45711
|
-
filePath,
|
|
45712
|
-
fileName: path7.basename(filePath),
|
|
45713
|
-
title
|
|
45714
|
-
};
|
|
45715
|
-
context.metadata({
|
|
45716
|
-
title,
|
|
45717
|
-
metadata: {
|
|
45718
|
-
htmlPreview: metadata
|
|
45719
|
-
}
|
|
45720
|
-
});
|
|
45721
|
-
return [
|
|
45722
|
-
"Prototype preview sent to frontend.",
|
|
45723
|
-
`Title: ${title}`,
|
|
45724
|
-
`Local path: ${filePath}`,
|
|
45725
|
-
`Preview URL: ${url3}`
|
|
45726
|
-
].join("\n");
|
|
45727
|
-
} catch (e) {
|
|
45728
|
-
return `Error: ${e instanceof Error ? e.message : String(e)}`;
|
|
45729
|
-
}
|
|
45730
|
-
}
|
|
45731
|
-
});
|
|
45732
|
-
}
|
|
45733
|
-
|
|
45734
45700
|
// node_modules/turndown/lib/turndown.es.js
|
|
45735
45701
|
function extend3(destination) {
|
|
45736
45702
|
for (var i = 1; i < arguments.length; i++) {
|
|
@@ -46781,7 +46747,7 @@ function cleanupMarkdown(md) {
|
|
|
46781
46747
|
return out.trim();
|
|
46782
46748
|
}
|
|
46783
46749
|
|
|
46784
|
-
// src/tools/harmony-doc/harmony-doc-tool.ts
|
|
46750
|
+
// src/tools/harmony-doc/harmony-doc-view-tool.ts
|
|
46785
46751
|
var docCache = /* @__PURE__ */ new Map();
|
|
46786
46752
|
var CACHE_TTL = 10 * 60 * 1e3;
|
|
46787
46753
|
function getCached(objectId) {
|
|
@@ -46798,9 +46764,9 @@ function setCache(objectId, doc, markdown, breadcrumb) {
|
|
|
46798
46764
|
}
|
|
46799
46765
|
function harmonyDocViewTool(_managers) {
|
|
46800
46766
|
return tool({
|
|
46801
|
-
description: "View a HarmonyOS official documentation page by URL with full Markdown content and pagination. Use this tool to read official API references, guides, and best practices from developer.huawei.com. Typically used with URLs obtained from
|
|
46767
|
+
description: "View a HarmonyOS official documentation page by URL with full Markdown content and pagination. Use this tool to read official API references, guides, and best practices from developer.huawei.com. Typically used with URLs obtained from harmony-doc-search results. Supports pagination for long documents \u2014 use the 'page' parameter to continue reading.",
|
|
46802
46768
|
args: {
|
|
46803
|
-
url: tool.schema.string().describe("Full URL of the document to view. Must be a developer.huawei.com URL
|
|
46769
|
+
url: tool.schema.string().describe("Full URL of the document to view. Must be a developer.huawei.com URL."),
|
|
46804
46770
|
page: tool.schema.number().describe("Page number for long documents. Starts at 1.").min(1).default(1)
|
|
46805
46771
|
},
|
|
46806
46772
|
execute: async (args, _context) => {
|
|
@@ -46899,13 +46865,67 @@ Source: ${url3}
|
|
|
46899
46865
|
}
|
|
46900
46866
|
}
|
|
46901
46867
|
|
|
46868
|
+
// src/tools/harmony-doc/harmony-doc-search-tool.ts
|
|
46869
|
+
var DEFAULT_SEARCH_COUNT = 5;
|
|
46870
|
+
function harmonyDocSearchTool(_managers) {
|
|
46871
|
+
return tool({
|
|
46872
|
+
description: "Search official HarmonyOS documentation from developer.huawei.com. This tool requires network access and takes several seconds to respond. Covers any HarmonyOS-related knowledge: API references, Kit capabilities, ArkUI components, ArkTS syntax, development guides, best practices, error codes, migration guides, sample code references. IMPORTANT: Use concise keywords for best results \u2014 fewer words = more precise matches. Example: 'ScanKit scanBarcode' instead of 'how to implement barcode scanning with ScanKit'. After reviewing results, use harmony-doc-view to read any document in full by URL.",
|
|
46873
|
+
args: {
|
|
46874
|
+
keyword: tool.schema.string().describe(
|
|
46875
|
+
"Concise search keyword for official HarmonyOS documentation. Keep it short and specific \u2014 prefer 1-3 keywords over long sentences. Supports any HarmonyOS-related query: Kit/Component names (ScanKit, AdsKit, List, Column), API names (scanBarcode, ShareController, @State, @Prop), ArkTS syntax (@Entry, @Builder, @Extend), feature keywords (\u626B\u7801, \u5E7F\u544A, \u5206\u4EAB, \u52A8\u753B, \u7F51\u7EDC\u8BF7\u6C42), error codes, migration topics, or any development concept."
|
|
46876
|
+
)
|
|
46877
|
+
},
|
|
46878
|
+
execute: async (args, _context) => {
|
|
46879
|
+
const docResults = await searchDocs(
|
|
46880
|
+
args.keyword,
|
|
46881
|
+
DEFAULT_SEARCH_COUNT
|
|
46882
|
+
).catch(
|
|
46883
|
+
(e) => new Error(
|
|
46884
|
+
`Doc search failed: ${e instanceof Error ? e.message : String(e)}`
|
|
46885
|
+
)
|
|
46886
|
+
);
|
|
46887
|
+
if (docResults instanceof Error) {
|
|
46888
|
+
return docResults.message;
|
|
46889
|
+
}
|
|
46890
|
+
if (docResults.length === 0) {
|
|
46891
|
+
return `No matching official documents found for "${args.keyword}".`;
|
|
46892
|
+
}
|
|
46893
|
+
const docInfo = docResults.map((r, i) => {
|
|
46894
|
+
const lines = [];
|
|
46895
|
+
let title = r.title;
|
|
46896
|
+
if (r.subsection && r.subsection !== r.title) {
|
|
46897
|
+
title += ` #${r.subsection}`;
|
|
46898
|
+
}
|
|
46899
|
+
lines.push(`${i + 1}. **${title}**`);
|
|
46900
|
+
let displayUrl = r.url;
|
|
46901
|
+
if (r.anchorId) {
|
|
46902
|
+
displayUrl += `#${r.anchorId}`;
|
|
46903
|
+
}
|
|
46904
|
+
lines.push(` URL: ${displayUrl}`);
|
|
46905
|
+
if (r.excerpt) {
|
|
46906
|
+
const suffix = r.excerptTruncated ? "..." : "";
|
|
46907
|
+
lines.push(` ${r.excerpt}${suffix}`);
|
|
46908
|
+
}
|
|
46909
|
+
if (r.breadcrumb.length > 0) {
|
|
46910
|
+
lines.push(` \u6765\u81EA: ${r.breadcrumb.join(" > ")}`);
|
|
46911
|
+
}
|
|
46912
|
+
return lines.join("\n");
|
|
46913
|
+
}).join("\n\n");
|
|
46914
|
+
return `${docInfo}
|
|
46915
|
+
|
|
46916
|
+
Use harmony-doc-view with a URL above to read any official document in full.`;
|
|
46917
|
+
}
|
|
46918
|
+
});
|
|
46919
|
+
}
|
|
46920
|
+
|
|
46902
46921
|
// src/tools/builtin.ts
|
|
46903
46922
|
function createBuiltinTools(managers) {
|
|
46904
46923
|
return {
|
|
46905
46924
|
createHmTemplate: createHmTemplateTool(managers),
|
|
46906
46925
|
skillSearch: skillSearchTool(managers),
|
|
46907
46926
|
html_preview: htmlPreviewTool(managers),
|
|
46908
|
-
"harmony-doc-view": harmonyDocViewTool(managers)
|
|
46927
|
+
"harmony-doc-view": harmonyDocViewTool(managers),
|
|
46928
|
+
"harmony-doc-search": harmonyDocSearchTool(managers)
|
|
46909
46929
|
};
|
|
46910
46930
|
}
|
|
46911
46931
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "@harmonyos-arkts/opencode-plugin",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.20-beta",
|
|
5
5
|
"description": "HarmonyOS Full-Lifecycle Development Assistant. Specialized in the complete development lifecycle of HarmonyOS applications, including project creation, UI development, state management, network requests, data storage, permission requests, performance optimization, testing, and release.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"license": "MIT",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"ArkTs"
|
|
31
31
|
],
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"@opencode-ai/sdk": "
|
|
33
|
+
"@opencode-ai/sdk": "1.15.1",
|
|
34
34
|
"diff": "7.0.0",
|
|
35
35
|
"env-paths": "4.0.0",
|
|
36
36
|
"jsonc-parser": "3.3.1",
|