@mindfoldhq/trellis 0.6.7 → 0.6.9
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 +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +38 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/commands/channel/adapters/codex.d.ts +7 -1
- package/dist/commands/channel/adapters/codex.d.ts.map +1 -1
- package/dist/commands/channel/adapters/codex.js +19 -2
- package/dist/commands/channel/adapters/codex.js.map +1 -1
- package/dist/commands/channel/adapters/index.d.ts +3 -1
- package/dist/commands/channel/adapters/index.d.ts.map +1 -1
- package/dist/commands/channel/adapters/index.js +1 -1
- package/dist/commands/channel/adapters/index.js.map +1 -1
- package/dist/commands/channel/agent-loader.d.ts +2 -2
- package/dist/commands/channel/agent-loader.d.ts.map +1 -1
- package/dist/commands/channel/agent-loader.js +9 -5
- package/dist/commands/channel/agent-loader.js.map +1 -1
- package/dist/commands/channel/context-loader.d.ts +1 -1
- package/dist/commands/channel/context-loader.d.ts.map +1 -1
- package/dist/commands/channel/context-loader.js +36 -15
- package/dist/commands/channel/context-loader.js.map +1 -1
- package/dist/commands/channel/context-trust.d.ts +31 -0
- package/dist/commands/channel/context-trust.d.ts.map +1 -0
- package/dist/commands/channel/context-trust.js +139 -0
- package/dist/commands/channel/context-trust.js.map +1 -0
- package/dist/commands/channel/index.d.ts.map +1 -1
- package/dist/commands/channel/index.js +4 -0
- package/dist/commands/channel/index.js.map +1 -1
- package/dist/commands/channel/spawn.d.ts +3 -0
- package/dist/commands/channel/spawn.d.ts.map +1 -1
- package/dist/commands/channel/spawn.js +5 -2
- package/dist/commands/channel/spawn.js.map +1 -1
- package/dist/commands/channel/supervisor.d.ts +3 -0
- package/dist/commands/channel/supervisor.d.ts.map +1 -1
- package/dist/commands/channel/supervisor.js +1 -0
- package/dist/commands/channel/supervisor.js.map +1 -1
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/mem.d.ts.map +1 -1
- package/dist/commands/mem.js +30 -9
- package/dist/commands/mem.js.map +1 -1
- package/dist/commands/update.d.ts +12 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +75 -7
- package/dist/commands/update.js.map +1 -1
- package/dist/configurators/codex.d.ts +36 -0
- package/dist/configurators/codex.d.ts.map +1 -1
- package/dist/configurators/codex.js +111 -13
- package/dist/configurators/codex.js.map +1 -1
- package/dist/configurators/grok.d.ts +22 -0
- package/dist/configurators/grok.d.ts.map +1 -0
- package/dist/configurators/grok.js +58 -0
- package/dist/configurators/grok.js.map +1 -0
- package/dist/configurators/index.d.ts.map +1 -1
- package/dist/configurators/index.js +17 -2
- package/dist/configurators/index.js.map +1 -1
- package/dist/configurators/kimi.d.ts +29 -0
- package/dist/configurators/kimi.d.ts.map +1 -0
- package/dist/configurators/kimi.js +81 -0
- package/dist/configurators/kimi.js.map +1 -0
- package/dist/configurators/pi.js +9 -9
- package/dist/configurators/pi.js.map +1 -1
- package/dist/configurators/shared.d.ts.map +1 -1
- package/dist/configurators/shared.js +12 -4
- package/dist/configurators/shared.js.map +1 -1
- package/dist/configurators/snow.d.ts +31 -0
- package/dist/configurators/snow.d.ts.map +1 -0
- package/dist/configurators/snow.js +95 -0
- package/dist/configurators/snow.js.map +1 -0
- package/dist/configurators/workflow.d.ts +14 -0
- package/dist/configurators/workflow.d.ts.map +1 -1
- package/dist/configurators/workflow.js +37 -1
- package/dist/configurators/workflow.js.map +1 -1
- package/dist/configurators/zcode.d.ts +9 -4
- package/dist/configurators/zcode.d.ts.map +1 -1
- package/dist/configurators/zcode.js +41 -12
- package/dist/configurators/zcode.js.map +1 -1
- package/dist/migrations/manifests/0.5.0-beta.0.json +1 -1
- package/dist/migrations/manifests/0.6.8.json +17 -0
- package/dist/migrations/manifests/0.6.9.json +9 -0
- package/dist/templates/codex/agents/trellis-check.toml +7 -12
- package/dist/templates/codex/agents/trellis-implement.toml +7 -12
- package/dist/templates/codex/agents/trellis-research.toml +15 -15
- package/dist/templates/codex/config.toml +11 -0
- package/dist/templates/codex/hooks/session-start.py +9 -3
- package/dist/templates/codex/hooks.json +12 -0
- package/dist/templates/codex/skills/brainstorm/SKILL.md +40 -13
- package/dist/templates/common/bundled-skills/trellis-meta/SKILL.md +2 -2
- package/dist/templates/common/bundled-skills/trellis-meta/references/customize-local/change-skills-or-commands.md +1 -1
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/agents.md +1 -0
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/hooks-and-settings.md +1 -1
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/overview.md +1 -1
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/platform-map.md +10 -4
- package/dist/templates/common/bundled-skills/trellis-meta/references/platform-files/skills-and-commands.md +2 -1
- package/dist/templates/common/bundled-skills/trellis-session-insight/SKILL.md +1 -1
- package/dist/templates/common/skills/brainstorm.md +40 -13
- package/dist/templates/copilot/prompts/brainstorm.prompt.md +40 -13
- package/dist/templates/grok/agents/trellis-check.md +105 -0
- package/dist/templates/grok/agents/trellis-implement.md +116 -0
- package/dist/templates/grok/agents/trellis-research.md +146 -0
- package/dist/templates/grok/index.d.ts +16 -0
- package/dist/templates/grok/index.d.ts.map +1 -0
- package/dist/templates/grok/index.js +19 -0
- package/dist/templates/grok/index.js.map +1 -0
- package/dist/templates/kimi/agents/trellis-check.md +103 -0
- package/dist/templates/kimi/agents/trellis-implement.md +114 -0
- package/dist/templates/kimi/agents/trellis-research.md +144 -0
- package/dist/templates/kimi/index.d.ts +19 -0
- package/dist/templates/kimi/index.d.ts.map +1 -0
- package/dist/templates/kimi/index.js +22 -0
- package/dist/templates/kimi/index.js.map +1 -0
- package/dist/templates/omp/extensions/trellis/index.ts.txt +133 -9
- package/dist/templates/opencode/lib/session-utils.js +8 -2
- package/dist/templates/opencode/lib/trellis-context.js +263 -43
- package/dist/templates/opencode/plugins/inject-subagent-context.js +89 -35
- package/dist/templates/opencode/plugins/inject-workflow-state.js +90 -5
- package/dist/templates/pi/extensions/trellis/index.ts.txt +278 -24
- package/dist/templates/pi/settings.json +0 -3
- package/dist/templates/shared-hooks/index.d.ts +11 -5
- package/dist/templates/shared-hooks/index.d.ts.map +1 -1
- package/dist/templates/shared-hooks/index.js +16 -5
- package/dist/templates/shared-hooks/index.js.map +1 -1
- package/dist/templates/shared-hooks/inject-subagent-context.py +466 -104
- package/dist/templates/shared-hooks/inject-workflow-state.py +86 -29
- package/dist/templates/shared-hooks/session-start.py +26 -6
- package/dist/templates/snow/SNOW.md +86 -0
- package/dist/templates/snow/agents/trellis-check.md +135 -0
- package/dist/templates/snow/agents/trellis-implement.md +153 -0
- package/dist/templates/snow/agents/trellis-research.md +114 -0
- package/dist/templates/snow/hooks/beforeSubAgentStart.json +15 -0
- package/dist/templates/snow/hooks/onSessionStart.json +15 -0
- package/dist/templates/snow/hooks/onUserMessage.json +15 -0
- package/dist/templates/snow/hooks/write-trellis-context.py +644 -0
- package/dist/templates/snow/index.d.ts +26 -0
- package/dist/templates/snow/index.d.ts.map +1 -0
- package/dist/templates/snow/index.js +36 -0
- package/dist/templates/snow/index.js.map +1 -0
- package/dist/templates/template-utils.d.ts.map +1 -1
- package/dist/templates/template-utils.js +5 -1
- package/dist/templates/template-utils.js.map +1 -1
- package/dist/templates/trellis/config.yaml +55 -7
- package/dist/templates/trellis/gitattributes.txt +9 -0
- package/dist/templates/trellis/index.d.ts +3 -1
- package/dist/templates/trellis/index.d.ts.map +1 -1
- package/dist/templates/trellis/index.js +3 -1
- package/dist/templates/trellis/index.js.map +1 -1
- package/dist/templates/trellis/scripts/add_session.py +94 -28
- package/dist/templates/trellis/scripts/common/active_task.py +44 -13
- package/dist/templates/trellis/scripts/common/cli_adapter.py +69 -5
- package/dist/templates/trellis/scripts/common/config.py +105 -10
- package/dist/templates/trellis/scripts/common/git.py +36 -0
- package/dist/templates/trellis/scripts/common/io.py +16 -9
- package/dist/templates/trellis/scripts/common/task_context.py +101 -7
- package/dist/templates/trellis/scripts/common/task_store.py +149 -22
- package/dist/templates/trellis/scripts/common/task_utils.py +3 -1
- package/dist/templates/trellis/scripts/common/trellis_config.py +2 -1
- package/dist/templates/trellis/scripts/common/workflow_phase.py +19 -12
- package/dist/templates/trellis/scripts/task.py +106 -10
- package/dist/templates/trellis/workflow.md +20 -19
- package/dist/templates/zcode/agents/trellis-check.md +7 -0
- package/dist/templates/zcode/agents/trellis-implement.md +13 -4
- package/dist/templates/zcode/config.json +42 -0
- package/dist/templates/zcode/index.d.ts +10 -1
- package/dist/templates/zcode/index.d.ts.map +1 -1
- package/dist/templates/zcode/index.js +12 -2
- package/dist/templates/zcode/index.js.map +1 -1
- package/dist/types/ai-tools.d.ts +4 -4
- package/dist/types/ai-tools.d.ts.map +1 -1
- package/dist/types/ai-tools.js +114 -2
- package/dist/types/ai-tools.js.map +1 -1
- package/dist/utils/template-fetcher.d.ts.map +1 -1
- package/dist/utils/template-fetcher.js +0 -3
- package/dist/utils/template-fetcher.js.map +1 -1
- package/package.json +2 -2
|
@@ -8,7 +8,13 @@
|
|
|
8
8
|
|
|
9
9
|
import { existsSync, readdirSync } from "fs"
|
|
10
10
|
import { join } from "path"
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
TrellisContext,
|
|
13
|
+
debugLog,
|
|
14
|
+
readContextInjectionLimits,
|
|
15
|
+
ContextBudget,
|
|
16
|
+
materializeArtifact,
|
|
17
|
+
} from "../lib/trellis-context.js"
|
|
12
18
|
|
|
13
19
|
// Supported subagent types
|
|
14
20
|
const AGENTS_ALL = ["implement", "check", "research"]
|
|
@@ -29,64 +35,112 @@ function extractActiveTaskHint(prompt) {
|
|
|
29
35
|
* Get context for implement agent. `taskDir` may be relative
|
|
30
36
|
* (`.trellis/tasks/foo`) or absolute; both are resolved via
|
|
31
37
|
* `ctx.resolveTaskDir`.
|
|
38
|
+
*
|
|
39
|
+
* Read order (mirrors Python `get_implement_context`):
|
|
40
|
+
* 1. All files in implement.jsonl (spec/research manifests)
|
|
41
|
+
* 2. prd.md (requirements)
|
|
42
|
+
* 3. design.md if present (technical design)
|
|
43
|
+
* 4. implement.md if present (execution plan)
|
|
44
|
+
* All blocks share one total budget (issue #441).
|
|
32
45
|
*/
|
|
33
46
|
function getImplementContext(ctx, taskDir) {
|
|
34
47
|
const parts = []
|
|
35
48
|
const taskDirFull = ctx.resolveTaskDir(taskDir)
|
|
36
49
|
if (!taskDirFull) return ""
|
|
37
50
|
|
|
38
|
-
const
|
|
39
|
-
const
|
|
40
|
-
if (entries.length > 0) {
|
|
41
|
-
parts.push(ctx.buildContextFromEntries(entries))
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const prd = ctx.readFile(join(taskDirFull, "prd.md"))
|
|
45
|
-
if (prd) {
|
|
46
|
-
parts.push(`=== ${taskDir}/prd.md (Requirements) ===\n${prd}`)
|
|
47
|
-
}
|
|
51
|
+
const limits = readContextInjectionLimits(ctx.directory)
|
|
52
|
+
const budget = new ContextBudget(limits.max_total_bytes)
|
|
48
53
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
54
|
+
// 1. Read implement.jsonl
|
|
55
|
+
const jsonlPath = join(taskDirFull, "implement.jsonl")
|
|
56
|
+
const blocks = ctx.readJsonlWithFiles(jsonlPath, limits, budget)
|
|
57
|
+
if (blocks.length > 0) {
|
|
58
|
+
parts.push(ctx.buildContextFromEntries(blocks))
|
|
52
59
|
}
|
|
53
60
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
61
|
+
// 2. Requirements document
|
|
62
|
+
const prdBlock = materializeArtifact(
|
|
63
|
+
ctx.directory,
|
|
64
|
+
`${taskDir}/prd.md`,
|
|
65
|
+
`${taskDir}/prd.md (Requirements)`,
|
|
66
|
+
"Requirements document",
|
|
67
|
+
limits,
|
|
68
|
+
budget,
|
|
69
|
+
)
|
|
70
|
+
if (prdBlock) parts.push(prdBlock)
|
|
71
|
+
|
|
72
|
+
// 3. Technical design for complex tasks
|
|
73
|
+
const designBlock = materializeArtifact(
|
|
74
|
+
ctx.directory,
|
|
75
|
+
`${taskDir}/design.md`,
|
|
76
|
+
`${taskDir}/design.md (Technical Design)`,
|
|
77
|
+
"Technical design document",
|
|
78
|
+
limits,
|
|
79
|
+
budget,
|
|
80
|
+
)
|
|
81
|
+
if (designBlock) parts.push(designBlock)
|
|
82
|
+
|
|
83
|
+
// 4. Execution plan for complex tasks
|
|
84
|
+
const implementPlanBlock = materializeArtifact(
|
|
85
|
+
ctx.directory,
|
|
86
|
+
`${taskDir}/implement.md`,
|
|
87
|
+
`${taskDir}/implement.md (Execution Plan)`,
|
|
88
|
+
"Execution plan document",
|
|
89
|
+
limits,
|
|
90
|
+
budget,
|
|
91
|
+
)
|
|
92
|
+
if (implementPlanBlock) parts.push(implementPlanBlock)
|
|
58
93
|
|
|
59
94
|
return parts.join("\n\n")
|
|
60
95
|
}
|
|
61
96
|
|
|
62
97
|
/**
|
|
63
98
|
* Get context for check agent. `taskDir` may be relative or absolute.
|
|
99
|
+
* Same read order and shared budget as the implement context.
|
|
64
100
|
*/
|
|
65
101
|
function getCheckContext(ctx, taskDir) {
|
|
66
102
|
const parts = []
|
|
67
103
|
const taskDirFull = ctx.resolveTaskDir(taskDir)
|
|
68
104
|
if (!taskDirFull) return ""
|
|
69
105
|
|
|
70
|
-
const
|
|
71
|
-
const
|
|
72
|
-
if (entries.length > 0) {
|
|
73
|
-
parts.push(ctx.buildContextFromEntries(entries))
|
|
74
|
-
}
|
|
106
|
+
const limits = readContextInjectionLimits(ctx.directory)
|
|
107
|
+
const budget = new ContextBudget(limits.max_total_bytes)
|
|
75
108
|
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
const design = ctx.readFile(join(taskDirFull, "design.md"))
|
|
82
|
-
if (design) {
|
|
83
|
-
parts.push(`=== ${taskDir}/design.md (Technical Design) ===\n${design}`)
|
|
109
|
+
const jsonlPath = join(taskDirFull, "check.jsonl")
|
|
110
|
+
const blocks = ctx.readJsonlWithFiles(jsonlPath, limits, budget)
|
|
111
|
+
if (blocks.length > 0) {
|
|
112
|
+
parts.push(ctx.buildContextFromEntries(blocks))
|
|
84
113
|
}
|
|
85
114
|
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
115
|
+
const prdBlock = materializeArtifact(
|
|
116
|
+
ctx.directory,
|
|
117
|
+
`${taskDir}/prd.md`,
|
|
118
|
+
`${taskDir}/prd.md (Requirements)`,
|
|
119
|
+
"Requirements document",
|
|
120
|
+
limits,
|
|
121
|
+
budget,
|
|
122
|
+
)
|
|
123
|
+
if (prdBlock) parts.push(prdBlock)
|
|
124
|
+
|
|
125
|
+
const designBlock = materializeArtifact(
|
|
126
|
+
ctx.directory,
|
|
127
|
+
`${taskDir}/design.md`,
|
|
128
|
+
`${taskDir}/design.md (Technical Design)`,
|
|
129
|
+
"Technical design document",
|
|
130
|
+
limits,
|
|
131
|
+
budget,
|
|
132
|
+
)
|
|
133
|
+
if (designBlock) parts.push(designBlock)
|
|
134
|
+
|
|
135
|
+
const implementPlanBlock = materializeArtifact(
|
|
136
|
+
ctx.directory,
|
|
137
|
+
`${taskDir}/implement.md`,
|
|
138
|
+
`${taskDir}/implement.md (Execution Plan)`,
|
|
139
|
+
"Execution plan document",
|
|
140
|
+
limits,
|
|
141
|
+
budget,
|
|
142
|
+
)
|
|
143
|
+
if (implementPlanBlock) parts.push(implementPlanBlock)
|
|
90
144
|
|
|
91
145
|
return parts.join("\n\n")
|
|
92
146
|
}
|
|
@@ -31,6 +31,82 @@ import { TrellisContext, debugLog, isTrellisSubagent } from "../lib/trellis-cont
|
|
|
31
31
|
// (so "in-review" / "blocked-by-team" work alongside "in_progress").
|
|
32
32
|
const TAG_RE = /\[workflow-state:([A-Za-z0-9_-]+)\]\s*\n([\s\S]*?)\n\s*\[\/workflow-state:\1\]/g
|
|
33
33
|
|
|
34
|
+
// Escape hatch for the per-turn breadcrumb (issue #427). Mirrors
|
|
35
|
+
// `common.config.get_prompt_injection_config()` / the shared Python hook's
|
|
36
|
+
// `_resolve_skip_keyword()` + `prompt_has_skip_keyword()`.
|
|
37
|
+
const DEFAULT_PROMPT_INJECTION_SKIP_KEYWORD = "no-trellis"
|
|
38
|
+
|
|
39
|
+
function stripInlineComment(value) {
|
|
40
|
+
let inQuote = null
|
|
41
|
+
for (let idx = 0; idx < value.length; idx++) {
|
|
42
|
+
const ch = value[idx]
|
|
43
|
+
if (inQuote) {
|
|
44
|
+
if (ch === inQuote) inQuote = null
|
|
45
|
+
continue
|
|
46
|
+
}
|
|
47
|
+
if (ch === '"' || ch === "'") {
|
|
48
|
+
inQuote = ch
|
|
49
|
+
continue
|
|
50
|
+
}
|
|
51
|
+
if (ch === "#" && (idx === 0 || /\s/.test(value[idx - 1]))) return value.slice(0, idx)
|
|
52
|
+
}
|
|
53
|
+
return value
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function unquoteYaml(s) {
|
|
57
|
+
if (s.length >= 2 && s[0] === s[s.length - 1] && (s[0] === '"' || s[0] === "'")) return s.slice(1, -1)
|
|
58
|
+
return s
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Line-based parser for ONLY the `prompt_injection:` block of
|
|
63
|
+
* `.trellis/config.yaml`. Not a general YAML parser — mirrors
|
|
64
|
+
* `common.config.get_prompt_injection_config()` semantics for this section
|
|
65
|
+
* only (missing key keeps the default; non-string value keeps the default).
|
|
66
|
+
*/
|
|
67
|
+
function readSkipKeyword(directory) {
|
|
68
|
+
const path = join(directory, ".trellis", "config.yaml")
|
|
69
|
+
if (!existsSync(path)) return DEFAULT_PROMPT_INJECTION_SKIP_KEYWORD
|
|
70
|
+
let text
|
|
71
|
+
try {
|
|
72
|
+
text = readFileSync(path, "utf-8")
|
|
73
|
+
} catch {
|
|
74
|
+
return DEFAULT_PROMPT_INJECTION_SKIP_KEYWORD
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
let inSection = false
|
|
78
|
+
let sectionIndent = -1
|
|
79
|
+
for (const rawLine of text.split(/\r?\n/)) {
|
|
80
|
+
const trimmed = rawLine.trim()
|
|
81
|
+
if (!inSection) {
|
|
82
|
+
if (/^prompt_injection\s*:\s*(#.*)?$/.test(trimmed)) {
|
|
83
|
+
inSection = true
|
|
84
|
+
sectionIndent = rawLine.length - rawLine.trimStart().length
|
|
85
|
+
}
|
|
86
|
+
continue
|
|
87
|
+
}
|
|
88
|
+
if (!trimmed || trimmed.startsWith("#")) continue
|
|
89
|
+
const indent = rawLine.length - rawLine.trimStart().length
|
|
90
|
+
if (indent <= sectionIndent) break
|
|
91
|
+
const m = trimmed.match(/^skip_keyword\s*:\s*(.*)$/)
|
|
92
|
+
if (!m) continue
|
|
93
|
+
return unquoteYaml(stripInlineComment(m[1]).trim())
|
|
94
|
+
}
|
|
95
|
+
return DEFAULT_PROMPT_INJECTION_SKIP_KEYWORD
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Case-insensitive, word-boundary match of `keyword` in `text`. Hyphen
|
|
100
|
+
* counts as a word char so "no-trellisx" / "xno-trellis" don't match, but
|
|
101
|
+
* punctuation/whitespace boundaries do. Empty keyword never matches.
|
|
102
|
+
*/
|
|
103
|
+
function promptHasSkipKeyword(text, keyword) {
|
|
104
|
+
if (!keyword || typeof text !== "string") return false
|
|
105
|
+
const escaped = keyword.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
|
|
106
|
+
const pattern = new RegExp(`(?<![\\w-])${escaped}(?![\\w-])`, "i")
|
|
107
|
+
return pattern.test(text)
|
|
108
|
+
}
|
|
109
|
+
|
|
34
110
|
/**
|
|
35
111
|
* Parse workflow.md for [workflow-state:STATUS] blocks.
|
|
36
112
|
*
|
|
@@ -124,18 +200,27 @@ export default async ({ directory }) => {
|
|
|
124
200
|
if (!ctx.isTrellisProject()) {
|
|
125
201
|
return
|
|
126
202
|
}
|
|
203
|
+
|
|
204
|
+
const parts = output?.parts || []
|
|
205
|
+
const textPartIndex = parts.findIndex(
|
|
206
|
+
p => p.type === "text" && p.text !== undefined,
|
|
207
|
+
)
|
|
208
|
+
const originalText = textPartIndex !== -1 ? (parts[textPartIndex].text || "") : ""
|
|
209
|
+
|
|
210
|
+
// Escape hatch (issue #427): user prompt contains the skip keyword
|
|
211
|
+
// as a standalone word — emit nothing for this turn only.
|
|
212
|
+
if (promptHasSkipKeyword(originalText, readSkipKeyword(directory))) {
|
|
213
|
+
debugLog("workflow-state", "Skipping turn: skip keyword present in prompt")
|
|
214
|
+
return
|
|
215
|
+
}
|
|
216
|
+
|
|
127
217
|
const templates = loadBreadcrumbs(directory)
|
|
128
218
|
const task = getActiveTask(ctx, input)
|
|
129
219
|
const breadcrumb = task
|
|
130
220
|
? buildBreadcrumb(task.id, task.status, templates, task.source)
|
|
131
221
|
: buildBreadcrumb(null, "no_task", templates)
|
|
132
222
|
|
|
133
|
-
const parts = output?.parts || []
|
|
134
|
-
const textPartIndex = parts.findIndex(
|
|
135
|
-
p => p.type === "text" && p.text !== undefined,
|
|
136
|
-
)
|
|
137
223
|
if (textPartIndex !== -1) {
|
|
138
|
-
const originalText = parts[textPartIndex].text || ""
|
|
139
224
|
parts[textPartIndex].text = `${breadcrumb}\n\n${originalText}`
|
|
140
225
|
} else {
|
|
141
226
|
parts.unshift({ type: "text", text: breadcrumb })
|
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
2
2
|
import { createHash, randomBytes } from "node:crypto";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
delimiter,
|
|
5
|
+
dirname,
|
|
6
|
+
isAbsolute,
|
|
7
|
+
join,
|
|
8
|
+
relative,
|
|
9
|
+
resolve,
|
|
10
|
+
} from "node:path";
|
|
4
11
|
import { spawn, spawnSync } from "node:child_process";
|
|
12
|
+
import { isUtf8 } from "node:buffer";
|
|
5
13
|
|
|
6
14
|
// ── Types ──────────────────────────────────────────────────────────────
|
|
7
15
|
type JsonObject = Record<string, unknown>;
|
|
@@ -84,8 +92,14 @@ const ABORT_KILL_GRACE_MS = 1500;
|
|
|
84
92
|
const SESSION_OVERVIEW_TIMEOUT_MS = 1500;
|
|
85
93
|
const THROTTLE_MS = 500;
|
|
86
94
|
const FIRST_REPLY_NOTICE = `<first-reply-notice>
|
|
87
|
-
|
|
88
|
-
|
|
95
|
+
On the first visible assistant reply in this session, briefly acknowledge that Trellis SessionStart context loaded.
|
|
96
|
+
Choose the acknowledgment language in this order:
|
|
97
|
+
1. Use the language of the user's current request (the user message that triggered this reply).
|
|
98
|
+
2. If that request has no clear natural language, use an explicitly established project communication language.
|
|
99
|
+
3. If neither provides a language, output the language-neutral fallback exactly: \`Trellis SessionStart ✓\`.
|
|
100
|
+
Continue directly with the user's request after the acknowledgment.
|
|
101
|
+
The acknowledgment must not alter the language used for the remainder of the response.
|
|
102
|
+
This notice is one-shot: do not repeat it after the first visible assistant reply in this session.
|
|
89
103
|
</first-reply-notice>`;
|
|
90
104
|
|
|
91
105
|
// ── State types ───────────────────────────────────────────────────────
|
|
@@ -716,6 +730,222 @@ class BBC {
|
|
|
716
730
|
}
|
|
717
731
|
}
|
|
718
732
|
|
|
733
|
+
// ── Context Injection Limits (issue #441) ───────────────────────────────
|
|
734
|
+
//
|
|
735
|
+
// Notice text and behavior mirrored byte-for-byte from the shared-hooks
|
|
736
|
+
// Python sub-agent context injection hook. Changing wording there requires
|
|
737
|
+
// changing it here too.
|
|
738
|
+
interface ContextInjectionLimits {
|
|
739
|
+
max_file_bytes: number;
|
|
740
|
+
max_artifact_bytes: number;
|
|
741
|
+
max_total_bytes: number;
|
|
742
|
+
}
|
|
743
|
+
const DEFAULT_CONTEXT_INJECTION_LIMITS: ContextInjectionLimits = {
|
|
744
|
+
max_file_bytes: 32768,
|
|
745
|
+
max_artifact_bytes: 65536,
|
|
746
|
+
max_total_bytes: 131072,
|
|
747
|
+
};
|
|
748
|
+
|
|
749
|
+
function truncateUtf8(buf: Buffer, cap: number): Buffer {
|
|
750
|
+
if (cap <= 0 || buf.length <= cap) return buf;
|
|
751
|
+
let i = cap;
|
|
752
|
+
// Back off over continuation bytes (10xxxxxx) to find the lead byte.
|
|
753
|
+
while (i > 0 && (buf[i - 1]! & 0xc0) === 0x80) i--;
|
|
754
|
+
if (i === 0) return Buffer.alloc(0);
|
|
755
|
+
const lead = buf[i - 1]!;
|
|
756
|
+
if (lead & 0x80) {
|
|
757
|
+
let seqLen = 1;
|
|
758
|
+
if ((lead & 0xe0) === 0xc0) seqLen = 2;
|
|
759
|
+
else if ((lead & 0xf0) === 0xe0) seqLen = 3;
|
|
760
|
+
else if ((lead & 0xf8) === 0xf0) seqLen = 4;
|
|
761
|
+
// Drop the lead byte too if its full sequence didn't fit.
|
|
762
|
+
if (i - 1 + seqLen > cap) i--;
|
|
763
|
+
}
|
|
764
|
+
return buf.subarray(0, i);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
function stripInlineComment(value: string): string {
|
|
768
|
+
let inQuote: string | null = null;
|
|
769
|
+
for (let idx = 0; idx < value.length; idx++) {
|
|
770
|
+
const ch = value[idx]!;
|
|
771
|
+
if (inQuote) {
|
|
772
|
+
if (ch === inQuote) inQuote = null;
|
|
773
|
+
continue;
|
|
774
|
+
}
|
|
775
|
+
if (ch === '"' || ch === "'") {
|
|
776
|
+
inQuote = ch;
|
|
777
|
+
continue;
|
|
778
|
+
}
|
|
779
|
+
if (ch === "#" && (idx === 0 || /\s/.test(value[idx - 1]!)))
|
|
780
|
+
return value.slice(0, idx);
|
|
781
|
+
}
|
|
782
|
+
return value;
|
|
783
|
+
}
|
|
784
|
+
function unquoteYaml(s: string): string {
|
|
785
|
+
if (s.length >= 2 && s[0] === s[s.length - 1] && (s[0] === '"' || s[0] === "'"))
|
|
786
|
+
return s.slice(1, -1);
|
|
787
|
+
return s;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
/** Line-based parser for ONLY the `context_injection:` block of
|
|
791
|
+
* `.trellis/config.yaml`. Not a general YAML parser — mirrors
|
|
792
|
+
* `common.config.get_context_injection_limits()` semantics for this
|
|
793
|
+
* section only (missing keys keep the default; invalid/negative values
|
|
794
|
+
* fall back to the default for that key). */
|
|
795
|
+
function readContextInjectionLimits(repoRoot: string): ContextInjectionLimits {
|
|
796
|
+
const limits: ContextInjectionLimits = { ...DEFAULT_CONTEXT_INJECTION_LIMITS };
|
|
797
|
+
const text = readText(join(repoRoot, ".trellis", "config.yaml"));
|
|
798
|
+
if (!text) return limits;
|
|
799
|
+
|
|
800
|
+
let inSection = false;
|
|
801
|
+
let sectionIndent = -1;
|
|
802
|
+
for (const rawLine of text.split(/\r?\n/)) {
|
|
803
|
+
const trimmed = rawLine.trim();
|
|
804
|
+
if (!inSection) {
|
|
805
|
+
if (/^context_injection\s*:\s*(#.*)?$/.test(trimmed)) {
|
|
806
|
+
inSection = true;
|
|
807
|
+
sectionIndent = rawLine.length - rawLine.trimStart().length;
|
|
808
|
+
}
|
|
809
|
+
continue;
|
|
810
|
+
}
|
|
811
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
812
|
+
const indent = rawLine.length - rawLine.trimStart().length;
|
|
813
|
+
if (indent <= sectionIndent) break;
|
|
814
|
+
const m = trimmed.match(/^([A-Za-z_][A-Za-z0-9_]*)\s*:\s*(.*)$/);
|
|
815
|
+
if (!m) continue;
|
|
816
|
+
const key = m[1]!;
|
|
817
|
+
if (!(key in limits)) continue;
|
|
818
|
+
const raw = unquoteYaml(stripInlineComment(m[2]!).trim()).trim();
|
|
819
|
+
if (!/^-?\d+$/.test(raw)) continue; // invalid -> keep default
|
|
820
|
+
const value = parseInt(raw, 10);
|
|
821
|
+
if (value < 0) continue; // negative -> keep default
|
|
822
|
+
(limits as unknown as Record<string, number>)[key] = value;
|
|
823
|
+
}
|
|
824
|
+
return limits;
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
class ContextBudget {
|
|
828
|
+
used = 0;
|
|
829
|
+
constructor(private maxTotalBytes: number) {}
|
|
830
|
+
hasRoom(size: number): boolean {
|
|
831
|
+
if (this.maxTotalBytes <= 0) return true;
|
|
832
|
+
return this.used + size <= this.maxTotalBytes;
|
|
833
|
+
}
|
|
834
|
+
add(size: number): void {
|
|
835
|
+
this.used += size;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
function truncateNotice(path: string, cap: number): string {
|
|
840
|
+
return `\n[Trellis: truncated at ${cap} bytes — read ${path} for the full content]`;
|
|
841
|
+
}
|
|
842
|
+
function isBinaryContent(data: Buffer): boolean {
|
|
843
|
+
return data.includes(0) || !isUtf8(data);
|
|
844
|
+
}
|
|
845
|
+
function binaryNotice(path: string, size: number, reason: string): string {
|
|
846
|
+
return `[Trellis: not inlined (binary file) — ${path} (${size} bytes): ${reason}]`;
|
|
847
|
+
}
|
|
848
|
+
function indexNotice(path: string, size: number, reason: string): string {
|
|
849
|
+
return `[Trellis: not inlined (total context limit reached) — ${path} (${size} bytes): ${reason}]`;
|
|
850
|
+
}
|
|
851
|
+
function budgetedBlock(
|
|
852
|
+
budget: ContextBudget,
|
|
853
|
+
header: string,
|
|
854
|
+
plainPath: string,
|
|
855
|
+
content: string,
|
|
856
|
+
reason: string,
|
|
857
|
+
sizeForIndex: number,
|
|
858
|
+
): string {
|
|
859
|
+
const block = `=== ${header} ===\n${content}`;
|
|
860
|
+
const blockBytes = Buffer.byteLength(block, "utf-8");
|
|
861
|
+
if (!budget.hasRoom(blockBytes)) {
|
|
862
|
+
const notice = indexNotice(plainPath, sizeForIndex, reason);
|
|
863
|
+
budget.add(Buffer.byteLength(notice, "utf-8"));
|
|
864
|
+
return notice;
|
|
865
|
+
}
|
|
866
|
+
budget.add(blockBytes);
|
|
867
|
+
return block;
|
|
868
|
+
}
|
|
869
|
+
function readFileBytes(basePath: string, filePath: string): Buffer | null {
|
|
870
|
+
const full = join(basePath, filePath);
|
|
871
|
+
try {
|
|
872
|
+
if (!statSync(full).isFile()) return null;
|
|
873
|
+
} catch {
|
|
874
|
+
return null;
|
|
875
|
+
}
|
|
876
|
+
try {
|
|
877
|
+
return readFileSync(full);
|
|
878
|
+
} catch {
|
|
879
|
+
return null;
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
function materializeFile(
|
|
883
|
+
basePath: string,
|
|
884
|
+
filePath: string,
|
|
885
|
+
reason: string,
|
|
886
|
+
limits: ContextInjectionLimits,
|
|
887
|
+
budget: ContextBudget,
|
|
888
|
+
): string | null {
|
|
889
|
+
const data = readFileBytes(basePath, filePath);
|
|
890
|
+
if (data === null) return null;
|
|
891
|
+
const size = data.length;
|
|
892
|
+
if (isBinaryContent(data)) {
|
|
893
|
+
const notice = binaryNotice(filePath, size, reason);
|
|
894
|
+
budget.add(Buffer.byteLength(notice, "utf-8"));
|
|
895
|
+
return notice;
|
|
896
|
+
}
|
|
897
|
+
const cap = limits.max_file_bytes;
|
|
898
|
+
const truncated = truncateUtf8(data, cap);
|
|
899
|
+
let content = truncated.toString("utf-8");
|
|
900
|
+
if (truncated.length < size) content += truncateNotice(filePath, cap);
|
|
901
|
+
return budgetedBlock(budget, filePath, filePath, content, reason, size);
|
|
902
|
+
}
|
|
903
|
+
function materializeArtifact(
|
|
904
|
+
basePath: string,
|
|
905
|
+
filePath: string,
|
|
906
|
+
headerLabel: string,
|
|
907
|
+
reason: string,
|
|
908
|
+
limits: ContextInjectionLimits,
|
|
909
|
+
budget: ContextBudget,
|
|
910
|
+
): string | null {
|
|
911
|
+
const data = readFileBytes(basePath, filePath);
|
|
912
|
+
if (data === null) return null;
|
|
913
|
+
const size = data.length;
|
|
914
|
+
const cap = limits.max_artifact_bytes;
|
|
915
|
+
const truncated = truncateUtf8(data, cap);
|
|
916
|
+
let content = truncated.toString("utf-8");
|
|
917
|
+
if (truncated.length < size) content += truncateNotice(filePath, cap);
|
|
918
|
+
return budgetedBlock(budget, headerLabel, filePath, content, reason, size);
|
|
919
|
+
}
|
|
920
|
+
interface JsonlEntry {
|
|
921
|
+
file: string;
|
|
922
|
+
type: string;
|
|
923
|
+
reason: string;
|
|
924
|
+
}
|
|
925
|
+
function readJsonlEntries(basePath: string, jsonlPath: string): JsonlEntry[] {
|
|
926
|
+
const text = readText(join(basePath, jsonlPath));
|
|
927
|
+
if (!text) return [];
|
|
928
|
+
const entries: JsonlEntry[] = [];
|
|
929
|
+
for (const line of text.split(/\r?\n/)) {
|
|
930
|
+
const t = line.trim();
|
|
931
|
+
if (!t) continue;
|
|
932
|
+
try {
|
|
933
|
+
const item = JSON.parse(t) as JsonObject;
|
|
934
|
+
const filePath =
|
|
935
|
+
(typeof item.file === "string" && item.file) ||
|
|
936
|
+
(typeof item.path === "string" && item.path) ||
|
|
937
|
+
"";
|
|
938
|
+
if (!filePath) continue;
|
|
939
|
+
entries.push({
|
|
940
|
+
file: filePath,
|
|
941
|
+
type: typeof item.type === "string" ? item.type : "file",
|
|
942
|
+
reason: (typeof item.reason === "string" && item.reason) || "-",
|
|
943
|
+
});
|
|
944
|
+
} catch {}
|
|
945
|
+
}
|
|
946
|
+
return entries;
|
|
947
|
+
}
|
|
948
|
+
|
|
719
949
|
// ── Trellis Context ────────────────────────────────────────────────────
|
|
720
950
|
function findRoot(start: string): string {
|
|
721
951
|
let c = resolve(start);
|
|
@@ -936,35 +1166,59 @@ function buildContext(root: string, agent: string, key: string | null): string {
|
|
|
936
1166
|
const dir = readTaskDir(root, key);
|
|
937
1167
|
if (!dir)
|
|
938
1168
|
return "No active Trellis task found. Read .trellis/ before proceeding.";
|
|
939
|
-
const
|
|
940
|
-
const
|
|
941
|
-
const
|
|
1169
|
+
const relTaskDir = relative(root, dir).replace(/\\/g, "/");
|
|
1170
|
+
const limits = readContextInjectionLimits(root);
|
|
1171
|
+
const budget = new ContextBudget(limits.max_total_bytes);
|
|
1172
|
+
|
|
1173
|
+
// 1. Curated spec/research files from {agent}.jsonl (same order, budget
|
|
1174
|
+
// processed first, matching Python's get_agent_context()).
|
|
942
1175
|
const jsonlName = TRELLIS_AGENT_JSONL[agent] ?? "";
|
|
943
|
-
|
|
1176
|
+
const specBlocks: string[] = [];
|
|
944
1177
|
if (jsonlName) {
|
|
945
|
-
const
|
|
946
|
-
|
|
947
|
-
const
|
|
948
|
-
if (
|
|
949
|
-
try {
|
|
950
|
-
const r = JSON.parse(t) as JsonObject;
|
|
951
|
-
const f = typeof r.file === "string" ? r.file : "";
|
|
952
|
-
if (f) {
|
|
953
|
-
const c = readText(join(root, f));
|
|
954
|
-
if (c) chunks.push(`## ${f}\n\n${c}`);
|
|
955
|
-
}
|
|
956
|
-
} catch {}
|
|
1178
|
+
for (const entry of readJsonlEntries(dir, jsonlName)) {
|
|
1179
|
+
if (entry.type === "directory") continue;
|
|
1180
|
+
const block = materializeFile(root, entry.file, entry.reason, limits, budget);
|
|
1181
|
+
if (block) specBlocks.push(block);
|
|
957
1182
|
}
|
|
958
|
-
spec = chunks.join("\n\n---\n\n");
|
|
959
1183
|
}
|
|
1184
|
+
const spec = specBlocks.join("\n\n");
|
|
1185
|
+
|
|
1186
|
+
// 2-4. Task artifacts, in order: prd.md -> design.md -> implement.md.
|
|
1187
|
+
const prd = materializeArtifact(
|
|
1188
|
+
root,
|
|
1189
|
+
`${relTaskDir}/prd.md`,
|
|
1190
|
+
`${relTaskDir}/prd.md (Requirements)`,
|
|
1191
|
+
"Requirements document",
|
|
1192
|
+
limits,
|
|
1193
|
+
budget,
|
|
1194
|
+
);
|
|
1195
|
+
const design = materializeArtifact(
|
|
1196
|
+
root,
|
|
1197
|
+
`${relTaskDir}/design.md`,
|
|
1198
|
+
`${relTaskDir}/design.md (Technical Design)`,
|
|
1199
|
+
"Technical design document",
|
|
1200
|
+
limits,
|
|
1201
|
+
budget,
|
|
1202
|
+
);
|
|
1203
|
+
const impl = materializeArtifact(
|
|
1204
|
+
root,
|
|
1205
|
+
`${relTaskDir}/implement.md`,
|
|
1206
|
+
`${relTaskDir}/implement.md (Execution Plan)`,
|
|
1207
|
+
"Execution plan document",
|
|
1208
|
+
limits,
|
|
1209
|
+
budget,
|
|
1210
|
+
);
|
|
1211
|
+
|
|
1212
|
+
// prd/design/impl already carry their own "=== path (label) ===" header
|
|
1213
|
+
// (from materializeArtifact) — no extra "### x.md" wrapper needed, that
|
|
1214
|
+
// would just double the header.
|
|
960
1215
|
return [
|
|
961
1216
|
`## Trellis Task Context`,
|
|
962
1217
|
`Task directory: ${dir}`,
|
|
963
1218
|
"",
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
impl ? "\n### implement.md\n" + impl : "",
|
|
1219
|
+
prd ?? `(missing) ${relTaskDir}/prd.md`,
|
|
1220
|
+
design ? "\n" + design : "",
|
|
1221
|
+
impl ? "\n" + impl : "",
|
|
968
1222
|
spec ? "\n### Curated Spec / Research Context\n" + spec : "",
|
|
969
1223
|
].join("\n");
|
|
970
1224
|
}
|
|
@@ -12,7 +12,7 @@ export interface HookScript {
|
|
|
12
12
|
content: string;
|
|
13
13
|
}
|
|
14
14
|
export type SharedHookName = "session-start.py" | "inject-shell-session-context.py" | "inject-workflow-state.py" | "inject-subagent-context.py";
|
|
15
|
-
export type SharedHookPlatform = "claude" | "cursor" | "codex" | "gemini" | "qoder" | "copilot" | "codebuddy" | "droid" | "kiro" | "trae";
|
|
15
|
+
export type SharedHookPlatform = "claude" | "cursor" | "codex" | "gemini" | "qoder" | "copilot" | "codebuddy" | "droid" | "kiro" | "trae" | "zcode";
|
|
16
16
|
/**
|
|
17
17
|
* Which shared hooks each platform actually invokes. Single source of truth
|
|
18
18
|
* for shared-hook distribution — both `writeSharedHooks` (runtime install)
|
|
@@ -25,10 +25,11 @@ export type SharedHookPlatform = "claude" | "cursor" | "codex" | "gemini" | "qod
|
|
|
25
25
|
* - `inject-workflow-state.py` — every platform with a UserPromptSubmit
|
|
26
26
|
* (or equivalent) event. Kiro + codex self-included; platforms without
|
|
27
27
|
* per-turn main-session hooks are excluded.
|
|
28
|
-
* - `inject-subagent-context.py` —
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
28
|
+
* - `inject-subagent-context.py` — platforms with native sub-agent context
|
|
29
|
+
* delivery. Most use a PreToolUse prompt mutation; Codex uses its
|
|
30
|
+
* SubagentStart `additionalContext` event. Class-2 (pull-based) platforms
|
|
31
|
+
* such as copilot, gemini, qoder, and trae still load context from a
|
|
32
|
+
* self-loading agent profile.
|
|
32
33
|
* - Kiro supports per-turn + spawn hooks on both surfaces (per the official
|
|
33
34
|
* docs https://kiro.dev/docs/cli/hooks/): the CLI custom agent declares
|
|
34
35
|
* `hooks.userPromptSubmit` + `hooks.agentSpawn`, and the IDE declares a
|
|
@@ -42,6 +43,11 @@ export type SharedHookPlatform = "claude" | "cursor" | "codex" | "gemini" | "qod
|
|
|
42
43
|
* or opt in to the Trellis one via `trellis init --with-statusline`
|
|
43
44
|
* (installed from `templates/claude/hooks/`, not from this table — no
|
|
44
45
|
* other platform has a statusLine event).
|
|
46
|
+
* - ZCode (3.x) ships a workspace hook config at `.zcode/config.json` covering
|
|
47
|
+
* SessionStart + UserPromptSubmit in the main session, plus PreToolUse for
|
|
48
|
+
* `Agent|Task`. Live probing confirmed `hookSpecificOutput.updatedInput`
|
|
49
|
+
* reaches the sub-agent prompt, so ZCode is class-1 and ships
|
|
50
|
+
* `inject-subagent-context.py`.
|
|
45
51
|
*/
|
|
46
52
|
export declare const SHARED_HOOKS_BY_PLATFORM: Record<SharedHookPlatform, readonly SharedHookName[]>;
|
|
47
53
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/shared-hooks/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAaH,MAAM,WAAW,UAAU;IACzB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,cAAc,GACtB,kBAAkB,GAClB,iCAAiC,GACjC,0BAA0B,GAC1B,4BAA4B,CAAC;AAEjC,MAAM,MAAM,kBAAkB,GAC1B,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,OAAO,GACP,SAAS,GACT,WAAW,GACX,OAAO,GACP,MAAM,GACN,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/templates/shared-hooks/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAaH,MAAM,WAAW,UAAU;IACzB,0CAA0C;IAC1C,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,cAAc,GACtB,kBAAkB,GAClB,iCAAiC,GACjC,0BAA0B,GAC1B,4BAA4B,CAAC;AAEjC,MAAM,MAAM,kBAAkB,GAC1B,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,QAAQ,GACR,OAAO,GACP,SAAS,GACT,WAAW,GACX,OAAO,GACP,MAAM,GACN,MAAM,GACN,OAAO,CAAC;AAEZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,wBAAwB,EAAE,MAAM,CAC3C,kBAAkB,EAClB,SAAS,cAAc,EAAE,CAqC1B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,UAAU,EAAE,CAWnD;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,kBAAkB,GAC3B,UAAU,EAAE,CAGd"}
|