@etiquekit/etq 0.0.1 → 1.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.
Files changed (83) hide show
  1. package/AGENTS.md +28 -0
  2. package/QuickStart.md +94 -0
  3. package/README.md +77 -9
  4. package/bin/etiquette +1149 -0
  5. package/bin/etiquette-core +313 -0
  6. package/docs/ARCHITECTURE.md +100 -0
  7. package/docs/CODEX_CLIENT_COMPATIBILITY.md +83 -0
  8. package/docs/CONCEPTS.md +128 -0
  9. package/docs/CONCEPT_STATUS.md +67 -0
  10. package/docs/CORE_PROFILE.md +70 -0
  11. package/docs/LANE_PROVISIONING.md +157 -0
  12. package/docs/README.md +29 -0
  13. package/docs/RELEASE_SURFACE_AUDIT.md +156 -0
  14. package/docs/SEAT_DISCIPLINE.md +68 -0
  15. package/docs/SEAT_PROVISIONING.md +100 -0
  16. package/docs/TEAM_HANDOFF.md +190 -0
  17. package/docs/WORKTREE_QOL.md +92 -0
  18. package/docs/contracts/ledger-entry/README.md +83 -0
  19. package/docs/contracts/ledger-entry/ledger-entry.v0.1.md +116 -0
  20. package/docs/contracts/ledger-entry/ledger-entry.v0.2.md +90 -0
  21. package/docs/contracts/ledger-entry/ledger-entry.v0.md +123 -0
  22. package/docs/contracts/ledger-entry/ledger-query-cli.v0.1.md +64 -0
  23. package/package.json +42 -11
  24. package/scripts/install.sh +144 -0
  25. package/scripts/uninstall.sh +58 -0
  26. package/templates/etiquette-vanilla-v0/README.md +69 -0
  27. package/templates/etiquette-vanilla-v0/bin/stamp-vanilla +33 -0
  28. package/templates/etiquette-vanilla-v0/source/control-seat/.llm-substrate/HANDOFF.md +22 -0
  29. package/templates/etiquette-vanilla-v0/source/control-seat/README.md +16 -0
  30. package/templates/etiquette-vanilla-v0/source/control-seat/bin/_lib/http.sh +121 -0
  31. package/templates/etiquette-vanilla-v0/source/control-seat/bin/_lib/sanitize.sh +191 -0
  32. package/templates/etiquette-vanilla-v0/source/control-seat/bin/_lib/state.sh +67 -0
  33. package/templates/etiquette-vanilla-v0/source/control-seat/bin/access-assurance-check +55 -0
  34. package/templates/etiquette-vanilla-v0/source/control-seat/bin/compact-local-events +71 -0
  35. package/templates/etiquette-vanilla-v0/source/control-seat/bin/hooks/post-tool-use +64 -0
  36. package/templates/etiquette-vanilla-v0/source/control-seat/bin/hooks/session-end +64 -0
  37. package/templates/etiquette-vanilla-v0/source/control-seat/bin/hooks/session-start +64 -0
  38. package/templates/etiquette-vanilla-v0/source/control-seat/bin/hooks/stop +64 -0
  39. package/templates/etiquette-vanilla-v0/source/control-seat/bin/hooks/user-prompt-submit +64 -0
  40. package/templates/etiquette-vanilla-v0/source/control-seat/bin/local-event +53 -0
  41. package/templates/etiquette-vanilla-v0/source/control-seat/bin/post-receipt +143 -0
  42. package/templates/etiquette-vanilla-v0/source/control-seat/bin/post-telemetry +112 -0
  43. package/templates/etiquette-vanilla-v0/source/control-seat/bin/seat-consume-pass +115 -0
  44. package/templates/etiquette-vanilla-v0/source/control-seat/bin/seat-doctor +20 -0
  45. package/templates/etiquette-vanilla-v0/source/control-seat/bin/seat-init +86 -0
  46. package/templates/etiquette-vanilla-v0/source/control-seat/bin/seat-post-readiness +171 -0
  47. package/templates/etiquette-vanilla-v0/source/control-seat/bin/session-init +132 -0
  48. package/templates/etiquette-vanilla-v0/source/control-seat/docs/work/access/ACCESS-ASSURANCE.md +39 -0
  49. package/templates/etiquette-vanilla-v0/source/control-seat/docs/work/access/workspace-secure-profile.v0.json +53 -0
  50. package/templates/etiquette-vanilla-v0/source/control-seat/docs/work/ledger/LEDGER.md +7 -0
  51. package/templates/etiquette-vanilla-v0/source/control-seat/docs/work/playbacks/PLAYBACK_TEMPLATE.md +31 -0
  52. package/templates/etiquette-vanilla-v0/source/control-seat/docs/work/receipts/.gitkeep +1 -0
  53. package/templates/etiquette-vanilla-v0/source/control-seat/docs/work/tasks/CONTROL-001.yaml +13 -0
  54. package/templates/etiquette-vanilla-v0/source/etiquette-kernel/README.md +6 -0
  55. package/templates/etiquette-vanilla-v0/source/etiquette-kernel/bin/kernel-doctor +11 -0
  56. package/templates/etiquette-vanilla-v0/source/etiquette-kernel/contracts/playback.v0.md +37 -0
  57. package/templates/etiquette-vanilla-v0/source/etiquette-kernel/contracts/receipt.v0.md +25 -0
  58. package/templates/etiquette-vanilla-v0/source/etiquette-kernel/contracts/seat-readiness.v0.md +22 -0
  59. package/templates/etiquette-vanilla-v0/source/etiquette-kernel/contracts/task.v0.md +18 -0
  60. package/templates/etiquette-vanilla-v0/validate-vanilla.sh +43 -0
  61. package/templates/github-actions/README.md +30 -0
  62. package/templates/github-actions/w1-webhook-wake-canary.yml +111 -0
  63. package/templates/hosted-receiver/README.md +41 -0
  64. package/templates/hosted-receiver/w1-github-webhook-receiver.mjs +129 -0
  65. package/templates/seat-packs-v0/README.md +72 -0
  66. package/templates/seat-packs-v0/bin/provision-seat +70 -0
  67. package/templates/seat-packs-v0/source/claude-code-seat/.llm-substrate/HANDOFF.md +24 -0
  68. package/templates/seat-packs-v0/source/claude-code-seat/README.md +19 -0
  69. package/templates/seat-packs-v0/source/claude-code-seat/bin/seat-doctor +8 -0
  70. package/templates/seat-packs-v0/source/codex-seat/.llm-substrate/HANDOFF.md +25 -0
  71. package/templates/seat-packs-v0/source/codex-seat/README.md +22 -0
  72. package/templates/seat-packs-v0/source/codex-seat/bin/seat-doctor +8 -0
  73. package/templates/seat-packs-v0/source/gemini-seat/.llm-substrate/HANDOFF.md +23 -0
  74. package/templates/seat-packs-v0/source/gemini-seat/README.md +19 -0
  75. package/templates/seat-packs-v0/source/gemini-seat/bin/seat-doctor +8 -0
  76. package/templates/seat-packs-v0/source/ollama-seat/.llm-substrate/HANDOFF.md +24 -0
  77. package/templates/seat-packs-v0/source/ollama-seat/README.md +19 -0
  78. package/templates/seat-packs-v0/source/ollama-seat/bin/seat-doctor +8 -0
  79. package/templates/seat-packs-v0/source/openrouter-seat/.llm-substrate/HANDOFF.md +24 -0
  80. package/templates/seat-packs-v0/source/openrouter-seat/README.md +19 -0
  81. package/templates/seat-packs-v0/source/openrouter-seat/bin/seat-doctor +8 -0
  82. package/templates/seat-packs-v0/validate-seat-packs.sh +27 -0
  83. package/bin/etq +0 -4
@@ -0,0 +1,116 @@
1
+ # ledger-entry.v0.1
2
+
3
+ `ledger-entry.v0.1` is a narrow retrieval amendment over `ledger-entry.v0`.
4
+ It adds advisory topic and status metadata for local retrieval only. It does
5
+ not authorize work, attach grants, close tasks, or replace receipts.
6
+
7
+ ## Compatibility
8
+
9
+ Existing `ledger-entry.v0` rows remain valid. Consumers must treat missing
10
+ fields as:
11
+
12
+ ```yaml
13
+ topic_hints: []
14
+ status_effect: none
15
+ ```
16
+
17
+ Writers may populate these fields only from explicit operator input, explicit
18
+ agent input, or known command context. They must not infer topics or status
19
+ effects from narrative prose.
20
+
21
+ ## Added Fields
22
+
23
+ ```yaml
24
+ topic_hints:
25
+ type: string[]
26
+ default: []
27
+ format: kebab-case
28
+ max_items: 8
29
+ authority: advisory_hint_only
30
+
31
+ status_effect:
32
+ type: enum
33
+ default: none
34
+ values:
35
+ - none
36
+ - observed
37
+ - changed
38
+ - gap_found
39
+ - reserved
40
+ - closed
41
+ - proved
42
+ authority: advisory_classification_only
43
+ ```
44
+
45
+ ## Compact Ledger Line
46
+
47
+ `LEDGER.md` may include the added fields as compact key-value tokens:
48
+
49
+ ```text
50
+ - 2026-05-20T09:30:00.000Z schema=ledger-entry.v0.1 entry_id=ledger-entry:topic-snapshot-example entry_type=review spine_eligible=true authority_class=advisory grants_execution=false export_class=workspace_shared refs=bus:events://1870,artifacts:docs/work/topic-snapshots/example.md topic_hints=ledger-retrieval,local-remote-sync status_effect=gap_found authority=advisory-only
51
+ ```
52
+
53
+ Omitted `topic_hints` means no topic hints. Omitted `status_effect` means
54
+ `none`.
55
+
56
+ ## Local Retrieval Index
57
+
58
+ V0.1 permits a generated local SQLite/FTS5 cache at:
59
+
60
+ ```text
61
+ .etiquette/state/ledger/index.db
62
+ ```
63
+
64
+ The index is derived and uncommitted. It is not canonical. Search results from
65
+ the index must carry literal authority-false flags:
66
+
67
+ ```yaml
68
+ is_canonical: false
69
+ regenerable: true
70
+ can_authorize: false
71
+ ```
72
+
73
+ Index regeneration policy:
74
+
75
+ - rebuild from canonical docs and ledger files;
76
+ - never write through from the index into `LEDGER.md`;
77
+ - delete and recreate the generated cache on rebuild;
78
+ - either rebuild explicitly or run a stale-check before using search results.
79
+
80
+ V0.1 reserves vector search, `sqlite-vec`, Chroma, and Postgres adapters for a
81
+ future lane. SQLite FTS5 is the only retrieval accelerator in this version.
82
+
83
+ ## Local-Private Verbatim Store
84
+
85
+ V0.1 also reserves an opt-in local-only verbatim store at:
86
+
87
+ ```text
88
+ .etiquette/state/ledger/private-verbatim.db
89
+ ```
90
+
91
+ Rules:
92
+
93
+ - disabled by default;
94
+ - requires explicit operator opt-in;
95
+ - never committed;
96
+ - never exported to hosted or shared projection;
97
+ - no automatic capture of session chat, bus packets, prompts, or tool output;
98
+ - any stored chunks must carry `export_class: local_private`.
99
+
100
+ Shared exports may include summaries and durable refs only.
101
+
102
+ ## Authority Boundary
103
+
104
+ ```yaml
105
+ authority_boundary:
106
+ can_authorize_work: false
107
+ can_execute_work: false
108
+ can_attach_grant: false
109
+ can_close_task: false
110
+ can_replace_receipt: false
111
+ can_replace_audit_log: false
112
+ ```
113
+
114
+ The ledger remains accountable truth. The index accelerates retrieval.
115
+ Verbatim memory stays local-private. Snapshots and capsules interpret with
116
+ citations. Receipts prove.
@@ -0,0 +1,90 @@
1
+ # ledger-entry.v0.2
2
+
3
+ `ledger-entry.v0.2` is a narrow bitemporal amendment over `ledger-entry.v0.1`.
4
+ It separates when a covered piece of work happened from when the ledger
5
+ learned about it, and it adds one entry type for honest late recording. It
6
+ does not authorize work, attach grants, close tasks, or replace receipts.
7
+
8
+ ## The rule this encodes
9
+
10
+ ```text
11
+ The leading timestamp (created_at) is the RECORDING time. It is never
12
+ backdated. If work was done off the spine, it is reconciled with a late
13
+ entry recorded at its true time, pointing at contemporaneous evidence.
14
+ Synthesizing entries with past recording times is corruption, not repair:
15
+ one plausible fake timestamp devalues every real one.
16
+ ```
17
+
18
+ This mirrors standing practice elsewhere: accounting adjusting entries,
19
+ clinical late entries, court orders entered nunc pro tunc, and compensating
20
+ events in event-sourced systems. The formal model is bitemporal data:
21
+ `valid_time` (when it happened) vs transaction time (`created_at`, when it
22
+ was recorded).
23
+
24
+ ## Compatibility
25
+
26
+ Existing `ledger-entry.v0` and `ledger-entry.v0.1` rows remain valid.
27
+ Consumers must treat missing fields as:
28
+
29
+ ```yaml
30
+ valid_time: (absent -> the covered work happened at recording time)
31
+ valid_time_end: (absent -> point-in-time, not a span)
32
+ ```
33
+
34
+ ## Added Fields
35
+
36
+ ```yaml
37
+ valid_time:
38
+ type: iso8601 timestamp
39
+ optional: true
40
+ meaning: when the covered work actually happened (span start if
41
+ valid_time_end is present)
42
+ constraint: must not be after created_at
43
+
44
+ valid_time_end:
45
+ type: iso8601 timestamp
46
+ optional: true
47
+ requires: valid_time
48
+ constraint: valid_time <= valid_time_end <= created_at
49
+ ```
50
+
51
+ ## Added Entry Type
52
+
53
+ `entry_type: retroactive_import` — a late reconciliation entry covering work
54
+ that was executed without contemporaneous spine entries. Rules, enforced by
55
+ the validator:
56
+
57
+ - requires schema `ledger-entry.v0.2` (rejected on v0/v0.1);
58
+ - must declare `valid_time` (what period it covers);
59
+ - must carry at least one contemporaneous evidence ref among
60
+ `refs.commits`, `refs.receipts`, or `refs.artifacts` — evidence that
61
+ carries its own independent timestamps (git commits are the canonical
62
+ witness);
63
+ - authority class must be `advisory` or `audit` — a late entry never mints
64
+ grants or execution authority;
65
+ - one reconciliation entry covering a span with an index artifact is
66
+ preferred over many synthetic per-event entries.
67
+
68
+ ## Compact Ledger Line
69
+
70
+ ```text
71
+ - 2026-07-02T11:00:00.000Z schema=ledger-entry.v0.2 entry_id=ledger-entry:recon-example entry_type=retroactive_import spine_eligible=true authority_class=audit grants_execution=false export_class=workspace_shared refs=commits:3919c0fa,artifacts:docs/work/huddle/recon-index.md valid_time=2026-07-02T00:40:00.000Z valid_time_end=2026-07-02T10:45:00.000Z
72
+ ```
73
+
74
+ Omitted `valid_time` means the entry covers its own recording moment.
75
+
76
+ ## Consumers
77
+
78
+ - The local ledger index (`ledger-query-cli.v0.1`) admits v0.2 lines; the
79
+ bitemporal tokens flow through the parsed `extra` map (no first-class
80
+ index columns in this amendment).
81
+ - Marination/sabbatical record passes are the intended writer of
82
+ `retroactive_import` entries: they may reorganize projections and append
83
+ reconciliations; they must never rewrite or backdate sources (see
84
+ `internal/docs/operations/MARINATION_CHARTER.md`).
85
+
86
+ ## Boundary
87
+
88
+ Advisory metadata only. No scoring engine, no automatic drift detection, no
89
+ hosted sync changes, no authority semantics beyond the explicit restriction
90
+ that retroactive entries cannot carry grant authority.
@@ -0,0 +1,123 @@
1
+ # ledger-entry.v0
2
+
3
+ `ledger-entry.v0` is the typed local ledger record used by the reflex spine.
4
+ It makes compact ledger lines structurally queryable without promoting the
5
+ ledger into an authority source.
6
+
7
+ ## Required Shape
8
+
9
+ ```yaml
10
+ schema: ledger-entry.v0
11
+ entry_id: ledger-entry:dispatch-record-example
12
+ created_at: 2026-05-19T09:30:00.000Z
13
+ entry_type: decision
14
+ spine_eligible: true
15
+ authority:
16
+ class: advisory
17
+ grants_execution: false
18
+ refs:
19
+ lanes: []
20
+ commits: []
21
+ prs: []
22
+ bus: []
23
+ artifacts: []
24
+ receipts:
25
+ - docs/work/receipts/example.yaml
26
+ export_class: workspace_shared
27
+ summary: compact operator-readable statement
28
+ legacy:
29
+ pre_v0: false
30
+ low_authority: false
31
+ ```
32
+
33
+ ## Field Rules
34
+
35
+ `entry_type` must be one of:
36
+
37
+ - `decision`
38
+ - `review`
39
+ - `receipt`
40
+ - `audit`
41
+ - `event`
42
+ - `heartbeat`
43
+ - `capability`
44
+ - `incident`
45
+ - `doctrine`
46
+ - `task`
47
+ - `closeout`
48
+
49
+ `authority.class` must be one of:
50
+
51
+ - `advisory`
52
+ - `grant`
53
+ - `receipt`
54
+ - `audit`
55
+ - `status`
56
+
57
+ `authority.grants_execution` defaults to `false`. Only entries with
58
+ `authority.class: grant` may set it to `true`, and only when the entry carries
59
+ the durable grant reference required by the local workflow.
60
+
61
+ `spine_eligible` is explicit. A reflex index must not infer it from
62
+ `entry_type`. Entries that are useful for current-state routing should set it to
63
+ `true`; archival, noisy, or unreviewed entries should set it to `false`.
64
+
65
+ `export_class` must be one of:
66
+
67
+ - `local_private`
68
+ - `workspace_shared`
69
+ - `org_projected`
70
+ - `public_safe`
71
+
72
+ For entries where `authority.class != advisory`, at least one durable `refs`
73
+ item is required. If evidence is unavailable, the entry must set
74
+ `legacy.low_authority: true` and must not be exported beyond local scope.
75
+
76
+ ## Compact Ledger Line
77
+
78
+ `LEDGER.md` may store the same object as one compact key-value line:
79
+
80
+ ```text
81
+ - 2026-05-19T09:30:00.000Z schema=ledger-entry.v0 entry_id=ledger-entry:dispatch-record-example entry_type=decision spine_eligible=true authority_class=advisory grants_execution=false export_class=workspace_shared refs=receipts:docs/work/receipts/example.yaml authority=advisory-only
82
+ ```
83
+
84
+ Consumers must tolerate earlier compact lines without `schema=ledger-entry.v0`
85
+ by treating them as:
86
+
87
+ ```yaml
88
+ schema: ledger-entry.v0
89
+ legacy:
90
+ pre_v0: true
91
+ low_authority: true
92
+ spine_eligible: false
93
+ ```
94
+
95
+ ## Spine And Brain Boundary
96
+
97
+ ```text
98
+ Reflex routes the present.
99
+ Sabbatical understands the arc.
100
+ Capsules compress the arc back into reflex context.
101
+ ```
102
+
103
+ The reflex spine reads typed ledger entries. The sabbatical brain may produce a
104
+ capsule or dossier, but it cannot write back into the spine directly. Promotion
105
+ from capsule to spine requires an explicit operator gate.
106
+
107
+ ## Authority Boundary
108
+
109
+ Ledger entries may record a grant reference, receipt, review, or status. They do
110
+ not independently authorize, execute, attach grants, close work, replace
111
+ receipts, or replace audit logs.
112
+
113
+ ```yaml
114
+ authority_boundary:
115
+ can_authorize_work: false
116
+ can_execute_work: false
117
+ can_attach_grant: false
118
+ can_replace_receipt: false
119
+ can_replace_audit_log: false
120
+ ```
121
+
122
+ The ledger is a durable operational record. It is not a scheduler, worker queue,
123
+ approval engine, or hosted source of truth.
@@ -0,0 +1,64 @@
1
+ # ledger-query-cli.v0.1
2
+
3
+ `ledger-query-cli.v0.1` is the compact-first local reader over the generated
4
+ ledger retrieval index. It does not replace `LEDGER.md`, receipts, grants, or
5
+ audit logs.
6
+
7
+ ## Commands
8
+
9
+ ```text
10
+ etiquette ledger index [--project <path>] [--db <path>] [--json]
11
+ etiquette ledger search <query> [--project <path>] [--db <path>] [--limit <n>] [--json]
12
+ etiquette ledger search --topic <slug> [--project <path>] [--db <path>] [--limit <n>] [--json]
13
+ etiquette ledger show <entry-or-ref-id> [--project <path>] [--db <path>]
14
+ ```
15
+
16
+ ## Behavior
17
+
18
+ - `index` rebuilds the generated SQLite/FTS5 cache from canonical local docs.
19
+ - `search` returns compact metadata only.
20
+ - `show` exact-fetches one ledger entry by entry id or durable ref.
21
+ - `search` and `show` fail if the cache is missing or stale.
22
+ - `--limit` is capped at 50.
23
+
24
+ ## Compact Search Result
25
+
26
+ ```yaml
27
+ entry_id: ledger-entry:topic-snapshot:example
28
+ title: ledger-entry:topic-snapshot:example
29
+ type: review
30
+ topic_hints:
31
+ - ledger-retrieval
32
+ status_effect: proved
33
+ refs:
34
+ - bus:events://1890
35
+ confidence: metadata
36
+ is_canonical: false
37
+ regenerable: true
38
+ can_authorize: false
39
+ ```
40
+
41
+ ## Exact Fetch Result
42
+
43
+ `show` returns the compact fields plus the canonical source pointer:
44
+
45
+ ```yaml
46
+ source_path: docs/work/ledger/LEDGER.md
47
+ line_no: 3
48
+ ```
49
+
50
+ It does not bulk dump historical documents.
51
+
52
+ ## Authority Boundary
53
+
54
+ ```yaml
55
+ authority_boundary:
56
+ can_authorize_work: false
57
+ can_execute_work: false
58
+ can_attach_grant: false
59
+ can_close_task: false
60
+ can_replace_receipt: false
61
+ can_replace_audit_log: false
62
+ ```
63
+
64
+ The CLI accelerates retrieval. It does not make decisions.
package/package.json CHANGED
@@ -1,17 +1,48 @@
1
1
  {
2
2
  "name": "@etiquekit/etq",
3
- "version": "0.0.1",
4
- "description": "Reserved: Etiquette \u2014 govern agent-assisted engineering work with seats, evidence, and promotion gates. Local-first CLI. Releases begin at https://etiquekit.com",
5
- "homepage": "https://etiquekit.com",
3
+ "version": "1.0.1",
4
+ "description": "Governance and evidence CLI for AI-assisted engineering seats.",
5
+ "private": false,
6
+ "type": "module",
6
7
  "bin": {
7
- "etq": "bin/etq"
8
+ "etq": "bin/etiquette",
9
+ "etiquette": "bin/etiquette",
10
+ "etiquette-core": "bin/etiquette-core"
11
+ },
12
+ "engines": {
13
+ "bun": ">=1.3.0",
14
+ "git": ">=2.40.0"
8
15
  },
9
16
  "files": [
10
- "bin",
11
- "README.md"
17
+ "AGENTS.md",
18
+ "QuickStart.md",
19
+ "README.md",
20
+ "bin/",
21
+ "docs/",
22
+ "scripts/install.sh",
23
+ "scripts/uninstall.sh",
24
+ "templates/",
25
+ "!docs/work/"
12
26
  ],
13
- "license": "SEE LICENSE AT https://etiquekit.com",
14
- "engines": {
15
- "node": ">=18"
16
- }
17
- }
27
+ "scripts": {
28
+ "test": "bun test contracts",
29
+ "typecheck": "tsc -p tsconfig.json --noEmit",
30
+ "cli": "bun packages/control/src/cli.ts",
31
+ "core:cli": "bun packages/control/src/core-cli.ts",
32
+ "release:scan": "sh scripts/release-scan.sh",
33
+ "release:pack": "sh scripts/release-pack-canary.sh",
34
+ "release:checksum": "sh scripts/release-checksum.sh",
35
+ "release:sign": "sh scripts/release-sign.sh",
36
+ "release:build": "sh scripts/release-build.sh",
37
+ "prepack": "sh scripts/release-build.sh"
38
+ },
39
+ "devDependencies": {
40
+ "@types/bun": "^1.2.17",
41
+ "typescript": "^5.7.3"
42
+ },
43
+ "dependencies": {
44
+ "yaml": "2.8.3",
45
+ "zod": "4.3.6"
46
+ },
47
+ "homepage": "https://etiquekit.com"
48
+ }
@@ -0,0 +1,144 @@
1
+ #!/bin/sh
2
+ # Install Etiquette from a signed release tarball into a user-local prefix.
3
+ set -eu
4
+
5
+ BASE_URL=${ETIQUETTE_INSTALL_BASE_URL:-https://etiquette.example.com/releases}
6
+ VERSION=${ETIQUETTE_INSTALL_VERSION:-latest}
7
+ INSTALL_ROOT=${ETIQUETTE_INSTALL_ROOT:-"$HOME/.etiquette"}
8
+ PUBLIC_KEY=${ETIQUETTE_RELEASE_PUBLIC_KEY:-}
9
+ PUBLIC_KEY_URL=${ETIQUETTE_RELEASE_PUBLIC_KEY_URL:-}
10
+ PUBLIC_KEY_SHA256=${ETIQUETTE_RELEASE_PUBLIC_KEY_SHA256:-}
11
+ MODIFY_PROFILE=0
12
+
13
+ usage() {
14
+ cat <<'USAGE'
15
+ usage: install.sh [--version <version>] [--base-url <url>] [--install-root <path>] [--public-key <path>] [--public-key-url <url>] [--public-key-sha256 <hex>] [--modify-profile]
16
+
17
+ Environment:
18
+ ETIQUETTE_INSTALL_BASE_URL release base URL, default https://etiquette.example.com/releases
19
+ ETIQUETTE_INSTALL_VERSION release version or latest
20
+ ETIQUETTE_INSTALL_ROOT install root, default ~/.etiquette
21
+ ETIQUETTE_RELEASE_PUBLIC_KEY RSA public key used to verify SHA256SUMS.sig
22
+ ETIQUETTE_RELEASE_PUBLIC_KEY_URL
23
+ HTTPS or file URL for the RSA public key
24
+ ETIQUETTE_RELEASE_PUBLIC_KEY_SHA256
25
+ expected SHA-256 hex for a downloaded public key
26
+ USAGE
27
+ }
28
+
29
+ while [ "$#" -gt 0 ]; do
30
+ case "$1" in
31
+ --version) VERSION=${2:?missing version}; shift 2 ;;
32
+ --base-url) BASE_URL=${2:?missing base URL}; shift 2 ;;
33
+ --install-root) INSTALL_ROOT=${2:?missing install root}; shift 2 ;;
34
+ --public-key) PUBLIC_KEY=${2:?missing public key}; shift 2 ;;
35
+ --public-key-url) PUBLIC_KEY_URL=${2:?missing public key URL}; shift 2 ;;
36
+ --public-key-sha256) PUBLIC_KEY_SHA256=${2:?missing public key SHA-256}; shift 2 ;;
37
+ --modify-profile) MODIFY_PROFILE=1; shift ;;
38
+ -h|--help) usage; exit 0 ;;
39
+ *) echo "install.sh: unknown argument: $1" >&2; usage >&2; exit 64 ;;
40
+ esac
41
+ done
42
+
43
+ need() {
44
+ if ! command -v "$1" >/dev/null 2>&1; then
45
+ echo "install.sh: missing required command: $1" >&2
46
+ exit 127
47
+ fi
48
+ }
49
+
50
+ need curl
51
+ need bun
52
+ need openssl
53
+ need shasum
54
+ need tar
55
+
56
+ TMPDIR_ROOT=${TMPDIR:-/tmp}
57
+ TMP=$(mktemp -d "$TMPDIR_ROOT/etiquette-install.XXXXXX")
58
+ trap 'rm -rf "$TMP"' EXIT INT TERM
59
+
60
+ if [ -n "$PUBLIC_KEY" ] && [ -n "$PUBLIC_KEY_URL" ]; then
61
+ echo "install.sh: use either --public-key or --public-key-url, not both" >&2
62
+ exit 64
63
+ fi
64
+
65
+ if [ -n "$PUBLIC_KEY" ]; then
66
+ if [ ! -f "$PUBLIC_KEY" ]; then
67
+ echo "install.sh: public key path does not exist: $PUBLIC_KEY" >&2
68
+ exit 1
69
+ fi
70
+ elif [ -n "$PUBLIC_KEY_URL" ]; then
71
+ if [ -z "$PUBLIC_KEY_SHA256" ]; then
72
+ echo "install.sh: --public-key-url requires --public-key-sha256" >&2
73
+ exit 1
74
+ fi
75
+ PUBLIC_KEY="$TMP/etiquette-release.pub"
76
+ curl -fsSL "$PUBLIC_KEY_URL" -o "$PUBLIC_KEY"
77
+ ACTUAL_KEY_SHA=$(shasum -a 256 "$PUBLIC_KEY" | awk '{ print $1 }')
78
+ if [ "$PUBLIC_KEY_SHA256" != "$ACTUAL_KEY_SHA" ]; then
79
+ echo "install.sh: public key SHA-256 mismatch" >&2
80
+ exit 1
81
+ fi
82
+ else
83
+ echo "install.sh: provide --public-key, or --public-key-url with --public-key-sha256" >&2
84
+ exit 1
85
+ fi
86
+
87
+ RELEASE_URL="${BASE_URL%/}/$VERSION"
88
+ cd "$TMP"
89
+ curl -fsSLO "$RELEASE_URL/SHA256SUMS"
90
+ curl -fsSLO "$RELEASE_URL/SHA256SUMS.sig"
91
+ TARBALL=$(awk '/etiquette-[0-9][^ ]*\.tgz$/ { print $2; exit }' SHA256SUMS)
92
+ if [ -z "$TARBALL" ]; then
93
+ echo "install.sh: SHA256SUMS does not name an etiquette release tarball" >&2
94
+ exit 1
95
+ fi
96
+ curl -fsSLO "$RELEASE_URL/$TARBALL"
97
+
98
+ EXPECTED=$(awk -v file="$TARBALL" '$2 == file { print $1; exit }' SHA256SUMS)
99
+ ACTUAL=$(shasum -a 256 "$TARBALL" | awk '{ print $1 }')
100
+ if [ "$EXPECTED" != "$ACTUAL" ]; then
101
+ echo "install.sh: checksum mismatch for $TARBALL" >&2
102
+ exit 1
103
+ fi
104
+
105
+ openssl dgst -sha256 -verify "$PUBLIC_KEY" -signature SHA256SUMS.sig SHA256SUMS >/dev/null
106
+
107
+ VERSION_DIR=$(basename "$TARBALL" .tgz)
108
+ LIB_DIR="$INSTALL_ROOT/lib/$VERSION_DIR"
109
+ BIN_DIR="$INSTALL_ROOT/bin"
110
+ mkdir -p "$LIB_DIR" "$BIN_DIR"
111
+ tar -xzf "$TARBALL"
112
+ rm -rf "$LIB_DIR"
113
+ mkdir -p "$LIB_DIR"
114
+ cp -R package/. "$LIB_DIR/"
115
+ if [ -f "$LIB_DIR/package.json" ]; then
116
+ (
117
+ cd "$LIB_DIR"
118
+ bun install --production >/dev/null
119
+ )
120
+ fi
121
+ ln -sfn "$LIB_DIR/bin/etiquette" "$BIN_DIR/etiquette"
122
+ ln -sfn "$LIB_DIR/bin/etiquette-core" "$BIN_DIR/etiquette-core"
123
+
124
+ if [ "$MODIFY_PROFILE" -eq 1 ]; then
125
+ PROFILE=${SHELL##*/}
126
+ case "$PROFILE" in
127
+ zsh) PROFILE_FILE="$HOME/.zshrc" ;;
128
+ bash) PROFILE_FILE="$HOME/.bashrc" ;;
129
+ *) PROFILE_FILE="$HOME/.profile" ;;
130
+ esac
131
+ LINE="export PATH=\"$BIN_DIR:\$PATH\""
132
+ touch "$PROFILE_FILE"
133
+ if ! grep -Fqx "$LINE" "$PROFILE_FILE"; then
134
+ printf '\n# Etiquette CLI\n%s\n' "$LINE" >> "$PROFILE_FILE"
135
+ fi
136
+ echo "install.sh: updated $PROFILE_FILE"
137
+ else
138
+ echo "install.sh: add $BIN_DIR to PATH, or rerun with --modify-profile"
139
+ fi
140
+
141
+ echo "install.sh: installed etiquette into $INSTALL_ROOT"
142
+ echo "install.sh: docs: https://etiquette.example.com"
143
+ echo "install.sh: run: $BIN_DIR/etiquette doctor --project <workspace>"
144
+ echo "install.sh: agent skill integrations are explicit; no Claude/Codex/Gemini config was modified"
@@ -0,0 +1,58 @@
1
+ #!/bin/sh
2
+ # Remove a user-local Etiquette CLI install without touching project ledgers.
3
+ set -eu
4
+
5
+ INSTALL_ROOT=${ETIQUETTE_INSTALL_ROOT:-"$HOME/.etiquette"}
6
+ DRY_RUN=0
7
+ YES=0
8
+
9
+ usage() {
10
+ cat <<'USAGE'
11
+ usage: uninstall.sh [--install-root <path>] [--dry-run] [--yes]
12
+
13
+ Removes user-local CLI links and installed release directories under the install
14
+ root. It never removes project-local .etiquette state, docs/work, receipts, or
15
+ ledgers from application repositories.
16
+ USAGE
17
+ }
18
+
19
+ while [ "$#" -gt 0 ]; do
20
+ case "$1" in
21
+ --install-root) INSTALL_ROOT=${2:?missing install root}; shift 2 ;;
22
+ --dry-run) DRY_RUN=1; shift ;;
23
+ --yes) YES=1; shift ;;
24
+ -h|--help) usage; exit 0 ;;
25
+ *) echo "uninstall.sh: unknown argument: $1" >&2; usage >&2; exit 64 ;;
26
+ esac
27
+ done
28
+
29
+ case "$INSTALL_ROOT" in
30
+ ""|"/"|"$HOME"|"$HOME/") echo "uninstall.sh: refusing unsafe install root: $INSTALL_ROOT" >&2; exit 64 ;;
31
+ esac
32
+
33
+ run() {
34
+ if [ "$DRY_RUN" -eq 1 ]; then
35
+ printf 'dry-run: %s\n' "$*"
36
+ else
37
+ "$@"
38
+ fi
39
+ }
40
+
41
+ if [ "$YES" -ne 1 ] && [ "$DRY_RUN" -ne 1 ]; then
42
+ echo "uninstall.sh: refusing without --yes (use --dry-run to preview)" >&2
43
+ exit 64
44
+ fi
45
+
46
+ run rm -f "$INSTALL_ROOT/bin/etiquette"
47
+ run rm -f "$INSTALL_ROOT/bin/etiquette-core"
48
+ if [ -d "$INSTALL_ROOT/lib" ]; then
49
+ for path in "$INSTALL_ROOT"/lib/etiquette-*; do
50
+ [ -e "$path" ] || continue
51
+ run rm -rf "$path"
52
+ done
53
+ fi
54
+ run rmdir "$INSTALL_ROOT/bin" 2>/dev/null || true
55
+ run rmdir "$INSTALL_ROOT/lib" 2>/dev/null || true
56
+ run rmdir "$INSTALL_ROOT" 2>/dev/null || true
57
+
58
+ echo "uninstall.sh: project .etiquette and docs/work directories were not touched"