aitable-workflow-cli 0.1.28 → 0.1.29-beta.1790736949347

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/assistant/assets/index-BA6il19d.css +1 -0
  2. package/dist/assistant/assets/{index-B3LvYfRW.js → index-BMzAOp70.js} +31 -31
  3. package/dist/assistant/index.html +2 -2
  4. package/dist/chunk-BBP5RVFU.js +15 -0
  5. package/dist/cli.js +180 -73
  6. package/dist/{config-ui-server-4SVD42Z3.js → config-ui-server-UWELHUH4.js} +1 -1
  7. package/dist/web/assets/index-Bnmnydwk.css +1 -0
  8. package/dist/web/assets/index-Dbs1xWB9.js +331 -0
  9. package/dist/web/index.html +2 -2
  10. package/dist/web/install.ps1 +173 -0
  11. package/dist/web/install.sh +188 -0
  12. package/package.json +3 -3
  13. package/templates/ai-native-sdlc/.env.example +11 -0
  14. package/templates/ai-native-sdlc/aitable-workflow.config.yml +47 -0
  15. package/templates/ai-native-sdlc/coding-agents.config.json +17 -0
  16. package/templates/ai-native-sdlc/docs/plans/2026-09-15-ai-native-sdlc-dual-staff-implementation-plan.md +150 -0
  17. package/templates/ai-native-sdlc/docs/plans/2026-09-15-ai-native-sdlc-dual-staff.md +213 -0
  18. package/templates/ai-native-sdlc/docs/plans/2026-09-16-domain-role-notification-routing.md +36 -0
  19. package/templates/ai-native-sdlc/docs/plans/2026-09-16-execution-resume-and-cr-loop.md +29 -0
  20. package/templates/ai-native-sdlc/docs/plans/2026-09-16-project-handoff.md +148 -0
  21. package/templates/ai-native-sdlc/docs/plans/2026-09-17-prd-code-context-and-readable-prompts.md +37 -0
  22. package/templates/ai-native-sdlc/docs/plans/2026-09-21-plan-merge-sync-and-agent-source.md +19 -0
  23. package/templates/ai-native-sdlc/docs/plans/2026-09-21-sdlc-base-ref-and-review-notification.md +18 -0
  24. package/templates/ai-native-sdlc/docs/plans/2026-09-29-borrow-from-joe-design.md +943 -0
  25. package/templates/ai-native-sdlc/lib/artifacts.ts +126 -0
  26. package/templates/ai-native-sdlc/lib/recipe-config.ts +34 -0
  27. package/templates/ai-native-sdlc/lib/recipe-helpers.ts +595 -0
  28. package/templates/ai-native-sdlc/npmrc +1 -0
  29. package/templates/ai-native-sdlc/package.json +19 -0
  30. package/templates/ai-native-sdlc/profile/profile.yml +115 -0
  31. package/templates/ai-native-sdlc/setup/module-config.seed.json +37 -0
  32. package/templates/ai-native-sdlc/test/artifacts.test.ts +72 -0
  33. package/templates/ai-native-sdlc/test/recipe-helpers.test.ts +931 -0
  34. package/templates/ai-native-sdlc/tsconfig.json +17 -0
  35. package/templates/ai-native-sdlc/workflows/.gitkeep +3 -0
  36. package/templates/ai-native-sdlc/workflows/execution/automations/blocked-questions-dev.json +91 -0
  37. package/templates/ai-native-sdlc/workflows/execution/automations/blocked-questions.json +91 -0
  38. package/templates/ai-native-sdlc/workflows/execution/automations/cr-review-dev.json +80 -0
  39. package/templates/ai-native-sdlc/workflows/execution/automations/cr-review.json +81 -0
  40. package/templates/ai-native-sdlc/workflows/execution/automations/resume-answers.json +42 -0
  41. package/templates/ai-native-sdlc/workflows/execution/automations/spec-review-dev.json +138 -0
  42. package/templates/ai-native-sdlc/workflows/execution/recipes/coding.recipe.ts +161 -0
  43. package/templates/ai-native-sdlc/workflows/execution/recipes/prd-review.recipe.ts +200 -0
  44. package/templates/ai-native-sdlc/workflows/execution/recipes/prd.recipe.ts +163 -0
  45. package/templates/ai-native-sdlc/workflows/execution/recipes/review.recipe.ts +257 -0
  46. package/templates/ai-native-sdlc/workflows/execution/recipes/spec-review.recipe.ts +242 -0
  47. package/templates/ai-native-sdlc/workflows/execution/recipes/spec.recipe.ts +173 -0
  48. package/templates/ai-native-sdlc/workflows/execution/workflow.yml +79 -0
  49. package/templates/ai-native-sdlc/workflows/intake/automations/accept-intake.json +101 -0
  50. package/templates/ai-native-sdlc/workflows/intake/recipes/classify-module.recipe.ts +133 -0
  51. package/templates/ai-native-sdlc/workflows/intake/recipes/create-change.recipe.ts +94 -0
  52. package/templates/ai-native-sdlc/workflows/intake/recipes/mechanical-deduplicate.recipe.ts +33 -0
  53. package/templates/ai-native-sdlc/workflows/intake/workflow.yml +62 -0
  54. package/templates/ai-native-sdlc/workspaces/dev/AGENTS.md +69 -0
  55. package/templates/ai-native-sdlc/workspaces/pm/AGENTS.md +48 -0
  56. package/templates/ai-native-sdlc/workspaces/reviewer/AGENTS.md +79 -0
  57. package/dist/assistant/assets/index-CCEHOkkJ.css +0 -1
  58. package/dist/chunk-YDJTCQW4.js +0 -15
  59. package/dist/web/assets/index-DPc2WOdp.css +0 -1
  60. package/dist/web/assets/index-HTw8K38o.js +0 -332
@@ -5,8 +5,8 @@
5
5
  <link rel="icon" type="image/svg+xml" href="/icon.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>aitable-workflow · AI 工作流编排</title>
8
- <script type="module" crossorigin src="/assets/index-HTw8K38o.js"></script>
9
- <link rel="stylesheet" crossorigin href="/assets/index-DPc2WOdp.css">
8
+ <script type="module" crossorigin src="/assets/index-Dbs1xWB9.js"></script>
9
+ <link rel="stylesheet" crossorigin href="/assets/index-Bnmnydwk.css">
10
10
  </head>
11
11
  <body>
12
12
  <div id="root"></div>
@@ -0,0 +1,173 @@
1
+ # Public same-origin bootstrap for Windows PowerShell 5.1+ (native x64 only).
2
+
3
+ $ErrorActionPreference = 'Stop'
4
+ $ProgressPreference = 'SilentlyContinue'
5
+
6
+ $MinimumNodeVersion = [Version]'20.18.1'
7
+ $NodeMajor = if ($env:AITABLE_NODE_MAJOR) { $env:AITABLE_NODE_MAJOR } else { '22' }
8
+ $InstallRoot = if ($env:AITABLE_INSTALL_ROOT) { $env:AITABLE_INSTALL_ROOT } elseif ($env:LOCALAPPDATA) { Join-Path $env:LOCALAPPDATA 'aitable-workflow' } else { Join-Path $HOME '.aitable-workflow' }
9
+ $NpmPrefix = if ($env:AITABLE_NPM_PREFIX) { $env:AITABLE_NPM_PREFIX } else { Join-Path $InstallRoot 'npm' }
10
+ $NodeDistUrls = if ($env:AITABLE_NODE_DIST_URLS) { $env:AITABLE_NODE_DIST_URLS -split ';' } else { @('https://nodejs.org/dist', 'https://npmmirror.com/mirrors/node') }
11
+
12
+ function Write-InstallerInfo([string]$Message) { Write-Host " $Message" }
13
+ function Stop-Installer([string]$Message) { throw $Message }
14
+
15
+ function Get-CommandPath([string]$Name) {
16
+ $command = Get-Command $Name -ErrorAction SilentlyContinue | Select-Object -First 1
17
+ if ($null -eq $command) { return $null }
18
+ return $command.Source
19
+ }
20
+
21
+ function Test-NodeReady {
22
+ $node = Get-CommandPath 'node.exe'
23
+ $npm = Get-CommandPath 'npm.cmd'
24
+ if ($null -eq $node -or $null -eq $npm) { return $false }
25
+ try {
26
+ $version = [Version]((& $node -p 'process.versions.node' 2>$null | Select-Object -Last 1).ToString().Trim())
27
+ if ($version -lt $MinimumNodeVersion) { return $false }
28
+ $script:NodeCommand = $node
29
+ $script:NpmCommand = $npm
30
+ return $true
31
+ }
32
+ catch { return $false }
33
+ }
34
+
35
+ function Invoke-Download([string]$Uri, [string]$Destination) {
36
+ Invoke-WebRequest -UseBasicParsing -Uri $Uri -OutFile $Destination
37
+ }
38
+
39
+ function Resolve-LatestNode([string]$Architecture) {
40
+ $escapedMajor = [Regex]::Escape($NodeMajor)
41
+ foreach ($base in $NodeDistUrls) {
42
+ $base = $base.Trim().TrimEnd('/')
43
+ if (-not $base) { continue }
44
+ try {
45
+ $checksums = (Invoke-WebRequest -UseBasicParsing -Uri "$base/latest-v$NodeMajor.x/SHASUMS256.txt").Content
46
+ $match = [Regex]::Match($checksums, "(?m)^([0-9a-fA-F]{64})\s+(node-v($escapedMajor\.[0-9]+\.[0-9]+)-win-$Architecture\.zip)\s*$")
47
+ if ($match.Success) {
48
+ return @{ Base = "$base/latest-v$NodeMajor.x"; Hash = $match.Groups[1].Value.ToLowerInvariant(); Archive = $match.Groups[2].Value; Version = $match.Groups[3].Value }
49
+ }
50
+ }
51
+ catch { Write-InstallerInfo "Node.js 下载源暂不可用:$base" }
52
+ }
53
+ Stop-Installer "无法从 Node.js 官方源或镜像解析 Node.js $NodeMajor.x。"
54
+ }
55
+
56
+ function Add-UserPath([string[]]$Entries) {
57
+ $registryPath = 'Registry::HKEY_CURRENT_USER\Environment'
58
+ if (-not (Test-Path -LiteralPath $registryPath)) { New-Item -Path $registryPath -Force | Out-Null }
59
+ $userPath = Get-ItemPropertyValue -LiteralPath $registryPath -Name Path -ErrorAction SilentlyContinue
60
+ $allEntries = @($Entries + ($userPath -split ';')) | Where-Object { -not [string]::IsNullOrWhiteSpace($_) }
61
+ $unique = @()
62
+ foreach ($entry in $allEntries) {
63
+ $entry = $entry.Trim().TrimEnd('\')
64
+ if ($unique -notcontains $entry) { $unique += $entry }
65
+ }
66
+ Set-ItemProperty -LiteralPath $registryPath -Name Path -Value ($unique -join ';') -Force
67
+ foreach ($entry in $Entries) {
68
+ if (($env:Path -split ';') -notcontains $entry) { $env:Path = "$entry;$env:Path" }
69
+ }
70
+ Write-InstallerInfo '已更新当前用户 PATH;若其他终端未识别新命令,请重开终端。'
71
+ }
72
+
73
+ function Install-NodeManaged {
74
+ $architecture = $env:PROCESSOR_ARCHITECTURE
75
+ if ($env:PROCESSOR_ARCHITEW6432) { $architecture = $env:PROCESSOR_ARCHITEW6432 }
76
+ if ($architecture -ne 'AMD64') { Stop-Installer "不支持的 Windows 架构:$architecture。当前只支持原生 Windows x64。" }
77
+
78
+ $tempDirectory = Join-Path ([IO.Path]::GetTempPath()) ("aitable-install-" + [Guid]::NewGuid().ToString('N'))
79
+ New-Item -ItemType Directory -Path $tempDirectory -Force | Out-Null
80
+ try {
81
+ $resolved = Resolve-LatestNode 'x64'
82
+ $archivePath = Join-Path $tempDirectory $resolved.Archive
83
+ Write-InstallerInfo "正在下载并校验 Node.js v$($resolved.Version)。"
84
+ Invoke-Download "$($resolved.Base)/$($resolved.Archive)" $archivePath
85
+ $actualHash = (Get-FileHash -Algorithm SHA256 -LiteralPath $archivePath).Hash.ToLowerInvariant()
86
+ if ($actualHash -ne $resolved.Hash) { Stop-Installer 'Node.js SHA256 校验失败,已中止安装。' }
87
+ Expand-Archive -LiteralPath $archivePath -DestinationPath $tempDirectory -Force
88
+
89
+ $target = Join-Path $InstallRoot "node-v$($resolved.Version)"
90
+ New-Item -ItemType Directory -Path $InstallRoot -Force | Out-Null
91
+ if (Test-Path -LiteralPath $target) {
92
+ if (-not (Test-Path -LiteralPath (Join-Path $target 'node.exe')) -or -not (Test-Path -LiteralPath (Join-Path $target 'npm.cmd'))) {
93
+ Stop-Installer "用户级 Node.js 路径已存在但不完整,未覆盖:$target。请检查后自行修复。"
94
+ }
95
+ }
96
+ else {
97
+ $staging = "$target.new.$(New-Guid)"
98
+ Move-Item -LiteralPath (Join-Path $tempDirectory "node-v$($resolved.Version)-win-x64") -Destination $staging
99
+ Move-Item -LiteralPath $staging -Destination $target
100
+ }
101
+ $script:NodeCommand = Join-Path $target 'node.exe'
102
+ $script:NpmCommand = Join-Path $target 'npm.cmd'
103
+ $script:ManagedNodeDirectory = $target
104
+ $env:Path = "$target;$env:Path"
105
+ }
106
+ finally {
107
+ if (Test-Path -LiteralPath $tempDirectory) { Remove-Item -LiteralPath $tempDirectory -Recurse -Force }
108
+ }
109
+ }
110
+
111
+ function Install-WithNvm([string]$NvmCommand) {
112
+ $architecture = $env:PROCESSOR_ARCHITECTURE
113
+ if ($env:PROCESSOR_ARCHITEW6432) { $architecture = $env:PROCESSOR_ARCHITEW6432 }
114
+ if ($architecture -ne 'AMD64') { Stop-Installer "不支持的 Windows 架构:$architecture。当前只支持原生 Windows x64。" }
115
+ $resolved = Resolve-LatestNode 'x64'
116
+ Write-InstallerInfo "检测到 nvm-windows,安装并选择 Node.js v$($resolved.Version)。"
117
+ & $NvmCommand install $resolved.Version 64
118
+ if ($LASTEXITCODE -eq 0) {
119
+ & $NvmCommand use $resolved.Version 64
120
+ if ($LASTEXITCODE -eq 0 -and (Test-NodeReady)) { return }
121
+ }
122
+ Write-InstallerInfo 'nvm-windows 无法在当前权限下切换版本;改用用户目录安装,不会请求管理员权限。'
123
+ Install-NodeManaged
124
+ }
125
+
126
+ function Install-Cli([string]$Package) {
127
+ Write-InstallerInfo "正在安装 $Package。"
128
+ $arguments = @('install', '--global', '--prefix', $NpmPrefix)
129
+ if ($env:AITABLE_REGISTRY) { $arguments += @('--registry', $env:AITABLE_REGISTRY) }
130
+ $arguments += $Package
131
+ & $script:NpmCommand @arguments
132
+ if ($LASTEXITCODE -ne 0) { Stop-Installer "npm 安装 $Package 失败,退出码 $LASTEXITCODE。" }
133
+ }
134
+
135
+ function Main {
136
+ if ($env:OS -ne 'Windows_NT') { Stop-Installer '该脚本只支持原生 Windows;macOS/Linux 请运行 install.sh。' }
137
+ if ($PSVersionTable.PSVersion -lt [Version]'5.1') { Stop-Installer '需要 Windows PowerShell 5.1 或更高版本。' }
138
+ $architecture = $env:PROCESSOR_ARCHITECTURE
139
+ if ($env:PROCESSOR_ARCHITEW6432) { $architecture = $env:PROCESSOR_ARCHITEW6432 }
140
+ if ($architecture -ne 'AMD64') { Stop-Installer "不支持的 Windows 架构:$architecture。当前只支持原生 Windows x64。" }
141
+ if ($NodeMajor -notmatch '^[1-9][0-9]*$') { Stop-Installer 'AITABLE_NODE_MAJOR 必须是正整数。' }
142
+ if (-not $env:LOCALAPPDATA) { Stop-Installer 'Windows 环境缺少 LOCALAPPDATA。' }
143
+ New-Item -ItemType Directory -Path $NpmPrefix -Force | Out-Null
144
+ $env:Path = "$NpmPrefix;$env:Path"
145
+
146
+ if (Test-NodeReady) {
147
+ $version = (& $script:NodeCommand -p 'process.versions.node' | Select-Object -Last 1).ToString().Trim()
148
+ Write-InstallerInfo "复用 Node.js v$version。"
149
+ }
150
+ else {
151
+ $nvm = Get-CommandPath 'nvm.exe'
152
+ if ($nvm) { Install-WithNvm $nvm }
153
+ else { Write-InstallerInfo "未检测到可用 Node.js;将安装用户级 Node.js $NodeMajor.x。"; Install-NodeManaged }
154
+ }
155
+
156
+ Install-Cli 'dingtalk-workspace-cli@latest'
157
+ Install-Cli 'aitable-workflow-cli@latest'
158
+ Install-Cli '@qoder-ai/qodercli@latest'
159
+
160
+ $pathEntries = @($NpmPrefix)
161
+ if ($script:ManagedNodeDirectory) { $pathEntries += $script:ManagedNodeDirectory }
162
+ Add-UserPath $pathEntries
163
+ Write-InstallerInfo "安装完成:Node.js v$(& $script:NodeCommand -p 'process.versions.node'),npm v$(& $script:NpmCommand --version)。"
164
+ foreach ($name in @('dws.cmd', 'aitable-workflow.cmd', 'qodercli.cmd')) {
165
+ if (-not (Get-CommandPath $name)) { Stop-Installer "$name 安装后仍不可用;请检查 npm registry 和用户 PATH。" }
166
+ Write-InstallerInfo "✓ $name 已就绪。"
167
+ }
168
+ Write-InstallerInfo '下一步:在接入卡片复制对应执行引擎的 Daemon 接入命令。'
169
+ Write-InstallerInfo 'DWS 首次使用时需自行登录:dws auth login。'
170
+ }
171
+
172
+ try { Main }
173
+ catch { Write-Error "安装失败:$($_.Exception.Message)"; throw }
@@ -0,0 +1,188 @@
1
+ #!/bin/sh
2
+ # Public same-origin bootstrap for the relay machine setup card.
3
+
4
+ set -eu
5
+
6
+ MIN_NODE_VERSION="20.18.1"
7
+ NODE_MAJOR="${AITABLE_NODE_MAJOR:-22}"
8
+ NPM_PREFIX="${AITABLE_NPM_PREFIX:-$HOME/.local/share/aitable-workflow/npm}"
9
+ NODE_ROOT="${AITABLE_INSTALL_ROOT:-$HOME/.local/share/aitable-workflow}"
10
+ NODE_DIST_URLS="${AITABLE_NODE_DIST_URLS:-https://nodejs.org/dist https://npmmirror.com/mirrors/node}"
11
+ TMP_DIR=""
12
+ PERSIST_NODE_BIN="0"
13
+
14
+ say() { printf ' %s\n' "$*"; }
15
+ fail() { printf ' ERROR: %s\n' "$*" >&2; exit 1; }
16
+ has() { command -v "$1" >/dev/null 2>&1; }
17
+
18
+ cleanup() {
19
+ if [ -n "$TMP_DIR" ] && [ -d "$TMP_DIR" ]; then rm -rf "$TMP_DIR"; fi
20
+ }
21
+ trap cleanup EXIT HUP INT TERM
22
+
23
+ version_at_least() {
24
+ awk -v current="${1#v}" -v required="$MIN_NODE_VERSION" '
25
+ BEGIN {
26
+ split(current, c, /[.]/); split(required, r, /[.]/);
27
+ for (i = 1; i <= 3; i++) {
28
+ if ((c[i] + 0) > (r[i] + 0)) exit 0;
29
+ if ((c[i] + 0) < (r[i] + 0)) exit 1;
30
+ }
31
+ exit 0;
32
+ }
33
+ ' </dev/null
34
+ }
35
+
36
+ node_is_ready() {
37
+ has node && has npm || return 1
38
+ _version=$(node -p 'process.versions.node' 2>/dev/null || true)
39
+ [ -n "$_version" ] && version_at_least "$_version"
40
+ }
41
+
42
+ download() {
43
+ if has curl; then curl -fsSL --retry 2 --connect-timeout 10 "$1" -o "$2"
44
+ elif has wget; then wget -q -O "$2" "$1"
45
+ else fail "需要 curl 或 wget 下载 Node.js。"; fi
46
+ }
47
+
48
+ platform_triplet() {
49
+ case "$(uname -s)" in
50
+ Darwin) NODE_OS=darwin ;;
51
+ Linux) NODE_OS=linux ;;
52
+ *) fail "不支持的操作系统:$(uname -s)。请在 macOS、Linux 或 WSL 中运行。" ;;
53
+ esac
54
+ case "$(uname -m)" in
55
+ arm64|aarch64) NODE_ARCH=arm64 ;;
56
+ x86_64|amd64) NODE_ARCH=x64 ;;
57
+ *) fail "不支持的 CPU 架构:$(uname -m)。支持 arm64 与 x64。" ;;
58
+ esac
59
+ }
60
+
61
+ load_nvm() {
62
+ has nvm && return 0
63
+ for _candidate in "${NVM_DIR:-$HOME/.nvm}/nvm.sh" "${XDG_CONFIG_HOME:-$HOME/.config}/nvm/nvm.sh" /opt/homebrew/opt/nvm/nvm.sh /usr/local/opt/nvm/nvm.sh; do
64
+ [ -s "$_candidate" ] || continue
65
+ set +u
66
+ . "$_candidate" --no-use || true
67
+ set -u
68
+ has nvm && return 0
69
+ done
70
+ return 1
71
+ }
72
+
73
+ install_node_managed() {
74
+ platform_triplet
75
+ has tar || fail "安装 Node.js 需要 tar。"
76
+ TMP_DIR=$(mktemp -d)
77
+ _checksums="$TMP_DIR/SHASUMS256.txt"
78
+ _source=""
79
+ _archive=""
80
+ for _base in $NODE_DIST_URLS; do
81
+ _url="${_base%/}/latest-v${NODE_MAJOR}.x/SHASUMS256.txt"
82
+ say "正在查询 Node.js ${NODE_MAJOR}.x:${_base%/}"
83
+ if download "$_url" "$_checksums"; then
84
+ _archive=$(awk -v suffix="-${NODE_OS}-${NODE_ARCH}.tar.gz" '$2 ~ /^node-v[0-9]/ && index($2, suffix) == length($2) - length(suffix) + 1 { print $2; exit }' "$_checksums")
85
+ if [ -n "$_archive" ]; then _source="${_base%/}/latest-v${NODE_MAJOR}.x"; break; fi
86
+ fi
87
+ done
88
+ [ -n "$_archive" ] || fail "无法从 Node.js 官方源或镜像解析 Node.js ${NODE_MAJOR}.x。"
89
+ _expected=$(awk -v file="$_archive" '$2 == file { print $1; exit }' "$_checksums")
90
+ [ -n "$_expected" ] || fail "Node.js 校验清单缺少 $_archive。"
91
+ download "$_source/$_archive" "$TMP_DIR/$_archive" || fail "Node.js 下载失败。"
92
+ if has sha256sum; then _actual=$(sha256sum "$TMP_DIR/$_archive" | awk '{print $1}')
93
+ elif has shasum; then _actual=$(shasum -a 256 "$TMP_DIR/$_archive" | awk '{print $1}')
94
+ else fail "缺少 sha256sum 或 shasum,无法校验 Node.js 下载内容。"; fi
95
+ [ "$_actual" = "$_expected" ] || fail "Node.js SHA256 校验失败。"
96
+ tar -xzf "$TMP_DIR/$_archive" -C "$TMP_DIR"
97
+ _extract="${_archive%.tar.gz}"
98
+ _version="${_extract#node-v}"
99
+ _version="${_version%-${NODE_OS}-${NODE_ARCH}}"
100
+ _target="$NODE_ROOT/node-v$_version"
101
+ mkdir -p "$NODE_ROOT" "$NPM_PREFIX/bin"
102
+ if [ -e "$_target" ]; then
103
+ [ -x "$_target/bin/node" ] && [ -x "$_target/bin/npm" ] \
104
+ || fail "用户级 Node.js 路径已存在但不完整,未覆盖:$_target。请检查后自行修复。"
105
+ else
106
+ _staging="$_target.new.$$"
107
+ mv "$TMP_DIR/$_extract" "$_staging"
108
+ mv "$_staging" "$_target"
109
+ fi
110
+ NODE_BIN="$_target/bin"
111
+ PATH="$NODE_BIN:$PATH"
112
+ export PATH
113
+ PERSIST_NODE_BIN="1"
114
+ hash -r 2>/dev/null || true
115
+ node_is_ready || fail "Node.js 安装后版本仍低于 v${MIN_NODE_VERSION},或 npm 不可用。"
116
+ }
117
+
118
+ persist_path() {
119
+ case "$(basename "${SHELL:-sh}")" in
120
+ zsh) _config="$HOME/.zshrc" ;;
121
+ bash) if [ "$(uname -s)" = Darwin ]; then _config="$HOME/.bash_profile"; else _config="$HOME/.bashrc"; fi ;;
122
+ *) _config="$HOME/.profile" ;;
123
+ esac
124
+ _prefix_quoted=$(printf '%s' "$NPM_PREFIX/bin" | sed "s/'/'\\\\''/g")
125
+ _line="export PATH='$_prefix_quoted':\"\$PATH\""
126
+ if [ "$PERSIST_NODE_BIN" = "1" ]; then
127
+ _node_quoted=$(printf '%s' "$NODE_BIN" | sed "s/'/'\\\\''/g")
128
+ _line="export PATH='$_prefix_quoted':'$_node_quoted':\"\$PATH\""
129
+ fi
130
+ _has_prefix="0"
131
+ _has_node="1"
132
+ if [ -f "$_config" ] && grep -F "$NPM_PREFIX/bin" "$_config" >/dev/null 2>&1; then _has_prefix="1"; fi
133
+ if [ "$PERSIST_NODE_BIN" = "1" ] && { [ ! -f "$_config" ] || ! grep -F "$NODE_BIN" "$_config" >/dev/null 2>&1; }; then _has_node="0"; fi
134
+ if [ "$_has_prefix" != "1" ] || [ "$_has_node" != "1" ]; then
135
+ { printf '\n# Added by the AITable Workflow installer.\n'; printf '%s\n' "$_line"; } >>"$_config"
136
+ say "已将 CLI 与 Node.js 目录加入 $_config;新终端将自动加载。"
137
+ fi
138
+ }
139
+
140
+ install_cli() {
141
+ _package="$1"
142
+ say "正在安装 ${_package}。"
143
+ if [ -n "${AITABLE_REGISTRY:-}" ]; then
144
+ npm install --global --prefix "$NPM_PREFIX" --registry "$AITABLE_REGISTRY" "$_package"
145
+ else
146
+ npm install --global --prefix "$NPM_PREFIX" "$_package"
147
+ fi
148
+ }
149
+
150
+ main() {
151
+ case "$NODE_MAJOR" in *[!0-9]*|'') fail "AITABLE_NODE_MAJOR 必须是整数。" ;; esac
152
+ platform_triplet
153
+ mkdir -p "$NPM_PREFIX/bin"
154
+ PATH="$NPM_PREFIX/bin:$PATH"
155
+ export PATH
156
+ if node_is_ready; then
157
+ say "复用 Node.js v$(node -p 'process.versions.node')。"
158
+ NODE_BIN="$(dirname "$(command -v node)")"
159
+ elif load_nvm; then
160
+ say "检测到 nvm,切换到 Node.js ${NODE_MAJOR}.x。"
161
+ nvm install "$NODE_MAJOR"
162
+ nvm alias default "$NODE_MAJOR"
163
+ nvm use "$NODE_MAJOR"
164
+ NODE_BIN="$(dirname "$(command -v node)")"
165
+ node_is_ready || fail "nvm 提供的 Node.js 未达到 v${MIN_NODE_VERSION}。"
166
+ else
167
+ say "未检测到可用 Node.js;将安装用户级 Node.js ${NODE_MAJOR}.x。"
168
+ install_node_managed
169
+ fi
170
+
171
+ PATH="$NPM_PREFIX/bin:$NODE_BIN:$PATH"
172
+ export PATH
173
+ mkdir -p "$NPM_PREFIX"
174
+ install_cli 'dingtalk-workspace-cli@latest'
175
+ install_cli 'aitable-workflow-cli@latest'
176
+ install_cli '@qoder-ai/qodercli@latest'
177
+ persist_path
178
+
179
+ say "安装完成:Node.js v$(node -p 'process.versions.node'),npm v$(npm --version)。"
180
+ for _command in dws aitable-workflow qodercli; do
181
+ if command -v "$_command" >/dev/null 2>&1; then say "✓ $_command:$(command -v "$_command")"
182
+ else fail "$_command 安装后仍不可用;请检查 npm registry 和 PATH。"; fi
183
+ done
184
+ say "下一步:在接入卡片复制对应执行引擎的 Daemon 接入命令。"
185
+ say "DWS 首次使用时需自行登录:dws auth login。"
186
+ }
187
+
188
+ main "$@"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aitable-workflow-cli",
3
- "version": "0.1.28",
3
+ "version": "0.1.29-beta.1790736949347",
4
4
  "description": "aitable-workflow 命令行工具(cli):init/design/setup/run/serve 等命令;含 relay 本地反连客户端与 daemon 进程管理。bin: aitable-workflow。",
5
5
  "type": "module",
6
6
  "bin": {
@@ -19,8 +19,8 @@
19
19
  "access": "public"
20
20
  },
21
21
  "dependencies": {
22
- "aitable-workflow-core": "0.1.28",
23
- "aitable-workflow-server": "0.1.28",
22
+ "aitable-workflow-core": "0.1.29-beta.1790736949347",
23
+ "aitable-workflow-server": "0.1.29-beta.1790736949347",
24
24
  "@inquirer/prompts": "^8.5.2",
25
25
  "commander": "^14.0.2",
26
26
  "dotenv": "^17.4.2",
@@ -0,0 +1,11 @@
1
+ # 外部凭据在这里**只声明变量名与用途**,真实值写进 .env(不入库)。
2
+ #
3
+ # 空脚手架不预设任何凭据:设计阶段确定了用哪些外部能力之后,
4
+ # 把对应变量补进这里,并在 profile.yml 里用 ${env.XXX} 引用。
5
+ #
6
+ # 常见的几类(用到才加,不要照抄):
7
+ # AI 表格 / 消息收发 → 依赖 dws CLI 已登录,不需要变量
8
+ # 自定义机器人 webhook → DINGTALK_WEBHOOK / DINGTALK_WEBHOOK_SECRET
9
+ # LLM 直连 → 对应 provider 的 API Key
10
+ ## 钉钉企业机器人凭据 JSON map(AI表格开发小助手)
11
+ DINGTALK_ROBOTS=
@@ -0,0 +1,47 @@
1
+ # aitable-workflow 配置 —— 空脚手架
2
+ #
3
+ # 这份文件是**故意不完整**的:`workflows/` 目录为空,`scene` 还没填。
4
+ # 交付流程的「设计」一步会按用户的真实需求补齐这两处,并生成
5
+ # workflows/<id>/{workflow.yml,recipes/} 与 profile 的 roles/workflows 段。
6
+ #
7
+ # 在设计完成之前 `aitable-workflow setup` 会报 workflow-not-found,这是预期的。
8
+
9
+ # ─── 场景描述 ─────────────────────────────────────
10
+ # 设计阶段把澄清后的业务流程写在这里:谁触发、经过哪几个环节、每环节谁做什么、
11
+ # 什么算做完、业务差异放哪。写完之后它就是这个项目的需求事实源。
12
+ scene: |
13
+ AI Native SDLC 双数字员工协作台:intake 受理需求并由 PM 分诊,execution 在同一条变更记录中依次执行 PM 意图/PRD 与 Dev 技术方案/编码/评审。AI 表格保存状态、问答、审批与链接;Git changes/ 保存可版本化工件。完成工件后自动推送并创建 CR,人工评审和合并仍是硬门禁。
14
+
15
+ # ─── Base 文件名 ─────────────────────────────────
16
+ # setup 建 Base 时优先用该名(缺省回落实例目录名)。设计阶段按场景改成产品视角的名字。
17
+ base_name: "AI Native SDLC 双数字员工协作台"
18
+
19
+ # ─── 工作流目录(多工作流)────────────────────────
20
+ workflows:
21
+ dir: "./workflows"
22
+
23
+ # ─── Agent 引擎 ──────────────────────────────────
24
+ agent:
25
+ # engine 留空:首次运行 `aitable-workflow setup` 时检测本机 coding agent 并回填
26
+ engine: qoder
27
+ max_concurrent: 3
28
+ # 1 小时:PRD/评审等阶段 agent 要产出多份工件并自检,10min 会在收尾前被硬切导致假失败。
29
+ timeout_ms: 3600000
30
+ max_step_failures: 5
31
+ # 一轮 poll 只执行一个阶段;下一轮由 durable「当前步骤」继续,避免同轮串行跨过可见阶段。
32
+ auto_advance: false
33
+ trace_dir: "./traces"
34
+
35
+ # ─── Recipe 配置 ─────────────────────────────────
36
+ recipe:
37
+ default_timeout_ms: 300000
38
+
39
+ # ─── 轮询配置 ────────────────────────────────────
40
+ polling:
41
+ interval_ms: 5000
42
+
43
+ # ─── SLA 配置 ─────────────────────────────────────
44
+ sla:
45
+ enabled: false
46
+ default_timeout_ms: 86400000
47
+ escalation_notify: []
@@ -0,0 +1,17 @@
1
+ {
2
+ "version": 1,
3
+ "agents": {
4
+ "claudecode": {
5
+ "enabled": true,
6
+ "cmd": "claude"
7
+ },
8
+ "codex": {
9
+ "enabled": true,
10
+ "permissionMode": "bypassPermissions"
11
+ },
12
+ "qoder": {
13
+ "enabled": true,
14
+ "permissionMode": "bypassPermissions"
15
+ }
16
+ }
17
+ }
@@ -0,0 +1,150 @@
1
+ # AI Native SDLC 双数字员工协作台 Implementation Plan
2
+
3
+ ## 2026-09-16 增量审计与纠偏
4
+
5
+ 本项目已完成过一次 setup,因此只允许追加配置或调整 recipe;不得删除、改名或改类型已有 AI 表格字段,也不得改写已回填的 tracker Base/Table ID。修复以已发布的 `aitable-workflow-core` 能力为边界,不修改框架源码。
6
+
7
+ - [ ] 将「领域字典表」改为 `classify-domain` recipe 的 `tableRefConfigSchema` 受管表引用,并通过 `config set` 绑定已创建表。
8
+ - [ ] 为每个配置化 recipe 声明 Zod config;移除未声明、靠 YAML 锚点隐式传入的部署配置。
9
+ - [ ] 将跨 workflow 创建变更改为 `{ ref: "workflow:execution.tracker" }`,禁止手工拆分 Base/Table ID 字符串。
10
+ - [ ] 让 Dev 先在 PM 工件仓库产出并持久化选定仓库,随后只为选中的 Dev 仓库创建 worktree、提交与 CR;所有 `changes/` 工件只写 PM 仓库。
11
+ - [ ] 修复人工问答、PRD/CR 评审和阶段跃迁的恢复条件;使用已发布 `isMerged` 确认已合并事实,绝不把 ready-to-merge 当作已合并。
12
+ - [ ] 逐个重新部署并验证自动化;确认受理通知由领域判定的「待评估」写入真正触发。
13
+ - [ ] 使用 setup 检查、`validate` 和受控试运行复核。只有完整链路有证据后才启动常驻服务。
14
+
15
+ ### 审计发现的框架缺口(不得用 recipe 伪造)
16
+
17
+ 1. 公开的 `field_definitions` 只支持文本、选择、人员等类型,不支持关联字段或查找字段;现有「需求池」「变更流水」的「领域」已经是文本列,原地改为关联列属于远端数据迁移。
18
+ 2. 原先 `toolkit.codeReview` 缺少已合并事实;项目现在升级为 `aitable-workflow-core@0.1.28-beta.1789525693558`,使用其只读 `isMerged` 作为阶段跃迁事实,绝不由 Agent 执行合并。
19
+ 3. `tableRefConfigSchema` 可以由 setup 创建「领域字典表」字段,但当前 setup schema 没有种子记录声明;已部署 Base 的七条领域记录需要保留,新的 Base 若要求“一次 setup 自动预填”需要框架级种子能力。
20
+
21
+ **Goal:** Generate, configure and verify a single-instance two-workflow AI Native SDLC project with PM/Dev handoff, Git artifacts, CR gates, blocked Q&A and session resume.
22
+
23
+ **Architecture:** `intake` owns 「需求池」 and creates records in `execution`'s distinct 「变更流水」 tracker. PM and Dev steps execute serially against one execution record; all mutable per-stage state is namespaced in fields and all durable artifacts live in the PM repository `changes/` directory.
24
+
25
+ **Tech Stack:** aitable-workflow profile v2, TypeScript ESM recipes, toolkit.coding/git/codeReview/table/messaging, DWS workflow-dsl/v1 automations, GitLab CR.
26
+
27
+ **Spec:** `docs/plans/2026-09-15-ai-native-sdlc-dual-staff.md`
28
+
29
+ ## Global constraints
30
+
31
+ - Depend on the framework session-resume CR before enabling a real resumed Agent call.
32
+ - Do not use toolkit.ai, extra tracker tables, or a design step. Steps stay `auto: true`; recipes use `needs_human` only for active CR polling, never as an approval-state substitute.
33
+ - Keep all user-visible names, enum values, notification copy and buttons exactly as specified.
34
+ - Use table fields only for durable workflow data; never depend on `$var` across retries or blocked recovery.
35
+ - 所有需要评审的阶段在完成本地 commit 后自动 push 并创建 CR;人工评审与合并仍为硬门禁。
36
+ - `blocked` 只用于 AI 问答,必须从 execution 候选轮询移除;CR 等待保持 `active` 并由当前 recipe 持续轮询。
37
+
38
+ ### Task 0: Repair execution recovery and CR lifecycle
39
+
40
+ **Files:**
41
+ - Modify: `package.json`, `package-lock.json`
42
+ - Modify: `workflows/execution/workflow.yml`
43
+ - Modify: `lib/recipe-helpers.ts`
44
+ - Modify: `workflows/execution/recipes/prd.recipe.ts`
45
+ - Modify: `workflows/execution/recipes/review.recipe.ts`
46
+ - Modify: `workflows/execution/automations/*.json`
47
+ - Test: `test/recipe-helpers.test.ts`
48
+
49
+ - [x] Upgrade to `aitable-workflow-core@0.1.28-beta.1789525693558` and prove the published `codeReview.isMerged` type is available.
50
+ - [x] Restrict execution tracker candidates to `active`; blocked AI questions are resumed only by an answer-update automation that writes `状态=active`.
51
+ - [x] Add an idempotent external-progress helper: it preserves `active`, writes changed human-readable wait fields once, and returns `needs_human` so CR checks retain the durable step pointer without creating a blocked-loop notification storm.
52
+ - [x] Replace PRD and review's readiness-only terminal branches with `isMerged`; PRD advances to plan only after its CR merges, and review advances to shipped only after every code CR merges plus 「待人处理=无」.
53
+ - [x] Keep 「属主」as PM/Dev through CR comment repair and wait cycles so existing domain-role question notifications route to a real responsible role; only `shipped` writes 「属主=人」.
54
+ - [x] Add and deploy 「人工答复续跑」 automation; it must not write 「当前阶段」「属主」or「阶段跃迁审计」.
55
+ - [x] Add regression tests for idempotent external-progress waiting and the execution tracker candidate-state contract.
56
+
57
+ ### Task 1: Create the project from the prescribed skeleton
58
+
59
+ **Files:**
60
+ - Create: `aitable-workflow.config.yml`, `package.json`, `.env.example`, `.gitignore`, `coding-agents.config.json`
61
+ - Create: `profile/profile.yml`, `profile/prompts/pm.md`, `profile/prompts/dev.md`
62
+ - Create: `workspaces/pm/AGENTS.md`, `workspaces/dev/AGENTS.md`
63
+
64
+ - [ ] Copy the design skill `assets/project` contents into `/Users/xule/work/code/agent-tests/ai-native-sdlc-dual-staff` without a nested `project/` directory.
65
+ - [ ] Set scene, business base name, conservative polling and profile v2 configuration.
66
+ - [ ] Declare PM repository, Dev repository allowlist, robot credentials and agent engine as deployment configuration, never Role fields.
67
+ - [ ] Declare every required environment value in `.env.example` without a real secret.
68
+ - [ ] Install project dependencies with `npm install`.
69
+
70
+ ### Task 2: Declare trackers, roles and views
71
+
72
+ **Files:**
73
+ - Create: `workflows/intake/workflow.yml`
74
+ - Create: `workflows/execution/workflow.yml`
75
+ - Modify: `profile/profile.yml`
76
+
77
+ - [ ] Define the exact 「需求池」, 「变更流水」 and 「领域字典表」 field contracts, including 「AI问题」, 「人工答复」, 「Agent会话ID」 and 「当前CR链接」.
78
+ - [ ] Define separate tracker IDs with the same deferred Base ID; reference the execution tracker using `{ ref: "workflow:execution.tracker" }`.
79
+ - [ ] Define the execution edges `intent → prd → prd-review → plan → build → review → shipped`; leave 「设计稿」 as an unused table option.
80
+ - [ ] Define PM and Dev roles with only allowed identity fields, and role workspaces with durable artifact/output instructions.
81
+ - [ ] Add stable views for pending intake, blocked changes and change history.
82
+
83
+ ### Task 3: Implement intake handler and PM recipes
84
+
85
+ **Files:**
86
+ - Create: `workflows/intake/recipes/intake_handler.recipe.ts`
87
+ - Create: `workflows/intake/recipes/mechanical-deduplicate.recipe.ts`
88
+ - Create: `workflows/intake/recipes/classify_domain.recipe.ts`
89
+ - Create: `workflows/intake/recipes/create_change.recipe.ts`
90
+ - Create: `workflows/execution/recipes/intent.recipe.ts`
91
+ - Create: `workflows/execution/recipes/prd.recipe.ts`
92
+ - Create: `workflows/**/__tests__/*.test.ts`
93
+
94
+ - [ ] Persist source composite-key deduplication outside ephemeral variables and return no duplicate change action.
95
+ - [ ] Use PM Coding Agent prompts to compare intake rows and select a domain from the read-only dictionary.
96
+ - [ ] Create execution records only after 「需求状态=已接受」, with initial execution state and a deterministic CHG ID.
97
+ - [ ] In intent/PRD recipes, ensure PM worktree, create Git artifacts, commit locally, write durable artifact/CR/session data, and block on unanswered questions or CR facts.
98
+ - [ ] Before every blocked return, use `table.updateCurrentRow()` to persist the blocking fields, then return `blocked`.
99
+
100
+ ### Task 4: Implement Dev recipes and cross-repository CR gates
101
+
102
+ **Files:**
103
+ - Create: `workflows/execution/recipes/plan.recipe.ts`
104
+ - Create: `workflows/execution/recipes/build.recipe.ts`
105
+ - Create: `workflows/execution/recipes/review.recipe.ts`
106
+ - Create: `workflows/execution/recipes/shipped.recipe.ts`
107
+ - Create: `workflows/execution/recipes/shared/*.ts`
108
+ - Create: `workflows/execution/__tests__/*.test.ts`
109
+
110
+ - [ ] Resolve only configured Dev repositories; unknown repositories persist a blocked condition and do no Git operation.
111
+ - [ ] Use deterministic worktrees, stage-keyed session map entries and real coding-agent execution for plan/build.
112
+ - [ ] Record actual test command output, CI state, commit and CR information in `05-build.md`, `06-review.md` and append-only 「产出物」.
113
+ - [ ] Poll unresolved comments, readiness and branch-merged facts; re-run the resumed Agent session after relevant human answers/comments.
114
+ - [ ] Require every Dev CR merged to master and the human release confirmation before recipe sets `状态=shipped` and `当前阶段=已发布`.
115
+
116
+ ### Task 5: Generate and validate the three required automations
117
+
118
+ **Files:**
119
+ - Create: `workflows/intake/automations/accept-intake.json`
120
+ - Create: `workflows/execution/automations/merge-gate.json`
121
+ - Create: `workflows/execution/automations/blocked-questions.json`
122
+ - Create: `workflows/execution/automations/cr-review.json`
123
+
124
+ - [ ] Retrieve and save the current DWS workflow `edit-example` in `.sandbox/` before authoring DSL.
125
+ - [ ] Implement the exact required intake and merge-gate copy/buttons.
126
+ - [ ] Implement notification-only blocked-question and CR-review automations using 「AI问题」 and 「当前CR链接」.
127
+ - [ ] Confirm no automation writes 「当前阶段」「属主」 or 「阶段跃迁审计」.
128
+ - [ ] Validate/deploy every automation to the target Base and retain only responses with `valid: true`.
129
+
130
+ ### Task 6: Setup and verification
131
+
132
+ **Files:**
133
+ - Create: `__tests__/workflow-contract.test.ts`
134
+ - Create: `.sandbox/smoke/intake.event.json`
135
+ - Create: `.sandbox/smoke/execution.event.json`
136
+
137
+ - [ ] Add tests for stage transition idempotency, blocked field persistence, session map isolation, composite intake deduplication and Dev allowlist enforcement.
138
+ - [ ] Run `aitable-workflow validate -c /Users/xule/work/code/agent-tests/ai-native-sdlc-dual-staff`.
139
+ - [ ] Run setup to create the Base, all tables, field options, domain seed rows, robot and automations; record generated IDs only in deployment configuration.
140
+ - [ ] Run controlled `trigger-once` for intake and execution and inspect actions plus table writes.
141
+ - [ ] Enable the remote CR acceptance switch only for an identified test record; verify a PM PRD CR and one Dev CR with real test/CI evidence.
142
+
143
+ ### Task 7: Start and hand off
144
+
145
+ **Files:**
146
+ - Verify: `.aitable-workflow/console-access.json`
147
+
148
+ - [ ] Start the service through `aitable-workflow start` only after setup and smoke evidence are available.
149
+ - [ ] Verify blocked question notification, answer consumption, resumed sessionId forwarding, CR review notification and phase transition on a controlled record.
150
+ - [ ] Report the Base, table IDs, automation validation evidence, console URL and every remaining external authorization requirement.