@harmonyos-arkts/opencode-plugin 0.0.12 → 0.0.13

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.
Files changed (2) hide show
  1. package/dist/index.js +153 -47
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5052,32 +5052,32 @@ var require_URL = __commonJS({
5052
5052
  else
5053
5053
  return basepath.substring(0, lastslash + 1) + refpath;
5054
5054
  }
5055
- function remove_dot_segments(path7) {
5056
- if (!path7) return path7;
5055
+ function remove_dot_segments(path9) {
5056
+ if (!path9) return path9;
5057
5057
  var output = "";
5058
- while (path7.length > 0) {
5059
- if (path7 === "." || path7 === "..") {
5060
- path7 = "";
5058
+ while (path9.length > 0) {
5059
+ if (path9 === "." || path9 === "..") {
5060
+ path9 = "";
5061
5061
  break;
5062
5062
  }
5063
- var twochars = path7.substring(0, 2);
5064
- var threechars = path7.substring(0, 3);
5065
- var fourchars = path7.substring(0, 4);
5063
+ var twochars = path9.substring(0, 2);
5064
+ var threechars = path9.substring(0, 3);
5065
+ var fourchars = path9.substring(0, 4);
5066
5066
  if (threechars === "../") {
5067
- path7 = path7.substring(3);
5067
+ path9 = path9.substring(3);
5068
5068
  } else if (twochars === "./") {
5069
- path7 = path7.substring(2);
5069
+ path9 = path9.substring(2);
5070
5070
  } else if (threechars === "/./") {
5071
- path7 = "/" + path7.substring(3);
5072
- } else if (twochars === "/." && path7.length === 2) {
5073
- path7 = "/";
5074
- } else if (fourchars === "/../" || threechars === "/.." && path7.length === 3) {
5075
- path7 = "/" + path7.substring(4);
5071
+ path9 = "/" + path9.substring(3);
5072
+ } else if (twochars === "/." && path9.length === 2) {
5073
+ path9 = "/";
5074
+ } else if (fourchars === "/../" || threechars === "/.." && path9.length === 3) {
5075
+ path9 = "/" + path9.substring(4);
5076
5076
  output = output.replace(/\/?[^\/]*$/, "");
5077
5077
  } else {
5078
- var segment = path7.match(/(\/?([^\/]*))/)[0];
5078
+ var segment = path9.match(/(\/?([^\/]*))/)[0];
5079
5079
  output += segment;
5080
- path7 = path7.substring(segment.length);
5080
+ path9 = path9.substring(segment.length);
5081
5081
  }
5082
5082
  }
5083
5083
  return output;
@@ -18304,10 +18304,10 @@ function mergeDefs(...defs) {
18304
18304
  function cloneDef(schema) {
18305
18305
  return mergeDefs(schema._zod.def);
18306
18306
  }
18307
- function getElementAtPath(obj, path7) {
18308
- if (!path7)
18307
+ function getElementAtPath(obj, path9) {
18308
+ if (!path9)
18309
18309
  return obj;
18310
- return path7.reduce((acc, key) => acc?.[key], obj);
18310
+ return path9.reduce((acc, key) => acc?.[key], obj);
18311
18311
  }
18312
18312
  function promiseAllObject(promisesObj) {
18313
18313
  const keys = Object.keys(promisesObj);
@@ -18690,11 +18690,11 @@ function aborted(x, startIndex = 0) {
18690
18690
  }
18691
18691
  return false;
18692
18692
  }
18693
- function prefixIssues(path7, issues) {
18693
+ function prefixIssues(path9, issues) {
18694
18694
  return issues.map((iss) => {
18695
18695
  var _a2;
18696
18696
  (_a2 = iss).path ?? (_a2.path = []);
18697
- iss.path.unshift(path7);
18697
+ iss.path.unshift(path9);
18698
18698
  return iss;
18699
18699
  });
18700
18700
  }
@@ -18877,7 +18877,7 @@ function formatError(error92, mapper = (issue3) => issue3.message) {
18877
18877
  }
18878
18878
  function treeifyError(error92, mapper = (issue3) => issue3.message) {
18879
18879
  const result = { errors: [] };
18880
- const processError = (error93, path7 = []) => {
18880
+ const processError = (error93, path9 = []) => {
18881
18881
  var _a2, _b;
18882
18882
  for (const issue3 of error93.issues) {
18883
18883
  if (issue3.code === "invalid_union" && issue3.errors.length) {
@@ -18887,7 +18887,7 @@ function treeifyError(error92, mapper = (issue3) => issue3.message) {
18887
18887
  } else if (issue3.code === "invalid_element") {
18888
18888
  processError({ issues: issue3.issues }, issue3.path);
18889
18889
  } else {
18890
- const fullpath = [...path7, ...issue3.path];
18890
+ const fullpath = [...path9, ...issue3.path];
18891
18891
  if (fullpath.length === 0) {
18892
18892
  result.errors.push(mapper(issue3));
18893
18893
  continue;
@@ -18919,8 +18919,8 @@ function treeifyError(error92, mapper = (issue3) => issue3.message) {
18919
18919
  }
18920
18920
  function toDotPath(_path) {
18921
18921
  const segs = [];
18922
- const path7 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
18923
- for (const seg of path7) {
18922
+ const path9 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
18923
+ for (const seg of path9) {
18924
18924
  if (typeof seg === "number")
18925
18925
  segs.push(`[${seg}]`);
18926
18926
  else if (typeof seg === "symbol")
@@ -30897,13 +30897,13 @@ function resolveRef(ref, ctx) {
30897
30897
  if (!ref.startsWith("#")) {
30898
30898
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
30899
30899
  }
30900
- const path7 = ref.slice(1).split("/").filter(Boolean);
30901
- if (path7.length === 0) {
30900
+ const path9 = ref.slice(1).split("/").filter(Boolean);
30901
+ if (path9.length === 0) {
30902
30902
  return ctx.rootSchema;
30903
30903
  }
30904
30904
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
30905
- if (path7[0] === defsKey) {
30906
- const key = path7[1];
30905
+ if (path9[0] === defsKey) {
30906
+ const key = path9[1];
30907
30907
  if (!key || !ctx.defs[key]) {
30908
30908
  throw new Error(`Reference not found: ${ref}`);
30909
30909
  }
@@ -31572,6 +31572,7 @@ var HM_DESIGN = `
31572
31572
  - Use the \`harmonyos-prd-design\` skill to create prd desgin documents
31573
31573
  - Reference design patterns and best practices from the skill documentation
31574
31574
  - Design documents should be stored in the project's \`.harmonyos/\` directory
31575
+ - After UX renders the prototype, write it as \`prototype.html\`, then call \`html_preview\` with \`filePath\` set to that file's local path so the frontend can open it reliably
31575
31576
  `;
31576
31577
  var HM_DEVELOP = `
31577
31578
  ### Development Phase
@@ -32938,10 +32939,10 @@ function mergeDefs2(...defs) {
32938
32939
  function cloneDef2(schema) {
32939
32940
  return mergeDefs2(schema._zod.def);
32940
32941
  }
32941
- function getElementAtPath2(obj, path7) {
32942
- if (!path7)
32942
+ function getElementAtPath2(obj, path9) {
32943
+ if (!path9)
32943
32944
  return obj;
32944
- return path7.reduce((acc, key) => acc?.[key], obj);
32945
+ return path9.reduce((acc, key) => acc?.[key], obj);
32945
32946
  }
32946
32947
  function promiseAllObject2(promisesObj) {
32947
32948
  const keys = Object.keys(promisesObj);
@@ -33302,11 +33303,11 @@ function aborted2(x, startIndex = 0) {
33302
33303
  }
33303
33304
  return false;
33304
33305
  }
33305
- function prefixIssues2(path7, issues) {
33306
+ function prefixIssues2(path9, issues) {
33306
33307
  return issues.map((iss) => {
33307
33308
  var _a2;
33308
33309
  (_a2 = iss).path ?? (_a2.path = []);
33309
- iss.path.unshift(path7);
33310
+ iss.path.unshift(path9);
33310
33311
  return iss;
33311
33312
  });
33312
33313
  }
@@ -33474,7 +33475,7 @@ function treeifyError2(error92, _mapper) {
33474
33475
  return issue3.message;
33475
33476
  };
33476
33477
  const result = { errors: [] };
33477
- const processError = (error93, path7 = []) => {
33478
+ const processError = (error93, path9 = []) => {
33478
33479
  var _a2, _b;
33479
33480
  for (const issue3 of error93.issues) {
33480
33481
  if (issue3.code === "invalid_union" && issue3.errors.length) {
@@ -33484,7 +33485,7 @@ function treeifyError2(error92, _mapper) {
33484
33485
  } else if (issue3.code === "invalid_element") {
33485
33486
  processError({ issues: issue3.issues }, issue3.path);
33486
33487
  } else {
33487
- const fullpath = [...path7, ...issue3.path];
33488
+ const fullpath = [...path9, ...issue3.path];
33488
33489
  if (fullpath.length === 0) {
33489
33490
  result.errors.push(mapper(issue3));
33490
33491
  continue;
@@ -33516,8 +33517,8 @@ function treeifyError2(error92, _mapper) {
33516
33517
  }
33517
33518
  function toDotPath2(_path) {
33518
33519
  const segs = [];
33519
- const path7 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
33520
- for (const seg of path7) {
33520
+ const path9 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
33521
+ for (const seg of path9) {
33521
33522
  if (typeof seg === "number")
33522
33523
  segs.push(`[${seg}]`);
33523
33524
  else if (typeof seg === "symbol")
@@ -45341,22 +45342,22 @@ var HEADERS = {
45341
45342
  "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"
45342
45343
  };
45343
45344
  var REQUEST_TIMEOUT_MS = 1e4;
45344
- async function post(path7, body) {
45345
+ async function post(path9, body) {
45345
45346
  const controller = new AbortController();
45346
45347
  const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
45347
45348
  try {
45348
- const res = await fetch(BASE_URL + path7, {
45349
+ const res = await fetch(BASE_URL + path9, {
45349
45350
  method: "POST",
45350
45351
  headers: HEADERS,
45351
45352
  body: JSON.stringify(body),
45352
45353
  signal: controller.signal
45353
45354
  });
45354
45355
  if (!res.ok) {
45355
- throw new Error(`API request failed: ${res.status} ${res.statusText} for ${path7}`);
45356
+ throw new Error(`API request failed: ${res.status} ${res.statusText} for ${path9}`);
45356
45357
  }
45357
45358
  const data = await res.json();
45358
45359
  if (data.code && data.code !== 0 && data.code !== "0") {
45359
- throw new Error(`API error [${data.code}]: ${data.message} for ${path7}`);
45360
+ throw new Error(`API error [${data.code}]: ${data.message} for ${path9}`);
45360
45361
  }
45361
45362
  return data;
45362
45363
  } finally {
@@ -45613,6 +45614,82 @@ Use harmony-doc-view with a URL above to read any official document in full.`
45613
45614
  });
45614
45615
  }
45615
45616
 
45617
+ // src/tools/html-preview/html-preview-tool.ts
45618
+ import { access } from "fs/promises";
45619
+ import path7 from "path";
45620
+ import { fileURLToPath as fileURLToPath2, pathToFileURL } from "url";
45621
+ var PROTOTYPE_HTML_FILENAME = "prototype.html";
45622
+ function toFileUrl(filePath) {
45623
+ return pathToFileURL(path7.resolve(filePath)).href;
45624
+ }
45625
+ async function fileExists(filePath) {
45626
+ try {
45627
+ await access(filePath);
45628
+ return true;
45629
+ } catch {
45630
+ return false;
45631
+ }
45632
+ }
45633
+ function resolvePrototypePath(directory, input) {
45634
+ const trimmed = input.trim();
45635
+ if (!trimmed) {
45636
+ throw new Error("filePath is required");
45637
+ }
45638
+ if (trimmed.startsWith("file://")) {
45639
+ return fileURLToPath2(trimmed);
45640
+ }
45641
+ return path7.isAbsolute(trimmed) ? trimmed : path7.resolve(directory, trimmed);
45642
+ }
45643
+ async function resolvePrototypePreview(directory, filePathInput) {
45644
+ const filePath = resolvePrototypePath(directory, filePathInput);
45645
+ if (!await fileExists(filePath)) {
45646
+ throw new Error(
45647
+ `Prototype HTML not found: ${filePath}. Pass the exact local path where ${PROTOTYPE_HTML_FILENAME} was written.`
45648
+ );
45649
+ }
45650
+ return { url: toFileUrl(filePath), filePath };
45651
+ }
45652
+ function htmlPreviewTool(_managers) {
45653
+ return tool({
45654
+ 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.",
45655
+ args: {
45656
+ filePath: tool.schema.string(
45657
+ "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."
45658
+ ),
45659
+ title: tool.schema.optional(
45660
+ tool.schema.string("Optional title shown in the preview panel")
45661
+ )
45662
+ },
45663
+ execute: async (args, context) => {
45664
+ try {
45665
+ log("[html_preview]", { filePath: args.filePath, title: args.title });
45666
+ const { url: url3, filePath } = await resolvePrototypePreview(context.directory, args.filePath);
45667
+ const title = args.title?.trim() || "Prototype Preview";
45668
+ const metadata = {
45669
+ url: url3,
45670
+ filePath,
45671
+ fileName: path7.basename(filePath),
45672
+ title
45673
+ };
45674
+ context.metadata({
45675
+ title,
45676
+ metadata: {
45677
+ htmlPreview: metadata
45678
+ }
45679
+ });
45680
+ return [
45681
+ "Prototype preview sent to frontend.",
45682
+ `Title: ${title}`,
45683
+ `Local path: ${filePath}`,
45684
+ `Preview URL: ${url3}`
45685
+ ].join("\n");
45686
+ } catch (e) {
45687
+ return `Error: ${e instanceof Error ? e.message : String(e)}`;
45688
+ }
45689
+ }
45690
+ });
45691
+ }
45692
+
45616
45693
  // node_modules/turndown/lib/turndown.es.js
45617
45694
  function extend3(destination) {
45618
45695
  for (var i = 1; i < arguments.length; i++) {
@@ -46786,6 +46863,7 @@ function createBuiltinTools(managers) {
46786
46863
  return {
46787
46864
  createHmTemplate: createHmTemplateTool(managers),
46788
46865
  skillSearch: skillSearchTool(managers),
46866
+ html_preview: htmlPreviewTool(managers),
46789
46867
  "harmony-doc-view": harmonyDocViewTool(managers)
46790
46868
  };
46791
46869
  }
@@ -46910,11 +46988,11 @@ Diff.prototype = {
46910
46988
  }
46911
46989
  }
46912
46990
  },
46913
- addToPath: function addToPath(path7, added, removed, oldPosInc, options) {
46914
- var last = path7.lastComponent;
46991
+ addToPath: function addToPath(path9, added, removed, oldPosInc, options) {
46992
+ var last = path9.lastComponent;
46915
46993
  if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
46916
46994
  return {
46917
- oldPos: path7.oldPos + oldPosInc,
46995
+ oldPos: path9.oldPos + oldPosInc,
46918
46996
  lastComponent: {
46919
46997
  count: last.count + 1,
46920
46998
  added,
@@ -46924,7 +47002,7 @@ Diff.prototype = {
46924
47002
  };
46925
47003
  } else {
46926
47004
  return {
46927
- oldPos: path7.oldPos + oldPosInc,
47005
+ oldPos: path9.oldPos + oldPosInc,
46928
47006
  lastComponent: {
46929
47007
  count: 1,
46930
47008
  added,
@@ -47361,6 +47439,9 @@ arrayDiff.join = arrayDiff.removeEmpty = function(value) {
47361
47439
  return value;
47362
47440
  };
47363
47441
 
47442
+ // src/hooks/tool-hooks.ts
47443
+ import path8 from "path";
47444
+
47364
47445
  // src/compress/compile-hvigorw.ts
47365
47446
  function processHvigorwCompileInfo(input, output) {
47366
47447
  if (input.tool !== "bash") return;
@@ -47402,6 +47483,7 @@ function createToolHooks(sessionManager, projectDir) {
47402
47483
  "tool.execute.after": async (input, output) => {
47403
47484
  processHvigorwCompileInfo(input, output);
47404
47485
  injectAiCodeChange(input, output);
47486
+ await injectHtmlPreview(input, output, projectDir);
47405
47487
  await updateEtsCount(sessionManager, projectDir, input);
47406
47488
  }
47407
47489
  };
@@ -47427,6 +47509,30 @@ async function updateEtsCount(sessionManager, projectDir, input) {
47427
47509
  }
47428
47510
  }
47429
47511
  }
47512
+ async function injectHtmlPreview(input, output, projectDir) {
47513
+ if (input.tool !== "html_preview") return;
47514
+ try {
47515
+ const existing = output.metadata.htmlPreview;
47516
+ if (existing?.url) {
47517
+ output.title = existing.title?.trim() || "Prototype Preview";
47518
+ return;
47519
+ }
47520
+ const filePathArg = input.args?.filePath;
47521
+ if (!filePathArg) return;
47522
+ const title = input.args?.title?.trim() || "Prototype Preview";
47523
+ const { url: url3, filePath } = await resolvePrototypePreview(projectDir, filePathArg);
47524
+ output.title = title;
47525
+ output.metadata.htmlPreview = {
47526
+ url: url3,
47527
+ filePath,
47528
+ fileName: path8.basename(filePath),
47529
+ title
47530
+ };
47531
+ log("htmlPreview injected", { url: url3, title });
47532
+ } catch (e) {
47533
+ log("htmlPreview after hook error", { tool: input.tool, error: String(e) });
47534
+ }
47535
+ }
47430
47536
  function injectAiCodeChange(input, output) {
47431
47537
  try {
47432
47538
  if (input.tool === "write") {
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.12",
4
+ "version": "0.0.13",
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",