@bvdm/delano 0.2.3 → 0.2.5
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/.delano/viewer/README.md +3 -2
- package/.delano/viewer/public/app.js +13 -1
- package/.delano/viewer/public/app.jsx +2312 -0
- package/.delano/viewer/public/delano-mark.svg +4 -0
- package/.delano/viewer/public/index.html +12 -14
- package/.delano/viewer/public/styles.css +1005 -833
- package/.delano/viewer/server.js +46 -5
- package/README.md +63 -3
- package/assets/install-manifest.json +7 -0
- package/assets/payload/.agents/adapters/manifest.schema.json +103 -0
- package/assets/payload/.agents/adapters/spec-kit/adapter.json +71 -0
- package/assets/payload/.agents/hooks/README.md +6 -1
- package/assets/payload/.agents/hooks/codex-session-status.js +123 -0
- package/assets/payload/.agents/schemas/status-transitions.json +35 -0
- package/assets/payload/.agents/scripts/README.md +1 -1
- package/assets/payload/.agents/scripts/check-status-transitions.mjs +171 -2
- package/assets/payload/.agents/scripts/pm/import-spec-kit.sh +605 -0
- package/assets/payload/.agents/scripts/pm/init.sh +31 -2
- package/assets/payload/.agents/scripts/pm/research.sh +296 -0
- package/assets/payload/.agents/scripts/pm/status.sh +135 -28
- package/assets/payload/.agents/scripts/pm/validate.sh +16 -0
- package/assets/payload/.codex/hooks.json +17 -0
- package/assets/payload/.delano/viewer/README.md +3 -2
- package/assets/payload/.delano/viewer/public/app.js +13 -1
- package/assets/payload/.delano/viewer/public/index.html +12 -14
- package/assets/payload/.delano/viewer/public/styles.css +1005 -833
- package/assets/payload/.delano/viewer/server.js +46 -5
- package/assets/payload/.project/templates/decisions.md +18 -0
- package/assets/payload/.project/templates/plan.md +17 -0
- package/assets/payload/.project/templates/spec.md +12 -0
- package/assets/payload/.project/templates/task.md +6 -0
- package/assets/payload/.project/templates/workstream.md +1 -0
- package/package.json +4 -2
- package/src/cli/commands/install.js +2 -1
- package/src/cli/commands/state.js +689 -0
- package/src/cli/commands/viewer.js +2 -1
- package/src/cli/commands/wrapper.js +29 -5
- package/src/cli/index.js +120 -7
- package/src/cli/lib/install.js +179 -2
- package/src/cli/lib/project-state.js +918 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
usage() {
|
|
5
|
+
cat <<'USAGE'
|
|
6
|
+
Usage:
|
|
7
|
+
research.sh <project-slug> <research-slug> [options]
|
|
8
|
+
|
|
9
|
+
Creates a repo-native Delano research intake folder for a project.
|
|
10
|
+
|
|
11
|
+
Required arguments:
|
|
12
|
+
project-slug Existing Delano project slug
|
|
13
|
+
research-slug Research folder slug in kebab-case
|
|
14
|
+
|
|
15
|
+
Options:
|
|
16
|
+
--title <title> Human-readable research title
|
|
17
|
+
--question <question> Primary research question
|
|
18
|
+
--owner <owner> Research owner, defaults to team
|
|
19
|
+
--no-validate Create artifacts without running Delano validation
|
|
20
|
+
--json Print a single machine-readable JSON result
|
|
21
|
+
-h, --help Show this help
|
|
22
|
+
|
|
23
|
+
Agent notes:
|
|
24
|
+
- Use this before mutating spec/plan/tasks when intent is unclear.
|
|
25
|
+
- Update findings.md and progress.md during investigation.
|
|
26
|
+
- Fold durable conclusions forward into spec.md, plan.md, decisions.md, workstreams, tasks, or updates.
|
|
27
|
+
- Research files are supporting discovery state, not executable task truth.
|
|
28
|
+
USAGE
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
resolve_python() {
|
|
32
|
+
if command -v python3 >/dev/null 2>&1 && python3 -c "import sys" >/dev/null 2>&1; then
|
|
33
|
+
PYTHON_CMD=(python3)
|
|
34
|
+
elif command -v py >/dev/null 2>&1 && py -3 -c "import sys" >/dev/null 2>&1; then
|
|
35
|
+
PYTHON_CMD=(py -3)
|
|
36
|
+
elif command -v python >/dev/null 2>&1 && python -c "import sys" >/dev/null 2>&1; then
|
|
37
|
+
PYTHON_CMD=(python)
|
|
38
|
+
else
|
|
39
|
+
echo "Error: Python runtime not found. Install python3, python, or py -3." >&2
|
|
40
|
+
exit 1
|
|
41
|
+
fi
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
resolve_python
|
|
45
|
+
|
|
46
|
+
json_escape() {
|
|
47
|
+
"${PYTHON_CMD[@]}" -c 'import json,sys; print(json.dumps(sys.stdin.read().rstrip("\n")))'
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if [[ "${1:-}" == "" || "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
|
|
51
|
+
usage
|
|
52
|
+
exit 0
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
if [[ "${2:-}" == "" ]]; then
|
|
56
|
+
usage
|
|
57
|
+
exit 1
|
|
58
|
+
fi
|
|
59
|
+
|
|
60
|
+
project_slug="$1"
|
|
61
|
+
research_slug="$2"
|
|
62
|
+
shift 2
|
|
63
|
+
|
|
64
|
+
title=""
|
|
65
|
+
question=""
|
|
66
|
+
owner="team"
|
|
67
|
+
validate="true"
|
|
68
|
+
json="false"
|
|
69
|
+
|
|
70
|
+
while [[ $# -gt 0 ]]; do
|
|
71
|
+
case "$1" in
|
|
72
|
+
--title)
|
|
73
|
+
title="${2:-}"
|
|
74
|
+
if [[ -z "$title" ]]; then echo "Error: --title requires a value"; exit 1; fi
|
|
75
|
+
shift 2
|
|
76
|
+
;;
|
|
77
|
+
--question)
|
|
78
|
+
question="${2:-}"
|
|
79
|
+
if [[ -z "$question" ]]; then echo "Error: --question requires a value"; exit 1; fi
|
|
80
|
+
shift 2
|
|
81
|
+
;;
|
|
82
|
+
--owner)
|
|
83
|
+
owner="${2:-}"
|
|
84
|
+
if [[ -z "$owner" ]]; then echo "Error: --owner requires a value"; exit 1; fi
|
|
85
|
+
shift 2
|
|
86
|
+
;;
|
|
87
|
+
--no-validate)
|
|
88
|
+
validate="false"
|
|
89
|
+
shift
|
|
90
|
+
;;
|
|
91
|
+
--json)
|
|
92
|
+
json="true"
|
|
93
|
+
shift
|
|
94
|
+
;;
|
|
95
|
+
-h|--help)
|
|
96
|
+
usage
|
|
97
|
+
exit 0
|
|
98
|
+
;;
|
|
99
|
+
--)
|
|
100
|
+
shift
|
|
101
|
+
;;
|
|
102
|
+
--*)
|
|
103
|
+
echo "Error: unknown option: $1"
|
|
104
|
+
exit 1
|
|
105
|
+
;;
|
|
106
|
+
*)
|
|
107
|
+
echo "Error: unexpected positional argument: $1"
|
|
108
|
+
exit 1
|
|
109
|
+
;;
|
|
110
|
+
esac
|
|
111
|
+
done
|
|
112
|
+
|
|
113
|
+
if [[ ! "$project_slug" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]]; then
|
|
114
|
+
echo "Error: project-slug must be kebab-case"
|
|
115
|
+
exit 1
|
|
116
|
+
fi
|
|
117
|
+
|
|
118
|
+
if [[ ! "$research_slug" =~ ^[a-z0-9]+(-[a-z0-9]+)*$ ]]; then
|
|
119
|
+
echo "Error: research-slug must be kebab-case"
|
|
120
|
+
exit 1
|
|
121
|
+
fi
|
|
122
|
+
|
|
123
|
+
root="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
124
|
+
cd "$root"
|
|
125
|
+
|
|
126
|
+
project_dir=".project/projects/$project_slug"
|
|
127
|
+
if [[ ! -d "$project_dir" ]]; then
|
|
128
|
+
echo "Error: Delano project not found: $project_dir"
|
|
129
|
+
exit 1
|
|
130
|
+
fi
|
|
131
|
+
|
|
132
|
+
research_dir="$project_dir/research/$research_slug"
|
|
133
|
+
if [[ -d "$research_dir" ]]; then
|
|
134
|
+
echo "Error: research intake already exists at $research_dir"
|
|
135
|
+
exit 1
|
|
136
|
+
fi
|
|
137
|
+
|
|
138
|
+
now="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
|
|
139
|
+
title="${title:-${research_slug//-/ }}"
|
|
140
|
+
question="${question:-<primary research question>}"
|
|
141
|
+
|
|
142
|
+
mkdir -p "$research_dir"
|
|
143
|
+
|
|
144
|
+
cat > "$research_dir/task_plan.md" <<PLAN
|
|
145
|
+
---
|
|
146
|
+
type: research_intake
|
|
147
|
+
project: $project_slug
|
|
148
|
+
slug: $research_slug
|
|
149
|
+
owner: $owner
|
|
150
|
+
status: opened
|
|
151
|
+
created: $now
|
|
152
|
+
updated: $now
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
# Research Plan: $title
|
|
156
|
+
|
|
157
|
+
## Goal
|
|
158
|
+
|
|
159
|
+
Answer the research question and fold durable conclusions into canonical Delano project artifacts.
|
|
160
|
+
|
|
161
|
+
## Primary Question
|
|
162
|
+
|
|
163
|
+
$question
|
|
164
|
+
|
|
165
|
+
## Scope
|
|
166
|
+
|
|
167
|
+
### In Scope
|
|
168
|
+
|
|
169
|
+
- Gather relevant evidence.
|
|
170
|
+
- Capture findings and decisions.
|
|
171
|
+
- Identify changes needed in \`spec.md\`, \`plan.md\`, \`decisions.md\`, workstreams, tasks, or updates.
|
|
172
|
+
|
|
173
|
+
### Out of Scope
|
|
174
|
+
|
|
175
|
+
- Marking delivery tasks done from research alone.
|
|
176
|
+
- External sync writes without normal Delano approval semantics.
|
|
177
|
+
- Storing secrets, credentials, or private machine paths.
|
|
178
|
+
|
|
179
|
+
## Current Phase
|
|
180
|
+
|
|
181
|
+
Opened
|
|
182
|
+
|
|
183
|
+
## Phases
|
|
184
|
+
|
|
185
|
+
- [x] Open research intake
|
|
186
|
+
- [ ] Investigate sources and options
|
|
187
|
+
- [ ] Summarize findings
|
|
188
|
+
- [ ] Fold forward into canonical project artifacts or explicitly close as no-action
|
|
189
|
+
|
|
190
|
+
## Decisions Made
|
|
191
|
+
|
|
192
|
+
| Decision | Rationale |
|
|
193
|
+
| --- | --- |
|
|
194
|
+
|
|
195
|
+
## Blockers
|
|
196
|
+
|
|
197
|
+
| Blocker | Owner | Check-back |
|
|
198
|
+
| --- | --- | --- |
|
|
199
|
+
PLAN
|
|
200
|
+
|
|
201
|
+
cat > "$research_dir/findings.md" <<FINDINGS
|
|
202
|
+
---
|
|
203
|
+
type: research_findings
|
|
204
|
+
project: $project_slug
|
|
205
|
+
slug: $research_slug
|
|
206
|
+
created: $now
|
|
207
|
+
updated: $now
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
# Findings: $title
|
|
211
|
+
|
|
212
|
+
## Source References
|
|
213
|
+
|
|
214
|
+
- <source, file, command, or artifact inspected>
|
|
215
|
+
|
|
216
|
+
## Observations
|
|
217
|
+
|
|
218
|
+
- <finding>
|
|
219
|
+
|
|
220
|
+
## Options Considered
|
|
221
|
+
|
|
222
|
+
| Option | Pros | Cons | Decision |
|
|
223
|
+
| --- | --- | --- | --- |
|
|
224
|
+
|
|
225
|
+
## Fold-Forward Candidates
|
|
226
|
+
|
|
227
|
+
| Finding | Target Artifact | Proposed Change |
|
|
228
|
+
| --- | --- | --- |
|
|
229
|
+
|
|
230
|
+
## Open Questions
|
|
231
|
+
|
|
232
|
+
- <question>
|
|
233
|
+
FINDINGS
|
|
234
|
+
|
|
235
|
+
cat > "$research_dir/progress.md" <<PROGRESS
|
|
236
|
+
---
|
|
237
|
+
type: research_progress
|
|
238
|
+
project: $project_slug
|
|
239
|
+
slug: $research_slug
|
|
240
|
+
created: $now
|
|
241
|
+
updated: $now
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
# Progress: $title
|
|
245
|
+
|
|
246
|
+
## $now
|
|
247
|
+
|
|
248
|
+
- Opened research intake for project \`$project_slug\`.
|
|
249
|
+
- Primary question: $question
|
|
250
|
+
|
|
251
|
+
## Validation Evidence
|
|
252
|
+
|
|
253
|
+
- Pending.
|
|
254
|
+
|
|
255
|
+
## Handoff Summary
|
|
256
|
+
|
|
257
|
+
- Pending.
|
|
258
|
+
PROGRESS
|
|
259
|
+
|
|
260
|
+
validation_status="skipped"
|
|
261
|
+
ok="true"
|
|
262
|
+
error=""
|
|
263
|
+
if [[ "$validate" == "true" ]]; then
|
|
264
|
+
if [[ "$json" == "true" ]]; then
|
|
265
|
+
validation_log="$(mktemp)"
|
|
266
|
+
if "$root/.agents/scripts/pm/validate.sh" >"$validation_log" 2>&1; then
|
|
267
|
+
validation_status="passed"
|
|
268
|
+
else
|
|
269
|
+
validation_status="failed"
|
|
270
|
+
ok="false"
|
|
271
|
+
error="validation_failed"
|
|
272
|
+
fi
|
|
273
|
+
rm -f "$validation_log"
|
|
274
|
+
else
|
|
275
|
+
"$root/.agents/scripts/pm/validate.sh"
|
|
276
|
+
validation_status="passed"
|
|
277
|
+
fi
|
|
278
|
+
fi
|
|
279
|
+
|
|
280
|
+
if [[ "$json" == "true" ]]; then
|
|
281
|
+
project_json="$(printf '%s' "$project_dir" | json_escape)"
|
|
282
|
+
research_json="$(printf '%s' "$research_dir" | json_escape)"
|
|
283
|
+
validation_json="$(printf '%s' "$validation_status" | json_escape)"
|
|
284
|
+
if [[ "$ok" == "true" ]]; then
|
|
285
|
+
printf '{"ok":true,"command":"research","project":%s,"research":%s,"files":["task_plan.md","findings.md","progress.md"],"validation":%s}\n' "$project_json" "$research_json" "$validation_json"
|
|
286
|
+
else
|
|
287
|
+
error_json="$(printf '%s' "$error" | json_escape)"
|
|
288
|
+
printf '{"ok":false,"command":"research","project":%s,"research":%s,"files":["task_plan.md","findings.md","progress.md"],"validation":%s,"error":%s}\n' "$project_json" "$research_json" "$validation_json" "$error_json"
|
|
289
|
+
exit 1
|
|
290
|
+
fi
|
|
291
|
+
else
|
|
292
|
+
echo "Created Delano research intake: $research_dir"
|
|
293
|
+
echo "Files: task_plan.md, findings.md, progress.md"
|
|
294
|
+
echo "Validation: $validation_status"
|
|
295
|
+
echo "Next: update findings.md and progress.md, then fold conclusions into canonical Delano artifacts."
|
|
296
|
+
fi
|
|
@@ -4,24 +4,92 @@ set -euo pipefail
|
|
|
4
4
|
root="$(git rev-parse --show-toplevel 2>/dev/null || pwd)"
|
|
5
5
|
cd "$root"
|
|
6
6
|
|
|
7
|
+
open_only=false
|
|
8
|
+
brief=false
|
|
9
|
+
|
|
10
|
+
usage() {
|
|
11
|
+
cat <<'EOF'
|
|
12
|
+
Usage:
|
|
13
|
+
status.sh [--open] [--brief]
|
|
14
|
+
|
|
15
|
+
Options:
|
|
16
|
+
--open Show only projects that are not closed.
|
|
17
|
+
--brief Show one compact line per project.
|
|
18
|
+
-h, --help
|
|
19
|
+
Show this help.
|
|
20
|
+
EOF
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
while [[ $# -gt 0 ]]; do
|
|
24
|
+
case "$1" in
|
|
25
|
+
--open)
|
|
26
|
+
open_only=true
|
|
27
|
+
;;
|
|
28
|
+
--brief)
|
|
29
|
+
brief=true
|
|
30
|
+
;;
|
|
31
|
+
-h|--help)
|
|
32
|
+
usage
|
|
33
|
+
exit 0
|
|
34
|
+
;;
|
|
35
|
+
*)
|
|
36
|
+
echo "Unknown status option: $1" >&2
|
|
37
|
+
usage >&2
|
|
38
|
+
exit 1
|
|
39
|
+
;;
|
|
40
|
+
esac
|
|
41
|
+
shift
|
|
42
|
+
done
|
|
43
|
+
|
|
7
44
|
fm_get() {
|
|
8
45
|
local file="$1"
|
|
9
46
|
local key="$2"
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
47
|
+
local line
|
|
48
|
+
local in_fm=0
|
|
49
|
+
while IFS= read -r line; do
|
|
50
|
+
if [[ "$line" =~ ^---[[:space:]]*$ ]]; then
|
|
51
|
+
if [[ $in_fm -eq 0 ]]; then
|
|
52
|
+
in_fm=1
|
|
53
|
+
continue
|
|
54
|
+
fi
|
|
55
|
+
return 1
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
if [[ $in_fm -eq 1 && "$line" == "$key:"* ]]; then
|
|
59
|
+
local value="${line#"$key:"}"
|
|
60
|
+
value="${value#"${value%%[![:space:]]*}"}"
|
|
61
|
+
printf '%s\n' "$value"
|
|
62
|
+
return 0
|
|
63
|
+
fi
|
|
64
|
+
done < "$file"
|
|
65
|
+
return 1
|
|
19
66
|
}
|
|
20
67
|
|
|
21
|
-
|
|
22
|
-
|
|
68
|
+
is_closed_spec_status() {
|
|
69
|
+
local status="${1:-unknown}"
|
|
70
|
+
[[ "$status" == "complete" || "$status" == "deferred" ]]
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
is_closed_plan_status() {
|
|
74
|
+
local status="${1:-unknown}"
|
|
75
|
+
[[ "$status" == "done" || "$status" == "deferred" ]]
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
is_closed_task_status() {
|
|
79
|
+
local status="${1:-unknown}"
|
|
80
|
+
[[ "$status" == "done" || "$status" == "deferred" || "$status" == "canceled" ]]
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if [[ "$open_only" == "true" ]]; then
|
|
84
|
+
echo "Delano open project status"
|
|
85
|
+
echo "=========================="
|
|
86
|
+
else
|
|
87
|
+
echo "Delano portfolio status"
|
|
88
|
+
echo "======================="
|
|
89
|
+
fi
|
|
23
90
|
|
|
24
91
|
project_count=0
|
|
92
|
+
printed_count=0
|
|
25
93
|
for project_dir in .project/projects/*; do
|
|
26
94
|
[[ -d "$project_dir" ]] || continue
|
|
27
95
|
[[ "$(basename "$project_dir")" == ".gitkeep" ]] && continue
|
|
@@ -31,31 +99,70 @@ for project_dir in .project/projects/*; do
|
|
|
31
99
|
spec_status="$(fm_get "$project_dir/spec.md" status 2>/dev/null || true)"
|
|
32
100
|
plan_status="$(fm_get "$project_dir/plan.md" status 2>/dev/null || true)"
|
|
33
101
|
|
|
34
|
-
echo ""
|
|
35
|
-
echo "Project: $slug"
|
|
36
|
-
echo " Spec status: ${spec_status:-unknown}"
|
|
37
|
-
echo " Plan status: ${plan_status:-unknown}"
|
|
38
|
-
|
|
39
102
|
total=0
|
|
103
|
+
open_tasks=0
|
|
104
|
+
backlog_count=0
|
|
105
|
+
ready_count=0
|
|
106
|
+
in_progress_count=0
|
|
107
|
+
review_count=0
|
|
108
|
+
done_count=0
|
|
109
|
+
blocked_count=0
|
|
110
|
+
deferred_count=0
|
|
111
|
+
canceled_count=0
|
|
112
|
+
unknown_count=0
|
|
40
113
|
for task in "$project_dir"/tasks/*.md; do
|
|
41
114
|
[[ -f "$task" ]] || continue
|
|
115
|
+
status="$(fm_get "$task" status 2>/dev/null || true)"
|
|
42
116
|
total=$((total + 1))
|
|
117
|
+
if ! is_closed_task_status "$status"; then
|
|
118
|
+
open_tasks=$((open_tasks + 1))
|
|
119
|
+
fi
|
|
120
|
+
case "$status" in
|
|
121
|
+
backlog) backlog_count=$((backlog_count + 1)) ;;
|
|
122
|
+
ready) ready_count=$((ready_count + 1)) ;;
|
|
123
|
+
in-progress) in_progress_count=$((in_progress_count + 1)) ;;
|
|
124
|
+
review) review_count=$((review_count + 1)) ;;
|
|
125
|
+
done) done_count=$((done_count + 1)) ;;
|
|
126
|
+
blocked) blocked_count=$((blocked_count + 1)) ;;
|
|
127
|
+
deferred) deferred_count=$((deferred_count + 1)) ;;
|
|
128
|
+
canceled) canceled_count=$((canceled_count + 1)) ;;
|
|
129
|
+
*) unknown_count=$((unknown_count + 1)) ;;
|
|
130
|
+
esac
|
|
43
131
|
done
|
|
44
132
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
133
|
+
project_open=false
|
|
134
|
+
if ! is_closed_spec_status "$spec_status" || ! is_closed_plan_status "$plan_status" || [[ $open_tasks -gt 0 ]]; then
|
|
135
|
+
project_open=true
|
|
136
|
+
fi
|
|
137
|
+
|
|
138
|
+
if [[ "$open_only" == "true" && "$project_open" != "true" ]]; then
|
|
139
|
+
continue
|
|
140
|
+
fi
|
|
141
|
+
|
|
142
|
+
printed_count=$((printed_count + 1))
|
|
143
|
+
|
|
144
|
+
if [[ "$brief" == "true" ]]; then
|
|
145
|
+
echo "${slug} spec=${spec_status:-unknown} plan=${plan_status:-unknown} open_tasks=${open_tasks} total_tasks=${total}"
|
|
146
|
+
else
|
|
147
|
+
echo ""
|
|
148
|
+
echo "Project: $slug"
|
|
149
|
+
echo " Spec status: ${spec_status:-unknown}"
|
|
150
|
+
echo " Plan status: ${plan_status:-unknown}"
|
|
151
|
+
[[ $backlog_count -gt 0 ]] && echo " backlog: $backlog_count"
|
|
152
|
+
[[ $ready_count -gt 0 ]] && echo " ready: $ready_count"
|
|
153
|
+
[[ $in_progress_count -gt 0 ]] && echo " in-progress: $in_progress_count"
|
|
154
|
+
[[ $review_count -gt 0 ]] && echo " review: $review_count"
|
|
155
|
+
[[ $done_count -gt 0 ]] && echo " done: $done_count"
|
|
156
|
+
[[ $blocked_count -gt 0 ]] && echo " blocked: $blocked_count"
|
|
157
|
+
[[ $deferred_count -gt 0 ]] && echo " deferred: $deferred_count"
|
|
158
|
+
[[ $canceled_count -gt 0 ]] && echo " canceled: $canceled_count"
|
|
159
|
+
[[ $unknown_count -gt 0 ]] && echo " unknown: $unknown_count"
|
|
160
|
+
echo " total tasks: $total"
|
|
161
|
+
fi
|
|
57
162
|
done
|
|
58
163
|
|
|
59
164
|
if [[ $project_count -eq 0 ]]; then
|
|
60
165
|
echo "No projects found. Create one with: .agents/scripts/pm/init.sh <slug> <project-name>"
|
|
166
|
+
elif [[ "$open_only" == "true" && $printed_count -eq 0 ]]; then
|
|
167
|
+
echo "No open projects found."
|
|
61
168
|
fi
|
|
@@ -467,6 +467,20 @@ if [[ -n "$artifact_schema_check" ]]; then
|
|
|
467
467
|
fi
|
|
468
468
|
fi
|
|
469
469
|
|
|
470
|
+
if [[ -f scripts/check-adapter-manifests.mjs ]]; then
|
|
471
|
+
echo ""
|
|
472
|
+
if command -v node >/dev/null 2>&1; then
|
|
473
|
+
if node scripts/check-adapter-manifests.mjs; then
|
|
474
|
+
true
|
|
475
|
+
else
|
|
476
|
+
errors=$((errors + 1))
|
|
477
|
+
fi
|
|
478
|
+
else
|
|
479
|
+
echo "❌ Node runtime not found for adapter manifest check"
|
|
480
|
+
errors=$((errors + 1))
|
|
481
|
+
fi
|
|
482
|
+
fi
|
|
483
|
+
|
|
470
484
|
operating_modes_check=""
|
|
471
485
|
if [[ -f .agents/scripts/check-operating-modes.mjs ]]; then
|
|
472
486
|
operating_modes_check=".agents/scripts/check-operating-modes.mjs"
|
|
@@ -497,6 +511,8 @@ fi
|
|
|
497
511
|
|
|
498
512
|
if [[ -n "$status_transition_check" ]]; then
|
|
499
513
|
echo ""
|
|
514
|
+
echo "Project lifecycle and status transition check"
|
|
515
|
+
echo "---------------------------------------------"
|
|
500
516
|
if command -v node >/dev/null 2>&1; then
|
|
501
517
|
if node "$status_transition_check"; then
|
|
502
518
|
true
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"SessionStart": [
|
|
4
|
+
{
|
|
5
|
+
"matcher": "startup|resume",
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "node \"$(git rev-parse --show-toplevel)/.agents/hooks/codex-session-status.js\"",
|
|
10
|
+
"timeout": 5,
|
|
11
|
+
"statusMessage": "Loading Delano open projects"
|
|
12
|
+
}
|
|
13
|
+
]
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
Minimal local frontend for browsing `.project` markdown contracts.
|
|
4
4
|
|
|
5
5
|
- Read-only: serves files from `.project` and does not write delivery state.
|
|
6
|
-
- Default URL: `http://127.0.0.1:3977`
|
|
7
|
-
- Override port: `DELANO_VIEWER_PORT=3987 npm run viewer`
|
|
6
|
+
- Default starting URL: `http://127.0.0.1:3977`
|
|
7
|
+
- Override starting port: `DELANO_VIEWER_PORT=3987 npm run viewer`
|
|
8
|
+
- Multiple viewers can run at once. If the starting port is already in use, the viewer tries the next available port and prints the actual URL.
|
|
8
9
|
|
|
9
10
|
Run from the repository root:
|
|
10
11
|
|
|
@@ -771,7 +771,19 @@ function render() {
|
|
|
771
771
|
});
|
|
772
772
|
document.querySelectorAll('[data-doc]').forEach((el) => el.onclick = () => loadDoc(el.dataset.doc));
|
|
773
773
|
document.querySelectorAll('[data-status]').forEach((el) => el.onclick = () => { state.status = el.dataset.status; render(); });
|
|
774
|
-
document.querySelectorAll('[data-role]').forEach((el) => el.onclick = () => {
|
|
774
|
+
document.querySelectorAll('[data-role]').forEach((el) => el.onclick = () => {
|
|
775
|
+
state.role = el.dataset.role;
|
|
776
|
+
state.workstream = null;
|
|
777
|
+
if (state.role !== 'all') {
|
|
778
|
+
const firstInRole = currentDocs().find((doc) => doc.role === state.role);
|
|
779
|
+
if (firstInRole) {
|
|
780
|
+
if (state.role === 'workstream') state.workstream = firstInRole.path;
|
|
781
|
+
loadDoc(firstInRole.path);
|
|
782
|
+
return;
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
render();
|
|
786
|
+
});
|
|
775
787
|
document.querySelectorAll('[data-workstream]').forEach((el) => el.onclick = () => { state.workstream = el.dataset.workstream; state.role = 'all'; loadDoc(el.dataset.doc); });
|
|
776
788
|
document.querySelectorAll('[data-clear-workstream]').forEach((el) => el.onclick = () => { state.workstream = null; render(); });
|
|
777
789
|
document.querySelectorAll('[data-outline-toggle]').forEach((el) => el.onclick = () => { state.outlineOpen = !state.outlineOpen; render(); });
|
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
<!doctype html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
href="https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,400;0,6..72,500;0,6..72,600;1,6..72,400&family=Instrument+Serif:ital@0;1&display=swap"
|
|
12
|
-
/>
|
|
13
|
-
<link rel="stylesheet" href="/styles.css" />
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>Delano Viewer</title>
|
|
7
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
8
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
9
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
|
10
|
+
<link rel="stylesheet" href="/styles.css" />
|
|
14
11
|
</head>
|
|
15
12
|
<body>
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
<div id="root"></div>
|
|
14
|
+
<script src="https://unpkg.com/react@18.3.1/umd/react.development.js" crossorigin="anonymous"></script>
|
|
15
|
+
<script src="https://unpkg.com/react-dom@18.3.1/umd/react-dom.development.js" crossorigin="anonymous"></script>
|
|
16
|
+
<script src="https://unpkg.com/@babel/standalone@7.29.0/babel.min.js" crossorigin="anonymous"></script>
|
|
17
|
+
<script type="text/babel" src="/app.jsx"></script>
|
|
20
18
|
</body>
|
|
21
19
|
</html>
|