@fluxyr/quill-core 0.1.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/dist/config.d.ts +24 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +98 -0
- package/dist/config.js.map +1 -0
- package/dist/conventions.d.ts +4 -0
- package/dist/conventions.d.ts.map +1 -0
- package/dist/conventions.js +51 -0
- package/dist/conventions.js.map +1 -0
- package/dist/engine/codemap.d.ts +3 -0
- package/dist/engine/codemap.d.ts.map +1 -0
- package/dist/engine/codemap.js +113 -0
- package/dist/engine/codemap.js.map +1 -0
- package/dist/engine/fileops.d.ts +18 -0
- package/dist/engine/fileops.d.ts.map +1 -0
- package/dist/engine/fileops.js +194 -0
- package/dist/engine/fileops.js.map +1 -0
- package/dist/engine/generate.d.ts +39 -0
- package/dist/engine/generate.d.ts.map +1 -0
- package/dist/engine/generate.js +126 -0
- package/dist/engine/generate.js.map +1 -0
- package/dist/engine/openrouter.d.ts +36 -0
- package/dist/engine/openrouter.d.ts.map +1 -0
- package/dist/engine/openrouter.js +108 -0
- package/dist/engine/openrouter.js.map +1 -0
- package/dist/engine/repair.d.ts +22 -0
- package/dist/engine/repair.d.ts.map +1 -0
- package/dist/engine/repair.js +37 -0
- package/dist/engine/repair.js.map +1 -0
- package/dist/engine/session.d.ts +26 -0
- package/dist/engine/session.d.ts.map +1 -0
- package/dist/engine/session.js +66 -0
- package/dist/engine/session.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +73 -0
- package/dist/index.js.map +1 -0
- package/dist/ledger/hash.d.ts +8 -0
- package/dist/ledger/hash.d.ts.map +1 -0
- package/dist/ledger/hash.js +95 -0
- package/dist/ledger/hash.js.map +1 -0
- package/dist/ledger/lockfile.d.ts +16 -0
- package/dist/ledger/lockfile.d.ts.map +1 -0
- package/dist/ledger/lockfile.js +101 -0
- package/dist/ledger/lockfile.js.map +1 -0
- package/dist/ledger/snapshot.d.ts +5 -0
- package/dist/ledger/snapshot.d.ts.map +1 -0
- package/dist/ledger/snapshot.js +61 -0
- package/dist/ledger/snapshot.js.map +1 -0
- package/dist/prompt/parse.d.ts +21 -0
- package/dist/prompt/parse.d.ts.map +1 -0
- package/dist/prompt/parse.js +95 -0
- package/dist/prompt/parse.js.map +1 -0
- package/dist/stack/helpers.d.ts +9 -0
- package/dist/stack/helpers.d.ts.map +1 -0
- package/dist/stack/helpers.js +84 -0
- package/dist/stack/helpers.js.map +1 -0
- package/dist/stack/registry.d.ts +10 -0
- package/dist/stack/registry.d.ts.map +1 -0
- package/dist/stack/registry.js +21 -0
- package/dist/stack/registry.js.map +1 -0
- package/dist/types.d.ts +126 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/package.json +39 -0
- package/prompts/000-uuid.md +27 -0
- package/prompts/010-base-model.md +27 -0
- package/prompts/020-routes.md +23 -0
- package/prompts/030-auth.md +16 -0
- package/prompts/040-errors.md +25 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for the Quill engine.
|
|
3
|
+
*
|
|
4
|
+
* Quill treats a web app as an ordered stack of micro-prompts (the durable
|
|
5
|
+
* asset) plus a resolved state (the lockfile). Code is a derived artifact,
|
|
6
|
+
* generated/evolved by opencode and verified by a stack adapter.
|
|
7
|
+
*/
|
|
8
|
+
export type PromptKind = "core" | "feature";
|
|
9
|
+
/** A single micro-prompt: natural-language spec + metadata. */
|
|
10
|
+
export interface PromptDoc {
|
|
11
|
+
/** Stable id, e.g. "0002-add-projects". */
|
|
12
|
+
id: string;
|
|
13
|
+
kind: PromptKind;
|
|
14
|
+
/** Ids this prompt depends on (informational; ordering is by `order`). */
|
|
15
|
+
dependsOn: string[];
|
|
16
|
+
/** Numeric prefix used to order feature prompts like migrations. */
|
|
17
|
+
order: number;
|
|
18
|
+
/** The natural-language specification. */
|
|
19
|
+
body: string;
|
|
20
|
+
/** Absolute path to the source markdown, when read from disk. */
|
|
21
|
+
filePath?: string;
|
|
22
|
+
}
|
|
23
|
+
/** A non-generated file copied verbatim into the generated app on init. */
|
|
24
|
+
export interface FileTemplate {
|
|
25
|
+
/** Path relative to the generated app root. */
|
|
26
|
+
path: string;
|
|
27
|
+
content: string;
|
|
28
|
+
}
|
|
29
|
+
/** Result of a stack adapter's verify() — feeds the repair loop. */
|
|
30
|
+
export interface VerifyResult {
|
|
31
|
+
ok: boolean;
|
|
32
|
+
/** One-line summary for logs. */
|
|
33
|
+
summary: string;
|
|
34
|
+
/** Detailed feedback (compiler/test output) fed back to opencode on failure. */
|
|
35
|
+
feedback: string;
|
|
36
|
+
}
|
|
37
|
+
/** Context handed to a stack adapter when composing the system prompt. */
|
|
38
|
+
export interface StackContext {
|
|
39
|
+
corePrompts: PromptDoc[];
|
|
40
|
+
/** Absolute path to the generated app root. */
|
|
41
|
+
generatedDir: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* A stack adapter encodes one target technology (e.g. Python/Flask). It does NOT
|
|
45
|
+
* own the core conventions (those are shared, in @fluxyr/quill-core); it contributes the
|
|
46
|
+
* framework binding (via buildSystemPrompt), the verbatim scaffold, and verify().
|
|
47
|
+
*/
|
|
48
|
+
export interface StackAdapter {
|
|
49
|
+
name: string;
|
|
50
|
+
/** Files copied verbatim into the generated app (load-bearing, byte-stable). */
|
|
51
|
+
scaffoldTemplates(): FileTemplate[];
|
|
52
|
+
/**
|
|
53
|
+
* Compose the system prompt: the shared core conventions (ctx.corePrompts,
|
|
54
|
+
* passed in by the engine) followed by this stack's framework binding.
|
|
55
|
+
*/
|
|
56
|
+
buildSystemPrompt(ctx: StackContext): string;
|
|
57
|
+
/** Compile/lint/test the generated app; returns feedback for the repair loop. */
|
|
58
|
+
verify(generatedDir: string): Promise<VerifyResult>;
|
|
59
|
+
}
|
|
60
|
+
/** LLM generation settings. Quill calls the provider's API directly. */
|
|
61
|
+
export interface LlmConfig {
|
|
62
|
+
/** Provider whose API we call. OpenRouter exposes every model behind one key. */
|
|
63
|
+
provider: "openrouter";
|
|
64
|
+
/** API base URL (default https://openrouter.ai/api/v1). */
|
|
65
|
+
baseUrl?: string;
|
|
66
|
+
/** Max repair passes after the initial generation (default 2). */
|
|
67
|
+
maxRepairPasses: number;
|
|
68
|
+
/** Sampling temperature (default 0 for reproducibility). */
|
|
69
|
+
temperature: number;
|
|
70
|
+
/** Run one self-review pass before verification (the article's doctrine). */
|
|
71
|
+
selfReview: boolean;
|
|
72
|
+
}
|
|
73
|
+
/** Project configuration persisted as quill.config.json. */
|
|
74
|
+
export interface QuillConfig {
|
|
75
|
+
/** Stack adapter name, e.g. "flask". */
|
|
76
|
+
stack: string;
|
|
77
|
+
/** Model slug as "provider/model" (OpenRouter), e.g. "minimax/minimax-m3". */
|
|
78
|
+
model: string;
|
|
79
|
+
paths: {
|
|
80
|
+
/** Prompts root, relative to project. */
|
|
81
|
+
prompts: string;
|
|
82
|
+
/** Generated app root, relative to project. */
|
|
83
|
+
generated: string;
|
|
84
|
+
};
|
|
85
|
+
llm: LlmConfig;
|
|
86
|
+
}
|
|
87
|
+
/** One applied feature prompt in the ledger. */
|
|
88
|
+
export interface AppliedEntry {
|
|
89
|
+
id: string;
|
|
90
|
+
promptHash: string;
|
|
91
|
+
codeHash: string;
|
|
92
|
+
model: string;
|
|
93
|
+
repairPasses: number;
|
|
94
|
+
appliedAt: string;
|
|
95
|
+
}
|
|
96
|
+
/** A named checkpoint: snapshot + reproducibility verdict. */
|
|
97
|
+
export interface CheckpointEntry {
|
|
98
|
+
name: string;
|
|
99
|
+
/** Last applied prompt id at checkpoint time (the "head"). */
|
|
100
|
+
head: string | null;
|
|
101
|
+
/** Snapshot dir relative to project, under .quill/checkpoints/. */
|
|
102
|
+
snapshotDir: string;
|
|
103
|
+
codeHash: string;
|
|
104
|
+
verified: boolean;
|
|
105
|
+
verifiedAt: string;
|
|
106
|
+
}
|
|
107
|
+
/** The resolved state: quill.lock.json. */
|
|
108
|
+
export interface Lockfile {
|
|
109
|
+
version: number;
|
|
110
|
+
stack: string;
|
|
111
|
+
model: string;
|
|
112
|
+
applied: AppliedEntry[];
|
|
113
|
+
checkpoints: CheckpointEntry[];
|
|
114
|
+
}
|
|
115
|
+
/** A chat message in the generation conversation. */
|
|
116
|
+
export interface ChatMessage {
|
|
117
|
+
role: "system" | "user" | "assistant";
|
|
118
|
+
content: string;
|
|
119
|
+
}
|
|
120
|
+
/** One file operation emitted by the model. */
|
|
121
|
+
export interface FileOp {
|
|
122
|
+
path: string;
|
|
123
|
+
action: "write" | "delete";
|
|
124
|
+
content?: string;
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Shared types for the Quill engine.
|
|
4
|
+
*
|
|
5
|
+
* Quill treats a web app as an ordered stack of micro-prompts (the durable
|
|
6
|
+
* asset) plus a resolved state (the lockfile). Code is a derived artifact,
|
|
7
|
+
* generated/evolved by opencode and verified by a stack adapter.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fluxyr/quill-core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Quill engine: shared conventions, micro-prompt ledger, OpenRouter engine, repair loop.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"prompts"
|
|
10
|
+
],
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"gray-matter": "^4.0.3"
|
|
13
|
+
},
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"author": "Fluxyr",
|
|
16
|
+
"homepage": "https://github.com/fluxyr-app/quill#readme",
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/fluxyr-app/quill/issues"
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/fluxyr-app/quill.git",
|
|
23
|
+
"directory": "packages/core"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"quill",
|
|
27
|
+
"code-generation",
|
|
28
|
+
"llm",
|
|
29
|
+
"micro-prompts",
|
|
30
|
+
"openrouter",
|
|
31
|
+
"scaffolding"
|
|
32
|
+
],
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=20"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: 000-uuid
|
|
3
|
+
kind: core
|
|
4
|
+
depends_on: []
|
|
5
|
+
---
|
|
6
|
+
# Identifiers — short IDs
|
|
7
|
+
|
|
8
|
+
Every resource is identified by a **UUID**. Internally — storage, foreign keys,
|
|
9
|
+
comparisons — the full UUID is used. Externally — everywhere an id crosses the
|
|
10
|
+
boundary to a client (URL paths, request bodies, response payloads) — the id is
|
|
11
|
+
represented as a compact **short ID**.
|
|
12
|
+
|
|
13
|
+
Short ID semantics:
|
|
14
|
+
- The short ID is a **Base-62** encoding of the 128-bit UUID using the alphabet
|
|
15
|
+
`0-9`, then `A-Z`, then `a-z` (digit value 0 = `0`, … 61 = `z`),
|
|
16
|
+
most-significant digit first, left-padded to a fixed length of **22 characters**.
|
|
17
|
+
- Encoding and decoding are exact inverses: any UUID → short ID → UUID returns the
|
|
18
|
+
original UUID. Decoding also accepts an already-full UUID and normalizes it.
|
|
19
|
+
- Resolving an inbound id accepts either form (short ID or full UUID) and yields the
|
|
20
|
+
UUID, or nothing when the input is not a valid identifier.
|
|
21
|
+
|
|
22
|
+
Rules:
|
|
23
|
+
- Ids are never hand-formatted when producing output: serializing a resource emits
|
|
24
|
+
its short ID automatically.
|
|
25
|
+
- Inbound ids (path parameters, and body fields that reference other resources) are
|
|
26
|
+
resolved to UUIDs before use.
|
|
27
|
+
- A foreign key holds the referenced resource's UUID id.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: 010-base-model
|
|
3
|
+
kind: core
|
|
4
|
+
depends_on: [000-uuid]
|
|
5
|
+
---
|
|
6
|
+
# Resources
|
|
7
|
+
|
|
8
|
+
The application is organized as a set of **resources** (entities). Every resource:
|
|
9
|
+
|
|
10
|
+
- Has a unique **id** that is a UUID (represented externally as a short ID — see
|
|
11
|
+
Identifiers).
|
|
12
|
+
- Records **created** and **updated** timestamps, maintained automatically.
|
|
13
|
+
- Is **persistable**: it can be created, fetched by id, listed, updated, and deleted.
|
|
14
|
+
- Has a canonical **serialized form** (its fields as data) used when returned to a
|
|
15
|
+
client; ids in that form are short IDs.
|
|
16
|
+
|
|
17
|
+
Modeling rules:
|
|
18
|
+
|
|
19
|
+
- Each resource is defined once, in its own unit named after the resource.
|
|
20
|
+
- Fields have explicit types and nullability; required fields are enforced.
|
|
21
|
+
- A resource may reference another by holding that resource's id as a **foreign key**;
|
|
22
|
+
state the delete behavior (cascade when the reference is an owned child, restrict
|
|
23
|
+
otherwise).
|
|
24
|
+
- Uniqueness rules (single-field or composite) are declared on the resource.
|
|
25
|
+
|
|
26
|
+
The shared behavior (id, timestamps, persistence, serialization) comes from a common
|
|
27
|
+
base — extend it, do not reimplement it per resource.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: 020-routes
|
|
3
|
+
kind: core
|
|
4
|
+
depends_on: [010-base-model]
|
|
5
|
+
---
|
|
6
|
+
# Endpoints
|
|
7
|
+
|
|
8
|
+
Resources are exposed over HTTP as account-scoped REST endpoints. For a resource
|
|
9
|
+
`things`, under the base path `/accounts/{account_id}/things`:
|
|
10
|
+
|
|
11
|
+
- **list** — read the collection.
|
|
12
|
+
- **create** — add to the collection; validate required fields first.
|
|
13
|
+
- **get** — read one by id.
|
|
14
|
+
- **update** — modify one by id (when the feature calls for it).
|
|
15
|
+
- **delete** — remove one by id (when the feature calls for it).
|
|
16
|
+
|
|
17
|
+
Conventions:
|
|
18
|
+
|
|
19
|
+
- Ids in paths are short IDs (see Identifiers) and are resolved to UUIDs before use.
|
|
20
|
+
- Return a resource's serialized form; return collections as arrays.
|
|
21
|
+
- Status codes: 200 for reads and updates, 201 for creates, 200/204 for deletes.
|
|
22
|
+
- Endpoints are grouped per resource and wired into the application automatically —
|
|
23
|
+
do not edit central bootstrap/registration to add them.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: 030-auth
|
|
3
|
+
kind: core
|
|
4
|
+
depends_on: [020-routes]
|
|
5
|
+
---
|
|
6
|
+
# Authorization & multi-tenancy
|
|
7
|
+
|
|
8
|
+
The application is multi-tenant: resources belong to an **account**, and endpoints
|
|
9
|
+
are scoped by account in the path (`/accounts/{account_id}/...`).
|
|
10
|
+
|
|
11
|
+
- Every resource-accessing endpoint is **guarded** by an authentication check.
|
|
12
|
+
- The auth mechanism may be a stub initially, but the guard must be present on all
|
|
13
|
+
protected endpoints, so that enabling real authentication later is a single,
|
|
14
|
+
localized change.
|
|
15
|
+
- Ownership is modeled by storing the owning account's (or user's) id as a foreign
|
|
16
|
+
key; scope queries by it wherever a feature requires ownership.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: 040-errors
|
|
3
|
+
kind: core
|
|
4
|
+
depends_on: [020-routes]
|
|
5
|
+
---
|
|
6
|
+
# Errors, tests & house rules
|
|
7
|
+
|
|
8
|
+
Errors:
|
|
9
|
+
|
|
10
|
+
- Failures return a consistent, structured error payload (a message, optionally a code).
|
|
11
|
+
- Use 400 for invalid input, 404 for a missing resource, 409 for conflicts (e.g. a
|
|
12
|
+
uniqueness violation).
|
|
13
|
+
|
|
14
|
+
Tests:
|
|
15
|
+
|
|
16
|
+
- Every feature ships automated tests covering at least create + read for its
|
|
17
|
+
resource, and asserting that ids returned to clients are short IDs (22 characters).
|
|
18
|
+
|
|
19
|
+
House rules:
|
|
20
|
+
|
|
21
|
+
- Keep changes minimal and localized to the feature at hand.
|
|
22
|
+
- Do not modify shared infrastructure that is provided: the base resource behavior,
|
|
23
|
+
the application bootstrap/registration, or the test harness.
|
|
24
|
+
- Add no external dependencies beyond the project's stack unless a feature requires it.
|
|
25
|
+
- The application must run with zero external services in its default configuration.
|