dsh-tower 2.1.0-beta.1 → 2.1.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 +51 -0
- package/COMPATIBILITY.md +1 -0
- package/CONTRIBUTING.md +8 -1
- package/README.en.md +8 -2
- package/README.md +8 -2
- package/adapters/default.js +2 -0
- package/app/archive.js +190 -0
- package/app/board.js +3 -1
- package/app/checkCompletion.js +15 -2
- package/app/gate.js +31 -13
- package/app/init.js +45 -3
- package/app/merge.js +6 -0
- package/app/mission.js +2 -0
- package/app/plan.js +12 -4
- package/app/read.js +59 -3
- package/app/review.js +2 -0
- package/app/teardown.js +22 -1
- package/app/tower.js +34 -6
- package/docs/agents/domain.md +38 -0
- package/docs/agents/issue-tracker.md +46 -0
- package/docs/agents/triage-labels.md +15 -0
- package/docs/architecture/overview.md +3 -1
- package/docs/guide/install-upgrade-migration.md +18 -1
- package/docs/reference/blockers.md +1 -1
- package/docs/reference/config.generated.md +4 -0
- package/docs/reference/config.md +4 -0
- package/docs/reference/doctor.md +58 -8
- package/docs/reference/errors.generated.md +2 -0
- package/docs/reference/errors.md +4 -2
- package/docs/reference/tools.generated.md +6 -6
- package/docs/reference/tools.md +7 -6
- package/docs/zh/guide/install-upgrade-migration.md +13 -1
- package/docs/zh/reference/blockers.md +1 -1
- package/docs/zh/reference/config.md +4 -0
- package/docs/zh/reference/doctor.md +35 -2
- package/docs/zh/reference/errors.md +4 -2
- package/docs/zh/reference/tools.md +3 -3
- package/domain/config/schema.js +26 -3
- package/domain/contracts/outputs.js +27 -1
- package/domain/contracts/tool-inputs/missions.js +2 -1
- package/domain/errors.js +2 -0
- package/domain/integration/gate.js +25 -11
- package/domain/integration/init.js +40 -4
- package/domain/mission.js +1 -1
- package/domain/missions/completion.js +58 -5
- package/domain/missions/lifecycle.js +2 -1
- package/domain/planning.js +6 -3
- package/domain/read/views.js +14 -1
- package/domain/report.js +9 -1
- package/domain/scope.js +83 -11
- package/domain/state/archive.js +257 -0
- package/domain/state/migrations.js +145 -0
- package/domain/state/schema.js +6 -0
- package/domain/state.js +154 -4
- package/domain/summary.js +2 -0
- package/lib/archive.js +279 -0
- package/lib/caseSensitivity.js +66 -0
- package/lib/doctor.js +178 -0
- package/lib/leases.js +14 -5
- package/lib/legacy.js +19 -5
- package/lib/persistence.js +12 -5
- package/lib/stateFile.js +99 -0
- package/lib/store.js +15 -0
- package/lib/tests.js +6 -2
- package/lib/worktreeOwnership.js +18 -7
- package/package.json +1 -1
- package/scripts/pack-manifest.txt +9 -0
- package/tools/complete.js +1 -1
- package/tools/doctor.js +1 -1
- package/tools/init.js +1 -1
- package/tools/plan.js +1 -1
- package/tools/preflight.js +1 -0
- package/tools/status.js +14 -6
- package/tools/teardown.js +1 -1
- package/types/index.d.ts +34 -0
package/tools/status.js
CHANGED
|
@@ -4,6 +4,7 @@ import { SCHEMAS, output } from '../domain/contracts/outputs.js'
|
|
|
4
4
|
import { classifyError } from '../domain/errors.js'
|
|
5
5
|
import { StatusInput } from '../domain/contracts/tool-inputs/index.js'
|
|
6
6
|
import { ROSTER_INACTIVE_STATES, isMarkdownFormat, isReservedState, isWorkerRole } from '../domain/vocabulary.js'
|
|
7
|
+
import { archiveView } from '../app/archive.js'
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* @param {any} ctx
|
|
@@ -19,9 +20,9 @@ export function registerStatusTool(ctx, deps) {
|
|
|
19
20
|
define(ctx, {
|
|
20
21
|
name: 'tower_status',
|
|
21
22
|
description:
|
|
22
|
-
'Read the Tower dashboard for a repository: state path, base branch, revision, mission status counts, paged mission summaries (scope/deps/tasks/worktree/owner), roster size, findings, config path and the activity tail. Pass missionId for one full mission (tasks, notes, reviews, findings, completion report); offset/limit page the mission list (default 20, max 100); includeGate adds preflight gate digests for the page; format:"markdown" returns the human-readable mission board. Read-only.',
|
|
23
|
+
'Read the Tower dashboard for a repository: state path, base branch, revision, mission status counts, paged mission summaries (scope/deps/tasks/worktree/owner), roster size, findings, archive count, config path and the activity tail. Pass missionId for one full mission (tasks, notes, reviews, findings, completion report; archived missions are loaded from their year file); offset/limit page the mission list (default 20, max 100); includeGate adds preflight gate digests for the page; includeArchived appends compact archived summaries after the active page; format:"markdown" returns the human-readable mission board (active missions plus an archived count). Read-only.',
|
|
23
24
|
parameters: StatusInput,
|
|
24
|
-
aliases: { mission_id: ['missionId'], include_gate: ['includeGate'] },
|
|
25
|
+
aliases: { mission_id: ['missionId'], include_gate: ['includeGate'], include_archived: ['includeArchived'] },
|
|
25
26
|
output: output(SCHEMAS.status),
|
|
26
27
|
async execute(args, exec) {
|
|
27
28
|
const tower = await Tower.open(args.repoRoot)
|
|
@@ -48,11 +49,18 @@ export function registerStatusTool(ctx, deps) {
|
|
|
48
49
|
}
|
|
49
50
|
}
|
|
50
51
|
const state = await tower.load()
|
|
51
|
-
const
|
|
52
|
+
const index = await tower.archiveIndex()
|
|
53
|
+
const activeIds = state.missions.map((mission) => mission.id)
|
|
54
|
+
const archivedIds = index.ok
|
|
55
|
+
? index.missions.map((entry) => entry.id).filter((id) => !activeIds.includes(id))
|
|
56
|
+
: []
|
|
57
|
+
// Hot state pages first, then archived summaries on demand (#73).
|
|
58
|
+
const ids = args.includeArchived === true ? [...activeIds, ...archivedIds] : activeIds
|
|
59
|
+
const total = ids.length
|
|
52
60
|
const offset = typeof args.offset === 'number' && Number.isInteger(args.offset) && args.offset > 0 ? args.offset : 0
|
|
53
61
|
const limit = typeof args.limit === 'number' && Number.isInteger(args.limit) ? Math.max(1, Math.min(100, args.limit)) : 20
|
|
54
|
-
const pageIds =
|
|
55
|
-
const status = await tower.status({ missionIds: pageIds })
|
|
62
|
+
const pageIds = ids.slice(offset, offset + limit)
|
|
63
|
+
const status = await tower.status({ missionIds: pageIds, includeArchived: args.includeArchived === true })
|
|
56
64
|
let page = status.missions
|
|
57
65
|
if (args.includeGate === true) {
|
|
58
66
|
const { activity, parentStatus } = await observeActivity(ctx, tower)
|
|
@@ -86,7 +94,7 @@ export function registerStatusTool(ctx, deps) {
|
|
|
86
94
|
if (isMarkdownFormat(args.format)) {
|
|
87
95
|
const state = await tower.load()
|
|
88
96
|
const output = /** @type {any} */ (result)
|
|
89
|
-
output.markdown = tower.boardMarkdown(state)
|
|
97
|
+
output.markdown = tower.boardMarkdown(state, archiveView(index))
|
|
90
98
|
}
|
|
91
99
|
return result
|
|
92
100
|
},
|
package/tools/teardown.js
CHANGED
|
@@ -21,7 +21,7 @@ export function registerTeardownTool(ctx, deps) {
|
|
|
21
21
|
define(ctx, {
|
|
22
22
|
name: 'tower_teardown',
|
|
23
23
|
description:
|
|
24
|
-
'Tear down eligible mission worktrees after their missions are merged or abandoned. A worktree whose roster agent is running is always kept (force cannot override); dirty worktrees need force; exclude keeps named missions. dry_run previews the remove/keep decisions without changing anything.',
|
|
24
|
+
'Tear down eligible mission worktrees after their missions are merged or abandoned. A worktree whose roster agent is running is always kept (force cannot override); dirty worktrees need force; exclude keeps named missions. dry_run previews the remove/keep decisions without changing anything. Terminal missions whose worktree is gone and whose configured archive policy is due (archive.afterDays / archive.maxMissions) are moved to <git-common-dir>/dsh-tower/archive/ so state.json stops rewriting them; nothing is deleted.',
|
|
25
25
|
parameters: TeardownInput,
|
|
26
26
|
aliases: {"dry_run":["dryRun"]},
|
|
27
27
|
board: true,
|
package/types/index.d.ts
CHANGED
|
@@ -99,6 +99,8 @@ export interface CompletionCheck {
|
|
|
99
99
|
|
|
100
100
|
export interface CompletionReport {
|
|
101
101
|
report?: string
|
|
102
|
+
/** UTF-8 byte length of `report`; absent on documents written before #89. */
|
|
103
|
+
reportBytes?: number
|
|
102
104
|
by?: string
|
|
103
105
|
at?: number
|
|
104
106
|
checks?: CompletionCheck[]
|
|
@@ -153,6 +155,34 @@ export interface Mission {
|
|
|
153
155
|
authorizationRef?: string | null
|
|
154
156
|
}
|
|
155
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Compact archived-mission entry (`archive/index.json`). It keeps enough of the
|
|
160
|
+
* mission for ordering, dependency lookups and id allocation without loading the
|
|
161
|
+
* full year file, and it is what `tower_status includeArchived` pages from (#73).
|
|
162
|
+
*/
|
|
163
|
+
export interface ArchiveIndexEntry {
|
|
164
|
+
id: string
|
|
165
|
+
title: string
|
|
166
|
+
status: MissionStatus
|
|
167
|
+
kind?: MissionKind
|
|
168
|
+
scope?: string[]
|
|
169
|
+
deps?: string[]
|
|
170
|
+
owner?: string | null
|
|
171
|
+
branch?: string | null
|
|
172
|
+
mergedCommit?: string | null
|
|
173
|
+
mergedAt?: number | null
|
|
174
|
+
updatedAt?: number | null
|
|
175
|
+
archivedAt: number
|
|
176
|
+
archivedYear: number
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** Full archived record (`archive/<year>.json`): mission + linked history. */
|
|
180
|
+
export interface ArchivedMissionRecord extends ArchiveIndexEntry {
|
|
181
|
+
mission: Mission
|
|
182
|
+
reviews: Review[]
|
|
183
|
+
findings: Finding[]
|
|
184
|
+
}
|
|
185
|
+
|
|
156
186
|
export interface Review {
|
|
157
187
|
id?: string
|
|
158
188
|
seq?: number
|
|
@@ -220,6 +250,8 @@ export interface TowerState {
|
|
|
220
250
|
createdAt?: number
|
|
221
251
|
updatedAt?: number
|
|
222
252
|
dirtyBase?: boolean
|
|
253
|
+
/** Detected once at tower_init; null means "not detected yet" (#90). */
|
|
254
|
+
caseInsensitive?: boolean | null
|
|
223
255
|
towerAgentId?: string | null
|
|
224
256
|
snapshotCommit?: string | null
|
|
225
257
|
snapshotRef?: string | null
|
|
@@ -268,6 +300,8 @@ export interface MissionSummary {
|
|
|
268
300
|
reviewPolicy: ReviewPolicy
|
|
269
301
|
mergedCommit: string | null
|
|
270
302
|
mergedAt: number | null
|
|
303
|
+
/** Size of the completion report without loading its body; null when absent. */
|
|
304
|
+
reportBytes: number | null
|
|
271
305
|
updatedAt?: number
|
|
272
306
|
}
|
|
273
307
|
|