@harmonyos-arkts/opencode-plugin 0.0.7 → 0.0.8
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
CHANGED
|
@@ -14836,7 +14836,9 @@ function scheduleFlush() {
|
|
|
14836
14836
|
}
|
|
14837
14837
|
function log(message, data) {
|
|
14838
14838
|
try {
|
|
14839
|
-
const
|
|
14839
|
+
const now = /* @__PURE__ */ new Date();
|
|
14840
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
14841
|
+
const timestamp = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}T${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}`;
|
|
14840
14842
|
const logEntry = `[${timestamp}] ${message} ${data ? JSON.stringify(data) : ""}
|
|
14841
14843
|
`;
|
|
14842
14844
|
buffer.push(logEntry);
|
|
@@ -14860,7 +14862,7 @@ var HM_DEVELOP = `
|
|
|
14860
14862
|
### Development Phase
|
|
14861
14863
|
- Use the \`harmonyos-atomic-dev\` skill to implement features according to the design document for harmonyos atomic service
|
|
14862
14864
|
- Use the \`harmonyos-atomic-dev\` skill to fix issues and modify function in current projects
|
|
14863
|
-
- Use the createHmTemplate tool to create empty applicaiton\u3001module\u3001atomic.
|
|
14865
|
+
- Use the createHmTemplate tool to create empty applicaiton\u3001module\u3001atomic.
|
|
14864
14866
|
- Use the \`.harmonyos/\` file (*.md\u3001*.html) as references to generate
|
|
14865
14867
|
- After completing development, you MUST proceed to the Build phase
|
|
14866
14868
|
- **NO EXCEPTIONS**: Code must be built successfully before marking development as complete
|
|
@@ -15023,8 +15025,8 @@ ${HM_BUILD}
|
|
|
15023
15025
|
|
|
15024
15026
|
Follow these workflows:
|
|
15025
15027
|
- **New project (greenfield)**: PRD Design \u2192 Development \u2192 Build.
|
|
15026
|
-
- **
|
|
15027
|
-
- **
|
|
15028
|
+
- **Complex tasks**: List a plan \u2192 Discuss plan details with the user if needed \u2192 Development \u2192 Build.
|
|
15029
|
+
- **Simple tasks**: Development \u2192 Build directly.
|
|
15028
15030
|
`;
|
|
15029
15031
|
}
|
|
15030
15032
|
function buildHmAgentPrompt(type) {
|
|
@@ -15169,7 +15171,11 @@ function createHmAgent() {
|
|
|
15169
15171
|
prompt: buildHmAgentPrompt("all"),
|
|
15170
15172
|
temperature: 0.3,
|
|
15171
15173
|
permission: {
|
|
15172
|
-
"
|
|
15174
|
+
"*": "allow",
|
|
15175
|
+
doom_loop: "ask",
|
|
15176
|
+
external_directory: {
|
|
15177
|
+
"*": "ask"
|
|
15178
|
+
}
|
|
15173
15179
|
},
|
|
15174
15180
|
metadata: void 0
|
|
15175
15181
|
};
|
|
@@ -15425,7 +15431,7 @@ function createConfigHandler(_pluginConfig, agent, _projectDir) {
|
|
|
15425
15431
|
template: "/harmony-development-env-check",
|
|
15426
15432
|
description: "\u68C0\u67E5 HarmonyOS \u5F00\u53D1\u73AF\u5883\u914D\u7F6E\uFF08Node.js\u3001JDK\u3001ohpm\u3001hvigor\u3001DevEco SDK\uFF09"
|
|
15427
15433
|
};
|
|
15428
|
-
log("Config merged"
|
|
15434
|
+
log("Config merged");
|
|
15429
15435
|
};
|
|
15430
15436
|
}
|
|
15431
15437
|
|
|
@@ -28138,23 +28144,20 @@ function createHmTemplateTool(managers) {
|
|
|
28138
28144
|
});
|
|
28139
28145
|
}
|
|
28140
28146
|
|
|
28141
|
-
// src/tools/skill-search/skill-search-tool.ts
|
|
28142
|
-
import { homedir as homedir2 } from "node:os";
|
|
28143
|
-
import { join as join4 } from "node:path";
|
|
28144
|
-
|
|
28145
28147
|
// src/tools/skill-search/search-skill.ts
|
|
28146
|
-
import { readFileSync } from "node:fs";
|
|
28147
|
-
import { join as
|
|
28148
|
+
import { readFileSync, existsSync } from "node:fs";
|
|
28149
|
+
import { join as join4 } from "node:path";
|
|
28148
28150
|
|
|
28149
28151
|
// src/tools/skill-search/tokenizer.ts
|
|
28152
|
+
var CJK_RE = /[一-鿿㐀-䶿]/;
|
|
28153
|
+
var SEG_RE = /[一-鿿㐀-䶿]+|[\w@.]+/g;
|
|
28154
|
+
var CAMEL_RE = /[A-Z]?[a-z]+|[A-Z]+(?=[A-Z][a-z]|\b)|[0-9]+/g;
|
|
28150
28155
|
var segmenter = new Intl.Segmenter("zh", { granularity: "word" });
|
|
28151
|
-
var SEG_RE = /[一-鿿㐀-䶿]+|[^\s\p{P}一-鿿㐀-䶿]+/gu;
|
|
28152
|
-
var CAMEL_RE = /[A-Z]?[a-z]+|[A-Z]+(?![a-z])/g;
|
|
28153
28156
|
function tokenize(text) {
|
|
28154
28157
|
const segments = text.match(SEG_RE) ?? [];
|
|
28155
28158
|
const tokens = [];
|
|
28156
28159
|
for (const seg of segments) {
|
|
28157
|
-
if (
|
|
28160
|
+
if (CJK_RE.test(seg)) {
|
|
28158
28161
|
for (const s of segmenter.segment(seg)) {
|
|
28159
28162
|
if (s.isWordLike) tokens.push(s.segment.toLowerCase().trim());
|
|
28160
28163
|
}
|
|
@@ -28170,7 +28173,7 @@ function tokenize(text) {
|
|
|
28170
28173
|
}
|
|
28171
28174
|
}
|
|
28172
28175
|
}
|
|
28173
|
-
return tokens.filter((w) => w.length > 0);
|
|
28176
|
+
return [...new Set(tokens.filter((w) => w.length > 0))];
|
|
28174
28177
|
}
|
|
28175
28178
|
|
|
28176
28179
|
// src/tools/skill-search/bm25.ts
|
|
@@ -28325,13 +28328,198 @@ var filter_default = [
|
|
|
28325
28328
|
{ id: "25", summary: "WaterFlow \u7011\u5E03\u6D41\u5E03\u5C40\u5F00\u53D1\u5B9E\u8DF5", path: "experience/experience_water_flow.md", category: "water_flow" }
|
|
28326
28329
|
];
|
|
28327
28330
|
|
|
28331
|
+
// src/tools/skill-search/build-sdk-index.ts
|
|
28332
|
+
import { readdir as readdir2, readFile as readFile3, writeFile } from "node:fs/promises";
|
|
28333
|
+
import { join as join3, relative, basename, dirname } from "node:path";
|
|
28334
|
+
var SCAN_DIRS = [
|
|
28335
|
+
"openharmony/js/api",
|
|
28336
|
+
"openharmony/ets/api",
|
|
28337
|
+
"openharmony/ets/component",
|
|
28338
|
+
"openharmony/ets/kits",
|
|
28339
|
+
"hms/ets/api",
|
|
28340
|
+
"hms/ets/kits"
|
|
28341
|
+
];
|
|
28342
|
+
var TS_EXT_RE = /\.(?:d\.ts|d\.ets|ts|ets)$/;
|
|
28343
|
+
async function scanFiles(dir) {
|
|
28344
|
+
const results = [];
|
|
28345
|
+
async function walk(current) {
|
|
28346
|
+
const entries = await readdir2(current, { withFileTypes: true });
|
|
28347
|
+
for (const entry of entries) {
|
|
28348
|
+
const full = join3(current, entry.name);
|
|
28349
|
+
if (entry.isDirectory()) {
|
|
28350
|
+
await walk(full);
|
|
28351
|
+
} else if (TS_EXT_RE.test(entry.name)) {
|
|
28352
|
+
results.push(full);
|
|
28353
|
+
}
|
|
28354
|
+
}
|
|
28355
|
+
}
|
|
28356
|
+
await walk(dir);
|
|
28357
|
+
return results;
|
|
28358
|
+
}
|
|
28359
|
+
function extractSummary(content, filename, relPath) {
|
|
28360
|
+
const rawName = filename.replace(/\.(?:d\.ts|d\.ets|ts|ets)$/, "");
|
|
28361
|
+
let moduleName;
|
|
28362
|
+
if (rawName.startsWith("@")) {
|
|
28363
|
+
moduleName = rawName.replace(/^@/, "");
|
|
28364
|
+
} else {
|
|
28365
|
+
const dirParts = dirname(relPath).split("/").filter(Boolean);
|
|
28366
|
+
moduleName = [...dirParts, rawName].join(".");
|
|
28367
|
+
}
|
|
28368
|
+
const symbols = [];
|
|
28369
|
+
const stripped = content.replace(/\/\*\*[\s\S]*?\*\//g, "").replace(/\/\/.*$/gm, "");
|
|
28370
|
+
const patterns = [
|
|
28371
|
+
// Prefixed at file/module level
|
|
28372
|
+
/declare\s+namespace\s+(\w+)/g,
|
|
28373
|
+
/export\s+(?:default\s+)?interface\s+(\w+)/g,
|
|
28374
|
+
/export\s+(?:default\s+)?class\s+(\w+)/g,
|
|
28375
|
+
/export\s+(?:default\s+)?function\s+(\w+)/g,
|
|
28376
|
+
/export\s+(?:default\s+)?const\s+(\w+)/g,
|
|
28377
|
+
/export\s+(?:default\s+)?type\s+(\w+)/g,
|
|
28378
|
+
/export\s+(?:default\s+)?enum\s+(\w+)/g,
|
|
28379
|
+
/export\s+module\s+(\w+)/g,
|
|
28380
|
+
/declare\s+function\s+(\w+)/g,
|
|
28381
|
+
/declare\s+class\s+(\w+)/g,
|
|
28382
|
+
/declare\s+interface\s+(\w+)/g,
|
|
28383
|
+
/declare\s+const\s+(\w+)/g,
|
|
28384
|
+
/declare\s+type\s+(\w+)/g,
|
|
28385
|
+
/declare\s+enum\s+(\w+)/g,
|
|
28386
|
+
// Bare declarations inside declare namespace / module blocks
|
|
28387
|
+
/\bfunction\s+(\w+)\s*\(/g,
|
|
28388
|
+
/\binterface\s+(\w+)\s*(?:\{|extends)/g,
|
|
28389
|
+
/\benum\s+(\w+)\s*\{/g,
|
|
28390
|
+
/\bclass\s+(\w+)\s*(?:\{|extends|implements)/g,
|
|
28391
|
+
/\btype\s+(\w+)\s*=/g
|
|
28392
|
+
];
|
|
28393
|
+
for (const pat of patterns) {
|
|
28394
|
+
let m;
|
|
28395
|
+
while ((m = pat.exec(stripped)) !== null) {
|
|
28396
|
+
if (!symbols.includes(m[1])) {
|
|
28397
|
+
symbols.push(m[1]);
|
|
28398
|
+
}
|
|
28399
|
+
}
|
|
28400
|
+
}
|
|
28401
|
+
const importNamedRe = /import\s+\{([^}]+)\}\s+from\s+/g;
|
|
28402
|
+
let mImport;
|
|
28403
|
+
while ((mImport = importNamedRe.exec(stripped)) !== null) {
|
|
28404
|
+
for (const name of mImport[1].split(",")) {
|
|
28405
|
+
const clean = name.trim().split(/\s+as\s+/)[0].trim();
|
|
28406
|
+
if (clean && !symbols.includes(clean)) {
|
|
28407
|
+
symbols.push(clean);
|
|
28408
|
+
}
|
|
28409
|
+
}
|
|
28410
|
+
}
|
|
28411
|
+
const importDefaultRe = /import\s+(\w+)\s+from\s+/g;
|
|
28412
|
+
let mDef;
|
|
28413
|
+
while ((mDef = importDefaultRe.exec(stripped)) !== null) {
|
|
28414
|
+
const name = mDef[1];
|
|
28415
|
+
if (!symbols.includes(name)) {
|
|
28416
|
+
symbols.push(name);
|
|
28417
|
+
}
|
|
28418
|
+
}
|
|
28419
|
+
const descMatch = content.match(
|
|
28420
|
+
/\*\s*(?:@description\s+)?(Provides[^.]*\.)/s
|
|
28421
|
+
);
|
|
28422
|
+
let providesDesc = "";
|
|
28423
|
+
if (descMatch) {
|
|
28424
|
+
providesDesc = descMatch[1].replace(/\*\s*/g, "").replace(/\n/g, " ").trim().slice(0, 200);
|
|
28425
|
+
}
|
|
28426
|
+
if (!providesDesc) {
|
|
28427
|
+
const gDesc = content.match(
|
|
28428
|
+
/\*\s*@description\s+([\s\S]*?)\s*\*\s*\//s
|
|
28429
|
+
);
|
|
28430
|
+
if (gDesc) {
|
|
28431
|
+
providesDesc = gDesc[1].replace(/\*\s*/g, "").replace(/\n/g, " ").trim().slice(0, 200);
|
|
28432
|
+
}
|
|
28433
|
+
}
|
|
28434
|
+
const kitMatch = content.match(/\*\s*@kit\s+(\w+)/);
|
|
28435
|
+
const kit = kitMatch ? kitMatch[1] : "";
|
|
28436
|
+
const syscapMatch = content.match(
|
|
28437
|
+
/\*\s*@syscap\s+SystemCapability\.([\w.]+)/
|
|
28438
|
+
);
|
|
28439
|
+
const syscap = syscapMatch ? syscapMatch[1] : "";
|
|
28440
|
+
const parts = [moduleName];
|
|
28441
|
+
if (kit && !moduleName.includes(kit)) parts.push(`Kit:${kit}`);
|
|
28442
|
+
if (syscap) parts.push(syscap);
|
|
28443
|
+
if (providesDesc) parts.push(providesDesc);
|
|
28444
|
+
if (symbols.length > 0) {
|
|
28445
|
+
parts.push(symbols.slice(0, 20).join(", "));
|
|
28446
|
+
}
|
|
28447
|
+
return {
|
|
28448
|
+
summary: parts.join(" | "),
|
|
28449
|
+
moduleName,
|
|
28450
|
+
symbols: symbols.slice(0, 50)
|
|
28451
|
+
};
|
|
28452
|
+
}
|
|
28453
|
+
async function buildSDKIndex(sdk_path) {
|
|
28454
|
+
let allFiles = [];
|
|
28455
|
+
for (const dir of SCAN_DIRS) {
|
|
28456
|
+
const fullDir = join3(sdk_path, "default", dir);
|
|
28457
|
+
log(`Scanning ${dir} ...`);
|
|
28458
|
+
const files = await scanFiles(fullDir);
|
|
28459
|
+
log(` Found ${files.length} files`);
|
|
28460
|
+
for (const f of files) {
|
|
28461
|
+
allFiles.push({
|
|
28462
|
+
absPath: f,
|
|
28463
|
+
relPath: relative(fullDir, f),
|
|
28464
|
+
sourceDir: dir
|
|
28465
|
+
});
|
|
28466
|
+
}
|
|
28467
|
+
}
|
|
28468
|
+
log(`Total files: ${allFiles.length}`);
|
|
28469
|
+
const entries = [];
|
|
28470
|
+
for (let i = 0; i < allFiles.length; i++) {
|
|
28471
|
+
const { absPath, relPath, sourceDir } = allFiles[i];
|
|
28472
|
+
const filename = basename(absPath);
|
|
28473
|
+
try {
|
|
28474
|
+
const content = await readFile3(absPath, "utf-8");
|
|
28475
|
+
const { summary, moduleName, symbols } = extractSummary(
|
|
28476
|
+
content,
|
|
28477
|
+
filename,
|
|
28478
|
+
relPath
|
|
28479
|
+
);
|
|
28480
|
+
entries.push({
|
|
28481
|
+
id: String(i + 1),
|
|
28482
|
+
summary,
|
|
28483
|
+
path: absPath,
|
|
28484
|
+
moduleName,
|
|
28485
|
+
symbols
|
|
28486
|
+
});
|
|
28487
|
+
} catch {
|
|
28488
|
+
}
|
|
28489
|
+
if ((i + 1) % 500 === 0) {
|
|
28490
|
+
log(`Processed ${i + 1}/${allFiles.length}`);
|
|
28491
|
+
}
|
|
28492
|
+
}
|
|
28493
|
+
const outputPath = join3(import.meta.dirname, "sdk-index.json");
|
|
28494
|
+
await writeFile(outputPath, JSON.stringify(entries, null, 2), "utf-8");
|
|
28495
|
+
log(`Done! Wrote ${entries.length} entries to sdk-index.json`);
|
|
28496
|
+
log(
|
|
28497
|
+
`Sample entries:`,
|
|
28498
|
+
entries.slice(0, 5).map((e) => e.moduleName)
|
|
28499
|
+
);
|
|
28500
|
+
}
|
|
28501
|
+
|
|
28328
28502
|
// src/tools/skill-search/search-skill.ts
|
|
28329
28503
|
var cachedEntries = null;
|
|
28330
28504
|
var cachedIndexableEntries = null;
|
|
28331
28505
|
var cachedFilters = null;
|
|
28332
28506
|
var cachedRetriever = null;
|
|
28333
|
-
|
|
28334
|
-
|
|
28507
|
+
var cachedSdkEntries = null;
|
|
28508
|
+
var cachedSdkRetriever = null;
|
|
28509
|
+
async function loadAndCache(resolvedPath) {
|
|
28510
|
+
const sdk_path = findSdkDir();
|
|
28511
|
+
log("start load sdk cache", sdk_path);
|
|
28512
|
+
if (sdk_path !== void 0) {
|
|
28513
|
+
const sdkIndexPath = join4(import.meta.dirname, "sdk-index.json");
|
|
28514
|
+
if (!existsSync(sdkIndexPath)) {
|
|
28515
|
+
log("sdk path is not exist, need to build");
|
|
28516
|
+
await buildSDKIndex(sdk_path);
|
|
28517
|
+
}
|
|
28518
|
+
loadSdkIndex();
|
|
28519
|
+
log("success to load sdk cache");
|
|
28520
|
+
}
|
|
28521
|
+
log("start load skill cache");
|
|
28522
|
+
const raw = readFileSync(join4(resolvedPath, "index.json"), "utf-8");
|
|
28335
28523
|
const entries = JSON.parse(raw);
|
|
28336
28524
|
if (!Array.isArray(entries) || entries.length === 0) {
|
|
28337
28525
|
return false;
|
|
@@ -28344,23 +28532,45 @@ function loadAndCache(resolvedPath) {
|
|
|
28344
28532
|
const retriever = new HybridRetriever();
|
|
28345
28533
|
retriever.addDocuments(documents, tokenizedDocs);
|
|
28346
28534
|
cachedRetriever = retriever;
|
|
28535
|
+
log("success to load sdk cache");
|
|
28347
28536
|
return true;
|
|
28348
28537
|
}
|
|
28349
|
-
function
|
|
28538
|
+
function loadSdkIndex() {
|
|
28539
|
+
if (cachedSdkRetriever) return true;
|
|
28540
|
+
const sdkIndexPath = join4(import.meta.dirname, "sdk-index.json");
|
|
28541
|
+
if (!existsSync(sdkIndexPath)) return false;
|
|
28542
|
+
try {
|
|
28543
|
+
const raw = readFileSync(sdkIndexPath, "utf-8");
|
|
28544
|
+
const entries = JSON.parse(raw);
|
|
28545
|
+
if (!Array.isArray(entries) || entries.length === 0) return false;
|
|
28546
|
+
cachedSdkEntries = entries;
|
|
28547
|
+
const documents = entries.map((e) => e.summary);
|
|
28548
|
+
const tokenizedDocs = documents.map((d) => tokenize(d));
|
|
28549
|
+
const retriever = new BM25Retriever();
|
|
28550
|
+
retriever.addDocuments(documents, tokenizedDocs);
|
|
28551
|
+
cachedSdkRetriever = retriever;
|
|
28552
|
+
return true;
|
|
28553
|
+
} catch {
|
|
28554
|
+
return false;
|
|
28555
|
+
}
|
|
28556
|
+
}
|
|
28557
|
+
async function searchSkill(skill_path, query, topK = 3) {
|
|
28350
28558
|
if (!cachedEntries) {
|
|
28351
28559
|
try {
|
|
28352
|
-
if (!loadAndCache(skill_path?.trim())) return [];
|
|
28560
|
+
if (!await loadAndCache(skill_path?.trim())) return [];
|
|
28353
28561
|
} catch {
|
|
28354
28562
|
return [];
|
|
28355
28563
|
}
|
|
28356
28564
|
}
|
|
28565
|
+
const prefix = skill_path.replace(/[\/\\]+$/, "");
|
|
28357
28566
|
const preFiltered = [];
|
|
28358
28567
|
for (const [category, entry] of cachedFilters) {
|
|
28359
28568
|
const idx = query.toLowerCase().indexOf(category);
|
|
28360
28569
|
if (idx !== -1) {
|
|
28361
28570
|
preFiltered.push({
|
|
28362
28571
|
ets_file_path: "",
|
|
28363
|
-
experience_file_path: entry.path
|
|
28572
|
+
experience_file_path: join4(prefix, entry.path),
|
|
28573
|
+
sdk_file_path: ""
|
|
28364
28574
|
});
|
|
28365
28575
|
query = (query.slice(0, idx) + query.slice(idx + category.length)).trim();
|
|
28366
28576
|
}
|
|
@@ -28368,21 +28578,42 @@ function searchSkill(skill_path, query, topK = 5) {
|
|
|
28368
28578
|
if (!query) {
|
|
28369
28579
|
return preFiltered;
|
|
28370
28580
|
}
|
|
28581
|
+
const MIN_SCORE = 0.01;
|
|
28582
|
+
const sdkResults = loadSdkIndex() ? cachedSdkRetriever.search(query, topK).filter((r) => r.score >= MIN_SCORE).map((r) => ({
|
|
28583
|
+
ets_file_path: "",
|
|
28584
|
+
experience_file_path: "",
|
|
28585
|
+
sdk_file_path: cachedSdkEntries[r.index].path
|
|
28586
|
+
})) : [];
|
|
28371
28587
|
const searchResults = cachedRetriever.search(query, topK);
|
|
28372
|
-
const MIN_SCORE = 2e-3;
|
|
28373
28588
|
const filtered = searchResults.filter((r) => r.score >= MIN_SCORE);
|
|
28374
|
-
|
|
28375
|
-
return [...preFiltered, ...
|
|
28589
|
+
const skillResults = filtered.length > 0 ? aggregateByExperience(convert_search_result(filtered, prefix)) : [];
|
|
28590
|
+
return [...preFiltered, ...skillResults, ...sdkResults];
|
|
28591
|
+
}
|
|
28592
|
+
function aggregateByExperience(results) {
|
|
28593
|
+
const map3 = /* @__PURE__ */ new Map();
|
|
28594
|
+
for (const r of results) {
|
|
28595
|
+
const key = r.experience_file_path || r.ets_file_path;
|
|
28596
|
+
const existing = map3.get(key);
|
|
28597
|
+
if (existing) {
|
|
28598
|
+
if (r.ets_file_path) {
|
|
28599
|
+
existing.ets_file_path = existing.ets_file_path ? existing.ets_file_path + "\n" + r.ets_file_path : r.ets_file_path;
|
|
28600
|
+
}
|
|
28601
|
+
} else {
|
|
28602
|
+
map3.set(key, { ...r });
|
|
28603
|
+
}
|
|
28604
|
+
}
|
|
28605
|
+
return [...map3.values()];
|
|
28376
28606
|
}
|
|
28377
|
-
function convert_search_result(searchResults) {
|
|
28607
|
+
function convert_search_result(searchResults, prefix) {
|
|
28378
28608
|
return searchResults.map((result, rank) => {
|
|
28379
28609
|
const entry = cachedIndexableEntries[result.index];
|
|
28380
28610
|
const experience = cachedEntries.find(
|
|
28381
28611
|
(e) => e.type === "experience" && e.category === entry.category
|
|
28382
28612
|
);
|
|
28383
28613
|
return {
|
|
28384
|
-
ets_file_path: entry.path,
|
|
28385
|
-
experience_file_path: experience?.path
|
|
28614
|
+
ets_file_path: join4(prefix, entry.path),
|
|
28615
|
+
experience_file_path: experience?.path ? join4(prefix, experience.path) : "",
|
|
28616
|
+
sdk_file_path: ""
|
|
28386
28617
|
};
|
|
28387
28618
|
});
|
|
28388
28619
|
}
|
|
@@ -28390,25 +28621,27 @@ function convert_search_result(searchResults) {
|
|
|
28390
28621
|
// src/tools/skill-search/skill-search-tool.ts
|
|
28391
28622
|
function skillSearchTool(managers) {
|
|
28392
28623
|
return tool({
|
|
28393
|
-
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. Use this tool instead of Glob/Grep when you need to find specific knowledge or documentation within harmonyos-atomic-dev skill.
|
|
28624
|
+
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. Use this tool instead of Glob/Grep when you need to find specific knowledge or documentation within harmonyos-atomic-dev skill. The results include experience_file_path (path to the matching experience document best practices) and ets_file_path (path to the ETS code examples and SDK API file). IMPORTANT: Each scenario only supports ONE tool call. Do NOT call this tool multiple times.",
|
|
28394
28625
|
args: {
|
|
28395
|
-
skill_path: tool.schema.string("Absolute path to the skill directory
|
|
28396
|
-
query: tool.schema.string("A decomposed requirement or intent describing what you want to find, broken down into searchable keywords separated by spaces."),
|
|
28397
|
-
topK: tool.schema.number("Maximum number of top-ranked documents to return. Actual results may be fewer depending on query relevance.").min(1).max(
|
|
28626
|
+
skill_path: tool.schema.string("Absolute path to the harmonyos-atomic-dev skill directory. IMPORTANT: this path should not contain any prefix or suffix like 'file://' or 'SKILL.md'."),
|
|
28627
|
+
query: tool.schema.string("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'. "),
|
|
28628
|
+
topK: tool.schema.number("Maximum number of top-ranked documents to return. Actual results may be fewer depending on query relevance.").min(1).max(3).default(3)
|
|
28398
28629
|
},
|
|
28399
28630
|
execute: async (args, context) => {
|
|
28400
28631
|
try {
|
|
28401
|
-
const results = searchSkill(args.skill_path, args.query, args.topK);
|
|
28632
|
+
const results = await searchSkill(args.skill_path, args.query, args.topK);
|
|
28402
28633
|
if (results.length === 0) {
|
|
28403
28634
|
return "No relative items found in the skill directory.";
|
|
28404
28635
|
}
|
|
28405
|
-
|
|
28406
|
-
|
|
28407
|
-
|
|
28408
|
-
|
|
28409
|
-
}
|
|
28410
|
-
return
|
|
28636
|
+
const sdkInfo = results.map((r) => {
|
|
28637
|
+
const parts = [];
|
|
28638
|
+
if (r.experience_file_path) parts.push(`experience path ${r.experience_file_path}`);
|
|
28639
|
+
if (r.ets_file_path) parts.push(`sample code path ${r.ets_file_path}`);
|
|
28640
|
+
if (r.sdk_file_path) parts.push(`sdk info path ${r.sdk_file_path}`);
|
|
28641
|
+
return parts.join("\n");
|
|
28411
28642
|
}).join("\n\n");
|
|
28643
|
+
return `You can read the following files as needed to obtain information.
|
|
28644
|
+
${sdkInfo}`;
|
|
28412
28645
|
} catch (e) {
|
|
28413
28646
|
return `Error: ${e instanceof Error ? e.message : String(e)}`;
|
|
28414
28647
|
}
|
|
@@ -28440,7 +28673,7 @@ function createTools(args) {
|
|
|
28440
28673
|
}
|
|
28441
28674
|
|
|
28442
28675
|
// src/hooks/tool-hooks.ts
|
|
28443
|
-
import { readFile as
|
|
28676
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
28444
28677
|
|
|
28445
28678
|
// node_modules/diff/lib/index.mjs
|
|
28446
28679
|
function Diff() {
|
|
@@ -29025,7 +29258,7 @@ function createToolHooks(sessionManager, projectDir) {
|
|
|
29025
29258
|
if (input.tool === "write") {
|
|
29026
29259
|
const filePath = output.args?.filePath;
|
|
29027
29260
|
if (filePath) {
|
|
29028
|
-
const oldContent = await
|
|
29261
|
+
const oldContent = await readFile4(filePath, "utf-8").catch(() => "");
|
|
29029
29262
|
writeContentCache.set(input.callID, oldContent);
|
|
29030
29263
|
}
|
|
29031
29264
|
}
|
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.8",
|
|
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",
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# HarmonyOS Application Template
|
|
2
|
-
|
|
3
|
-
HarmonyOS 标准应用工程模板,基于 Stage 模型,适用于开发完整的 HarmonyOS 应用程序。
|
|
4
|
-
|
|
5
|
-
## 目录结构
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
application/
|
|
9
|
-
├── AppScope/ # 应用全局配置
|
|
10
|
-
│ ├── app.json5 # 应用包名、版本号、图标等全局信息
|
|
11
|
-
│ └── resources/ # 应用级资源(图标、字符串)
|
|
12
|
-
├── entry/ # 主模块(Entry Module)
|
|
13
|
-
│ ├── src/
|
|
14
|
-
│ │ ├── main/
|
|
15
|
-
│ │ │ ├── ets/
|
|
16
|
-
│ │ │ │ ├── entryability/ # UIAbility 入口
|
|
17
|
-
│ │ │ │ ├── entrybackupability/# 备份恢复 ExtensionAbility
|
|
18
|
-
│ │ │ │ └── pages/ # 页面(Index.ets)
|
|
19
|
-
│ │ │ ├── resources/ # 模块资源(字符串、颜色、图片、配置)
|
|
20
|
-
│ │ │ └── module.json5 # 模块配置(Ability、页面路由)
|
|
21
|
-
│ │ ├── ohosTest/ # 仪器化测试
|
|
22
|
-
│ │ └── test/ # 本地单元测试
|
|
23
|
-
│ ├── build-profile.json5 # 模块级构建配置
|
|
24
|
-
│ ├── oh-package.json5 # 模块依赖声明
|
|
25
|
-
│ └── hvigorfile.ts # Hvigor 构建脚本
|
|
26
|
-
├── hvigor/ # Hvigor 构建引擎配置
|
|
27
|
-
├── build-profile.json5 # 工程级构建配置(签名、SDK 版本、模块列表)
|
|
28
|
-
├── oh-package.json5 # 工程级依赖声明
|
|
29
|
-
├── hvigorfile.ts # 工程级 Hvigor 脚本
|
|
30
|
-
└── code-linter.json5 # 代码检查配置
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## 关键配置
|
|
34
|
-
|
|
35
|
-
| 配置项 | 值 |
|
|
36
|
-
|--------|-----|
|
|
37
|
-
| bundleName | `com.example.app` |
|
|
38
|
-
| module type | `entry` |
|
|
39
|
-
| targetSdkVersion | `6.0.1(21)` |
|
|
40
|
-
| runtimeOS | `HarmonyOS` |
|
|
41
|
-
| installationFree | `false` |
|
|
42
|
-
|
|
43
|
-
## 使用场景
|
|
44
|
-
|
|
45
|
-
- 创建一个新的 HarmonyOS 标准应用工程
|
|
46
|
-
- 包含完整的 UIAbility 生命周期管理
|
|
47
|
-
- 内置备份恢复能力(EntryBackupAbility)
|
|
48
|
-
- 适合需要独立安装和分发的应用
|
|
49
|
-
|
|
50
|
-
## 使用方式
|
|
51
|
-
|
|
52
|
-
此模板由 `createHmTemplate` 工具自动下载和解压,作为 HarmonyOS 应用开发的初始工程骨架。
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# HarmonyOS Atomic Service Template
|
|
2
|
-
|
|
3
|
-
HarmonyOS 元服务(Atomic Service)工程模板,基于 Stage 模型,适用于开发免安装的轻量化服务。
|
|
4
|
-
|
|
5
|
-
## 目录结构
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
atomic/
|
|
9
|
-
├── AppScope/ # 应用全局配置
|
|
10
|
-
│ ├── app.json5 # 应用包名、版本号(bundleType: "atomicService")
|
|
11
|
-
│ └── resources/ # 应用级资源(图标、字符串)
|
|
12
|
-
├── entry/ # 主模块(Entry Module)
|
|
13
|
-
│ ├── src/
|
|
14
|
-
│ │ ├── main/
|
|
15
|
-
│ │ │ ├── ets/
|
|
16
|
-
│ │ │ │ ├── entryability/ # UIAbility 入口
|
|
17
|
-
│ │ │ │ └── pages/ # 页面(Index.ets)
|
|
18
|
-
│ │ │ ├── resources/ # 模块资源(字符串、颜色、图片、配置)
|
|
19
|
-
│ │ │ └── module.json5 # 模块配置(Ability、页面路由)
|
|
20
|
-
│ │ ├── ohosTest/ # 仪器化测试
|
|
21
|
-
│ │ ├── test/ # 本地单元测试
|
|
22
|
-
│ │ └── mock/ # Mock 配置
|
|
23
|
-
│ ├── build-profile.json5 # 模块级构建配置
|
|
24
|
-
│ ├── oh-package.json5 # 模块依赖声明
|
|
25
|
-
│ └── hvigorfile.ts # Hvigor 构建脚本
|
|
26
|
-
├── hvigor/ # Hvigor 构建引擎配置
|
|
27
|
-
├── build-profile.json5 # 工程级构建配置(签名、SDK 版本、模块列表)
|
|
28
|
-
├── oh-package.json5 # 工程级依赖声明
|
|
29
|
-
├── hvigorfile.ts # 工程级 Hvigor 脚本
|
|
30
|
-
└── code-linter.json5 # 代码检查配置
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
## 关键配置
|
|
34
|
-
|
|
35
|
-
| 配置项 | 值 |
|
|
36
|
-
|--------|-----|
|
|
37
|
-
| bundleName | `com.atomicservice.example` |
|
|
38
|
-
| bundleType | `atomicService` |
|
|
39
|
-
| module type | `entry` |
|
|
40
|
-
| targetSdkVersion | `6.0.1(21)` |
|
|
41
|
-
| runtimeOS | `HarmonyOS` |
|
|
42
|
-
| installationFree | `true` |
|
|
43
|
-
|
|
44
|
-
## 与 Application 模板的区别
|
|
45
|
-
|
|
46
|
-
| 特性 | Application | Atomic Service |
|
|
47
|
-
|------|-------------|----------------|
|
|
48
|
-
| bundleType | 默认(app) | `atomicService` |
|
|
49
|
-
| installationFree | `false` | `true` |
|
|
50
|
-
| 备份能力 | 包含 EntryBackupAbility | 不包含 |
|
|
51
|
-
| 图标资源 | layered_image | app_icon |
|
|
52
|
-
| 免安装 | 不支持 | 支持 |
|
|
53
|
-
|
|
54
|
-
## 使用场景
|
|
55
|
-
|
|
56
|
-
- 开发免安装的元服务(Atomic Service)
|
|
57
|
-
- 适用于服务卡片、快捷服务、轻量级功能入口
|
|
58
|
-
- 通过 HarmonyOS 服务分发平台进行分发
|
|
59
|
-
|
|
60
|
-
## 使用方式
|
|
61
|
-
|
|
62
|
-
此模板由 `createHmTemplate` 工具自动下载和解压,作为 HarmonyOS 元服务开发的初始工程骨架。
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
# HarmonyOS Module Template
|
|
2
|
-
|
|
3
|
-
HarmonyOS HAR(HarmonyOS Archive)库模块模板,用于开发可复用的共享库模块。
|
|
4
|
-
|
|
5
|
-
## 目录结构
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
module/
|
|
9
|
-
├── src/
|
|
10
|
-
│ ├── main/
|
|
11
|
-
│ │ ├── ets/
|
|
12
|
-
│ │ │ └── components/ # 导出的组件(MainPage.ets)
|
|
13
|
-
│ │ ├── resources/ # 模块资源(字符串、浮点数)
|
|
14
|
-
│ │ └── module.json5 # 模块配置(type: "har")
|
|
15
|
-
│ ├── ohosTest/ # 仪器化测试
|
|
16
|
-
│ └── test/ # 本地单元测试
|
|
17
|
-
├── Index.ets # 库模块导出入口
|
|
18
|
-
├── build-profile.json5 # 模块级构建配置
|
|
19
|
-
├── oh-package.json5 # 模块依赖声明
|
|
20
|
-
├── hvigorfile.ts # Hvigor 构建脚本
|
|
21
|
-
├── consumer-rules.txt # 混淆消费者规则
|
|
22
|
-
└── obfuscation-rules.txt # 混淆规则
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
## 关键配置
|
|
26
|
-
|
|
27
|
-
| 配置项 | 值 |
|
|
28
|
-
|--------|-----|
|
|
29
|
-
| module name | `library` |
|
|
30
|
-
| module type | `har` |
|
|
31
|
-
| deviceTypes | `["phone"]` |
|
|
32
|
-
| apiType | `stageMode` |
|
|
33
|
-
|
|
34
|
-
## 使用场景
|
|
35
|
-
|
|
36
|
-
- 创建一个可复用的 HAR 共享库
|
|
37
|
-
- 封装通用组件、工具类或业务逻辑供多个模块引用
|
|
38
|
-
- 通过 `oh-package.json5` 管理依赖,支持混淆配置
|
|
39
|
-
|
|
40
|
-
## 使用方式
|
|
41
|
-
|
|
42
|
-
此模板由 `createHmTemplate` 工具自动下载和解压,用于在现有 HarmonyOS 工程中添加新的 HAR 库模块。将模板内容复制到工程目录下并在 `build-profile.json5` 的 `modules` 中注册即可。
|