@workscribe/cli 2.1.0 → 3.0.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/README.md +7 -4
- package/dist/index.js +5061 -1455
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/shell/hook.bash +26 -5
- package/shell/hook.zsh +14 -4
- package/skills/workscribe/SKILL.md +7 -2
- package/skills/workscribe/references/json-contract.md +24 -6
- package/skills/workscribe/references/summary-format.md +4 -3
package/package.json
CHANGED
package/shell/hook.bash
CHANGED
|
@@ -1,9 +1,26 @@
|
|
|
1
1
|
# Workscribe — developer work journal
|
|
2
2
|
# Do not edit this block manually. Managed by `workscribe init`.
|
|
3
3
|
# workscribe:hook:start
|
|
4
|
+
# workscribe:hook-version 2
|
|
5
|
+
# Now in milliseconds, or nothing: bash 5's $EPOCHREALTIME, else `date +%s` (macOS's bash 3.2 has no $EPOCHREALTIME,
|
|
6
|
+
# and its BSD date has no %N)
|
|
7
|
+
_workscribe_now_ms() {
|
|
8
|
+
if [[ -n "${EPOCHREALTIME:-}" ]]; then
|
|
9
|
+
local micros=${EPOCHREALTIME//[.,]/}
|
|
10
|
+
[[ $micros =~ ^[0-9]+$ ]] && echo $(( 10#$micros / 1000 ))
|
|
11
|
+
return 0
|
|
12
|
+
fi
|
|
13
|
+
local seconds
|
|
14
|
+
seconds=$(date +%s 2>/dev/null)
|
|
15
|
+
[[ $seconds =~ ^[0-9]+$ ]] && echo $(( seconds * 1000 ))
|
|
16
|
+
return 0
|
|
17
|
+
}
|
|
18
|
+
|
|
4
19
|
_workscribe_preexec() {
|
|
20
|
+
# The DEBUG trap also fires for the rest of the rc file — nothing before the first prompt is the user's command
|
|
21
|
+
[[ -n "${_workscribe_primed:-}" ]] || return 0
|
|
5
22
|
if [ "$BASH_COMMAND" != "_workscribe_precmd" ]; then
|
|
6
|
-
_workscribe_cmd_start=$(
|
|
23
|
+
_workscribe_cmd_start=$(_workscribe_now_ms)
|
|
7
24
|
_workscribe_last_cmd="$BASH_COMMAND"
|
|
8
25
|
_workscribe_git_before=$(git rev-parse HEAD 2>/dev/null || echo "")
|
|
9
26
|
fi
|
|
@@ -13,17 +30,21 @@ _workscribe_precmd() {
|
|
|
13
30
|
local exit_code=$?
|
|
14
31
|
command -v workscribe &>/dev/null || return 0
|
|
15
32
|
if [[ -n "$_workscribe_last_cmd" ]]; then
|
|
16
|
-
|
|
17
|
-
now
|
|
18
|
-
|
|
33
|
+
# The command is captured even when it can't be timed: no duration rather than no event
|
|
34
|
+
local now duration=""
|
|
35
|
+
now=$(_workscribe_now_ms)
|
|
36
|
+
if [[ $now =~ ^[0-9]+$ && $_workscribe_cmd_start =~ ^[0-9]+$ ]]; then
|
|
37
|
+
duration=$(( now - _workscribe_cmd_start ))
|
|
38
|
+
fi
|
|
19
39
|
command workscribe _capture \
|
|
20
40
|
--cmd "$_workscribe_last_cmd" \
|
|
21
41
|
--cwd "$PWD" \
|
|
22
42
|
--exit "$exit_code" \
|
|
23
|
-
|
|
43
|
+
${duration:+--duration "$duration"} \
|
|
24
44
|
${_workscribe_git_before:+--git-before "$_workscribe_git_before"} \
|
|
25
45
|
> /dev/null 2>&1 &
|
|
26
46
|
_workscribe_last_cmd=""
|
|
47
|
+
_workscribe_cmd_start=""
|
|
27
48
|
_workscribe_git_before=""
|
|
28
49
|
fi
|
|
29
50
|
# Skip the alert check on the first precmd: it fires before the shell has
|
package/shell/hook.zsh
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# Workscribe — developer work journal
|
|
2
2
|
# Do not edit this block manually. Managed by `workscribe init`.
|
|
3
3
|
# workscribe:hook:start
|
|
4
|
+
# workscribe:hook-version 2
|
|
5
|
+
# $EPOCHREALTIME exists only once zsh/datetime is loaded — plain zsh doesn't load it
|
|
6
|
+
zmodload zsh/datetime 2>/dev/null
|
|
7
|
+
|
|
4
8
|
_workscribe_preexec() {
|
|
5
9
|
_workscribe_cmd_start=$EPOCHREALTIME
|
|
6
10
|
_workscribe_cmd="$1"
|
|
@@ -11,16 +15,22 @@ _workscribe_precmd() {
|
|
|
11
15
|
local exit_code=$?
|
|
12
16
|
command -v workscribe > /dev/null 2>&1 || return 0
|
|
13
17
|
if [[ -n "$_workscribe_cmd" ]]; then
|
|
14
|
-
|
|
15
|
-
|
|
18
|
+
# Optional flags as an array: zsh doesn't word-split ${x:+--flag "$x"}, which would pass "--flag value" as one
|
|
19
|
+
# argument. And the command is captured even when it can't be timed.
|
|
20
|
+
local -a _workscribe_args
|
|
21
|
+
if [[ -n "$_workscribe_cmd_start" && -n "$EPOCHREALTIME" ]]; then
|
|
22
|
+
local _raw_ms=$(( (EPOCHREALTIME - _workscribe_cmd_start) * 1000 ))
|
|
23
|
+
_workscribe_args+=(--duration "${_raw_ms%%.*}")
|
|
24
|
+
fi
|
|
25
|
+
[[ -n "$_workscribe_git_before" ]] && _workscribe_args+=(--git-before "$_workscribe_git_before")
|
|
16
26
|
command workscribe _capture \
|
|
17
27
|
--cmd "$_workscribe_cmd" \
|
|
18
28
|
--cwd "$PWD" \
|
|
19
29
|
--exit "$exit_code" \
|
|
20
|
-
|
|
21
|
-
${_workscribe_git_before:+--git-before "$_workscribe_git_before"} \
|
|
30
|
+
"${_workscribe_args[@]}" \
|
|
22
31
|
> /dev/null 2>&1 &!
|
|
23
32
|
_workscribe_cmd=""
|
|
33
|
+
_workscribe_cmd_start=""
|
|
24
34
|
_workscribe_git_before=""
|
|
25
35
|
fi
|
|
26
36
|
# Skip the alert check on the first precmd: it fires before the shell has
|
|
@@ -22,18 +22,23 @@ workscribe sessions --json
|
|
|
22
22
|
|
|
23
23
|
Add `--date YYYY-MM-DD` for another day. For "this week", run it once per day (Monday to today) and save each day's sessions — but note `workscribe summary --week` keeps using Workscribe's own digest; saved summaries are per day. The output is one line of JSON; see [references/json-contract.md](references/json-contract.md) for the fields you'll use. An empty `sessions` list means nothing was captured — tell the user and stop.
|
|
24
24
|
|
|
25
|
+
Each session is one project's **thread** inside a work block. When the developer worked across several repos at once, their threads share a block and overlap in time: `alongside` lists the keys of the others.
|
|
26
|
+
|
|
27
|
+
If it reports that **Workscribe hasn't finished upgrading the data**, ask the developer before running `workscribe upgrade` — it backs up their database first and can take a while on a long history. Once it finishes, run `workscribe sessions --json` again.
|
|
28
|
+
|
|
25
29
|
## 2. Write one block per session
|
|
26
30
|
|
|
27
31
|
Follow [references/summary-format.md](references/summary-format.md). In short:
|
|
28
32
|
|
|
29
33
|
```
|
|
30
|
-
## <project> (<
|
|
34
|
+
## <project> (<branches>) — <duration>
|
|
31
35
|
- <outcome>
|
|
32
36
|
```
|
|
33
37
|
|
|
34
38
|
- Up to **7 bullets**, most important first: what was built, fixed, shipped or decided.
|
|
35
39
|
- Build bullets from `commits` (cite the short hash, e.g. `(a1b2c3d)`), test and build results (`exitCode` 0 vs non-zero; `null` means unknown, never "failed"), `notes` (always include them), and `hint`s on unclassified events.
|
|
36
40
|
- Describe outcomes, not commands or tools. Never name the AI tool used. Don't invent anything the data doesn't show.
|
|
41
|
+
- Don't name the projects worked `alongside` — Workscribe adds that line under each saved summary itself. Never repeat their work.
|
|
37
42
|
- Skip a session with nothing notable rather than padding it.
|
|
38
43
|
|
|
39
44
|
## 3. Save each block
|
|
@@ -58,4 +63,4 @@ Show the summaries, then say they were saved to Workscribe: `workscribe summary`
|
|
|
58
63
|
|
|
59
64
|
## Privacy
|
|
60
65
|
|
|
61
|
-
Running this skill sends the JSON — categories, commit subjects, notes, short redacted hints for unclassified commands, and each session's repo path and working directory; never full commands or IDE file paths — to the model provider behind this agent, along with any files you read under `repoPath`. If the developer needs summaries that never leave their machine, point them to `workscribe summary`, whose template engine runs entirely offline.
|
|
66
|
+
Running this skill sends the JSON — categories, commit subjects, notes, short redacted hints for unclassified commands, the ids of the agent conversations the work came from, and each session's repo path and working directory; never full commands or IDE file paths — to the model provider behind this agent, along with any files you read under `repoPath`. If the developer needs summaries that never leave their machine, point them to `workscribe summary`, whose template engine runs entirely offline.
|
|
@@ -1,24 +1,39 @@
|
|
|
1
1
|
# `workscribe sessions --json` — fields this skill uses
|
|
2
2
|
|
|
3
|
-
The full contract is documented at workscribe.co/docs/commands#json-output-contract. Within `schemaVersion:
|
|
3
|
+
The full contract is documented at workscribe.co/docs/commands#json-output-contract. Within `schemaVersion: 2`, fields are only ever added — ignore any you don't recognise.
|
|
4
|
+
|
|
5
|
+
Each session is one project's **thread**: that project's work inside a work block (a stretch between idle gaps). Working across several repos at once gives one block with a thread per repo, so sessions of one block overlap in time.
|
|
4
6
|
|
|
5
7
|
```json
|
|
6
8
|
{
|
|
7
|
-
"schemaVersion":
|
|
9
|
+
"schemaVersion": 2,
|
|
8
10
|
"date": "2026-10-25",
|
|
11
|
+
"blocks": [
|
|
12
|
+
{
|
|
13
|
+
"id": 1,
|
|
14
|
+
"startedAt": "2026-10-25T09:00:00.000Z",
|
|
15
|
+
"endedAt": "2026-10-25T10:30:00.000Z",
|
|
16
|
+
"activeMinutes": 85,
|
|
17
|
+
"threadKeys": ["api|2026-10-25T09:00:00.000Z", "web|2026-10-25T09:40:00.000Z"]
|
|
18
|
+
}
|
|
19
|
+
],
|
|
9
20
|
"sessions": [
|
|
10
21
|
{
|
|
11
22
|
"key": "api|2026-10-25T09:00:00.000Z",
|
|
12
23
|
"project": "api",
|
|
13
24
|
"repoPath": "/Users/dev/api",
|
|
14
25
|
"branch": "feature/auth",
|
|
26
|
+
"branches": ["feature/auth", "main"],
|
|
15
27
|
"startedAt": "2026-10-25T09:00:00.000Z",
|
|
16
28
|
"endedAt": "2026-10-25T10:30:00.000Z",
|
|
17
|
-
"
|
|
29
|
+
"activeMinutes": 70,
|
|
30
|
+
"blockId": 1,
|
|
31
|
+
"alongside": ["web|2026-10-25T09:40:00.000Z"],
|
|
32
|
+
"tickets": ["API-412"],
|
|
18
33
|
"notes": ["blocked on staging credentials"],
|
|
19
34
|
"commits": [
|
|
20
|
-
{ "hash": "a1b2c3d", "subject": "fix: token refresh race", "source": "git" },
|
|
21
|
-
{ "hash": null, "subject": "wip: amended away", "source": "captured" }
|
|
35
|
+
{ "hash": "a1b2c3d", "subject": "fix: token refresh race", "committedAt": "2026-10-25T10:12:00+01:00", "source": "git" },
|
|
36
|
+
{ "hash": null, "subject": "wip: amended away", "committedAt": "2026-10-25T09:41:07.000Z", "source": "captured" }
|
|
22
37
|
],
|
|
23
38
|
"events": [
|
|
24
39
|
{ "category": "testing", "exitCode": 1, "metadata": { "tool": "npm" } },
|
|
@@ -33,7 +48,10 @@ The full contract is documented at workscribe.co/docs/commands#json-output-contr
|
|
|
33
48
|
| Field | Use it for |
|
|
34
49
|
|---|---|
|
|
35
50
|
| `key` | The `--key` when saving this session's summary. Copy it exactly. |
|
|
36
|
-
| `project`, `branch`, `
|
|
51
|
+
| `project`, `branch`, `activeMinutes` | The block heading. `project` is the project's name, a `~/path` for work outside any project, or `null` (write `unknown`). `activeMinutes` is the time spent on this project; `startedAt`–`endedAt` can span other projects' work too. |
|
|
52
|
+
| `branches` | Every branch the session touched, in the order first seen. `branch` is the latest of them, the one the session ended on. Each commit's `committedAt` says when it was made. |
|
|
53
|
+
| `alongside` | The keys of the sessions worked in the same block. Don't mention those projects — Workscribe adds an `Alongside:` line under each summary itself — and leave their work to their own blocks. |
|
|
54
|
+
| `tickets` | Ticket keys the session's branches and commits name. Mention one when the work is about it (e.g. "Fixed the token refresh race (API-412)"); don't list them for their own sake. May be empty even when a branch names one, right after an update. |
|
|
37
55
|
| `repoPath` | Where to read files if a commit needs context. `null` outside a git repo. |
|
|
38
56
|
| `notes` | The developer's own notes — always include them. |
|
|
39
57
|
| `commits` | The main source of outcomes. `source: "git"` has a short `hash` to cite; `"captured"` commits have `hash: null` (amended or rebased). |
|
|
@@ -5,12 +5,13 @@ One block per session, in exactly the shape Workscribe uses everywhere else, so
|
|
|
5
5
|
## Heading
|
|
6
6
|
|
|
7
7
|
```
|
|
8
|
-
## <project> (<
|
|
8
|
+
## <project> (<branches>) — <duration>
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
-
|
|
11
|
+
- `<branches>` is every branch in `branches`, in order, separated by `, ` — for example `## api (main, feature/auth) — 1h 30m`. With one branch it's just that branch.
|
|
12
|
+
- Leave out the parentheses when `branches` is empty.
|
|
12
13
|
- If `project` is `null` (no repo and no events), use `unknown`, as Workscribe does.
|
|
13
|
-
- Duration from `
|
|
14
|
+
- Duration from `activeMinutes` — the time actually spent on that project; a session's start-to-end span can include work on other projects. Under an hour as `45m`; otherwise `1h` or `1h 30m`.
|
|
14
15
|
|
|
15
16
|
## Bullets
|
|
16
17
|
|