一个将任务生命周期和独立嵌入式终端结合在一起的 Wails 桌面应用。
- 任务包含必填标题、可选描述和可选颜色,并按“未执行 / 执行中 / 已完成”管理;左侧以三个状态标签页分类展示并记住上次选择,已完成任务不可再次执行。未执行和已完成标签都可进入选择模式,批量删除无生命周期执行记录的任务;删除前必须确认,且只移除任务记录,不影响工作目录或生命周期命令。执行中任务以及正在执行或等待重试命令链的任务不可删除。
- 新建任务可使用颜色选择器设置颜色,任务列表会以该颜色标记对应任务。
- 设置中的“任务模板”可维护多个具名模板并选择当前模板。模板字段支持键、显示名称、字符串或布尔值、必填、默认值和生命周期环境变量注入;当前模板字段显示在任务描述和颜色之间。新安装及尚未选择模板的既有设置会预置并选中“默认分支”模板,其中
branch字段显示为“默认分支”、默认值为空且必须填写。任务保存字段值及所用模板 ID,模板切换或删除字段后仍会保留历史值;重新使用同一字段键时可恢复历史值。未执行或执行中的任务仍引用某模板时不可删除该模板;只被已完成任务引用的模板可以删除。 - 顶部“额外信息管理”采用“分类即模板”的方式:先定义模板的固定字段、默认值和动态参数,再按模板填写并保存可复用的信息;每个模板都自动包含固定
name字段,信息列表和任务选择器均以其值展示。动态参数支持文本和复选框两种输入类型:复选框默认未选中,在应用持久化快照中保存为字符串true或false,且不提供必填设置。信息还可新增自身的动态参数,任务选择信息后会带入模板参数及信息参数,只显示显示名称和可编辑值,且仍可在任务内新增动态参数。模板区域可整体折叠,信息按模板折叠分组,搜索仅过滤信息名称并保留所有分类。任务保存完整快照,因此信息或模板之后被删除仍可保留并编辑任务级动态参数。内置 Git 模板包含“项目名称”(name)、“仓库地址”(repository)和动态“仓库分支”(branch);其固定键和显示名称不可修改,可设置默认值并添加字段或参数,branch始终是可选文本参数。 - 开始任务时创建独立工作目录并保存目录快照;结束任务经确认后关闭该任务全部终端并安全删除目录。
- 支持可复用的生命周期命令链和具名预设。设置中的“生命周期编排”可为自定义命令和命令链勾选一个或多个适用钩子;链只能加入覆盖其全部范围的命令。预设可为全部五个钩子组合链选择,并可设为可选的默认预设;新建任务可一键套用预设、选择不使用预设,或再逐钩子调整为“自定义”。任务只保存展开后的链映射,后续编辑或删除预设不会影响既有任务。未执行任务编辑时可调整链选择;执行中和已完成任务只读展示链选择。系统内置“创建任务工作目录”固定用于
beforeStart和postStart,“删除任务工作目录”固定仅用于postEnd,“克隆指定 Git 仓库”固定仅用于beforeStart和postStart;既有“Git 仓库克隆”可用于beforeStart、postStart、beforeEnd和updateTask;“生成清单文件”和“更新默认分支”可用于beforeStart、postStart和updateTask。六者均不可修改或删除。 - 执行中的任务可从右键菜单或“任务操作”下拉菜单新增多个终端。暂时无需关注的执行中任务可通过“搁置任务”收纳到列表末尾的“已搁置(n)”折叠区;搁置不改变任务状态或终端运行,重启后仍会保留,取消搁置后任务追加到正常执行中列表末尾。终端作为任务树子节点显示,并在右侧使用 xterm 交互;选中的非空终端文本会自动复制到系统剪贴板,右键可直接粘贴系统剪贴板的非空文本;程序可通过 OSC 0/2 标题序列实时设置终端名称,未设置时显示“终端”;双击任务条目可展开或收起终端,任务可在同一状态标签页内拖动排序并持久化。
- 终端和任务提供会话级实时状态:绿色表示工作中、紫色表示未读、灰色表示空闲、红色表示异常。工作中和未读状态点会以扩散动画提示;任务收起时显示按“异常 > 未读 > 工作中 > 空闲”汇总的状态点;展开时仅显示各终端状态。主动关闭的终端会从界面移除,异常退出的终端保留红色状态点。
- 任务操作菜单可在设置中排序;固定操作可改名和调序,但其行为不可修改。搁置切换也是固定操作,可分别设置执行中显示的“搁置任务”和已搁置时显示的“取消搁置”名称。自定义操作可配置名称、命令、逐行参数、是否显示为独立终端,以及可选的前置、后置脚本。自定义命令和脚本都会通过已选择 Shell 的初始化环境、在任务工作目录中启动,因此可直接使用该 Shell
PATH中的codex或脚本;未显示终端的命令会在任务工作目录中后台启动,例如code .。 - 每个前置、后置脚本分别配置
script(脚本路径或 ShellPATH中的可执行脚本)和arguments;参数每行一个,空白行忽略。不会进行占位符替换、字符串拼接,也不会把上下文 JSON 追加到命令行。脚本会从 UTF-8 标准输入接收主命令上下文:{"taskId":"任务 ID","directory":"任务工作目录","command":"主命令","arguments":["主命令参数"]}。前置脚本成功后才会启动主命令;主命令实际退出后才会运行后置脚本,无论主命令是否成功退出。前置失败会显示错误并停止主命令,后置失败只显示错误;任务进入结束流程后,尚未触发的后置脚本会跳过。 - 工作区根目录、任务树宽度、亮色/暗色模式、终端 Shell 路径、任务操作菜单、实时状态方式和本机 HTTP 服务开关可持久化设置;设置使用“工作区与外观 / 终端 Shell / 菜单管理 / 实时状态”四个 Tab。新增或编辑自定义菜单项会在独立弹窗中完成,其中“前后置脚本”Tab 的“?”入口说明标准输入 JSON 字段和参数传递规则;确认主设置前不会写入磁盘。设置界面会探测当前平台可用的 Shell 供下拉选择,也支持手动填写有效路径。修改根目录只影响后续任务。
- 退出时若有执行中任务会请求确认,仅关闭 PTY,会保留任务状态和工作目录。
命令链按配置顺序执行。自定义命令通过任务设置中选定的 Shell 启动;系统目录命令、“克隆指定 Git 仓库”、“Git 仓库克隆”、“生成清单文件”和“更新默认分支”均由应用直接执行。第一条自定义命令的 UTF-8 标准输入是任务 HTTP 详情同结构的 JSON;当本机 HTTP 服务正在监听时,顶层额外包含当前 API 基址 baseURL。baseURL 仅通过标准输入传递,不会作为终端环境变量。templateFields 始终是当前任务模板筛选后的对象,无当前模板时为 {}。每一条后续自定义命令的标准输入严格等于上一条命令的标准输出原始字节,不会自动解析、合并或补回任务参数,因此命令应自行输出下一条命令需要的内容。
当前模板中勾选“注入生命周期环境变量”的字段只会传入自定义生命周期 Shell 命令:键 environment 会成为 TASKAI_ENVIRONMENT。字符串保持原值,布尔值使用 true 或 false,可选字符串为空时也会传入空值变量。普通终端、任务菜单命令、前后置脚本以及内置工作区、Git 命令均不会获得这些变量。
beforeStart 在任务状态变为“执行中”前运行,beforeEnd 在状态变为“已完成”前运行;两者失败时状态不会改变。postStart、postEnd 和执行中任务更新后的 updateTask 在状态或内容保存后运行,失败不会回滚已提交的状态或内容。开始前链异步完成后,任务树会自动切换到“执行中”并保留该任务,即使生命周期事件先于开始请求的旧响应到达。链执行或失败等待重试期间,任务树会显示当前钩子、命令和序号,并锁定编辑、排序、状态变更、右键菜单及任务操作;点击“重试命令链”会始终从链的第一条命令重新开始。
默认预设把“创建任务工作目录”放在 beforeStart,把“删除任务工作目录”放在 postEnd。该默认预设可在设置中清除或替换;选择预设时会整体替换全部钩子的选择,预设未包含的钩子会清空。内置创建操作可安全复用已存在的任务目录,删除不存在目录也视为成功。除 postEnd 外,命令都在任务工作目录中执行;postEnd 在工作区根目录中执行。若已完成任务引用的链后来被删除,界面仍会保留失败记录;重试时会提示“命令链已删除”。
命令和链可勾选多个适用钩子,但链内每条命令都必须覆盖链勾选的全部钩子。若链已被命令链预设引用,不能删除该链,也不能移除被预设引用的钩子范围;若链已被未执行或执行中任务选择,保存时同样不得移除这些任务所需的范围。这样既有任务在不可编辑链选择的前提下仍保持可执行。旧配置中的自定义命令和链会自动迁移为五个钩子均适用。
生命周期命令、命令链、命令链预设和默认预设选择只能通过“生命周期编排”的专用保存操作修改。工作区、外观和面板宽度等普通设置的保存,以及创建、编辑或切换状态时的任务保存,都不会提交或覆盖这些配置。各类保存交错执行时,系统会保留最新的生命周期配置;重启后,已保存的预设仍可在设置中查看并用于新建任务。专用保存完成后界面会刷新为最新的生命周期配置。
生命周期命令的“固定参数”属于命令本身,每次执行都会传入。新增或编辑自定义命令时可选择“允许在命令链中追加参数”;关闭时,命令链编辑器不会显示该命令的追加参数框,开启时才可逐行配置每个链引用的追加参数。关闭开关不会清空或改写已保存的链级追加参数,重新开启后会恢复显示;无论开关当前状态如何,既有链执行时都会先传入固定参数,再传入已保存的链级追加参数。系统“创建任务工作目录”和“删除任务工作目录”固定禁止追加参数,两种 Git 克隆命令、“生成清单文件”和“更新默认分支”固定允许。
系统提供两条可删除但不会自动选中的命令链。iterations-ai 仅适用于 beforeStart,依次执行更新默认分支、创建任务工作目录、以 repository=git@gitlab.jiandan100.cn:webdev/iterations-ai.git 克隆指定仓库、生成清单文件,以及以 dir=workspaces 执行 Git 仓库克隆。“更新仓库”仅适用于 updateTask,依次执行更新默认分支、生成清单文件并以 dir=workspaces 执行 Git 仓库克隆。两条链都不写入默认预设;未被预设、未执行或执行中任务引用时可按普通链删除,删除后不会在下次启动时重新创建。既有配置仅在完整匹配旧版预置链时才会自动前置该命令;已修改或删除的预置链保持不变。
“更新仓库”链不会执行 git pull、fetch、合并、覆盖或删除已有工作树;其 Git 仓库克隆步骤只会处理缺失的目标,已存在的目标继续跳过。iterations-ai 在指定仓库已经克隆后从链首重试时会因根目录非空而失败,须先清理任务目录再重试。
系统命令“更新默认分支”可加入 beforeStart、postStart 或 updateTask 链。追加参数可留空,留空时读取当前任务模板的 branch 字段;也可且只能填写一行 templateField=<字段键>,以指定其他模板字段。字段值在调度命令链时冻结;字段不存在、缺失或为空白字符串时不设置默认分支,字段不是字符串时命令失败。
该命令只修改本次命令链的运行时任务副本:它会把模板字段值填入所有内置 Git 信息中空白的 branch 参数,已明确填写的 Git 分支保持不变。不会修改已保存的任务、Git 信息或应用设置。需要将模板分支用于后续 Git 克隆或清单时,必须把该命令置于对应命令前;链中没有该命令时,后续命令不会隐式读取模板分支。
系统命令“克隆指定 Git 仓库”用于以 Git 模板初始化任务目录,只能加入 beforeStart 或 postStart 链。命令链参数必须且只能包含一行 repository=<仓库地址>;也可额外包含一行 dir=<相对目录>。dir 省略时,仓库直接克隆到任务工作目录本身;填写时直接克隆到 <任务工作目录>/<dir>,不会再创建以仓库或项目名称命名的嵌套目录。该命令只克隆链参数指定的一个仓库,完全不读取任务的 Git 附加信息。
执行前任务工作目录必须已存在,目标目录可以是空目录或由命令安全创建的空子目录;任何非空目录、普通文件、符号链接、绝对路径或会跳出任务工作目录的路径都会失败,不会跳过、覆盖或删除已有内容。通常应将“创建任务工作目录”置于同一 beforeStart 或 postStart 链的前面。
该命令的分支只由同一链中位于它之前的“更新默认分支”命令提供。未设置该命令,或该命令未取得非空字符串字段值时,不传 --branch,由远程仓库决定默认分支,因此不会假定默认分支名为 main 或 master;设置后优先检出远程同名分支,远程不存在时先克隆远程默认分支,再创建同名本地分支。该值仅在本次链执行期间有效,不会回填任务的 Git 附加信息分支快照。
在任务中选择一个或多个内置 Git 信息后,可在“生命周期编排”中把系统命令“Git 仓库克隆”加入命令链。该命令的追加参数可留空;留空时以任务工作目录为克隆根目录。若需要克隆到子目录,参数必须逐行填写且只能填写一行:dir=<相对目录>。dir 相对于任务工作目录,. 也表示任务工作目录;不接受绝对路径、空目录、.. 或会跳出任务工作目录的路径。
建议在 beforeStart 链中先放置“创建任务工作目录”,再放置“Git 仓库克隆”。应用会依次处理所选 Git 信息;留空时每个项目克隆到 <任务工作目录>/<项目名称>,例如配置 dir=repositories 时则克隆到 <任务工作目录>/repositories/<项目名称>。目标路径已经存在(无论是文件还是目录)时会跳过该项目;因此在某个仓库失败后重试同一命令链,会保留并跳过已经成功克隆的仓库。
克隆时直接调用本机 git,不会通过任务选定的 Shell 解释仓库地址、分支或目录。远程分支检查和克隆始终以目标目录的父目录作为工作目录,不依赖应用进程启动时的当前目录。未填写分支时使用远程默认分支;填写的分支在远程存在时直接检出;远程不存在该分支时,先克隆远程默认分支,再以它为基础创建同名本地分支。将“更新默认分支”置于此前时,空白 Git 分支会仅在本次执行中由指定模板字段补齐。Git 命令不会自动加入默认预设;除推荐的 beforeStart 外,也可按需要配置在 postStart、beforeEnd 或 updateTask 链中。
系统命令“生成清单文件”可加入 beforeStart、postStart 或 updateTask 链。参数均为可选且最多一行:dir=<相对目录> 指定任务工作目录内的输出目录,name=<文件名> 指定清单文件名。未填写时生成 <任务工作目录>/manifest.yaml。dir 不接受绝对路径或会跳出任务工作目录的路径;name 必须是单个文件名,不能包含目录。缺失的合法 dir 子目录会安全创建,符号链接、目录或其他非普通文件目标会失败。
清单使用 YAML,固定包含 iteration、desc、repos:前两项分别是任务标题和任务描述;repos 按任务选中的内置 Git 信息顺序生成,每项包含 name(项目名称)、url(仓库地址)和 branch(分支)。没有选中 Git 信息时写为 repos: []。清单只读取本次执行任务副本中的 Git branch:已填写的值直接使用;要为其中的空值填入模板字段,需在链中先执行“更新默认分支”;未执行该命令时空值写为空字符串。
同一目标文件会在完整生成后原子替换,因此 postStart 或 updateTask 的重复运行会同步最新任务内容。beforeStart 使用该命令时,通常应在同一命令链中先放置“创建任务工作目录”;目录或写入失败会阻止任务启动,postStart 和 updateTask 中的失败则保留已提交状态并提供重试。
实时状态只保留在当前应用会话,重启后从空闲状态重新开始。设置中的“实时状态”提供三种方式:
- 根据终端标题变化(默认):当终端通过 OSC 0/2 更新为不同标题时,终端立即进入工作中;连续 1.5 秒没有新的标题变化后,当前选中的终端变为空闲,未选中的终端变为未读。点击终端会将它的未读状态清为空闲。
- 根据终端输出变化:任意非空终端输出(包括命令回显、进度刷新、ANSI 或 OSC 控制序列)都会使终端立即进入工作中;每次输出都会重新计算 1.5 秒静默期,静默后当前选中的终端变为空闲,未选中的终端变为未读。
- 通过 HTTP 接口:需要填写 1–65535 的端口,并会自动启用本机 HTTP 服务。服务只监听
127.0.0.1,不提供鉴权;可直接更新任务或终端状态。任务的直接更新是临时覆盖,下一次终端状态更新会重新按终端状态汇总。
也可以在标题变化或终端输出变化模式下独立启用本机 HTTP 服务,以查询任务、终端和状态数据;当独立开关关闭且状态管理不使用 HTTP 时,服务会停止。
新创建的普通终端和“显示终端”的自定义命令始终会注入:
TASKAI_TASK_ID=<任务 ID>
TASKAI_TERMINAL_ID=<终端 ID>
本机 HTTP 服务正在监听时,之后新建的终端还会额外注入:
TASKAI_STATUS_API=http://127.0.0.1:<端口>/api/v1
无终端后台自定义命令和前置、后置脚本仅注入 TASKAI_TASK_ID。
切换状态方式、服务开关或端口不会修改已经运行的进程环境变量;请新建终端后再使用新的配置。
状态枚举为 idle、working、unread、error。查询接口:
curl "$TASKAI_STATUS_API/status"示例响应:
{
"tasks": [
{
"taskId": "任务 ID",
"title": "任务名称",
"lifecycleStatus": "running",
"status": "working",
"terminals": [
{"terminalId": "终端 ID", "status": "working"}
]
}
]
}/status 的 status 参数可按任务生命周期筛选,合法取值为 pending、running、completed。响应中的 lifecycleStatus 是任务生命周期,status 仍是实时终端状态:
curl "$TASKAI_STATUS_API/status?status=completed"任务查询接口不依赖状态管理方式。status 参数可省略;合法取值仅为 pending、running、completed。省略时返回全部任务,指定时只返回对应生命周期的任务:
curl 'http://127.0.0.1:<端口>/api/v1/tasks?status=pending'
curl 'http://127.0.0.1:<端口>/api/v1/tasks?status=running'
curl 'http://127.0.0.1:<端口>/api/v1/tasks?status=completed'
curl 'http://127.0.0.1:<端口>/api/v1/tasks/<任务 ID>'列表返回任务数组;详情返回单个任务,包含 id、title、description、color、status、创建/完成时间以及工作区根目录和任务工作目录。详情额外包含 extraInfo:它按 catalogue 聚合为对象键,每项将全部固定字段的键和值及参数键、参数值平铺为对象;复选框参数返回 JSON 布尔值 true 或 false,固定字段和文本参数返回字符串。详情还包含 terminals:每项返回活动终端的 id、执行 command 和实时 status。普通终端的命令为 Shell 路径,自定义命令终端使用其启动命令;状态为 idle、working、unread 或 error。没有活动终端时该字段为 []。详情还会返回 lifecycleChains(五个钩子的链 ID 选择)以及执行中或失败时的 lifecycleExecution(钩子、链、当前命令、序号、状态和错误)。列表接口不返回 extraInfo 或 terminals。无效 status 返回 400,不存在的任务返回 404。
列表和详情中的每个任务对象均包含 templateFields。它是为外部扩展准备的独立 JSON 对象,只含当前模板定义的字段和值,不含显示名称、默认值或模板 ID;字符串保持 JSON 字符串,布尔字段保持 JSON 布尔值。无当前模板或任务没有可见字段时返回空对象 {},不再属于当前模板的历史值不会输出。例如:{"templateFields":{"environment":"production","deploy":true}}。
例如任务选择两个 Git 信息后,详情中的附加信息为:
{
"extraInfo": {
"git": [
{"name": "API 服务", "repository": "git@example.com:team/api.git", "branch": "main"},
{"name": "Web 服务", "repository": "git@example.com:team/web.git", "branch": "release/1.0"}
]
}
}extraInfo 返回固定字段 name 作为信息名称,但不返回字段显示名称、参数显示名称或元素内独立的 catalogue 字段;任务未选择附加信息时返回空对象 {}。复选框的 JSON 布尔输出仅适用于任务详情 HTTP 接口,应用内部快照仍以字符串保存以兼容既有数据。
更新当前终端会自动重新汇总对应任务:
curl -X PUT "$TASKAI_STATUS_API/tasks/$TASKAI_TASK_ID/terminals/$TASKAI_TERMINAL_ID/status" \
-H 'Content-Type: application/json' \
--data '{"status":"working"}'也可以直接临时更新任务状态:
curl -X PUT "$TASKAI_STATUS_API/tasks/$TASKAI_TASK_ID/status" \
-H 'Content-Type: application/json' \
--data '{"status":"unread"}'两个更新接口的请求体都要求 status 字段,合法取值仅为 idle、working、unread、error,例如 {"status":"working"};成功响应包含 taskId、taskStatus,终端更新还包含 terminalId、terminalStatus。无效 JSON 或状态返回 400,不存在的任务或终端返回 404,已结束任务或已关闭终端返回 409,错误方法返回 405;错误响应为 {"error":"..."}。
wails dev前端单独运行:
cd frontend
npm run devgo test -race ./...
cd frontend && npm test && npm run buildWails 的 Linux 与 macOS 图形依赖不支持在其他操作系统上稳定交叉编译,因此请在目标系统上运行对应脚本。构建产物统一位于 build/bin。
Linux(默认 amd64,可选 arm64 或 arm):
chmod +x scripts/build-linux.sh
./scripts/build-linux.sh
./scripts/build-linux.sh arm64在 Debian/Ubuntu 或兼容环境中,可在二进制构建成功后额外生成 DEB 包:
./scripts/build-linux.sh --deb --version 1.2.3
./scripts/build-linux.sh arm --deb --version 1.2.3
TASKAI_DEB_VERSION=1.2.3 ./scripts/build-linux.sh --debDEB 位于 build/bin/taskai_<版本>_<架构>.deb;其中 arm 会规范化为 Debian 的 armhf。版本号优先级依次为 --version、TASKAI_DEB_VERSION 和基于当前 Git 短提交号的开发版本。可在安装前检查包信息和文件布局:
dpkg-deb --info build/bin/taskai_1.2.3_amd64.deb
dpkg-deb --contents build/bin/taskai_1.2.3_amd64.deb
sudo apt install ./build/bin/taskai_1.2.3_amd64.debWindows PowerShell(默认 amd64,可选 arm64 或 386;传入 -NSIS 时生成安装程序):
.\scripts\build-windows.ps1
.\scripts\build-windows.ps1 -Architecture arm64
.\scripts\build-windows.ps1 -NSIS脚本会在构建前删除已有的 build/windows/icon.ico,使 Wails 从当前 build/appicon.png 重新生成 ICO;普通 EXE 与 NSIS 安装程序会使用同一最新图标。
macOS(默认构建 Universal 二进制;可选 amd64 或 arm64):
chmod +x scripts/build-macos.sh
./scripts/build-macos.sh
./scripts/build-macos.sh arm64- 类 Unix 平台使用
creack/pty。 - Windows 使用 ConPTY,需要 Windows 10 1809 / Windows Server 2019 或更高版本。
- Linux 打包或运行 Wails 需要 GTK 3 和 WebKitGTK 开发包。脚本优先使用
libwebkit2gtk-4.1-dev(传递webkit2_41标签),也兼容libwebkit2gtk-4.0-dev。 - Linux 的
--deb模式还需要dpkg-deb和dpkg-shlibdeps(通常由dpkg与dpkg-dev提供),并应在目标发行版或 ABI 兼容环境中构建。 - Windows 构建需要 Wails CLI、Go 和 C/C++ 编译工具链;使用
-NSIS还需要安装 NSIS。 - macOS 构建需要 Wails CLI、Go 与 Xcode 命令行工具。