diff --git a/CLI/Tests/TritonKitCLITests/DeviceCrossPlatformTests.swift b/CLI/Tests/TritonKitCLITests/DeviceCrossPlatformTests.swift index 73dc187..4f6829e 100644 --- a/CLI/Tests/TritonKitCLITests/DeviceCrossPlatformTests.swift +++ b/CLI/Tests/TritonKitCLITests/DeviceCrossPlatformTests.swift @@ -91,6 +91,8 @@ struct DeviceCrossPlatformTests { #expect(appOptionNames.contains("--runtime")) #expect(app.examples.contains("triton app list --device iphone15 --user-only --json")) #expect(app.examples.contains("triton app install --device harmony-a --hap /tmp/Demo.hap --json")) + #expect(app.examples.contains(#"triton app go "example://debug""#)) + #expect(app.examples.contains(#"triton app go "example://debug" --device iphone15"#)) #expect(app.examples.contains("triton app prefs get DEBUG-mock --device iphone15 --bundle-id com.example.app --json")) #expect(smokeOptionNames.contains("--device")) diff --git a/CLI/Tests/TritonKitCLITests/SchemaFactSourceTests.swift b/CLI/Tests/TritonKitCLITests/SchemaFactSourceTests.swift index 0822305..3942462 100644 --- a/CLI/Tests/TritonKitCLITests/SchemaFactSourceTests.swift +++ b/CLI/Tests/TritonKitCLITests/SchemaFactSourceTests.swift @@ -709,7 +709,9 @@ struct SchemaFactSourceTests { #expect(openURL.primaryNextActionSource == "next-step-step") #expect(openURL.steps.map(\.id) == ["target-resolve", "app-open-url", "wait-text", "assert-text", "evidence"]) #expect(openURL.steps.first(where: { $0.id == "app-open-url" })?.workflowCategories == ["app", "assert", "evidence", "target"]) - #expect(openURL.steps.first(where: { $0.id == "app-open-url" })?.command.contains("--wait-ready") == true) + #expect(openURL.steps.first(where: { $0.id == "app-open-url" })?.command.contains("triton app go") == true) + #expect(openURL.steps.first(where: { $0.id == "app-open-url" })?.command.contains("--wait-ready") == false) + #expect(openURL.steps.first(where: { $0.id == "app-open-url" })?.command.contains("--json") == false) let webview = buildWorkflowPlan( capabilities: capabilities, @@ -1631,6 +1633,7 @@ struct SchemaFactSourceTests { @Test("capability groups keep machine-readable next-action output flags") func capabilityGroupsKeepMachineReadableNextActionOutputFlags() { let fixtures = capabilityStateFixtures() + let schemas = commandSchemaMap() var missingMachineReadableFlags: [String] = [] var screenshotObserveMismatches: [String] = [] @@ -1651,7 +1654,10 @@ struct SchemaFactSourceTests { let hasJSONFlag = argSet.contains("--json") || argSet.contains("--jsonl") let hasPlanFormatJSON = args.contains("--format") && args.contains("json") let hasScreenshotMetadata = argSet.contains("--metadata") - if !(hasJSONFlag || hasPlanFormatJSON || hasScreenshotMetadata) { + let defaultsToJSON = schemas[nextAction.command]?.options.contains { + $0.name == "--format" && $0.defaultValue == "json" + } == true + if !(hasJSONFlag || hasPlanFormatJSON || hasScreenshotMetadata || defaultsToJSON) { missingMachineReadableFlags.append(context) } @@ -1886,6 +1892,75 @@ struct SchemaFactSourceTests { #expect(assertTextExistsPlaceholderMismatches == []) } + @Test("capability next-action url placeholders stay canonical") + func capabilityNextActionURLPlaceholdersStayCanonical() { + let fixtures = capabilityStateFixtures() + + var urlFlagPlaceholderMismatches: [String] = [] + var openURLFlagPlaceholderMismatches: [String] = [] + var appOpenURLArgumentMismatches: [String] = [] + var routeAssertCurrentURLArgumentMismatches: [String] = [] + + for fixture in fixtures { + for capability in fixture.capabilities { + guard let nextAction = capability.nextAction else { + continue + } + let args = nextAction.args + let context = "\(fixture.name):\(capability.name):command=\(nextAction.command):args=\(args)" + + for (index, arg) in args.enumerated() where arg == "--url" { + guard args.indices.contains(index + 1) else { + urlFlagPlaceholderMismatches.append("\(context):missing-url-value") + continue + } + if args[index + 1] != "" { + urlFlagPlaceholderMismatches.append("\(context):expected=:actual=\(args[index + 1])") + } + } + + for (index, arg) in args.enumerated() where arg == "--open-url" { + guard args.indices.contains(index + 1) else { + openURLFlagPlaceholderMismatches.append("\(context):missing-open-url-value") + continue + } + if args[index + 1] != "" { + openURLFlagPlaceholderMismatches.append("\(context):expected=:actual=\(args[index + 1])") + } + } + + if nextAction.command == "app", + args.first == "open-url" || args.first == "go" { + guard args.indices.contains(1) else { + appOpenURLArgumentMismatches.append("\(context):missing-open-url-argument") + continue + } + if args[1] != "" { + appOpenURLArgumentMismatches.append("\(context):expected=:actual=\(args[1])") + } + } + + if nextAction.command == "route", + args.first == "assert-current-url" { + guard args.indices.contains(1) else { + routeAssertCurrentURLArgumentMismatches.append("\(context):missing-expected-url-argument") + continue + } + if args[1] != "" { + routeAssertCurrentURLArgumentMismatches.append( + "\(context):expected=:actual=\(args[1])" + ) + } + } + } + } + + #expect(urlFlagPlaceholderMismatches == []) + #expect(openURLFlagPlaceholderMismatches == []) + #expect(appOpenURLArgumentMismatches == []) + #expect(routeAssertCurrentURLArgumentMismatches == []) + } + @Test("capability names remain unique for agent indexing") func capabilityNamesRemainUniqueForAgentIndexing() { var duplicateSchemaCapabilities: [String] = [] @@ -3742,7 +3817,7 @@ struct SchemaFactSourceTests { #expect(app.failureCodes.contains("app_launch_failed")) #expect(app.failureCodes.contains("host_open_url_failed")) - #expect(app.nextCommands.contains("triton app open-url --wait-ready --snapshot --json")) + #expect(app.nextCommands.contains("triton app go ")) expectContract(app, selector: "host.app-action", fields: [ "ok", "action", "runtimeScope", "target", "selection", "tool", "exitCode", "riskLevel", "sourceCommand", "stdoutTruncated", "stderrTruncated", "artifacts", "note", diff --git a/README.md b/README.md index 69bcc6e..88322d6 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,35 @@ Before filing a public issue, redact private project and personal information. D | Build, test, run, and diagnose an unknown Apple repo | [CLI Integration Guide](#cli-integration-guide) | Use `triton xcode`, `triton xcresult`, and artifact commands before raw `xcodebuild`. | | Prepare a HarmonyOS / DevEco Emulator | [Harmony App Integration Guide](#harmony-app-integration-guide) | Host-side HDC adapter works without embedded runtime. | | Validate a Harmony embedded runtime | [Harmony App Integration Guide](#harmony-app-integration-guide) | Use package id / import path `tritonkit` and `--runtime-base-url` direct checks while the SDK is standalone. | +| Add optional Codex / agent workflows | [Optional Agent Skills](#optional-agent-skills) | Install only the public skills; internal skills are for TritonKit repository maintenance. | + +## Optional Agent Skills + +TritonKit ships optional Codex / agent skills for AI-assisted adoption, feedback, and local emulator regression work. They are not required to use the iOS runtime, Harmony runtime notes, or macOS `triton` CLI. + +External users and adopting projects should install only the public skills from `.agents/tritonkit-skills/public/` or from the release asset `tritonkit-skills.tar.gz`. Current public skills are: + +- `tritonkit-dev-feedback`: collect adoption feedback, missing capabilities, confusing behavior, and documentation gaps as actionable TritonKit issues. +- `tritonkit-emulator-cli-takeover`: guide local CLI takeover of iOS Simulator, Android Emulator, and HarmonyOS / DevEco Emulator workflows. +- `tritonkit-real-project-regression`: validate TritonKit against real app projects while isolating external repo changes and preserving machine-readable evidence. + +Do not install `.agents/tritonkit-skills/internal/` into adopting projects by default. Internal skills are repo-maintenance, governance, planning, supervision, and implementation workflows for TritonKit maintainers, and release packaging excludes them. + +If you install from a source checkout, copy only the public skill directories into your Codex / agent skills directory: + +```sh +# Replace AGENT_SKILLS_DIR with your Codex / agent's configured skills directory. +mkdir -p "$AGENT_SKILLS_DIR" +cp -R .agents/tritonkit-skills/public/* "$AGENT_SKILLS_DIR"/ +``` + +If you install from a release asset, extract the public skill bundle into that same configured skills directory: + +```sh +tar -xzf tritonkit-skills.tar.gz -C "$AGENT_SKILLS_DIR" +``` + +Restart the Codex / agent session after installation so the new skills are discovered. ## iOS Embedded Runtime Integration Guide @@ -363,8 +392,9 @@ triton app install --device booted --app /tmp/Demo.app --json triton app uninstall --device booted --bundle-id com.example.app --confirm --json triton app launch --device booted --bundle-id com.example.app --json triton app terminate --device booted --bundle-id com.example.app --json +triton app go "example://debug" +triton app go "example://debug" --device booted triton app open-url "example://debug" --device booted --json -triton app open-url "example://debug" --device booted --wait-ready --snapshot --json triton webview current-url --platform ios --json triton route assert-current-url "https://example.invalid/path" --platform ios --json triton app container --device booted --bundle-id com.example.app --kind data --json @@ -375,8 +405,9 @@ triton app prefs dump --device booted --bundle-id com.example.app --json Destructive commands require `--confirm` by default, and `runtime delete` supports `--dry-run` first so agents can inspect the selected runtimes before deleting anything. -`app open-url` only proves the URL was submitted to Simulator. Continue with `triton wait`, `triton find`, `triton assert`, `triton webview current-url`, `triton route assert-current-url`, or `triton app prefs get` to verify the business state. -When an embedded runtime is expected to be connected, add `--wait-ready --snapshot` to make the one-shot result include runtime readiness and an app/route/AX snapshot summary. +`app go ` is the short iOS deep-link smoke entry: it opens the URL, waits for embedded runtime readiness, returns an app/route/AX snapshot summary, and defaults to JSON output. Use `--device ` only when the current/default target is ambiguous. +For iOS simulator selectors, `sim:` is optional. `--device 60667794-96F8-40E6-8664-85538EC4663E` and `--device sim:60667794-96F8-40E6-8664-85538EC4663E` both resolve to the same simulator; keep `sim:` only when you want explicit platform disambiguation. +`app open-url` is the lower-level host action and only proves the URL was submitted to Simulator. Continue with `triton wait`, `triton find`, `triton assert`, `triton webview current-url`, `triton route assert-current-url`, or `triton app prefs get` to verify the business state. Xcode project discovery and `xcodebuild` execution are also exposed through Triton CLI. Use this path before falling back to XcodeBuildMCP or raw `xcodebuild` so the agent sees stable JSON/JSONL contracts: diff --git a/Sources/TritonKitCLI/CLIHostCommands.swift b/Sources/TritonKitCLI/CLIHostCommands.swift index 1d50029..7ec8054 100644 --- a/Sources/TritonKitCLI/CLIHostCommands.swift +++ b/Sources/TritonKitCLI/CLIHostCommands.swift @@ -933,6 +933,59 @@ private func hostDeviceSelectionRequest( ) } +private func resolveDefaultIOSHostDeviceSelection( + device: String?, + simulator: String?, + name: String?, + runtime: String?, + state: String?, + ready: Bool +) throws -> HostDeviceSelectionResult { + let explicitDevice = device ?? simulator + if explicitDevice != nil { + return try resolveHostDeviceSelection( + request: hostDeviceSelectionRequest( + device: explicitDevice, + platform: .ios, + defaultPlatform: .ios, + name: name, + runtime: runtime, + state: state, + ready: ready + ), + hdc: "hdc" + ) + } + + do { + return try resolveHostDeviceSelection( + request: hostDeviceSelectionRequest( + device: "current", + platform: .ios, + defaultPlatform: .ios, + name: name, + runtime: runtime, + state: state, + ready: ready + ), + hdc: "hdc" + ) + } catch HostDeviceSelectionError.targetNotFound(let target) where target == "current" { + return try resolveHostDeviceSelection( + request: hostDeviceSelectionRequest( + device: nil, + platform: .ios, + defaultPlatform: .ios, + name: name, + runtime: runtime, + state: state, + ready: ready + ), + hdc: "hdc" + ) + } +} + func ensureHostDeviceSelectorCompatibility(device: String?, simulator: String?, target: String?) throws { if device != nil && (simulator != nil || target != nil) { throw HostDeviceSelectionError.parameterConflict("--device cannot be combined with --simulator or Harmony --target.") @@ -978,6 +1031,7 @@ struct HostApp: AsyncParsableCommand { HostAppUninstall.self, HostAppLaunch.self, HostAppTerminate.self, + HostAppGo.self, HostAppOpenURL.self, HostAppContainer.self, HostAppPrefs.self, @@ -1400,6 +1454,71 @@ struct HostAppTerminate: AsyncParsableCommand { } } +struct HostAppGo: AsyncParsableCommand { + static let configuration = CommandConfiguration(commandName: "go", abstract: "Open a URL and return runtime readiness plus snapshot") + + @Argument(help: "URL to open") var url: String + @Option(help: "Unified host device selector: alias, sim:, raw id, booted, or current") var device: String? + @Option(help: "Explicit iOS simulator selector: UDID or booted") var simulator: String? + @Option(help: "Device name filter, for example iPhone 15") var name: String? + @Option(help: "Runtime filter, for example iOS 26.5") var runtime: String? + @Option(help: "Target state filter, for example booted") var state: String? + @Flag(help: "Only match ready targets") var ready = false + @Option(name: .customLong("runtime-target"), help: "iOS embedded runtime target id from `triton list`") var runtimeTarget: String = TKLocalTargetID + @Option(name: .customLong("snapshot-include"), help: "Comma-separated snapshot sections") var snapshotInclude: String = "app,scene,route,ax,geometry" + @Option(name: .customLong("max-ax-nodes"), help: "Maximum AX nodes in the runtime snapshot") var maxAXNodes: Int? + @Option(help: "Server host") var host: String = "127.0.0.1" + @Option(help: "Server port") var port: Int = 19421 + @Option(help: "Runtime wait timeout in seconds") var timeout: Double = 20 + @Option(help: "Runtime wait polling interval in seconds") var interval: Double = 0.5 + @Flag(help: "Alias for --format json") var json = false + @Option(help: "Output format: text or json") var format: ClientOutputFormat = .json + + func run() async throws { + let outputFormat = effectiveFormat(format, json: json) + do { + try ensureHostDeviceSelectorCompatibility(device: device, simulator: simulator, target: nil) + let selection = try resolveDefaultIOSHostDeviceSelection( + device: device, + simulator: simulator, + name: name, + runtime: runtime, + state: state, + ready: ready + ) + let include = snapshotInclude.split(separator: ",").map { $0.trimmingCharacters(in: .whitespacesAndNewlines) }.filter { !$0.isEmpty } + let summary = try await runIOSAppOpenURLFlow(options: IOSAppOpenURLFlowOptions( + simulator: selection.target.target, + runtimeTarget: runtimeTarget, + url: url, + waitReady: true, + snapshot: true, + snapshotInclude: include, + maxAXNodes: maxAXNodes, + host: host, + port: port, + timeout: timeout, + interval: interval + )) + switch outputFormat { + case .json: + print(try encodeJSON(summary)) + case .text: + print("status: \(summary.status.rawValue)") + print("source: \(summary.hostAction.sourceCommand)") + if let ready = summary.ready { + print("runtime: connected=\(ready.connected) hierarchy=\(ready.hierarchyCacheState ?? "-")") + } + if let snapshot = summary.snapshot { + print("snapshot: app=\(snapshot.appName ?? "-") axNodes=\(snapshot.axNodeCount ?? 0)") + } + } + } catch { + try failCommand(error, outputFormat: outputFormat, endpoint: "/request", host: host, port: port) + } + } +} + struct HostAppOpenURL: AsyncParsableCommand { static let configuration = CommandConfiguration(commandName: "open-url", abstract: "Open a URL in a simulator or Harmony app") diff --git a/Sources/TritonKitCLI/CLIRuntimeTransport.swift b/Sources/TritonKitCLI/CLIRuntimeTransport.swift index 680d8f5..964aea0 100644 --- a/Sources/TritonKitCLI/CLIRuntimeTransport.swift +++ b/Sources/TritonKitCLI/CLIRuntimeTransport.swift @@ -561,9 +561,9 @@ func runtimeCapabilityNextAction( case "host-app": return TKCLINextAction(command: "app", args: ["list", "--device", "", "--json"]) case "host-app-open-url-ready": - return TKCLINextAction(command: "app", args: ["open-url", "", "--device", "", "--wait-ready", "--json"]) + return TKCLINextAction(command: "app", args: ["go", "", "--device", ""]) case "host-app-open-url-snapshot": - return TKCLINextAction(command: "app", args: ["open-url", "", "--device", "", "--wait-ready", "--snapshot", "--json"]) + return TKCLINextAction(command: "app", args: ["go", "", "--device", ""]) case "host-preferences": return TKCLINextAction(command: "app", args: ["prefs", "get", "", "--device", "", "--bundle-id", "", "--json"]) case "xcode-discovery", "xcode-build", "xcode-test", "xcode-run": @@ -1289,12 +1289,9 @@ func buildTaskWorkflowPlan( id: "app-open-url", title: "Open app URL and capture runtime readiness", command: [ - "triton", "app", "open-url", + "triton", "app", "go", planValue(request.url, ""), "--device", planValue(request.device, ""), - "--wait-ready", - "--snapshot", - "--json", ].map(shellEscaped).joined(separator: " "), requiresServer: true, requiresTarget: true, diff --git a/Sources/TritonKitCLI/CLISchemaHostCommands.swift b/Sources/TritonKitCLI/CLISchemaHostCommands.swift index e52f5f8..a7d1c77 100644 --- a/Sources/TritonKitCLI/CLISchemaHostCommands.swift +++ b/Sources/TritonKitCLI/CLISchemaHostCommands.swift @@ -250,6 +250,7 @@ func hostCommandSchemas() -> [TKCommandSchema] { TKCommandSchemaOption(name: "launch --platform harmony --bundle --ability ", type: "Subcommand", description: "Launch a Harmony app ability"), TKCommandSchemaOption(name: "terminate --bundle-id ", type: "Subcommand", description: "Terminate a running simulator app"), TKCommandSchemaOption(name: "terminate --platform harmony --bundle ", type: "Subcommand", description: "Force-stop a Harmony app"), + TKCommandSchemaOption(name: "go ", type: "Subcommand", description: "Open an iOS URL, wait for embedded runtime readiness, and return a snapshot summary"), TKCommandSchemaOption(name: "open-url ", type: "Subcommand", description: "Submit a URL to the simulator"), TKCommandSchemaOption(name: "open-url --wait-ready --snapshot", type: "Subcommand", description: "Open a URL, wait for embedded runtime readiness, and return an app/route/AX snapshot summary"), TKCommandSchemaOption(name: "open-url --platform harmony --bundle --ability ", type: "Subcommand", description: "Open a Harmony deep link through aa start -U"), @@ -300,6 +301,8 @@ func hostCommandSchemas() -> [TKCommandSchema] { "triton app launch --platform harmony --bundle com.example.app --ability EntryAbility --json", "triton app open-url --device harmony-a --bundle com.example.app --ability EntryAbility example://debug --json", "triton app terminate --device iphone15 --bundle-id com.example.app --json", + #"triton app go "example://debug""#, + #"triton app go "example://debug" --device iphone15"#, #"triton app open-url "example://debug" --device iphone15 --json"#, #"triton app open-url "example://debug" --device iphone15 --wait-ready --snapshot --json"#, "triton app container --device iphone15 --bundle-id com.example.app --kind data --json", @@ -311,7 +314,7 @@ func hostCommandSchemas() -> [TKCommandSchema] { outputSemantics: "Use app for host-side install, launch, terminate, open-url, container, and preferences. For smoke readiness, prefer open-url with --wait-ready --snapshot.", artifacts: ["app-container", "app-preferences", "runtime-snapshot"], nextCommands: [ - "triton app open-url --wait-ready --snapshot --json", + "triton app go ", "triton status --json", "triton assert text-exists --json", "triton evidence --output --json", diff --git a/docs-linhay/dev/ai-cli-readable-control.md b/docs-linhay/dev/ai-cli-readable-control.md index bb239df..bdff144 100644 --- a/docs-linhay/dev/ai-cli-readable-control.md +++ b/docs-linhay/dev/ai-cli-readable-control.md @@ -76,7 +76,9 @@ TritonKit 首期不需要 Web 端。AI agent 的读取与控制入口收敛到 C - `triton app list --device --user-only --format json`:读取已安装 App 列表,输出 bundle id、display name、version、application type、bundle/data/group container 等结构化字段;`--simulator ` 作为 iOS 兼容路径保留。 - `triton app info --device --bundle-id --format json`:读取单个已安装 App 元数据;当 `simctl appinfo` 对缺失 bundle 只回显 `CFBundleIdentifier` 时,归一为 `app_info_not_available`。 - `triton app install --device --app --format json`、`triton app uninstall --device --bundle-id --confirm --format json`、`triton app launch --device --bundle-id --format json`、`triton app terminate --device --bundle-id --format json`:App 生命周期首批入口,返回 host action envelope;`uninstall` 必须显式 `--confirm`,业务就绪仍需继续用 `status/wait/find/assert/prefs` 验证。 -- `triton app open-url --device --format json`:提交 deep link 或 URL 到 simulator;该命令只证明 URL 已提交,业务完成需继续用 `wait/find/assert` 或 preferences 验证。若目标 App 已接入 DEBUG embedded runtime,可追加 `--wait-ready --snapshot --snapshot-include app,scene,route,ax,geometry --max-ax-nodes `,让单次输出同时包含 host action、runtime readiness 和 app/route/AX snapshot 摘要。 +- `triton app go [--device ]`:iOS deep-link smoke 的短入口;默认提交 URL、等待 embedded runtime ready、返回 app/route/AX snapshot summary,并默认 JSON 输出。若当前/default target 唯一,可省略 `--device`。 +- iOS simulator 的 `--device` selector 支持裸 UDID、`sim:`、`booted`、`current` 与 alias;`sim:` 只是平台消歧前缀,不是必填。 +- `triton app open-url --device --format json`:低层 host action,只证明 deep link 或 URL 已提交到 simulator;业务完成需继续用 `wait/find/assert`、preferences、route 或 `app go` 验证。 - `triton app container --device --bundle-id --kind data --format json`:读取 simulator App container path。 - `triton app prefs get --device --bundle-id --format json`、`triton app prefs dump --device --bundle-id --format json`:读取 App preferences plist,避免 agent 解析 `plutil -p` 人读文本。 - `triton app prefs set --device --bundle-id --format json`:向 iOS Simulator App data container 中的 preferences plist 写入一个 property-list compatible JSON 值,支持 string/bool/int/double/array/object,拒绝 `null`,输出 `previousValue/newValue/plistPath/restartAdvice`。同一 plist 的多 key 设置应串行执行,避免并发写入产生最后写入覆盖。 diff --git a/docs-linhay/memory/2026-06-02.md b/docs-linhay/memory/2026-06-02.md new file mode 100644 index 0000000..743ff81 --- /dev/null +++ b/docs-linhay/memory/2026-06-02.md @@ -0,0 +1,10 @@ +# 2026-06-02 + +## Round 180:短 deep link 验证入口 + +- 用户指出 `triton app open-url --device --wait-ready --snapshot --json` 过长,不适合作为 agent 高频入口。 +- 新增 `triton app go `:默认执行 iOS deep link 提交、runtime readiness wait、snapshot summary,并默认 JSON 输出。 +- `app go` 的 target 选择顺序为显式 `--device/--simulator`、当前 target、唯一 ready iOS target;因此常用流程可先 `triton device use sim:`,后续只执行 `triton app go `。 +- `--json` 可省略:schema 默认 `--format=json` 被测试门禁认可为机器可读输出,不再强制默认 JSON 命令在 nextAction/plan 中显式追加 `--json`。 +- 文档已同步:`README.md` 与 `docs-linhay/dev/ai-cli-readable-control.md`。 +- 新增 checkpoint:`docs-linhay/spaces/20260527-command-surface-optimization/plans/checkpoints/20260602-round-180-short-app-go-deeplink-entry.md`。 diff --git a/docs-linhay/memory/2026-06-04.md b/docs-linhay/memory/2026-06-04.md new file mode 100644 index 0000000..352490b --- /dev/null +++ b/docs-linhay/memory/2026-06-04.md @@ -0,0 +1,6 @@ +# 2026-06-04 + +## Issue #27 Optional Agent Skills README + +- 为 `docs-linhay/spaces/20260604-issue-27-agent-skills-readme/` 建立执行计划,验收聚焦根 README 是否明确可选 Codex / agent skills 的 public/internal 边界。 +- 根 README 新增 `Optional Agent Skills` 章节:外部用户只安装 `.agents/tritonkit-skills/public/` 或 release asset `tritonkit-skills.tar.gz` 中的 public skills;当前 public skills 为 `tritonkit-dev-feedback`、`tritonkit-emulator-cli-takeover`、`tritonkit-real-project-regression`;`.agents/tritonkit-skills/internal/` 仅用于 TritonKit repo maintenance,不默认安装到 adopting projects;安装后需重启 Codex / agent session。 diff --git a/docs-linhay/scripts/verify-simulator-gate.sh b/docs-linhay/scripts/verify-simulator-gate.sh index df748a6..7acf586 100755 --- a/docs-linhay/scripts/verify-simulator-gate.sh +++ b/docs-linhay/scripts/verify-simulator-gate.sh @@ -17,6 +17,7 @@ run swift test --package-path "$repo_root/CLI" --filter DeviceCrossPlatformTests run swift test --package-path "$repo_root/CLI" --filter SchemaFactSourceTests/capabilityNextActionTargetSelectorPlaceholdersStayCanonical run swift test --package-path "$repo_root/CLI" --filter SchemaFactSourceTests/capabilityNextActionPlatformFlagsStayCanonicalAndFamilyAligned run swift test --package-path "$repo_root/CLI" --filter SchemaFactSourceTests/capabilityNextActionTextPlaceholdersStayCanonical +run swift test --package-path "$repo_root/CLI" --filter SchemaFactSourceTests/capabilityNextActionURLPlaceholdersStayCanonical smoke_port="${TRITON_IOS_RUNTIME_SMOKE_PORT:-$((28000 + (RANDOM % 1200)))}" echo "[sim-gate] TRITON_IOS_RUNTIME_SMOKE_PORT=$smoke_port" run env TRITON_IOS_RUNTIME_SMOKE_PORT="$smoke_port" "$repo_root/docs-linhay/scripts/verify-ios-runtime-observe-smoke.sh" diff --git a/docs-linhay/spaces/20260527-command-surface-optimization/plans/checkpoints/20260602-round-180-short-app-go-deeplink-entry.md b/docs-linhay/spaces/20260527-command-surface-optimization/plans/checkpoints/20260602-round-180-short-app-go-deeplink-entry.md new file mode 100644 index 0000000..78317fd --- /dev/null +++ b/docs-linhay/spaces/20260527-command-surface-optimization/plans/checkpoints/20260602-round-180-short-app-go-deeplink-entry.md @@ -0,0 +1,42 @@ +# Round 180 - short app go deeplink entry(2026-06-02) + +## 背景 + +- 真实使用中,iOS deep link 验证命令过长:`triton app open-url --device --wait-ready --snapshot --json`。 +- 对 agent 来说,`wait-ready + snapshot + json` 是常用安全模式,不应要求每次显式拼出。 + +## 变更 + +- 新增短入口:`triton app go `。 +- `app go` 默认执行 iOS `open-url + wait-ready + snapshot`,并保持 JSON 为默认输出。 +- `app go` 的 target 选择顺序:显式 `--device/--simulator`、当前 target、唯一 ready iOS target。 +- iOS simulator selector 支持裸 UDID 与 `sim:`;`sim:` 只是平台消歧前缀,不是必填。 +- `triton plan open-url` 和 capability `nextAction` 首选 `triton app go `,不再推荐长 `open-url --wait-ready --snapshot --json`。 +- `--json` 可省略:schema 默认 `--format=json` 被纳入机器可读门禁,不再强制对默认 JSON 命令追加显式 `--json`。 + +## 用户可用命令 + +```bash +triton device use sim:60667794-96F8-40E6-8664-85538EC4663E +triton app go "dxy-jobmd://nativejump/test/talentMoreFilter" +``` + +若不想写 current target,也可保留显式 selector: + +```bash +triton app go "dxy-jobmd://nativejump/test/talentMoreFilter" --device sim:60667794-96F8-40E6-8664-85538EC4663E +``` + +也可以省略 `sim:`: + +```bash +triton app go "dxy-jobmd://nativejump/test/talentMoreFilter" --device 60667794-96F8-40E6-8664-85538EC4663E +``` + +## 验证 + +- `swift build --package-path CLI --product triton` 通过。 +- `swift test --package-path CLI --filter SchemaFactSourceTests/capabilityGroupsKeepMachineReadableNextActionOutputFlags` 通过。 +- `swift test --package-path CLI --filter SchemaFactSourceTests/capabilityNextActionsStayAlignedWithCommandSchemas` 通过。 +- `swift test --package-path CLI --filter SchemaFactSourceTests/taskWorkflowPlansExposeExecutableCommandSequences` 通过。 +- `swift test --package-path CLI --filter DeviceCrossPlatformTests/appAndSmokeSchemasExposeUnifiedDeviceSelector` 通过。 diff --git a/docs-linhay/spaces/20260604-issue-27-agent-skills-readme/README.md b/docs-linhay/spaces/20260604-issue-27-agent-skills-readme/README.md new file mode 100644 index 0000000..de69219 --- /dev/null +++ b/docs-linhay/spaces/20260604-issue-27-agent-skills-readme/README.md @@ -0,0 +1,33 @@ +# Issue 27 - Clarify optional Codex/agent skills installation in README + +## 背景 + +GitHub Issue #27 指出:根 README 已覆盖 iOS embedded runtime、macOS CLI 与 Harmony / DevEco 集成路径,但没有明显说明 TritonKit 随附的可选 Codex/agent skills 安装路径,外部采用项目容易遗漏自动化指导。 + +## 目标 + +- 在根 README 的集成/安装说明中增加简短的 Optional Agent Skills 说明。 +- 明确外部用户只安装 `.agents/tritonkit-skills/public/` 下的 public skills。 +- 明确 `.agents/tritonkit-skills/internal/` 仅用于 TritonKit 仓库维护,不应作为外部项目默认安装内容。 +- 提醒安装后重启 Codex / agent session 以重新发现 skills。 + +## 非目标 + +- 不改动 skill 打包逻辑。 +- 不新增 Web/Wails UI。 +- 不改动 CLI/HTTP 业务契约。 + +## BDD 场景与验收 + +### 场景:外部采用者从根 README 发现可选 agent skills + +Given 外部采用者阅读根 README +When 查找 TritonKit 可选自动化/agent 指南 +Then README 应展示 Optional Agent Skills 章节 +And 列出 public skill 路径 +And 说明 internal skills 不面向外部默认安装 +And 提醒安装后重启 Codex / agent session + +## 相关链接 + +- GitHub Issue: https://github.com/NeptuneKit/TritonKit/issues/27 diff --git a/docs-linhay/spaces/20260604-issue-27-agent-skills-readme/plans/implementation.md b/docs-linhay/spaces/20260604-issue-27-agent-skills-readme/plans/implementation.md new file mode 100644 index 0000000..ec89e8a --- /dev/null +++ b/docs-linhay/spaces/20260604-issue-27-agent-skills-readme/plans/implementation.md @@ -0,0 +1,18 @@ +# Issue 27 实施计划 + +## BDD 验收 + +- Given 外部采用者阅读根 README +- When 查找 TritonKit 可选 Codex / agent skills 安装说明 +- Then README 展示 `Optional Agent Skills` 章节 +- And 明确 public skill 源路径 `.agents/tritonkit-skills/public/` 与 release asset `tritonkit-skills.tar.gz` +- And 列出当前 public skills:`tritonkit-dev-feedback`、`tritonkit-emulator-cli-takeover`、`tritonkit-real-project-regression` +- And 说明 `.agents/tritonkit-skills/internal/` 仅用于 TritonKit repo maintenance,不默认安装到 adopting projects +- And 提醒安装后重启 Codex / agent session + +## 执行步骤 + +1. 阅读 space README、根 README、`.agents/tritonkit-skills/README.md` 与 public skill front matter,确认 packaging 只包含 public skills。 +2. 在根 README 集成路径表后补充 `Optional Agent Skills` 章节。 +3. 运行 `docs-linhay/scripts/check-docs.sh` 做纯文档结构校验。 +4. 写回 memory 并提交本地 commit。