diff --git a/DESIGN.md b/DESIGN.md index dfa324f..1574f1f 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -80,3 +80,11 @@ Chromium 浏览器点击、按键、输入和滚动使用明确的 foreground 本地目录可能保留 OCU 与早期 Cua 候选改动,而发布引用已经包含后续修订。先检查 Git 状态、分叉提交和具体文件,分别记录源码状态、发布状态及实际安装状态;旧候选文档的结论不能覆盖发布记录。 发布范围较窄时可在最新目标分支的隔离工作树中移植本次提交,推送后核对远端 SHA。原目录的未归并分支和用户改动继续保留,不能为了发布文档而顺带推送全部历史、覆盖文件或删除本地开发现场。 + +## 声明式工作区扩展 + +`plugins/task-review` 使用清单版本 3 的 workspace 接口。插件声明面板位置和宽度、字段标签/选项/报告属性;宿主负责安全渲染、响应式布局、任务绑定存储、并发保存与报告缓存。纯界面扩展不声明 MCP、Skill、设备资源或调度器,不参与模型执行插件选择。 + +评审由人工填写,使用「通过 / 失败」按钮,备注独立选填。未装或停用时不贡献界面与新报告字段;卸载保留任务内记录,重装后恢复;任务删除时清理。插件不可改写原任务执行状态或既有复验结论。 + +工作区扩展从 ARTEMIS 2.3.0 起提供。catalog-v3.json 服务 2.3.0+,旧 catalog.json 保留给严格校验清单版本的 2.2.x;执行插件更新应同步两个索引,工作区插件仅加入新版索引。先发布并回读核验不可变附件,再提交包含新插件的市场索引。 diff --git a/README.md b/README.md index 2e2958b..b151cc4 100644 --- a/README.md +++ b/README.md @@ -36,3 +36,9 @@ python tests/cua_discovery_smoke.py <安装后的artemis-cua-adapter.exe> --app 插件版本跟随所用 Cua Driver 上游版本。市场已发布适配版为 `0.36.0+artemis.4`,发行标签 `cua-driver-v0.36.0+artemis.4`;当前源码候选为 `0.38.0+artemis.1`,对应上游标签 `cua-driver-rs-v0.38.0`。只修改 ARTEMIS 适配而未升级上游时使用 `+artemis.N` 后缀区分不可变安装包;包内 `provenance.json` 记录上游提交、原包校验值和适配修订,构建会检查版本对应关系。 [发行说明](plugins/cua-driver/RELEASE.md) · [ARTEMIS 主项目](https://git.playones.com/chenmingxuan/Artemis-Eapil) + +## 工作区扩展:任务人工评审 1.0.0 + +[task-review](plugins/task-review/README.md) 使用 ARTEMIS 清单版本 3,为步骤回放增加需求 Markdown 与人工评审侧栏,并将选填结果写入报告。此插件不运行 MCP 或设备操作,需要 ARTEMIS 2.3.0+,在主程序插件市场安装并启用;2.2.x 尚不支持。 + +构建:`python scripts/build_task_review.py`。输出 ZIP 与校验文件位于 `artifacts/task-review/`。验证范围见 [VERIFICATION](plugins/task-review/VERIFICATION.md)。发行标签 `task-review-v1.0.0`,市场安装包与 SHA256 以 `catalog-v3.json` 为准;`catalog.json` 保留给 2.2.x。 diff --git a/catalog-v3.json b/catalog-v3.json new file mode 100644 index 0000000..4a93fce --- /dev/null +++ b/catalog-v3.json @@ -0,0 +1,192 @@ +{ + "schema_version": 1, + "plugins": [ + { + "manifest": { + "schema_version": 2, + "id": "cua-driver", + "name": "电脑控制 · Cua", + "version": "0.38.0+artemis.1", + "description": "通过 Cua Driver 的窗口截图与可访问性树操作 Windows 应用及浏览器窗口;复用 ARTEMIS 的任务调度、步骤证据与录像。", + "artemis_version": ">=2.0.0,<3.0.0", + "platforms": [ + "win32" + ], + "architectures": [ + "amd64" + ], + "source": "https://github.com/trycua/cua", + "license": "MIT", + "server": { + "transport": "stdio", + "command": "${plugin_dir}/bin/artemis-cua-adapter.exe" + }, + "skill": "SKILL.md", + "targets": [ + "computer", + "mixed" + ], + "resources": [ + "desktop:local" + ], + "observation": { + "tool": "list_windows", + "arguments": { + "on_screen_only": true + }, + "refresh_tools": [ + "get_window_state" + ] + }, + "capabilities": { + "kind": "visual", + "recording": "windows", + "tools": { + "list_windows": { + "effect": "read", + "observation": true, + "idempotent": true, + "target_argument": "", + "cancellation": "unknown", + "evidence": [ + "text" + ] + }, + "get_window_state": { + "effect": "read", + "observation": true, + "idempotent": true, + "target_argument": "window_id", + "cancellation": "unknown", + "evidence": [ + "text", + "image" + ] + }, + "verify_state": { + "effect": "read", + "observation": false, + "idempotent": true, + "target_argument": "window_id", + "cancellation": "unknown", + "evidence": [ + "text", + "image" + ] + }, + "click": { + "effect": "write", + "observation": false, + "idempotent": false, + "target_argument": "window_id", + "cancellation": "unknown", + "evidence": [ + "text", + "image" + ] + }, + "drag": { + "effect": "write", + "observation": false, + "idempotent": false, + "target_argument": "window_id", + "cancellation": "unknown", + "evidence": [ + "text", + "image" + ] + }, + "type_text": { + "effect": "write", + "observation": false, + "idempotent": false, + "target_argument": "window_id", + "cancellation": "unknown", + "evidence": [ + "text", + "image" + ] + }, + "press_key": { + "effect": "write", + "observation": false, + "idempotent": false, + "target_argument": "window_id", + "cancellation": "unknown", + "evidence": [ + "text", + "image" + ] + }, + "set_value": { + "effect": "write", + "observation": false, + "idempotent": false, + "target_argument": "window_id", + "cancellation": "unknown", + "evidence": [ + "text", + "image" + ] + }, + "scroll": { + "effect": "write", + "observation": false, + "idempotent": false, + "target_argument": "window_id", + "cancellation": "unknown", + "evidence": [ + "text", + "image" + ] + }, + "save_screenshot": { + "effect": "write", + "observation": false, + "idempotent": false, + "target_argument": "window_id", + "cancellation": "unknown", + "evidence": [ + "text", + "image", + "file" + ] + }, + "click_at": { + "effect": "write", + "observation": false, + "idempotent": false, + "target_argument": "window_id", + "cancellation": "unknown", + "evidence": [ + "text", + "image" + ] + }, + "bring_to_front": { + "effect": "write", + "observation": false, + "idempotent": true, + "target_argument": "window_id", + "cancellation": "unknown", + "evidence": [ + "text", + "image", + "state" + ] + } + }, + "required_tools": [ + "list_windows", + "get_window_state", + "save_screenshot" + ] + } + }, + "release_stage": "preview", + "archive_url": "https://git.playones.com/chenmingxuan/Artemis-Plugins/releases/download/cua-driver-v0.38.0+artemis.1/cua-driver-0.38.0+artemis.1-windows-amd64.zip", + "sha256": "c007da16d58c4165a1a344113e650e68bd92a69ad3ce4ca8285818c5426dc0f4", + "verification": "Windows x64 预览,配套 ARTEMIS 2.2.0。固定 Driver 0.38.0、源码提交和官方 ZIP 校验值;包含已知无标题 Shell/菜单兼容补丁及重新构建运行库。Go 测试、vet、构建及包内源码/二进制校验通过;菜单/任务栏 9 次调用、隔离 Brave 表单 38 次调用通过,并参与仅 PC 与跨端集中回归。前台输入占用桌面;显示光标与系统鼠标偶发分离待复现,未全面覆盖多屏/DPI、长时间压力、其他托盘菜单及原失败业务全流程。详情见 plugins/cua-driver/VERIFICATION.md。" + } + ] +} diff --git a/plugins/task-review/LICENSE b/plugins/task-review/LICENSE new file mode 100644 index 0000000..ba26287 --- /dev/null +++ b/plugins/task-review/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2026 Google LLC. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/plugins/task-review/README.md b/plugins/task-review/README.md new file mode 100644 index 0000000..f145021 --- /dev/null +++ b/plugins/task-review/README.md @@ -0,0 +1,13 @@ +# 任务人工评审 1.0.0 + +需要 ARTEMIS 2.3.0 或更高的 2.x 版本。升级主程序后,打开「插件」市场,安装「任务人工评审」并手动启用。也可在「插件 → 高级接入」导入本目录或发行 ZIP。2.2.x 不支持此接口。 + +在步骤回放打开「任务需求」查看本次运行最初收到的需求提示词(Markdown),打开「人工评审」填写两个独立维度及各自备注。全部选填,空项不阻止保存或导出。只有任务结束后可以编辑;可修改、清空并查看历史。 + +此插件没有 MCP、Skill、AI 调用、设备操作或任务执行资源。评审不覆盖原有测试结论和人工复验。安装并启用时,单任务 Word/Excel、批次汇总及资料包报告显示评审字段,未填字段为空。禁用或卸载后隐藏面板及新导出中的字段,历史数据由宿主保留,重新安装启用后恢复。已下载报告不会改写;删除任务会清理该任务的评审。 + +`workspace.panels[].width` 声明首选、最小和最大宽度(CSS 像素);宿主根据播放器和屏幕空间调整布局,窄屏可低于声明的最小值以避免溢出。默认收起、左右独立展开;窄屏一次展开一侧;单侧展开始终保持在回放左边或右边。 + +在仓库根目录运行 `python scripts/build_task_review.py` 生成安装 ZIP 和 SHA256SUMS.txt。产物默认在 `artifacts/task-review/`,不提交构建产物。发行标签为 `task-review-v1.0.0`;市场索引 catalog-v3.json 引用对应发行 ZIP 与校验值。 + +回放标题栏的侧栏按钮控制左右展开;两项评审使用「通过 / 失败」分段按钮,再次点击已选项可清空。导出保留相同中文值。 diff --git a/plugins/task-review/RELEASE.md b/plugins/task-review/RELEASE.md new file mode 100644 index 0000000..e0ab15a --- /dev/null +++ b/plugins/task-review/RELEASE.md @@ -0,0 +1,13 @@ +# 任务人工评审 1.0.0 + +需要 ARTEMIS 2.3.0+(2.x)。先升级主程序,再从「插件」市场安装「任务人工评审」并启用;也可导入本发行页的 `task-review-1.0.0.zip`。 + +- 步骤回放左侧展示任务最初需求提示词,支持 Markdown;右侧填写人工评审。 +- 「AI执行准确性」「测试结果正确性」各有「通过 / 失败」按钮和独立可选备注。均可留空、清空,不需要 AI 参与。 +- 标题栏控制左右展开,普通浮窗及影院模式均可用,单侧也保持左右布局。 +- 终态任务允许保存、修改及查看历史;并发修订校验和幂等重试防止覆盖或重复保存。 +- 安装启用时,字段进入单任务 Word/Excel、批次汇总和资料包报告;空项留空。禁用或卸载后不出现在新导出中,已保存数据由宿主保留。 + +插件没有运行进程、MCP 服务或设备操作,无需手机、模拟器或付费模型。它不覆盖任务结论或既有人工复验,复跑也不会继承上一轮评审。 + +验证:Windows 隔离示例的 UI、保存与导出检查通过;宿主确定性回归及前端构建通过,详见 [验证记录](VERIFICATION.md)。macOS/Linux 尚未实测。下载后可用 SHA256SUMS.txt 校验安装包。 diff --git a/plugins/task-review/VERIFICATION.md b/plugins/task-review/VERIFICATION.md new file mode 100644 index 0000000..9d3a84c --- /dev/null +++ b/plugins/task-review/VERIFICATION.md @@ -0,0 +1,21 @@ +# 任务人工评审 1.0.0 验证记录 + +日期:2026-10-27。发布目标:task-review-v1.0.0。 + +宿主:ARTEMIS 2.3.0。插件基于独立插件仓库 b780a60,未夹带其他未发布插件变更;清单最低宿主版本为 2.3.0,2.2.x 不支持。 + +## 已验证 + +- 宿主默认确定性测试:3197 passed,2 skipped,8 deselected。 +- 前端 ChromeHeadless:336 项通过;生产构建通过。 +- 宿主 Ruff 格式/静态检查、质量基线、核心 Pyright 通过。 +- 清单和字段验证、仅启用插件贡献字段、纯界面插件不参与执行选择。 +- 原始任务提示词 Markdown、部分填写、清空、失败重试保留输入、修订冲突、历史记录、切换任务不串写。 +- 运行中只读,终态可评审;禁用/卸载隐藏贡献,重装恢复,删除任务/批次清理;复跑不继承。 +- Word/Excel 单任务和批次汇总、ZIP 报告包含已启用贡献,未填为空;评审和插件状态变更使旧缓存失效。 +- 使用生产前端与隔离示例任务进行浏览器验证:标题栏左右开关、普通浮窗/影院模式、浅色/深色、单侧在左右展开;600/740px 容器左右布局的浏览器回归通过。 +- 实际通过网页保存中文「通过」,生成 Word/Excel 并确认值为中文,另一未填结果为空。 + +## 范围 + +验证使用 Windows 本地环境与临时数据库,不操作用户设备、业务应用或现有任务,不调用模型。未在 macOS/Linux 实测,不将此记录视为真实业务用例通过或市场发布证明。此插件无运行进程和 MCP,因此不需要设备动作、取消进程或录像验收。 diff --git a/plugins/task-review/plugin.json b/plugins/task-review/plugin.json new file mode 100644 index 0000000..77f3f4e --- /dev/null +++ b/plugins/task-review/plugin.json @@ -0,0 +1,84 @@ +{ + "schema_version": 3, + "id": "task-review", + "name": "任务人工评审", + "version": "1.0.0", + "description": "在步骤回放中查看初始需求提示词,由人工标记 AI 执行准确性与测试结果正确性,按需填写备注并随报告导出。", + "artemis_version": ">=2.3.0,<3.0.0", + "platforms": [ + "win32", + "linux", + "darwin" + ], + "architectures": [ + "amd64", + "arm64" + ], + "license": "Apache-2.0", + "targets": [], + "capabilities": { + "kind": "other", + "recording": "none", + "tools": {} + }, + "workspace": { + "panels": [ + { + "id": "requirements", + "title": "任务需求", + "side": "left", + "kind": "initial_prompt", + "width": { + "preferred": 340, + "minimum": 240, + "maximum": 480 + } + }, + { + "id": "review", + "title": "人工评审", + "side": "right", + "kind": "form", + "width": { + "preferred": 360, + "minimum": 260, + "maximum": 520 + } + } + ], + "fields": [ + { + "id": "execution_accuracy", + "label": "AI执行准确性", + "description": "Artemis自动化是否按照内部实际测试用例步骤执行", + "kind": "choice", + "options": [ + "通过", + "失败" + ] + }, + { + "id": "execution_note", + "label": "AI执行准确性备注", + "kind": "text", + "max_length": 2000 + }, + { + "id": "result_correctness", + "label": "测试结果正确性", + "description": "Artemis 按照内部实际用例步骤执行后,人工再次确认结果正确性", + "kind": "choice", + "options": [ + "通过", + "失败" + ] + }, + { + "id": "result_note", + "label": "测试结果正确性备注", + "kind": "text", + "max_length": 2000 + } + ] + } +} diff --git a/scripts/build_task_review.py b/scripts/build_task_review.py new file mode 100644 index 0000000..e8a379f --- /dev/null +++ b/scripts/build_task_review.py @@ -0,0 +1,30 @@ +"""Build the declarative task review plugin without runtime dependencies.""" + +import argparse +import hashlib +import json +from pathlib import Path +import zipfile + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--output", type=Path, default=Path("artifacts/task-review")) + args = parser.parse_args() + package = Path(__file__).resolve().parents[1] / "plugins" / "task-review" + manifest = json.loads((package / "plugin.json").read_text(encoding="utf-8")) + args.output.mkdir(parents=True, exist_ok=True) + target = args.output / f"task-review-{manifest['version']}.zip" + with zipfile.ZipFile(target, "w", compression=zipfile.ZIP_DEFLATED) as archive: + for name in ("plugin.json", "README.md", "LICENSE", "VERIFICATION.md", "RELEASE.md"): + info = zipfile.ZipInfo(name, date_time=(2026, 10, 27, 0, 0, 0)) + info.compress_type = zipfile.ZIP_DEFLATED + info.external_attr = 0o100644 << 16 + archive.writestr(info, (package / name).read_bytes()) + digest = hashlib.sha256(target.read_bytes()).hexdigest() + (args.output / "SHA256SUMS.txt").write_text(f"{digest} {target.name}\n", encoding="ascii") + print(f"{target}\nSHA256 {digest}") + + +if __name__ == "__main__": + main()