@balpal4495/quorum 1.0.0 → 2.0.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/README.md +238 -194
- package/SETUP.md +60 -96
- package/bin/commands/init.js +59 -60
- package/bin/quorum.js +0 -0
- package/package.json +4 -2
- package/bin/init.js +0 -378
package/SETUP.md
CHANGED
|
@@ -12,9 +12,16 @@ If you have Node.js 18+ available, run this from the project root:
|
|
|
12
12
|
npx @balpal4495/quorum@latest init
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
This handles all steps below automatically —
|
|
15
|
+
This handles all steps below automatically — writing Quorum docs, merging instruction files,
|
|
16
|
+
updating `package.json`, `.gitignore`, and creating the Chronicle directory.
|
|
16
17
|
|
|
17
|
-
After it completes, run `npm install
|
|
18
|
+
After it completes, run `npm install`. The CLI is immediately usable:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
quorum advisor brief
|
|
22
|
+
quorum advisor "what has the team decided about X?"
|
|
23
|
+
quorum check --outcome '...' --design '...'
|
|
24
|
+
```
|
|
18
25
|
|
|
19
26
|
---
|
|
20
27
|
|
|
@@ -29,9 +36,9 @@ Do not skip steps. Do not ask for confirmation between steps — complete the fu
|
|
|
29
36
|
|
|
30
37
|
Read these files in full before proceeding:
|
|
31
38
|
|
|
32
|
-
- `quorum/
|
|
33
|
-
- `quorum/
|
|
34
|
-
- `.github/copilot-instructions.md` — workflow rules for AI agents
|
|
39
|
+
- `quorum/AGENTS.md` — module file ownership and invariants
|
|
40
|
+
- `quorum/CLAUDE.md` — design decisions and constraints
|
|
41
|
+
- `.github/copilot-instructions.md` — workflow rules for AI agents
|
|
35
42
|
|
|
36
43
|
These are your operating instructions for everything that follows.
|
|
37
44
|
|
|
@@ -52,14 +59,12 @@ Does .chronicle/ exist? yes / no
|
|
|
52
59
|
|
|
53
60
|
---
|
|
54
61
|
|
|
55
|
-
## Step 3 — Install
|
|
62
|
+
## Step 3 — Install Quorum
|
|
56
63
|
|
|
57
|
-
Open `package.json` at the project root. Add
|
|
64
|
+
Open `package.json` at the project root. Add to `devDependencies` if not already present:
|
|
58
65
|
|
|
59
66
|
```json
|
|
60
|
-
"
|
|
61
|
-
"vectordb": "^0.4.0",
|
|
62
|
-
"@xenova/transformers": "^2.17.0"
|
|
67
|
+
"@balpal4495/quorum": "^2.0.0"
|
|
63
68
|
```
|
|
64
69
|
|
|
65
70
|
Then run:
|
|
@@ -70,77 +75,57 @@ npm install
|
|
|
70
75
|
|
|
71
76
|
If the project uses `yarn` or `pnpm`, use the appropriate installer instead.
|
|
72
77
|
|
|
73
|
-
> `zod` is required for all structured LLM output validation.
|
|
74
|
-
> `vectordb` is the LanceDB adapter (swappable — see `quorum/modules/oracle/adapters/`).
|
|
75
|
-
> `@xenova/transformers` is the local ONNX embedder (swappable — see `quorum/modules/oracle/adapters/xenova-embedder.ts`).
|
|
76
|
-
|
|
77
78
|
---
|
|
78
79
|
|
|
79
80
|
## Step 4 — Merge AI instruction files
|
|
80
81
|
|
|
81
82
|
### 4a. `.github/copilot-instructions.md`
|
|
82
83
|
|
|
83
|
-
The automated init command
|
|
84
|
+
The automated init command handles this step automatically.
|
|
84
85
|
|
|
85
|
-
**If
|
|
86
|
-
|
|
87
|
-
Check whether `.github/copilot-instructions.md` already exists.
|
|
88
|
-
|
|
89
|
-
**If it does not exist:** Fetch the Quorum copilot instructions from the Quorum GitHub repo (`balpal4495/Quorum`) at `.github/copilot-instructions.md` and write it to `.github/copilot-instructions.md` in the project root.
|
|
90
|
-
|
|
91
|
-
**If it already exists and does not contain `<!-- quorum -->`:** Append the Quorum instructions to the existing file, preceded by:
|
|
86
|
+
**If completing manually:** fetch `.github/copilot-instructions.md` from the Quorum GitHub repo (`balpal4495/Quorum`) and write it to `.github/copilot-instructions.md` in the project root. If the file already exists and does not contain `<!-- quorum:start -->`, append:
|
|
92
87
|
|
|
93
88
|
```markdown
|
|
94
89
|
---
|
|
95
90
|
|
|
96
|
-
<!-- quorum -->
|
|
91
|
+
<!-- quorum:start -->
|
|
92
|
+
<content from Quorum repo>
|
|
93
|
+
<!-- quorum:end -->
|
|
97
94
|
```
|
|
98
95
|
|
|
99
|
-
Do not replace or overwrite existing content.
|
|
100
|
-
|
|
101
96
|
### 4b. `AGENTS.md`
|
|
102
97
|
|
|
103
98
|
**If it does not exist:**
|
|
104
|
-
Create `AGENTS.md` at the project root with this content:
|
|
105
99
|
|
|
106
100
|
```markdown
|
|
107
101
|
# Agent Instructions
|
|
108
102
|
|
|
109
|
-
|
|
103
|
+
<!-- quorum:start -->
|
|
104
|
+
## Quorum
|
|
105
|
+
|
|
106
|
+
See [quorum/AGENTS.md](quorum/AGENTS.md) for module file ownership and internals.
|
|
110
107
|
See [.github/copilot-instructions.md](.github/copilot-instructions.md) for workflow rules.
|
|
108
|
+
<!-- quorum:end -->
|
|
111
109
|
```
|
|
112
110
|
|
|
113
|
-
**If it already exists:**
|
|
114
|
-
Append to it:
|
|
115
|
-
|
|
116
|
-
```markdown
|
|
117
|
-
|
|
118
|
-
## Quorum modules
|
|
119
|
-
|
|
120
|
-
See [quorum/modules/AGENTS.md](quorum/modules/AGENTS.md) for Advisor, Oracle, Jury, Council, and Sentinel internals.
|
|
121
|
-
```
|
|
111
|
+
**If it already exists:** append the `<!-- quorum:start --> ... <!-- quorum:end -->` block above.
|
|
122
112
|
|
|
123
113
|
### 4c. `CLAUDE.md`
|
|
124
114
|
|
|
125
115
|
**If it does not exist:**
|
|
126
|
-
Create `CLAUDE.md` at the project root with this content:
|
|
127
116
|
|
|
128
117
|
```markdown
|
|
129
118
|
# Claude Instructions
|
|
130
119
|
|
|
131
|
-
|
|
120
|
+
<!-- quorum:start -->
|
|
121
|
+
## Quorum
|
|
122
|
+
|
|
123
|
+
See [quorum/CLAUDE.md](quorum/CLAUDE.md) for design decisions and invariants.
|
|
132
124
|
See [.github/copilot-instructions.md](.github/copilot-instructions.md) for workflow rules.
|
|
125
|
+
<!-- quorum:end -->
|
|
133
126
|
```
|
|
134
127
|
|
|
135
|
-
**If it already exists:**
|
|
136
|
-
Append to it:
|
|
137
|
-
|
|
138
|
-
```markdown
|
|
139
|
-
|
|
140
|
-
## Quorum modules
|
|
141
|
-
|
|
142
|
-
See [quorum/modules/CLAUDE.md](quorum/modules/CLAUDE.md) for Advisor, Oracle, Jury, Council, and Sentinel internals.
|
|
143
|
-
```
|
|
128
|
+
**If it already exists:** append the `<!-- quorum:start --> ... <!-- quorum:end -->` block above.
|
|
144
129
|
|
|
145
130
|
---
|
|
146
131
|
|
|
@@ -148,27 +133,25 @@ See [quorum/modules/CLAUDE.md](quorum/modules/CLAUDE.md) for Advisor, Oracle, Ju
|
|
|
148
133
|
|
|
149
134
|
**If `.gitignore` does not exist**, create it.
|
|
150
135
|
|
|
151
|
-
Add the following block if
|
|
136
|
+
Add the following block if not already present:
|
|
152
137
|
|
|
153
138
|
```gitignore
|
|
154
139
|
# Quorum — Chronicle
|
|
155
140
|
# entries/ is a LanceDB binary vector store — do not commit
|
|
156
141
|
.chronicle/entries/
|
|
157
|
-
|
|
158
|
-
# proposals/ contains pending human-approval writes — commit these
|
|
159
|
-
# (remove the line above if you want to ignore the whole store)
|
|
142
|
+
.chronicle/query-log.jsonl
|
|
160
143
|
```
|
|
161
144
|
|
|
162
145
|
---
|
|
163
146
|
|
|
164
|
-
## Step 6 — Wire setup() into the project
|
|
147
|
+
## Step 6 — Wire setup() into the project (programmatic use only)
|
|
165
148
|
|
|
166
|
-
|
|
149
|
+
Skip this step if you are using only the CLI (`quorum advisor`, `quorum check`, etc.).
|
|
167
150
|
|
|
168
|
-
|
|
151
|
+
For programmatic use, find the application entry point (e.g. `index.ts`, `server.ts`, `app.ts`).
|
|
169
152
|
|
|
170
153
|
```typescript
|
|
171
|
-
import { setup } from "
|
|
154
|
+
import { setup } from "@balpal4495/quorum"
|
|
172
155
|
|
|
173
156
|
const { oracle, evaluate, deliberate, ask } = await setup({
|
|
174
157
|
llm: yourLLMProvider, // replace with your project's LLM provider function
|
|
@@ -176,13 +159,11 @@ const { oracle, evaluate, deliberate, ask } = await setup({
|
|
|
176
159
|
```
|
|
177
160
|
|
|
178
161
|
`setup()` creates `.chronicle/` directories, warms the embedder, and wires all module dependencies.
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
`ask(question)` is the plain-language interface — it queries Oracle automatically, synthesises Chronicle evidence into a concise answer, and retries internally until the answer meets a confidence threshold. Use it to answer questions rather than to evaluate designs.
|
|
162
|
+
Must be called once before any `oracle.query()`, `evaluate()`, `deliberate()`, or `ask()` call.
|
|
182
163
|
|
|
183
|
-
|
|
164
|
+
`ask(question)` is the plain-language interface — it queries Oracle automatically, synthesises Chronicle evidence into a concise answer, and retries internally until the answer meets a confidence threshold.
|
|
184
165
|
|
|
185
|
-
**Approving Chronicle proposals:**
|
|
166
|
+
**Approving Chronicle proposals:**
|
|
186
167
|
|
|
187
168
|
```bash
|
|
188
169
|
quorum commit --list # see pending proposals
|
|
@@ -190,39 +171,33 @@ quorum commit <id> # approve and index a proposal
|
|
|
190
171
|
quorum commit <id> --dry-run # preview without writing
|
|
191
172
|
```
|
|
192
173
|
|
|
193
|
-
Requires `@xenova/transformers` and `vectordb` (both added in Step 3).
|
|
194
|
-
|
|
195
174
|
---
|
|
196
175
|
|
|
197
176
|
## Step 7 — Verify Chronicle is created
|
|
198
177
|
|
|
199
|
-
|
|
178
|
+
Confirm `.chronicle/proposals/` and `.chronicle/committed/` exist:
|
|
200
179
|
|
|
201
180
|
```bash
|
|
202
181
|
ls .chronicle/
|
|
203
|
-
# expected: proposals/
|
|
204
|
-
# entries/ will appear after the first oracle.commit()
|
|
182
|
+
# expected: committed/ proposals/
|
|
205
183
|
```
|
|
206
184
|
|
|
207
|
-
If the directory is not created, re-check that `setup()` is being awaited correctly.
|
|
208
|
-
|
|
209
185
|
---
|
|
210
186
|
|
|
211
|
-
## Step 8 —
|
|
212
|
-
|
|
213
|
-
Confirm the modules are working in this environment:
|
|
187
|
+
## Step 8 — Verify the CLI works
|
|
214
188
|
|
|
215
189
|
```bash
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
# Eval suite — deterministic assertions, no LLM required
|
|
220
|
-
npx vitest run quorum/evals/
|
|
190
|
+
quorum advisor brief
|
|
191
|
+
quorum growth
|
|
221
192
|
```
|
|
222
193
|
|
|
223
|
-
|
|
194
|
+
Both commands run without any LLM. If they fail, check that `npm install` completed successfully.
|
|
224
195
|
|
|
225
|
-
|
|
196
|
+
To run Quorum's eval suite (optional — tests Quorum's own correctness):
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
npx vitest run node_modules/@balpal4495/quorum/evals/
|
|
200
|
+
```
|
|
226
201
|
|
|
227
202
|
---
|
|
228
203
|
|
|
@@ -231,10 +206,9 @@ The eval suite runs canonical test cases (known-bad proposals that should block,
|
|
|
231
206
|
Once all steps are complete, report:
|
|
232
207
|
|
|
233
208
|
1. Which files were created vs appended
|
|
234
|
-
2.
|
|
235
|
-
3.
|
|
236
|
-
4.
|
|
237
|
-
5. Any step that could not be completed and why
|
|
209
|
+
2. Whether `npm install` succeeded
|
|
210
|
+
3. The path to `setup()` in the entry point if wired (or note if CLI-only)
|
|
211
|
+
4. Any step that could not be completed and why
|
|
238
212
|
|
|
239
213
|
---
|
|
240
214
|
|
|
@@ -242,10 +216,7 @@ Once all steps are complete, report:
|
|
|
242
216
|
|
|
243
217
|
Skip this step if you do not have Google Gemini CLI installed. Quorum is fully functional without it.
|
|
244
218
|
|
|
245
|
-
|
|
246
|
-
analysis to Gemini — useful when a task requires surveying the whole codebase at once.
|
|
247
|
-
|
|
248
|
-
**10a. Install Gemini CLI** (if not already installed — requires Node.js 18+):
|
|
219
|
+
**10a. Install Gemini CLI** (if not already installed):
|
|
249
220
|
|
|
250
221
|
```bash
|
|
251
222
|
npm install -g @google/gemini-cli
|
|
@@ -258,30 +229,23 @@ export GEMINI_API_KEY="your-key-here"
|
|
|
258
229
|
export GEMINI_CLI_TRUST_WORKSPACE=true
|
|
259
230
|
```
|
|
260
231
|
|
|
261
|
-
**10c. Create `GEMINI.md`** at the project root
|
|
262
|
-
Copy `quorum/modules/AGENTS.md` content as a starting point, or write a brief description of
|
|
263
|
-
the project and the Quorum architecture. The `GEMINI.md` in the Quorum repo itself is a
|
|
264
|
-
working example.
|
|
232
|
+
**10c. Create `GEMINI.md`** at the project root. Use `quorum/AGENTS.md` content as a starting point, or write a brief description of the project and the Quorum architecture.
|
|
265
233
|
|
|
266
|
-
Once the key is set and `gemini -p "hello"` responds, Claude Code will automatically detect
|
|
267
|
-
Gemini and use it for large-context tasks.
|
|
234
|
+
Once the key is set and `gemini -p "hello"` responds, Claude Code will automatically detect Gemini and use it for large-context tasks.
|
|
268
235
|
|
|
269
236
|
---
|
|
270
237
|
|
|
271
238
|
## After setup
|
|
272
239
|
|
|
273
|
-
You are now operating under Quorum. The rules in `quorum/
|
|
240
|
+
You are now operating under Quorum. The rules in `quorum/AGENTS.md` and `.github/copilot-instructions.md` apply to all subsequent work.
|
|
274
241
|
|
|
275
242
|
Key reminders:
|
|
276
243
|
- **Ask Advisor for context.** `quorum advisor "what has the team decided about X?"` before starting any meaningful work.
|
|
277
|
-
- **Query Oracle before proposing anything.** `oracle.query("what you're about to do")` first.
|
|
278
244
|
- **Never call `oracle.commit()` autonomously.** Only `oracle.propose()`. A human commits.
|
|
279
245
|
- **Chronicle entries are ground truth.** Respect `refuted` entries — do not retry what has already failed.
|
|
280
246
|
|
|
281
247
|
### CLI quick reference
|
|
282
248
|
|
|
283
|
-
These commands are available globally after `npm install -g @balpal4495/quorum`:
|
|
284
|
-
|
|
285
249
|
| Command | What it does |
|
|
286
250
|
|---|---|
|
|
287
251
|
| `quorum advisor "question"` | Ask a plain-language question — answer synthesised from Chronicle (needs LLM) |
|
|
@@ -297,4 +261,4 @@ These commands are available globally after `npm install -g @balpal4495/quorum`:
|
|
|
297
261
|
|
|
298
262
|
`quorum check` exit codes: `0` = low/medium risk · `1` = high · `2` = critical
|
|
299
263
|
|
|
300
|
-
`quorum advisor ask` and `quorum evolve` auto-detect any available LLM: `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, `OPENAI_BASE_URL`, Ollama at localhost:11434, or an authenticated `gemini` CLI. When running inside an AI agent
|
|
264
|
+
`quorum advisor ask` and `quorum evolve` auto-detect any available LLM: `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, `OPENAI_BASE_URL`, Ollama at localhost:11434, or an authenticated `gemini` CLI. When running inside an AI agent with no separate key, they output Chronicle evidence and a synthesis request for the agent to answer inline.
|
package/bin/commands/init.js
CHANGED
|
@@ -10,12 +10,6 @@ const _require = createRequire(import.meta.url)
|
|
|
10
10
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
11
11
|
const QUORUM_ROOT = path.resolve(__dirname, "../..")
|
|
12
12
|
|
|
13
|
-
const DEPS = { zod: "^3.23.0" }
|
|
14
|
-
const OPTIONAL_DEPS = {
|
|
15
|
-
vectordb: "^0.4.0",
|
|
16
|
-
"@xenova/transformers": "^2.17.0",
|
|
17
|
-
}
|
|
18
|
-
|
|
19
13
|
async function exists(p) {
|
|
20
14
|
return fs.access(p).then(() => true).catch(() => false)
|
|
21
15
|
}
|
|
@@ -29,25 +23,24 @@ function geminiAvailable() {
|
|
|
29
23
|
}
|
|
30
24
|
|
|
31
25
|
async function guardAlreadyInitialized(target) {
|
|
32
|
-
if (await exists(path.join(target, "quorum"
|
|
26
|
+
if (await exists(path.join(target, ".quorum-version"))) {
|
|
33
27
|
console.log(c.yellow("\nQuorum is already initialized in this project."))
|
|
34
|
-
console.log("
|
|
28
|
+
console.log("Run 'npm update @balpal4495/quorum' to upgrade to the latest version.\n")
|
|
35
29
|
process.exit(0)
|
|
36
30
|
}
|
|
37
31
|
}
|
|
38
32
|
|
|
39
|
-
async function
|
|
40
|
-
log.section("
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
log.created("quorum/modules/")
|
|
33
|
+
async function writeQuorumDocs(target) {
|
|
34
|
+
log.section("Writing Quorum docs")
|
|
35
|
+
await fs.mkdir(path.join(target, "quorum"), { recursive: true })
|
|
36
|
+
for (const file of ["CLAUDE.md", "AGENTS.md"]) {
|
|
37
|
+
const src = path.join(QUORUM_ROOT, "modules", file)
|
|
38
|
+
const dest = path.join(target, "quorum", file)
|
|
39
|
+
if (await exists(src)) {
|
|
40
|
+
await fs.copyFile(src, dest)
|
|
41
|
+
log.created(`quorum/${file}`)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
51
44
|
await fs.copyFile(
|
|
52
45
|
path.join(QUORUM_ROOT, "SETUP.md"),
|
|
53
46
|
path.join(target, "quorum", "SETUP.md"),
|
|
@@ -55,11 +48,9 @@ async function copyModules(target) {
|
|
|
55
48
|
log.created("quorum/SETUP.md")
|
|
56
49
|
}
|
|
57
50
|
|
|
58
|
-
async function
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
await fs.cp(src, dest, { recursive: true })
|
|
62
|
-
log.created("quorum/evals/")
|
|
51
|
+
async function writeQuorumVersion(target, version) {
|
|
52
|
+
await fs.writeFile(path.join(target, ".quorum-version"), version + "\n", "utf8")
|
|
53
|
+
log.created(".quorum-version")
|
|
63
54
|
}
|
|
64
55
|
|
|
65
56
|
async function mergeCopilotInstructions(target) {
|
|
@@ -67,14 +58,15 @@ async function mergeCopilotInstructions(target) {
|
|
|
67
58
|
const src = path.join(QUORUM_ROOT, ".github", "copilot-instructions.md")
|
|
68
59
|
const dest = path.join(target, ".github", "copilot-instructions.md")
|
|
69
60
|
const content = await fs.readFile(src, "utf8")
|
|
61
|
+
const block = `<!-- quorum:start -->\n${content}\n<!-- quorum:end -->`
|
|
70
62
|
await fs.mkdir(path.join(target, ".github"), { recursive: true })
|
|
71
63
|
if (await exists(dest)) {
|
|
72
64
|
const existing = await fs.readFile(dest, "utf8")
|
|
73
|
-
if (existing.includes("<!-- quorum -->")) { log.skipped(".github/copilot-instructions.md (already present)"); return }
|
|
74
|
-
await fs.appendFile(dest, `\n\n---\n\n
|
|
65
|
+
if (existing.includes("<!-- quorum:start -->")) { log.skipped(".github/copilot-instructions.md (already present)"); return }
|
|
66
|
+
await fs.appendFile(dest, `\n\n---\n\n${block}`, "utf8")
|
|
75
67
|
log.appended(".github/copilot-instructions.md")
|
|
76
68
|
} else {
|
|
77
|
-
await fs.writeFile(dest,
|
|
69
|
+
await fs.writeFile(dest, block, "utf8")
|
|
78
70
|
log.created(".github/copilot-instructions.md")
|
|
79
71
|
}
|
|
80
72
|
}
|
|
@@ -82,13 +74,18 @@ async function mergeCopilotInstructions(target) {
|
|
|
82
74
|
async function mergeAgentsMd(target) {
|
|
83
75
|
const dest = path.join(target, "AGENTS.md")
|
|
84
76
|
const section = [
|
|
85
|
-
"",
|
|
86
|
-
"
|
|
87
|
-
"
|
|
77
|
+
"",
|
|
78
|
+
"<!-- quorum:start -->",
|
|
79
|
+
"## Quorum",
|
|
80
|
+
"",
|
|
81
|
+
"See [quorum/AGENTS.md](quorum/AGENTS.md) for module file ownership and internals.",
|
|
82
|
+
"See [.github/copilot-instructions.md](.github/copilot-instructions.md) for workflow rules.",
|
|
83
|
+
"<!-- quorum:end -->",
|
|
84
|
+
"",
|
|
88
85
|
].join("\n")
|
|
89
86
|
if (await exists(dest)) {
|
|
90
87
|
const existing = await fs.readFile(dest, "utf8")
|
|
91
|
-
if (existing.includes("quorum
|
|
88
|
+
if (existing.includes("<!-- quorum:start -->")) { log.skipped("AGENTS.md (already present)"); return }
|
|
92
89
|
await fs.appendFile(dest, section, "utf8")
|
|
93
90
|
log.appended("AGENTS.md")
|
|
94
91
|
} else {
|
|
@@ -98,11 +95,12 @@ async function mergeAgentsMd(target) {
|
|
|
98
95
|
}
|
|
99
96
|
|
|
100
97
|
async function mergeClaudeMd(target) {
|
|
101
|
-
const dest
|
|
98
|
+
const dest = path.join(target, "CLAUDE.md")
|
|
102
99
|
const section = `
|
|
103
|
-
|
|
100
|
+
<!-- quorum:start -->
|
|
101
|
+
## Quorum
|
|
104
102
|
|
|
105
|
-
See [quorum/
|
|
103
|
+
See [quorum/CLAUDE.md](quorum/CLAUDE.md) for design decisions and invariants.
|
|
106
104
|
See [.github/copilot-instructions.md](.github/copilot-instructions.md) for workflow rules.
|
|
107
105
|
|
|
108
106
|
## Gemini CLI (optional assistant)
|
|
@@ -127,10 +125,11 @@ source ~/.zshrc && gemini -p "I'm about to change X. What should I watch out for
|
|
|
127
125
|
|
|
128
126
|
You reason about Gemini's output — it assists, you decide. Never pass its response to the
|
|
129
127
|
user unfiltered. If Gemini contradicts what you know from reading the code, trust your reading.
|
|
128
|
+
<!-- quorum:end -->
|
|
130
129
|
`
|
|
131
130
|
if (await exists(dest)) {
|
|
132
131
|
const existing = await fs.readFile(dest, "utf8")
|
|
133
|
-
if (existing.includes("quorum
|
|
132
|
+
if (existing.includes("<!-- quorum:start -->")) { log.skipped("CLAUDE.md (already present)"); return }
|
|
134
133
|
await fs.appendFile(dest, section, "utf8")
|
|
135
134
|
log.appended("CLAUDE.md")
|
|
136
135
|
} else {
|
|
@@ -147,7 +146,7 @@ async function mergeGeminiMd(target) {
|
|
|
147
146
|
if (await exists(src)) { await fs.copyFile(src, dest); log.created("GEMINI.md") }
|
|
148
147
|
}
|
|
149
148
|
|
|
150
|
-
async function updatePackageJson(target) {
|
|
149
|
+
async function updatePackageJson(target, version) {
|
|
151
150
|
log.section("Updating package.json")
|
|
152
151
|
const pkgPath = path.join(target, "package.json")
|
|
153
152
|
let pkg
|
|
@@ -157,30 +156,27 @@ async function updatePackageJson(target) {
|
|
|
157
156
|
pkg = { name: path.basename(target), version: "0.1.0", private: true }
|
|
158
157
|
log.warn("No package.json found — creating a minimal one")
|
|
159
158
|
}
|
|
160
|
-
pkg.
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}
|
|
166
|
-
for (const [name, version] of Object.entries(OPTIONAL_DEPS)) {
|
|
167
|
-
if (!pkg.optionalDependencies[name]) { pkg.optionalDependencies[name] = version; added.push(`${name} (optional)`) }
|
|
159
|
+
pkg.devDependencies = pkg.devDependencies ?? {}
|
|
160
|
+
const quorumRange = `^${version}`
|
|
161
|
+
if (pkg.devDependencies["@balpal4495/quorum"] || pkg.dependencies?.["@balpal4495/quorum"]) {
|
|
162
|
+
log.skipped("package.json (@balpal4495/quorum already present)")
|
|
163
|
+
return
|
|
168
164
|
}
|
|
165
|
+
pkg.devDependencies["@balpal4495/quorum"] = quorumRange
|
|
169
166
|
await fs.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8")
|
|
170
|
-
|
|
171
|
-
log.appended(`package.json — added: ${added.join(", ")}`)
|
|
172
|
-
} else {
|
|
173
|
-
log.skipped("package.json (all deps already present)")
|
|
174
|
-
}
|
|
167
|
+
log.appended(`package.json — added @balpal4495/quorum@${quorumRange} to devDependencies`)
|
|
175
168
|
}
|
|
176
169
|
|
|
177
170
|
async function updateGitignore(target) {
|
|
178
171
|
log.section("Updating .gitignore")
|
|
179
172
|
const dest = path.join(target, ".gitignore")
|
|
180
173
|
const block = [
|
|
181
|
-
"",
|
|
174
|
+
"",
|
|
175
|
+
"# Quorum — Chronicle",
|
|
182
176
|
"# entries/ is a binary vector store — do not commit",
|
|
183
|
-
".chronicle/entries/",
|
|
177
|
+
".chronicle/entries/",
|
|
178
|
+
".chronicle/query-log.jsonl",
|
|
179
|
+
"",
|
|
184
180
|
].join("\n")
|
|
185
181
|
if (await exists(dest)) {
|
|
186
182
|
const existing = await fs.readFile(dest, "utf8")
|
|
@@ -195,7 +191,7 @@ async function updateGitignore(target) {
|
|
|
195
191
|
|
|
196
192
|
async function createChronicle(target) {
|
|
197
193
|
log.section("Creating Chronicle")
|
|
198
|
-
await fs.mkdir(path.join(target, ".chronicle", "proposals"),
|
|
194
|
+
await fs.mkdir(path.join(target, ".chronicle", "proposals"), { recursive: true })
|
|
199
195
|
log.created(".chronicle/proposals/")
|
|
200
196
|
await fs.mkdir(path.join(target, ".chronicle", "committed"), { recursive: true })
|
|
201
197
|
log.created(".chronicle/committed/")
|
|
@@ -213,30 +209,33 @@ export async function run(PKG_VERSION) {
|
|
|
213
209
|
}
|
|
214
210
|
|
|
215
211
|
await guardAlreadyInitialized(target)
|
|
216
|
-
await
|
|
217
|
-
await copyEvals(target)
|
|
212
|
+
await writeQuorumDocs(target)
|
|
218
213
|
await mergeCopilotInstructions(target)
|
|
219
214
|
await mergeAgentsMd(target)
|
|
220
215
|
await mergeClaudeMd(target)
|
|
221
216
|
await mergeGeminiMd(target)
|
|
222
|
-
await updatePackageJson(target)
|
|
217
|
+
await updatePackageJson(target, PKG_VERSION)
|
|
223
218
|
await updateGitignore(target)
|
|
224
219
|
await createChronicle(target)
|
|
220
|
+
await writeQuorumVersion(target, PKG_VERSION)
|
|
225
221
|
|
|
226
222
|
const hasGemini = geminiAvailable()
|
|
227
223
|
|
|
228
|
-
console.log(`\n${c.green("✓ Quorum initialized.")}`)
|
|
224
|
+
console.log(`\n${c.green("✓ Quorum initialized.")} ${c.dim(`(v${PKG_VERSION})`)}`)
|
|
229
225
|
console.log("\nNext steps:")
|
|
230
226
|
console.log(" 1. npm install")
|
|
231
|
-
console.log(" 2.
|
|
232
|
-
console.log(c.dim(
|
|
227
|
+
console.log(" 2. Use the CLI:")
|
|
228
|
+
console.log(c.dim(" quorum advisor brief"))
|
|
229
|
+
console.log(c.dim(' quorum advisor "what has the team decided about X?"'))
|
|
230
|
+
console.log(c.dim(" quorum check --outcome '...' --design '...'"))
|
|
231
|
+
console.log("\n For programmatic use:")
|
|
232
|
+
console.log(c.dim(' import { setup } from "@balpal4495/quorum"'))
|
|
233
233
|
console.log(c.dim(' const { oracle, evaluate, deliberate } = await setup({ llm: yourProvider })'))
|
|
234
234
|
console.log("\n Or tell your AI: \"follow quorum/SETUP.md\"")
|
|
235
235
|
|
|
236
236
|
if (!hasGemini) {
|
|
237
237
|
console.log(`\n ${c.dim("Optional: install Gemini CLI for large-context assistance")}`)
|
|
238
238
|
console.log(c.dim(" npm install -g @google/gemini-cli + set GEMINI_API_KEY"))
|
|
239
|
-
console.log(c.dim(" See quorum/SETUP.md Step 10 for details."))
|
|
240
239
|
} else {
|
|
241
240
|
console.log(`\n ${c.green("✓ Gemini CLI detected")} — GEMINI.md written. Set GEMINI_API_KEY if not already set.`)
|
|
242
241
|
}
|
package/bin/quorum.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@balpal4495/quorum",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Portable reasoning layer for agentic codebases — Oracle, Jury, Council, Sentinel",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -22,8 +22,10 @@
|
|
|
22
22
|
"bin": {
|
|
23
23
|
"quorum": "bin/quorum.js"
|
|
24
24
|
},
|
|
25
|
+
"exports": {
|
|
26
|
+
".": "./modules/setup.ts"
|
|
27
|
+
},
|
|
25
28
|
"scripts": {
|
|
26
|
-
"init": "node bin/init.js",
|
|
27
29
|
"test": "vitest run modules/ evals/",
|
|
28
30
|
"test:watch": "vitest modules/",
|
|
29
31
|
"typecheck": "tsc --noEmit"
|