@procrastivity/clast 0.0.3 → 0.0.4
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-plugin/skills/day-wakeup/SKILL.md +21 -19
- package/.claude-plugin/skills/wakeup/SKILL.md +15 -13
- package/README.md +32 -29
- package/bin/clast +22 -124
- package/bin/clast-plumbing +173 -0
- package/examples/cron/clast-snapshot.service +2 -2
- package/examples/cron/clast-snapshot.timer +1 -1
- package/examples/cron/crontab.sample +4 -4
- package/examples/workflows/morning-briefing.md +11 -11
- package/hooks/snapshot.sh +5 -5
- package/lib/clast/clast-dismissed-lib.bash +6 -5
- package/lib/clast/clast-lib.bash +5 -2
- package/lib/clast/clast-manifest-lib.bash +28 -5
- package/lib/clast/clast-porcelain-lib.bash +217 -0
- package/lib/clast/clast-porcelain-subcommands/brief.bash +167 -0
- package/{bin/clast-wake → lib/clast/clast-porcelain-subcommands/wake.bash} +87 -217
- package/lib/clast/clast-registry-lib.bash +32 -14
- package/lib/clast/clast-subcommands/projects.bash +7 -1
- package/lib/clast/clast-subcommands/sessions.bash +92 -47
- package/lib/clast/clast-subcommands/show.bash +15 -4
- package/lib/clast/clast-subcommands/snapshot.bash +12 -2
- package/lib/clast/clast-subcommands/stats.bash +7 -2
- package/package.json +2 -3
- package/bin/clast-brief +0 -305
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: day-wakeup
|
|
3
|
-
description: 'Generate curated journal entries from yesterday''s Claude Code sessions across all projects. Use when the user says "/day-wakeup", "day wakeup", "morning briefing", "catch me up on yesterday", "what did I work on yesterday", "review my day", "process yesterday''s sessions", or otherwise signals they want to curate prior work across projects at the start of a new day. Runs `clast snapshot` to ensure fresh data, then walks through each uncurated session from yesterday and proposes a draft entry the user can accept, edit, or skip. Prompts for promotion of decisions, common-issues, and workflows per accepted session. This is the once-per-day curation flow; for per-project briefings use /wakeup; for mid-session pivots use session-brief.'
|
|
3
|
+
description: 'Generate curated journal entries from yesterday''s Claude Code sessions across all projects. Use when the user says "/day-wakeup", "day wakeup", "morning briefing", "catch me up on yesterday", "what did I work on yesterday", "review my day", "process yesterday''s sessions", or otherwise signals they want to curate prior work across projects at the start of a new day. Runs `clast-plumbing snapshot` to ensure fresh data, then walks through each uncurated session from yesterday and proposes a draft entry the user can accept, edit, or skip. Prompts for promotion of decisions, common-issues, and workflows per accepted session. This is the once-per-day curation flow; for per-project briefings use /wakeup; for mid-session pivots use session-brief.'
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Day Wakeup
|
|
@@ -13,28 +13,30 @@ Curation at end-of-session has high friction (the user wants to stop, not summar
|
|
|
13
13
|
|
|
14
14
|
The transcripts themselves are captured automatically by the SessionStart hook + cron — the user never has to remember to log anything. What `/day-wakeup` does is **curate the captured transcripts into durable entries the user controls**, and prompt for promotion of decisions, common-issues, and workflows along the way.
|
|
15
15
|
|
|
16
|
-
## Step 0: Resolve the clast binary
|
|
16
|
+
## Step 0: Resolve the clast-plumbing binary
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
This skill calls the deterministic core (`clast-plumbing`), not the
|
|
19
|
+
LLM-aware porcelain (`clast`). Determine the binary to use once at the
|
|
20
|
+
start and reuse the result for all commands in this skill:
|
|
20
21
|
|
|
21
22
|
```bash
|
|
22
|
-
if [[ -n "${CLAUDE_PLUGIN_ROOT:-}" && -x "$CLAUDE_PLUGIN_ROOT/bin/clast" ]]; then
|
|
23
|
-
CLAST_BIN="$CLAUDE_PLUGIN_ROOT/bin/clast"
|
|
24
|
-
elif command -v clast >/dev/null 2>&1; then
|
|
25
|
-
CLAST_BIN="clast"
|
|
23
|
+
if [[ -n "${CLAUDE_PLUGIN_ROOT:-}" && -x "$CLAUDE_PLUGIN_ROOT/bin/clast-plumbing" ]]; then
|
|
24
|
+
CLAST_BIN="$CLAUDE_PLUGIN_ROOT/bin/clast-plumbing"
|
|
25
|
+
elif command -v clast-plumbing >/dev/null 2>&1; then
|
|
26
|
+
CLAST_BIN="clast-plumbing"
|
|
26
27
|
else
|
|
27
28
|
_pdir="$(find ~/.claude -maxdepth 5 -name plugin.json -path '*/clast/.claude-plugin/*' -print -quit 2>/dev/null)"
|
|
28
29
|
if [[ -n "$_pdir" ]]; then
|
|
29
|
-
CLAST_BIN="$(cd "$(dirname "$_pdir")/../.." && pwd)/bin/clast"
|
|
30
|
+
CLAST_BIN="$(cd "$(dirname "$_pdir")/../.." && pwd)/bin/clast-plumbing"
|
|
30
31
|
fi
|
|
31
32
|
fi
|
|
32
33
|
```
|
|
33
34
|
|
|
34
|
-
If `CLAST_BIN` is still empty, tell the user: "clast CLI not found.
|
|
35
|
-
with `npm i -g @procrastivity/clast` or see the README for other
|
|
35
|
+
If `CLAST_BIN` is still empty, tell the user: "clast-plumbing CLI not found.
|
|
36
|
+
Install it with `npm i -g @procrastivity/clast` or see the README for other
|
|
37
|
+
options."
|
|
36
38
|
|
|
37
|
-
Use `$CLAST_BIN` in place of bare `clast` for all commands in this skill.
|
|
39
|
+
Use `$CLAST_BIN` in place of bare `clast-plumbing` for all commands in this skill.
|
|
38
40
|
|
|
39
41
|
## Step 1: Ensure fresh data
|
|
40
42
|
|
|
@@ -108,7 +110,7 @@ For each session in the list:
|
|
|
108
110
|
5. Present the **promotion question** (see below) via AskUserQuestion.
|
|
109
111
|
|
|
110
112
|
6. Handle the response:
|
|
111
|
-
- **Accept** (any combination of accept-flavored options): pipe the draft to `clast entries write` via stdin.
|
|
113
|
+
- **Accept** (any combination of accept-flavored options): pipe the draft to `clast-plumbing entries write` via stdin.
|
|
112
114
|
- **Edit**: prompt the user for what to change, regenerate the draft incorporating their feedback, loop.
|
|
113
115
|
- **Skip**: do not write.
|
|
114
116
|
- **Stop here**: end the entire `/day-wakeup` flow, leaving remaining sessions uncurated (user can resume tomorrow).
|
|
@@ -133,7 +135,7 @@ Run `/wakeup <project>` to start working on a specific project today.
|
|
|
133
135
|
|
|
134
136
|
## Draft generation prompt
|
|
135
137
|
|
|
136
|
-
The prompt templates live in `lib/clast/prompts/` so they are shared with the
|
|
138
|
+
The prompt templates live in `lib/clast/prompts/` so they are shared with the porcelain `clast wake` subcommand:
|
|
137
139
|
|
|
138
140
|
- **System prompt:** `lib/clast/prompts/day-wakeup-draft-system.md`
|
|
139
141
|
- **User prompt template:** `lib/clast/prompts/day-wakeup-draft-user.md` (uses `{{placeholder}}` syntax)
|
|
@@ -175,7 +177,7 @@ If the user selects `Edit`:
|
|
|
175
177
|
When the user accepts:
|
|
176
178
|
|
|
177
179
|
1. Extract the suggested tags from the draft (the user may have edited them).
|
|
178
|
-
2. Pipe the entry body (without the suggested-tags trailer) to `clast entries write`:
|
|
180
|
+
2. Pipe the entry body (without the suggested-tags trailer) to `clast-plumbing entries write`:
|
|
179
181
|
|
|
180
182
|
```bash
|
|
181
183
|
$CLAST_BIN entries write \
|
|
@@ -190,14 +192,14 @@ $CLAST_BIN entries write \
|
|
|
190
192
|
|
|
191
193
|
3. If the write succeeds, append a one-line confirmation to the running summary.
|
|
192
194
|
|
|
193
|
-
For promoted items (decisions, common-issues, workflows): currently these are tracked inside the entry's body for v1. **TODO for v1.1: separate `clast decisions write` / `clast common-issues write` / `clast workflows write` subcommands and a directory structure to match.** Note this in the user-facing summary so the user knows they're folded into the entry for now.
|
|
195
|
+
For promoted items (decisions, common-issues, workflows): currently these are tracked inside the entry's body for v1. **TODO for v1.1: separate `clast-plumbing decisions write` / `clast-plumbing common-issues write` / `clast-plumbing workflows write` subcommands and a directory structure to match.** Note this in the user-facing summary so the user knows they're folded into the entry for now.
|
|
194
196
|
|
|
195
|
-
<!-- step-12 addition: v1 promotion section convention --> When folding promoted items into the accepted entry body, append `## Decision`, `## Common issue`, or `## Workflow` (h2, singular, capitalized), each followed by the prompted-for title (h3) and body before invoking `clast entries write`.
|
|
197
|
+
<!-- step-12 addition: v1 promotion section convention --> When folding promoted items into the accepted entry body, append `## Decision`, `## Common issue`, or `## Workflow` (h2, singular, capitalized), each followed by the prompted-for title (h3) and body before invoking `clast-plumbing entries write`.
|
|
196
198
|
|
|
197
199
|
## Edge cases
|
|
198
200
|
|
|
199
201
|
- **No uncurated sessions**: print "Nothing to curate — all sessions are curated or dismissed." and stop.
|
|
200
202
|
- **Multi-day backlog**: present the triage step (Step 2) so the user can choose scope before processing.
|
|
201
|
-
- **`clast snapshot` fails**: warn the user, then attempt to proceed with whatever's already in the manifest.
|
|
202
|
-
- **`clast show` fails for a specific session**: skip that session, note it in the final summary, continue with the rest.
|
|
203
|
+
- **`clast-plumbing snapshot` fails**: warn the user, then attempt to proceed with whatever's already in the manifest.
|
|
204
|
+
- **`clast-plumbing show` fails for a specific session**: skip that session, note it in the final summary, continue with the rest.
|
|
203
205
|
- **User says "do them all without prompting"**: not a v1 feature. Each session gets its own AskUserQuestion. The friction is intentional — it's where curation happens.
|
|
@@ -12,28 +12,30 @@ Synthesize a briefing for the current (or named) project so the user can resume
|
|
|
12
12
|
|
|
13
13
|
`/day-wakeup` curates yesterday's work into entries. `/wakeup` reads those entries back when starting work in a specific repo. The two are complementary: one writes, one reads.
|
|
14
14
|
|
|
15
|
-
## Step 0: Resolve the clast binary
|
|
15
|
+
## Step 0: Resolve the clast-plumbing binary
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
This skill calls the deterministic core (`clast-plumbing`), not the
|
|
18
|
+
LLM-aware porcelain (`clast`). Determine the binary to use once at the
|
|
19
|
+
start and reuse the result for all commands in this skill:
|
|
19
20
|
|
|
20
21
|
```bash
|
|
21
|
-
if [[ -n "${CLAUDE_PLUGIN_ROOT:-}" && -x "$CLAUDE_PLUGIN_ROOT/bin/clast" ]]; then
|
|
22
|
-
CLAST_BIN="$CLAUDE_PLUGIN_ROOT/bin/clast"
|
|
23
|
-
elif command -v clast >/dev/null 2>&1; then
|
|
24
|
-
CLAST_BIN="clast"
|
|
22
|
+
if [[ -n "${CLAUDE_PLUGIN_ROOT:-}" && -x "$CLAUDE_PLUGIN_ROOT/bin/clast-plumbing" ]]; then
|
|
23
|
+
CLAST_BIN="$CLAUDE_PLUGIN_ROOT/bin/clast-plumbing"
|
|
24
|
+
elif command -v clast-plumbing >/dev/null 2>&1; then
|
|
25
|
+
CLAST_BIN="clast-plumbing"
|
|
25
26
|
else
|
|
26
27
|
_pdir="$(find ~/.claude -maxdepth 5 -name plugin.json -path '*/clast/.claude-plugin/*' -print -quit 2>/dev/null)"
|
|
27
28
|
if [[ -n "$_pdir" ]]; then
|
|
28
|
-
CLAST_BIN="$(cd "$(dirname "$_pdir")/../.." && pwd)/bin/clast"
|
|
29
|
+
CLAST_BIN="$(cd "$(dirname "$_pdir")/../.." && pwd)/bin/clast-plumbing"
|
|
29
30
|
fi
|
|
30
31
|
fi
|
|
31
32
|
```
|
|
32
33
|
|
|
33
|
-
If `CLAST_BIN` is still empty, tell the user: "clast CLI not found.
|
|
34
|
-
with `npm i -g @procrastivity/clast` or see the README for other
|
|
34
|
+
If `CLAST_BIN` is still empty, tell the user: "clast-plumbing CLI not found.
|
|
35
|
+
Install it with `npm i -g @procrastivity/clast` or see the README for other
|
|
36
|
+
options."
|
|
35
37
|
|
|
36
|
-
Use `$CLAST_BIN` in place of bare `clast` for all commands in this skill.
|
|
38
|
+
Use `$CLAST_BIN` in place of bare `clast-plumbing` for all commands in this skill.
|
|
37
39
|
|
|
38
40
|
## Step 1: Resolve the project
|
|
39
41
|
|
|
@@ -43,7 +45,7 @@ If the user passed a slug as an argument (`/wakeup xesapps`), use it directly. O
|
|
|
43
45
|
$CLAST_BIN registry resolve "$(pwd)"
|
|
44
46
|
```
|
|
45
47
|
|
|
46
|
-
If `pwd` doesn't resolve and no slug was given: print "Not in a registered project. Run `clast registry add .` first, or invoke as `/wakeup <slug>`." and stop.
|
|
48
|
+
If `pwd` doesn't resolve and no slug was given: print "Not in a registered project. Run `clast-plumbing registry add .` first, or invoke as `/wakeup <slug>`." and stop.
|
|
47
49
|
|
|
48
50
|
## Step 2: Gather data
|
|
49
51
|
|
|
@@ -103,7 +105,7 @@ Wakeup is read-only. Never invoke write-form subcommands (`entries write`, `brea
|
|
|
103
105
|
|
|
104
106
|
## Edge cases
|
|
105
107
|
|
|
106
|
-
- **No entries for project**: print "No curated entries for `<slug>` yet. Run `/day-wakeup` to process recent sessions, or run `clast sessions --project <slug>` to see what's available." and stop.
|
|
108
|
+
- **No entries for project**: print "No curated entries for `<slug>` yet. Run `/day-wakeup` to process recent sessions, or run `clast-plumbing sessions --project <slug>` to see what's available." and stop.
|
|
107
109
|
- **Slug resolves but no entries and no sessions**: print "Project `<slug>` registered but has no journal activity yet."
|
|
108
110
|
- **Today's session count > 5**: summarize ("worked 12 sessions today, most recent 16:22 on branch `loop-guard-ngram`") rather than listing all.
|
|
109
111
|
|
package/README.md
CHANGED
|
@@ -6,27 +6,30 @@ Capture, curate, and surface Claude Code session history across all your project
|
|
|
6
6
|
|
|
7
7
|
## What it does
|
|
8
8
|
|
|
9
|
-
- **CLI**
|
|
9
|
+
- **CLI** — two binaries, porcelain over plumbing:
|
|
10
|
+
- `clast` — porcelain (LLM-aware): `clast wake`, `clast brief`. See [run without Claude Code](./docs/guides/run-without-claude-code.md).
|
|
11
|
+
- `clast-plumbing` — deterministic core: snapshot, browse, and query your Claude Code session JSONL history.
|
|
10
12
|
- **Plugin** — installs skills (`/day-wakeup`, `/wakeup`) that surface recent session context.
|
|
11
13
|
- **SessionStart hook** — quietly snapshots active sessions in the background each time Claude Code starts.
|
|
12
14
|
|
|
13
15
|
## Capture your sessions
|
|
14
16
|
|
|
15
17
|
```sh
|
|
16
|
-
clast snapshot # copy any new sessions into the journal
|
|
17
|
-
clast snapshot --dry-run --json | jq # preview what would be captured
|
|
18
|
+
clast-plumbing snapshot # copy any new sessions into the journal
|
|
19
|
+
clast-plumbing snapshot --dry-run --json | jq # preview what would be captured
|
|
18
20
|
```
|
|
19
21
|
|
|
20
|
-
`clast snapshot` is idempotent and silent on no-op, safe to run from
|
|
21
|
-
a SessionStart hook. See
|
|
22
|
+
`clast-plumbing snapshot` is idempotent and silent on no-op, safe to run from
|
|
23
|
+
cron or a SessionStart hook. See
|
|
24
|
+
[`docs/reference/cli.md#clast-snapshot`](./docs/reference/cli.md#clast-snapshot)
|
|
22
25
|
for the full flag reference.
|
|
23
26
|
|
|
24
27
|
## Read your sessions
|
|
25
28
|
|
|
26
29
|
```sh
|
|
27
|
-
clast projects # which projects had activity today
|
|
28
|
-
clast sessions --since -7d # sessions captured in the last week
|
|
29
|
-
clast show <session-uuid> --full # metadata + first/last turns
|
|
30
|
+
clast-plumbing projects # which projects had activity today
|
|
31
|
+
clast-plumbing sessions --since -7d # sessions captured in the last week
|
|
32
|
+
clast-plumbing show <session-uuid> --full # metadata + first/last turns
|
|
30
33
|
```
|
|
31
34
|
|
|
32
35
|
Window flags (`--day`, `--since`, `--until`) accept ISO dates and
|
|
@@ -39,14 +42,14 @@ for the full flag and output schemas.
|
|
|
39
42
|
## Curate an entry
|
|
40
43
|
|
|
41
44
|
```sh
|
|
42
|
-
clast entries # list curated entries
|
|
43
|
-
clast entries read 2026-05-30-1430-xesapps-foo.md # cat a single entry
|
|
44
|
-
printf 'Notes...\n' | clast entries write \
|
|
45
|
-
--session <session-uuid> --slug short-slug --body-stdin
|
|
45
|
+
clast-plumbing entries # list curated entries
|
|
46
|
+
clast-plumbing entries read 2026-05-30-1430-xesapps-foo.md # cat a single entry
|
|
47
|
+
printf 'Notes...\n' | clast-plumbing entries write \
|
|
48
|
+
--session <session-uuid> --slug short-slug --body-stdin # write a new entry
|
|
46
49
|
```
|
|
47
50
|
|
|
48
|
-
`clast entries write` looks up the session in the manifest, composes
|
|
49
|
-
documented frontmatter from the captured snapshot + registry, and writes
|
|
51
|
+
`clast-plumbing entries write` looks up the session in the manifest, composes
|
|
52
|
+
the documented frontmatter from the captured snapshot + registry, and writes
|
|
50
53
|
`entries/YYYY-MM-DD-HHMM-<project-slug>-<session-slug>.md` atomically. See
|
|
51
54
|
[`docs/reference/cli.md#entry-frontmatter`](./docs/reference/cli.md#entry-frontmatter)
|
|
52
55
|
for the full frontmatter schema and
|
|
@@ -56,11 +59,11 @@ for the flag reference.
|
|
|
56
59
|
## Leave a breadcrumb
|
|
57
60
|
|
|
58
61
|
```sh
|
|
59
|
-
clast breadcrumb --project xesapps 'check migration before deploy'
|
|
60
|
-
clast breadcrumb --global 'remember to bump the cache version'
|
|
62
|
+
clast-plumbing breadcrumb --project xesapps 'check migration before deploy'
|
|
63
|
+
clast-plumbing breadcrumb --global 'remember to bump the cache version'
|
|
61
64
|
|
|
62
|
-
clast breadcrumb --read --project xesapps
|
|
63
|
-
clast breadcrumb --read --global
|
|
65
|
+
clast-plumbing breadcrumb --read --project xesapps
|
|
66
|
+
clast-plumbing breadcrumb --read --global
|
|
64
67
|
```
|
|
65
68
|
|
|
66
69
|
Breadcrumbs are append-only one-line notes for `/wakeup` and `/day-wakeup`.
|
|
@@ -70,17 +73,17 @@ for the full command contract.
|
|
|
70
73
|
## Inspect and audit the journal
|
|
71
74
|
|
|
72
75
|
```sh
|
|
73
|
-
clast stats # one-line activity summary for today
|
|
74
|
-
clast stats --since -7d # rollup over the last week
|
|
76
|
+
clast-plumbing stats # one-line activity summary for today
|
|
77
|
+
clast-plumbing stats --since -7d # rollup over the last week
|
|
75
78
|
|
|
76
|
-
clast doctor # check manifest, registry, snapshots
|
|
77
|
-
clast doctor --fix # rebuild a broken manifest, prune orphans
|
|
79
|
+
clast-plumbing doctor # check manifest, registry, snapshots
|
|
80
|
+
clast-plumbing doctor --fix # rebuild a broken manifest, prune orphans
|
|
78
81
|
```
|
|
79
82
|
|
|
80
83
|
See [`docs/reference/cli.md#clast-stats`](./docs/reference/cli.md#clast-stats)
|
|
81
84
|
and [`docs/reference/cli.md#clast-doctor`](./docs/reference/cli.md#clast-doctor)
|
|
82
|
-
for the contract reference, and `clast stats --help` /
|
|
83
|
-
for the current set of flags.
|
|
85
|
+
for the contract reference, and `clast-plumbing stats --help` /
|
|
86
|
+
`clast-plumbing doctor --help` for the current set of flags.
|
|
84
87
|
|
|
85
88
|
## Install to a prefix
|
|
86
89
|
|
|
@@ -102,9 +105,9 @@ for the rationale.
|
|
|
102
105
|
With Nix flakes enabled, you can use `clast` directly from the public flake:
|
|
103
106
|
|
|
104
107
|
```sh
|
|
105
|
-
nix run github:procrastivity/clast -- whereami
|
|
106
108
|
nix profile install github:procrastivity/clast
|
|
107
|
-
nix build .#default && ./result/bin/clast --version
|
|
109
|
+
nix build .#default && ./result/bin/clast --version # porcelain
|
|
110
|
+
nix build .#default && ./result/bin/clast-plumbing --help # plumbing
|
|
108
111
|
```
|
|
109
112
|
|
|
110
113
|
For Home Manager or nix-darwin users, `overlays.default` exposes `pkgs.clast`.
|
|
@@ -135,9 +138,9 @@ The plugin can be installed from any local checkout, or via `npm install -g`
|
|
|
135
138
|
(which puts `.claude-plugin/` under `npm root -g`); a centralized marketplace
|
|
136
139
|
listing is a separate distribution channel deliberately not pursued for v1.
|
|
137
140
|
Today the plugin ships a single `SessionStart` hook: every time a Claude Code
|
|
138
|
-
session starts it backgrounds `clast snapshot`, so your journal stays
|
|
139
|
-
with zero manual effort. The hook is best-effort and silent: if the
|
|
140
|
-
isn't on your `PATH` yet, sessions still start cleanly. See
|
|
141
|
+
session starts it backgrounds `clast-plumbing snapshot`, so your journal stays
|
|
142
|
+
current with zero manual effort. The hook is best-effort and silent: if the
|
|
143
|
+
`clast-plumbing` CLI isn't on your `PATH` yet, sessions still start cleanly. See
|
|
141
144
|
[`docs/reference/plugin.md#hook-sessionstart`](./docs/reference/plugin.md#hook-sessionstart)
|
|
142
145
|
for the hook's design rationale.
|
|
143
146
|
|
package/bin/clast
CHANGED
|
@@ -1,93 +1,41 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
# clast —
|
|
2
|
+
# clast — porcelain over clast-plumbing, with an OpenAI-compatible LLM
|
|
3
|
+
# provider. Owns the `wake` and `brief` subcommands. Every other verb is a
|
|
4
|
+
# clean error — the porcelain does not proxy to plumbing.
|
|
3
5
|
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
# each defines a single function `clast_cmd_<name>`.
|
|
6
|
+
# Subcommand files live in $CLAST_LIB/clast-porcelain-subcommands/<name>.bash
|
|
7
|
+
# and each defines a single function `clast_cmd_<name>`.
|
|
7
8
|
set -euo pipefail
|
|
8
9
|
|
|
9
10
|
CLAST_LIB="${CLAST_LIB:-$(dirname "$(realpath "$0")")/../lib/clast}"
|
|
10
11
|
export CLAST_LIB
|
|
11
12
|
|
|
12
|
-
# shellcheck source=lib/clast/clast-lib.bash
|
|
13
|
-
source "$CLAST_LIB/clast-lib.bash"
|
|
14
|
-
# shellcheck source=lib/clast/clast-decode-lib.bash
|
|
15
|
-
source "$CLAST_LIB/clast-decode-lib.bash"
|
|
16
|
-
# shellcheck source=lib/clast/clast-registry-lib.bash
|
|
17
|
-
source "$CLAST_LIB/clast-registry-lib.bash"
|
|
18
|
-
# shellcheck source=lib/clast/clast-manifest-lib.bash
|
|
19
|
-
source "$CLAST_LIB/clast-manifest-lib.bash"
|
|
20
|
-
|
|
21
|
-
# --- Global flag parsing -------------------------------------------------
|
|
22
|
-
#
|
|
23
|
-
# Walk argv before the subcommand name, peeling off any recognized global
|
|
24
|
-
# flag and setting the corresponding env var. Stop at the first non-flag
|
|
25
|
-
# arg (the subcommand) or at `--`. Remaining argv is passed to the
|
|
26
|
-
# subcommand untouched.
|
|
27
|
-
#
|
|
28
|
-
# `--json` and `--journal-dir`/`--projects-dir` are forwarded to the lib
|
|
29
|
-
# via env so subcommands can also accept them locally without re-parsing.
|
|
13
|
+
# shellcheck source=lib/clast/clast-porcelain-lib.bash
|
|
14
|
+
source "$CLAST_LIB/clast-porcelain-lib.bash"
|
|
30
15
|
|
|
31
16
|
declare -a _CLAST_REMAINING=()
|
|
32
17
|
|
|
33
18
|
while [[ $# -gt 0 ]]; do
|
|
34
19
|
case "$1" in
|
|
35
20
|
-h|--help|help)
|
|
36
|
-
|
|
21
|
+
clast_porcelain_usage
|
|
37
22
|
exit 0
|
|
38
23
|
;;
|
|
39
24
|
--version)
|
|
40
|
-
echo "clast $(
|
|
25
|
+
echo "clast $(clast_porcelain_version)"
|
|
41
26
|
exit 0
|
|
42
27
|
;;
|
|
43
|
-
--json)
|
|
44
|
-
export CLAST_JSON=1
|
|
45
|
-
shift
|
|
46
|
-
;;
|
|
47
|
-
-v|--verbose)
|
|
48
|
-
export CLAST_VERBOSE=1
|
|
49
|
-
shift
|
|
50
|
-
;;
|
|
51
|
-
-q|--quiet)
|
|
52
|
-
export CLAST_QUIET=1
|
|
53
|
-
shift
|
|
54
|
-
;;
|
|
55
|
-
--journal-dir)
|
|
56
|
-
if [[ $# -lt 2 ]]; then
|
|
57
|
-
clast_log_error "--journal-dir requires a value"
|
|
58
|
-
exit 2
|
|
59
|
-
fi
|
|
60
|
-
export CLAST_JOURNAL_DIR="$2"
|
|
61
|
-
shift 2
|
|
62
|
-
;;
|
|
63
|
-
--journal-dir=*)
|
|
64
|
-
export CLAST_JOURNAL_DIR="${1#*=}"
|
|
65
|
-
shift
|
|
66
|
-
;;
|
|
67
|
-
--projects-dir)
|
|
68
|
-
if [[ $# -lt 2 ]]; then
|
|
69
|
-
clast_log_error "--projects-dir requires a value"
|
|
70
|
-
exit 2
|
|
71
|
-
fi
|
|
72
|
-
export CLAST_PROJECTS_DIR="$2"
|
|
73
|
-
shift 2
|
|
74
|
-
;;
|
|
75
|
-
--projects-dir=*)
|
|
76
|
-
export CLAST_PROJECTS_DIR="${1#*=}"
|
|
77
|
-
shift
|
|
78
|
-
;;
|
|
79
28
|
--)
|
|
80
29
|
shift
|
|
81
30
|
_CLAST_REMAINING+=("$@")
|
|
82
31
|
break
|
|
83
32
|
;;
|
|
84
33
|
-*)
|
|
85
|
-
|
|
86
|
-
|
|
34
|
+
clast_porcelain_log_error "unknown global flag: $1"
|
|
35
|
+
clast_porcelain_usage >&2
|
|
87
36
|
exit 2
|
|
88
37
|
;;
|
|
89
38
|
*)
|
|
90
|
-
# First non-flag arg is the subcommand; stop parsing.
|
|
91
39
|
_CLAST_REMAINING+=("$@")
|
|
92
40
|
break
|
|
93
41
|
;;
|
|
@@ -95,7 +43,7 @@ while [[ $# -gt 0 ]]; do
|
|
|
95
43
|
done
|
|
96
44
|
|
|
97
45
|
if [[ ${#_CLAST_REMAINING[@]} -eq 0 ]]; then
|
|
98
|
-
|
|
46
|
+
clast_porcelain_usage
|
|
99
47
|
exit 0
|
|
100
48
|
fi
|
|
101
49
|
|
|
@@ -103,70 +51,20 @@ set -- "${_CLAST_REMAINING[@]}"
|
|
|
103
51
|
|
|
104
52
|
cmd="$1"; shift
|
|
105
53
|
|
|
106
|
-
# --- Subcommand dispatch -------------------------------------------------
|
|
107
|
-
|
|
108
|
-
# Map of stubbed subcommands → step number that will implement them.
|
|
109
|
-
# Future steps replace each stub with a real `source` + dispatch below.
|
|
110
|
-
_clast_stub() {
|
|
111
|
-
local name="$1" step="$2"
|
|
112
|
-
clast_log_error "$name is not yet implemented (planned for step $step)"
|
|
113
|
-
exit 2
|
|
114
|
-
}
|
|
115
|
-
|
|
116
54
|
case "$cmd" in
|
|
117
|
-
|
|
118
|
-
# shellcheck source=lib/clast/clast-subcommands/
|
|
119
|
-
source "$CLAST_LIB/clast-subcommands/
|
|
120
|
-
|
|
121
|
-
;;
|
|
122
|
-
snapshot)
|
|
123
|
-
# shellcheck source=lib/clast/clast-subcommands/snapshot.bash
|
|
124
|
-
source "$CLAST_LIB/clast-subcommands/snapshot.bash"
|
|
125
|
-
clast_cmd_snapshot "$@"
|
|
126
|
-
;;
|
|
127
|
-
projects)
|
|
128
|
-
# shellcheck source=lib/clast/clast-subcommands/projects.bash
|
|
129
|
-
source "$CLAST_LIB/clast-subcommands/projects.bash"
|
|
130
|
-
clast_cmd_projects "$@"
|
|
131
|
-
;;
|
|
132
|
-
sessions)
|
|
133
|
-
# shellcheck source=lib/clast/clast-subcommands/sessions.bash
|
|
134
|
-
source "$CLAST_LIB/clast-subcommands/sessions.bash"
|
|
135
|
-
clast_cmd_sessions "$@"
|
|
136
|
-
;;
|
|
137
|
-
show)
|
|
138
|
-
# shellcheck source=lib/clast/clast-subcommands/show.bash
|
|
139
|
-
source "$CLAST_LIB/clast-subcommands/show.bash"
|
|
140
|
-
clast_cmd_show "$@"
|
|
141
|
-
;;
|
|
142
|
-
entries)
|
|
143
|
-
# shellcheck source=lib/clast/clast-subcommands/entries.bash
|
|
144
|
-
source "$CLAST_LIB/clast-subcommands/entries.bash"
|
|
145
|
-
clast_cmd_entries "$@"
|
|
146
|
-
;;
|
|
147
|
-
breadcrumb)
|
|
148
|
-
# shellcheck source=lib/clast/clast-subcommands/breadcrumb.bash
|
|
149
|
-
source "$CLAST_LIB/clast-subcommands/breadcrumb.bash"
|
|
150
|
-
clast_cmd_breadcrumb "$@"
|
|
151
|
-
;;
|
|
152
|
-
registry)
|
|
153
|
-
# shellcheck source=lib/clast/clast-subcommands/registry.bash
|
|
154
|
-
source "$CLAST_LIB/clast-subcommands/registry.bash"
|
|
155
|
-
clast_cmd_registry "$@"
|
|
156
|
-
;;
|
|
157
|
-
stats)
|
|
158
|
-
# shellcheck source=lib/clast/clast-subcommands/stats.bash
|
|
159
|
-
source "$CLAST_LIB/clast-subcommands/stats.bash"
|
|
160
|
-
clast_cmd_stats "$@"
|
|
55
|
+
wake)
|
|
56
|
+
# shellcheck source=lib/clast/clast-porcelain-subcommands/wake.bash
|
|
57
|
+
source "$CLAST_LIB/clast-porcelain-subcommands/wake.bash"
|
|
58
|
+
clast_cmd_wake "$@"
|
|
161
59
|
;;
|
|
162
|
-
|
|
163
|
-
# shellcheck source=lib/clast/clast-subcommands/
|
|
164
|
-
source "$CLAST_LIB/clast-subcommands/
|
|
165
|
-
|
|
60
|
+
brief)
|
|
61
|
+
# shellcheck source=lib/clast/clast-porcelain-subcommands/brief.bash
|
|
62
|
+
source "$CLAST_LIB/clast-porcelain-subcommands/brief.bash"
|
|
63
|
+
clast_cmd_brief "$@"
|
|
166
64
|
;;
|
|
167
65
|
*)
|
|
168
|
-
|
|
169
|
-
|
|
66
|
+
clast_porcelain_log_error "unknown subcommand '$cmd'"
|
|
67
|
+
clast_porcelain_usage >&2
|
|
170
68
|
exit 2
|
|
171
69
|
;;
|
|
172
70
|
esac
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# clast-plumbing — main dispatcher (the deterministic, LLM-free core).
|
|
3
|
+
#
|
|
4
|
+
# Parses global flags, sources libs, dispatches to a subcommand.
|
|
5
|
+
# Subcommand files live in $CLAST_LIB/clast-subcommands/<name>.bash and
|
|
6
|
+
# each defines a single function `clast_cmd_<name>`. The user-facing
|
|
7
|
+
# porcelain is `bin/clast` (see `clast --help` for that surface).
|
|
8
|
+
set -euo pipefail
|
|
9
|
+
|
|
10
|
+
CLAST_LIB="${CLAST_LIB:-$(dirname "$(realpath "$0")")/../lib/clast}"
|
|
11
|
+
export CLAST_LIB
|
|
12
|
+
|
|
13
|
+
# shellcheck source=lib/clast/clast-lib.bash
|
|
14
|
+
source "$CLAST_LIB/clast-lib.bash"
|
|
15
|
+
# shellcheck source=lib/clast/clast-decode-lib.bash
|
|
16
|
+
source "$CLAST_LIB/clast-decode-lib.bash"
|
|
17
|
+
# shellcheck source=lib/clast/clast-registry-lib.bash
|
|
18
|
+
source "$CLAST_LIB/clast-registry-lib.bash"
|
|
19
|
+
# shellcheck source=lib/clast/clast-manifest-lib.bash
|
|
20
|
+
source "$CLAST_LIB/clast-manifest-lib.bash"
|
|
21
|
+
|
|
22
|
+
# --- Global flag parsing -------------------------------------------------
|
|
23
|
+
#
|
|
24
|
+
# Walk argv before the subcommand name, peeling off any recognized global
|
|
25
|
+
# flag and setting the corresponding env var. Stop at the first non-flag
|
|
26
|
+
# arg (the subcommand) or at `--`. Remaining argv is passed to the
|
|
27
|
+
# subcommand untouched.
|
|
28
|
+
#
|
|
29
|
+
# `--json` and `--journal-dir`/`--projects-dir` are forwarded to the lib
|
|
30
|
+
# via env so subcommands can also accept them locally without re-parsing.
|
|
31
|
+
|
|
32
|
+
declare -a _CLAST_REMAINING=()
|
|
33
|
+
|
|
34
|
+
while [[ $# -gt 0 ]]; do
|
|
35
|
+
case "$1" in
|
|
36
|
+
-h|--help|help)
|
|
37
|
+
clast_usage
|
|
38
|
+
exit 0
|
|
39
|
+
;;
|
|
40
|
+
--version)
|
|
41
|
+
echo "clast-plumbing $(clast_version)"
|
|
42
|
+
exit 0
|
|
43
|
+
;;
|
|
44
|
+
--json)
|
|
45
|
+
export CLAST_JSON=1
|
|
46
|
+
shift
|
|
47
|
+
;;
|
|
48
|
+
-v|--verbose)
|
|
49
|
+
export CLAST_VERBOSE=1
|
|
50
|
+
shift
|
|
51
|
+
;;
|
|
52
|
+
-q|--quiet)
|
|
53
|
+
export CLAST_QUIET=1
|
|
54
|
+
shift
|
|
55
|
+
;;
|
|
56
|
+
--journal-dir)
|
|
57
|
+
if [[ $# -lt 2 ]]; then
|
|
58
|
+
clast_log_error "--journal-dir requires a value"
|
|
59
|
+
exit 2
|
|
60
|
+
fi
|
|
61
|
+
export CLAST_JOURNAL_DIR="$2"
|
|
62
|
+
shift 2
|
|
63
|
+
;;
|
|
64
|
+
--journal-dir=*)
|
|
65
|
+
export CLAST_JOURNAL_DIR="${1#*=}"
|
|
66
|
+
shift
|
|
67
|
+
;;
|
|
68
|
+
--projects-dir)
|
|
69
|
+
if [[ $# -lt 2 ]]; then
|
|
70
|
+
clast_log_error "--projects-dir requires a value"
|
|
71
|
+
exit 2
|
|
72
|
+
fi
|
|
73
|
+
export CLAST_PROJECTS_DIR="$2"
|
|
74
|
+
shift 2
|
|
75
|
+
;;
|
|
76
|
+
--projects-dir=*)
|
|
77
|
+
export CLAST_PROJECTS_DIR="${1#*=}"
|
|
78
|
+
shift
|
|
79
|
+
;;
|
|
80
|
+
--)
|
|
81
|
+
shift
|
|
82
|
+
_CLAST_REMAINING+=("$@")
|
|
83
|
+
break
|
|
84
|
+
;;
|
|
85
|
+
-*)
|
|
86
|
+
clast_log_error "unknown global flag: $1"
|
|
87
|
+
clast_usage >&2
|
|
88
|
+
exit 2
|
|
89
|
+
;;
|
|
90
|
+
*)
|
|
91
|
+
# First non-flag arg is the subcommand; stop parsing.
|
|
92
|
+
_CLAST_REMAINING+=("$@")
|
|
93
|
+
break
|
|
94
|
+
;;
|
|
95
|
+
esac
|
|
96
|
+
done
|
|
97
|
+
|
|
98
|
+
if [[ ${#_CLAST_REMAINING[@]} -eq 0 ]]; then
|
|
99
|
+
clast_usage
|
|
100
|
+
exit 0
|
|
101
|
+
fi
|
|
102
|
+
|
|
103
|
+
set -- "${_CLAST_REMAINING[@]}"
|
|
104
|
+
|
|
105
|
+
cmd="$1"; shift
|
|
106
|
+
|
|
107
|
+
# --- Subcommand dispatch -------------------------------------------------
|
|
108
|
+
|
|
109
|
+
# Map of stubbed subcommands → step number that will implement them.
|
|
110
|
+
# Future steps replace each stub with a real `source` + dispatch below.
|
|
111
|
+
_clast_stub() {
|
|
112
|
+
local name="$1" step="$2"
|
|
113
|
+
clast_log_error "$name is not yet implemented (planned for step $step)"
|
|
114
|
+
exit 2
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
case "$cmd" in
|
|
118
|
+
whereami)
|
|
119
|
+
# shellcheck source=lib/clast/clast-subcommands/whereami.bash
|
|
120
|
+
source "$CLAST_LIB/clast-subcommands/whereami.bash"
|
|
121
|
+
clast_cmd_whereami "$@"
|
|
122
|
+
;;
|
|
123
|
+
snapshot)
|
|
124
|
+
# shellcheck source=lib/clast/clast-subcommands/snapshot.bash
|
|
125
|
+
source "$CLAST_LIB/clast-subcommands/snapshot.bash"
|
|
126
|
+
clast_cmd_snapshot "$@"
|
|
127
|
+
;;
|
|
128
|
+
projects)
|
|
129
|
+
# shellcheck source=lib/clast/clast-subcommands/projects.bash
|
|
130
|
+
source "$CLAST_LIB/clast-subcommands/projects.bash"
|
|
131
|
+
clast_cmd_projects "$@"
|
|
132
|
+
;;
|
|
133
|
+
sessions)
|
|
134
|
+
# shellcheck source=lib/clast/clast-subcommands/sessions.bash
|
|
135
|
+
source "$CLAST_LIB/clast-subcommands/sessions.bash"
|
|
136
|
+
clast_cmd_sessions "$@"
|
|
137
|
+
;;
|
|
138
|
+
show)
|
|
139
|
+
# shellcheck source=lib/clast/clast-subcommands/show.bash
|
|
140
|
+
source "$CLAST_LIB/clast-subcommands/show.bash"
|
|
141
|
+
clast_cmd_show "$@"
|
|
142
|
+
;;
|
|
143
|
+
entries)
|
|
144
|
+
# shellcheck source=lib/clast/clast-subcommands/entries.bash
|
|
145
|
+
source "$CLAST_LIB/clast-subcommands/entries.bash"
|
|
146
|
+
clast_cmd_entries "$@"
|
|
147
|
+
;;
|
|
148
|
+
breadcrumb)
|
|
149
|
+
# shellcheck source=lib/clast/clast-subcommands/breadcrumb.bash
|
|
150
|
+
source "$CLAST_LIB/clast-subcommands/breadcrumb.bash"
|
|
151
|
+
clast_cmd_breadcrumb "$@"
|
|
152
|
+
;;
|
|
153
|
+
registry)
|
|
154
|
+
# shellcheck source=lib/clast/clast-subcommands/registry.bash
|
|
155
|
+
source "$CLAST_LIB/clast-subcommands/registry.bash"
|
|
156
|
+
clast_cmd_registry "$@"
|
|
157
|
+
;;
|
|
158
|
+
stats)
|
|
159
|
+
# shellcheck source=lib/clast/clast-subcommands/stats.bash
|
|
160
|
+
source "$CLAST_LIB/clast-subcommands/stats.bash"
|
|
161
|
+
clast_cmd_stats "$@"
|
|
162
|
+
;;
|
|
163
|
+
doctor)
|
|
164
|
+
# shellcheck source=lib/clast/clast-subcommands/doctor.bash
|
|
165
|
+
source "$CLAST_LIB/clast-subcommands/doctor.bash"
|
|
166
|
+
clast_cmd_doctor "$@"
|
|
167
|
+
;;
|
|
168
|
+
*)
|
|
169
|
+
clast_log_error "unknown subcommand '$cmd'"
|
|
170
|
+
clast_usage >&2
|
|
171
|
+
exit 2
|
|
172
|
+
;;
|
|
173
|
+
esac
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
# then enable the timer with: systemctl --user enable --now clast-snapshot.timer
|
|
4
4
|
|
|
5
5
|
[Unit]
|
|
6
|
-
Description=Capture Claude Code transcripts with clast
|
|
6
|
+
Description=Capture Claude Code transcripts with clast-plumbing
|
|
7
7
|
|
|
8
8
|
[Service]
|
|
9
9
|
Type=oneshot
|
|
10
|
-
ExecStart=/usr/local/bin/clast snapshot
|
|
10
|
+
ExecStart=/usr/local/bin/clast-plumbing snapshot
|