android2harmony 0.1.3 → 0.1.5
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 -407
- package/agents/self-tester.md +376 -339
- package/dist/index.js +131 -586
- package/dist/index.js.map +4 -4
- package/package.json +36 -37
- package/skills/a2h-resource-convert/SKILL.md +902 -0
- package/skills/a2h-resource-convert/references/code-vector-icon-rules.md +335 -0
- package/skills/{hmos-resources-convert → a2h-resource-convert}/references/conversion-rules.md +15 -2
- package/skills/{hmos-resources-convert → a2h-resource-convert}/references/dependency-analysis-rules.md +24 -2
- package/skills/a2h-resource-convert/references/lottie-conversion-rules.md +219 -0
- package/skills/{hmos-resources-convert → a2h-resource-convert}/references/resource-mapping-rules.md +27 -2
- package/skills/{hmos-resources-convert → a2h-resource-convert}/references/xml-drawable-to-svg-rules.md +118 -1
- package/skills/a2h-resource-convert/scripts/a2h_resource_convert.js +2166 -0
- package/skills/a2h-resource-convert/scripts/code_vector_icons.js +607 -0
- package/skills/a2h-resource-convert/scripts/package.json +3 -0
- package/skills/a2h-resource-convert/scripts/svg_fidelity_check.js +632 -0
- package/skills/a2h-ui-transfer/SKILL.md +420 -0
- package/skills/a2h-ui-transfer/references/conversion-procedure.md +572 -0
- package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/_/350/214/203/345/274/217/351/200/211/346/213/251/350/257/264/346/230/216.md +1 -1
- package/skills/a2h-ui-transfer/references/mvvm-v2/_/350/243/205/351/245/260/345/231/250/351/200/237/346/237/245.md +133 -0
- package/skills/{hmos-batch-ui-align/scripts/android_parse_fast.ts → a2h-ui-transfer/scripts/android_parse_fast.js} +397 -283
- package/skills/a2h-ui-transfer/scripts/arkts_static_check.js +1624 -0
- package/skills/a2h-ui-transfer/scripts/measure_pack.js +1005 -0
- package/skills/a2h-ui-transfer/scripts/package.json +3 -0
- package/skills/hmos-incremental-ui-align/README.md +251 -251
- package/skills/hmos-incremental-ui-align/SKILL.md +364 -364
- package/skills/hmos-incremental-ui-align/references/State_Model_Template.md +2 -2
- package/skills/hmos-incremental-ui-align/scripts/app_feature_verify.js +790 -0
- package/skills/hmos-incremental-ui-align/scripts/extract_checklist.js +285 -0
- package/skills/hmos-incremental-ui-align/scripts/navigation-capure.md +76 -76
- package/skills/hmos-incremental-ui-align/scripts/page_capture.js +756 -0
- package/skills/hmos-incremental-ui-align/scripts/page_capture_burst.js +155 -0
- package/skills/hmos-batch-ui-align/SKILL.md +0 -141
- package/skills/hmos-batch-ui-align/references/conversion-procedure.md +0 -217
- package/skills/hmos-incremental-ui-align/scripts/app_feature_verify.ts +0 -999
- package/skills/hmos-incremental-ui-align/scripts/extract_checklist.ts +0 -343
- package/skills/hmos-incremental-ui-align/scripts/page_capture.ts +0 -977
- package/skills/hmos-incremental-ui-align/scripts/page_capture_burst.ts +0 -188
- package/skills/hmos-resources-convert/SKILL.md +0 -654
- package/skills/hmos-resources-convert/template/AppScope/app.json5 +0 -10
- package/skills/hmos-resources-convert/template/AppScope/resources/base/element/string.json +0 -8
- package/skills/hmos-resources-convert/template/AppScope/resources/base/media/background.png +0 -0
- package/skills/hmos-resources-convert/template/AppScope/resources/base/media/foreground.png +0 -0
- package/skills/hmos-resources-convert/template/AppScope/resources/base/media/layered_image.json +0 -7
- package/skills/hmos-resources-convert/template/build-profile.json5 +0 -42
- package/skills/hmos-resources-convert/template/code-linter.json5 +0 -32
- package/skills/hmos-resources-convert/template/entry/build-profile.json5 +0 -33
- package/skills/hmos-resources-convert/template/entry/hvigorfile.ts +0 -6
- package/skills/hmos-resources-convert/template/entry/obfuscation-rules.txt +0 -23
- package/skills/hmos-resources-convert/template/entry/oh-package.json5 +0 -10
- package/skills/hmos-resources-convert/template/entry/src/main/ets/entryability/EntryAbility.ets +0 -48
- package/skills/hmos-resources-convert/template/entry/src/main/ets/entrybackupability/EntryBackupAbility.ets +0 -16
- package/skills/hmos-resources-convert/template/entry/src/main/ets/pages/Index.ets +0 -23
- package/skills/hmos-resources-convert/template/entry/src/main/module.json5 +0 -55
- package/skills/hmos-resources-convert/template/entry/src/main/resources/base/element/color.json +0 -8
- package/skills/hmos-resources-convert/template/entry/src/main/resources/base/element/float.json +0 -8
- package/skills/hmos-resources-convert/template/entry/src/main/resources/base/element/string.json +0 -16
- package/skills/hmos-resources-convert/template/entry/src/main/resources/base/media/background.png +0 -0
- package/skills/hmos-resources-convert/template/entry/src/main/resources/base/media/foreground.png +0 -0
- package/skills/hmos-resources-convert/template/entry/src/main/resources/base/media/layered_image.json +0 -7
- package/skills/hmos-resources-convert/template/entry/src/main/resources/base/media/startIcon.png +0 -0
- package/skills/hmos-resources-convert/template/entry/src/main/resources/base/profile/backup_config.json +0 -3
- package/skills/hmos-resources-convert/template/entry/src/main/resources/base/profile/main_pages.json +0 -5
- package/skills/hmos-resources-convert/template/entry/src/main/resources/dark/element/color.json +0 -8
- package/skills/hmos-resources-convert/template/entry/src/mock/mock-config.json5 +0 -2
- package/skills/hmos-resources-convert/template/entry/src/ohosTest/ets/test/Ability.test.ets +0 -35
- package/skills/hmos-resources-convert/template/entry/src/ohosTest/ets/test/List.test.ets +0 -5
- package/skills/hmos-resources-convert/template/entry/src/ohosTest/module.json5 +0 -16
- package/skills/hmos-resources-convert/template/entry/src/test/List.test.ets +0 -5
- package/skills/hmos-resources-convert/template/entry/src/test/LocalUnit.test.ets +0 -33
- package/skills/hmos-resources-convert/template/hvigor/hvigor-config.json5 +0 -23
- package/skills/hmos-resources-convert/template/hvigorfile.ts +0 -6
- package/skills/hmos-resources-convert/template/oh-package-lock.json5 +0 -28
- package/skills/hmos-resources-convert/template/oh-package.json5 +0 -10
- package/tools/autotest/deps/autotest-agent-0.1.1.tgz +0 -0
- package/tools/autotest/engine/batch-launcher.ts +0 -326
- package/tools/autotest/engine/report-tool.ts +0 -773
- package/tools/autotest/engine/self-test-runner.ts +0 -1024
- package/tools/autotest/engine/testcases-tool.ts +0 -246
- package/tools/autotest/resolve-metadata-tool.ts +0 -143
- package/tools/autotest/runner/logger.ts +0 -45
- package/tools/autotest/runner/process-utils.ts +0 -41
- package/tools/autotest/validate.ts +0 -115
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mappings/android-to-harmonyOS-ui-atomic-component-mapping-reference.md +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mappings/android-to-harmonyOS-ui-interaction-mapping-reference.md +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mappings/android-to-harmonyOS-ui-layout-mapping-reference.md +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm/@Link/350/243/205/351/245/260/345/231/250/357/274/232/347/210/266/345/255/220/345/217/214/345/220/221/345/220/214/346/255/245.md" +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm/@Observed/350/243/205/351/245/260/345/231/250/345/222/214@ObjectLink/350/243/205/351/245/260/345/231/250/357/274/232/345/265/214/345/245/227/347/261/273/345/257/271/350/261/241/345/261/236/346/200/247/345/217/230/345/214/226.md" +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm/@Prop/350/243/205/351/245/260/345/231/250/357/274/232/347/210/266/345/255/220/345/215/225/345/220/221/345/220/214/346/255/245.md" +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm/@Provide/350/243/205/351/245/260/345/231/250/345/222/214@Consume/350/243/205/351/245/260/345/231/250/357/274/232/344/270/216/345/220/216/344/273/243/347/273/204/344/273/266/345/217/214/345/220/221/345/220/214/346/255/245.md" +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm/@State/350/243/205/351/245/260/345/231/250/357/274/232/347/273/204/344/273/266/345/206/205/347/212/266/346/200/201.md" +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm/@Track/350/243/205/351/245/260/345/231/250/357/274/232class/345/257/271/350/261/241/345/261/236/346/200/247/347/272/247/346/233/264/346/226/260.md" +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm/@Watch/350/243/205/351/245/260/345/231/250/357/274/232/347/212/266/346/200/201/345/217/230/351/207/217/346/233/264/346/224/271/351/200/232/347/237/245.md" +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm/AppStorage/357/274/232/345/272/224/347/224/250/345/205/250/345/261/200/347/232/204UI/347/212/266/346/200/201/345/255/230/345/202/250.md" +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm/Environment/357/274/232/350/256/276/345/244/207/347/216/257/345/242/203/346/237/245/350/257/242.md" +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm/LocalStorage/357/274/232/351/241/265/351/235/242/347/272/247UI/347/212/266/346/200/201/345/255/230/345/202/250.md" +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm/MVVM/346/250/241/345/274/217/357/274/210V1/357/274/211.md" +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm/PersistentStorage/357/274/232/346/214/201/344/271/205/345/214/226/345/255/230/345/202/250UI/347/212/266/346/200/201.md" +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm//347/256/241/347/220/206/345/272/224/347/224/250/346/213/245/346/234/211/347/232/204/347/212/266/346/200/201/346/246/202/350/277/260.md" +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/!!/350/257/255/346/263/225/357/274/232/345/217/214/345/220/221/347/273/221/345/256/232.md" +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/@Computed/350/243/205/351/245/260/345/231/250/357/274/232/350/256/241/347/256/227/345/261/236/346/200/247.md" +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/@Event/350/243/205/351/245/260/345/231/250/357/274/232/350/247/204/350/214/203/347/273/204/344/273/266/350/276/223/345/207/272.md" +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/@Local/350/243/205/351/245/260/345/231/250/357/274/232/347/273/204/344/273/266/345/206/205/351/203/250/347/212/266/346/200/201.md" +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/@Monitor/350/243/205/351/245/260/345/231/250/357/274/232/347/212/266/346/200/201/345/217/230/351/207/217/344/277/256/346/224/271/345/274/202/346/255/245/347/233/221/345/220/254.md" +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/@ObservedV2/350/243/205/351/245/260/345/231/250/345/222/214@Trace/350/243/205/351/245/260/345/231/250/357/274/232/347/261/273/345/261/236/346/200/247/345/217/230/345/214/226/350/247/202/346/265/213.md" +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/@Once/350/243/205/351/245/260/345/231/250/357/274/232/345/210/235/345/247/213/345/214/226/345/220/214/346/255/245/344/270/200/346/254/241.md" +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/@Param/350/243/205/351/245/260/345/231/250/357/274/232/347/273/204/344/273/266/345/244/226/351/203/250/350/276/223/345/205/245.md" +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/@Provider/350/243/205/351/245/260/345/231/250/345/222/214@Consumer/350/243/205/351/245/260/345/231/250/357/274/232/350/267/250/347/273/204/344/273/266/345/261/202/347/272/247/345/217/214/345/220/221/345/220/214/346/255/245.md" +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/@Type/350/243/205/351/245/260/345/231/250/357/274/232/346/240/207/350/256/260/347/261/273/345/261/236/346/200/247/347/232/204/347/261/273/345/236/213.md" +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/AppStorageV2/357/274/232/345/272/224/347/224/250/345/205/250/345/261/200UI/347/212/266/346/200/201/345/255/230/345/202/250.md" +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/MVVM/346/250/241/345/274/217/357/274/210V2/357/274/211.md" +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2/PersistenceV2/357/274/232/346/214/201/344/271/205/345/214/226/345/255/230/345/202/250UI/347/212/266/346/200/201.md" +0 -0
- /package/skills/{hmos-batch-ui-align → a2h-ui-transfer}/references/mvvm-v2//347/212/266/346/200/201/347/256/241/347/220/206V1/345/220/221V2/350/277/201/347/247/273/344/270/216/346/267/267/347/224/250/346/214/207/345/257/274.md" +0 -0
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/index.ts", "../src/paths.ts", "../src/discovery.ts", "../src/env.ts", "../src/tools/a2h-
|
|
4
|
-
"sourcesContent": ["import path from \"node:path\"\r\nimport type { A2HHostDeps, Plugin, PluginInput, PluginHooks } from \"./types\"\r\nimport { PKG_ROOT } from \"./paths\"\r\nimport { discoverA2HAgents } from \"./discovery\"\r\nimport { buildA2HEnvBase } from \"./env\"\r\nimport { makeA2hAppFeatureVerifyTool } from \"./tools/a2h-app-feature-verify\"\r\nimport { makeA2hAutotestResolveMetadataTool } from \"./tools/a2h-autotest-resolve-metadata\"\r\nimport { makeA2hAutotestTestcasesTool } from \"./tools/a2h-autotest-testcases\"\r\nimport { makeA2hAutotestReportTool } from \"./tools/a2h-autotest-report\"\r\nimport { makeA2hAutotestSelftestTool } from \"./tools/a2h-autotest-selftest\"\r\n\r\n// Public re-exports \u2014 the package's external surface (dev eco code loads\r\n// dist/index.js at runtime and calls `createServer`; `A2HHostDeps` /\r\n// `PLUGIN_ID` are kept exported for any TS consumers).\r\nexport type { A2HHostDeps } from \"./types\"\r\nexport { PLUGIN_ID } from \"./paths\"\r\n\r\n/**\r\n * Create the A2H DevEco Code plugin.\r\n *\r\n * This is a self-contained plugin - skills/, agents/, and tools/\r\n * are bundled inside the package, NOT referenced from HomeTrans.\r\n * A2H-Plugin is the independently publishable \"plugin edition\" of HomeTrans.\r\n *\r\n * @param deps - host dependencies injected by DevEco Code's thin bridge.\r\n * The A2H Plugin defines what it needs (A2HHostDeps);\r\n * DevEco Code provides how to resolve it.\r\n * @returns A Plugin function ready to be registered as a built-in plugin.\r\n */\r\nexport function createServer(deps: A2HHostDeps): Plugin {\r\n return async (input: PluginInput): Promise<PluginHooks> => {\r\n // All A2H assets live inside this package (self-contained, no HomeTrans dep)\r\n const skillsRoot = path.join(PKG_ROOT, \"skills\")\r\n const agentsRoot = path.join(PKG_ROOT, \"agents\")\r\n\r\n // Auto-discover agents: scan top-level agents/*.md, parse `name:` from\r\n // frontmatter, strip frontmatter for prompt body. Adding/removing/renaming\r\n // an agent is just a file drop \u2014 no code change, no rebuild.\r\n const agentPrompts = discoverA2HAgents(agentsRoot)\r\n\r\n return {\r\n dispose: async () => {\r\n agentPrompts.clear()\r\n },\r\n\r\n // \u2500\u2500 config hook: register skills search paths and agents \u2500\u2500\r\n config: async (cfg: Record<string, unknown>) => {\r\n // --- Skills ---\r\n const skills = (cfg.skills as Record<string, unknown>) || {}\r\n cfg.skills = skills\r\n\r\n // Register the bundled skills/ directory as an additional search path.\r\n // All bundled skills are user-visible \u2014 there is no partial-visibility\r\n // (hidden) layer anymore, so we only register the search path here.\r\n const paths = (skills.paths as string[]) || []\r\n skills.paths = paths\r\n if (!paths.includes(skillsRoot)) {\r\n paths.push(skillsRoot)\r\n }\r\n\r\n // --- Agents ---\r\n const agent = (cfg.agent as Record<string, Record<string, unknown>>) || {}\r\n cfg.agent = agent\r\n\r\n for (const [name, prompt] of agentPrompts) {\r\n // Don't overwrite if the user already configured this agent\r\n if (!agent[name]) {\r\n agent[name] = {\r\n mode: \"subagent\",\r\n hidden: true,\r\n prompt,\r\n }\r\n }\r\n }\r\n\r\n },\r\n\r\n // \u2500\u2500 shell.env hook: inject DevEco Studio paths + multimodal model \u2500\u2500\r\n // params (from A2HHostDeps.resolveModelParams) as env vars, so the\r\n // UI-alignment scripts (app_feature_verify.ts) can call the model\r\n // without falling back to ~/.hometrans/config.json.\r\n \"shell.env\": async (\r\n shellInput: { cwd: string; sessionID?: string; callID?: string },\r\n output: { env: Record<string, string> },\r\n ) => {\r\n const a2hEnv = await buildA2HEnvBase(deps)\r\n Object.assign(output.env, a2hEnv)\r\n },\r\n\r\n // \u2500\u2500 tool hook: run the UI-verification phone agent without leaking the\r\n // model apiKey into env/argv \u2014 it is resolved from the host and piped to\r\n // the script over stdin. See src/tools/a2h-app-feature-verify.ts.\r\n //\r\n // The autotest_* tools wrap the engine scripts under tools/autotest/\r\n // (vendored from HomeTrans). They are grouped by noun \u2014 each tool\r\n // dispatches on an `action` enum (e.g. `a2h_autotest_selftest` covers\r\n // run|status|kill|check_hap|check_inputs|check_pre), so 11 engine\r\n // subcommands surface as 4 plugin tools. Only `a2h_autotest_selftest`\r\n // with `action:\"run\"` needs a model, resolved via deps.resolveModelParams\r\n // and piped over stdin with the same secret-handling discipline; the\r\n // rest are pure JSON/Markdown transforms or state probes with no model\r\n // and no device.\r\n tool: {\r\n a2h_app_feature_verify: makeA2hAppFeatureVerifyTool(deps),\r\n a2h_autotest_resolve_metadata: makeA2hAutotestResolveMetadataTool(deps),\r\n a2h_autotest_testcases: makeA2hAutotestTestcasesTool(deps),\r\n a2h_autotest_report: makeA2hAutotestReportTool(deps),\r\n a2h_autotest_selftest: makeA2hAutotestSelftestTool(deps),\r\n },\r\n }\r\n }\r\n}\r\n", "import path from \"node:path\"\r\nimport { fileURLToPath } from \"node:url\"\r\n\r\n// Resolve package root (one directory above dist/ or src/). Computed once here\r\n// and imported everywhere else so there's a single source of truth. After\r\n// esbuild bundling, import.meta.url points at dist/index.js, so this still\r\n// resolves to the package root at runtime.\r\nconst __filename = fileURLToPath(import.meta.url)\r\nconst __dirname = path.dirname(__filename)\r\n\r\n/** Absolute path to the A2H-Plugin package root. */\r\nexport const PKG_ROOT = path.resolve(__dirname, \"..\")\r\n\r\n/** Public plugin id. */\r\nexport const PLUGIN_ID = \"android2harmony\"\r\n", "import path from \"node:path\"\r\nimport fs from \"node:fs\"\r\n\r\n/**\r\n * Strip YAML frontmatter (--- ... ---) from agent .md files.\r\n * Agent .md files have metadata in frontmatter; only the body\r\n * should be used as the LLM prompt.\r\n */\r\nexport function stripFrontmatter(content: string): string {\r\n const match = content.match(/^---\\s*\\n([\\s\\S]*?)\\n---\\s*\\n/)\r\n return match ? content.slice(match[0].length).trim() : content\r\n}\r\n\r\n/**\r\n * Minimal YAML frontmatter extractor for A2H-owned `.md` files (SKILL.md\r\n * and agent `.md`). A2H controls the frontmatter format, so we only need\r\n * the top-level `name` (a scalar). This avoids pulling a YAML dependency\r\n * into the plugin.\r\n *\r\n * Returns the parsed `name`, or null when the file has no usable frontmatter\r\n * (e.g. a README dropped into a directory that's also scanned for agents).\r\n */\r\nexport function parseFrontmatter(content: string): string | null {\r\n const match = content.match(/^---\\s*\\r?\\n([\\s\\S]*?)\\r?\\n---/)\r\n if (!match) return null\r\n const lines = match[1].split(/\\r?\\n/)\r\n\r\n for (const line of lines) {\r\n if (!line.trim() || line.trim().startsWith(\"#\")) continue\r\n if (line.length - line.trimStart().length !== 0) continue // skip indented (e.g. metadata block) lines\r\n\r\n const kv = line.trim().match(/^([a-zA-Z_][a-zA-Z0-9_-]*):\\s*(.*)$/)\r\n if (!kv) continue\r\n if (kv[1] === \"name\") {\r\n return kv[2].trim().replace(/^[\"']|[\"']$/g, \"\")\r\n }\r\n }\r\n\r\n return null\r\n}\r\n\r\n/**\r\n * Scan the bundled agents/ directory and return a `name \u2192 prompt body` map.\r\n *\r\n * Only top-level `.md` files are considered (subdirectories like `scripts/`\r\n * are skipped via `isFile()`). Files without a `name:` field in frontmatter\r\n * (e.g. a stray README) are silently skipped \u2014 the frontmatter name is the\r\n * source of truth, not the file basename. The body (frontmatter stripped)\r\n * becomes the LLM prompt.\r\n *\r\n * Adding a new agent is therefore a zero-code, zero-rebuild change: just\r\n * drop an `.md` with `name:` frontmatter into `agents/`.\r\n */\r\nexport function discoverA2HAgents(agentsRoot: string): Map<string, string> {\r\n const result = new Map<string, string>()\r\n let entries: fs.Dirent[]\r\n try {\r\n entries = fs.readdirSync(agentsRoot, { withFileTypes: true })\r\n } catch {\r\n return result\r\n }\r\n for (const entry of entries) {\r\n if (!entry.isFile() || !entry.name.endsWith(\".md\")) continue\r\n const file = path.join(agentsRoot, entry.name)\r\n let raw: string\r\n try {\r\n raw = fs.readFileSync(file, \"utf-8\")\r\n } catch {\r\n continue\r\n }\r\n const name = parseFrontmatter(raw)\r\n if (!name) continue // not a valid agent file (no `name:` frontmatter)\r\n result.set(name, stripFrontmatter(raw))\r\n }\r\n return result\r\n}\r\n", "import path from \"node:path\"\nimport type { A2HHostDeps } from \"./types\"\n\n/**\n * Build the A2H env var set from host-injected deps. Shared by the `shell.env`\n * hook (so every shell session sees these). Env vars are the single source of\n * truth in the plugin context for non-secret paths.\n *\n * Contains only DevEco/SDK path vars. The multimodal model apiKey is NOT\n * injected here anymore \u2014 putting it in `process.env` leaked it to every\n * descendant process (adb/hdc, sub-agents), to `/proc/<pid>/environ`, crash\n * dumps, and any `env`/`printenv` output. Instead the `a2h_app_feature_verify`\n * plugin tool resolves the params via `A2HHostDeps.resolveModelParams` and pipes\n * them to the script over stdin (`--model-stdin`), so the key stays in process\n * memory + the stdin pipe and never enters env/argv/disk.\n *\n * Nothing secret is present in this env set, but it is still good hygiene not\n * to dump it into logs verbatim.\n */\nexport async function buildA2HEnvBase(\n deps: A2HHostDeps,\n): Promise<Record<string, string>> {\n const env: Record<string, string> = {}\n\n const home = await deps.resolveDevEcoHome()\n if (home) {\n const sdk = deps.resolveSdkPath(home)\n env[\"DEVECO_HOME\"] = home\n env[\"DEVECO_SDK_HOME\"] = sdk\n env[\"OHOS_SDK_PATH\"] = path.join(sdk, \"default\", \"openharmony\", \"ets\")\n env[\"HMS_SDK_PATH\"] = path.join(sdk, \"default\", \"hms\", \"ets\")\n }\n\n return env\n}\n", "import { spawn } from \"node:child_process\"\nimport path from \"node:path\"\nimport { PKG_ROOT } from \"../paths\"\nimport type { A2HHostDeps, ToolContext, ToolDefinition } from \"../types\"\n\n// The bundled UI-feature-verification script (TypeScript, run directly by\n// Node \u2265 22.18 which strips types natively \u2014 same as when the agent ran\n// `node app_feature_verify.ts` via the shell).\nconst SCRIPT_PATH = path.join(\n PKG_ROOT,\n \"skills\",\n \"hmos-incremental-ui-align\",\n \"scripts\",\n \"app_feature_verify.ts\",\n)\n\n/**\n * Env vars that may carry a model apiKey. Stripped from the child's env so the\n * key is never inherited by the spawned script or its adb/hdc descendants. The\n * script instead receives the key via the stdin pipe (`--model-stdin`).\n */\nconst SECRET_ENV = [\n \"HOMETRANS_MODEL_API_KEY\",\n \"HOMETRANS_MODEL_NAME\",\n \"HOMETRANS_MODEL_BASE_URL\",\n \"GLM_API_KEY\",\n \"TEST_API_KEY\",\n] as const\n\n/** Cap stdout returned to the host so a runaway loop can't overflow the chat. */\nfunction cap(s: string, max = 50000): string {\n if (s.length <= max) return s\n const half = Math.floor(max / 2)\n return s.slice(0, half) + `\\n\u2026[truncated ${s.length - max} chars]\u2026\\n` + s.slice(-half)\n}\n\n/**\n * Build the `a2h_app_feature_verify` plugin tool.\n *\n * Spawns app_feature_verify.ts with the model config piped to its stdin, so the\n * apiKey travels only through the OS pipe + process memory \u2014 never env, argv,\n * or a plugin-written file. The host resolves the params (apiKey) via\n * `deps.resolveModelParams`; the tool is the only thing that ever holds it.\n */\nexport function makeA2hAppFeatureVerifyTool(deps: A2HHostDeps): ToolDefinition {\n return {\n description:\n \"Run the a2h UI feature-verification phone agent (app_feature_verify.ts) to navigate an app and verify a feature path on a connected device. The multimodal model apiKey is resolved from the host and piped to the script over stdin \u2014 it is never placed in env or argv, so it is not visible to the spawned adb/hdc subprocesses. Use this instead of running `node app_feature_verify.ts` directly. The script runs its internal agent loop (screenshot \u2192 model \u2192 action) up to maxSteps and prints per-step thinking + actions; the full stdout is returned on success. One of task/prompt/feature is required; app and package are required.\",\n args: {\n type: \"object\",\n properties: {\n app: { type: \"string\", description: \"\u76EE\u6807 app \u663E\u793A\u540D\uFF08required\uFF09\" },\n package: { type: \"string\", description: \"\u76EE\u6807 app \u5305\u540D\uFF08required\uFF09\" },\n device: {\n type: \"string\",\n enum: [\"hdc\", \"adb\"],\n default: \"hdc\",\n description: \"\u8BBE\u5907\u9A71\u52A8\uFF1Ahdc(HarmonyOS) / adb(Android)\",\n },\n task: {\n type: \"string\",\n description: \"L1/L2/L3 \u4EFB\u52A1\u8DEF\u5F84\uFF0C\u5982 L1\u76F8\u518C\u8BE6\u60C5L2\u66F4\u591A\uFF08\u4E0E prompt/feature \u4E09\u9009\u4E00\uFF09\",\n },\n prompt: { type: \"string\", description: \"\u81EA\u7531 prompt\uFF08\u4E0E task/feature \u4E09\u9009\u4E00\uFF09\" },\n feature: { type: \"string\", description: \".md \u529F\u80FD\u6E05\u5355\u8DEF\u5F84\uFF08\u4E0E task/prompt \u4E09\u9009\u4E00\uFF09\" },\n maxSteps: { type: \"number\", default: 30, description: \"\u6700\u5927 agent \u6B65\u6570\" },\n appHints: { type: \"string\", description: \"\u5E94\u7528\u5BFC\u822A\u63D0\u793A\" },\n serial: { type: \"string\", description: \"\u8BBE\u5907\u5E8F\u5217\u53F7\" },\n limit: { type: \"number\", description: \"--feature \u6A21\u5F0F\u4E0B\u53D6\u524D N \u6761\" },\n offset: { type: \"number\", default: 1, description: \"--feature \u6A21\u5F0F\u4E0B\u504F\u79FB\" },\n quiet: { type: \"boolean\", default: false, description: \"\u6291\u5236\u63D0\u793A\u6027\u8F93\u51FA\" },\n },\n required: [\"app\", \"package\"],\n },\n execute: async (args: Record<string, unknown>, context: ToolContext) => {\n const app = String(args.app ?? \"\")\n const pkg = String(args.package ?? \"\")\n if (!app || !pkg) {\n throw new Error(\"a2h_app_feature_verify: `app` and `package` are required\")\n }\n const task = args.task != null ? String(args.task) : null\n const prompt = args.prompt != null ? String(args.prompt) : null\n const feature = args.feature != null ? String(args.feature) : null\n if (!task && !prompt && !feature) {\n throw new Error(\"a2h_app_feature_verify: one of `task` / `prompt` / `feature` is required\")\n }\n\n // Resolve host model params \u2014 the apiKey lives only in this process's\n // memory from here on.\n const model = await deps.resolveModelParams(context.worktree)\n if (!model || !model.apiKey) {\n throw new Error(\"a2h_app_feature_verify: host did not provide model params (apiKey missing)\")\n }\n\n // Assemble argv from provided args; append --model-stdin so the script\n // reads model config from stdin rather than env/argv.\n const argv: string[] = [\"--app\", app, \"--package\", pkg, \"--device\", String(args.device ?? \"hdc\")]\n if (task) argv.push(\"--task\", task)\n if (prompt) argv.push(\"--prompt\", prompt)\n if (feature) argv.push(\"--feature\", feature)\n if (args.maxSteps != null) argv.push(\"--max-steps\", String(args.maxSteps))\n if (args.appHints != null) argv.push(\"--app-hints\", String(args.appHints))\n if (args.serial != null) argv.push(\"--serial\", String(args.serial))\n if (args.limit != null) argv.push(\"--limit\", String(args.limit))\n if (args.offset != null) argv.push(\"--offset\", String(args.offset))\n if (args.quiet === true) argv.push(\"--quiet\")\n argv.push(\"--model-stdin\")\n\n // Sanitize env: strip every var that could carry a model apiKey so the\n // child (and its adb/hdc descendants) cannot read it from the environment.\n const env: NodeJS.ProcessEnv = { ...process.env }\n for (const k of SECRET_ENV) delete env[k]\n\n // Spawn via PATH `node` (same binary the shell used to run the .ts script\n // \u2014 guaranteed \u2265 22.18 for native TS). process.execPath might be an older\n // host node, so prefer PATH resolution to match prior working behavior.\n const child = spawn(\"node\", [SCRIPT_PATH, ...argv], {\n cwd: context.directory,\n env,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n })\n\n // Pipe the model config to the child's stdin and close it \u2014 the key\n // traverses only the OS pipe, never env/argv/disk.\n child.stdin.end(\n JSON.stringify({ apiKey: model.apiKey, modelName: model.modelName, baseURL: model.baseURL }),\n )\n\n let stdout = \"\"\n let stderr = \"\"\n let spawnError = \"\"\n const stepRe = /\u6267\u884C\u52A8\u4F5C:\\s*(.*)/g\n child.stdout.on(\"data\", (chunk: Buffer) => {\n const text = chunk.toString(\"utf8\")\n stdout += text\n // Surface the latest step's action as the tool's running title.\n const matches = [...text.matchAll(stepRe)]\n if (matches.length) {\n const last = matches[matches.length - 1][1].trim()\n try {\n context.metadata({ title: `UI verify: ${last.slice(0, 80)}` })\n } catch {\n /* host may not implement metadata \u2014 non-essential */\n }\n }\n })\n child.stderr.on(\"data\", (chunk: Buffer) => {\n stderr += chunk.toString(\"utf8\")\n })\n\n // Honor abort: kill the child if the host cancels the tool call.\n const onAbort = () => {\n if (!child.killed) child.kill(\"SIGTERM\")\n }\n context.abort.addEventListener(\"abort\", onAbort)\n\n const code: number = await new Promise((resolve) => {\n child.on(\"close\", resolve)\n child.on(\"error\", (err: Error) => {\n spawnError = err.message\n resolve(-1)\n })\n })\n context.abort.removeEventListener(\"abort\", onAbort)\n\n if (code !== 0) {\n if (spawnError) {\n throw new Error(`a2h_app_feature_verify: failed to spawn node \u2014 ${spawnError}`)\n }\n const tail = stderr.slice(-2000)\n throw new Error(`a2h_app_feature_verify failed (exit ${code}): ${tail || \"(no stderr)\"}`)\n }\n return { ok: true, exitCode: code, output: cap(stdout) }\n },\n }\n}\n", "import path from \"node:path\"\nimport type { A2HHostDeps, ToolContext, ToolDefinition } from \"../types\"\nimport { AUTOTEST_ROOT, autotestToolError, runAutotestScript } from \"./autotest-shared\"\n\nconst SCRIPT_REL = path.join(\"resolve-metadata-tool.ts\")\nconst TOOL_ID = \"a2h_autotest_resolve_metadata\"\n\n/**\n * Build the `a2h_autotest_resolve_metadata` plugin tool.\n *\n * Wraps `tools/autotest/resolve-metadata-tool.ts`: deterministically resolves\n * `bundle_name` / `app_name` from a HarmonyOS project's `AppScope/app.json5`\n * (resolving `$string:xxx` refs) and writes `app-metadata.json`. No model, no\n * device \u2014 pure metadata extraction.\n */\nexport function makeA2hAutotestResolveMetadataTool(_deps: A2HHostDeps): ToolDefinition {\n return {\n description:\n \"Resolve bundle_name / app_name from a HarmonyOS project (reads AppScope/app.json5 and resolves $string refs) and writes app-metadata.json. Pure metadata extraction \u2014 no model, no device. Use this instead of running `node resolve-metadata-tool.ts` directly. Returns the written metadata JSON path + stdout on success.\",\n args: {\n type: \"object\",\n properties: {\n projectDir: {\n type: \"string\",\n description: \"HarmonyOS \u5DE5\u7A0B\u6839\u76EE\u5F55\uFF08\u542B AppScope/app.json5\uFF09\",\n },\n output: {\n type: \"string\",\n description: \"app-metadata.json \u8F93\u51FA\u8DEF\u5F84\",\n },\n },\n required: [\"projectDir\", \"output\"],\n },\n execute: async (args: Record<string, unknown>, context: ToolContext) => {\n const projectDir = String(args.projectDir ?? \"\")\n const output = String(args.output ?? \"\")\n if (!projectDir || !output) {\n throw new Error(`${TOOL_ID}: \\`projectDir\\` and \\`output\\` are required`)\n }\n const argv = [\"--project-dir\", projectDir, \"--output\", output]\n const r = await runAutotestScript({\n scriptRel: SCRIPT_REL,\n argv,\n cwd: context.directory,\n abort: context.abort,\n })\n if (!r.ok) throw autotestToolError(TOOL_ID, r)\n return { ok: true, exitCode: r.exitCode, output: r.stdout }\n },\n }\n}\n", "import { spawn } from \"node:child_process\"\nimport path from \"node:path\"\nimport { PKG_ROOT } from \"../paths\"\n\n/**\n * Shared spawn harness for the a2h autotest plugin tools. Each tool wraps a\n * `node <tools/autotest/...>.ts` engine script; this centralizes the\n * boilerplate (PATH `node` for \u226522.18 native TS, secret-env strip, captured\n * stdio, abort, output cap) so the 4 tool files stay thin.\n */\nexport const AUTOTEST_ROOT = path.join(PKG_ROOT, \"tools\", \"autotest\")\n\n/**\n * Env vars that may carry a model apiKey. Stripped from the child's env so the\n * key is never inherited by the spawned script or its hdc/adb descendants. The\n * selftest `run` script instead receives the key via the stdin pipe\n * (`--model-stdin`).\n */\nconst SECRET_ENV = [\n \"HOMETRANS_MODEL_API_KEY\",\n \"HOMETRANS_MODEL_NAME\",\n \"HOMETRANS_MODEL_BASE_URL\",\n \"GLM_API_KEY\",\n \"TEST_API_KEY\",\n] as const\n\n/** Cap stdout returned to the host so a runaway loop can't overflow the chat. */\nexport function cap(s: string, max = 50000): string {\n if (s.length <= max) return s\n const half = Math.floor(max / 2)\n return s.slice(0, half) + `\\n\u2026[truncated ${s.length - max} chars]\u2026\\n` + s.slice(-half)\n}\n\nexport interface RunOpts {\n /** Path under tools/autotest/ to the engine .ts script, e.g. \"engine/self-test-runner.ts\". */\n scriptRel: string\n /** Argv after the script path (subcommand + flags). */\n argv: string[]\n /** Working directory (typically context.directory). */\n cwd: string\n /** Abort signal from the tool context. */\n abort: AbortSignal\n /** Optional stdin payload (e.g. model config JSON) \u2014 written then closed. */\n stdin?: string\n /** Optional progress hook for stdout chunks (surfaces a running title). */\n onStdoutChunk?: (text: string) => void\n}\n\nexport interface RunResult {\n ok: boolean\n exitCode: number\n stdout: string\n stderr: string\n spawnError: string\n}\n\n/**\n * Spawn `node <tools/autotest/...> argv` with secret env stripped, captured\n * stdio, and abort \u2192 SIGTERM the child. Resolves with a RunResult (never\n * rejects); callers decide ok/fail from `exitCode`).\n */\nexport function runAutotestScript(opts: RunOpts): Promise<RunResult> {\n return new Promise((resolve) => {\n const scriptPath = path.join(AUTOTEST_ROOT, opts.scriptRel)\n const env: NodeJS.ProcessEnv = { ...process.env }\n for (const k of SECRET_ENV) delete env[k]\n\n // PATH `node` (guaranteed \u2265 22.18 for native TS type-stripping); process.execPath\n // may be an older host node, so prefer PATH resolution (matches a2h_app_feature_verify).\n const child = spawn(\"node\", [scriptPath, ...opts.argv], {\n cwd: opts.cwd,\n env,\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n })\n\n let stdout = \"\"\n let stderr = \"\"\n let spawnError = \"\"\n\n child.stdout.on(\"data\", (chunk: Buffer) => {\n const text = chunk.toString(\"utf8\")\n stdout += text\n opts.onStdoutChunk?.(text)\n })\n child.stderr.on(\"data\", (chunk: Buffer) => {\n stderr += chunk.toString(\"utf8\")\n })\n\n // Write the stdin payload (or just close stdin) \u2014 the key travels only\n // through the OS pipe, never env/argv/disk.\n child.stdin.end(opts.stdin ?? \"\")\n\n const onAbort = () => {\n if (!child.killed) child.kill(\"SIGTERM\")\n }\n opts.abort.addEventListener(\"abort\", onAbort)\n\n child.on(\"close\", (code: number | null) => {\n opts.abort.removeEventListener(\"abort\", onAbort)\n resolve({ ok: code === 0, exitCode: code ?? -1, stdout: cap(stdout), stderr, spawnError })\n })\n child.on(\"error\", (err: Error) => {\n opts.abort.removeEventListener(\"abort\", onAbort)\n spawnError = err.message\n resolve({ ok: false, exitCode: -1, stdout: cap(stdout), stderr, spawnError })\n })\n })\n}\n\n/** Build a tool-shaped Error from a non-zero run result. */\nexport function autotestToolError(toolId: string, r: RunResult): Error {\n if (r.spawnError) return new Error(`${toolId}: failed to spawn node \u2014 ${r.spawnError}`)\n const tail = r.stderr.slice(-2000)\n return new Error(`${toolId} failed (exit ${r.exitCode}): ${tail || \"(no stderr)\"}`)\n}\n", "import path from \"node:path\"\nimport type { A2HHostDeps, ToolContext, ToolDefinition } from \"../types\"\nimport { autotestToolError, runAutotestScript } from \"./autotest-shared\"\n\nconst SCRIPT_REL = path.join(\"engine\", \"testcases-tool.ts\")\nconst TOOL_ID = \"a2h_autotest_testcases\"\n\n/**\n * Build the `a2h_autotest_testcases` plugin tool \u2014 the grouped entry point for\n * the testcases engine (`tools/autotest/engine/testcases-tool.ts`).\n *\n * Two actions, dispatched on `action`:\n * - `generate`: build a schema-compliant testcases.json from extractor output\n * ({ bundle_name, app_name, cases:[{case_name,actions,expected_results}] }).\n * Optional `validate` validates the generated file in place.\n * - `validate`: check an existing testcases.json against the schema.\n *\n * No model, no device. Transform convention \u2014 a non-zero exit is a real\n * failure: `autotestToolError` is thrown (only `generate`/`validate` are\n * transform ops, never state probes).\n */\nexport function makeA2hAutotestTestcasesTool(_deps: A2HHostDeps): ToolDefinition {\n return {\n description:\n \"HarmonyOS self-test testcases.json engine \u2014 grouped by noun, dispatched on `action`. `generate`: build a schema-compliant testcases.json from extractor output ({ bundle_name, app_name, cases:[{case_name,actions,expected_results}] }); pass `validate` to validate in place. `validate`: check an existing testcases.json against the schema. No model, no device. Non-zero exit is a failure (thrown). Use this instead of running `node testcases-tool.ts` directly.\",\n args: {\n type: \"object\",\n properties: {\n action: {\n type: \"string\",\n enum: [\"generate\", \"validate\"],\n description: \"generate=\u4ECE\u62BD\u53D6\u8F93\u51FA\u5EFA testcases.json\uFF1Bvalidate=\u6821\u9A8C\u5DF2\u6709 testcases.json\",\n },\n input: { type: \"string\", description: \"[generate] \u62BD\u53D6\u8F93\u51FA JSON \u8DEF\u5F84\" },\n output: { type: \"string\", description: \"[generate] testcases.json \u8F93\u51FA\u8DEF\u5F84\" },\n validate: { type: \"boolean\", default: false, description: \"[generate] \u5199\u5B8C\u540E\u5C31\u5730\u6821\u9A8C\" },\n path: { type: \"string\", description: \"[validate] \u8981\u6821\u9A8C\u7684 testcases.json \u8DEF\u5F84\" },\n },\n required: [\"action\"],\n },\n execute: async (args: Record<string, unknown>, context: ToolContext) => {\n const action = String(args.action ?? \"\")\n if (action === \"generate\") {\n const input = String(args.input ?? \"\")\n const output = String(args.output ?? \"\")\n if (!input || !output) {\n throw new Error(`${TOOL_ID}: \\`action:\"generate\"\\` requires \\`input\\` and \\`output\\``)\n }\n const argv = [\"generate\", input, output]\n if (args.validate === true) argv.push(\"--validate\")\n const r = await runAutotestScript({\n scriptRel: SCRIPT_REL,\n argv,\n cwd: context.directory,\n abort: context.abort,\n })\n if (!r.ok) throw autotestToolError(TOOL_ID, r)\n return { ok: true, exitCode: r.exitCode, output: r.stdout }\n }\n if (action === \"validate\") {\n const p = String(args.path ?? \"\")\n if (!p) {\n throw new Error(`${TOOL_ID}: \\`action:\"validate\"\\` requires \\`path\\``)\n }\n const argv = [\"validate\", p]\n const r = await runAutotestScript({\n scriptRel: SCRIPT_REL,\n argv,\n cwd: context.directory,\n abort: context.abort,\n })\n if (!r.ok) throw autotestToolError(TOOL_ID, r)\n return { ok: true, exitCode: r.exitCode, output: r.stdout }\n }\n throw new Error(`${TOOL_ID}: unknown \\`action\\` \"${action}\" (expected generate|validate)`)\n },\n }\n}\n", "import path from \"node:path\"\nimport type { A2HHostDeps, ToolContext, ToolDefinition } from \"../types\"\nimport { autotestToolError, runAutotestScript } from \"./autotest-shared\"\n\nconst SCRIPT_REL = path.join(\"engine\", \"report-tool.ts\")\nconst TOOL_ID = \"a2h_autotest_report\"\n\n/**\n * Build the `a2h_autotest_report` plugin tool \u2014 the grouped entry point for\n * the report engine (`tools/autotest/engine/report-tool.ts`).\n *\n * Two actions, dispatched on `action`:\n * - `generate`: render self-test-report.md from a task_<ts>/ directory\n * (summary.json + task_results.jsonl + per-case judgment logs). Optional\n * `validate` validates the rendered report in place.\n * - `validate`: check an existing self-test-report.md's layout.\n *\n * No model, no device. Transform convention \u2014 non-zero exit is a real failure\n * (`autotestToolError` thrown).\n */\nexport function makeA2hAutotestReportTool(_deps: A2HHostDeps): ToolDefinition {\n return {\n description:\n \"HarmonyOS self-test report engine \u2014 grouped by noun, dispatched on `action`. `generate`: render self-test-report.md from a task_<ts>/ directory (summary.json + task_results.jsonl + per-case judgment logs): overview, pre-cases, regular-cases, summary table, suggestions; pass `validate` to validate in place. `validate`: check an existing report.md's layout. No model, no device. Non-zero exit is a failure (thrown). Use this instead of running `node report-tool.ts` directly.\",\n args: {\n type: \"object\",\n properties: {\n action: {\n type: \"string\",\n enum: [\"generate\", \"validate\"],\n description: \"generate=\u4ECE task \u76EE\u5F55\u6E32\u67D3 self-test-report.md\uFF1Bvalidate=\u6821\u9A8C\u5DF2\u6709 report.md \u5E03\u5C40\",\n },\n taskSubdir: { type: \"string\", description: \"[generate] task_<ts>/ \u76EE\u5F55\u8DEF\u5F84\" },\n appMetadata: { type: \"string\", description: \"[generate] app-metadata.json \u8DEF\u5F84\" },\n hap: { type: \"string\", description: \"[generate] HAP \u6587\u4EF6\u8DEF\u5F84\" },\n device: { type: \"string\", description: \"[generate] \u8BBE\u5907\u6807\u8BC6\uFF08\u5982 127.0.0.1:5555\uFF09\" },\n suite: { type: \"string\", description: \"[generate] \u6D4B\u8BD5\u5957\u4EF6\u6807\u9898\" },\n out: { type: \"string\", description: \"[generate] self-test-report.md \u8F93\u51FA\u8DEF\u5F84\" },\n validate: { type: \"boolean\", default: false, description: \"[generate] \u5199\u5B8C\u540E\u5C31\u5730\u6821\u9A8C\" },\n path: { type: \"string\", description: \"[validate] \u8981\u6821\u9A8C\u7684 report.md \u8DEF\u5F84\" },\n },\n required: [\"action\"],\n },\n execute: async (args: Record<string, unknown>, context: ToolContext) => {\n const action = String(args.action ?? \"\")\n if (action === \"generate\") {\n const taskSubdir = String(args.taskSubdir ?? \"\")\n const appMetadata = String(args.appMetadata ?? \"\")\n const hap = String(args.hap ?? \"\")\n const device = String(args.device ?? \"\")\n const suite = String(args.suite ?? \"\")\n const out = String(args.out ?? \"\")\n if (!taskSubdir || !appMetadata || !hap || !device || !suite || !out) {\n throw new Error(\n `${TOOL_ID}: \\`action:\"generate\"\\` requires \\`taskSubdir\\`, \\`appMetadata\\`, \\`hap\\`, \\`device\\`, \\`suite\\`, \\`out\\``,\n )\n }\n const argv = [\n \"generate\",\n \"--task-subdir\", taskSubdir,\n \"--app-metadata\", appMetadata,\n \"--hap\", hap,\n \"--device\", device,\n \"--suite\", suite,\n \"--out\", out,\n ]\n if (args.validate === true) argv.push(\"--validate\")\n const r = await runAutotestScript({\n scriptRel: SCRIPT_REL,\n argv,\n cwd: context.directory,\n abort: context.abort,\n })\n if (!r.ok) throw autotestToolError(TOOL_ID, r)\n return { ok: true, exitCode: r.exitCode, output: r.stdout }\n }\n if (action === \"validate\") {\n const p = String(args.path ?? \"\")\n if (!p) {\n throw new Error(`${TOOL_ID}: \\`action:\"validate\"\\` requires \\`path\\``)\n }\n const argv = [\"validate\", p]\n const r = await runAutotestScript({\n scriptRel: SCRIPT_REL,\n argv,\n cwd: context.directory,\n abort: context.abort,\n })\n if (!r.ok) throw autotestToolError(TOOL_ID, r)\n return { ok: true, exitCode: r.exitCode, output: r.stdout }\n }\n throw new Error(`${TOOL_ID}: unknown \\`action\\` \"${action}\" (expected generate|validate)`)\n },\n }\n}\n", "import { spawn } from \"node:child_process\"\nimport path from \"node:path\"\nimport type { A2HHostDeps, ToolContext, ToolDefinition } from \"../types\"\nimport { AUTOTEST_ROOT, runAutotestScript } from \"./autotest-shared\"\n\nconst SCRIPT_REL = path.join(\"engine\", \"self-test-runner.ts\")\nconst TOOL_ID = \"a2h_autotest_selftest\"\n\n/**\n * Build the `a2h_autotest_selftest` plugin tool \u2014 the grouped entry point for\n * the self-test engine (`tools/autotest/engine/self-test-runner.ts`).\n *\n * Six actions, dispatched on `action`:\n * - `run`: hdc uninstall+install of the HAP, then spawn a detached\n * `@autotest/agent` batch. The multimodal model is resolved via the host's\n * `deps.resolveModelParams(worktree)` and piped through stdin\n * (`--model-stdin`) \u2014 the apiKey never touches env/argv/disk. Without\n * `timeout`, returns RUNNING JSON immediately (exit 2); with `timeout`,\n * blocks until terminal or timeout (0 COMPLETED / 1 FAILED / 3 CRASHED /\n * 4 NOT_STARTED / 5 TIMEOUT). Abort fires a detached `kill --task-dir`.\n * - `status`: probe on-disk state (summary.json / task_results.jsonl / pid\n * liveness). 0 COMPLETED / 2 RUNNING / 3 CRASHED / 4 NOT_STARTED.\n * - `kill`: terminate the batch tree via the pid file. NO_PID_FILE /\n * ALREADY_DEAD / KILLED.\n * - `check_hap`: validate a hap_path (every entry exists + \u22651 entry HAP).\n * - `check_inputs`: validate testcases.json parses to a non-empty array +\n * app-metadata.json has required fields.\n * - `check_pre`: assert [PRE]-prefixed cases are contiguous from index 0.\n *\n * All six use the STATE convention \u2014 exit codes are states/check results, NOT\n * failures: only a spawn error throws; otherwise the stdout JSON + exitCode\n * are returned for the caller to branch on (non-zero = a state or a failed\n * check, reason in stdout).\n *\n * Only `run` needs a model. The factory takes `deps` so the `run` branch can\n * call `deps.resolveModelParams`; the other five branches ignore `deps`.\n */\nexport function makeA2hAutotestSelftestTool(deps: A2HHostDeps): ToolDefinition {\n return {\n description:\n \"HarmonyOS on-device self-test engine \u2014 grouped by noun, dispatched on `action`. `run`: hdc uninstall+install of HAP, then a detached @autotest/agent batch (multimodal model resolved by the host, piped via stdin; never env/argv/disk). Without `timeout` returns RUNNING immediately (exit 2); with `timeout` blocks until terminal (0 COMPLETED / 1 FAILED / 3 CRASHED / 4 NOT_STARTED / 5 TIMEOUT). `status`: probe on-disk state (0/2/3/4). `kill`: tear down the batch tree. `check_hap`/`check_inputs`/`check_pre`: pre-flight validators (0 = passed). Exit codes are states, not errors \u2014 branch on `status` in the returned JSON. Only `run` needs a model. Use this instead of running `node self-test-runner.ts` directly.\",\n args: {\n type: \"object\",\n properties: {\n action: {\n type: \"string\",\n enum: [\"run\", \"status\", \"kill\", \"check_hap\", \"check_inputs\", \"check_pre\"],\n description:\n \"run=\u88C5 HAP + \u8DD1 batch\uFF08\u9700\u6A21\u578B\uFF09\uFF1Bstatus=\u63A2\u72B6\u6001\uFF1Bkill=\u7EC8\u6B62 batch\uFF1Bcheck_hap=\u6821\u9A8C hap_path\uFF1Bcheck_inputs=\u6821\u9A8C testcases+metadata\uFF1Bcheck_pre=\u6821\u9A8C [PRE] \u8FDE\u7EED\",\n },\n // \u2500\u2500 run \u2500\u2500\n testcases: { type: \"string\", description: \"[run/check_inputs/check_pre] \u6D4B\u8BD5\u7528\u4F8B\u6587\u4EF6\uFF08JSON \u6570\u7EC4\u6216 JSONL\uFF09\" },\n hap: { type: \"string\", description: \"[run/check_hap] \u7B7E\u540D\u5305\uFF08.hap/.hsp \u6587\u4EF6\u3001\u76EE\u5F55\uFF0C\u6216\u9017\u53F7\u5206\u9694\u591A\u9879\uFF09\" },\n bundleName: { type: \"string\", description: \"[run] \u5305\u540D\uFF08bundle_name\uFF09\" },\n taskDir: {\n type: \"string\",\n description: \"[run/status/kill] \u4EFB\u52A1\u76EE\u5F55\uFF08run \u5185\u90E8\u5EFA task_<ts> \u5B50\u76EE\u5F55\uFF1B\u4E0D\u4F20\u5219\u9ED8\u8BA4 'task'\uFF09\u3002status/kill \u636E\u6B64\u627E batch.pid\",\n },\n outputDir: { type: \"string\", description: \"[run/status] \u65E5\u5FD7\u76EE\u5F55\uFF08\u4E0D\u4F20\u5219\u540C taskDir\uFF09\" },\n category: { type: \"string\", description: \"[run] \u6D4B\u8BD5\u5206\u7C7B\u540D\uFF0C\u4F20\u7ED9 batch-launcher\" },\n timeout: {\n type: [\"number\", \"string\"],\n description: \"[run] \u963B\u585E\u81F3\u7EC8\u6001\u6216\u8D85\u65F6\u3002\u6570\u503C=\u79D2\u6570\uFF1B\\\"auto\\\"=\u5F15\u64CE\u89E3\u6790 testcases \u540E\u6309\u7528\u4F8B\u6570\u00D7720s \u81EA\u52A8\u63A8\u5BFC\uFF08\u6BCF\u4F8B 10min + 20% \u4F59\u91CF\uFF09\u3002\u4E0D\u4F20\u5219\u7ACB\u5373\u8FD4\u56DE RUNNING\uFF1B\u8D85\u65F6\u540E\u81EA\u52A8 kill batch \u5E76\u8FD4\u56DE TIMEOUT\uFF08exit 5\uFF09\",\n },\n deviceSn: { type: \"string\", description: \"[run] \u8BBE\u5907\u5E8F\u5217\u53F7\uFF08\u2192 AutoTestAgent.deviceSn\uFF09\" },\n ip: { type: \"string\", description: \"[run] \u8BBE\u5907 IP\uFF08\u2192 AutoTestAgent.ip\uFF09\" },\n port: { type: \"string\", description: \"[run] \u8BBE\u5907\u7AEF\u53E3\uFF08\u2192 AutoTestAgent.port\uFF09\" },\n agentMode: { type: \"string\", description: \"[run] agent \u6A21\u5F0F\uFF08\u9ED8\u8BA4 single\uFF09\" },\n maxSteps: { type: \"number\", description: \"[run] \u5355\u7528\u4F8B\u6700\u5927\u6B65\u6570\" },\n promptVersion: { type: \"string\", description: \"[run] prompt \u7248\u672C\uFF08\u9ED8\u8BA4 v2.0\uFF09\" },\n // \u2500\u2500 check_inputs \u2500\u2500\n metadata: { type: \"string\", description: \"[check_inputs] app-metadata.json \u8DEF\u5F84\" },\n },\n required: [\"action\"],\n },\n execute: async (args: Record<string, unknown>, context: ToolContext) => {\n const action = String(args.action ?? \"\")\n\n // \u2500\u2500 run \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (action === \"run\") {\n const testcases = String(args.testcases ?? \"\")\n const hap = String(args.hap ?? \"\")\n const bundleName = String(args.bundleName ?? \"\")\n if (!testcases || !hap || !bundleName) {\n throw new Error(`${TOOL_ID}: \\`action:\"run\"\\` requires \\`testcases\\`, \\`hap\\`, \\`bundleName\\``)\n }\n // Effective taskDir drives both argv and the abort-cleanup kill spawn.\n // self-test-runner defaults to 'task' when --task-dir is absent, so mirror that.\n const taskDir = String(args.taskDir ?? \"task\")\n\n const argv = [\n \"run\",\n \"--testcases\", testcases,\n \"--hap\", hap,\n \"--bundle-name\", bundleName,\n \"--task-dir\", taskDir,\n \"--model-stdin\",\n ]\n if (args.outputDir) argv.push(\"--output-dir\", String(args.outputDir))\n if (args.category) argv.push(\"--category\", String(args.category))\n if (args.deviceSn) argv.push(\"--device-sn\", String(args.deviceSn))\n if (args.ip) argv.push(\"--ip\", String(args.ip))\n if (args.port) argv.push(\"--port\", String(args.port))\n if (args.agentMode) argv.push(\"--agent-mode\", String(args.agentMode))\n if (args.maxSteps !== undefined && args.maxSteps !== null) {\n argv.push(\"--max-steps\", String(args.maxSteps))\n }\n if (args.promptVersion) argv.push(\"--prompt-version\", String(args.promptVersion))\n if (args.timeout !== undefined && args.timeout !== null) {\n argv.push(\"--timeout\", String(args.timeout))\n }\n\n // Resolve the model via the host; null = host can't supply one \u2014 fail\n // fast rather than spawning a batch that dies mid-flight for lack of creds.\n const model = await deps.resolveModelParams(context.worktree)\n if (!model) {\n throw new Error(\n `${TOOL_ID}: \\`action:\"run\"\\` needs a model but deps.resolveModelParams returned null ` +\n `for worktree ${context.worktree ?? \"(none)\"} \u2014 configure the host's model provider`,\n )\n }\n const stdin = JSON.stringify({\n apiKey: model.apiKey,\n modelName: model.modelName,\n baseURL: model.baseURL,\n })\n\n // Abort cleanup: the detached batch survives SIGTERM of the\n // self-test-runner child, so on abort also fire `kill --task-dir`.\n // Fire-and-forget; best-effort.\n const onAbortKill = (): void => {\n try {\n const env: NodeJS.ProcessEnv = { ...process.env }\n // strip secrets defensively (kill needs no model)\n delete env.HOMETRANS_MODEL_API_KEY\n delete env.HOMETRANS_MODEL_NAME\n delete env.HOMETRANS_MODEL_BASE_URL\n delete env.GLM_API_KEY\n delete env.TEST_API_KEY\n const k = spawn(\n \"node\",\n [path.join(AUTOTEST_ROOT, SCRIPT_REL), \"kill\", \"--task-dir\", taskDir],\n { cwd: context.directory, env, stdio: \"ignore\", detached: true, windowsHide: true },\n )\n k.on(\"error\", () => { /* best effort \u2014 swallow */ })\n k.unref()\n } catch {\n // best effort\n }\n }\n if (!context.abort.aborted) {\n context.abort.addEventListener(\"abort\", onAbortKill)\n }\n\n const r = await runAutotestScript({\n scriptRel: SCRIPT_REL,\n argv,\n cwd: context.directory,\n abort: context.abort,\n stdin,\n })\n\n // Remove our abort listener; the shared harness removes its own on close.\n context.abort.removeEventListener(\"abort\", onAbortKill)\n\n if (r.spawnError) {\n throw new Error(`${TOOL_ID}: failed to spawn node \u2014 ${r.spawnError}`)\n }\n // Exit codes are states, not failures \u2014 surface the JSON + code.\n return { ok: r.exitCode === 0, exitCode: r.exitCode, output: r.stdout }\n }\n\n // \u2500\u2500 status \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (action === \"status\") {\n const taskDir = String(args.taskDir ?? \"\")\n if (!taskDir) {\n throw new Error(`${TOOL_ID}: \\`action:\"status\"\\` requires \\`taskDir\\``)\n }\n const argv = [\"status\", \"--task-dir\", taskDir]\n if (args.outputDir) argv.push(\"--output-dir\", String(args.outputDir))\n const r = await runAutotestScript({\n scriptRel: SCRIPT_REL,\n argv,\n cwd: context.directory,\n abort: context.abort,\n })\n if (r.spawnError) {\n throw new Error(`${TOOL_ID}: failed to spawn node \u2014 ${r.spawnError}`)\n }\n return { ok: r.exitCode === 0, exitCode: r.exitCode, output: r.stdout }\n }\n\n // \u2500\u2500 kill \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (action === \"kill\") {\n const taskDir = String(args.taskDir ?? \"\")\n if (!taskDir) {\n throw new Error(`${TOOL_ID}: \\`action:\"kill\"\\` requires \\`taskDir\\``)\n }\n const argv = [\"kill\", \"--task-dir\", taskDir]\n const r = await runAutotestScript({\n scriptRel: SCRIPT_REL,\n argv,\n cwd: context.directory,\n abort: context.abort,\n })\n if (r.spawnError) {\n throw new Error(`${TOOL_ID}: failed to spawn node \u2014 ${r.spawnError}`)\n }\n return { ok: r.exitCode === 0, exitCode: r.exitCode, output: r.stdout }\n }\n\n // \u2500\u2500 check_hap \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (action === \"check_hap\") {\n const hap = String(args.hap ?? \"\")\n if (!hap) {\n throw new Error(`${TOOL_ID}: \\`action:\"check_hap\"\\` requires \\`hap\\``)\n }\n const argv = [\"check-hap\", \"--hap\", hap]\n const r = await runAutotestScript({\n scriptRel: SCRIPT_REL,\n argv,\n cwd: context.directory,\n abort: context.abort,\n })\n if (r.spawnError) {\n throw new Error(`${TOOL_ID}: failed to spawn node \u2014 ${r.spawnError}`)\n }\n return { ok: r.exitCode === 0, exitCode: r.exitCode, output: r.stdout }\n }\n\n // \u2500\u2500 check_inputs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (action === \"check_inputs\") {\n const testcases = String(args.testcases ?? \"\")\n const metadata = String(args.metadata ?? \"\")\n if (!testcases || !metadata) {\n throw new Error(`${TOOL_ID}: \\`action:\"check_inputs\"\\` requires \\`testcases\\` and \\`metadata\\``)\n }\n const argv = [\"check-inputs\", \"--testcases\", testcases, \"--metadata\", metadata]\n const r = await runAutotestScript({\n scriptRel: SCRIPT_REL,\n argv,\n cwd: context.directory,\n abort: context.abort,\n })\n if (r.spawnError) {\n throw new Error(`${TOOL_ID}: failed to spawn node \u2014 ${r.spawnError}`)\n }\n return { ok: r.exitCode === 0, exitCode: r.exitCode, output: r.stdout }\n }\n\n // \u2500\u2500 check_pre \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n if (action === \"check_pre\") {\n const testcases = String(args.testcases ?? \"\")\n if (!testcases) {\n throw new Error(`${TOOL_ID}: \\`action:\"check_pre\"\\` requires \\`testcases\\``)\n }\n const argv = [\"check-pre\", \"--testcases\", testcases]\n const r = await runAutotestScript({\n scriptRel: SCRIPT_REL,\n argv,\n cwd: context.directory,\n abort: context.abort,\n })\n if (r.spawnError) {\n throw new Error(`${TOOL_ID}: failed to spawn node \u2014 ${r.spawnError}`)\n }\n return { ok: r.exitCode === 0, exitCode: r.exitCode, output: r.stdout }\n }\n\n throw new Error(\n `${TOOL_ID}: unknown \\`action\\` \"${action}\" (expected run|status|kill|check_hap|check_inputs|check_pre)`,\n )\n },\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": ["path", "path", "path", "path", "path", "path"
|
|
3
|
+
"sources": ["../src/index.ts", "../src/paths.ts", "../src/discovery.ts", "../src/env.ts", "../src/tools/a2h-run-model-script.ts"],
|
|
4
|
+
"sourcesContent": ["import path from \"node:path\"\r\nimport type { A2HHostDeps, Plugin, PluginInput, PluginHooks } from \"./types\"\r\nimport { PKG_ROOT } from \"./paths\"\r\nimport { discoverA2HAgents } from \"./discovery\"\r\nimport { buildA2HEnvBase } from \"./env\"\r\nimport { makeA2hRunModelScriptTool } from \"./tools/a2h-run-model-script\"\r\n\r\n// Public re-exports \u2014 the package's external surface (dev eco code loads\r\n// dist/index.js at runtime and calls `createServer`; `A2HHostDeps` /\r\n// `PLUGIN_ID` are kept exported for any TS consumers).\r\nexport type { A2HHostDeps } from \"./types\"\r\nexport { PLUGIN_ID } from \"./paths\"\r\n\r\n/**\r\n * Create the A2H DevEco Code plugin.\r\n *\r\n * This is a self-contained plugin - skills/, agents/, and tools/\r\n * are bundled inside the package, NOT referenced from HomeTrans.\r\n * A2H-Plugin is the independently publishable \"plugin edition\" of HomeTrans.\r\n *\r\n * @param deps - host dependencies injected by DevEco Code's thin bridge.\r\n * The A2H Plugin defines what it needs (A2HHostDeps);\r\n * DevEco Code provides how to resolve it.\r\n * @returns A Plugin function ready to be registered as a built-in plugin.\r\n */\r\nexport function createServer(deps: A2HHostDeps): Plugin {\r\n return async (input: PluginInput): Promise<PluginHooks> => {\r\n // All A2H assets live inside this package (self-contained, no HomeTrans dep)\r\n const skillsRoot = path.join(PKG_ROOT, \"skills\")\r\n const agentsRoot = path.join(PKG_ROOT, \"agents\")\r\n\r\n // Auto-discover agents: scan top-level agents/*.md, parse `name:` from\r\n // frontmatter, strip frontmatter for prompt body. Adding/removing/renaming\r\n // an agent is just a file drop \u2014 no code change, no rebuild.\r\n const agentPrompts = discoverA2HAgents(agentsRoot)\r\n\r\n return {\r\n dispose: async () => {\r\n agentPrompts.clear()\r\n },\r\n\r\n // \u2500\u2500 config hook: register skills search paths and agents \u2500\u2500\r\n config: async (cfg: Record<string, unknown>) => {\r\n // --- Skills ---\r\n const skills = (cfg.skills as Record<string, unknown>) || {}\r\n cfg.skills = skills\r\n\r\n // Register the bundled skills/ directory as an additional search path.\r\n // All bundled skills are user-visible \u2014 there is no partial-visibility\r\n // (hidden) layer anymore, so we only register the search path here.\r\n const paths = (skills.paths as string[]) || []\r\n skills.paths = paths\r\n if (!paths.includes(skillsRoot)) {\r\n paths.push(skillsRoot)\r\n }\r\n\r\n // --- Agents ---\r\n const agent = (cfg.agent as Record<string, Record<string, unknown>>) || {}\r\n cfg.agent = agent\r\n\r\n for (const [name, prompt] of agentPrompts) {\r\n // Don't overwrite if the user already configured this agent\r\n if (!agent[name]) {\r\n agent[name] = {\r\n mode: \"subagent\",\r\n hidden: true,\r\n prompt,\r\n }\r\n }\r\n }\r\n\r\n },\r\n\r\n // \u2500\u2500 shell.env hook: inject DevEco Studio / SDK path vars only. The \u2500\u2500\r\n // multimodal model apiKey is deliberately NOT put in env (it would leak\r\n // to every adb/hdc descendant); the a2h_run_model_script tool pipes it to\r\n // the script over stdin instead. See src/env.ts.\r\n \"shell.env\": async (\r\n shellInput: { cwd: string; sessionID?: string; callID?: string },\r\n output: { env: Record<string, string> },\r\n ) => {\r\n const a2hEnv = await buildA2HEnvBase(deps)\r\n Object.assign(output.env, a2hEnv)\r\n },\r\n\r\n // \u2500\u2500 tool hook: run skill scripts that need the multimodal model without\r\n // leaking the apiKey into env/argv. The generic `a2h_run_model_script`\r\n // tool is driven by a registry of scripts (src/tools/a2h-run-model-\r\n // script.ts): the agent picks a registered `script` and passes its CLI\r\n // `commandArgs`; the tool resolves the apiKey from the host and pipes it to the\r\n // script over stdin. Adding a model script = one registry entry (no new\r\n // tool file, no index.ts change).\r\n //\r\n // The AutoTest engine (selftest / testcases / report / resolve-metadata)\r\n // is no longer vendored here \u2014 it lives in the HomeTrans package and is\r\n // invoked directly via `node` by agents/self-tester.md (see that file's\r\n // \"Resolving the AutoTest Tools Directory\" section). a2h therefore ships\r\n // only this one plugin tool and carries no autotest runtime dependency.\r\n tool: {\r\n a2h_run_model_script: makeA2hRunModelScriptTool(deps),\r\n },\r\n }\r\n }\r\n}\r\n", "import path from \"node:path\"\r\nimport { fileURLToPath } from \"node:url\"\r\n\r\n// Resolve package root (one directory above dist/ or src/). Computed once here\r\n// and imported everywhere else so there's a single source of truth. After\r\n// esbuild bundling, import.meta.url points at dist/index.js, so this still\r\n// resolves to the package root at runtime.\r\nconst __filename = fileURLToPath(import.meta.url)\r\nconst __dirname = path.dirname(__filename)\r\n\r\n/** Absolute path to the A2H-Plugin package root. */\r\nexport const PKG_ROOT = path.resolve(__dirname, \"..\")\r\n\r\n/** Public plugin id. */\r\nexport const PLUGIN_ID = \"android2harmony\"\r\n", "import path from \"node:path\"\r\nimport fs from \"node:fs\"\r\n\r\n/**\r\n * Strip YAML frontmatter (--- ... ---) from agent .md files.\r\n * Agent .md files have metadata in frontmatter; only the body\r\n * should be used as the LLM prompt.\r\n */\r\nexport function stripFrontmatter(content: string): string {\r\n const match = content.match(/^---\\s*\\n([\\s\\S]*?)\\n---\\s*\\n/)\r\n return match ? content.slice(match[0].length).trim() : content\r\n}\r\n\r\n/**\r\n * Minimal YAML frontmatter extractor for A2H-owned `.md` files (SKILL.md\r\n * and agent `.md`). A2H controls the frontmatter format, so we only need\r\n * the top-level `name` (a scalar). This avoids pulling a YAML dependency\r\n * into the plugin.\r\n *\r\n * Returns the parsed `name`, or null when the file has no usable frontmatter\r\n * (e.g. a README dropped into a directory that's also scanned for agents).\r\n */\r\nexport function parseFrontmatter(content: string): string | null {\r\n const match = content.match(/^---\\s*\\r?\\n([\\s\\S]*?)\\r?\\n---/)\r\n if (!match) return null\r\n const lines = match[1].split(/\\r?\\n/)\r\n\r\n for (const line of lines) {\r\n if (!line.trim() || line.trim().startsWith(\"#\")) continue\r\n if (line.length - line.trimStart().length !== 0) continue // skip indented (e.g. metadata block) lines\r\n\r\n const kv = line.trim().match(/^([a-zA-Z_][a-zA-Z0-9_-]*):\\s*(.*)$/)\r\n if (!kv) continue\r\n if (kv[1] === \"name\") {\r\n return kv[2].trim().replace(/^[\"']|[\"']$/g, \"\")\r\n }\r\n }\r\n\r\n return null\r\n}\r\n\r\n/**\r\n * Scan the bundled agents/ directory and return a `name \u2192 prompt body` map.\r\n *\r\n * Only top-level `.md` files are considered (subdirectories like `scripts/`\r\n * are skipped via `isFile()`). Files without a `name:` field in frontmatter\r\n * (e.g. a stray README) are silently skipped \u2014 the frontmatter name is the\r\n * source of truth, not the file basename. The body (frontmatter stripped)\r\n * becomes the LLM prompt.\r\n *\r\n * Adding a new agent is therefore a zero-code, zero-rebuild change: just\r\n * drop an `.md` with `name:` frontmatter into `agents/`.\r\n */\r\nexport function discoverA2HAgents(agentsRoot: string): Map<string, string> {\r\n const result = new Map<string, string>()\r\n let entries: fs.Dirent[]\r\n try {\r\n entries = fs.readdirSync(agentsRoot, { withFileTypes: true })\r\n } catch {\r\n return result\r\n }\r\n for (const entry of entries) {\r\n if (!entry.isFile() || !entry.name.endsWith(\".md\")) continue\r\n const file = path.join(agentsRoot, entry.name)\r\n let raw: string\r\n try {\r\n raw = fs.readFileSync(file, \"utf-8\")\r\n } catch {\r\n continue\r\n }\r\n const name = parseFrontmatter(raw)\r\n if (!name) continue // not a valid agent file (no `name:` frontmatter)\r\n result.set(name, stripFrontmatter(raw))\r\n }\r\n return result\r\n}\r\n", "import path from \"node:path\"\r\nimport type { A2HHostDeps } from \"./types\"\r\n\r\n/**\r\n * Build the A2H env var set from host-injected deps. Shared by the `shell.env`\r\n * hook (so every shell session sees these). Env vars are the single source of\r\n * truth in the plugin context for non-secret paths.\r\n *\r\n * Contains only DevEco/SDK path vars. The multimodal model apiKey is NOT\r\n * injected here anymore \u2014 putting it in `process.env` leaked it to every\r\n * descendant process (adb/hdc, sub-agents), to `/proc/<pid>/environ`, crash\r\n * dumps, and any `env`/`printenv` output. Instead the `a2h_run_model_script`\r\n * plugin tool resolves the params via `A2HHostDeps.resolveModelParams` and pipes\r\n * them to the script over stdin (`--model-stdin`), so the key stays in process\r\n * memory + the stdin pipe and never enters env/argv/disk.\r\n *\r\n * Nothing secret is present in this env set, but it is still good hygiene not\r\n * to dump it into logs verbatim.\r\n */\r\nexport async function buildA2HEnvBase(\r\n deps: A2HHostDeps,\r\n): Promise<Record<string, string>> {\r\n const env: Record<string, string> = {}\r\n\r\n const home = await deps.resolveDevEcoHome()\r\n if (home) {\r\n const sdk = deps.resolveSdkPath(home)\r\n env[\"DEVECO_HOME\"] = home\r\n env[\"DEVECO_SDK_HOME\"] = sdk\r\n env[\"OHOS_SDK_PATH\"] = path.join(sdk, \"default\", \"openharmony\", \"ets\")\r\n env[\"HMS_SDK_PATH\"] = path.join(sdk, \"default\", \"hms\", \"ets\")\r\n }\r\n\r\n return env\r\n}\r\n", "import { spawn } from \"node:child_process\"\r\nimport path from \"node:path\"\r\nimport { PKG_ROOT } from \"../paths\"\r\nimport type { A2HHostDeps, ToolContext, ToolDefinition } from \"../types\"\r\n\r\n/**\r\n * Generic \"run a skill script that needs the multimodal model\" tool.\r\n *\r\n * One tool, driven by a registry of scripts. The agent picks a `script` and\r\n * passes its params as an object (camelCase fields); the tool flattens them to\r\n * `--kebab-case` CLI argv and spawns the script. The model apiKey is resolved\r\n * from the host and piped to the script's stdin \u2014 the key traverses only the OS\r\n * pipe + process memory, never env/argv/disk, so it is invisible to the spawned\r\n * adb/hdc descendants. Adding a model script = one registry entry (no new tool\r\n * file, no index.ts change); the tool description auto-extends.\r\n */\r\n\r\ninterface ModelScriptEntry {\r\n /** `script` enum value the agent passes. */\r\n name: string\r\n /** Absolute path to the .js script (source; runs under node_modules without native type-stripping). */\r\n path: string\r\n /** Per-script params summary; documents the camelCase fields the agent passes. */\r\n argsHelp: string\r\n}\r\n\r\n/**\r\n * Registry of model-consuming skill scripts. This is the security allowlist\r\n * (the agent cannot pass an arbitrary path \u2014 only a registered `name`) and the\r\n * sole place to edit when adding a script. The tool description is built from\r\n * this so it auto-extends without touching tool code.\r\n */\r\nconst MODEL_SCRIPTS: ModelScriptEntry[] = [\r\n {\r\n name: \"app_feature_verify\",\r\n path: path.join(\r\n PKG_ROOT,\r\n \"skills\",\r\n \"hmos-incremental-ui-align\",\r\n \"scripts\",\r\n \"app_feature_verify.js\",\r\n ),\r\n argsHelp:\r\n \"UI \u5BFB\u8DEF phone-agent:\u5728 HarmonyOS(hdc)\u6216 Android(adb)\u5DF2\u8FDE\u63A5\u8BBE\u5907\u4E0A,\u6309\u8DEF\u5F84/\u63D0\u793A\u5BFC\u822A\u5230\u76EE\u6807\u9875\u9762\u5E76\u622A\u56FE+\u6A21\u578B\u5224\u5B9A\u662F\u5426\u5230\u8FBE\u3002\\n\\n\" +\r\n \"| \u5B57\u6BB5 | \u7C7B\u578B | \u7EA6\u675F | \u8BF4\u660E |\\n\" +\r\n \"|---|---|---|---|\\n\" +\r\n \"| app | string | \u5FC5\u586B | \u76EE\u6807\u5E94\u7528\u663E\u793A\u540D |\\n\" +\r\n \"| package | string | \u5FC5\u586B | \u76EE\u6807\u5E94\u7528\u5305\u540D |\\n\" +\r\n \"| device | string | \u9ED8\u8BA4 hdc | \u8BBE\u5907\u9A71\u52A8,\u53D6\u503C hdc \u6216 adb |\\n\" +\r\n \"| prompt | string | \u4E09\u9009\u4E00 | \u81EA\u7531\u5BFC\u822A\u63CF\u8FF0 |\\n\" +\r\n \"| task | string | \u4E09\u9009\u4E00 | L1\u2026>L2\u2026>L3\u2026 \u5C42\u7EA7\u8DEF\u5F84 |\\n\" +\r\n \"| feature | string | \u4E09\u9009\u4E00 | features.md \u8DEF\u5F84 |\\n\" +\r\n \"| maxSteps | number | \u9ED8\u8BA4 30 | \u6700\u5927 agent \u6B65\u6570 |\\n\" +\r\n \"| serial | string | \u53EF\u9009 | \u8BBE\u5907\u5E8F\u5217\u53F7(\u591A\u8BBE\u5907\u65F6) |\\n\" +\r\n \"| appHints | string | \u53EF\u9009 | \u5E94\u7528\u5BFC\u822A\u63D0\u793A |\\n\" +\r\n \"| limit | number | \u53EF\u9009 | --feature \u6A21\u5F0F\u53D6\u524D N \u6761 |\\n\" +\r\n \"| offset | number | \u9ED8\u8BA4 1 | --feature \u6A21\u5F0F\u504F\u79FB |\\n\" +\r\n \"| quiet | boolean | \u53EF\u9009 | true \u65F6\u6291\u5236\u63D0\u793A\u6027\u8F93\u51FA |\\n\\n\" +\r\n \"\u7EA6\u675F:app \u4E0E package \u5FC5\u586B,\u4E14 prompt/task/feature \u4E09\u9009\u4E00\u3002\\n\" +\r\n '\u793A\u4F8B:commandArgs = {\"app\":\"\u56FE\u5E93\",\"package\":\"com.x.gallery\",\"device\":\"adb\",\"prompt\":\"\u8FDB\u5165\u8BBE\u7F6E\u9875\u9762\",\"maxSteps\":15}',\r\n },\r\n]\r\n\r\n/** Cap stdout returned to the host so a runaway loop can't overflow the chat. */\r\nfunction cap(s: string, max = 50000): string {\r\n if (s.length <= max) return s\r\n const half = Math.floor(max / 2)\r\n return s.slice(0, half) + `\\n\u2026[truncated ${s.length - max} chars]\u2026\\n` + s.slice(-half)\r\n}\r\n\r\n/**\r\n * Shared runner: resolve host model params, spawn the script with the model\r\n * config piped to stdin, collect stdout/stderr, honor abort, and return the\r\n * capped stdout (or throw on non-zero exit).\r\n *\r\n * The apiKey is resolved from the host and piped to the script over stdin\r\n * (`--model-stdin`); the agent never handles it.\r\n */\r\nasync function runModelScript(\r\n deps: A2HHostDeps,\r\n context: ToolContext,\r\n entry: ModelScriptEntry,\r\n argv: string[],\r\n): Promise<{ ok: true; exitCode: number; output: string }> {\r\n const model = await deps.resolveModelParams(context.worktree)\r\n if (!model || !model.apiKey) {\r\n throw new Error(\r\n `a2h_run_model_script (${entry.name}): host did not provide model params (apiKey missing)`,\r\n )\r\n }\r\n\r\n const finalArgv = [...argv, \"--model-stdin\"]\r\n\r\n // Spawn via PATH `node`. process.execPath might be an older/different host\r\n // node (e.g. a bundled runtime), so prefer PATH resolution to match prior\r\n // working behavior. The script is precompiled .js, so no native type-stripping\r\n // is involved and it runs fine even though the path sits under node_modules.\r\n const child = spawn(\"node\", [entry.path, ...finalArgv], {\r\n cwd: context.directory,\r\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\r\n })\r\n\r\n // Pipe the model config to the child's stdin and close it \u2014 the key traverses\r\n // only the OS pipe, never env/argv/disk.\r\n child.stdin.end(\r\n JSON.stringify({ apiKey: model.apiKey, modelName: model.modelName, baseURL: model.baseURL }),\r\n )\r\n\r\n let stdout = \"\"\r\n let stderr = \"\"\r\n let spawnError = \"\"\r\n child.stdout.on(\"data\", (chunk: Buffer) => {\r\n const text = chunk.toString(\"utf8\")\r\n stdout += text\r\n // Surface the last non-empty line as a running title so the host can show\r\n // progress. Generic (not script-specific) \u2014 the agent sees no secrets.\r\n const lines = text.split(/\\r?\\n/)\r\n for (let i = lines.length - 1; i >= 0; i--) {\r\n const line = lines[i].trim()\r\n if (line) {\r\n try {\r\n context.metadata({ title: line.slice(0, 80) })\r\n } catch {\r\n /* host may not implement metadata \u2014 non-essential */\r\n }\r\n break\r\n }\r\n }\r\n })\r\n child.stderr.on(\"data\", (chunk: Buffer) => {\r\n stderr += chunk.toString(\"utf8\")\r\n })\r\n\r\n // Honor abort: kill the child if the host cancels the tool call.\r\n const onAbort = () => {\r\n if (!child.killed) child.kill(\"SIGTERM\")\r\n }\r\n context.abort.addEventListener(\"abort\", onAbort)\r\n\r\n const code: number = await new Promise((resolve) => {\r\n child.on(\"close\", resolve)\r\n child.on(\"error\", (err: Error) => {\r\n spawnError = err.message\r\n resolve(-1)\r\n })\r\n })\r\n context.abort.removeEventListener(\"abort\", onAbort)\r\n\r\n if (code !== 0) {\r\n if (spawnError) {\r\n throw new Error(`a2h_run_model_script (${entry.name}): failed to spawn node \u2014 ${spawnError}`)\r\n }\r\n const tail = stderr.slice(-2000)\r\n throw new Error(\r\n `a2h_run_model_script (${entry.name}) failed (exit ${code}): ${tail || \"(no stderr)\"}`,\r\n )\r\n }\r\n return { ok: true, exitCode: code, output: cap(stdout) }\r\n}\r\n\r\n/** camelCase \u2192 --kebab-case flag (maxSteps \u2192 --max-steps). */\r\nconst kebab = (s: string): string => \"--\" + s.replace(/([a-z0-9])([A-Z])/g, \"$1-$2\").toLowerCase()\r\n\r\n/**\r\n * Flatten a params object into CLI argv: each entry \u2192 `--kebab-case` flag + its\r\n * value; booleans \u2192 flag-only when true (false/null/undefined skipped). Generic\r\n * over any script whose flags are kebab-cased, so it is not coupled to a schema.\r\n */\r\nfunction flattenParams(obj: Record<string, unknown>): string[] {\r\n const out: string[] = []\r\n for (const [k, v] of Object.entries(obj)) {\r\n if (v == null) continue\r\n if (typeof v === \"boolean\") {\r\n if (v) out.push(kebab(k))\r\n } else {\r\n out.push(kebab(k), String(v))\r\n }\r\n }\r\n return out\r\n}\r\n\r\nconst DESCRIPTION_PREFIX =\r\n \"\u8FD0\u884C\u9700\u8981\u591A\u6A21\u6001\u6A21\u578B\u7684 skill \u811A\u672C:\u5728 HarmonyOS \u6216 Android \u8BBE\u5907\u4E0A\u6267\u884C\u7531 `script` \u9009\u5B9A\u7684\u811A\u672C,\u628A\u53C2\u6570\u4F5C\u4E3A\u5BF9\u8C61(camelCase \u5B57\u6BB5)\u4F20\u5165,\u5DE5\u5177\u81EA\u52A8\u8F6C\u4E3A --kebab-case \u547D\u4EE4\u884C\u53C2\u6570\u900F\u4F20\u7ED9 `node` \u8FDB\u7A0B,\u8FD0\u884C\u5B8C\u6BD5\u8FD4\u56DE\u811A\u672C stdout\u3002\u4F60\u53EA\u9700\u63D0\u4F9B `script` \u4E0E `commandArgs`,\u6A21\u578B\u76F8\u5173\u914D\u7F6E(apiKey \u7B49)\u7531\u5DE5\u5177\u5185\u90E8\u7ECF stdin \u6CE8\u5165,\u4E0D\u8981\u4F20 `apiKey`/`modelStdin` \u5B57\u6BB5\u3002\\n\\n\" +\r\n \"\u53EF\u7528\u811A\u672C\u53CA\u5176\u53C2\u6570:\\n\"\r\n\r\n/**\r\n * Build the `a2h_run_model_script` plugin tool.\r\n *\r\n * Generic over scripts: the agent selects a registered `script` and passes its\r\n * params as an object; the tool flattens them to CLI argv. The model apiKey is\r\n * resolved from the host and piped to the script over stdin \u2014 never env/argv/\r\n * disk, so invisible to adb/hdc descendants. Use this instead of running the\r\n * script via `node` directly (a direct run can only get the key from\r\n * env/argv/config, which leaks).\r\n */\r\nexport function makeA2hRunModelScriptTool(deps: A2HHostDeps): ToolDefinition {\r\n return {\r\n description:\r\n DESCRIPTION_PREFIX +\r\n MODEL_SCRIPTS.map((s) => `${s.name}: ${s.argsHelp}`).join(\"\\n\"),\r\n // `args` is a flat field-name\u2192field-schema MAP (not a full `{type:\"object\",\r\n // properties, required}` schema object). The host's `legacyJsonSchema` reads\r\n // this map and builds the LLM-facing schema itself: `{type:\"object\",\r\n // properties:{script, commandArgs}, required:[script, commandArgs]}` (it\r\n // marks every field required). Declaring the full-schema wrapper here would\r\n // make `legacyJsonSchema` mis-read `properties` as a literal field name \u2192 the\r\n // model receives a schema with a single `properties` field and wraps its\r\n // input under it \u2192 \"unknown script\". Keep it a field-map.\r\n args: {\r\n script: {\r\n type: \"string\",\r\n enum: MODEL_SCRIPTS.map((s) => s.name),\r\n description: \"\u8981\u8FD0\u884C\u7684\u6A21\u578B\u811A\u672C\u540D,\u89C1\u4E0A\u65B9\u5404\u6761\u76EE\",\r\n },\r\n commandArgs: {\r\n type: \"object\",\r\n description:\r\n '\u8BE5\u811A\u672C\u7684\u53C2\u6570\u5BF9\u8C61(camelCase \u5B57\u6BB5,\u5DE5\u5177\u81EA\u52A8\u8F6C\u4E3A --kebab-case \u547D\u4EE4\u884C\u53C2\u6570),\u6309\u4E0A\u65B9\u5BF9\u5E94\u6761\u76EE\u8BF4\u660E\u586B\u5199,\u5F62\u5982 {\"device\":\"adb\",\"app\":\"\u56FE\u5E93\",\"package\":\"com.x\",\"prompt\":\"\u8FDB\u5165\u8BBE\u7F6E\",\"maxSteps\":15}',\r\n },\r\n },\r\n execute: async (args: Record<string, unknown>, context: ToolContext) => {\r\n const name = String(args.script ?? \"\")\r\n const entry = MODEL_SCRIPTS.find((s) => s.name === name)\r\n if (!entry) {\r\n throw new Error(\r\n `a2h_run_model_script: unknown script \"${name}\". Registered: ${MODEL_SCRIPTS.map((s) => s.name).join(\", \")}`,\r\n )\r\n }\r\n // `commandArgs` may arrive as an object, a JSON string of that object, or as\r\n // top-level fields (model-dependent) \u2014 collect them all, then flatten.\r\n const params: Record<string, unknown> = {}\r\n const a = args.commandArgs\r\n if (a && typeof a === \"object\") {\r\n Object.assign(params, a as Record<string, unknown>)\r\n } else if (typeof a === \"string\" && a.trim()) {\r\n try {\r\n const parsed: unknown = JSON.parse(a)\r\n if (parsed && typeof parsed === \"object\") {\r\n Object.assign(params, parsed as Record<string, unknown>)\r\n }\r\n } catch {\r\n /* not JSON \u2014 fall through to top-level fields */\r\n }\r\n }\r\n for (const [k, v] of Object.entries(args)) {\r\n if (k !== \"script\" && k !== \"commandArgs\") params[k] = v\r\n }\r\n return runModelScript(deps, context, entry, flattenParams(params))\r\n },\r\n }\r\n}\r\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["path", "path", "path", "path", "path", "path"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,37 +1,36 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "android2harmony",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "
|
|
5
|
-
"type": "module",
|
|
6
|
-
"license": "MIT",
|
|
7
|
-
"publishConfig": {
|
|
8
|
-
"registry": "https://registry.npmjs.org/"
|
|
9
|
-
},
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
"
|
|
13
|
-
},
|
|
14
|
-
"
|
|
15
|
-
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"
|
|
26
|
-
},
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "android2harmony",
|
|
3
|
+
"version": "0.1.5",
|
|
4
|
+
"description": "HomeTrans Plugin for DevEco Code — standalone plugin containing A2H skills, agents, and tools for converting Android apps to HarmonyOS",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"registry": "https://registry.npmjs.org/"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://gitcode.com/SMAT/HomeTrans/tree/deveco-code"
|
|
13
|
+
},
|
|
14
|
+
"main": "./dist/index.js",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": "./dist/index.js"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"skills",
|
|
21
|
+
"agents"
|
|
22
|
+
],
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "node scripts/build.js",
|
|
25
|
+
"dev": "tsc --watch"
|
|
26
|
+
},
|
|
27
|
+
"engines": {
|
|
28
|
+
"node": ">=22.18.0"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^22.0.0",
|
|
33
|
+
"esbuild": "^0.25.0",
|
|
34
|
+
"typescript": "^5.4.5"
|
|
35
|
+
}
|
|
36
|
+
}
|