dsh-tower 2.6.0 → 2.7.0
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.
- package/CHANGELOG.md +82 -0
- package/COMPATIBILITY.md +1 -0
- package/CONTRIBUTING.md +1 -1
- package/README.en.md +2 -1
- package/README.md +6 -1
- package/adapters/leases.js +20 -6
- package/adapters/legacy.js +149 -37
- package/adapters/stateFile.js +11 -1
- package/app/archive.js +30 -5
- package/app/briefing.js +95 -12
- package/app/checkCompletion.js +107 -18
- package/app/enrichedMissions.js +1 -1
- package/app/freshness.js +77 -0
- package/app/gate.js +26 -12
- package/app/merge.js +7 -4
- package/app/mission.js +24 -1
- package/app/missionContext.js +2 -1
- package/app/plan.js +64 -1
- package/app/provision.js +133 -22
- package/app/read.js +38 -5
- package/app/rebase.js +10 -8
- package/app/review.js +97 -61
- package/app/reviewCheckout.js +133 -0
- package/app/sandbox.js +121 -0
- package/app/sharedCheckout.js +90 -0
- package/app/spawn-prechecks.js +25 -24
- package/app/spawn-support.js +59 -8
- package/app/spawn.js +3 -0
- package/app/teardown.js +119 -2
- package/app/tower.js +29 -1
- package/cordis.patch.yml +50 -0
- package/docs/adr/0006-mission-shapes.md +306 -0
- package/docs/architecture/overview.md +6 -4
- package/docs/guide/install-upgrade-migration.md +26 -0
- package/docs/operations/runbook.md +1 -1
- package/docs/reference/blockers.md +8 -4
- package/docs/reference/component-surface.md +7 -2
- package/docs/reference/config.generated.md +6 -4
- package/docs/reference/config.md +1 -2
- package/docs/reference/doctor.md +7 -7
- package/docs/reference/operations.md +1 -1
- package/docs/reference/shapes.md +123 -0
- package/docs/reference/surface-budget.md +33 -1
- package/docs/reference/testing.md +4 -2
- package/docs/reference/tools.generated.md +5 -5
- package/docs/reference/tools.md +2 -2
- package/docs/zh/reference/blockers.md +2 -2
- package/docs/zh/reference/config.md +1 -2
- package/docs/zh/reference/testing.md +3 -2
- package/domain/batch.js +75 -105
- package/domain/collab/batch.js +30 -10
- package/domain/collab/spawn.js +53 -16
- package/domain/config/schema.js +47 -17
- package/domain/contracts/outputs.js +0 -1
- package/domain/contracts/tool-inputs/missions.js +9 -1
- package/domain/evidence.js +283 -0
- package/domain/gate.js +11 -31
- package/domain/integration/gate.js +17 -43
- package/domain/integration/init.js +3 -2
- package/domain/integration/provision.js +51 -0
- package/domain/integration/rebase.js +16 -1
- package/domain/mission.js +16 -33
- package/domain/missions/completion.js +46 -8
- package/domain/missions/findings.js +2 -1
- package/domain/missions/lifecycle.js +131 -35
- package/domain/missions/plan.js +30 -6
- package/domain/missions/review.js +2 -18
- package/domain/planning.js +5 -5
- package/domain/read/missionContext.js +17 -3
- package/domain/read/views.js +5 -1
- package/domain/roles.js +222 -0
- package/domain/roster.js +9 -3
- package/domain/scope.js +51 -0
- package/domain/shapes/build.js +254 -0
- package/domain/shapes/index.js +171 -0
- package/domain/shapes/survey.js +445 -0
- package/domain/state/archive.js +28 -4
- package/domain/state/migrations.js +111 -4
- package/domain/state/schema.js +69 -7
- package/domain/state/semantics.js +93 -13
- package/domain/state.js +5 -1
- package/domain/summary.js +5 -11
- package/domain/vocabulary.js +15 -33
- package/host/capability-registry.js +25 -9
- package/host/doctor.js +2 -1
- package/host/preset-survey-sandbox.js +19 -0
- package/host/preset-survey.js +18 -0
- package/host/presets.js +8 -3
- package/host/tool-registry.js +14 -12
- package/locale/en.json +16 -1
- package/locale/preset-survey/en.json +6 -0
- package/locale/preset-survey/zh.json +6 -0
- package/locale/preset-survey-sandbox/en.json +6 -0
- package/locale/preset-survey-sandbox/zh.json +6 -0
- package/locale/zh.json +16 -1
- package/package.json +13 -2
- package/ports/state.js +8 -1
- package/scripts/architecture-waivers.json +3 -3
- package/scripts/check-docs.mjs +1 -1
- package/scripts/check-pack.mjs +2 -0
- package/scripts/component-surface.json +68 -20
- package/scripts/generate-capability-locale.mjs +5 -0
- package/scripts/generate-shapes-reference.mjs +171 -0
- package/scripts/mount-smoke/surface.mjs +3 -0
- package/scripts/pack-manifest.txt +21 -0
- package/scripts/shape-audit.mjs +361 -0
- package/scripts/surface-baseline.json +68 -4
- package/survey-sandbox.js +48 -0
- package/survey.js +40 -0
- package/tools/complete.js +5 -5
- package/tools/diff.js +5 -3
- package/tools/plan.js +1 -1
- package/tools/preflight.js +3 -2
- package/tools/spawn.js +47 -49
- package/tools/test.js +2 -1
- package/types/index.d.ts +66 -5
package/app/spawn-support.js
CHANGED
|
@@ -1,7 +1,55 @@
|
|
|
1
1
|
// tower_spawn support (#56 P3c): briefing assembly, agent options, and the
|
|
2
2
|
// wait/result settling path. Split out of tools/spawn.js; no I/O of its own.
|
|
3
|
+
import { shapeFor } from '../domain/shapes/index.js'
|
|
4
|
+
import { roleBriefingKind, rolePlacement } from '../domain/roles.js'
|
|
3
5
|
import { workerBriefing, reviewerBriefing } from './briefing.js'
|
|
4
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Resolve where a spawn runs (#149 W3). A worker gets the shape's provisioning
|
|
9
|
+
* (branch worktree, shared checkout, or detached survey sandbox); a reviewer
|
|
10
|
+
* gets a disposable detached checkout at the recorded branch tip, so the
|
|
11
|
+
* verdict is stamped with a commit instead of a live worktree HEAD.
|
|
12
|
+
* @param {any} tower
|
|
13
|
+
* @param {{ role: string, context: any, missionId: string, name: string, worktreeRoot?: string, includeDirtyBase?: boolean, instructions?: string }} input
|
|
14
|
+
*/
|
|
15
|
+
export async function provisionSpawnPlacement(tower, { role, context, missionId, name, worktreeRoot, includeDirtyBase, instructions }) {
|
|
16
|
+
// #149 W4: the role contract decides the placement; the shape supplies the
|
|
17
|
+
// mission provisioning facts it does not own.
|
|
18
|
+
const reviewCheckout = rolePlacement(role) === 'review-checkout'
|
|
19
|
+
const shape = shapeFor(context.mission.kind)
|
|
20
|
+
const provisioned = reviewCheckout
|
|
21
|
+
? null
|
|
22
|
+
: await tower.provision({ missionId, worktreeRoot, includeDirtyBase: includeDirtyBase !== false })
|
|
23
|
+
const review = reviewCheckout
|
|
24
|
+
? await tower.provisionReviewCheckout({ missionId, name, worktreeRoot })
|
|
25
|
+
: null
|
|
26
|
+
const mission = review ? review.mission : provisioned.mission
|
|
27
|
+
const worktree = review ? mission.worktree : provisioned.worktree
|
|
28
|
+
const cwd = review ? review.path : (provisioned.cwd ?? worktree.path)
|
|
29
|
+
const branch = worktree?.branch ?? null
|
|
30
|
+
// The briefing must describe the checkout that actually exists: a detached
|
|
31
|
+
// sandbox is recorded only after provision, so use the provisioned mission.
|
|
32
|
+
const briefing = buildSpawnBriefing({
|
|
33
|
+
role,
|
|
34
|
+
towerRoot: tower.root,
|
|
35
|
+
context: /** @type {any} */ ({ ...context, mission }),
|
|
36
|
+
worktree,
|
|
37
|
+
review,
|
|
38
|
+
instructions,
|
|
39
|
+
})
|
|
40
|
+
return {
|
|
41
|
+
mission,
|
|
42
|
+
worktree,
|
|
43
|
+
cwd,
|
|
44
|
+
branch,
|
|
45
|
+
review,
|
|
46
|
+
briefing,
|
|
47
|
+
provisioning: review ? 'review-checkout' : (provisioned.provisioning ?? shape.provisioning),
|
|
48
|
+
created: review ? true : provisioned.created,
|
|
49
|
+
sandbox: provisioned?.sandbox ?? null,
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
5
53
|
/**
|
|
6
54
|
* @param {any} model
|
|
7
55
|
*/
|
|
@@ -14,25 +62,28 @@ export function buildAgentOptions(model) {
|
|
|
14
62
|
}
|
|
15
63
|
|
|
16
64
|
/**
|
|
17
|
-
* @param {{ role: string, towerRoot: string, context: any, worktree: any, instructions: string | undefined }} input
|
|
65
|
+
* @param {{ role: string, towerRoot: string, context: any, worktree: any, review?: any, instructions: string | undefined }} input
|
|
18
66
|
*/
|
|
19
|
-
export function buildSpawnBriefing({ role, towerRoot, context, worktree, instructions }) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
67
|
+
export function buildSpawnBriefing({ role, towerRoot, context, worktree, review = null, instructions }) {
|
|
68
|
+
// Only a shape that owns a worktree gets the git checkout projection; a survey
|
|
69
|
+
// reads the shared checkout and must not see a worktree record it does not own.
|
|
70
|
+
const shape = shapeFor(context.mission.kind)
|
|
71
|
+
const mission = shape.fields.worktree
|
|
72
|
+
? { ...context.mission, worktree: { path: worktree.path, branch: worktree.branch, baseCommit: worktree.baseCommit } }
|
|
73
|
+
: { ...context.mission }
|
|
24
74
|
const briefing = {
|
|
25
75
|
repoRoot: towerRoot,
|
|
26
76
|
base: context.base,
|
|
27
77
|
mission,
|
|
28
78
|
deps: context.deps,
|
|
29
|
-
worktree,
|
|
79
|
+
worktree: worktree ?? null,
|
|
80
|
+
review,
|
|
30
81
|
instructions,
|
|
31
82
|
reviews: context.reviews,
|
|
32
83
|
findings: context.findings,
|
|
33
84
|
completionReport: context.completionReport,
|
|
34
85
|
}
|
|
35
|
-
return role === '
|
|
86
|
+
return roleBriefingKind(role) === 'reviewer' ? reviewerBriefing(briefing) : workerBriefing(briefing)
|
|
36
87
|
}
|
|
37
88
|
|
|
38
89
|
/**
|
package/app/spawn.js
CHANGED
|
@@ -96,6 +96,9 @@ export async function recordSpawn(tower, input) {
|
|
|
96
96
|
const now = Date.now()
|
|
97
97
|
const entry = recordSpawnEntry({
|
|
98
98
|
roster: state.roster,
|
|
99
|
+
// The live-worker count resolves each roster row's kind, so the whole
|
|
100
|
+
// mission list is required: a survey row is not a build worker (#148).
|
|
101
|
+
missions: state.missions,
|
|
99
102
|
mission,
|
|
100
103
|
input,
|
|
101
104
|
spawnTip,
|
package/app/teardown.js
CHANGED
|
@@ -21,6 +21,106 @@ import {
|
|
|
21
21
|
teardownRemovedDecision,
|
|
22
22
|
} from '../domain/integration/teardown.js'
|
|
23
23
|
import { sweepArchive } from './archive.js'
|
|
24
|
+
import { cleanupSandbox } from './sandbox.js'
|
|
25
|
+
import { cleanupReviewCheckout } from './reviewCheckout.js'
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Disposable review checkouts (#149 W3). A reviewer works in a detached checkout
|
|
29
|
+
* at its recorded review commit and the checkout is removed when the verdict is
|
|
30
|
+
* recorded; a failed spawn or an interrupted reviewer leaves it behind, so
|
|
31
|
+
* teardown retries the bounded removal and clears the recorded path. A checkout
|
|
32
|
+
* whose reviewer is still active is kept. This runs before the worktree phase so
|
|
33
|
+
* its state revisions never invalidate the worktree claims.
|
|
34
|
+
* @param {any} tower
|
|
35
|
+
* @param {any} input
|
|
36
|
+
* @returns {Promise<{ decisions: any[], removed: string[] }>}
|
|
37
|
+
*/
|
|
38
|
+
async function teardownReviewCheckouts(tower, input) {
|
|
39
|
+
const state = await tower.load()
|
|
40
|
+
const exclude = new Set(input.exclude ?? [])
|
|
41
|
+
const decisions = []
|
|
42
|
+
const removed = []
|
|
43
|
+
for (const entry of state.roster ?? []) {
|
|
44
|
+
const checkout = typeof entry.reviewCheckout === 'string' ? entry.reviewCheckout : null
|
|
45
|
+
if (!checkout) continue
|
|
46
|
+
const row = { name: entry.name, missionId: entry.missionId ?? null, checkout }
|
|
47
|
+
if (exclude.has(entry.missionId)) {
|
|
48
|
+
decisions.push({ ...row, action: 'keep', reason: 'excluded' })
|
|
49
|
+
continue
|
|
50
|
+
}
|
|
51
|
+
if (entry.state === 'active') {
|
|
52
|
+
decisions.push({ ...row, action: 'keep', reason: 'reviewer is active' })
|
|
53
|
+
continue
|
|
54
|
+
}
|
|
55
|
+
if (input.dryRun === true) {
|
|
56
|
+
decisions.push({ ...row, action: 'remove', reason: 'eligible' })
|
|
57
|
+
continue
|
|
58
|
+
}
|
|
59
|
+
const outcome = await cleanupReviewCheckout(tower, { name: entry.name, missionId: entry.missionId })
|
|
60
|
+
if (!outcome || outcome.removal.ok) {
|
|
61
|
+
decisions.push({ ...row, action: 'removed', reason: outcome ? 'checkout was already gone' : 'checkout and record were already gone' })
|
|
62
|
+
removed.push(entry.name)
|
|
63
|
+
continue
|
|
64
|
+
}
|
|
65
|
+
decisions.push({
|
|
66
|
+
...row,
|
|
67
|
+
action: 'keep',
|
|
68
|
+
reason: `checkout cleanup failed after ${outcome.removal.attempts} attempt(s): ${outcome.removal.error}`,
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
return { decisions, removed }
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Disposable detached survey sandboxes (#148 W2). A terminal survey may still
|
|
76
|
+
* carry a sandbox after a failed cleanup; teardown retries with the same bounded
|
|
77
|
+
* removal as completion. Run before the worktree phase so its state revisions
|
|
78
|
+
* never invalidate the worktree claims.
|
|
79
|
+
* @param {any} tower
|
|
80
|
+
* @param {any} input
|
|
81
|
+
* @returns {Promise<{ decisions: any[], removed: string[] }>}
|
|
82
|
+
*/
|
|
83
|
+
async function teardownSandboxes(tower, input) {
|
|
84
|
+
const state = await tower.load()
|
|
85
|
+
const activity = input.activity ?? {}
|
|
86
|
+
const exclude = new Set(input.exclude ?? [])
|
|
87
|
+
const decisions = []
|
|
88
|
+
const removed = []
|
|
89
|
+
for (const mission of state.missions) {
|
|
90
|
+
const sandbox = typeof /** @type {any} */ (mission).sandbox === 'string' ? /** @type {any} */ (mission).sandbox : null
|
|
91
|
+
if (!sandbox) continue
|
|
92
|
+
if (exclude.has(mission.id)) {
|
|
93
|
+
decisions.push({ missionId: mission.id, action: 'keep', sandbox, reason: 'excluded' })
|
|
94
|
+
continue
|
|
95
|
+
}
|
|
96
|
+
if (hasLiveAgent(state, mission.id, activity)) {
|
|
97
|
+
decisions.push({ missionId: mission.id, action: 'keep', sandbox, reason: 'live agent' })
|
|
98
|
+
continue
|
|
99
|
+
}
|
|
100
|
+
if (!['completed', 'abandoned'].includes(mission.status)) {
|
|
101
|
+
decisions.push({ missionId: mission.id, action: 'keep', sandbox, reason: `mission is ${mission.status}` })
|
|
102
|
+
continue
|
|
103
|
+
}
|
|
104
|
+
if (input.dryRun === true) {
|
|
105
|
+
decisions.push({ missionId: mission.id, action: 'remove', sandbox, reason: 'eligible' })
|
|
106
|
+
continue
|
|
107
|
+
}
|
|
108
|
+
const outcome = await cleanupSandbox(tower, mission.id)
|
|
109
|
+
if (!outcome) {
|
|
110
|
+
decisions.push({ missionId: mission.id, action: 'removed', sandbox, reason: 'sandbox was already gone' })
|
|
111
|
+
removed.push(mission.id)
|
|
112
|
+
continue
|
|
113
|
+
}
|
|
114
|
+
if (outcome.ok) removed.push(mission.id)
|
|
115
|
+
decisions.push({
|
|
116
|
+
missionId: mission.id,
|
|
117
|
+
action: outcome.ok ? 'removed' : 'keep',
|
|
118
|
+
sandbox,
|
|
119
|
+
...(outcome.ok ? {} : { reason: `sandbox cleanup failed after ${outcome.attempts} attempt(s): ${outcome.error}` }),
|
|
120
|
+
})
|
|
121
|
+
}
|
|
122
|
+
return { decisions, removed }
|
|
123
|
+
}
|
|
24
124
|
|
|
25
125
|
/**
|
|
26
126
|
* Phase 1 (#51): decide every keep/remove outcome without holding the state
|
|
@@ -87,8 +187,23 @@ async function claimRemoval(tower, candidate, expectedRevision, input) {
|
|
|
87
187
|
}
|
|
88
188
|
|
|
89
189
|
export async function teardown(tower, input) {
|
|
190
|
+
// Sandbox cleanup runs first: it owns its own short locks and revisions, so
|
|
191
|
+
// the worktree prepare/act/commit phases below see a stable revision.
|
|
192
|
+
// Review checkout cleanup first: it owns its own short locks and revisions, so
|
|
193
|
+
// the worktree prepare/act/commit phases below see a stable revision.
|
|
194
|
+
const reviews = await teardownReviewCheckouts(tower, input)
|
|
195
|
+
const sandboxes = await teardownSandboxes(tower, input)
|
|
90
196
|
const prepared = await prepareTeardown(tower, input)
|
|
91
|
-
if (prepared.dryRun)
|
|
197
|
+
if (prepared.dryRun) {
|
|
198
|
+
return {
|
|
199
|
+
ok: true,
|
|
200
|
+
dryRun: true,
|
|
201
|
+
removed: [],
|
|
202
|
+
decisions: [...reviews.decisions, ...sandboxes.decisions, ...prepared.decisions],
|
|
203
|
+
reviewCheckoutsRemoved: [],
|
|
204
|
+
sandboxesRemoved: [],
|
|
205
|
+
}
|
|
206
|
+
}
|
|
92
207
|
|
|
93
208
|
const removed = []
|
|
94
209
|
let expectedRevision = prepared.stateRevision
|
|
@@ -197,7 +312,9 @@ export async function teardown(tower, input) {
|
|
|
197
312
|
ok: true,
|
|
198
313
|
dryRun: false,
|
|
199
314
|
removed,
|
|
200
|
-
decisions: prepared.decisions,
|
|
315
|
+
decisions: [...reviews.decisions, ...sandboxes.decisions, ...prepared.decisions],
|
|
316
|
+
reviewCheckoutsRemoved: reviews.removed,
|
|
317
|
+
sandboxesRemoved: sandboxes.removed,
|
|
201
318
|
archived: archive.archived,
|
|
202
319
|
...(archive.error ? { archiveError: archive.error } : {}),
|
|
203
320
|
}
|
package/app/tower.js
CHANGED
|
@@ -28,6 +28,7 @@ import { writeBoard, boardFile } from './board.js'
|
|
|
28
28
|
import { archiveIndex, archivedMission } from './archive.js'
|
|
29
29
|
import { recordSpawnOutcome, recordInterrupt, reserveRoster, recordSpawn, rosterView } from './spawn.js'
|
|
30
30
|
import { recordTestRun, recordLegacySnapshot, recordLegacyMap } from './recording.js'
|
|
31
|
+
import { resolveLegacySurveyRead } from './sharedCheckout.js'
|
|
31
32
|
|
|
32
33
|
export const ROLES = ['worker', 'reviewer']
|
|
33
34
|
const MAX_REVIEW_ROUNDS = 5
|
|
@@ -99,6 +100,7 @@ import { rebase } from './rebase.js'
|
|
|
99
100
|
import { merge } from './merge.js'
|
|
100
101
|
import { init } from './init.js'
|
|
101
102
|
import { provision } from './provision.js'
|
|
103
|
+
import { provisionReviewCheckout } from './reviewCheckout.js'
|
|
102
104
|
import { addFinding, readFindings, findings } from './findings.js'
|
|
103
105
|
import { recordMessage, recordDelivery, inbox } from './messages.js'
|
|
104
106
|
import { createBatch, closeBatch, abandonBatch, batchStatus } from './batch.js'
|
|
@@ -170,6 +172,20 @@ export class Tower {
|
|
|
170
172
|
return (await this.git(cwd, ['rev-parse', ref])).trim()
|
|
171
173
|
}
|
|
172
174
|
|
|
175
|
+
/**
|
|
176
|
+
* The commit a mission branch points at, resolved from the branch ref. Never
|
|
177
|
+
* reads a live worktree checkout: a checkout is a view, the ref is the fact
|
|
178
|
+
* (#149 W3 review evidence and every tip comparison use this).
|
|
179
|
+
* @param {{ id?: string, worktree?: { branch?: string } | null }} mission
|
|
180
|
+
*/
|
|
181
|
+
async branchTip(mission) {
|
|
182
|
+
const branch = mission?.worktree?.branch
|
|
183
|
+
if (typeof branch !== 'string' || branch.length === 0) {
|
|
184
|
+
fail(`mission ${mission?.id ?? ''} has no branch to resolve`.replace(' ', ' '), 'invalid-argument')
|
|
185
|
+
}
|
|
186
|
+
return this.revParse(this.root, `refs/heads/${branch}`)
|
|
187
|
+
}
|
|
188
|
+
|
|
173
189
|
async isClean(cwd) {
|
|
174
190
|
return (await this.git(cwd, ['status', '--porcelain'])).trim().length === 0
|
|
175
191
|
}
|
|
@@ -193,6 +209,9 @@ export class Tower {
|
|
|
193
209
|
paths: this.paths,
|
|
194
210
|
now: this.deps.clock?.now ? this.deps.clock.now() : Date.now(),
|
|
195
211
|
persist: options.persist,
|
|
212
|
+
// A legacy survey planned but never provisioned recorded no base; the
|
|
213
|
+
// loader resolves it once, from this checkout, before the pure migration.
|
|
214
|
+
resolveLegacySurvey: (rawState) => resolveLegacySurveyRead(this, rawState),
|
|
196
215
|
})
|
|
197
216
|
this.stateLoad = { ...loaded.version, migration: loaded.migration }
|
|
198
217
|
return loaded.state
|
|
@@ -279,6 +298,15 @@ export class Tower {
|
|
|
279
298
|
return provision(this, input)
|
|
280
299
|
}
|
|
281
300
|
|
|
301
|
+
/**
|
|
302
|
+
* Provision the disposable detached review checkout for a reviewer (#149 W3).
|
|
303
|
+
* The commit it returns is the reviewer's evidence for every later read and
|
|
304
|
+
* the verdict stamp.
|
|
305
|
+
*/
|
|
306
|
+
async provisionReviewCheckout(input = {}) {
|
|
307
|
+
return provisionReviewCheckout(this, input)
|
|
308
|
+
}
|
|
309
|
+
|
|
282
310
|
async missionContext(missionId) {
|
|
283
311
|
return missionContext(this, missionId)
|
|
284
312
|
}
|
|
@@ -521,7 +549,7 @@ export class Tower {
|
|
|
521
549
|
let branchTip
|
|
522
550
|
try {
|
|
523
551
|
baseTip = await this.revParse(this.root, state.base)
|
|
524
|
-
branchTip = await this.
|
|
552
|
+
branchTip = await this.branchTip(mission)
|
|
525
553
|
} catch {
|
|
526
554
|
return null
|
|
527
555
|
}
|
package/cordis.patch.yml
CHANGED
|
@@ -110,3 +110,53 @@
|
|
|
110
110
|
name: '@deepseek-ai/dsh-tool-fs-search'
|
|
111
111
|
config:
|
|
112
112
|
sampleOverCapGlobResults: false
|
|
113
|
+
# #148 D7/W2: one visible survey capability row. The group is the switch:
|
|
114
|
+
# both the read-only preset and the detached-sandbox preset are nested
|
|
115
|
+
# dependencies of it, so the sandbox placement is tuning and adds no second
|
|
116
|
+
# visible component. Off means a survey cannot be planned (tower_plan refuses
|
|
117
|
+
# with an actionable code) and no survey agent can be dispatched; build
|
|
118
|
+
# missions are unaffected. Read-only remains structural for the shared
|
|
119
|
+
# placement (the preset allow-list has no write, edit, or shell tool); the
|
|
120
|
+
# sandbox preset exists only for `survey.sandbox: 'detached'`.
|
|
121
|
+
- id: tower-survey
|
|
122
|
+
name: cordis:group
|
|
123
|
+
group: true
|
|
124
|
+
config:
|
|
125
|
+
- id: preset-tower-survey
|
|
126
|
+
name: 'dsh-tower/preset-survey'
|
|
127
|
+
config:
|
|
128
|
+
id: tower-survey
|
|
129
|
+
name: Tower Survey
|
|
130
|
+
description: Read-only inspection of one recorded commit in the shared checkout.
|
|
131
|
+
order: 62
|
|
132
|
+
plugins:
|
|
133
|
+
- id: tower-survey-policy
|
|
134
|
+
name: 'dsh-tower/survey'
|
|
135
|
+
- id: tower-survey-fs
|
|
136
|
+
name: '@deepseek-ai/dsh-tool-fs'
|
|
137
|
+
config:
|
|
138
|
+
write: false
|
|
139
|
+
edit: false
|
|
140
|
+
readImage: false
|
|
141
|
+
- id: tower-survey-fs-search
|
|
142
|
+
name: '@deepseek-ai/dsh-tool-fs-search'
|
|
143
|
+
config:
|
|
144
|
+
sampleOverCapGlobResults: false
|
|
145
|
+
- id: preset-tower-survey-sandbox
|
|
146
|
+
name: 'dsh-tower/preset-survey-sandbox'
|
|
147
|
+
config:
|
|
148
|
+
id: tower-survey-sandbox
|
|
149
|
+
name: Tower Survey Sandbox
|
|
150
|
+
description: Disposable detached checkout for a survey that may write or run commands while reading one recorded commit.
|
|
151
|
+
order: 63
|
|
152
|
+
plugins:
|
|
153
|
+
- id: tower-survey-sandbox-policy
|
|
154
|
+
name: 'dsh-tower/survey-sandbox'
|
|
155
|
+
- id: tower-survey-sandbox-fs
|
|
156
|
+
name: '@deepseek-ai/dsh-tool-fs'
|
|
157
|
+
- id: tower-survey-sandbox-fs-search
|
|
158
|
+
name: '@deepseek-ai/dsh-tool-fs-search'
|
|
159
|
+
config:
|
|
160
|
+
sampleOverCapGlobResults: false
|
|
161
|
+
- id: tower-survey-sandbox-pwsh
|
|
162
|
+
name: '@deepseek-ai/dsh-tool-pwsh'
|