@erclx/aitk 1.6.0 → 1.7.1
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/claude/.claude-plugin/plugin.json +1 -1
- package/docs/agents/records.md +1 -1
- package/package.json +1 -1
- package/scripts/core/check-color-source.sh +41 -0
- package/scripts/core/snapshot.sh +17 -15
- package/scripts/core/verify.sh +1 -0
- package/scripts/lib/ui.sh +82 -13
- package/scripts/manage-sandbox.sh +6 -0
- package/scripts/tooling/ref.sh +6 -0
- package/src/records/backup.ts +11 -4
- package/tooling/claude/manifest.toml +1 -1
- package/tooling/claude/reference.md +1 -1
package/docs/agents/records.md
CHANGED
|
@@ -110,7 +110,7 @@ aitk records push --json
|
|
|
110
110
|
aitk records pull
|
|
111
111
|
```
|
|
112
112
|
|
|
113
|
-
The backed folders are `groundwork`, `intake`, `memory`, `plans`, `plans-archive`, `review`, `review-archive`, `task-archive`, `tasks`, and `teach`, all under `.claude/`. They are the
|
|
113
|
+
The backed folders are `groundwork`, `intake`, `memory`, `plans`, `plans-archive`, `review`, `review-archive`, `task-archive`, `tasks`, and `teach`, all under `.claude/`. They are the Claude ignore group the claude manifest ships, minus three entries: `.claude/.tmp`, which is deletable without loss, `.claude/worktrees/`, whose contents belong to the project repository already, and `.claude/.records.git/`, which is the history the other ten are pushed into. The list is a constant rather than configuration, matching the four folder names `validate` hardcodes.
|
|
114
114
|
|
|
115
115
|
Records are gitignored by design, so the history lives in a second git directory at `.claude/.records.git` with `.claude/` as its work tree. Every path stays where it is, which is what a separate checkout could not do. The verbs stage the ten folders by explicit pathspec with `--force`, so nothing outside them can enter the index however the ignore rules read, and the project working tree and its index are never touched.
|
|
116
116
|
|
package/package.json
CHANGED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -e
|
|
3
|
+
set -o pipefail
|
|
4
|
+
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
6
|
+
PROJECT_ROOT="${PROJECT_ROOT:-$(cd "$SCRIPT_DIR/../.." && pwd)}"
|
|
7
|
+
|
|
8
|
+
SCRIPTS_ROOT="$PROJECT_ROOT/scripts"
|
|
9
|
+
PALETTE_SOURCE="$SCRIPTS_ROOT/lib/ui.sh"
|
|
10
|
+
|
|
11
|
+
# `find` writes to stderr and returns non-zero for a missing root, inside a
|
|
12
|
+
# process substitution whose status nothing reads. Without this the walk covers
|
|
13
|
+
# nothing and the check reports the tree clean having never measured it.
|
|
14
|
+
if [ ! -f "$PALETTE_SOURCE" ]; then
|
|
15
|
+
echo "No palette source at ${PALETTE_SOURCE#"$PROJECT_ROOT/"}, color sourcing unverifiable." >&2
|
|
16
|
+
exit 1
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
# Any SGR sequence in either spelling. The cursor and erase sequences an
|
|
20
|
+
# interactive prompt writes end in a letter instead, and they run only where a
|
|
21
|
+
# terminal already exists, so they are not what this measures.
|
|
22
|
+
SGR='\\(033|e|x1b)\[[0-9;]*m'
|
|
23
|
+
|
|
24
|
+
# Sixteen copies of one decision is what made color impossible to turn off on
|
|
25
|
+
# the TypeScript side. A rule nothing enforces rebuilds them the next time a
|
|
26
|
+
# script wants grey, so the escape lives in the shared library and every other
|
|
27
|
+
# script reads the palette that library derives for its stream.
|
|
28
|
+
offenders=""
|
|
29
|
+
while IFS= read -r file; do
|
|
30
|
+
[ "$file" = "$PALETTE_SOURCE" ] && continue
|
|
31
|
+
if grep -qE "$SGR" "$file"; then
|
|
32
|
+
offenders="$offenders ${file#"$PROJECT_ROOT/"}"$'\n'
|
|
33
|
+
fi
|
|
34
|
+
done < <(find "$SCRIPTS_ROOT" -type f -name '*.sh')
|
|
35
|
+
|
|
36
|
+
if [ -n "$offenders" ]; then
|
|
37
|
+
echo "A color escape is defined outside the shared library:" >&2
|
|
38
|
+
printf '%s' "$offenders" >&2
|
|
39
|
+
echo "Source scripts/lib/ui.sh and read its palette, so one answer covers every writer." >&2
|
|
40
|
+
exit 1
|
|
41
|
+
fi
|
package/scripts/core/snapshot.sh
CHANGED
|
@@ -2,19 +2,13 @@
|
|
|
2
2
|
set -e
|
|
3
3
|
set -o pipefail
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
WHITE='\033[1;37m'
|
|
8
|
-
GREY='\033[0;90m'
|
|
9
|
-
NC='\033[0m'
|
|
5
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
6
|
+
PROJECT_ROOT="${PROJECT_ROOT:-$(cd "$SCRIPT_DIR/../.." && pwd)}"
|
|
10
7
|
|
|
11
|
-
|
|
8
|
+
# shellcheck source=/dev/null
|
|
9
|
+
source "$PROJECT_ROOT/scripts/lib/ui.sh"
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
log_error() {
|
|
15
|
-
echo -e "${GREY}│${NC} ${RED}✗${NC} $1"
|
|
16
|
-
exit 1
|
|
17
|
-
}
|
|
11
|
+
NESTED="${VERIFY_NESTED:-false}"
|
|
18
12
|
|
|
19
13
|
OUTPUT_FILE=".claude/.tmp/project/PROJECT-SNAPSHOT.md"
|
|
20
14
|
|
|
@@ -117,15 +111,23 @@ write_snapshot() {
|
|
|
117
111
|
main() {
|
|
118
112
|
check_dependencies
|
|
119
113
|
|
|
120
|
-
if [ "$NESTED" = false ]; then
|
|
114
|
+
if [ "$NESTED" = false ]; then open_timeline; fi
|
|
121
115
|
|
|
122
|
-
|
|
116
|
+
log_step "Snapshot"
|
|
123
117
|
write_snapshot
|
|
124
118
|
log_info "Written to $OUTPUT_FILE"
|
|
125
119
|
|
|
120
|
+
# The whole frame goes to stderr, since the run writes its document to a file
|
|
121
|
+
# and leaves stdout carrying nothing. Edges on stdout with the body on stderr
|
|
122
|
+
# would capture as a frame with no body inside it.
|
|
126
123
|
if [ "$NESTED" = false ]; then
|
|
127
|
-
|
|
128
|
-
|
|
124
|
+
close_timeline
|
|
125
|
+
# All six are declared to scope what `set_palette` assigns, so the four this
|
|
126
|
+
# line never spells stay out of the globals a sourcing script reads.
|
|
127
|
+
# shellcheck disable=SC2034
|
|
128
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
129
|
+
set_palette 2
|
|
130
|
+
echo -e "\n${GREEN}✓ Snapshot complete${NC}" >&2
|
|
129
131
|
fi
|
|
130
132
|
}
|
|
131
133
|
|
package/scripts/core/verify.sh
CHANGED
|
@@ -595,6 +595,7 @@ main() {
|
|
|
595
595
|
log_step "Shell"
|
|
596
596
|
if has_changed '\.sh$|^package\.json$'; then
|
|
597
597
|
run_check "bun run check:shell" "Shell check failed"
|
|
598
|
+
run_check "bash $PROJECT_ROOT/scripts/core/check-color-source.sh" "A color escape is defined outside scripts/lib/ui.sh."
|
|
598
599
|
log_info "Shell check passed"
|
|
599
600
|
else
|
|
600
601
|
log_info "Skipped, no shell changes"
|
package/scripts/lib/ui.sh
CHANGED
|
@@ -12,26 +12,85 @@ fi
|
|
|
12
12
|
# shellcheck source=/dev/null
|
|
13
13
|
source "$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")/sandbox-path.sh"
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
# `NO_COLOR` follows the published convention, where any non-empty value turns
|
|
16
|
+
# color off whatever the value says.
|
|
17
|
+
supports_color() {
|
|
18
|
+
[ -z "${NO_COLOR:-}" ] && [ -t "$1" ]
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
# Assigns the six palette names for one file descriptor. The blank palette keeps
|
|
22
|
+
# every frame character and drops only the escapes, so a captured run still
|
|
23
|
+
# reads as one block.
|
|
24
|
+
#
|
|
25
|
+
# Bash returns a string and nothing richer, so the palette arrives through the
|
|
26
|
+
# caller's own scope. A writer declaring all six `local` before calling this
|
|
27
|
+
# keeps the assignment to itself, which is what leaves the source-time answer
|
|
28
|
+
# below standing for anything that sources this file.
|
|
29
|
+
set_palette() {
|
|
30
|
+
if supports_color "$1"; then
|
|
31
|
+
GREEN='\033[0;32m'
|
|
32
|
+
RED='\033[0;31m'
|
|
33
|
+
YELLOW='\033[0;33m'
|
|
34
|
+
WHITE='\033[1;37m'
|
|
35
|
+
GREY='\033[0;90m'
|
|
36
|
+
NC='\033[0m'
|
|
37
|
+
else
|
|
38
|
+
GREEN=''
|
|
39
|
+
RED=''
|
|
40
|
+
YELLOW=''
|
|
41
|
+
WHITE=''
|
|
42
|
+
GREY=''
|
|
43
|
+
NC=''
|
|
44
|
+
fi
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# Every writer below frames to stderr and asks about that stream at write time,
|
|
48
|
+
# so no answer is frozen before a caller's redirect is in place. This one answers
|
|
49
|
+
# for stdout instead, because it is read by a sourcing script writing its own
|
|
50
|
+
# frame with a bare `echo`, and that is the stream a bare `echo` reaches.
|
|
51
|
+
set_palette 1
|
|
52
|
+
|
|
53
|
+
log_info() {
|
|
54
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
55
|
+
set_palette 2
|
|
56
|
+
echo -e "${GREY}│${NC} ${GREEN}✓${NC} $1" >&2
|
|
57
|
+
}
|
|
58
|
+
log_warn() {
|
|
59
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
60
|
+
set_palette 2
|
|
61
|
+
echo -e "${GREY}│${NC} ${YELLOW}!${NC} $1" >&2
|
|
62
|
+
}
|
|
24
63
|
log_error() {
|
|
64
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
65
|
+
set_palette 2
|
|
25
66
|
echo -e "${GREY}│${NC} ${RED}✗${NC} $1" >&2
|
|
26
67
|
exit 1
|
|
27
68
|
}
|
|
28
|
-
log_step() {
|
|
29
|
-
|
|
30
|
-
|
|
69
|
+
log_step() {
|
|
70
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
71
|
+
set_palette 2
|
|
72
|
+
echo -e "${GREY}│${NC}\n${GREY}├${NC} ${WHITE}$1${NC}" >&2
|
|
73
|
+
}
|
|
74
|
+
log_add() {
|
|
75
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
76
|
+
set_palette 2
|
|
77
|
+
echo -e "${GREY}│${NC} ${GREEN}+${NC} $1" >&2
|
|
78
|
+
}
|
|
79
|
+
log_rem() {
|
|
80
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
81
|
+
set_palette 2
|
|
82
|
+
echo -e "${GREY}│${NC} ${RED}-${NC} $1" >&2
|
|
83
|
+
}
|
|
31
84
|
|
|
32
|
-
pipe_output() {
|
|
85
|
+
pipe_output() {
|
|
86
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
87
|
+
set_palette 2
|
|
88
|
+
while IFS= read -r line; do echo -e "${GREY}│${NC} $line" >&2; done
|
|
89
|
+
}
|
|
33
90
|
|
|
34
91
|
open_timeline() {
|
|
92
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
93
|
+
set_palette 2
|
|
35
94
|
echo -e "${GREY}┌${NC}" >&2
|
|
36
95
|
if [ -n "${1:-}" ]; then
|
|
37
96
|
echo -e "${GREY}│${NC} ${WHITE}$1${NC}" >&2
|
|
@@ -39,6 +98,8 @@ open_timeline() {
|
|
|
39
98
|
}
|
|
40
99
|
|
|
41
100
|
close_timeline() {
|
|
101
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
102
|
+
set_palette 2
|
|
42
103
|
echo -e "${GREY}└${NC}" >&2
|
|
43
104
|
}
|
|
44
105
|
|
|
@@ -52,6 +113,8 @@ guard_root() {
|
|
|
52
113
|
}
|
|
53
114
|
|
|
54
115
|
require_project_root() {
|
|
116
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
117
|
+
set_palette 2
|
|
55
118
|
local sandbox
|
|
56
119
|
sandbox="$(resolve_sandbox_dir)"
|
|
57
120
|
if [[ "$PWD" == "$sandbox" || "$PWD" == "$sandbox"/* ]]; then
|
|
@@ -65,6 +128,8 @@ require_project_root() {
|
|
|
65
128
|
}
|
|
66
129
|
|
|
67
130
|
ask() {
|
|
131
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
132
|
+
set_palette 2
|
|
68
133
|
local prompt_text=$1
|
|
69
134
|
local var_name=$2
|
|
70
135
|
local default_val=$3
|
|
@@ -107,6 +172,8 @@ ask() {
|
|
|
107
172
|
}
|
|
108
173
|
|
|
109
174
|
select_or_route_scenario() {
|
|
175
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
176
|
+
set_palette 2
|
|
110
177
|
local prompt_text=$1
|
|
111
178
|
shift
|
|
112
179
|
local options=("$@")
|
|
@@ -122,6 +189,8 @@ select_or_route_scenario() {
|
|
|
122
189
|
}
|
|
123
190
|
|
|
124
191
|
select_option() {
|
|
192
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
193
|
+
set_palette 2
|
|
125
194
|
local prompt_text=$1
|
|
126
195
|
shift
|
|
127
196
|
local options=("$@")
|
|
@@ -320,6 +320,8 @@ execute_sandbox_and_commit() {
|
|
|
320
320
|
}
|
|
321
321
|
|
|
322
322
|
finalize_sandbox_run() {
|
|
323
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
324
|
+
set_palette 2
|
|
323
325
|
trap - EXIT
|
|
324
326
|
close_timeline
|
|
325
327
|
echo "" >&2
|
|
@@ -327,6 +329,8 @@ finalize_sandbox_run() {
|
|
|
327
329
|
}
|
|
328
330
|
|
|
329
331
|
cmd_clean() {
|
|
332
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
333
|
+
set_palette 2
|
|
330
334
|
log_step "Removing sandbox"
|
|
331
335
|
rm -rf "$SANDBOX"
|
|
332
336
|
log_rem "$SANDBOX"
|
|
@@ -337,6 +341,8 @@ cmd_clean() {
|
|
|
337
341
|
}
|
|
338
342
|
|
|
339
343
|
reset_sandbox() {
|
|
344
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
345
|
+
set_palette 2
|
|
340
346
|
if [ ! -d "$SANDBOX/.git" ]; then
|
|
341
347
|
log_error "No sandbox found. Run \`aitk sandbox\` first."
|
|
342
348
|
fi
|
package/scripts/tooling/ref.sh
CHANGED
|
@@ -91,6 +91,12 @@ main() {
|
|
|
91
91
|
local stack="$1"
|
|
92
92
|
local target="${2:-.}"
|
|
93
93
|
|
|
94
|
+
# Every frame below goes to stderr, so it asks about that stream rather than
|
|
95
|
+
# reading the source-time answer, which is for stdout and is what `show_help`
|
|
96
|
+
# above wants. Declared after the help branch so that call keeps it.
|
|
97
|
+
local GREEN RED YELLOW WHITE GREY NC
|
|
98
|
+
set_palette 2
|
|
99
|
+
|
|
94
100
|
echo -e "${GREY}┌${NC}" >&2
|
|
95
101
|
echo -e "${GREY}│${NC} ${WHITE}aitk tooling ref${NC}" >&2
|
|
96
102
|
|
package/src/records/backup.ts
CHANGED
|
@@ -5,10 +5,17 @@ import { gitEnv } from '@/git-env'
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* The folders a backup carries, relative to `.claude/`. They are the `# Claude`
|
|
8
|
-
* group
|
|
9
|
-
* without loss,
|
|
10
|
-
* enclosing repository already
|
|
11
|
-
*
|
|
8
|
+
* group the claude manifest ships, minus three: `.claude/.tmp`, which is
|
|
9
|
+
* defined as deletable without loss, `.claude/worktrees/`, whose contents
|
|
10
|
+
* belong to the enclosing repository already, and `.claude/.records.git/`,
|
|
11
|
+
* which is the history the other ten are pushed into. The list is spelled out
|
|
12
|
+
* rather than read off that group so adding an ignore entry cannot silently
|
|
13
|
+
* enlarge the payload.
|
|
14
|
+
*
|
|
15
|
+
* The manifest group is the one this reads rather than the enclosing
|
|
16
|
+
* repository's own `.gitignore`, which spreads the same entries across two
|
|
17
|
+
* headers and carries `.claude/README.md` that no target receives. Subtracting
|
|
18
|
+
* three from that file instead yields eleven names against this list of ten.
|
|
12
19
|
*
|
|
13
20
|
* `RECORD_KINDS` in `validate.ts` overlaps this on five names and carries one
|
|
14
21
|
* more that no backup reaches. The two lists differ on purpose: one is what a
|
|
@@ -8,4 +8,4 @@ runtime = ""
|
|
|
8
8
|
scaffold = ""
|
|
9
9
|
|
|
10
10
|
[gitignore]
|
|
11
|
-
"# Claude" = [".claude/.tmp/", ".claude/groundwork/", ".claude/intake/", ".claude/memory/", ".claude/plans/", ".claude/plans-archive/", ".claude/review/", ".claude/review-archive/", ".claude/task-archive/", ".claude/worktrees/", ".claude/tasks/"]
|
|
11
|
+
"# Claude" = [".claude/.records.git/", ".claude/.tmp/", ".claude/groundwork/", ".claude/intake/", ".claude/memory/", ".claude/plans/", ".claude/plans-archive/", ".claude/review/", ".claude/review-archive/", ".claude/task-archive/", ".claude/worktrees/", ".claude/tasks/", ".claude/teach/"]
|
|
@@ -50,7 +50,7 @@ A project installed before the diagram surface became a folder still holds `.cla
|
|
|
50
50
|
|
|
51
51
|
## Gitignore
|
|
52
52
|
|
|
53
|
-
- `# Claude`: `.claude/.tmp/`, `.claude/groundwork/`, `.claude/intake/`, `.claude/memory/`, `.claude/plans/`, `.claude/plans-archive/`, `.claude/review/`, `.claude/review-archive/`, `.claude/task-archive/`, `.claude/worktrees/`, `.claude/tasks/`
|
|
53
|
+
- `# Claude`: `.claude/.records.git/`, `.claude/.tmp/`, `.claude/groundwork/`, `.claude/intake/`, `.claude/memory/`, `.claude/plans/`, `.claude/plans-archive/`, `.claude/review/`, `.claude/review-archive/`, `.claude/task-archive/`, `.claude/worktrees/`, `.claude/tasks/`, `.claude/teach/`
|
|
54
54
|
|
|
55
55
|
## CLI
|
|
56
56
|
|