moshcode 0.70.0 → 0.72.0
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/marketplace.json +24 -0
- package/README.md +120 -0
- package/bin/moshcode.mjs +46 -0
- package/package.json +1 -1
- package/plugins/billing/.claude-plugin/plugin.json +13 -0
- package/plugins/billing/README.md +42 -0
- package/plugins/billing/commands/hours.md +37 -0
- package/plugins/billing/commands/invoice.md +39 -0
- package/plugins/billing/commands/rate.md +40 -0
- package/plugins/billing/commands/report.md +28 -0
- package/plugins/timer/.claude-plugin/plugin.json +13 -0
- package/plugins/timer/README.md +36 -0
- package/plugins/timer/commands/report.md +32 -0
- package/plugins/timer/commands/start.md +33 -0
- package/plugins/timer/commands/status.md +27 -0
- package/plugins/timer/commands/stop.md +30 -0
- package/prd/0012-billing-baked-into-the-agent-cli.md +129 -0
- package/src/billing.mjs +363 -0
- package/src/business-delegate.mjs +105 -0
- package/src/business-store.mjs +155 -0
- package/src/cli-schema.mjs +245 -0
- package/src/clients.mjs +328 -0
- package/src/commands.mjs +9 -0
- package/src/payments.mjs +258 -0
- package/src/plugins.mjs +39 -7
- package/src/rates.mjs +368 -0
- package/src/teams.mjs +459 -0
- package/src/timer.mjs +354 -0
- package/src/tools.mjs +18 -0
- package/src/tui.mjs +77 -0
|
@@ -30,6 +30,30 @@
|
|
|
30
30
|
},
|
|
31
31
|
"homepage": "https://github.com/moshcoder/moshcode#crypto",
|
|
32
32
|
"keywords": ["crypto", "bitcoin", "markets", "prices", "advis0r"]
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
"name": "timer",
|
|
36
|
+
"description": "Track time against projects from inside your engine, backed by @profullstack/timer: start and stop a clock, log time you forgot, and report billable hours with the agent count that priced them.",
|
|
37
|
+
"source": "./plugins/timer",
|
|
38
|
+
"category": "productivity",
|
|
39
|
+
"author": {
|
|
40
|
+
"name": "moshcoder",
|
|
41
|
+
"url": "https://moshcode.sh"
|
|
42
|
+
},
|
|
43
|
+
"homepage": "https://github.com/profullstack/timer#readme",
|
|
44
|
+
"keywords": ["timer", "time-tracking", "billable", "hours", "profullstack"]
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"name": "billing",
|
|
48
|
+
"description": "Turn tracked hours into an invoice, backed by @profullstack/billing: clients, rate cards written as contract sentences, agent-hour arithmetic, and invoices rendered to HTML you can print to PDF.",
|
|
49
|
+
"source": "./plugins/billing",
|
|
50
|
+
"category": "productivity",
|
|
51
|
+
"author": {
|
|
52
|
+
"name": "moshcoder",
|
|
53
|
+
"url": "https://moshcode.sh"
|
|
54
|
+
},
|
|
55
|
+
"homepage": "https://github.com/profullstack/billing#readme",
|
|
56
|
+
"keywords": ["billing", "invoice", "clients", "rates", "profullstack"]
|
|
33
57
|
}
|
|
34
58
|
]
|
|
35
59
|
}
|
package/README.md
CHANGED
|
@@ -62,6 +62,12 @@ or miss one that does. A test fails the build when it drifts.
|
|
|
62
62
|
| `moshcode crypto` <br>`coins` | tools | crypto market data from advis0r.com |
|
|
63
63
|
| `moshcode news` | tools | headlines from your feeds, or a search |
|
|
64
64
|
| `moshcode rss` | tools | read the same headlines in a full-screen reader |
|
|
65
|
+
| `moshcode timer` | business | track time — on, off, and what it added up to |
|
|
66
|
+
| `moshcode client` <br>`business` `merchant` `customer` | business | who the work is for — clients, businesses, merchants |
|
|
67
|
+
| `moshcode team` <br>`teams` | business | who may do what on this machine |
|
|
68
|
+
| `moshcode rate` <br>`rates` | business | what an hour of agent time costs |
|
|
69
|
+
| `moshcode billing` <br>`invoice` | business | turn tracked time into an invoice |
|
|
70
|
+
| `moshcode payments` | business | the rail invoices go out on |
|
|
65
71
|
| `moshcode plugin` <br>`plugins` | extend | install moshcode's slash commands into Claude Code |
|
|
66
72
|
| `moshcode commands` | script | list built-in moshscript commands |
|
|
67
73
|
| `moshcode completion` | extend | print a shell completion script |
|
|
@@ -937,6 +943,120 @@ event, and publishes it to the displayed relays. Both flows leave the final
|
|
|
937
943
|
confirmation in the browser. If the pit is remote or headless, `/post` prints
|
|
938
944
|
the composer URL instead.
|
|
939
945
|
|
|
946
|
+
## Getting paid (`/timer`, `/client`, `/rate`, `/billing`, `/payments`)
|
|
947
|
+
|
|
948
|
+
Every agentic CLI helps you do the work. This one also bills for it. Six words,
|
|
949
|
+
each useful on its own — the timer needs no client, the rate needs no gateway
|
|
950
|
+
(PRD [0012](prd/0012-billing-baked-into-the-agent-cli.md)).
|
|
951
|
+
|
|
952
|
+
> **`/timer` and `/billing` now prefer their own CLIs.** Tracking time and
|
|
953
|
+
> sending an invoice are not moshcode ideas — they are useful under any agentic
|
|
954
|
+
> CLI, and on Windows, where moshcode does not go. So they also ship standalone:
|
|
955
|
+
> [`@profullstack/timer`](https://github.com/profullstack/timer) and
|
|
956
|
+
> [`@profullstack/billing`](https://github.com/profullstack/billing).
|
|
957
|
+
>
|
|
958
|
+
> ```sh
|
|
959
|
+
> moshcode install timer billing # or: npm install -g @profullstack/timer @profullstack/billing
|
|
960
|
+
> ```
|
|
961
|
+
>
|
|
962
|
+
> Installing them changes nothing on its own. Switch the hand-over on when you
|
|
963
|
+
> are ready to move:
|
|
964
|
+
>
|
|
965
|
+
> ```sh
|
|
966
|
+
> billing import # look at what would come across
|
|
967
|
+
> billing import --apply # move it
|
|
968
|
+
> export MOSHCODE_EXTERNAL_BILLING=1 # /timer and /billing now run the CLIs
|
|
969
|
+
> ```
|
|
970
|
+
>
|
|
971
|
+
> **It is opt-in for a reason.** Only half this layer has an outside home:
|
|
972
|
+
> `/client`, `/rate`, `/payments` and `/team` stay here, because the rails and
|
|
973
|
+
> the permission model are moshcode's and `/client`'s freeform dotted fields
|
|
974
|
+
> have no shape in the package's typed client model. Handing over the other
|
|
975
|
+
> half automatically would split your records across two stores — `/client` and
|
|
976
|
+
> `/rate` writing `~/.moshcode/business.json` while `/billing` reads the
|
|
977
|
+
> package's own ledger, so the invoice for a client you had just created would
|
|
978
|
+
> not exist. `billing import` is what closes that gap, which is why it comes
|
|
979
|
+
> first.
|
|
980
|
+
>
|
|
981
|
+
> The standalone billing carries the same rate model (`$100/hour/agent/upto:4`)
|
|
982
|
+
> and bills **agent-hours**.
|
|
983
|
+
|
|
984
|
+
```sh
|
|
985
|
+
moshcode timer on acme --task "batch payments" --agents auto # auto counts the herd
|
|
986
|
+
moshcode timer off # → 1h 12m, $480.00
|
|
987
|
+
moshcode timer log --week # this week's timesheet
|
|
988
|
+
```
|
|
989
|
+
|
|
990
|
+
The timer is a stopwatch and a ledger in `~/.moshcode/timers.json`, and it knows
|
|
991
|
+
nothing about money. It does know about **agents**, which is what makes it
|
|
992
|
+
different from every other stopwatch: an hour of moshcode is an hour times
|
|
993
|
+
however many engines ran in it.
|
|
994
|
+
|
|
995
|
+
```sh
|
|
996
|
+
moshcode client create "Acme Inc", https://acme.com, +1-555-0100
|
|
997
|
+
moshcode client create globex --contact.telephone +1-555-0200 --contact.name Jane
|
|
998
|
+
moshcode client payee acme-inc solana:9xQe… # where their payments land
|
|
999
|
+
```
|
|
1000
|
+
|
|
1001
|
+
Contact details are written the way they arrive: the comma form for what you
|
|
1002
|
+
pasted out of a signature, `--a.b` dotted flags for anything else. There is no
|
|
1003
|
+
fixed field list — `--billing.po` works because it says what it means.
|
|
1004
|
+
`/business`, `/merchant` and `/customer` are the same command.
|
|
1005
|
+
|
|
1006
|
+
```sh
|
|
1007
|
+
moshcode rate set default $100/hour/agent/upto:4
|
|
1008
|
+
moshcode rate set acme-inc 0.5 SOL/day --prefer SOL,USDC --accept fiat
|
|
1009
|
+
moshcode rate set initech $5000/project
|
|
1010
|
+
```
|
|
1011
|
+
|
|
1012
|
+
`$100/hour/agent/upto:4` is the sentence from the contract, parsed: price,
|
|
1013
|
+
period, unit, and the cap that made the client sign. Four agents cost four
|
|
1014
|
+
hundred an hour and **so do six**. Order after the price does not matter.
|
|
1015
|
+
|
|
1016
|
+
```sh
|
|
1017
|
+
moshcode billing acme-inc # a preview — writes nothing
|
|
1018
|
+
moshcode billing acme-inc --month --mark # claim the time, record the invoice
|
|
1019
|
+
moshcode billing acme-inc --send # compose the gateway command
|
|
1020
|
+
moshcode billing acme-inc --send --yes # …and run it
|
|
1021
|
+
```
|
|
1022
|
+
|
|
1023
|
+
Two rules the shape enforces: time is never billed twice (an entry carries the
|
|
1024
|
+
invoice that claimed it, and `--mark` is the only verb that writes), and nothing
|
|
1025
|
+
settles to an address nobody chose — no payee and no wallet rail is a refusal,
|
|
1026
|
+
not a guess.
|
|
1027
|
+
|
|
1028
|
+
```sh
|
|
1029
|
+
moshcode payments connect coinpay # runs `coinpay login`
|
|
1030
|
+
moshcode payments connect wallet --chain solana --address 9xQe… # no gateway at all
|
|
1031
|
+
moshcode payments connect paypal --vault profullstack--prod # keys live in the vault
|
|
1032
|
+
```
|
|
1033
|
+
|
|
1034
|
+
moshcode composes an invoice; a gateway delivers it. No secret is stored here: a
|
|
1035
|
+
CLI gateway keeps its own session, and an OAuth gateway gets a reference to the
|
|
1036
|
+
vault its keys live in (`moshcode secrets`), never the keys.
|
|
1037
|
+
|
|
1038
|
+
### Teams and grants (`/team`)
|
|
1039
|
+
|
|
1040
|
+
For a machine you handed to somebody else:
|
|
1041
|
+
|
|
1042
|
+
```sh
|
|
1043
|
+
moshcode team create Profullstack
|
|
1044
|
+
moshcode team add profullstack preshy --role member --rate '$80/hour'
|
|
1045
|
+
moshcode team grant profullstack preshy tools:coinpay
|
|
1046
|
+
moshcode team can profullstack/preshy payments:write # → no
|
|
1047
|
+
```
|
|
1048
|
+
|
|
1049
|
+
A permission is `surface:target`, written however you say it — `tools:coinpay`,
|
|
1050
|
+
`tools/coinpay` and `allow(tools/coinpay)` are one grant. Roles (`owner`,
|
|
1051
|
+
`admin`, `member`, `client`) are a starting set; grants add to them.
|
|
1052
|
+
|
|
1053
|
+
The pit gates itself only when `MOSHCODE_MEMBER=<team>/<handle>` is set — with
|
|
1054
|
+
it unset the owner is at the keyboard and nothing is checked. **This is a
|
|
1055
|
+
guardrail, not a security boundary.** moshcode runs as the person at the
|
|
1056
|
+
keyboard, and anyone who can type `/team` can also edit
|
|
1057
|
+
`~/.moshcode/business.json`. A boundary that has to hold against somebody is an
|
|
1058
|
+
OS account, a container, or a scoped credential.
|
|
1059
|
+
|
|
940
1060
|
## The arcade (`/games`)
|
|
941
1061
|
|
|
942
1062
|
Twenty-two games, in the pit or straight from a shell. There are no menus, no options
|
package/bin/moshcode.mjs
CHANGED
|
@@ -418,6 +418,52 @@ async function main() {
|
|
|
418
418
|
if (code) process.exitCode = code;
|
|
419
419
|
return;
|
|
420
420
|
}
|
|
421
|
+
// The business layer. Imported where they are dispatched rather than at the
|
|
422
|
+
// top of the file: six modules that read two JSON files are dead weight in
|
|
423
|
+
// the startup path of `moshcode claude`, which is what this binary is mostly
|
|
424
|
+
// asked to do.
|
|
425
|
+
if (cmd === "timer") {
|
|
426
|
+
// @profullstack/timer when it is installed, the built-in otherwise. See
|
|
427
|
+
// src/business-delegate.mjs for why the external one wins.
|
|
428
|
+
const { delegate, installHint } = await import("../src/business-delegate.mjs");
|
|
429
|
+
const handed = await delegate("timer", rest, {});
|
|
430
|
+
if (handed.delegated) { process.exitCode = handed.code; return; }
|
|
431
|
+
const { timerCommand } = await import("../src/timer.mjs");
|
|
432
|
+
process.exitCode = (await timerCommand(rest)) || 0;
|
|
433
|
+
const hint = installHint("timer");
|
|
434
|
+
if (hint) process.stderr.write(`${hint}\n`);
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
if (cmd === "client" || cmd === "business" || cmd === "merchant" || cmd === "customer") {
|
|
438
|
+
const { clientCommand } = await import("../src/clients.mjs");
|
|
439
|
+
process.exitCode = clientCommand(rest) || 0;
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
if (cmd === "team" || cmd === "teams") {
|
|
443
|
+
const { teamCommand } = await import("../src/teams.mjs");
|
|
444
|
+
process.exitCode = teamCommand(rest) || 0;
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
if (cmd === "rate" || cmd === "rates") {
|
|
448
|
+
const { rateCommand } = await import("../src/rates.mjs");
|
|
449
|
+
process.exitCode = rateCommand(rest) || 0;
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
if (cmd === "billing" || cmd === "invoice") {
|
|
453
|
+
const { delegate, installHint } = await import("../src/business-delegate.mjs");
|
|
454
|
+
const handed = await delegate(cmd, rest, {});
|
|
455
|
+
if (handed.delegated) { process.exitCode = handed.code; return; }
|
|
456
|
+
const { billingCommand } = await import("../src/billing.mjs");
|
|
457
|
+
process.exitCode = billingCommand(rest) || 0;
|
|
458
|
+
const hint = installHint(cmd);
|
|
459
|
+
if (hint) process.stderr.write(`${hint}\n`);
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
if (cmd === "payments") {
|
|
463
|
+
const { paymentsCommand } = await import("../src/payments.mjs");
|
|
464
|
+
process.exitCode = paymentsCommand(rest) || 0;
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
421
467
|
if (cmd === "games" || cmd === "game" || cmd === "arcade") {
|
|
422
468
|
const code = await gamesCommand(rest);
|
|
423
469
|
if (code) process.exitCode = code;
|
package/package.json
CHANGED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://anthropic.com/claude-code/plugin.schema.json",
|
|
3
|
+
"name": "billing",
|
|
4
|
+
"description": "Turn tracked hours into an invoice, backed by @profullstack/billing: clients, rate cards written as contract sentences, agent-hour arithmetic, and invoices rendered to HTML you can print to PDF.",
|
|
5
|
+
"version": "0.1.0",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "moshcoder",
|
|
8
|
+
"url": "https://moshcode.sh"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/profullstack/billing#readme",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"keywords": ["billing", "invoice", "clients", "rates", "profullstack"]
|
|
13
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# billing
|
|
2
|
+
|
|
3
|
+
Slash commands for
|
|
4
|
+
[`@profullstack/billing`](https://github.com/profullstack/billing) — clients,
|
|
5
|
+
rates and invoices, built on the hours `@profullstack/timer` tracked.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
/billing:rate set acme '$100/hour/agent/upto:4'
|
|
9
|
+
/billing:hours --client acme --month
|
|
10
|
+
/billing:invoice --client acme --from-timer --month
|
|
11
|
+
/billing:report
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Install the CLI
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
npm install -g @profullstack/billing
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
or, inside moshcode:
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
moshcode install billing
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## What it is for
|
|
27
|
+
|
|
28
|
+
A rate is the sentence from the contract, parsed. `$100/hour/agent/upto:4` means
|
|
29
|
+
four agents cost four hundred an hour and so do six, and the invoice bills
|
|
30
|
+
**agent-hours** so the client can check the line by hand: `quantity × rate`
|
|
31
|
+
always equals `amount`.
|
|
32
|
+
|
|
33
|
+
Two rules the shape enforces. The same hour never reaches two invoices — each
|
|
34
|
+
invoice records the timer entry ids it covers, so voiding one releases them.
|
|
35
|
+
And creating an invoice is a proposal: `--dry-run` validates the whole thing and
|
|
36
|
+
writes nothing, a new invoice is a draft, and nothing is ever emailed.
|
|
37
|
+
|
|
38
|
+
## Coming from moshcode
|
|
39
|
+
|
|
40
|
+
moshcode used to keep this layer internally. `billing import` brings it across
|
|
41
|
+
from `~/.moshcode/business.json` and `timers.json`, shows the plan first, and
|
|
42
|
+
never modifies the originals.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Tracked hours not yet on an invoice, priced at the client's rate.
|
|
3
|
+
argument-hint: --client <name> [--month|--week]
|
|
4
|
+
allowed-tools: Bash(billing hours:*), Bash(billing client:*), Bash(billing rate:*)
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Task
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
billing hours $ARGUMENTS --json
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
This is the preview of what `billing invoice new --from-timer` would bill. Same
|
|
14
|
+
filters, same grouping, same arithmetic — it writes nothing.
|
|
15
|
+
|
|
16
|
+
## Reading the response
|
|
17
|
+
|
|
18
|
+
- `items[]` — the line items, each with `description`, `quantity` (in the rate's
|
|
19
|
+
own billing unit), `unitPriceMajor`, `amount`, `hours` and `timerIds`.
|
|
20
|
+
- `unit` — what `quantity` is measured in: `hours`, or `agent-hours` when the
|
|
21
|
+
rate is priced per agent.
|
|
22
|
+
- `hours` / `units` / `subtotal` — the totals.
|
|
23
|
+
- `skipped` — `{ running, unbillable, alreadyBilled }`.
|
|
24
|
+
|
|
25
|
+
## Rules
|
|
26
|
+
|
|
27
|
+
- **Always read `skipped.running` back to the user.** Those hours are not
|
|
28
|
+
missing, they are on a clock that is still ticking and become billable the
|
|
29
|
+
moment it stops. "Nothing to bill" is misleading when the real answer is "stop
|
|
30
|
+
the clock first".
|
|
31
|
+
- Exit 3 means no unbilled hours matched, or the client does not exist. Read the
|
|
32
|
+
message; it distinguishes them.
|
|
33
|
+
- When `unit` is `agent-hours`, explain the multiplier if the user seems
|
|
34
|
+
surprised: 3 hours with 2 agents is 6 agent-hours. `quantity * unitPrice`
|
|
35
|
+
always equals `amount`.
|
|
36
|
+
- If there is no rate, the error says so and names the command that sets one.
|
|
37
|
+
Do not invent a rate to get past it.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Draft an invoice from tracked time or fixed line items, for a person to approve.
|
|
3
|
+
argument-hint: --client <name> --from-timer --month
|
|
4
|
+
allowed-tools: Bash(billing invoice:*), Bash(billing hours:*), Bash(billing client:*), Bash(billing rate:*)
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Task
|
|
8
|
+
|
|
9
|
+
Propose an invoice for `$ARGUMENTS`. **Always dry-run first:**
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
billing invoice new $ARGUMENTS --dry-run --json
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Show the user what it would create. Only run it again without `--dry-run` when
|
|
16
|
+
they have said to.
|
|
17
|
+
|
|
18
|
+
Line items come from `--from-timer` (tracked hours), from `--item
|
|
19
|
+
"Description|quantity|price"`, or both on the same invoice.
|
|
20
|
+
|
|
21
|
+
## Rules
|
|
22
|
+
|
|
23
|
+
- **Creating an invoice is a business action. Do not write one unprompted.**
|
|
24
|
+
`--dry-run` builds and validates the entire invoice — the rate lookup and the
|
|
25
|
+
double-billing check included — so a dry run that succeeds means the real one
|
|
26
|
+
will. There is no reason to skip it.
|
|
27
|
+
- A new invoice is a **draft**. `billing invoice mark <n> sent` is a separate,
|
|
28
|
+
deliberate step and this tool never emails anything. Do not mark an invoice
|
|
29
|
+
sent or paid unless the user asked.
|
|
30
|
+
- Read `amounts` (decimal) when talking to a person; the bare `total` is in
|
|
31
|
+
minor units.
|
|
32
|
+
- Exit 3 on `--from-timer` means there were no unbilled hours. Check
|
|
33
|
+
`billing hours` and report `skipped.running` rather than concluding there is
|
|
34
|
+
nothing to bill.
|
|
35
|
+
- The same hour cannot reach two invoices: each invoice records the timer entry
|
|
36
|
+
ids it covers. If the user wants to re-bill something, voiding the old invoice
|
|
37
|
+
releases those hours.
|
|
38
|
+
- Prefer `billing invoice render <n> --format html --out <file>` when they want
|
|
39
|
+
something to send: it is one self-contained file that prints to PDF.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Read or set what your time costs, written the way the contract says it.
|
|
3
|
+
argument-hint: "[set <client|default> '$100/hour/agent/upto:4']"
|
|
4
|
+
allowed-tools: Bash(billing rate:*), Bash(billing client:*)
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Task
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
billing rate $ARGUMENTS --json
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
With no arguments this lists every rate. `set`, `show` and `rm` take a target,
|
|
14
|
+
which is either a client handle or `default`.
|
|
15
|
+
|
|
16
|
+
## The spec
|
|
17
|
+
|
|
18
|
+
A price, then any of these in any order:
|
|
19
|
+
|
|
20
|
+
- a period: `hour`, `day` (8h), `week` (40h), `month` (160h), `project`, `task`
|
|
21
|
+
- a unit that gets multiplied: `agent`, `seat`, `person`, `team`
|
|
22
|
+
- `upto:N` to cap the multiplier, `min:N` for a minimum billed period
|
|
23
|
+
|
|
24
|
+
`$100/hour/agent/upto:4` means four agents cost four hundred an hour, and so do
|
|
25
|
+
six. `0.5 SOL/day`, `250 USDC/task` and `$5000/project` all parse too.
|
|
26
|
+
|
|
27
|
+
## Rules
|
|
28
|
+
|
|
29
|
+
- **Do not set or change a rate unless the user asked.** This is the number in
|
|
30
|
+
somebody's contract.
|
|
31
|
+
- Read `describes` back to them when confirming — it is the rate as a sentence,
|
|
32
|
+
and it is how you catch a spec that parsed differently from how it was meant.
|
|
33
|
+
- Settlement (`--prefer SOL --accept fiat`) is deliberately separate from the
|
|
34
|
+
price. The number in the contract does not change because the rail did, so do
|
|
35
|
+
not "convert" a rate to a preferred ticker.
|
|
36
|
+
- A price given in a ticker invoices in that ticker. Do not turn `0.5 SOL` into
|
|
37
|
+
a dollar figure: nobody computed that number.
|
|
38
|
+
- If a spec is rejected, the error names the words that are allowed. Fix the
|
|
39
|
+
spec rather than falling back to a bare number, which would silently mean
|
|
40
|
+
"per hour, flat".
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: What has been billed, collected, and what is still owed.
|
|
3
|
+
argument-hint: "[--client <name>] [--year|--month]"
|
|
4
|
+
allowed-tools: Bash(billing report:*), Bash(billing invoice:*)
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Task
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
billing report $ARGUMENTS --json
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Reading the response
|
|
14
|
+
|
|
15
|
+
- `totals` — `billed`, `collected`, `outstanding`, `overdue`, `draft`, all as
|
|
16
|
+
decimal numbers in `currency`.
|
|
17
|
+
- `byClient[]` — the same figures per client, biggest outstanding first.
|
|
18
|
+
|
|
19
|
+
## Rules
|
|
20
|
+
|
|
21
|
+
- **`draft` is not money anybody owes you.** A draft invoice has not been
|
|
22
|
+
issued, so keep it out of any "you are owed X" sentence and name it
|
|
23
|
+
separately.
|
|
24
|
+
- `overdue` is derived from the due date at read time, never stored. It is a
|
|
25
|
+
subset of `outstanding`, not an addition to it — do not sum them.
|
|
26
|
+
- Windows apply to the **issue date** here, not to when the work was done.
|
|
27
|
+
- For the invoices behind a figure, use `billing invoice list --overdue --json`
|
|
28
|
+
or `--status sent`. Do not guess at which invoices make up a total.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://anthropic.com/claude-code/plugin.schema.json",
|
|
3
|
+
"name": "timer",
|
|
4
|
+
"description": "Track time against projects from inside your engine, backed by @profullstack/timer: start and stop a clock, log time you forgot, and report billable hours with the agent count that priced them.",
|
|
5
|
+
"version": "0.1.0",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "moshcoder",
|
|
8
|
+
"url": "https://moshcode.sh"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/profullstack/timer#readme",
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"keywords": ["timer", "time-tracking", "billable", "hours", "profullstack"]
|
|
13
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# timer
|
|
2
|
+
|
|
3
|
+
Slash commands for [`@profullstack/timer`](https://github.com/profullstack/timer)
|
|
4
|
+
— a time tracker that runs on Linux, macOS and Windows, and answers `--json` on
|
|
5
|
+
every command so an agent can clock its own work.
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
/timer:start acme fix the login redirect
|
|
9
|
+
/timer:status
|
|
10
|
+
/timer:stop
|
|
11
|
+
/timer:report --week --group day
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Install the CLI
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
npm install -g @profullstack/timer
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
or, inside moshcode:
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
moshcode install timer
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## What it is for
|
|
27
|
+
|
|
28
|
+
An hour of agentic work is an hour times however many engines ran in it, so an
|
|
29
|
+
entry carries an agent count (`--agents 4`). `@profullstack/billing` multiplies
|
|
30
|
+
by it when the rate says to and ignores it when the rate is flat.
|
|
31
|
+
|
|
32
|
+
Several clocks may run at once. That is deliberate: parallel agents each track
|
|
33
|
+
their own work and do not stop each other.
|
|
34
|
+
|
|
35
|
+
The timesheet is one JSON file at `~/.profullstack/timer/timesheet.json`, and
|
|
36
|
+
billing reads it directly.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Totals for a period, grouped by project, task, day, tag or agent.
|
|
3
|
+
argument-hint: "[--week|--month] [--group project|task|day|tag|agent]"
|
|
4
|
+
allowed-tools: Bash(timer report:*), Bash(timer log:*), Bash(timer projects:*)
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Task
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
timer report $ARGUMENTS --json
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Windows: `--today`, `--yesterday`, `--week` (from Monday), `--month`, `--year`,
|
|
14
|
+
or explicit `--since` / `--until`. Groups: `project` (default), `task`, `day`,
|
|
15
|
+
`tag`, `agent`, `none`.
|
|
16
|
+
|
|
17
|
+
## Reading the response
|
|
18
|
+
|
|
19
|
+
`rows[]` each carry `key`, `entries`, `hours` and `billableHours`. `totals` has
|
|
20
|
+
the same figures for the whole window.
|
|
21
|
+
|
|
22
|
+
## Rules
|
|
23
|
+
|
|
24
|
+
- **A window compares against the entry's start, and `--until` is exclusive.**
|
|
25
|
+
An entry that ran past midnight belongs to the day it began on. Say so if the
|
|
26
|
+
user questions a boundary rather than guessing at a bug.
|
|
27
|
+
- Report `hours` and `billableHours` separately whenever they differ.
|
|
28
|
+
- `timer log` is the command for the entries behind a number. Reach for it when
|
|
29
|
+
the user asks why a total looks the way it does.
|
|
30
|
+
- Do not convert hours into money here. The rate lives in
|
|
31
|
+
`@profullstack/billing`, which knows about agent multipliers and caps; a
|
|
32
|
+
hours-times-rate figure invented here will disagree with the invoice.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Start the clock on a project, optionally recording how many agents are working.
|
|
3
|
+
argument-hint: <project> [task words…]
|
|
4
|
+
allowed-tools: Bash(timer start:*), Bash(timer status:*), Bash(timer on:*)
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Task
|
|
8
|
+
|
|
9
|
+
Start a clock for `$ARGUMENTS`.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
timer start $ARGUMENTS --json
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The first word is the project; everything after it is the task, so no quoting is
|
|
16
|
+
needed. Useful flags:
|
|
17
|
+
|
|
18
|
+
- `--agents N` — how many engines are working. An agent-priced rate multiplies
|
|
19
|
+
by this, so it is the difference between a $400 afternoon and a $1,600 one.
|
|
20
|
+
- `--at 09:15` or `--at -20m` — the clock you meant to start earlier.
|
|
21
|
+
- `--tag`, `--note`, `--no-billable`.
|
|
22
|
+
|
|
23
|
+
## Rules
|
|
24
|
+
|
|
25
|
+
- **Do not pass `--switch` unless the user asked to stop their other clocks.**
|
|
26
|
+
Several clocks running at once is normal here: parallel agents each track
|
|
27
|
+
their own work, and stopping someone else's is not recoverable from the log.
|
|
28
|
+
- If `started.alsoRunning` comes back non-empty, mention how many other clocks
|
|
29
|
+
are running. Do not stop them.
|
|
30
|
+
- Report the entry id — `timer stop --id <id>` needs it, and so does the user if
|
|
31
|
+
they want to correct the entry later.
|
|
32
|
+
- If the command exits 2, the command line was wrong; read the error and fix it
|
|
33
|
+
rather than retrying the same thing.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: What is running right now, and what today adds up to.
|
|
3
|
+
allowed-tools: Bash(timer status:*), Bash(timer log:*)
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Task
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
timer status --json
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Reading the response
|
|
13
|
+
|
|
14
|
+
- `running[]` — every live clock, each with `seconds` counting up to now.
|
|
15
|
+
- `today` — totals for entries that *started* today: `hours` and `billableHours`.
|
|
16
|
+
- `dataFile` — where the timesheet lives, worth quoting if the user is surprised
|
|
17
|
+
by what is or is not in it.
|
|
18
|
+
|
|
19
|
+
## Rules
|
|
20
|
+
|
|
21
|
+
- An empty `running` array is a normal answer. Exit status is 0 either way, so
|
|
22
|
+
never report "nothing running" as a failure.
|
|
23
|
+
- `hours` and `billableHours` differ when something is marked `--no-billable`.
|
|
24
|
+
If they differ, give both — "how long did this take" and "what can I charge
|
|
25
|
+
for it" are different questions.
|
|
26
|
+
- A running clock's duration is still moving. Do not present it as a final
|
|
27
|
+
figure, and note that billing will not invoice it until it is stopped.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Stop a running clock and report what it came to.
|
|
3
|
+
argument-hint: "[id]"
|
|
4
|
+
allowed-tools: Bash(timer stop:*), Bash(timer off:*), Bash(timer status:*)
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Task
|
|
8
|
+
|
|
9
|
+
Stop the clock for `$ARGUMENTS` (empty means the newest one).
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
timer stop $ARGUMENTS --json
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Targets: nothing (the most recently started clock), an id or an unambiguous
|
|
16
|
+
prefix of one, `--project <p>`, or `--all`.
|
|
17
|
+
|
|
18
|
+
## Reading the response
|
|
19
|
+
|
|
20
|
+
`stopped[]` carries `seconds`, `hours` and `agents` for each entry closed.
|
|
21
|
+
`hours` is the figure an invoice uses.
|
|
22
|
+
|
|
23
|
+
## Rules
|
|
24
|
+
|
|
25
|
+
- **`stopped: []` with exit 0 means nothing was running.** That is an answer,
|
|
26
|
+
not a failure — say so plainly and do not retry or treat it as an error.
|
|
27
|
+
- Do not pass `--all` unless the user asked to stop everything. Other clocks may
|
|
28
|
+
belong to other agents.
|
|
29
|
+
- `--at` can backdate the stop, but a stop earlier than the start is refused
|
|
30
|
+
rather than clamped to zero. If that happens, the entry is untouched.
|