@harmonyos-arkts/opencode-plugin 0.0.13 → 0.0.14
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/index.js +54 -67
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -31452,31 +31452,28 @@ import path2 from "path";
|
|
|
31452
31452
|
import fs from "fs/promises";
|
|
31453
31453
|
import os2 from "os";
|
|
31454
31454
|
var paths = envPaths("hm-plugin");
|
|
31455
|
-
var
|
|
31456
|
-
|
|
31457
|
-
|
|
31458
|
-
|
|
31459
|
-
|
|
31460
|
-
|
|
31461
|
-
|
|
31462
|
-
|
|
31463
|
-
|
|
31464
|
-
|
|
31465
|
-
|
|
31466
|
-
|
|
31467
|
-
state: paths.data
|
|
31468
|
-
};
|
|
31469
|
-
})(HMGlobal || (HMGlobal = {}));
|
|
31455
|
+
var Path = {
|
|
31456
|
+
// Allow override via OPENCODE_TEST_HOME for test isolation
|
|
31457
|
+
get home() {
|
|
31458
|
+
return process.env.OPENCODE_TEST_HOME || os2.homedir();
|
|
31459
|
+
},
|
|
31460
|
+
data: paths.data,
|
|
31461
|
+
bin: path2.join(paths.data, "bin"),
|
|
31462
|
+
log: paths.log,
|
|
31463
|
+
cache: paths.cache,
|
|
31464
|
+
config: paths.config,
|
|
31465
|
+
state: paths.data
|
|
31466
|
+
};
|
|
31470
31467
|
await Promise.all([
|
|
31471
|
-
fs.mkdir(
|
|
31472
|
-
fs.mkdir(
|
|
31473
|
-
fs.mkdir(
|
|
31474
|
-
fs.mkdir(
|
|
31475
|
-
fs.mkdir(
|
|
31468
|
+
fs.mkdir(Path.data, { recursive: true }),
|
|
31469
|
+
fs.mkdir(Path.config, { recursive: true }),
|
|
31470
|
+
fs.mkdir(Path.state, { recursive: true }),
|
|
31471
|
+
fs.mkdir(Path.log, { recursive: true }),
|
|
31472
|
+
fs.mkdir(Path.bin, { recursive: true })
|
|
31476
31473
|
]);
|
|
31477
31474
|
|
|
31478
31475
|
// src/shared/log.ts
|
|
31479
|
-
var logFile = path3.join(
|
|
31476
|
+
var logFile = path3.join(Path.log, "plugin.log");
|
|
31480
31477
|
var logDir = path3.dirname(logFile);
|
|
31481
31478
|
var MAX_LOG_SIZE_BYTES = 5 * 1024 * 1024;
|
|
31482
31479
|
var MAX_LOG_AGE_DAYS = 7;
|
|
@@ -31568,7 +31565,7 @@ cleanupRotatedLogs();
|
|
|
31568
31565
|
|
|
31569
31566
|
// src/agents/prompt.ts
|
|
31570
31567
|
var HM_DESIGN = `
|
|
31571
|
-
###
|
|
31568
|
+
### Design Phase
|
|
31572
31569
|
- Use the \`harmonyos-prd-design\` skill to create prd desgin documents
|
|
31573
31570
|
- Reference design patterns and best practices from the skill documentation
|
|
31574
31571
|
- Design documents should be stored in the project's \`.harmonyos/\` directory
|
|
@@ -31734,33 +31731,29 @@ function buildPlanPrompt(type) {
|
|
|
31734
31731
|
}
|
|
31735
31732
|
}
|
|
31736
31733
|
function buildAllAgentPrompt() {
|
|
31737
|
-
return
|
|
31734
|
+
return `- **New project (greenfield)**: Design \u2192 Development \u2192 Build. Do not skip the design phase, as it is critical for planning and architectural decisions.
|
|
31735
|
+
- **Complex tasks**: List a plan \u2192 Discuss plan details with the user if needed \u2192 Development \u2192 Build.
|
|
31736
|
+
- **Simple tasks**: Development \u2192 Build directly.
|
|
31737
|
+
|
|
31738
|
+
Each phase has its own set of best practices and workflows to ensure efficient and successful project completion.
|
|
31739
|
+
|
|
31738
31740
|
${HM_DESIGN}
|
|
31739
31741
|
${HM_DEVELOP}
|
|
31740
31742
|
${HM_BUILD}
|
|
31741
|
-
|
|
31742
|
-
Follow these workflows:
|
|
31743
|
-
- **New project (greenfield)**: PRD Design \u2192 Development \u2192 Build.
|
|
31744
|
-
- **Complex tasks**: List a plan \u2192 Discuss plan details with the user if needed \u2192 Development \u2192 Build.
|
|
31745
|
-
- **Simple tasks**: Development \u2192 Build directly.
|
|
31746
31743
|
`;
|
|
31747
31744
|
}
|
|
31748
31745
|
function buildHmAgentPrompt(type) {
|
|
31749
31746
|
return `You are HarmonyOS Dev Assistant(HDACode), an expert coding agent specialized in HarmonyOS development.
|
|
31750
|
-
|
|
31751
31747
|
You are an interactive CLI tool that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user.
|
|
31752
|
-
|
|
31753
31748
|
IMPORTANT: You must NEVER generate or guess URLs for the user unless you are confident that the URLs are for helping the user with programming. You may use URLs provided by the user in their messages or local files.
|
|
31754
|
-
|
|
31755
31749
|
When the user directly asks about HDACode (eg. "can HDACode do...", "does HDACode have..."), or asks in second person (eg. "are you able...", "can you do..."), or asks how to use a specific HDACode feature (eg. implement a hook, write a slash command, or install an MCP server), use the WebFetch tool to gather information to answer the question from HDACode docs.
|
|
31756
|
-
|
|
31757
31750
|
**IMPORTANT**: All HarmonyOS development tasks must follow these workflows:
|
|
31758
31751
|
|
|
31759
31752
|
${buildPlanPrompt(type)}
|
|
31760
31753
|
|
|
31761
31754
|
# Tone and style
|
|
31762
31755
|
- Only use emojis if the user explicitly requests it. Avoid using emojis in all communication unless asked.
|
|
31763
|
-
-
|
|
31756
|
+
- You MUST reply in Chinese (\u7B80\u4F53\u4E2D\u6587) at all times; code, technical identifiers, and file paths are excluded from this rule.
|
|
31764
31757
|
- Your output will be displayed on a command line interface. You can use GitHub-flavored markdown for formatting, and will be rendered in a monospace font using the CommonMark specification.
|
|
31765
31758
|
- Keep your responses brief and direct. Lead with the answer or action, not the reasoning. Skip preamble and postamble (e.g., "The answer is...", "Based on the information provided..."). Only elaborate when the user asks for detail.
|
|
31766
31759
|
- Output text to communicate with the user; all text you output outside of tool use is displayed to the user. Only use tools to complete tasks. Never use tools like Bash or code comments as means to communicate with the user during the session.
|
|
@@ -31797,24 +31790,6 @@ The first item has been fixed, let me mark the first todo as completed, and move
|
|
|
31797
31790
|
</example>
|
|
31798
31791
|
In the above example, the assistant completes all the tasks, including the 10 error fixes and running the build and fixing all errors.
|
|
31799
31792
|
|
|
31800
|
-
<example>
|
|
31801
|
-
user: Help me write a new feature that allows users to track their usage metrics and export them to various formats
|
|
31802
|
-
assistant: I'll help you implement a usage metrics tracking and export feature. Let me first use the TodoWrite tool to plan this task.
|
|
31803
|
-
Adding the following todos to the todo list:
|
|
31804
|
-
1. Research existing metrics tracking in the codebase
|
|
31805
|
-
2. Design the metrics collection system
|
|
31806
|
-
3. Implement core metrics tracking functionality
|
|
31807
|
-
4. Create export functionality for different formats
|
|
31808
|
-
|
|
31809
|
-
Let me start by researching the existing codebase to understand what metrics we might already be tracking and how we can build on that.
|
|
31810
|
-
|
|
31811
|
-
I'm going to search for any existing metrics or telemetry code in the project.
|
|
31812
|
-
|
|
31813
|
-
I've found some existing telemetry code. Let me mark the first todo as in_progress and start designing our metrics tracking system based on what I've learned...
|
|
31814
|
-
|
|
31815
|
-
[Assistant continues implementing the feature step by step, marking todos as in_progress and completed as they go]
|
|
31816
|
-
</example>
|
|
31817
|
-
|
|
31818
31793
|
|
|
31819
31794
|
# Doing tasks
|
|
31820
31795
|
The user will primarily request you perform software engineering tasks. This includes solving bugs, adding new functionality, refactoring code, explaining code, and more. For these tasks the following steps are recommended:
|
|
@@ -44631,7 +44606,7 @@ function tool(input) {
|
|
|
44631
44606
|
tool.schema = external_exports2;
|
|
44632
44607
|
|
|
44633
44608
|
// src/tools/create-template/download-template.ts
|
|
44634
|
-
import { cpSync,
|
|
44609
|
+
import { cpSync, existsSync } from "fs";
|
|
44635
44610
|
import path6 from "path";
|
|
44636
44611
|
import { fileURLToPath } from "url";
|
|
44637
44612
|
|
|
@@ -44721,7 +44696,9 @@ async function downloadTemplate(mode, filePath) {
|
|
|
44721
44696
|
}
|
|
44722
44697
|
const targetDir = path6.resolve(filePath);
|
|
44723
44698
|
const templateDir = path6.join(__dirname, "templates", templateType);
|
|
44724
|
-
|
|
44699
|
+
if (!existsSync(targetDir)) {
|
|
44700
|
+
throw new Error(`Directory does not exist: ${targetDir}. Please create it first.`);
|
|
44701
|
+
}
|
|
44725
44702
|
cpSync(templateDir, targetDir, { recursive: true });
|
|
44726
44703
|
const sdkInfo = getSdkVersion();
|
|
44727
44704
|
if (sdkInfo) {
|
|
@@ -44836,15 +44813,15 @@ async function updateEtsCache(sessionManager, sessionID, directory) {
|
|
|
44836
44813
|
var CHECK_ETS_TEMPLATE_MODES = /* @__PURE__ */ new Set(["atomic", "application"]);
|
|
44837
44814
|
function createHmTemplateTool(managers) {
|
|
44838
44815
|
return tool({
|
|
44839
|
-
description: "Create an empty HarmonyOS project template. Supports three modes: 'application' (full app), 'module' (sub-module), 'atomic' (atomic service).
|
|
44816
|
+
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.",
|
|
44840
44817
|
args: {
|
|
44841
|
-
filePath: tool.schema.string("Absolute path of the target directory where the template will be created"),
|
|
44818
|
+
filePath: tool.schema.string("Absolute path of the target directory where the template will be created. Defaults to the current working directory if not specified."),
|
|
44842
44819
|
mode: tool.schema.string("Template type: 'application' (\u5E94\u7528), 'module' (\u6A21\u5757), or 'atomic' (\u5143\u670D\u52A1)")
|
|
44843
44820
|
},
|
|
44844
44821
|
execute: async (args, context) => {
|
|
44845
44822
|
try {
|
|
44846
44823
|
if (CHECK_ETS_TEMPLATE_MODES.has(args.mode)) {
|
|
44847
|
-
const fileCount = await checkEtsExists(
|
|
44824
|
+
const fileCount = await checkEtsExists(args.filePath);
|
|
44848
44825
|
if (fileCount > 0) {
|
|
44849
44826
|
log("[createHmTemplate] skipped, ets files exist", { fileCount });
|
|
44850
44827
|
return `Skipped: Current directory already contains ${fileCount} .ets file(s). Template download is not needed.`;
|
|
@@ -44861,7 +44838,7 @@ function createHmTemplateTool(managers) {
|
|
|
44861
44838
|
}
|
|
44862
44839
|
|
|
44863
44840
|
// src/tools/skill-search/search-skill.ts
|
|
44864
|
-
import { readFileSync, existsSync } from "node:fs";
|
|
44841
|
+
import { readFileSync, existsSync as existsSync2 } from "node:fs";
|
|
44865
44842
|
import { join as join4 } from "node:path";
|
|
44866
44843
|
|
|
44867
44844
|
// src/tools/skill-search/tokenizer.ts
|
|
@@ -44896,7 +44873,10 @@ function tokenize(text) {
|
|
|
44896
44873
|
var BM25Retriever = class {
|
|
44897
44874
|
k1;
|
|
44898
44875
|
b;
|
|
44899
|
-
|
|
44876
|
+
_documents = [];
|
|
44877
|
+
get documents() {
|
|
44878
|
+
return this._documents;
|
|
44879
|
+
}
|
|
44900
44880
|
tokenizedDocs = [];
|
|
44901
44881
|
df = /* @__PURE__ */ new Map();
|
|
44902
44882
|
tfMaps = [];
|
|
@@ -44906,7 +44886,7 @@ var BM25Retriever = class {
|
|
|
44906
44886
|
this.b = opts?.b ?? 0.75;
|
|
44907
44887
|
}
|
|
44908
44888
|
addDocuments(docs, tokenized) {
|
|
44909
|
-
this.
|
|
44889
|
+
this._documents = [...this._documents, ...docs];
|
|
44910
44890
|
this.tokenizedDocs = [...this.tokenizedDocs, ...tokenized];
|
|
44911
44891
|
const totalLen = this.tokenizedDocs.reduce(
|
|
44912
44892
|
(sum, doc) => sum + doc.length,
|
|
@@ -44991,12 +44971,12 @@ var HybridRetriever = class {
|
|
|
44991
44971
|
this.keyword.addDocuments(docs, tokenized);
|
|
44992
44972
|
}
|
|
44993
44973
|
search(query, topK = 5) {
|
|
44994
|
-
if (this.bm25
|
|
44974
|
+
if (this.bm25.documents.length === 0) return [];
|
|
44995
44975
|
const poolSize = topK * 3;
|
|
44996
44976
|
const bm25Results = this.bm25.search(query, poolSize);
|
|
44997
44977
|
const keywordResults = this.keyword.search(query, poolSize);
|
|
44998
44978
|
const rrfK = 60;
|
|
44999
|
-
const documents = this.bm25
|
|
44979
|
+
const documents = this.bm25.documents;
|
|
45000
44980
|
const scores = /* @__PURE__ */ new Map();
|
|
45001
44981
|
for (let rank = 0; rank < bm25Results.length; rank++) {
|
|
45002
44982
|
const idx = bm25Results[rank].index;
|
|
@@ -45227,7 +45207,7 @@ async function loadAndCache(resolvedPath) {
|
|
|
45227
45207
|
log("start load sdk cache", sdk_path);
|
|
45228
45208
|
if (sdk_path !== void 0) {
|
|
45229
45209
|
const sdkIndexPath = join4(import.meta.dirname, "sdk-index.json");
|
|
45230
|
-
if (!
|
|
45210
|
+
if (!existsSync2(sdkIndexPath)) {
|
|
45231
45211
|
log("sdk path is not exist, need to build");
|
|
45232
45212
|
await buildSDKIndex(sdk_path);
|
|
45233
45213
|
}
|
|
@@ -45254,7 +45234,7 @@ async function loadAndCache(resolvedPath) {
|
|
|
45254
45234
|
function loadSdkIndex() {
|
|
45255
45235
|
if (cachedSdkRetriever) return true;
|
|
45256
45236
|
const sdkIndexPath = join4(import.meta.dirname, "sdk-index.json");
|
|
45257
|
-
if (!
|
|
45237
|
+
if (!existsSync2(sdkIndexPath)) return false;
|
|
45258
45238
|
try {
|
|
45259
45239
|
const raw = readFileSync(sdkIndexPath, "utf-8");
|
|
45260
45240
|
const entries = JSON.parse(raw);
|
|
@@ -45286,7 +45266,8 @@ async function searchSkill(skill_path, query, topK = 3) {
|
|
|
45286
45266
|
preFiltered.push({
|
|
45287
45267
|
ets_file_path: "",
|
|
45288
45268
|
experience_file_path: join4(prefix, entry.path),
|
|
45289
|
-
sdk_file_path: ""
|
|
45269
|
+
sdk_file_path: "",
|
|
45270
|
+
score: 0
|
|
45290
45271
|
});
|
|
45291
45272
|
query = (query.slice(0, idx) + query.slice(idx + category.length)).trim();
|
|
45292
45273
|
}
|
|
@@ -45298,7 +45279,8 @@ async function searchSkill(skill_path, query, topK = 3) {
|
|
|
45298
45279
|
const sdkResults = loadSdkIndex() ? cachedSdkRetriever.search(query, topK).filter((r) => r.score >= MIN_SCORE).map((r) => ({
|
|
45299
45280
|
ets_file_path: "",
|
|
45300
45281
|
experience_file_path: "",
|
|
45301
|
-
sdk_file_path: cachedSdkEntries[r.index].path
|
|
45282
|
+
sdk_file_path: cachedSdkEntries[r.index].path,
|
|
45283
|
+
score: r.score
|
|
45302
45284
|
})) : [];
|
|
45303
45285
|
const searchResults = cachedRetriever.search(query, topK);
|
|
45304
45286
|
const filtered = searchResults.filter((r) => r.score >= MIN_SCORE);
|
|
@@ -45314,6 +45296,9 @@ function aggregateByExperience(results) {
|
|
|
45314
45296
|
if (r.ets_file_path) {
|
|
45315
45297
|
existing.ets_file_path = existing.ets_file_path ? existing.ets_file_path + "\n" + r.ets_file_path : r.ets_file_path;
|
|
45316
45298
|
}
|
|
45299
|
+
if (r.score > existing.score) {
|
|
45300
|
+
existing.score = r.score;
|
|
45301
|
+
}
|
|
45317
45302
|
} else {
|
|
45318
45303
|
map3.set(key, { ...r });
|
|
45319
45304
|
}
|
|
@@ -45329,7 +45314,8 @@ function convert_search_result(searchResults, prefix) {
|
|
|
45329
45314
|
return {
|
|
45330
45315
|
ets_file_path: join4(prefix, entry.path),
|
|
45331
45316
|
experience_file_path: experience?.path ? join4(prefix, experience.path) : "",
|
|
45332
|
-
sdk_file_path: ""
|
|
45317
|
+
sdk_file_path: "",
|
|
45318
|
+
score: result.score
|
|
45333
45319
|
};
|
|
45334
45320
|
});
|
|
45335
45321
|
}
|
|
@@ -45564,6 +45550,7 @@ ${localResults.message}`);
|
|
|
45564
45550
|
} else {
|
|
45565
45551
|
const localInfo = localResults.map((r) => {
|
|
45566
45552
|
const lines = [];
|
|
45553
|
+
lines.push(`score ${r.score.toFixed(4)}`);
|
|
45567
45554
|
if (r.experience_file_path) lines.push(`- experience path: ${r.experience_file_path}`);
|
|
45568
45555
|
if (r.ets_file_path) lines.push(`- sample code path: ${r.ets_file_path}`);
|
|
45569
45556
|
if (r.sdk_file_path) lines.push(`- sdk info path: ${r.sdk_file_path}`);
|
|
@@ -47677,7 +47664,7 @@ function createHooks(args) {
|
|
|
47677
47664
|
["tool.execute.before", () => toolHooks["tool.execute.before"]],
|
|
47678
47665
|
["tool.execute.after", () => toolHooks["tool.execute.after"]],
|
|
47679
47666
|
["command.execute.before", () => commandHooks["command.execute.before"]],
|
|
47680
|
-
["event", () => sessionHooks
|
|
47667
|
+
["event", () => sessionHooks.event],
|
|
47681
47668
|
["chat.params", () => createChatParamsHandler(config3)],
|
|
47682
47669
|
["chat.message", () => createChatMessageHandler(ctx, managers)]
|
|
47683
47670
|
];
|
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.14",
|
|
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",
|