@compilr-dev/sdk 0.10.41 → 0.12.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/entitlements/fetch.d.ts +16 -0
- package/dist/entitlements/fetch.js +32 -0
- package/dist/entitlements/index.d.ts +1 -0
- package/dist/entitlements/index.js +1 -0
- package/dist/host/auth-api.d.ts +49 -0
- package/dist/host/auth-api.js +201 -0
- package/dist/host/auth-store.d.ts +36 -0
- package/dist/host/auth-store.js +105 -0
- package/dist/host/auth-types.d.ts +105 -0
- package/dist/host/auth-types.js +11 -0
- package/dist/host/device-flow.d.ts +44 -0
- package/dist/host/device-flow.js +111 -0
- package/dist/host/index.d.ts +13 -0
- package/dist/host/index.js +10 -0
- package/dist/host/settings-schema.d.ts +148 -0
- package/dist/host/settings-schema.js +107 -0
- package/dist/host/token.d.ts +34 -0
- package/dist/host/token.js +56 -0
- package/dist/index.d.ts +8 -4
- package/dist/index.js +9 -3
- package/dist/permissions.d.ts +8 -0
- package/dist/permissions.js +19 -0
- package/dist/platform/file-artifact-service.d.ts +55 -0
- package/dist/platform/file-artifact-service.js +140 -0
- package/dist/platform/index.d.ts +2 -0
- package/dist/platform/index.js +2 -0
- package/dist/skills/software-skills.js +26 -20
- package/package.json +1 -1
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FileArtifactService — file-backed IArtifactService shared by CLI and Desktop.
|
|
3
|
+
*
|
|
4
|
+
* Both hosts previously hand-rolled identical artifact CRUD on top of the SDK's
|
|
5
|
+
* ArtifactStore, reading/writing the SAME file:
|
|
6
|
+
* {sessionsDir}/{global | project-<id>}/artifacts/artifacts.json
|
|
7
|
+
* This consolidates that logic next to FileEpisodeStore / ProjectAnchorStore.
|
|
8
|
+
*
|
|
9
|
+
* Each operation does a fresh load → mutate → save (the file is the source of
|
|
10
|
+
* truth, shared per-project across terminals), matching the prior behavior.
|
|
11
|
+
*
|
|
12
|
+
* Hosts wire in:
|
|
13
|
+
* - getProjectId: resolved per call, so the service follows project switches
|
|
14
|
+
* - onSaved (optional): fired after a create/update persists — the CLI uses it
|
|
15
|
+
* to record team activity; Desktop omits it
|
|
16
|
+
* - onError (optional): load/save failures, so each host logs as it sees fit
|
|
17
|
+
*/
|
|
18
|
+
import type { IArtifactService, ArtifactData, ArtifactSummaryData, ArtifactType } from './services.js';
|
|
19
|
+
export interface FileArtifactServiceConfig {
|
|
20
|
+
/** Sessions root, e.g. ~/.compilr-dev/sessions */
|
|
21
|
+
sessionsDir: string;
|
|
22
|
+
/** Active project id (null = global), resolved on every call. */
|
|
23
|
+
getProjectId: () => number | null;
|
|
24
|
+
/** Fired after a successful create/update persists. */
|
|
25
|
+
onSaved?: (artifact: ArtifactData, isUpdate: boolean) => void;
|
|
26
|
+
/** Fired on a load/save failure (host decides how to log). */
|
|
27
|
+
onError?: (err: unknown, op: 'load' | 'save') => void;
|
|
28
|
+
}
|
|
29
|
+
export declare class FileArtifactService implements IArtifactService {
|
|
30
|
+
private readonly config;
|
|
31
|
+
constructor(config: FileArtifactServiceConfig);
|
|
32
|
+
private artifactsDir;
|
|
33
|
+
private dataFile;
|
|
34
|
+
/** Load the artifact store for a project from disk (empty store if absent). */
|
|
35
|
+
private loadStore;
|
|
36
|
+
/** Persist the artifact store for a project to disk. */
|
|
37
|
+
private saveStore;
|
|
38
|
+
save(input: {
|
|
39
|
+
name: string;
|
|
40
|
+
type: ArtifactType;
|
|
41
|
+
content: string;
|
|
42
|
+
summary?: string;
|
|
43
|
+
agent?: string;
|
|
44
|
+
}): Promise<{
|
|
45
|
+
artifact: ArtifactData;
|
|
46
|
+
isUpdate: boolean;
|
|
47
|
+
}>;
|
|
48
|
+
getByName(name: string): Promise<ArtifactData | null>;
|
|
49
|
+
list(options?: {
|
|
50
|
+
type?: ArtifactType;
|
|
51
|
+
agent?: string;
|
|
52
|
+
search?: string;
|
|
53
|
+
}): Promise<ArtifactSummaryData[]>;
|
|
54
|
+
delete(name: string): Promise<ArtifactData | null>;
|
|
55
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FileArtifactService — file-backed IArtifactService shared by CLI and Desktop.
|
|
3
|
+
*
|
|
4
|
+
* Both hosts previously hand-rolled identical artifact CRUD on top of the SDK's
|
|
5
|
+
* ArtifactStore, reading/writing the SAME file:
|
|
6
|
+
* {sessionsDir}/{global | project-<id>}/artifacts/artifacts.json
|
|
7
|
+
* This consolidates that logic next to FileEpisodeStore / ProjectAnchorStore.
|
|
8
|
+
*
|
|
9
|
+
* Each operation does a fresh load → mutate → save (the file is the source of
|
|
10
|
+
* truth, shared per-project across terminals), matching the prior behavior.
|
|
11
|
+
*
|
|
12
|
+
* Hosts wire in:
|
|
13
|
+
* - getProjectId: resolved per call, so the service follows project switches
|
|
14
|
+
* - onSaved (optional): fired after a create/update persists — the CLI uses it
|
|
15
|
+
* to record team activity; Desktop omits it
|
|
16
|
+
* - onError (optional): load/save failures, so each host logs as it sees fit
|
|
17
|
+
*/
|
|
18
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
19
|
+
import { join } from 'path';
|
|
20
|
+
import { ArtifactStore } from '../team/artifacts.js';
|
|
21
|
+
function toArtifactData(a) {
|
|
22
|
+
return {
|
|
23
|
+
id: a.id,
|
|
24
|
+
name: a.name,
|
|
25
|
+
agent: a.agent,
|
|
26
|
+
type: a.type,
|
|
27
|
+
content: a.content,
|
|
28
|
+
summary: a.summary,
|
|
29
|
+
version: a.version,
|
|
30
|
+
createdAt: a.createdAt,
|
|
31
|
+
updatedAt: a.updatedAt,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export class FileArtifactService {
|
|
35
|
+
config;
|
|
36
|
+
constructor(config) {
|
|
37
|
+
this.config = config;
|
|
38
|
+
}
|
|
39
|
+
artifactsDir(projectId) {
|
|
40
|
+
const projectDir = projectId === null
|
|
41
|
+
? join(this.config.sessionsDir, 'global')
|
|
42
|
+
: join(this.config.sessionsDir, `project-${String(projectId)}`);
|
|
43
|
+
return join(projectDir, 'artifacts');
|
|
44
|
+
}
|
|
45
|
+
dataFile(projectId) {
|
|
46
|
+
return join(this.artifactsDir(projectId), 'artifacts.json');
|
|
47
|
+
}
|
|
48
|
+
/** Load the artifact store for a project from disk (empty store if absent). */
|
|
49
|
+
loadStore(projectId) {
|
|
50
|
+
const store = new ArtifactStore();
|
|
51
|
+
const file = this.dataFile(projectId);
|
|
52
|
+
if (!existsSync(file))
|
|
53
|
+
return store;
|
|
54
|
+
try {
|
|
55
|
+
const data = JSON.parse(readFileSync(file, 'utf-8'));
|
|
56
|
+
store.restore(data);
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
// Corrupt/unreadable — start fresh rather than crash the tool call.
|
|
60
|
+
this.config.onError?.(err, 'load');
|
|
61
|
+
}
|
|
62
|
+
return store;
|
|
63
|
+
}
|
|
64
|
+
/** Persist the artifact store for a project to disk. */
|
|
65
|
+
saveStore(projectId, store) {
|
|
66
|
+
const dir = this.artifactsDir(projectId);
|
|
67
|
+
if (!existsSync(dir))
|
|
68
|
+
mkdirSync(dir, { recursive: true });
|
|
69
|
+
try {
|
|
70
|
+
writeFileSync(this.dataFile(projectId), JSON.stringify(store.serialize(), null, 2), 'utf-8');
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
this.config.onError?.(err, 'save');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
save(input) {
|
|
77
|
+
const projectId = this.config.getProjectId();
|
|
78
|
+
const store = this.loadStore(projectId);
|
|
79
|
+
const agentId = input.agent ?? 'default';
|
|
80
|
+
const existing = store.getByName(input.name);
|
|
81
|
+
if (existing) {
|
|
82
|
+
const updated = store.update(existing.id, {
|
|
83
|
+
content: input.content,
|
|
84
|
+
summary: input.summary,
|
|
85
|
+
type: input.type,
|
|
86
|
+
});
|
|
87
|
+
if (!updated)
|
|
88
|
+
throw new Error(`Failed to update artifact "${input.name}"`);
|
|
89
|
+
this.saveStore(projectId, store);
|
|
90
|
+
const artifact = toArtifactData(updated);
|
|
91
|
+
this.config.onSaved?.(artifact, true);
|
|
92
|
+
return Promise.resolve({ artifact, isUpdate: true });
|
|
93
|
+
}
|
|
94
|
+
const created = store.create({
|
|
95
|
+
name: input.name,
|
|
96
|
+
agent: agentId,
|
|
97
|
+
type: input.type,
|
|
98
|
+
content: input.content,
|
|
99
|
+
summary: input.summary,
|
|
100
|
+
});
|
|
101
|
+
this.saveStore(projectId, store);
|
|
102
|
+
const artifact = toArtifactData(created);
|
|
103
|
+
this.config.onSaved?.(artifact, false);
|
|
104
|
+
return Promise.resolve({ artifact, isUpdate: false });
|
|
105
|
+
}
|
|
106
|
+
getByName(name) {
|
|
107
|
+
const store = this.loadStore(this.config.getProjectId());
|
|
108
|
+
const a = store.getByName(name);
|
|
109
|
+
return Promise.resolve(a ? toArtifactData(a) : null);
|
|
110
|
+
}
|
|
111
|
+
list(options) {
|
|
112
|
+
const store = this.loadStore(this.config.getProjectId());
|
|
113
|
+
let items = options?.search ? store.search(options.search) : store.list();
|
|
114
|
+
if (options?.type)
|
|
115
|
+
items = items.filter((a) => a.type === options.type);
|
|
116
|
+
if (options?.agent)
|
|
117
|
+
items = items.filter((a) => a.agent === options.agent);
|
|
118
|
+
const summaries = items.map((a) => ({
|
|
119
|
+
id: a.id,
|
|
120
|
+
name: a.name,
|
|
121
|
+
agent: a.agent,
|
|
122
|
+
type: a.type,
|
|
123
|
+
summary: a.summary,
|
|
124
|
+
version: a.version,
|
|
125
|
+
updatedAt: a.updatedAt,
|
|
126
|
+
}));
|
|
127
|
+
return Promise.resolve(summaries);
|
|
128
|
+
}
|
|
129
|
+
delete(name) {
|
|
130
|
+
const projectId = this.config.getProjectId();
|
|
131
|
+
const store = this.loadStore(projectId);
|
|
132
|
+
const a = store.getByName(name);
|
|
133
|
+
if (!a)
|
|
134
|
+
return Promise.resolve(null);
|
|
135
|
+
if (!store.delete(a.id))
|
|
136
|
+
return Promise.resolve(null);
|
|
137
|
+
this.saveStore(projectId, store);
|
|
138
|
+
return Promise.resolve(toArtifactData(a));
|
|
139
|
+
}
|
|
140
|
+
}
|
package/dist/platform/index.d.ts
CHANGED
|
@@ -11,5 +11,7 @@ export { createSQLiteRepositories, SQLiteProjectRepository, SQLiteWorkItemReposi
|
|
|
11
11
|
export type { SQLiteRepositories, CreateSQLiteRepositoriesOptions, ProjectDeleteHooks, ProjectRecord, WorkItemRecord, ProjectDocumentRecord, WorkItemCommentRecord, } from './sqlite/index.js';
|
|
12
12
|
export { ProjectAnchorStore } from './file-anchor-service.js';
|
|
13
13
|
export type { ProjectAnchorStoreConfig } from './file-anchor-service.js';
|
|
14
|
+
export { FileArtifactService } from './file-artifact-service.js';
|
|
15
|
+
export type { FileArtifactServiceConfig } from './file-artifact-service.js';
|
|
14
16
|
export { STEP_ORDER, GUIDED_STEP_CRITERIA, getNextStep, isValidTransition, getStepCriteria, formatStepDisplay, getStepNumber, } from './workflow.js';
|
|
15
17
|
export type { StepCriteria } from './workflow.js';
|
package/dist/platform/index.js
CHANGED
|
@@ -7,5 +7,7 @@ export { createPlatformTools, createProjectTools, createWorkItemTools, createDoc
|
|
|
7
7
|
export { createSQLiteRepositories, SQLiteProjectRepository, SQLiteWorkItemRepository, SQLiteDocumentRepository, SQLitePlanRepository, SQLiteCommentRepository, getDatabase, closeDatabase, closeAllDatabases, databaseExists, SCHEMA_VERSION, SCHEMA_SQL, } from './sqlite/index.js';
|
|
8
8
|
// File-based anchor service (shared by CLI and Desktop)
|
|
9
9
|
export { ProjectAnchorStore } from './file-anchor-service.js';
|
|
10
|
+
// File-based artifact service (shared by CLI and Desktop)
|
|
11
|
+
export { FileArtifactService } from './file-artifact-service.js';
|
|
10
12
|
// Workflow (pure step-criteria logic)
|
|
11
13
|
export { STEP_ORDER, GUIDED_STEP_CRITERIA, getNextStep, isValidTransition, getStepCriteria, formatStepDisplay, getStepNumber, } from './workflow.js';
|
|
@@ -60,10 +60,14 @@ When you have enough information:
|
|
|
60
60
|
- Nice-to-haves (type: feature, priority: medium/low)
|
|
61
61
|
- Technical setup tasks (type: chore, priority: high)
|
|
62
62
|
- Known risks/unknowns (type: tech-debt, priority: medium)
|
|
63
|
-
4.
|
|
64
|
-
-
|
|
63
|
+
4. Save the PRD to the project DATABASE (never a file):
|
|
64
|
+
- Check for an existing PRD first: project_document_get({ doc_type: "prd" })
|
|
65
|
+
- If none exists, create it:
|
|
66
|
+
project_document_add({ doc_type: "prd", title: "Product Requirements Document", content: "<full markdown>" })
|
|
67
|
+
- If one exists, update it section by section:
|
|
68
|
+
project_document_patch({ doc_type: "prd", operation: "replace_section", section_heading: "## <heading>", content: "..." })
|
|
65
69
|
- Fill in: Problem Statement, Goals, User Stories, Functional Requirements
|
|
66
|
-
-
|
|
70
|
+
- CRITICAL: project documents live in the database. NEVER use write_file / edit / bash mkdir to create a PRD.md file on disk.
|
|
67
71
|
5. Present the backlog and PRD summary to user for confirmation
|
|
68
72
|
- If CHORE-001 was added, mention: "Run /scaffold to create the project foundation"
|
|
69
73
|
6. If the project involves managing entities (CRUD operations on things like users, orders, products):
|
|
@@ -83,7 +87,7 @@ When you have enough information:
|
|
|
83
87
|
✓ MVP features are defined
|
|
84
88
|
✓ Backlog has 5-15 items
|
|
85
89
|
✓ For fresh projects: CHORE-001 scaffolding item is first (critical priority)
|
|
86
|
-
✓ PRD
|
|
90
|
+
✓ PRD saved to the database (doc_type: prd) — not written to a file
|
|
87
91
|
✓ If entity-based: user informed about /scaffold auto-generation
|
|
88
92
|
✓ User has approved the backlog`,
|
|
89
93
|
tags: ['planning', 'requirements'],
|
|
@@ -440,11 +444,12 @@ export const prdSkill = defineSkill({
|
|
|
440
444
|
- "Read current PRD"
|
|
441
445
|
- "Identify section to update"
|
|
442
446
|
- "Gather updates"
|
|
443
|
-
- "
|
|
447
|
+
- "Save updated PRD"
|
|
444
448
|
|
|
445
|
-
2. Read the existing PRD
|
|
446
|
-
-
|
|
447
|
-
- If no
|
|
449
|
+
2. Read the existing PRD from the project DATABASE:
|
|
450
|
+
- Use project_document_get({ doc_type: "prd" })
|
|
451
|
+
- If it returns no document, inform the user to run /design first
|
|
452
|
+
- The PRD is a database document, NOT a file — never read PRD.md from disk
|
|
448
453
|
|
|
449
454
|
3. Present current PRD sections to user using ask_user_simple:
|
|
450
455
|
- Question: "Which section would you like to update?"
|
|
@@ -482,21 +487,23 @@ Based on section selected:
|
|
|
482
487
|
- What to add/change
|
|
483
488
|
- What to remove
|
|
484
489
|
- Any clarifications
|
|
485
|
-
3.
|
|
490
|
+
3. Save the change to the database with project_document_patch:
|
|
491
|
+
- project_document_patch({ doc_type: "prd", operation: "replace_section", section_heading: "## <heading>", content: "..." })
|
|
492
|
+
- Use operation "append" / "prepend" to add new content without replacing
|
|
486
493
|
4. Show the updated section for confirmation
|
|
487
494
|
|
|
488
495
|
## RULES
|
|
489
496
|
|
|
490
|
-
1. ALWAYS read the existing PRD first
|
|
497
|
+
1. ALWAYS read the existing PRD first (project_document_get)
|
|
491
498
|
2. Use ask_user_simple for section selection
|
|
492
499
|
3. Use ask_user for gathering detailed updates
|
|
493
|
-
4. Preserve sections you're not updating
|
|
494
|
-
5.
|
|
500
|
+
4. Preserve sections you're not updating (patch one section at a time)
|
|
501
|
+
5. CRITICAL: the PRD lives in the database. Save with project_document_patch / project_document_add — NEVER write_file / edit / a PRD.md file on disk
|
|
495
502
|
6. Keep formatting consistent with existing document
|
|
496
503
|
7. If scope changes affect backlog, suggest running /refine
|
|
497
504
|
|
|
498
505
|
## COMPLETION CRITERIA
|
|
499
|
-
✓ PRD
|
|
506
|
+
✓ PRD is updated in the database (doc_type: prd)
|
|
500
507
|
✓ User has reviewed the updates
|
|
501
508
|
✓ Related backlog updates are suggested if needed`,
|
|
502
509
|
tags: ['planning', 'requirements'],
|
|
@@ -532,7 +539,7 @@ export const sessionNotesSkill = defineSkill({
|
|
|
532
539
|
|
|
533
540
|
## SESSION NOTE STRUCTURE
|
|
534
541
|
|
|
535
|
-
|
|
542
|
+
Compose a markdown note with this structure (it will be saved to the database, not a file):
|
|
536
543
|
|
|
537
544
|
\`\`\`markdown
|
|
538
545
|
# Session Note - {{title}}
|
|
@@ -573,13 +580,12 @@ Create a markdown file with this structure:
|
|
|
573
580
|
*Generated by /note*
|
|
574
581
|
\`\`\`
|
|
575
582
|
|
|
576
|
-
##
|
|
583
|
+
## WHERE TO SAVE
|
|
577
584
|
|
|
578
|
-
Save the note to:
|
|
579
|
-
|
|
580
|
-
- Two repo: \`{{project}}-docs/04-session-notes/{{YYYY-MM-DD}}-{{slug}}.md\`
|
|
585
|
+
Save the note to the project DATABASE with:
|
|
586
|
+
project_document_add({ doc_type: "notes", title: "Session Note — {{title}}", content: "<full markdown>" })
|
|
581
587
|
|
|
582
|
-
|
|
588
|
+
CRITICAL: session notes are database documents. NEVER write a .md file (no write_file / edit / bash mkdir, no .compilr/sessions/ or {{project}}-docs/ paths).
|
|
583
589
|
|
|
584
590
|
## RULES
|
|
585
591
|
|
|
@@ -591,7 +597,7 @@ Create the directory if it doesn't exist.
|
|
|
591
597
|
6. If user provides a title, use it; otherwise generate one from the summary
|
|
592
598
|
|
|
593
599
|
## COMPLETION CRITERIA
|
|
594
|
-
✓ Session note
|
|
600
|
+
✓ Session note saved to the database (doc_type: notes)
|
|
595
601
|
✓ All sections are filled in
|
|
596
602
|
✓ User has reviewed the note`,
|
|
597
603
|
tags: ['documentation', 'session'],
|