@blxzer/cursor-trellis 0.1.0 → 0.1.2
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/README.md +124 -5
- package/README.zh-CN.md +170 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +1 -33
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/init.d.ts +0 -13
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +7 -14
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/uninstall.d.ts.map +1 -1
- package/dist/commands/uninstall.js +3 -32
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +7 -84
- package/dist/commands/update.js.map +1 -1
- package/dist/configurators/index.d.ts +7 -8
- package/dist/configurators/index.d.ts.map +1 -1
- package/dist/configurators/index.js +11 -236
- package/dist/configurators/index.js.map +1 -1
- package/dist/configurators/workflow.d.ts.map +1 -1
- package/dist/configurators/workflow.js +5 -1
- package/dist/configurators/workflow.js.map +1 -1
- package/dist/migrations/manifests/0.1.1.json +9 -0
- package/dist/migrations/manifests/0.1.2.json +9 -0
- package/dist/templates/common/bundled-skills/smart-search-cli/SKILL.md +3 -3
- package/dist/templates/common/bundled-skills/trellis-meta/SKILL.md +4 -2
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-agents.md +8 -15
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-hooks.md +7 -7
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-skills-or-commands.md +18 -21
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/overview.md +2 -2
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/generated-files.md +10 -7
- package/dist/templates/common/bundled-skills/trellis-meta/references/local-architecture/overview.md +4 -4
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/agents.md +20 -31
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/hooks-and-settings.md +20 -31
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/overview.md +24 -40
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/platform-map.md +28 -59
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/skills-and-commands.md +12 -28
- package/dist/templates/common/bundled-skills/trellis-skill-creator/references/trellis-skill-locations.md +2 -2
- package/dist/templates/cursor/hooks.json +6 -0
- package/dist/templates/cursor/rules/retrieval-routing.mdc +57 -0
- package/dist/templates/extract.d.ts +0 -14
- package/dist/templates/extract.d.ts.map +1 -1
- package/dist/templates/extract.js +0 -34
- package/dist/templates/extract.js.map +1 -1
- package/dist/templates/markdown/agents.md +2 -6
- package/dist/templates/markdown/index.d.ts +1 -0
- package/dist/templates/markdown/index.d.ts.map +1 -1
- package/dist/templates/markdown/index.js +1 -0
- package/dist/templates/markdown/index.js.map +1 -1
- package/dist/templates/markdown/prompts/run-semantic-slice-12.md.txt +41 -0
- package/dist/templates/markdown/spec/guides/code-reuse-thinking-guide.md.txt +14 -14
- package/dist/templates/markdown/spec/guides/cross-layer-thinking-guide.md.txt +8 -20
- package/dist/templates/markdown/spec/guides/cross-platform-thinking-guide.md.txt +15 -14
- package/dist/templates/markdown/spec/guides/cursor-context-injection-guide.md.txt +4 -2
- package/dist/templates/markdown/spec/guides/cursor-semantic-compliance.md.txt +49 -0
- package/dist/templates/markdown/spec/guides/cursor-subagent-policy.md.txt +18 -5
- package/dist/templates/markdown/spec/guides/retrieval-daily-guide.md.txt +68 -20
- package/dist/templates/shared-hooks/index.d.ts +1 -1
- package/dist/templates/shared-hooks/index.d.ts.map +1 -1
- package/dist/templates/shared-hooks/index.js +1 -0
- package/dist/templates/shared-hooks/index.js.map +1 -1
- package/dist/templates/shared-hooks/inject-retrieval-plan.py +163 -0
- package/dist/templates/shared-hooks/inject-subagent-context.py +31 -567
- package/dist/templates/shared-hooks/research-end-retrieval-pack.py +2 -11
- package/dist/templates/trellis/index.d.ts +12 -0
- package/dist/templates/trellis/index.d.ts.map +1 -1
- package/dist/templates/trellis/index.js +24 -0
- package/dist/templates/trellis/index.js.map +1 -1
- package/dist/templates/trellis/scripts/aggregate_retrieval_telemetry.py +342 -0
- package/dist/templates/trellis/scripts/batch_plan_envelope.py +105 -0
- package/dist/templates/trellis/scripts/codegraph_session_smoke.py +76 -0
- package/dist/templates/trellis/scripts/common/active_task.py +116 -147
- package/dist/templates/trellis/scripts/common/cli_adapter.py +34 -710
- package/dist/templates/trellis/scripts/common/codebase_retrieval_router.py +49 -106
- package/dist/templates/trellis/scripts/common/git_context.py +17 -2
- package/dist/templates/trellis/scripts/common/project_file_stats.py +91 -0
- package/dist/templates/trellis/scripts/common/retrieval_adapter_metadata.py +9 -11
- package/dist/templates/trellis/scripts/common/retrieval_agent_instructions.py +313 -0
- package/dist/templates/trellis/scripts/common/retrieval_pack.py +0 -6
- package/dist/templates/trellis/scripts/common/retrieval_pack_context.py +0 -4
- package/dist/templates/trellis/scripts/common/retrieval_plan_gate.py +76 -0
- package/dist/templates/trellis/scripts/common/retrieval_result_ranking.py +253 -0
- package/dist/templates/trellis/scripts/common/retrieval_tool_classification.py +157 -0
- package/dist/templates/trellis/scripts/common/semantic_plan_gate.py +52 -0
- package/dist/templates/trellis/scripts/common/subagent_dispatch.py +527 -0
- package/dist/templates/trellis/scripts/common/task_store.py +32 -0
- package/dist/templates/trellis/scripts/common/workflow_phase.py +3 -24
- package/dist/templates/trellis/scripts/rank_retrieval_candidates.py +80 -0
- package/dist/templates/trellis/scripts/route_codebase_retrieval.py +38 -11
- package/dist/templates/trellis/scripts/score_evidence.py +112 -0
- package/dist/templates/trellis/scripts/task.py +26 -0
- package/dist/templates/trellis/workflow.md +844 -960
- package/dist/types/ai-tools.d.ts +13 -16
- package/dist/types/ai-tools.d.ts.map +1 -1
- package/dist/types/ai-tools.js +5 -238
- package/dist/types/ai-tools.js.map +1 -1
- package/dist/utils/codebase-retrieval-router.d.ts +1 -8
- package/dist/utils/codebase-retrieval-router.d.ts.map +1 -1
- package/dist/utils/codebase-retrieval-router.js +39 -180
- package/dist/utils/codebase-retrieval-router.js.map +1 -1
- package/dist/utils/project-capabilities.d.ts.map +1 -1
- package/dist/utils/project-capabilities.js +10 -24
- package/dist/utils/project-capabilities.js.map +1 -1
- package/dist/utils/retrieval-agent-instructions.d.ts +14 -0
- package/dist/utils/retrieval-agent-instructions.d.ts.map +1 -0
- package/dist/utils/retrieval-agent-instructions.js +221 -0
- package/dist/utils/retrieval-agent-instructions.js.map +1 -0
- package/dist/utils/retrieval-execution-telemetry.d.ts +43 -85
- package/dist/utils/retrieval-execution-telemetry.d.ts.map +1 -1
- package/dist/utils/retrieval-execution-telemetry.js +289 -22
- package/dist/utils/retrieval-execution-telemetry.js.map +1 -1
- package/dist/utils/retrieval-result-ranking.js +1 -1
- package/dist/utils/retrieval-result-ranking.js.map +1 -1
- package/dist/utils/retrieval-tool-classification.d.ts +32 -0
- package/dist/utils/retrieval-tool-classification.d.ts.map +1 -0
- package/dist/utils/retrieval-tool-classification.js +113 -0
- package/dist/utils/retrieval-tool-classification.js.map +1 -0
- package/dist/utils/uninstall-scrubbers.d.ts +0 -36
- package/dist/utils/uninstall-scrubbers.d.ts.map +1 -1
- package/dist/utils/uninstall-scrubbers.js +0 -184
- package/dist/utils/uninstall-scrubbers.js.map +1 -1
- package/package.json +4 -2
- package/dist/commands/mem.d.ts +0 -30
- package/dist/commands/mem.d.ts.map +0 -1
- package/dist/commands/mem.js +0 -424
- package/dist/commands/mem.js.map +0 -1
- package/dist/configurators/antigravity.d.ts +0 -7
- package/dist/configurators/antigravity.d.ts.map +0 -1
- package/dist/configurators/antigravity.js +0 -19
- package/dist/configurators/antigravity.js.map +0 -1
- package/dist/configurators/claude.d.ts +0 -9
- package/dist/configurators/claude.d.ts.map +0 -1
- package/dist/configurators/claude.js +0 -72
- package/dist/configurators/claude.js.map +0 -1
- package/dist/configurators/codebuddy.d.ts +0 -10
- package/dist/configurators/codebuddy.d.ts.map +0 -1
- package/dist/configurators/codebuddy.js +0 -30
- package/dist/configurators/codebuddy.js.map +0 -1
- package/dist/configurators/codex.d.ts +0 -8
- package/dist/configurators/codex.d.ts.map +0 -1
- package/dist/configurators/codex.js +0 -87
- package/dist/configurators/codex.js.map +0 -1
- package/dist/configurators/copilot.d.ts +0 -10
- package/dist/configurators/copilot.d.ts.map +0 -1
- package/dist/configurators/copilot.js +0 -51
- package/dist/configurators/copilot.js.map +0 -1
- package/dist/configurators/droid.d.ts +0 -10
- package/dist/configurators/droid.d.ts.map +0 -1
- package/dist/configurators/droid.js +0 -30
- package/dist/configurators/droid.js.map +0 -1
- package/dist/configurators/gemini.d.ts +0 -16
- package/dist/configurators/gemini.d.ts.map +0 -1
- package/dist/configurators/gemini.js +0 -38
- package/dist/configurators/gemini.js.map +0 -1
- package/dist/configurators/kilo.d.ts +0 -7
- package/dist/configurators/kilo.d.ts.map +0 -1
- package/dist/configurators/kilo.js +0 -19
- package/dist/configurators/kilo.js.map +0 -1
- package/dist/configurators/kiro.d.ts +0 -8
- package/dist/configurators/kiro.d.ts.map +0 -1
- package/dist/configurators/kiro.js +0 -24
- package/dist/configurators/kiro.js.map +0 -1
- package/dist/configurators/opencode.d.ts +0 -14
- package/dist/configurators/opencode.d.ts.map +0 -1
- package/dist/configurators/opencode.js +0 -96
- package/dist/configurators/opencode.js.map +0 -1
- package/dist/configurators/pi.d.ts +0 -3
- package/dist/configurators/pi.d.ts.map +0 -1
- package/dist/configurators/pi.js +0 -45
- package/dist/configurators/pi.js.map +0 -1
- package/dist/configurators/qoder.d.ts +0 -11
- package/dist/configurators/qoder.d.ts.map +0 -1
- package/dist/configurators/qoder.js +0 -31
- package/dist/configurators/qoder.js.map +0 -1
- package/dist/configurators/windsurf.d.ts +0 -7
- package/dist/configurators/windsurf.d.ts.map +0 -1
- package/dist/configurators/windsurf.js +0 -19
- package/dist/configurators/windsurf.js.map +0 -1
- package/dist/templates/claude/agents/trellis-check.md +0 -124
- package/dist/templates/claude/agents/trellis-implement.md +0 -110
- package/dist/templates/claude/agents/trellis-research.md +0 -137
- package/dist/templates/claude/index.d.ts +0 -22
- package/dist/templates/claude/index.d.ts.map +0 -1
- package/dist/templates/claude/index.js +0 -46
- package/dist/templates/claude/index.js.map +0 -1
- package/dist/templates/claude/settings.json +0 -84
- package/dist/templates/codebuddy/agents/trellis-check.md +0 -115
- package/dist/templates/codebuddy/agents/trellis-implement.md +0 -110
- package/dist/templates/codebuddy/agents/trellis-research.md +0 -137
- package/dist/templates/codebuddy/index.d.ts +0 -15
- package/dist/templates/codebuddy/index.d.ts.map +0 -1
- package/dist/templates/codebuddy/index.js +0 -15
- package/dist/templates/codebuddy/index.js.map +0 -1
- package/dist/templates/codebuddy/settings.json +0 -70
- package/dist/templates/codex/agents/trellis-check.toml +0 -67
- package/dist/templates/codex/agents/trellis-implement.toml +0 -40
- package/dist/templates/codex/agents/trellis-research.toml +0 -73
- package/dist/templates/codex/config.toml +0 -28
- package/dist/templates/codex/hooks/session-start.py +0 -575
- package/dist/templates/codex/hooks.json +0 -15
- package/dist/templates/codex/index.d.ts +0 -39
- package/dist/templates/codex/index.d.ts.map +0 -1
- package/dist/templates/codex/index.js +0 -85
- package/dist/templates/codex/index.js.map +0 -1
- package/dist/templates/codex/skills/before-dev/SKILL.md +0 -40
- package/dist/templates/codex/skills/brainstorm/SKILL.md +0 -112
- package/dist/templates/codex/skills/break-loop/SKILL.md +0 -130
- package/dist/templates/codex/skills/check/SKILL.md +0 -98
- package/dist/templates/codex/skills/check-cross-layer/SKILL.md +0 -158
- package/dist/templates/codex/skills/create-command/SKILL.md +0 -101
- package/dist/templates/codex/skills/finish-work/SKILL.md +0 -90
- package/dist/templates/codex/skills/improve-ut/SKILL.md +0 -69
- package/dist/templates/codex/skills/integrate-skill/SKILL.md +0 -221
- package/dist/templates/codex/skills/onboard/SKILL.md +0 -363
- package/dist/templates/codex/skills/record-session/SKILL.md +0 -67
- package/dist/templates/codex/skills/start/SKILL.md +0 -66
- package/dist/templates/codex/skills/update-spec/SKILL.md +0 -335
- package/dist/templates/copilot/hooks/session-start.py +0 -557
- package/dist/templates/copilot/hooks.json +0 -19
- package/dist/templates/copilot/index.d.ts +0 -23
- package/dist/templates/copilot/index.d.ts.map +0 -1
- package/dist/templates/copilot/index.js +0 -54
- package/dist/templates/copilot/index.js.map +0 -1
- package/dist/templates/copilot/prompts/before-dev.prompt.md +0 -39
- package/dist/templates/copilot/prompts/brainstorm.prompt.md +0 -111
- package/dist/templates/copilot/prompts/break-loop.prompt.md +0 -129
- package/dist/templates/copilot/prompts/check-cross-layer.prompt.md +0 -157
- package/dist/templates/copilot/prompts/check.prompt.md +0 -97
- package/dist/templates/copilot/prompts/create-command.prompt.md +0 -116
- package/dist/templates/copilot/prompts/finish-work.prompt.md +0 -99
- package/dist/templates/copilot/prompts/integrate-skill.prompt.md +0 -223
- package/dist/templates/copilot/prompts/onboard.prompt.md +0 -362
- package/dist/templates/copilot/prompts/parallel.prompt.md +0 -204
- package/dist/templates/copilot/prompts/record-session.prompt.md +0 -66
- package/dist/templates/copilot/prompts/start.prompt.md +0 -63
- package/dist/templates/copilot/prompts/update-spec.prompt.md +0 -358
- package/dist/templates/droid/droids/trellis-check.md +0 -107
- package/dist/templates/droid/droids/trellis-implement.md +0 -102
- package/dist/templates/droid/droids/trellis-research.md +0 -137
- package/dist/templates/droid/index.d.ts +0 -15
- package/dist/templates/droid/index.d.ts.map +0 -1
- package/dist/templates/droid/index.js +0 -15
- package/dist/templates/droid/index.js.map +0 -1
- package/dist/templates/droid/settings.json +0 -70
- package/dist/templates/gemini/agents/trellis-check.md +0 -107
- package/dist/templates/gemini/agents/trellis-implement.md +0 -102
- package/dist/templates/gemini/agents/trellis-research.md +0 -136
- package/dist/templates/gemini/index.d.ts +0 -13
- package/dist/templates/gemini/index.d.ts.map +0 -1
- package/dist/templates/gemini/index.js +0 -13
- package/dist/templates/gemini/index.js.map +0 -1
- package/dist/templates/gemini/settings.json +0 -28
- package/dist/templates/kiro/agents/trellis-check.json +0 -26
- package/dist/templates/kiro/agents/trellis-implement.json +0 -26
- package/dist/templates/kiro/agents/trellis-research.json +0 -30
- package/dist/templates/kiro/index.d.ts +0 -18
- package/dist/templates/kiro/index.d.ts.map +0 -1
- package/dist/templates/kiro/index.js +0 -18
- package/dist/templates/kiro/index.js.map +0 -1
- package/dist/templates/opencode/agents/trellis-check.md +0 -122
- package/dist/templates/opencode/agents/trellis-implement.md +0 -118
- package/dist/templates/opencode/agents/trellis-research.md +0 -145
- package/dist/templates/opencode/lib/session-utils.js +0 -667
- package/dist/templates/opencode/lib/trellis-context.js +0 -336
- package/dist/templates/opencode/package.json +0 -5
- package/dist/templates/opencode/plugins/inject-subagent-context.js +0 -495
- package/dist/templates/opencode/plugins/inject-workflow-state.js +0 -159
- package/dist/templates/opencode/plugins/session-start.js +0 -101
- package/dist/templates/pi/agents/trellis-check.md +0 -37
- package/dist/templates/pi/agents/trellis-implement.md +0 -42
- package/dist/templates/pi/agents/trellis-research.md +0 -25
- package/dist/templates/pi/extensions/trellis/index.ts.txt +0 -1600
- package/dist/templates/pi/index.d.ts +0 -5
- package/dist/templates/pi/index.d.ts.map +0 -1
- package/dist/templates/pi/index.js +0 -12
- package/dist/templates/pi/index.js.map +0 -1
- package/dist/templates/pi/settings.json +0 -12
- package/dist/templates/qoder/agents/trellis-check.md +0 -108
- package/dist/templates/qoder/agents/trellis-implement.md +0 -103
- package/dist/templates/qoder/agents/trellis-research.md +0 -137
- package/dist/templates/qoder/index.d.ts +0 -15
- package/dist/templates/qoder/index.d.ts.map +0 -1
- package/dist/templates/qoder/index.js +0 -15
- package/dist/templates/qoder/index.js.map +0 -1
- package/dist/templates/qoder/settings.json +0 -47
|
@@ -1,667 +0,0 @@
|
|
|
1
|
-
/* global process */
|
|
2
|
-
import { existsSync, readFileSync, readdirSync, statSync } from "fs"
|
|
3
|
-
import { join } from "path"
|
|
4
|
-
import { execFileSync } from "child_process"
|
|
5
|
-
import { platform } from "os"
|
|
6
|
-
import { debugLog } from "./trellis-context.js"
|
|
7
|
-
|
|
8
|
-
const PYTHON_CMD = platform() === "win32" ? "python" : "python3"
|
|
9
|
-
|
|
10
|
-
const FIRST_REPLY_NOTICE = `<first-reply-notice>
|
|
11
|
-
First visible reply: say once in Chinese that Trellis SessionStart context is loaded, then answer directly.
|
|
12
|
-
This notice is one-shot: do not repeat it after the first assistant reply in the same session.
|
|
13
|
-
</first-reply-notice>`
|
|
14
|
-
|
|
15
|
-
function hasCuratedJsonlEntry(jsonlPath) {
|
|
16
|
-
try {
|
|
17
|
-
const content = readFileSync(jsonlPath, "utf-8")
|
|
18
|
-
for (const rawLine of content.split(/\r?\n/)) {
|
|
19
|
-
const line = rawLine.trim()
|
|
20
|
-
if (!line) continue
|
|
21
|
-
try {
|
|
22
|
-
const row = JSON.parse(line)
|
|
23
|
-
if (row && typeof row === "object" && typeof row.file === "string" && row.file) {
|
|
24
|
-
return true
|
|
25
|
-
}
|
|
26
|
-
} catch {
|
|
27
|
-
// Ignore malformed line
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
} catch {
|
|
31
|
-
return false
|
|
32
|
-
}
|
|
33
|
-
return false
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
function getTaskStatus(ctx, platformInput = null) {
|
|
37
|
-
const active = ctx.getActiveTask(platformInput)
|
|
38
|
-
const taskRef = active.taskPath
|
|
39
|
-
if (!taskRef) {
|
|
40
|
-
return (
|
|
41
|
-
"Trellis framework: active\n" +
|
|
42
|
-
"Selected task: none\n" +
|
|
43
|
-
"Next-Action: Use the Task Dashboard to choose select/create/inspect/continue-without-task. " +
|
|
44
|
-
"Do not auto-select an existing task."
|
|
45
|
-
)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const taskDir = ctx.resolveTaskDir(taskRef)
|
|
49
|
-
|
|
50
|
-
if (active.stale || !taskDir || !existsSync(taskDir)) {
|
|
51
|
-
return (
|
|
52
|
-
`Trellis framework: active\nSelected task: ${taskRef}\n` +
|
|
53
|
-
"Status: STALE SELECTION\n" +
|
|
54
|
-
"Next-Action: Task directory not found. Run: python3 ./.trellis/scripts/task.py exit"
|
|
55
|
-
)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
let taskData = {}
|
|
59
|
-
const taskJsonPath = join(taskDir, "task.json")
|
|
60
|
-
if (existsSync(taskJsonPath)) {
|
|
61
|
-
try {
|
|
62
|
-
taskData = JSON.parse(readFileSync(taskJsonPath, "utf-8"))
|
|
63
|
-
} catch {
|
|
64
|
-
// Ignore parse errors
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const taskTitle = taskData.title || taskRef
|
|
69
|
-
const taskStatus = taskData.status || "unknown"
|
|
70
|
-
|
|
71
|
-
if (taskStatus === "completed") {
|
|
72
|
-
return `Status: COMPLETED\nTask: ${taskTitle}\nNext-Action: Run /trellis:finish-work. If the working tree is dirty, return to Phase 3.4 first.`
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const hasPrd = existsSync(join(taskDir, "prd.md"))
|
|
76
|
-
const hasDesign = existsSync(join(taskDir, "design.md"))
|
|
77
|
-
const hasImplementPlan = existsSync(join(taskDir, "implement.md"))
|
|
78
|
-
const artifactNames = ["prd.md", "design.md", "implement.md", "implement.jsonl", "check.jsonl"]
|
|
79
|
-
const present = artifactNames.filter(name => existsSync(join(taskDir, name)))
|
|
80
|
-
if (existsSync(join(taskDir, "research"))) present.push("research/")
|
|
81
|
-
const presentLine = present.length > 0 ? present.join(", ") : "(none)"
|
|
82
|
-
const implementJsonl = join(taskDir, "implement.jsonl")
|
|
83
|
-
const checkJsonl = join(taskDir, "check.jsonl")
|
|
84
|
-
const jsonlReady =
|
|
85
|
-
(!existsSync(implementJsonl) || hasCuratedJsonlEntry(implementJsonl)) &&
|
|
86
|
-
(!existsSync(checkJsonl) || hasCuratedJsonlEntry(checkJsonl))
|
|
87
|
-
|
|
88
|
-
if (taskStatus === "planning" && !hasPrd) {
|
|
89
|
-
return `Status: PLANNING\nTask: ${taskTitle}\nPresent: ${presentLine}\nNext-Action: Load trellis-brainstorm and write prd.md. Stay in planning.`
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (taskStatus === "planning") {
|
|
93
|
-
const missingComplex = []
|
|
94
|
-
if (!hasDesign) missingComplex.push("design.md")
|
|
95
|
-
if (!hasImplementPlan) missingComplex.push("implement.md")
|
|
96
|
-
const nextBits = []
|
|
97
|
-
if (missingComplex.length > 0) {
|
|
98
|
-
nextBits.push(
|
|
99
|
-
`Lightweight task can request execution readiness review with PRD-only; complex task must add ${missingComplex.join(", ")} before start-execution --check`,
|
|
100
|
-
)
|
|
101
|
-
} else {
|
|
102
|
-
nextBits.push("Planning artifacts are present; run `task.py start-execution <task> --check`, report PASS, then ask for explicit execution approval")
|
|
103
|
-
}
|
|
104
|
-
if (!jsonlReady) {
|
|
105
|
-
nextBits.push("curate `implement.jsonl` and `check.jsonl` before sub-agent mode start")
|
|
106
|
-
}
|
|
107
|
-
return `Status: PLANNING\nTask: ${taskTitle}\nPresent: ${presentLine}\nNext-Action: ${nextBits.join("; ")}. Do not enter implementation until explicit execution approval is granted.`
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
return (
|
|
111
|
-
`Status: ${String(taskStatus).toUpperCase()}\nTask: ${taskTitle}\n` +
|
|
112
|
-
`Present: ${presentLine}\n` +
|
|
113
|
-
"Next-Action: Follow the matching per-turn workflow-state. " +
|
|
114
|
-
"Implementation/check context order is jsonl entries -> `prd.md` -> `design.md if present` -> `implement.md if present`."
|
|
115
|
-
)
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function loadTrellisConfig(directory, contextKey = null) {
|
|
119
|
-
const scriptPath = join(directory, ".trellis", "scripts", "get_context.py")
|
|
120
|
-
if (!existsSync(scriptPath)) {
|
|
121
|
-
return { isMonorepo: false, packages: {}, specScope: null, activeTaskPackage: null, defaultPackage: null }
|
|
122
|
-
}
|
|
123
|
-
try {
|
|
124
|
-
const output = execFileSync(PYTHON_CMD, [scriptPath, "--mode", "packages", "--json"], {
|
|
125
|
-
cwd: directory,
|
|
126
|
-
timeout: 5000,
|
|
127
|
-
encoding: "utf-8",
|
|
128
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
129
|
-
env: {
|
|
130
|
-
...process.env,
|
|
131
|
-
...(contextKey ? { TRELLIS_CONTEXT_ID: contextKey } : {}),
|
|
132
|
-
},
|
|
133
|
-
})
|
|
134
|
-
const data = JSON.parse(output)
|
|
135
|
-
if (data.mode !== "monorepo") {
|
|
136
|
-
return { isMonorepo: false, packages: {}, specScope: null, activeTaskPackage: null, defaultPackage: null }
|
|
137
|
-
}
|
|
138
|
-
const pkgDict = {}
|
|
139
|
-
for (const pkg of (data.packages || [])) {
|
|
140
|
-
pkgDict[pkg.name] = pkg
|
|
141
|
-
}
|
|
142
|
-
return {
|
|
143
|
-
isMonorepo: true,
|
|
144
|
-
packages: pkgDict,
|
|
145
|
-
specScope: data.specScope || null,
|
|
146
|
-
activeTaskPackage: data.activeTaskPackage || null,
|
|
147
|
-
defaultPackage: data.defaultPackage || null,
|
|
148
|
-
}
|
|
149
|
-
} catch (e) {
|
|
150
|
-
debugLog("session", "loadTrellisConfig error:", e.message)
|
|
151
|
-
return { isMonorepo: false, packages: {}, specScope: null, activeTaskPackage: null, defaultPackage: null }
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function checkLegacySpec(directory, config) {
|
|
156
|
-
if (!config.isMonorepo || Object.keys(config.packages).length === 0) {
|
|
157
|
-
return null
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const specDir = join(directory, ".trellis", "spec")
|
|
161
|
-
if (!existsSync(specDir)) return null
|
|
162
|
-
|
|
163
|
-
let hasLegacy = false
|
|
164
|
-
for (const name of ["backend", "frontend"]) {
|
|
165
|
-
if (existsSync(join(specDir, name, "index.md"))) {
|
|
166
|
-
hasLegacy = true
|
|
167
|
-
break
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
if (!hasLegacy) return null
|
|
171
|
-
|
|
172
|
-
const pkgNames = Object.keys(config.packages).sort()
|
|
173
|
-
const missing = pkgNames.filter(name => !existsSync(join(specDir, name)))
|
|
174
|
-
|
|
175
|
-
if (missing.length === 0) return null
|
|
176
|
-
|
|
177
|
-
if (missing.length === pkgNames.length) {
|
|
178
|
-
return (
|
|
179
|
-
`[!] Legacy spec structure detected: found \`spec/backend/\` or \`spec/frontend/\` ` +
|
|
180
|
-
`but no package-scoped \`spec/<package>/\` directories.\n` +
|
|
181
|
-
`Monorepo packages: ${pkgNames.join(", ")}\n` +
|
|
182
|
-
`Please reorganize: \`spec/backend/\` -> \`spec/<package>/backend/\``
|
|
183
|
-
)
|
|
184
|
-
}
|
|
185
|
-
return (
|
|
186
|
-
`[!] Partial spec migration detected: packages ${missing.join(", ")} ` +
|
|
187
|
-
`still missing \`spec/<pkg>/\` directory.\n` +
|
|
188
|
-
`Please complete migration for all packages.`
|
|
189
|
-
)
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function resolveSpecScope(config) {
|
|
193
|
-
if (!config.isMonorepo || Object.keys(config.packages).length === 0) {
|
|
194
|
-
return null
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
const { specScope, activeTaskPackage, defaultPackage, packages } = config
|
|
198
|
-
if (specScope == null) return null
|
|
199
|
-
|
|
200
|
-
if (specScope === "active_task") {
|
|
201
|
-
if (activeTaskPackage && activeTaskPackage in packages) return new Set([activeTaskPackage])
|
|
202
|
-
if (defaultPackage && defaultPackage in packages) return new Set([defaultPackage])
|
|
203
|
-
return null
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
if (Array.isArray(specScope)) {
|
|
207
|
-
const valid = new Set()
|
|
208
|
-
for (const entry of specScope) {
|
|
209
|
-
if (entry in packages) {
|
|
210
|
-
valid.add(entry)
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
if (valid.size > 0) return valid
|
|
214
|
-
if (activeTaskPackage && activeTaskPackage in packages) return new Set([activeTaskPackage])
|
|
215
|
-
if (defaultPackage && defaultPackage in packages) return new Set([defaultPackage])
|
|
216
|
-
return null
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
return null
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
function collectSpecIndexPaths(directory, allowedPkgs) {
|
|
223
|
-
const specDir = join(directory, ".trellis", "spec")
|
|
224
|
-
const paths = []
|
|
225
|
-
|
|
226
|
-
const guidesIndex = join(specDir, "guides", "index.md")
|
|
227
|
-
if (existsSync(guidesIndex)) {
|
|
228
|
-
paths.push(".trellis/spec/guides/index.md")
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
if (!existsSync(specDir)) return paths
|
|
232
|
-
|
|
233
|
-
try {
|
|
234
|
-
const subs = readdirSync(specDir).filter(name => {
|
|
235
|
-
if (name.startsWith(".") || name === "guides") return false
|
|
236
|
-
try {
|
|
237
|
-
return statSync(join(specDir, name)).isDirectory()
|
|
238
|
-
} catch {
|
|
239
|
-
return false
|
|
240
|
-
}
|
|
241
|
-
}).sort()
|
|
242
|
-
|
|
243
|
-
for (const sub of subs) {
|
|
244
|
-
const indexFile = join(specDir, sub, "index.md")
|
|
245
|
-
if (existsSync(indexFile)) {
|
|
246
|
-
paths.push(`.trellis/spec/${sub}/index.md`)
|
|
247
|
-
} else {
|
|
248
|
-
if (allowedPkgs !== null && !allowedPkgs.has(sub)) continue
|
|
249
|
-
try {
|
|
250
|
-
const nested = readdirSync(join(specDir, sub)).filter(name => {
|
|
251
|
-
try {
|
|
252
|
-
return statSync(join(specDir, sub, name)).isDirectory()
|
|
253
|
-
} catch {
|
|
254
|
-
return false
|
|
255
|
-
}
|
|
256
|
-
}).sort()
|
|
257
|
-
for (const layer of nested) {
|
|
258
|
-
const nestedIndex = join(specDir, sub, layer, "index.md")
|
|
259
|
-
if (existsSync(nestedIndex)) {
|
|
260
|
-
paths.push(`.trellis/spec/${sub}/${layer}/index.md`)
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
} catch {
|
|
264
|
-
// Ignore directory read errors
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
} catch {
|
|
269
|
-
// Ignore spec directory read errors
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
return paths
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
function readDeveloper(directory) {
|
|
276
|
-
try {
|
|
277
|
-
const content = readFileSync(join(directory, ".trellis", ".developer"), "utf-8")
|
|
278
|
-
for (const line of content.split(/\r?\n/)) {
|
|
279
|
-
if (line.startsWith("name=")) return line.slice("name=".length).trim()
|
|
280
|
-
}
|
|
281
|
-
} catch {
|
|
282
|
-
// Ignore missing developer file
|
|
283
|
-
}
|
|
284
|
-
return "(not initialized)"
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
function runGit(directory, args) {
|
|
288
|
-
try {
|
|
289
|
-
return execFileSync("git", args, {
|
|
290
|
-
cwd: directory,
|
|
291
|
-
timeout: 3000,
|
|
292
|
-
encoding: "utf-8",
|
|
293
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
294
|
-
}).trim()
|
|
295
|
-
} catch {
|
|
296
|
-
return ""
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
function buildCompactCurrentState(ctx, platformInput, specIndexPaths) {
|
|
301
|
-
const directory = ctx.directory
|
|
302
|
-
const lines = []
|
|
303
|
-
lines.push(`Developer: ${readDeveloper(directory)}`)
|
|
304
|
-
|
|
305
|
-
const branch = runGit(directory, ["branch", "--show-current"]) || "(detached)"
|
|
306
|
-
const dirtyCount = runGit(directory, ["status", "--porcelain"])
|
|
307
|
-
.split(/\r?\n/)
|
|
308
|
-
.filter(line => line.trim()).length
|
|
309
|
-
lines.push(`Git: branch ${branch}; ${dirtyCount === 0 ? "clean" : `dirty ${dirtyCount} paths`}.`)
|
|
310
|
-
|
|
311
|
-
const active = ctx.getActiveTask(platformInput)
|
|
312
|
-
lines.push("Trellis framework: active")
|
|
313
|
-
if (active.taskPath) {
|
|
314
|
-
const taskDir = ctx.resolveTaskDir(active.taskPath)
|
|
315
|
-
let status = "unknown"
|
|
316
|
-
if (taskDir) {
|
|
317
|
-
try {
|
|
318
|
-
const data = JSON.parse(readFileSync(join(taskDir, "task.json"), "utf-8"))
|
|
319
|
-
status = data.status || "unknown"
|
|
320
|
-
} catch {
|
|
321
|
-
// Ignore parse errors
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
lines.push(`Selected task: ${active.taskPath}; status=${status}.`)
|
|
325
|
-
} else {
|
|
326
|
-
lines.push("Selected task: none.")
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
const tasksDir = join(directory, ".trellis", "tasks")
|
|
330
|
-
if (existsSync(tasksDir)) {
|
|
331
|
-
try {
|
|
332
|
-
const activeTasks = readdirSync(tasksDir, { withFileTypes: true })
|
|
333
|
-
.filter(entry => entry.isDirectory() && entry.name !== "archive" && existsSync(join(tasksDir, entry.name, "task.json")))
|
|
334
|
-
lines.push(`Active tasks: ${activeTasks.length} total. Use the Task Dashboard for routing; use \`python3 ./.trellis/scripts/task.py list --mine\` only for raw inspection.`)
|
|
335
|
-
} catch {
|
|
336
|
-
// Ignore task list errors
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
const developer = readDeveloper(directory)
|
|
341
|
-
const workspaceDir = join(directory, ".trellis", "workspace", developer)
|
|
342
|
-
if (developer !== "(not initialized)" && existsSync(workspaceDir)) {
|
|
343
|
-
try {
|
|
344
|
-
const journals = readdirSync(workspaceDir)
|
|
345
|
-
.filter(name => /^journal-\d+\.md$/.test(name))
|
|
346
|
-
.sort((a, b) => Number(a.match(/\d+/)?.[0] || 0) - Number(b.match(/\d+/)?.[0] || 0))
|
|
347
|
-
const journal = journals[journals.length - 1]
|
|
348
|
-
if (journal) {
|
|
349
|
-
const journalPath = join(workspaceDir, journal)
|
|
350
|
-
const lineCount = readFileSync(journalPath, "utf-8").split(/\r?\n/).length
|
|
351
|
-
lines.push(`Journal: .trellis/workspace/${developer}/${journal}, ${lineCount} / 2000 lines.`)
|
|
352
|
-
}
|
|
353
|
-
} catch {
|
|
354
|
-
// Ignore journal errors
|
|
355
|
-
}
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
if (specIndexPaths.length > 0) {
|
|
359
|
-
lines.push(`Spec indexes: ${specIndexPaths.length} available.`)
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
return lines.join("\n")
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
function readTaskData(taskDir) {
|
|
366
|
-
try {
|
|
367
|
-
return JSON.parse(readFileSync(join(taskDir, "task.json"), "utf-8"))
|
|
368
|
-
} catch {
|
|
369
|
-
return null
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
function readActiveTasks(directory) {
|
|
374
|
-
const tasksDir = join(directory, ".trellis", "tasks")
|
|
375
|
-
const tasks = new Map()
|
|
376
|
-
if (!existsSync(tasksDir)) return tasks
|
|
377
|
-
|
|
378
|
-
try {
|
|
379
|
-
const entries = readdirSync(tasksDir, { withFileTypes: true })
|
|
380
|
-
.filter(entry => entry.isDirectory() && entry.name !== "archive")
|
|
381
|
-
.sort((a, b) => a.name.localeCompare(b.name))
|
|
382
|
-
for (const entry of entries) {
|
|
383
|
-
const taskDir = join(tasksDir, entry.name)
|
|
384
|
-
const data = readTaskData(taskDir)
|
|
385
|
-
if (!data || typeof data !== "object") continue
|
|
386
|
-
tasks.set(entry.name, {
|
|
387
|
-
dirName: entry.name,
|
|
388
|
-
status: data.status || "unknown",
|
|
389
|
-
assignee: data.assignee || "-",
|
|
390
|
-
parent: data.parent || null,
|
|
391
|
-
children: Array.isArray(data.children) ? data.children : [],
|
|
392
|
-
})
|
|
393
|
-
}
|
|
394
|
-
} catch {
|
|
395
|
-
// Ignore task directory read errors
|
|
396
|
-
}
|
|
397
|
-
return tasks
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
function childrenProgress(children, statuses) {
|
|
401
|
-
if (!Array.isArray(children) || children.length === 0) return ""
|
|
402
|
-
const done = children.filter(
|
|
403
|
-
child => !statuses.has(child) || ["completed", "done"].includes(statuses.get(child)),
|
|
404
|
-
).length
|
|
405
|
-
return ` [${done}/${children.length} done]`
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
function appendDashboardTask(lines, name, tasks, statuses, printed, indent = 0) {
|
|
409
|
-
const task = tasks.get(name)
|
|
410
|
-
if (!task) return
|
|
411
|
-
printed.add(name)
|
|
412
|
-
const prefix = " ".repeat(indent) + " - "
|
|
413
|
-
const progress = childrenProgress(task.children, statuses)
|
|
414
|
-
lines.push(`${prefix}.trellis/tasks/${name} (${task.status})${progress} [${task.assignee || "-"}]`)
|
|
415
|
-
for (const childName of task.children) {
|
|
416
|
-
if (tasks.has(childName)) {
|
|
417
|
-
appendDashboardTask(lines, childName, tasks, statuses, printed, indent + 1)
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
function buildFallbackTaskDashboard(ctx, platformInput) {
|
|
423
|
-
const active = ctx.getActiveTask(platformInput)
|
|
424
|
-
const lines = [
|
|
425
|
-
"Task Dashboard",
|
|
426
|
-
"Trellis framework: active",
|
|
427
|
-
active.taskPath
|
|
428
|
-
? `Selected task: ${active.taskPath}${active.source ? ` (${active.source})` : ""}`
|
|
429
|
-
: "Selected task: none",
|
|
430
|
-
"",
|
|
431
|
-
]
|
|
432
|
-
|
|
433
|
-
const tasks = readActiveTasks(ctx.directory)
|
|
434
|
-
const statuses = new Map([...tasks.entries()].map(([name, task]) => [name, task.status]))
|
|
435
|
-
if (tasks.size === 0) {
|
|
436
|
-
lines.push("Tasks: none")
|
|
437
|
-
} else {
|
|
438
|
-
const printed = new Set()
|
|
439
|
-
for (const status of ["planning", "in_progress", "review", "blocked"]) {
|
|
440
|
-
const names = [...tasks.keys()]
|
|
441
|
-
.filter(name => tasks.get(name)?.status === status && !tasks.get(name)?.parent)
|
|
442
|
-
.sort()
|
|
443
|
-
if (names.length === 0) continue
|
|
444
|
-
lines.push(`${status.replace(/_/g, " ").replace(/\b\w/g, c => c.toUpperCase())}:`)
|
|
445
|
-
for (const name of names) {
|
|
446
|
-
appendDashboardTask(lines, name, tasks, statuses, printed)
|
|
447
|
-
}
|
|
448
|
-
lines.push("")
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
const otherNames = [...tasks.keys()]
|
|
452
|
-
.filter(name => !printed.has(name) && !tasks.get(name)?.parent)
|
|
453
|
-
.sort()
|
|
454
|
-
if (otherNames.length > 0) {
|
|
455
|
-
lines.push("Other:")
|
|
456
|
-
for (const name of otherNames) {
|
|
457
|
-
appendDashboardTask(lines, name, tasks, statuses, printed)
|
|
458
|
-
}
|
|
459
|
-
lines.push("")
|
|
460
|
-
}
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
lines.push("Suggested actions:")
|
|
464
|
-
lines.push(" - Select a task: python3 ./.trellis/scripts/task.py select <task>")
|
|
465
|
-
lines.push(" - Create a task: python3 ./.trellis/scripts/task.py create \"<title>\" --slug <slug>")
|
|
466
|
-
lines.push(" - Inspect raw list: python3 ./.trellis/scripts/task.py list")
|
|
467
|
-
lines.push(" - Continue without a task only for No Task or Micro-Grill work")
|
|
468
|
-
|
|
469
|
-
const developer = readDeveloper(ctx.directory)
|
|
470
|
-
if (developer !== "(not initialized)") {
|
|
471
|
-
lines.push(`Developer: ${developer}`)
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
return lines.map(line => line.trimEnd()).join("\n").trimEnd()
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
function buildPythonTaskDashboard(directory, contextKey) {
|
|
478
|
-
const scriptPath = join(directory, ".trellis", "scripts", "task.py")
|
|
479
|
-
if (!existsSync(scriptPath)) return ""
|
|
480
|
-
|
|
481
|
-
try {
|
|
482
|
-
return execFileSync(PYTHON_CMD, [scriptPath, "dashboard"], {
|
|
483
|
-
cwd: directory,
|
|
484
|
-
timeout: 5000,
|
|
485
|
-
encoding: "utf-8",
|
|
486
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
487
|
-
env: {
|
|
488
|
-
...process.env,
|
|
489
|
-
...(contextKey ? { TRELLIS_CONTEXT_ID: contextKey } : {}),
|
|
490
|
-
},
|
|
491
|
-
}).trim()
|
|
492
|
-
} catch {
|
|
493
|
-
return ""
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
function buildTaskDashboard(ctx, platformInput, contextKey) {
|
|
498
|
-
return buildPythonTaskDashboard(ctx.directory, contextKey) ||
|
|
499
|
-
buildFallbackTaskDashboard(ctx, platformInput)
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
export function buildSessionContext(ctx, platformInput = null) {
|
|
503
|
-
const directory = ctx.directory
|
|
504
|
-
const contextKey = typeof ctx.getContextKey === "function"
|
|
505
|
-
? ctx.getContextKey(platformInput)
|
|
506
|
-
: null
|
|
507
|
-
|
|
508
|
-
const config = loadTrellisConfig(directory, contextKey)
|
|
509
|
-
const allowedPkgs = resolveSpecScope(config)
|
|
510
|
-
const paths = collectSpecIndexPaths(directory, allowedPkgs)
|
|
511
|
-
|
|
512
|
-
const parts = []
|
|
513
|
-
|
|
514
|
-
parts.push(`<session-context>
|
|
515
|
-
Trellis compact SessionStart context. Use it to orient the session; load details on demand.
|
|
516
|
-
</session-context>`)
|
|
517
|
-
parts.push(FIRST_REPLY_NOTICE)
|
|
518
|
-
|
|
519
|
-
const legacyWarning = checkLegacySpec(directory, config)
|
|
520
|
-
if (legacyWarning) {
|
|
521
|
-
parts.push(`<migration-warning>\n${legacyWarning}\n</migration-warning>`)
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
parts.push("<current-state>")
|
|
525
|
-
parts.push(buildCompactCurrentState(ctx, platformInput, paths))
|
|
526
|
-
parts.push("</current-state>")
|
|
527
|
-
|
|
528
|
-
parts.push("<task-dashboard>")
|
|
529
|
-
parts.push(buildTaskDashboard(ctx, platformInput, contextKey))
|
|
530
|
-
parts.push("</task-dashboard>")
|
|
531
|
-
|
|
532
|
-
const workflowContent = ctx.readProjectFile(".trellis/workflow.md")
|
|
533
|
-
if (workflowContent) {
|
|
534
|
-
const allLines = workflowContent.split("\n")
|
|
535
|
-
const overviewLines = [
|
|
536
|
-
"# Development Workflow - Session Summary",
|
|
537
|
-
"Full guide: .trellis/workflow.md. Step detail: `python3 ./.trellis/scripts/get_context.py --mode phase --step <X.Y>`.",
|
|
538
|
-
"",
|
|
539
|
-
]
|
|
540
|
-
|
|
541
|
-
let rangeStart = -1
|
|
542
|
-
let rangeEnd = allLines.length
|
|
543
|
-
for (let i = 0; i < allLines.length; i++) {
|
|
544
|
-
const stripped = allLines[i].trim()
|
|
545
|
-
if (rangeStart === -1 && stripped === "## Phase Index") {
|
|
546
|
-
rangeStart = i
|
|
547
|
-
} else if (rangeStart !== -1 && stripped === "## Phase 1: Plan") {
|
|
548
|
-
rangeEnd = i
|
|
549
|
-
break
|
|
550
|
-
}
|
|
551
|
-
}
|
|
552
|
-
if (rangeStart !== -1) {
|
|
553
|
-
const strippedStateBlocks = allLines
|
|
554
|
-
.slice(rangeStart, rangeEnd)
|
|
555
|
-
.join("\n")
|
|
556
|
-
.replace(/\[workflow-state:([A-Za-z0-9_-]+)\]\s*\n[\s\S]*?\n\s*\[\/workflow-state:\1\]\n?/g, "")
|
|
557
|
-
.replace(/<!--[\s\S]*?-->/g, "")
|
|
558
|
-
.replace(/^\[(?!\/?workflow-state:)\/?[^\]\n]+\]\s*\n?/gm, "")
|
|
559
|
-
.replace(/\n{3,}/g, "\n\n")
|
|
560
|
-
overviewLines.push(strippedStateBlocks.trimEnd())
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
parts.push("<trellis-workflow>")
|
|
564
|
-
parts.push(overviewLines.join("\n").trimEnd())
|
|
565
|
-
parts.push("</trellis-workflow>")
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
parts.push("<guidelines>")
|
|
569
|
-
parts.push(
|
|
570
|
-
"Task context order for implementation/check: jsonl entries -> `prd.md` -> " +
|
|
571
|
-
"`design.md if present` -> `implement.md if present`. Missing optional artifacts " +
|
|
572
|
-
"are skipped for lightweight tasks.\n"
|
|
573
|
-
)
|
|
574
|
-
|
|
575
|
-
if (paths.length > 0) {
|
|
576
|
-
parts.push("## Available indexes (read on demand)")
|
|
577
|
-
for (const p of paths) {
|
|
578
|
-
parts.push(`- ${p}`)
|
|
579
|
-
}
|
|
580
|
-
parts.push("")
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
parts.push(
|
|
584
|
-
"Discover more via: " +
|
|
585
|
-
"`python3 ./.trellis/scripts/get_context.py --mode packages`"
|
|
586
|
-
)
|
|
587
|
-
parts.push("</guidelines>")
|
|
588
|
-
|
|
589
|
-
const taskStatus = getTaskStatus(ctx, platformInput)
|
|
590
|
-
parts.push(`<task-status>\n${taskStatus}\n</task-status>`)
|
|
591
|
-
|
|
592
|
-
parts.push(`<ready>
|
|
593
|
-
Context loaded. Follow <task-status>. Load workflow/spec/task details only when needed.
|
|
594
|
-
</ready>`)
|
|
595
|
-
|
|
596
|
-
return parts.join("\n\n")
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
function getTrellisMetadata(metadata) {
|
|
600
|
-
if (!metadata || typeof metadata !== "object") {
|
|
601
|
-
return {}
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
const trellis = metadata.trellis
|
|
605
|
-
if (!trellis || typeof trellis !== "object") {
|
|
606
|
-
return {}
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
return trellis
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
function markPartAsSessionStart(part) {
|
|
613
|
-
const metadata = part.metadata && typeof part.metadata === "object"
|
|
614
|
-
? part.metadata
|
|
615
|
-
: {}
|
|
616
|
-
part.metadata = {
|
|
617
|
-
...metadata,
|
|
618
|
-
trellis: {
|
|
619
|
-
...getTrellisMetadata(metadata),
|
|
620
|
-
sessionStart: true,
|
|
621
|
-
},
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
function hasSessionStartMarker(part) {
|
|
626
|
-
if (!part || part.type !== "text" || typeof part.text !== "string") {
|
|
627
|
-
return false
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
return getTrellisMetadata(part.metadata).sessionStart === true
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
export function hasInjectedTrellisContext(messages) {
|
|
634
|
-
if (!Array.isArray(messages)) {
|
|
635
|
-
return false
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
return messages.some(message => {
|
|
639
|
-
if (!message?.info || message.info.role !== "user" || !Array.isArray(message.parts)) {
|
|
640
|
-
return false
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
return message.parts.some(hasSessionStartMarker)
|
|
644
|
-
})
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
export async function hasPersistedInjectedContext(client, directory, sessionID) {
|
|
648
|
-
try {
|
|
649
|
-
const response = await client.session.messages({
|
|
650
|
-
path: { id: sessionID },
|
|
651
|
-
query: { directory },
|
|
652
|
-
throwOnError: true,
|
|
653
|
-
})
|
|
654
|
-
return hasInjectedTrellisContext(response.data || [])
|
|
655
|
-
} catch (error) {
|
|
656
|
-
debugLog(
|
|
657
|
-
"session",
|
|
658
|
-
"Failed to read session history for dedupe:",
|
|
659
|
-
error instanceof Error ? error.message : String(error),
|
|
660
|
-
)
|
|
661
|
-
return false
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
|
|
665
|
-
export function markContextInjected(part) {
|
|
666
|
-
markPartAsSessionStart(part)
|
|
667
|
-
}
|