@elevasis/sdk 0.5.14 → 0.5.16
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/dist/cli.cjs +841 -541
- package/dist/index.d.ts +24 -0
- package/dist/index.js +53 -0
- package/dist/templates.js +305 -108
- package/dist/worker/index.js +7 -8
- package/package.json +1 -1
- package/reference/framework/agent.mdx +7 -7
- package/reference/framework/index.mdx +10 -10
- package/reference/framework/project-structure.mdx +8 -8
- package/reference/getting-started.mdx +1 -1
package/dist/templates.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// package.json
|
|
2
2
|
|
|
3
3
|
// src/cli/commands/templates/core/workspace.ts
|
|
4
|
-
var TEMPLATE_VERSION =
|
|
4
|
+
var TEMPLATE_VERSION = 29;
|
|
5
5
|
function configTemplate() {
|
|
6
6
|
return `import type { ElevasConfig } from '@elevasis/sdk'
|
|
7
7
|
|
|
@@ -49,6 +49,28 @@ function claudeSettingsTemplate() {
|
|
|
49
49
|
}
|
|
50
50
|
]
|
|
51
51
|
}
|
|
52
|
+
],
|
|
53
|
+
PostToolUse: [
|
|
54
|
+
{
|
|
55
|
+
matcher: "Write|Edit|MultiEdit",
|
|
56
|
+
hooks: [
|
|
57
|
+
{
|
|
58
|
+
type: "command",
|
|
59
|
+
command: "node .claude/hooks/post-edit-validate.mjs"
|
|
60
|
+
}
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
PostToolUseFailure: [
|
|
65
|
+
{
|
|
66
|
+
matcher: "Bash",
|
|
67
|
+
hooks: [
|
|
68
|
+
{
|
|
69
|
+
type: "command",
|
|
70
|
+
command: "node .claude/hooks/tool-failure-recovery.mjs"
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
}
|
|
52
74
|
]
|
|
53
75
|
}
|
|
54
76
|
},
|
|
@@ -82,8 +104,8 @@ process.stdin.on('end', () => {
|
|
|
82
104
|
function claudeSdkBoundaryHookTemplate() {
|
|
83
105
|
return String.raw`#!/usr/bin/env node
|
|
84
106
|
// enforce-sdk-boundary.mjs
|
|
85
|
-
// Blocks
|
|
86
|
-
//
|
|
107
|
+
// Blocks file modifications (Write, Edit, MultiEdit, destructive Bash) outside the project root.
|
|
108
|
+
// Git, gh, and other CLI tools are NOT blocked -- the agent can use them freely.
|
|
87
109
|
|
|
88
110
|
import { resolve, normalize } from "node:path";
|
|
89
111
|
import { appendFileSync, mkdirSync } from "node:fs";
|
|
@@ -128,44 +150,6 @@ try {
|
|
|
128
150
|
if (input.tool_name === "Bash") {
|
|
129
151
|
const cmd = input.tool_input?.command ?? "";
|
|
130
152
|
|
|
131
|
-
// GitHub CLI -- blocked (affects shared remote state, user-initiated only)
|
|
132
|
-
if (/\bgh\b/.test(cmd)) {
|
|
133
|
-
deny(
|
|
134
|
-
"BLOCKED: GitHub CLI (gh) command detected.\n" +
|
|
135
|
-
"WHY: GitHub CLI operations affect shared remote state (PRs, issues, releases). These must be user-initiated.\n" +
|
|
136
|
-
"INSTEAD: Ask the user to run this gh command manually."
|
|
137
|
-
);
|
|
138
|
-
process.exit(0);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Destructive git -- blocked
|
|
142
|
-
if (/(?<!-)\bgit\s+reset\b/.test(cmd) && /--hard/.test(cmd)) {
|
|
143
|
-
deny(
|
|
144
|
-
"BLOCKED: git reset --hard detected.\n" +
|
|
145
|
-
"WHY: Hard resets destroy uncommitted work and cannot be undone. This must be user-initiated.\n" +
|
|
146
|
-
"INSTEAD: Ask the user to run this git command manually."
|
|
147
|
-
);
|
|
148
|
-
process.exit(0);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
if (/(?<!-)\bgit\s+clean\b/.test(cmd) && /-[a-zA-Z]*f/.test(cmd)) {
|
|
152
|
-
deny(
|
|
153
|
-
"BLOCKED: git clean -f detected.\n" +
|
|
154
|
-
"WHY: Force-cleaning the working tree permanently removes untracked files. This must be user-initiated.\n" +
|
|
155
|
-
"INSTEAD: Ask the user to run this git command manually."
|
|
156
|
-
);
|
|
157
|
-
process.exit(0);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if (/(?<!-)\bgit\s+(rebase|merge)\b/.test(cmd)) {
|
|
161
|
-
deny(
|
|
162
|
-
"BLOCKED: git rebase/merge detected.\n" +
|
|
163
|
-
"WHY: Rebase and merge rewrite history or combine branches in ways that require user judgment.\n" +
|
|
164
|
-
"INSTEAD: Ask the user to run this git command manually."
|
|
165
|
-
);
|
|
166
|
-
process.exit(0);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
153
|
// Path-scoped blocks -- destructive commands or redirects outside project root
|
|
170
154
|
const winPaths = cmd.match(/(?<![A-Za-z])[A-Za-z]:[/\\][^\s"'|;&)]+/g) || [];
|
|
171
155
|
const unixPaths = cmd.match(/(?<=\s|^|"|')\/[^\s"'|;&)]+/g) || [];
|
|
@@ -348,7 +332,7 @@ For detailed per-dimension adaptation rules, read
|
|
|
348
332
|
| --- | --- |
|
|
349
333
|
| \`/meta\` | Project lifecycle: init, status, fix, deploy, health |
|
|
350
334
|
| \`/docs\` | Browse, create, and verify permanent documentation |
|
|
351
|
-
| \`/work\` | Task tracking: create, save, resume
|
|
335
|
+
| \`/work\` | Task tracking: auto-detects intent (create, save, resume); suggests complete |
|
|
352
336
|
| \`/tutorial\` | Progressive learning path (21 items across 4 sections) |
|
|
353
337
|
|
|
354
338
|
## Skills
|
|
@@ -580,43 +564,46 @@ Observation focus: full lifecycle coverage, pipeline internals.
|
|
|
580
564
|
**Item 4: /work and /docs**
|
|
581
565
|
|
|
582
566
|
When automation is none:
|
|
583
|
-
"You can ask the assistant to track work across conversations.
|
|
584
|
-
|
|
585
|
-
you
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
567
|
+
"You can ask the assistant to track work across conversations. Just say /work and tell it
|
|
568
|
+
what you're working on -- it figures out the rest. It'll save your progress automatically,
|
|
569
|
+
and next session you just say /work to pick up where you left off." Walk through the
|
|
570
|
+
concept without deep command details. Then introduce /docs:
|
|
571
|
+
"When a task is done, the assistant will ask if you want to finalize it -- that moves it
|
|
572
|
+
to docs/ permanently. /docs helps you find and read what's there -- like a notebook for
|
|
573
|
+
your project." Run /docs (no args) to show the docs/ overview together.
|
|
574
|
+
Verify: Run \`/work\` and describe "practice task", see it created automatically.
|
|
590
575
|
Then run /docs to see the docs/ structure.
|
|
591
576
|
Observation focus: persistence concept, cross-session continuity, docs as permanent notes.
|
|
592
577
|
|
|
593
578
|
When automation is low-code:
|
|
594
|
-
Show /work
|
|
595
|
-
|
|
596
|
-
|
|
579
|
+
Show /work as intent-driven: the agent detects whether to create, resume, or save based
|
|
580
|
+
on context. Create happens when you describe new work, resume when you pick an existing
|
|
581
|
+
task, save happens automatically when progress is made. Complete is the only action that
|
|
582
|
+
asks permission first.
|
|
597
583
|
Then introduce /docs: "/docs is for permanent knowledge -- things that don't expire. Use
|
|
598
584
|
/docs create to document a workflow or integration. Use /docs verify to check if your
|
|
599
585
|
docs match the current code." Explain the boundary: /work manages in-progress/, /docs
|
|
600
586
|
manages permanent docs/.
|
|
601
|
-
Verify:
|
|
602
|
-
|
|
603
|
-
Observation focus: task tracking
|
|
587
|
+
Verify: Run \`/work\` and describe "practice task", see auto-create. Make some changes,
|
|
588
|
+
then notice auto-save. Then run /docs to browse docs/.
|
|
589
|
+
Observation focus: intent-driven task tracking, /work vs /docs separation.
|
|
604
590
|
|
|
605
591
|
When automation is custom:
|
|
606
592
|
Read \`.claude/commands/work.md\`. Full /work coverage:
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
593
|
+
Intent detection table (list, create, resume, save auto-invoked; complete always suggests).
|
|
594
|
+
Task doc anatomy: kebab-case filename, frontmatter with status, Objective/Plan/Progress/
|
|
595
|
+
Resume Context sections. Auto-save behavior: triggers on heavy context, wrap-up signals,
|
|
596
|
+
2+ steps completed. Resolution order for resume: number, keyword match, single in-progress.
|
|
610
597
|
Then read \`.claude/commands/docs.md\`. Cover /docs operations:
|
|
611
598
|
/docs (default): browse permanent docs/, categorized with read-only auto-generated files
|
|
612
599
|
separate; /docs create: interview-driven, resource-aware doc creation from src/ code
|
|
613
600
|
analysis; /docs verify: cross-references resource IDs, schema fields, platform tools in
|
|
614
601
|
docs against src/ -- standalone analog of /meta fix step 5.
|
|
615
|
-
Explain the relationship: /work owns docs/in-progress/ (task lifecycle),
|
|
602
|
+
Explain the relationship: /work owns docs/in-progress/ (task lifecycle), completing a task
|
|
616
603
|
moves docs to permanent location, /docs browses and verifies what's there.
|
|
617
|
-
Verify: Create a task
|
|
618
|
-
to see it in the permanent docs/ listing.
|
|
619
|
-
Observation focus:
|
|
604
|
+
Verify: Create a task via /work, make progress, observe auto-save, then run /work complete
|
|
605
|
+
to move it. Run /docs to see it in the permanent docs/ listing.
|
|
606
|
+
Observation focus: intent detection, auto-save behavior, /work-to-/docs handoff, docs verification.
|
|
620
607
|
|
|
621
608
|
**Item 5: Your First Custom Workflow**
|
|
622
609
|
|
|
@@ -1150,6 +1137,8 @@ function claudeWorkCommandTemplate() {
|
|
|
1150
1137
|
|
|
1151
1138
|
You are a task tracking assistant for this Elevasis workspace. \`/work\` is the primary command for managing all work and projects.
|
|
1152
1139
|
|
|
1140
|
+
Your job is to **intelligently manage tasks without requiring the user to know subcommands**. Detect what the user needs from context and act accordingly.
|
|
1141
|
+
|
|
1153
1142
|
## Context
|
|
1154
1143
|
|
|
1155
1144
|
Read \`docs/priorities.mdx\` if it exists for current priorities.
|
|
@@ -1169,9 +1158,25 @@ When scanning, treat \`index.mdx\` as the primary task doc for a directory.
|
|
|
1169
1158
|
|
|
1170
1159
|
Enforce exactly three values in frontmatter: \`planned\`, \`in-progress\`, \`complete\`.
|
|
1171
1160
|
|
|
1172
|
-
##
|
|
1161
|
+
## Intent Detection
|
|
1162
|
+
|
|
1163
|
+
When \`/work\` is invoked (with or without arguments), detect intent from context:
|
|
1173
1164
|
|
|
1174
|
-
|
|
1165
|
+
| Signal | Action |
|
|
1166
|
+
|--------|--------|
|
|
1167
|
+
| No arguments, no active conversation context | **List** tasks, then let user pick |
|
|
1168
|
+
| User picks a number or names a task | **Resume** that task automatically |
|
|
1169
|
+
| User describes new work (not matching existing tasks) | **Create** a task doc automatically |
|
|
1170
|
+
| \`/work\` with a description that matches no existing task | **Create** automatically |
|
|
1171
|
+
| \`/work\` with a keyword/name matching an existing task | **Resume** automatically |
|
|
1172
|
+
| Conversation is getting heavy, user wrapping up, or 2+ steps completed | **Save** automatically |
|
|
1173
|
+
| All plan steps are COMPLETE | **Suggest** \`/work complete\` (never auto-invoke) |
|
|
1174
|
+
|
|
1175
|
+
**Key principle:** Create, save, and resume are auto-invoked. Complete always asks permission first.
|
|
1176
|
+
|
|
1177
|
+
## Behaviors
|
|
1178
|
+
|
|
1179
|
+
### List and Pick (default when no context)
|
|
1175
1180
|
|
|
1176
1181
|
1. Scan \`docs/in-progress/\` recursively for \`.mdx\` files with \`status\` frontmatter
|
|
1177
1182
|
2. For directories, read \`index.mdx\` as the primary task doc
|
|
@@ -1190,30 +1195,25 @@ Active Tasks
|
|
|
1190
1195
|
3. [complete] CRM Integration
|
|
1191
1196
|
Completed: 2026-03-03
|
|
1192
1197
|
|
|
1193
|
-
Pick a task by number or name
|
|
1194
|
-
- "create" to start new work
|
|
1195
|
-
- "complete <name>" to finish a task
|
|
1198
|
+
Pick a task by number or name, or describe new work to start.
|
|
1196
1199
|
\`\`\`
|
|
1197
1200
|
|
|
1198
1201
|
4. Cross-reference with \`docs/priorities.mdx\` if it exists
|
|
1199
|
-
5. When the user picks a number or describes a task
|
|
1200
|
-
6. If no tasks found,
|
|
1202
|
+
5. When the user picks a number or describes a task, auto-invoke the appropriate flow (resume or create)
|
|
1203
|
+
6. If no tasks found, ask: "What are you trying to accomplish?"
|
|
1201
1204
|
|
|
1202
|
-
###
|
|
1205
|
+
### Create (auto-invoked when new work detected)
|
|
1203
1206
|
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
1. If no description given, ask: "What are you trying to accomplish?"
|
|
1207
|
-
2. Ask 2-3 focused questions:
|
|
1207
|
+
1. If the user's intent is clear, skip the interview and create directly
|
|
1208
|
+
2. If ambiguous, ask 1-2 focused questions:
|
|
1208
1209
|
- "What does success look like?" (acceptance criteria)
|
|
1209
|
-
- "
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
- Scan \`docs/in-progress/\` for existing directories related to the topic
|
|
1210
|
+
- "Do we need to investigate anything first, or is the path clear?"
|
|
1211
|
+
3. Scan \`docs/in-progress/\` for existing directories related to the topic
|
|
1212
|
+
4. Determine directory placement:
|
|
1213
1213
|
- If related to existing directory, create as a file within it
|
|
1214
1214
|
- If new concept that may grow, create \`docs/in-progress/<slug>/index.mdx\`
|
|
1215
1215
|
- If small/standalone, create \`docs/in-progress/<slug>.mdx\`
|
|
1216
|
-
|
|
1216
|
+
5. Create the doc with \`status: planned\` and structured sections:
|
|
1217
1217
|
|
|
1218
1218
|
\`\`\`yaml
|
|
1219
1219
|
---
|
|
@@ -1225,15 +1225,20 @@ status: planned
|
|
|
1225
1225
|
|
|
1226
1226
|
Sections: Objective (what and why), Plan (numbered steps), Progress (per-step tracking with PENDING markers), Resume Context (current state, key docs, "To continue" prompt).
|
|
1227
1227
|
|
|
1228
|
-
|
|
1229
|
-
|
|
1228
|
+
6. Update \`docs/priorities.mdx\` if it exists
|
|
1229
|
+
7. Report what was created with location and step count
|
|
1230
1230
|
|
|
1231
|
-
###
|
|
1231
|
+
### Save (auto-invoked when progress detected)
|
|
1232
1232
|
|
|
1233
|
-
|
|
1233
|
+
Auto-save triggers (do NOT ask, just save):
|
|
1234
|
+
- The conversation context is getting heavy (many tool calls, large file reads)
|
|
1235
|
+
- The user appears to be wrapping up (thanks, goodbye, switching topics)
|
|
1236
|
+
- Significant progress has been made (2+ steps completed without saving)
|
|
1237
|
+
- Before a context reset
|
|
1234
1238
|
|
|
1235
|
-
|
|
1236
|
-
|
|
1239
|
+
Save flow:
|
|
1240
|
+
1. Identify the current task from conversation context
|
|
1241
|
+
2. If not working on a tracked task, offer to create a new one
|
|
1237
1242
|
3. Update Progress section:
|
|
1238
1243
|
- Mark completed steps as \`COMPLETE\` with: what was done, key decisions, files changed
|
|
1239
1244
|
- Mark current step as \`IN PROGRESS\` with current state
|
|
@@ -1243,15 +1248,13 @@ Update the current task doc's Progress and Resume Context:
|
|
|
1243
1248
|
- Files Modified: table of file paths and descriptions of changes
|
|
1244
1249
|
- Key docs to read on resume: file paths with why they matter
|
|
1245
1250
|
- To continue: copy-pasteable prompt for the next session
|
|
1246
|
-
5. Set \`status\` appropriately (\`in-progress\` if ongoing
|
|
1247
|
-
6.
|
|
1248
|
-
|
|
1249
|
-
### \`resume [name-or-number]\`
|
|
1251
|
+
5. Set \`status\` appropriately (\`in-progress\` if ongoing)
|
|
1252
|
+
6. Briefly confirm: "Progress saved to {path}."
|
|
1250
1253
|
|
|
1251
|
-
Resume
|
|
1254
|
+
### Resume (auto-invoked when existing task detected)
|
|
1252
1255
|
|
|
1253
1256
|
**Resolution order:**
|
|
1254
|
-
1. If a number is given
|
|
1257
|
+
1. If a number is given, map to the numbered list from the task list
|
|
1255
1258
|
2. If a name/keyword is given, substring match against task titles and filenames in \`docs/in-progress/\`
|
|
1256
1259
|
3. If no argument, scan for \`status: in-progress\` docs -- if one found, use it; if multiple, list and ask
|
|
1257
1260
|
4. If multiple matches, list them and ask which to resume
|
|
@@ -1277,35 +1280,32 @@ Key context loaded:
|
|
|
1277
1280
|
Ready to continue. {Copy of "To continue" prompt}
|
|
1278
1281
|
\`\`\`
|
|
1279
1282
|
|
|
1280
|
-
###
|
|
1283
|
+
### Complete (NEVER auto-invoked -- always suggest)
|
|
1281
1284
|
|
|
1282
|
-
|
|
1285
|
+
When all plan steps are COMPLETE, suggest: "All steps for '{task}' look done. Want me to finalize it?"
|
|
1283
1286
|
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
+
Only proceed after explicit user confirmation. Then:
|
|
1288
|
+
|
|
1289
|
+
1. **Validate readiness:** Check that all plan steps are marked COMPLETE. If not, warn and ask for confirmation.
|
|
1290
|
+
2. **Clean up the doc:**
|
|
1287
1291
|
- Strip \`## Resume Context\` section entirely (header through next \`##\` or EOF)
|
|
1288
1292
|
- Strip progress markers: \`COMPLETE\`, \`IN PROGRESS\`, \`PENDING\` from step headings
|
|
1289
1293
|
- Remove steps still marked PENDING entirely (header + body) -- they were never done
|
|
1290
1294
|
- Remove \`status\` from frontmatter (keep \`title\` and \`description\`)
|
|
1291
1295
|
- Target 200-400 lines; flag if result exceeds 500 lines
|
|
1292
|
-
|
|
1296
|
+
3. **Determine destination:**
|
|
1293
1297
|
- Scan \`docs/\` (excluding \`docs/in-progress/\`) for existing directories related to this work
|
|
1294
1298
|
- If a related directory exists, propose merging into it
|
|
1295
1299
|
- If no related directory, propose \`docs/<slug>/\` or \`docs/<slug>.mdx\`
|
|
1296
1300
|
- Present the proposed destination and ask user to confirm
|
|
1297
|
-
|
|
1301
|
+
4. **Move the doc(s):**
|
|
1298
1302
|
- Single file: move from \`docs/in-progress/\` to destination
|
|
1299
1303
|
- Directory: move entire directory
|
|
1300
|
-
|
|
1304
|
+
5. **Verify and report:**
|
|
1301
1305
|
- Confirm destination exists, source removed
|
|
1302
1306
|
- Check no leftover \`status:\` or \`## Resume Context\` in moved files
|
|
1303
1307
|
- Update \`docs/priorities.mdx\` if it exists
|
|
1304
1308
|
- Report: task title, cleanup stats (lines before/after), destination path
|
|
1305
|
-
|
|
1306
|
-
## Completion Suggestions
|
|
1307
|
-
|
|
1308
|
-
When the agent observes that all plan steps for a task are marked COMPLETE and the user seems to be moving on, proactively suggest: "All steps for '{task}' are complete. Run \`/work complete\` to finalize it."
|
|
1309
1309
|
`;
|
|
1310
1310
|
}
|
|
1311
1311
|
function claudeDocsCommandTemplate() {
|
|
@@ -1371,7 +1371,7 @@ Steps:
|
|
|
1371
1371
|
|
|
1372
1372
|
### \`create [description]\` -- Reference Doc Creation
|
|
1373
1373
|
|
|
1374
|
-
Interview-driven creation for permanent documentation. Task docs go through \`/work
|
|
1374
|
+
Interview-driven creation for permanent documentation. Task docs go through \`/work\`.
|
|
1375
1375
|
|
|
1376
1376
|
1. If no description given, ask: "What do you want to document?"
|
|
1377
1377
|
2. Determine doc type (infer or ask):
|
|
@@ -1705,17 +1705,19 @@ Exactly three values for frontmatter \`status\`: \`planned\`, \`in-progress\`, \
|
|
|
1705
1705
|
- IN PROGRESS -> COMPLETE (finishing a step)
|
|
1706
1706
|
- Do NOT update on every action -- only on step transitions
|
|
1707
1707
|
|
|
1708
|
-
## Save
|
|
1708
|
+
## Auto-Save Behavior
|
|
1709
1709
|
|
|
1710
|
-
|
|
1710
|
+
The agent auto-saves progress (no user action needed) when:
|
|
1711
1711
|
- The conversation context is getting heavy (many tool calls, large file reads)
|
|
1712
1712
|
- The user appears to be wrapping up (thanks, goodbye, switching topics)
|
|
1713
1713
|
- Significant progress has been made (2+ steps completed without saving)
|
|
1714
|
-
- Before a
|
|
1714
|
+
- Before a context reset
|
|
1715
|
+
|
|
1716
|
+
Auto-save updates the task doc's Progress and Resume Context sections silently, then briefly confirms.
|
|
1715
1717
|
|
|
1716
1718
|
## Completion Suggestions
|
|
1717
1719
|
|
|
1718
|
-
When all plan steps are marked COMPLETE, suggest
|
|
1720
|
+
When all plan steps are marked COMPLETE, **suggest** completing the task -- never auto-invoke. Ask: "All steps for '{task}' look done. Want me to finalize it?"
|
|
1719
1721
|
|
|
1720
1722
|
## Directory Conventions
|
|
1721
1723
|
|
|
@@ -1725,6 +1727,199 @@ When all plan steps are marked COMPLETE, suggest \`/work complete\` to finalize
|
|
|
1725
1727
|
- Completed tasks move OUT of \`docs/in-progress/\` to \`docs/<relevant-dir>/\`
|
|
1726
1728
|
`;
|
|
1727
1729
|
}
|
|
1730
|
+
function claudePostEditValidateHookTemplate() {
|
|
1731
|
+
return `#!/usr/bin/env node
|
|
1732
|
+
// post-edit-validate.mjs
|
|
1733
|
+
// PostToolUse hook \u2014 auto-formats with prettier, type-checks .ts/.tsx files.
|
|
1734
|
+
// Fires after Edit|Write|MultiEdit succeeds.
|
|
1735
|
+
|
|
1736
|
+
import { existsSync } from 'node:fs'
|
|
1737
|
+
import { resolve, normalize, extname, join, dirname } from 'node:path'
|
|
1738
|
+
import { execSync } from 'node:child_process'
|
|
1739
|
+
|
|
1740
|
+
const ROOT = process.env.CLAUDE_PROJECT_DIR ?? process.cwd()
|
|
1741
|
+
|
|
1742
|
+
// Extensions prettier should format
|
|
1743
|
+
const PRETTIER_EXTENSIONS = new Set([
|
|
1744
|
+
'.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.json', '.css', '.md', '.mdx'
|
|
1745
|
+
])
|
|
1746
|
+
|
|
1747
|
+
// Extensions that trigger type-checking
|
|
1748
|
+
const TS_EXTENSIONS = new Set(['.ts', '.tsx'])
|
|
1749
|
+
|
|
1750
|
+
function findNearestTsconfig(startDir) {
|
|
1751
|
+
let dir = startDir
|
|
1752
|
+
const root = normalize(ROOT)
|
|
1753
|
+
while (dir.length >= root.length) {
|
|
1754
|
+
const candidate = join(dir, 'tsconfig.json')
|
|
1755
|
+
if (existsSync(candidate)) return candidate
|
|
1756
|
+
const parent = dirname(dir)
|
|
1757
|
+
if (parent === dir) break
|
|
1758
|
+
dir = parent
|
|
1759
|
+
}
|
|
1760
|
+
return null
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
try {
|
|
1764
|
+
const chunks = []
|
|
1765
|
+
for await (const chunk of process.stdin) chunks.push(chunk)
|
|
1766
|
+
const input = JSON.parse(Buffer.concat(chunks).toString())
|
|
1767
|
+
|
|
1768
|
+
const filePath = input.tool_input?.file_path
|
|
1769
|
+
if (!filePath) process.exit(0)
|
|
1770
|
+
|
|
1771
|
+
const ext = extname(filePath).toLowerCase()
|
|
1772
|
+
const absPath = normalize(resolve(filePath))
|
|
1773
|
+
if (!existsSync(absPath)) process.exit(0)
|
|
1774
|
+
|
|
1775
|
+
const results = []
|
|
1776
|
+
|
|
1777
|
+
// 1. Prettier
|
|
1778
|
+
if (PRETTIER_EXTENSIONS.has(ext)) {
|
|
1779
|
+
try {
|
|
1780
|
+
execSync('pnpm exec prettier --write "' + absPath + '"', {
|
|
1781
|
+
cwd: ROOT,
|
|
1782
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1783
|
+
timeout: 10_000
|
|
1784
|
+
})
|
|
1785
|
+
} catch (err) {
|
|
1786
|
+
const stderr = err.stderr?.toString().trim() || ''
|
|
1787
|
+
if (stderr && !/ignored/i.test(stderr)) {
|
|
1788
|
+
results.push('Prettier error: ' + stderr.slice(0, 300))
|
|
1789
|
+
}
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
// 2. Type-check for .ts/.tsx
|
|
1794
|
+
if (TS_EXTENSIONS.has(ext)) {
|
|
1795
|
+
const tsconfig = findNearestTsconfig(dirname(absPath))
|
|
1796
|
+
if (tsconfig) {
|
|
1797
|
+
try {
|
|
1798
|
+
execSync('pnpm exec tsc --noEmit -p "' + tsconfig + '"', {
|
|
1799
|
+
cwd: ROOT,
|
|
1800
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1801
|
+
timeout: 30_000,
|
|
1802
|
+
env: { ...process.env, NODE_OPTIONS: '--max-old-space-size=4096' }
|
|
1803
|
+
})
|
|
1804
|
+
} catch (err) {
|
|
1805
|
+
if (err.killed) process.exit(0) // Don't block on timeout
|
|
1806
|
+
const stdout = err.stdout?.toString() || ''
|
|
1807
|
+
if (stdout.includes('error TS')) {
|
|
1808
|
+
const errorLines = stdout
|
|
1809
|
+
.split('\\n')
|
|
1810
|
+
.filter(l => l.includes('error TS'))
|
|
1811
|
+
.slice(0, 10)
|
|
1812
|
+
results.push('Type errors after editing ' + filePath + ':\\n' + errorLines.join('\\n'))
|
|
1813
|
+
}
|
|
1814
|
+
}
|
|
1815
|
+
}
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1818
|
+
// Output errors to Claude's context (silence = success)
|
|
1819
|
+
if (results.length > 0) {
|
|
1820
|
+
process.stderr.write(results.join('\\n\\n'))
|
|
1821
|
+
process.exit(2) // Exit 2 = send stderr as feedback to Claude
|
|
1822
|
+
}
|
|
1823
|
+
} catch {}
|
|
1824
|
+
|
|
1825
|
+
process.exit(0)
|
|
1826
|
+
`;
|
|
1827
|
+
}
|
|
1828
|
+
function claudeToolFailureRecoveryHookTemplate() {
|
|
1829
|
+
return `#!/usr/bin/env node
|
|
1830
|
+
// tool-failure-recovery.mjs
|
|
1831
|
+
// PostToolUseFailure hook \u2014 pattern-matches known Bash errors and returns
|
|
1832
|
+
// recovery advice via stderr + exit 2 (feedback to Claude).
|
|
1833
|
+
|
|
1834
|
+
const RECOVERY_TABLE = [
|
|
1835
|
+
{
|
|
1836
|
+
test: r => /JavaScript heap out of memory/i.test(r),
|
|
1837
|
+
advice: 'Out of memory.',
|
|
1838
|
+
fix: 'Run the command with NODE_OPTIONS="--max-old-space-size=4096".',
|
|
1839
|
+
why: 'Large TypeScript projects can exceed Node default heap limit.',
|
|
1840
|
+
},
|
|
1841
|
+
{
|
|
1842
|
+
test: r => /boundary hook/i.test(r) && /block|denied/i.test(r),
|
|
1843
|
+
advice: 'Command blocked by SDK boundary hook.',
|
|
1844
|
+
fix: 'Ask the user to run this command manually.',
|
|
1845
|
+
why: 'The boundary hook blocks file modifications (Write, Edit, destructive Bash) outside the project boundary.',
|
|
1846
|
+
see: 'CLAUDE.md',
|
|
1847
|
+
},
|
|
1848
|
+
{
|
|
1849
|
+
test: r => /ENOENT/.test(r) && /node_modules/.test(r),
|
|
1850
|
+
advice: 'Missing node_modules dependency.',
|
|
1851
|
+
fix: 'Run: pnpm install',
|
|
1852
|
+
why: 'Dependencies are not installed or were cleared.',
|
|
1853
|
+
},
|
|
1854
|
+
{
|
|
1855
|
+
test: r => /ERR_MODULE_NOT_FOUND/.test(r) && /@elevasis\\/sdk/.test(r),
|
|
1856
|
+
advice: '@elevasis/sdk module not found.',
|
|
1857
|
+
fix: 'Run: pnpm install \u2014 then verify @elevasis/sdk is in package.json dependencies.',
|
|
1858
|
+
why: 'The SDK package is not installed or the version is mismatched.',
|
|
1859
|
+
},
|
|
1860
|
+
{
|
|
1861
|
+
test: r => /ERR_MODULE_NOT_FOUND/.test(r),
|
|
1862
|
+
advice: 'Module not found at import path.',
|
|
1863
|
+
fix: 'Check the import path and verify the package is installed (pnpm install).',
|
|
1864
|
+
why: 'The import path does not match any installed package or local file.',
|
|
1865
|
+
},
|
|
1866
|
+
{
|
|
1867
|
+
test: r => /TS2307/.test(r) || (/cannot find/i.test(r) && /declaration/i.test(r)),
|
|
1868
|
+
advice: 'TypeScript cannot resolve module or declaration file.',
|
|
1869
|
+
fix: 'Check that the package is installed and tsconfig paths are correct.',
|
|
1870
|
+
why: 'Missing dependency or incorrect TypeScript configuration.',
|
|
1871
|
+
},
|
|
1872
|
+
{
|
|
1873
|
+
test: r => /EPERM/.test(r) || /permission denied/i.test(r),
|
|
1874
|
+
advice: 'Permission denied (EPERM).',
|
|
1875
|
+
fix: 'Close the file in any other process (editor, terminal, or dev server) and retry.',
|
|
1876
|
+
why: 'On Windows, files locked by another process cannot be written to.',
|
|
1877
|
+
},
|
|
1878
|
+
{
|
|
1879
|
+
test: r => /lockfile/i.test(r) && /conflict|outdated|ERR_PNPM/i.test(r),
|
|
1880
|
+
advice: 'pnpm lockfile conflict or outdated.',
|
|
1881
|
+
fix: 'Run: pnpm install to regenerate the lockfile.',
|
|
1882
|
+
why: 'The lockfile is out of sync with package.json changes.',
|
|
1883
|
+
},
|
|
1884
|
+
{
|
|
1885
|
+
test: r => /elevasis-sdk check/.test(r) || /elevasis-sdk deploy/.test(r),
|
|
1886
|
+
advice: 'elevasis-sdk CLI command failed.',
|
|
1887
|
+
fix: 'Check the error output above. Common causes: missing .env ELEVASIS_API_KEY, invalid resource schemas, or network issues.',
|
|
1888
|
+
why: 'The SDK CLI validates resources and communicates with the platform API.',
|
|
1889
|
+
},
|
|
1890
|
+
{
|
|
1891
|
+
test: r => /EADDRINUSE/.test(r),
|
|
1892
|
+
advice: 'Port already in use.',
|
|
1893
|
+
fix: 'Find and kill the process using the port, or use a different port.',
|
|
1894
|
+
why: 'A previous dev server or process is still holding the port.',
|
|
1895
|
+
},
|
|
1896
|
+
]
|
|
1897
|
+
|
|
1898
|
+
function formatRecovery(entry) {
|
|
1899
|
+
let msg = 'FAILED: ' + entry.advice + '\\nFIX: ' + entry.fix
|
|
1900
|
+
if (entry.why) msg += '\\nWHY: ' + entry.why
|
|
1901
|
+
if (entry.see) msg += '\\nSEE: ' + entry.see
|
|
1902
|
+
return msg
|
|
1903
|
+
}
|
|
1904
|
+
|
|
1905
|
+
try {
|
|
1906
|
+
const chunks = []
|
|
1907
|
+
for await (const chunk of process.stdin) chunks.push(chunk)
|
|
1908
|
+
const input = JSON.parse(Buffer.concat(chunks).toString())
|
|
1909
|
+
|
|
1910
|
+
const response = input.tool_response ?? ''
|
|
1911
|
+
|
|
1912
|
+
for (const entry of RECOVERY_TABLE) {
|
|
1913
|
+
if (entry.test(response)) {
|
|
1914
|
+
process.stderr.write(formatRecovery(entry))
|
|
1915
|
+
process.exit(2)
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
} catch {}
|
|
1919
|
+
|
|
1920
|
+
process.exit(0)
|
|
1921
|
+
`;
|
|
1922
|
+
}
|
|
1728
1923
|
|
|
1729
1924
|
// src/cli/commands/templates/core/resources.ts
|
|
1730
1925
|
function starterWorkflowTemplate() {
|
|
@@ -1882,6 +2077,8 @@ function getManagedTemplates(ctx = {}) {
|
|
|
1882
2077
|
".claude/settings.json": claudeSettingsTemplate,
|
|
1883
2078
|
".claude/scripts/statusline-command.js": claudeStatuslineScriptTemplate,
|
|
1884
2079
|
".claude/hooks/enforce-sdk-boundary.mjs": claudeSdkBoundaryHookTemplate,
|
|
2080
|
+
".claude/hooks/post-edit-validate.mjs": claudePostEditValidateHookTemplate,
|
|
2081
|
+
".claude/hooks/tool-failure-recovery.mjs": claudeToolFailureRecoveryHookTemplate,
|
|
1885
2082
|
".claude/commands/tutorial.md": claudeTutorialCommandTemplate,
|
|
1886
2083
|
".claude/commands/meta.md": claudeMetaCommandTemplate,
|
|
1887
2084
|
".claude/commands/work.md": claudeWorkCommandTemplate,
|
package/dist/worker/index.js
CHANGED
|
@@ -3596,13 +3596,9 @@ function validateActionSequence(actions) {
|
|
|
3596
3596
|
throw new Error("Multiple complete actions not allowed in single iteration");
|
|
3597
3597
|
}
|
|
3598
3598
|
if (completeActions.length === 1) {
|
|
3599
|
-
const
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
if (hasIncompatibleActions) {
|
|
3603
|
-
throw new Error(
|
|
3604
|
-
"Complete action cannot mix with tool-call or navigate-knowledge actions"
|
|
3605
|
-
);
|
|
3599
|
+
const hasNavigateKnowledge = actions.some((a) => a.type === "navigate-knowledge");
|
|
3600
|
+
if (hasNavigateKnowledge) {
|
|
3601
|
+
throw new Error("Complete action cannot mix with navigate-knowledge actions");
|
|
3606
3602
|
}
|
|
3607
3603
|
}
|
|
3608
3604
|
}
|
|
@@ -4912,7 +4908,10 @@ var scheduler = createAdapter("scheduler", [
|
|
|
4912
4908
|
|
|
4913
4909
|
// src/worker/adapters/llm.ts
|
|
4914
4910
|
var llm = {
|
|
4915
|
-
generate: (params) =>
|
|
4911
|
+
generate: async (params) => {
|
|
4912
|
+
const result = await platform.call({ tool: "llm", method: "generate", params });
|
|
4913
|
+
return { output: result };
|
|
4914
|
+
}
|
|
4916
4915
|
};
|
|
4917
4916
|
|
|
4918
4917
|
// src/worker/adapters/storage.ts
|
package/package.json
CHANGED
|
@@ -73,15 +73,15 @@ The `/docs` command manages the permanent `docs/` tree -- everything except `doc
|
|
|
73
73
|
|
|
74
74
|
### `/work` Command
|
|
75
75
|
|
|
76
|
-
The `/work` command manages in-progress task tracking across sessions. It uses `docs/in-progress/` for task documents with standardized frontmatter (`status: planned | in-progress | complete`).
|
|
76
|
+
The `/work` command manages in-progress task tracking across sessions. It uses `docs/in-progress/` for task documents with standardized frontmatter (`status: planned | in-progress | complete`).
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
- **`/work create`** -- Guided interview (5 questions) covering objective, acceptance criteria, relation to existing work, investigation needed, and placement. New docs start with `status: planned`. Placement is determined intelligently: related directory, new directory for multi-file tasks, flat file for small tasks.
|
|
80
|
-
- **`/work save`** -- Comprehensive snapshot: progress markers, files modified table, key docs to read on resume, and a copy-pasteable "To continue" prompt. Proactively suggested before context pressure builds.
|
|
81
|
-
- **`/work resume [<name>]`** -- Load a task by number, keyword, or auto-detect. Loads key docs in parallel and verifies referenced files exist. No file paths required.
|
|
82
|
-
- **`/work complete`** -- Seven-step pipeline: resolve target, validate readiness, clean doc (strip resume context, remove progress markers, target 200-400 lines), determine destination in `docs/`, confirm with user, move, verify.
|
|
78
|
+
`/work` is intent-driven -- the agent detects what to do from context rather than requiring explicit subcommands:
|
|
83
79
|
|
|
84
|
-
|
|
80
|
+
- **`/work`** (no arguments) -- Lists tasks sorted by status (`in-progress` first) with last-saved date and current step. Pick by number or name to auto-resume, or describe new work to auto-create a task.
|
|
81
|
+
- **Auto-create** -- When the user describes work that doesn't match an existing task, the agent creates a task doc automatically. If intent is clear, it skips the interview; if ambiguous, it asks 1-2 focused questions.
|
|
82
|
+
- **Auto-save** -- The agent saves progress silently when the conversation context is getting heavy, the user is wrapping up, or 2+ steps have been completed without saving. Updates progress markers, files modified, and resume context.
|
|
83
|
+
- **Auto-resume** -- When the user picks an existing task (by number, name, or keyword), the agent loads context and resumes automatically.
|
|
84
|
+
- **Suggest complete** -- When all plan steps are marked COMPLETE, the agent suggests finalizing: "All steps for '{task}' look done. Want me to finalize it?" It never auto-invokes completion. The complete flow validates readiness, cleans the doc (strips resume context, removes progress markers, targets 200-400 lines), determines destination in `docs/`, confirms with user, moves, and verifies.
|
|
85
85
|
|
|
86
86
|
**Directory conventions for `docs/in-progress/`:**
|
|
87
87
|
|