Skip to content

Commit b9ee224

Browse files
committed
docs(workflow): finish the tools wording left over from #1535 (#1548)
A node Bot runs with a normal Bot's full access and its tools field only names connectors, so Settings no longer says each Bot follows its own permission, the delivery template lists only github on the Coder and nothing on the Tester, and the README says naming bash grants nothing. Docs-not-needed: docs/subsystems/workflow.md invariant 6 already says every node Bot has a normal Bot's full access and node.tools names connectors only (#1535). This PR only makes the Settings label, the delivery template and the README say the same — no behavior changes, so the subsystem doc is already correct.
1 parent a221306 commit b9ee224

8 files changed

Lines changed: 45 additions & 11 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Workflow Settings says the run's full access is a normal Bot's instead of a per-Bot permission choice, and the delivery template lists only connectors a node really calls (`github`). The README says plainly that naming `bash` grants nothing.

‎core/test/workflow-node-connectors.test.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,9 @@ test('the built-in delivery nodes make github available exactly where the node n
132132
assert.match(guardFor(bot.id, COMPOSIO[0]), /not granted to this run/, `${nodeId} may not call composio`)
133133
}
134134

135-
// The tester names bash only, and planner/writer name nothing: no connector for either.
135+
// The tester, planner and writer name nothing, so none of them reaches a connector.
136136
const tester = byNode.get('tester')
137-
assert.deepEqual(tester.stepTools, ['bash'])
137+
assert.equal(tester.stepTools, undefined, 'the tester names no connector')
138138
assert.match(guardFor(tester.id, GITHUB[0]), /not granted to this run/)
139139
for (const nodeId of ['planner', 'writer']) {
140140
const bot = byNode.get(nodeId)

‎patches/ds-bot/files/test/workflow-node-connectors.test.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,9 +132,9 @@ test('the built-in delivery nodes make github available exactly where the node n
132132
assert.match(guardFor(bot.id, COMPOSIO[0]), /not granted to this run/, `${nodeId} may not call composio`)
133133
}
134134

135-
// The tester names bash only, and planner/writer name nothing: no connector for either.
135+
// The tester, planner and writer name nothing, so none of them reaches a connector.
136136
const tester = byNode.get('tester')
137-
assert.deepEqual(tester.stepTools, ['bash'])
137+
assert.equal(tester.stepTools, undefined, 'the tester names no connector')
138138
assert.match(guardFor(tester.id, GITHUB[0]), /not granted to this run/)
139139
for (const nodeId of ['planner', 'writer']) {
140140
const bot = byNode.get(nodeId)

‎plugins/workflow/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ A required input must be an output of the same name on an ancestor. A root node
3434

3535
On a live run, a successor stays queued until its required inputs are present. If every predecessor is already done or failed and an input is still missing, that node fails and the run stops. The dispatch text includes `Input <name>: <value>`. The Bot reports outputs as `OUTPUT <name>: <value>`. A node with one declared output may put that value in the reply body.
3636

37-
The delivery template passes `task` → `plan` → `copy` → `patch`, then `review` and `report` into `release`. Coder and Tester name `bash`; Coder, Reviewer and Deployer name `github`. The weekly template passes `task` → `notes` → `metrics` → `report`.
37+
The delivery template passes `task` → `plan` → `copy` → `patch`, then `review` and `report` into `release`. Coder, Reviewer and Deployer name `github`; the Tester names none, because `bash` is not a connector and grants nothing here (#1535). The weekly template passes `task` → `notes` → `metrics` → `report`.
3838

3939
## Branches and loops
4040

‎plugins/workflow/client.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ window.__ModuleLoader__.load({
6363
'Each Bot\'s own model': '跟随各个 Bot 的模型',
6464
'{count} models': '{count} 个模型',
6565
Permissions: '权限',
66-
'Each Bot\'s own permission': '跟随各个 Bot 的权限',
66+
'Full access, same as a normal Bot': '完全访问,与普通 Bot 相同',
6767
'On failure': '失败策略',
6868
'Tester retries once. Any other failed step stops the run.': 'Tester 失败后自动重试 1 次。其他节点失败则停住。',
6969
'A failed step stops the run.': '失败的节点停住,等你处理。',
@@ -770,7 +770,7 @@ window.__ModuleLoader__.load({
770770
return h('div', { className: 'wf-box' },
771771
h('div', { className: 'wf-kv' }, h('span', null, tr('Trigger')), h('span', null, trigger)),
772772
h('div', { className: 'wf-kv' }, h('span', null, tr('Model')), h('span', null, modelLabel)),
773-
h('div', { className: 'wf-kv' }, h('span', null, tr('Permissions')), h('span', null, tr('Each Bot\'s own permission'))),
773+
h('div', { className: 'wf-kv' }, h('span', null, tr('Permissions')), h('span', null, tr('Full access, same as a normal Bot'))),
774774
h('div', { className: 'wf-kv' }, h('span', null, tr('On failure')), h('span', null, tr(retries ? 'Tester retries once. Any other failed step stops the run.' : 'A failed step stops the run.'))),
775775
h('div', { className: 'wf-kv' }, h('span', null, tr('Concurrent runs')), h('span', null, String(workflow.maxConcurrent ?? 2))),
776776
h('div', { className: 'wf-kv' }, h('span', null, tr('Members')), h('span', null, workflow.chain)))

‎plugins/workflow/src/template.js‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const writer = {
3030
const coder = {
3131
id: 'coder', name: 'Coder', role: '代码实现',
3232
instructions: '根据 Planner 的子任务和 Writer 的文案修改代码,提交 PR,并在 PR 描述中列出变更。',
33-
tools: ['github', 'bash', 'read', 'edit'],
33+
tools: ['github'],
3434
inputs: [{ name: 'copy', type: 'text', required: true }],
3535
outputs: [{ name: 'patch', type: 'text' }],
3636
}
@@ -44,7 +44,6 @@ const reviewer = {
4444
const tester = {
4545
id: 'tester', name: 'Tester', role: '自动化测试', failOnce: true,
4646
instructions: '运行单元、快照和 E2E。失败时自动重试 1 次,仍失败则停在本节点。',
47-
tools: ['bash'],
4847
inputs: [{ name: 'patch', type: 'text', required: true }],
4948
outputs: [{ name: 'report', type: 'text' }],
5049
}

‎plugins/workflow/test/client.test.js‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1383,3 +1383,37 @@ test('the settings page injects the workflow stylesheet without the sidebar sect
13831383
globalThis.document = prev
13841384
}
13851385
})
1386+
1387+
test('the drawer details name the permission every node Bot actually runs with', async () => {
1388+
// #1535 made every node Bot danger-full-access, so a row claiming each Bot follows
1389+
// its own permission was stale (#1548): the details must say the run's full access
1390+
// is the same as a normal Bot's, and must not claim a per-Bot choice.
1391+
const graph = delivery()
1392+
const call = async (name) => {
1393+
if (name === 'workflow/state') return { workflows: [graph], templates: [{ id: 'delivery', name: '发布交付流水线' }] }
1394+
if (name === 'workflow/messages') return { messages: graph.messages }
1395+
return { ok: true, workflows: [graph] }
1396+
}
1397+
const view = mount(client.Section, { roster: { bots: [] }, call, actions: {} })
1398+
await settle()
1399+
findAll(view.tree, node => node.type === 'button' && textOf(node).includes('发布交付流水线'))[0].props.onClick()
1400+
findAll(view.tree, node => node.type === 'button' && textOf(node) === 'Flow')[0].props.onClick()
1401+
await settle()
1402+
findAll(view.tree, node => node.type === 'button' && textOf(node) === 'Details')[0].props.onClick()
1403+
await settle()
1404+
const rows = findAll(view.tree, node => node.props?.className === 'wf-kv')
1405+
const permission = rows.find(row => textOf(row.children?.[0] ?? '') === client.tr('Permissions'))
1406+
assert.ok(permission, 'the details list a Permissions row')
1407+
const value = textOf(permission.children[1])
1408+
assert.doesNotMatch(value, /own permission/i, 'a node Bot does not pick its own permission')
1409+
assert.match(value, /full access/i, 'the row names the full access a node Bot runs with')
1410+
assert.match(value, /same as a normal Bot/i, 'and says it is a normal Bot\'s full access')
1411+
const prev = globalThis.__flybot__
1412+
globalThis.__flybot__ = { t: key => (key === 'Tasks' ? '任务' : key) }
1413+
try {
1414+
assert.equal(client.tr('Full access, same as a normal Bot'), '完全访问,与普通 Bot 相同', 'the row is translated')
1415+
} finally {
1416+
globalThis.__flybot__ = prev
1417+
}
1418+
view.unmount()
1419+
})

‎plugins/workflow/test/ephemeral.test.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -756,10 +756,10 @@ test('the built-in delivery nodes hand their connector list to the host', async
756756
assert.notEqual(state?.ok, false, `${nodeId} advanced: ${state?.error ?? ''}`)
757757
}
758758
const byNode = new Map(created.map(spec => [spec.fields.nodeId, spec]))
759-
assert.deepEqual(byNode.get('coder').tools, ['github', 'bash', 'read', 'edit'], 'Coder names github')
759+
assert.deepEqual(byNode.get('coder').tools, ['github'], 'Coder names github')
760760
assert.deepEqual(byNode.get('reviewer').tools, ['github'], 'Reviewer names github')
761761
assert.deepEqual(byNode.get('deployer').tools, ['github'], 'Deployer names github')
762-
assert.deepEqual(byNode.get('tester').tools, ['bash'], 'Tester names no connector')
762+
assert.deepEqual(byNode.get('tester').tools, [], 'Tester names no connector')
763763
assert.deepEqual(byNode.get('planner').tools, [], 'Planner names no connector')
764764
for (const spec of created) assert.equal(spec.permission, 'danger-full-access', 'file and shell rights are a normal Bot\'s')
765765
})

0 commit comments

Comments
 (0)