@reqall/core 0.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.
- package/dist/classify.d.ts +12 -0
- package/dist/classify.d.ts.map +1 -0
- package/dist/classify.js +38 -0
- package/dist/classify.js.map +1 -0
- package/dist/config.d.ts +9 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +23 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +7 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +27 -0
- package/dist/context.js.map +1 -0
- package/dist/detect-project.d.ts +8 -0
- package/dist/detect-project.d.ts.map +1 -0
- package/dist/detect-project.js +32 -0
- package/dist/detect-project.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +47 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +19 -0
- package/src/classify.ts +45 -0
- package/src/config.ts +26 -0
- package/src/context.ts +36 -0
- package/src/detect-project.ts +34 -0
- package/src/index.ts +16 -0
- package/src/types.ts +55 -0
- package/tsconfig.json +8 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { WorkClassification } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Classification prompt injected into agent context after a task completes.
|
|
4
|
+
* The agent host uses this to decide whether and how to persist the work.
|
|
5
|
+
*/
|
|
6
|
+
export declare const CLASSIFICATION_PROMPT = "Classify the work just completed into exactly one category:\n\n| Work type | kind | status |\n|------------------------------------|---------|------------|\n| Bug fix | issue | resolved |\n| Architectural change | arch | resolved |\n| New feature request (not yet done) | todo | open |\n| Completed feature request | todo | resolved |\n| New spec or plan | spec | open |\n| Trivial / Q&A / unclassifiable | \u2014 | no action |\n\nIf the work is non-trivial, save it via reqall:upsert_record with the appropriate kind, status, and a short descriptive title.\nIf the work created or modified relationships between records, also call reqall:upsert_edge.";
|
|
7
|
+
/**
|
|
8
|
+
* Parse a classification response from the agent into a structured result.
|
|
9
|
+
* Returns null if the work should be skipped (trivial/Q&A).
|
|
10
|
+
*/
|
|
11
|
+
export declare function parseClassification(kind: string | undefined, status: string | undefined, title: string | undefined): WorkClassification | null;
|
|
12
|
+
//# sourceMappingURL=classify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classify.d.ts","sourceRoot":"","sources":["../src/classify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD;;;GAGG;AACH,eAAO,MAAM,qBAAqB,+xBAY2D,CAAC;AAE9F;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,kBAAkB,GAAG,IAAI,CAgB3B"}
|
package/dist/classify.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Classification prompt injected into agent context after a task completes.
|
|
3
|
+
* The agent host uses this to decide whether and how to persist the work.
|
|
4
|
+
*/
|
|
5
|
+
export const CLASSIFICATION_PROMPT = `Classify the work just completed into exactly one category:
|
|
6
|
+
|
|
7
|
+
| Work type | kind | status |
|
|
8
|
+
|------------------------------------|---------|------------|
|
|
9
|
+
| Bug fix | issue | resolved |
|
|
10
|
+
| Architectural change | arch | resolved |
|
|
11
|
+
| New feature request (not yet done) | todo | open |
|
|
12
|
+
| Completed feature request | todo | resolved |
|
|
13
|
+
| New spec or plan | spec | open |
|
|
14
|
+
| Trivial / Q&A / unclassifiable | — | no action |
|
|
15
|
+
|
|
16
|
+
If the work is non-trivial, save it via reqall:upsert_record with the appropriate kind, status, and a short descriptive title.
|
|
17
|
+
If the work created or modified relationships between records, also call reqall:upsert_edge.`;
|
|
18
|
+
/**
|
|
19
|
+
* Parse a classification response from the agent into a structured result.
|
|
20
|
+
* Returns null if the work should be skipped (trivial/Q&A).
|
|
21
|
+
*/
|
|
22
|
+
export function parseClassification(kind, status, title) {
|
|
23
|
+
if (!kind || kind === '—' || !title) {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
const validKinds = ['issue', 'spec', 'arch', 'test', 'todo'];
|
|
27
|
+
const validStatuses = ['open', 'resolved', 'archived', 'active', 'inactive'];
|
|
28
|
+
if (!validKinds.includes(kind))
|
|
29
|
+
return null;
|
|
30
|
+
if (status && !validStatuses.includes(status))
|
|
31
|
+
return null;
|
|
32
|
+
return {
|
|
33
|
+
kind: kind,
|
|
34
|
+
status: (status || 'open'),
|
|
35
|
+
title,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=classify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classify.js","sourceRoot":"","sources":["../src/classify.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG;;;;;;;;;;;;6FAYwD,CAAC;AAE9F;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CACjC,IAAwB,EACxB,MAA0B,EAC1B,KAAyB;IAEzB,IAAI,CAAC,IAAI,IAAI,IAAI,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QACpC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,UAAU,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAU,CAAC;IACtE,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,CAAU,CAAC;IAEtF,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAW,CAAC;QAAE,OAAO,IAAI,CAAC;IACnD,IAAI,MAAM,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,MAAa,CAAC;QAAE,OAAO,IAAI,CAAC;IAElE,OAAO;QACL,IAAI,EAAE,IAAkC;QACxC,MAAM,EAAE,CAAC,MAAM,IAAI,MAAM,CAAiC;QAC1D,KAAK;KACN,CAAC;AACJ,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ReqallConfig } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Load Reqall configuration from environment variables.
|
|
4
|
+
*
|
|
5
|
+
* Required: REQALL_API_KEY
|
|
6
|
+
* Optional: REQALL_URL, REQALL_PROJECT_NAME, REQALL_CONTEXT_LIMIT, REQALL_RECENCY_HOURS
|
|
7
|
+
*/
|
|
8
|
+
export declare function loadConfig(): ReqallConfig;
|
|
9
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAM/C;;;;;GAKG;AACH,wBAAgB,UAAU,IAAI,YAAY,CAazC"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const DEFAULT_URL = 'https://reqall.net';
|
|
2
|
+
const DEFAULT_CONTEXT_LIMIT = 5;
|
|
3
|
+
const DEFAULT_RECENCY_HOURS = 1;
|
|
4
|
+
/**
|
|
5
|
+
* Load Reqall configuration from environment variables.
|
|
6
|
+
*
|
|
7
|
+
* Required: REQALL_API_KEY
|
|
8
|
+
* Optional: REQALL_URL, REQALL_PROJECT_NAME, REQALL_CONTEXT_LIMIT, REQALL_RECENCY_HOURS
|
|
9
|
+
*/
|
|
10
|
+
export function loadConfig() {
|
|
11
|
+
const apiKey = process.env.REQALL_API_KEY;
|
|
12
|
+
if (!apiKey) {
|
|
13
|
+
throw new Error('REQALL_API_KEY environment variable is required');
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
apiKey,
|
|
17
|
+
url: process.env.REQALL_URL || DEFAULT_URL,
|
|
18
|
+
projectName: process.env.REQALL_PROJECT_NAME || undefined,
|
|
19
|
+
contextLimit: parseInt(process.env.REQALL_CONTEXT_LIMIT || '', 10) || DEFAULT_CONTEXT_LIMIT,
|
|
20
|
+
recencyHours: parseInt(process.env.REQALL_RECENCY_HOURS || '', 10) || DEFAULT_RECENCY_HOURS,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,GAAG,oBAAoB,CAAC;AACzC,MAAM,qBAAqB,GAAG,CAAC,CAAC;AAChC,MAAM,qBAAqB,GAAG,CAAC,CAAC;AAEhC;;;;;GAKG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IAC1C,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IAED,OAAO;QACL,MAAM;QACN,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,WAAW;QAC1C,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,SAAS;QACzD,YAAY,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,qBAAqB;QAC3F,YAAY,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,qBAAqB;KAC5F,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Record, SearchResult } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Format recent records and search results into context lines
|
|
4
|
+
* suitable for injection into an agent's prompt.
|
|
5
|
+
*/
|
|
6
|
+
export declare function formatContext(projectName: string, recentRecords: Record[], searchResults: SearchResult[]): string;
|
|
7
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEvD;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,EAAE,EACvB,aAAa,EAAE,YAAY,EAAE,GAC5B,MAAM,CAyBR"}
|
package/dist/context.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format recent records and search results into context lines
|
|
3
|
+
* suitable for injection into an agent's prompt.
|
|
4
|
+
*/
|
|
5
|
+
export function formatContext(projectName, recentRecords, searchResults) {
|
|
6
|
+
const lines = [];
|
|
7
|
+
lines.push(`[reqall] Project: ${projectName}`);
|
|
8
|
+
if (recentRecords.length > 0) {
|
|
9
|
+
lines.push(`[reqall] Recently updated records:`);
|
|
10
|
+
for (const r of recentRecords) {
|
|
11
|
+
lines.push(`- [${r.kind}] ${r.title} (id=${r.id}, status=${r.status}, updated: ${r.updated_at})`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
if (searchResults.length > 0) {
|
|
15
|
+
lines.push(`[reqall] Relevant context from memory:`);
|
|
16
|
+
for (const r of searchResults) {
|
|
17
|
+
const proj = r.project_name ? `project: ${r.project_name}, ` : '';
|
|
18
|
+
lines.push(`- [${r.kind}] ${r.title} (${proj}status: ${r.status}, similarity: ${r.similarity.toFixed(2)})`);
|
|
19
|
+
if (r.body) {
|
|
20
|
+
const truncated = r.body.length > 200 ? r.body.slice(0, 200) + '…' : r.body;
|
|
21
|
+
lines.push(` ${truncated}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return lines.join('\n');
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,aAAa,CAC3B,WAAmB,EACnB,aAAuB,EACvB,aAA6B;IAE7B,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,KAAK,CAAC,IAAI,CAAC,qBAAqB,WAAW,EAAE,CAAC,CAAC;IAE/C,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,KAAK,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAC;QACjD,KAAK,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,MAAM,cAAc,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC;QACpG,CAAC;IACH,CAAC;IAED,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,KAAK,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;QACrD,KAAK,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC;YAC9B,MAAM,IAAI,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;YAClE,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,KAAK,KAAK,IAAI,WAAW,CAAC,CAAC,MAAM,iBAAiB,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;YAC5G,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;gBACX,MAAM,SAAS,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;gBAC5E,KAAK,CAAC,IAAI,CAAC,KAAK,SAAS,EAAE,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect the current project name using a 3-step priority:
|
|
3
|
+
* 1. REQALL_PROJECT_NAME environment variable (explicit override)
|
|
4
|
+
* 2. Git remote — `<org>/<repo>` (e.g. `fingerskier/reqall`)
|
|
5
|
+
* 3. Current working directory basename as fallback
|
|
6
|
+
*/
|
|
7
|
+
export declare function detectProject(cwd?: string): string;
|
|
8
|
+
//# sourceMappingURL=detect-project.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect-project.d.ts","sourceRoot":"","sources":["../src/detect-project.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAwBlD"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import { basename } from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Detect the current project name using a 3-step priority:
|
|
5
|
+
* 1. REQALL_PROJECT_NAME environment variable (explicit override)
|
|
6
|
+
* 2. Git remote — `<org>/<repo>` (e.g. `fingerskier/reqall`)
|
|
7
|
+
* 3. Current working directory basename as fallback
|
|
8
|
+
*/
|
|
9
|
+
export function detectProject(cwd) {
|
|
10
|
+
// 1. Explicit env var override
|
|
11
|
+
if (process.env.REQALL_PROJECT_NAME) {
|
|
12
|
+
return process.env.REQALL_PROJECT_NAME;
|
|
13
|
+
}
|
|
14
|
+
// 2. Git remote detection
|
|
15
|
+
try {
|
|
16
|
+
const remote = execSync('git remote get-url origin', {
|
|
17
|
+
cwd: cwd || process.cwd(),
|
|
18
|
+
encoding: 'utf-8',
|
|
19
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
20
|
+
}).trim();
|
|
21
|
+
const match = remote.match(/[:/]([^/]+\/[^/]+?)(?:\.git)?$/);
|
|
22
|
+
if (match) {
|
|
23
|
+
return match[1];
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
// Not a git repo or no remote — fall through
|
|
28
|
+
}
|
|
29
|
+
// 3. cwd basename fallback
|
|
30
|
+
return basename(cwd || process.cwd());
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=detect-project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect-project.js","sourceRoot":"","sources":["../src/detect-project.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,GAAY;IACxC,+BAA+B;IAC/B,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,CAAC;QACpC,OAAO,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;IACzC,CAAC;IAED,0BAA0B;IAC1B,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,2BAA2B,EAAE;YACnD,GAAG,EAAE,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE;YACzB,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;SAChC,CAAC,CAAC,IAAI,EAAE,CAAC;QAEV,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,gCAAgC,CAAC,CAAC;QAC7D,IAAI,KAAK,EAAE,CAAC;YACV,OAAO,KAAK,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,6CAA6C;IAC/C,CAAC;IAED,2BAA2B;IAC3B,OAAO,QAAQ,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;AACxC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { loadConfig } from './config.js';
|
|
2
|
+
export { detectProject } from './detect-project.js';
|
|
3
|
+
export { parseClassification as classifyWork, CLASSIFICATION_PROMPT } from './classify.js';
|
|
4
|
+
export { formatContext } from './context.js';
|
|
5
|
+
export type { ReqallConfig, RecordKind, RecordStatus, EdgeRelationship, EntityType, Project, Record, SearchResult, Edge, WorkClassification, } from './types.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,mBAAmB,IAAI,YAAY,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC3F,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,YAAY,EACV,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,gBAAgB,EAChB,UAAU,EACV,OAAO,EACP,MAAM,EACN,YAAY,EACZ,IAAI,EACJ,kBAAkB,GACnB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { loadConfig } from './config.js';
|
|
2
|
+
export { detectProject } from './detect-project.js';
|
|
3
|
+
export { parseClassification as classifyWork, CLASSIFICATION_PROMPT } from './classify.js';
|
|
4
|
+
export { formatContext } from './context.js';
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,mBAAmB,IAAI,YAAY,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AAC3F,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/** Record kinds stored in Reqall */
|
|
2
|
+
export type RecordKind = 'issue' | 'spec' | 'arch' | 'test' | 'todo';
|
|
3
|
+
/** Record statuses */
|
|
4
|
+
export type RecordStatus = 'open' | 'resolved' | 'archived' | 'active' | 'inactive';
|
|
5
|
+
/** Edge relationship types */
|
|
6
|
+
export type EdgeRelationship = 'blocks' | 'implements' | 'tests' | 'parent' | 'related';
|
|
7
|
+
/** Entity types for edges */
|
|
8
|
+
export type EntityType = 'records' | 'projects';
|
|
9
|
+
export interface ReqallConfig {
|
|
10
|
+
apiKey: string;
|
|
11
|
+
url: string;
|
|
12
|
+
projectName?: string;
|
|
13
|
+
contextLimit: number;
|
|
14
|
+
recencyHours: number;
|
|
15
|
+
}
|
|
16
|
+
export interface Project {
|
|
17
|
+
id: number;
|
|
18
|
+
name: string;
|
|
19
|
+
}
|
|
20
|
+
export interface Record {
|
|
21
|
+
id: number;
|
|
22
|
+
project_id: number;
|
|
23
|
+
project_name?: string;
|
|
24
|
+
kind: RecordKind;
|
|
25
|
+
title: string;
|
|
26
|
+
body?: string;
|
|
27
|
+
status: RecordStatus;
|
|
28
|
+
updated_at: string;
|
|
29
|
+
}
|
|
30
|
+
export interface SearchResult extends Record {
|
|
31
|
+
similarity: number;
|
|
32
|
+
}
|
|
33
|
+
export interface Edge {
|
|
34
|
+
id: number;
|
|
35
|
+
source_id: number;
|
|
36
|
+
source_table: EntityType;
|
|
37
|
+
target_id: number;
|
|
38
|
+
target_table: EntityType;
|
|
39
|
+
relationship: EdgeRelationship;
|
|
40
|
+
updated_at: string;
|
|
41
|
+
}
|
|
42
|
+
export interface WorkClassification {
|
|
43
|
+
kind: RecordKind;
|
|
44
|
+
status: RecordStatus;
|
|
45
|
+
title: string;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,oCAAoC;AACpC,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAErE,sBAAsB;AACtB,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,UAAU,GAAG,UAAU,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEpF,8BAA8B;AAC9B,MAAM,MAAM,gBAAgB,GAAG,QAAQ,GAAG,YAAY,GAAG,OAAO,GAAG,QAAQ,GAAG,SAAS,CAAC;AAExF,6BAA6B;AAC7B,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,UAAU,CAAC;AAEhD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,YAAY,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAa,SAAQ,MAAM;IAC1C,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,UAAU,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,UAAU,CAAC;IACzB,YAAY,EAAE,gBAAgB,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,YAAY,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;CACf"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@reqall/core",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Shared plugin logic for Reqall AI agent plugins",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc",
|
|
17
|
+
"clean": "rm -rf dist"
|
|
18
|
+
}
|
|
19
|
+
}
|
package/src/classify.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { WorkClassification } from './types.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Classification prompt injected into agent context after a task completes.
|
|
5
|
+
* The agent host uses this to decide whether and how to persist the work.
|
|
6
|
+
*/
|
|
7
|
+
export const CLASSIFICATION_PROMPT = `Classify the work just completed into exactly one category:
|
|
8
|
+
|
|
9
|
+
| Work type | kind | status |
|
|
10
|
+
|------------------------------------|---------|------------|
|
|
11
|
+
| Bug fix | issue | resolved |
|
|
12
|
+
| Architectural change | arch | resolved |
|
|
13
|
+
| New feature request (not yet done) | todo | open |
|
|
14
|
+
| Completed feature request | todo | resolved |
|
|
15
|
+
| New spec or plan | spec | open |
|
|
16
|
+
| Trivial / Q&A / unclassifiable | — | no action |
|
|
17
|
+
|
|
18
|
+
If the work is non-trivial, save it via reqall:upsert_record with the appropriate kind, status, and a short descriptive title.
|
|
19
|
+
If the work created or modified relationships between records, also call reqall:upsert_edge.`;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Parse a classification response from the agent into a structured result.
|
|
23
|
+
* Returns null if the work should be skipped (trivial/Q&A).
|
|
24
|
+
*/
|
|
25
|
+
export function parseClassification(
|
|
26
|
+
kind: string | undefined,
|
|
27
|
+
status: string | undefined,
|
|
28
|
+
title: string | undefined,
|
|
29
|
+
): WorkClassification | null {
|
|
30
|
+
if (!kind || kind === '—' || !title) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const validKinds = ['issue', 'spec', 'arch', 'test', 'todo'] as const;
|
|
35
|
+
const validStatuses = ['open', 'resolved', 'archived', 'active', 'inactive'] as const;
|
|
36
|
+
|
|
37
|
+
if (!validKinds.includes(kind as any)) return null;
|
|
38
|
+
if (status && !validStatuses.includes(status as any)) return null;
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
kind: kind as WorkClassification['kind'],
|
|
42
|
+
status: (status || 'open') as WorkClassification['status'],
|
|
43
|
+
title,
|
|
44
|
+
};
|
|
45
|
+
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ReqallConfig } from './types.js';
|
|
2
|
+
|
|
3
|
+
const DEFAULT_URL = 'https://reqall.net';
|
|
4
|
+
const DEFAULT_CONTEXT_LIMIT = 5;
|
|
5
|
+
const DEFAULT_RECENCY_HOURS = 1;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Load Reqall configuration from environment variables.
|
|
9
|
+
*
|
|
10
|
+
* Required: REQALL_API_KEY
|
|
11
|
+
* Optional: REQALL_URL, REQALL_PROJECT_NAME, REQALL_CONTEXT_LIMIT, REQALL_RECENCY_HOURS
|
|
12
|
+
*/
|
|
13
|
+
export function loadConfig(): ReqallConfig {
|
|
14
|
+
const apiKey = process.env.REQALL_API_KEY;
|
|
15
|
+
if (!apiKey) {
|
|
16
|
+
throw new Error('REQALL_API_KEY environment variable is required');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
apiKey,
|
|
21
|
+
url: process.env.REQALL_URL || DEFAULT_URL,
|
|
22
|
+
projectName: process.env.REQALL_PROJECT_NAME || undefined,
|
|
23
|
+
contextLimit: parseInt(process.env.REQALL_CONTEXT_LIMIT || '', 10) || DEFAULT_CONTEXT_LIMIT,
|
|
24
|
+
recencyHours: parseInt(process.env.REQALL_RECENCY_HOURS || '', 10) || DEFAULT_RECENCY_HOURS,
|
|
25
|
+
};
|
|
26
|
+
}
|
package/src/context.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Record, SearchResult } from './types.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Format recent records and search results into context lines
|
|
5
|
+
* suitable for injection into an agent's prompt.
|
|
6
|
+
*/
|
|
7
|
+
export function formatContext(
|
|
8
|
+
projectName: string,
|
|
9
|
+
recentRecords: Record[],
|
|
10
|
+
searchResults: SearchResult[],
|
|
11
|
+
): string {
|
|
12
|
+
const lines: string[] = [];
|
|
13
|
+
|
|
14
|
+
lines.push(`[reqall] Project: ${projectName}`);
|
|
15
|
+
|
|
16
|
+
if (recentRecords.length > 0) {
|
|
17
|
+
lines.push(`[reqall] Recently updated records:`);
|
|
18
|
+
for (const r of recentRecords) {
|
|
19
|
+
lines.push(`- [${r.kind}] ${r.title} (id=${r.id}, status=${r.status}, updated: ${r.updated_at})`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (searchResults.length > 0) {
|
|
24
|
+
lines.push(`[reqall] Relevant context from memory:`);
|
|
25
|
+
for (const r of searchResults) {
|
|
26
|
+
const proj = r.project_name ? `project: ${r.project_name}, ` : '';
|
|
27
|
+
lines.push(`- [${r.kind}] ${r.title} (${proj}status: ${r.status}, similarity: ${r.similarity.toFixed(2)})`);
|
|
28
|
+
if (r.body) {
|
|
29
|
+
const truncated = r.body.length > 200 ? r.body.slice(0, 200) + '…' : r.body;
|
|
30
|
+
lines.push(` ${truncated}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return lines.join('\n');
|
|
36
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import { basename } from 'node:path';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Detect the current project name using a 3-step priority:
|
|
6
|
+
* 1. REQALL_PROJECT_NAME environment variable (explicit override)
|
|
7
|
+
* 2. Git remote — `<org>/<repo>` (e.g. `fingerskier/reqall`)
|
|
8
|
+
* 3. Current working directory basename as fallback
|
|
9
|
+
*/
|
|
10
|
+
export function detectProject(cwd?: string): string {
|
|
11
|
+
// 1. Explicit env var override
|
|
12
|
+
if (process.env.REQALL_PROJECT_NAME) {
|
|
13
|
+
return process.env.REQALL_PROJECT_NAME;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// 2. Git remote detection
|
|
17
|
+
try {
|
|
18
|
+
const remote = execSync('git remote get-url origin', {
|
|
19
|
+
cwd: cwd || process.cwd(),
|
|
20
|
+
encoding: 'utf-8',
|
|
21
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
22
|
+
}).trim();
|
|
23
|
+
|
|
24
|
+
const match = remote.match(/[:/]([^/]+\/[^/]+?)(?:\.git)?$/);
|
|
25
|
+
if (match) {
|
|
26
|
+
return match[1];
|
|
27
|
+
}
|
|
28
|
+
} catch {
|
|
29
|
+
// Not a git repo or no remote — fall through
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// 3. cwd basename fallback
|
|
33
|
+
return basename(cwd || process.cwd());
|
|
34
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export { loadConfig } from './config.js';
|
|
2
|
+
export { detectProject } from './detect-project.js';
|
|
3
|
+
export { parseClassification as classifyWork, CLASSIFICATION_PROMPT } from './classify.js';
|
|
4
|
+
export { formatContext } from './context.js';
|
|
5
|
+
export type {
|
|
6
|
+
ReqallConfig,
|
|
7
|
+
RecordKind,
|
|
8
|
+
RecordStatus,
|
|
9
|
+
EdgeRelationship,
|
|
10
|
+
EntityType,
|
|
11
|
+
Project,
|
|
12
|
+
Record,
|
|
13
|
+
SearchResult,
|
|
14
|
+
Edge,
|
|
15
|
+
WorkClassification,
|
|
16
|
+
} from './types.js';
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** Record kinds stored in Reqall */
|
|
2
|
+
export type RecordKind = 'issue' | 'spec' | 'arch' | 'test' | 'todo';
|
|
3
|
+
|
|
4
|
+
/** Record statuses */
|
|
5
|
+
export type RecordStatus = 'open' | 'resolved' | 'archived' | 'active' | 'inactive';
|
|
6
|
+
|
|
7
|
+
/** Edge relationship types */
|
|
8
|
+
export type EdgeRelationship = 'blocks' | 'implements' | 'tests' | 'parent' | 'related';
|
|
9
|
+
|
|
10
|
+
/** Entity types for edges */
|
|
11
|
+
export type EntityType = 'records' | 'projects';
|
|
12
|
+
|
|
13
|
+
export interface ReqallConfig {
|
|
14
|
+
apiKey: string;
|
|
15
|
+
url: string;
|
|
16
|
+
projectName?: string;
|
|
17
|
+
contextLimit: number;
|
|
18
|
+
recencyHours: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface Project {
|
|
22
|
+
id: number;
|
|
23
|
+
name: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface Record {
|
|
27
|
+
id: number;
|
|
28
|
+
project_id: number;
|
|
29
|
+
project_name?: string;
|
|
30
|
+
kind: RecordKind;
|
|
31
|
+
title: string;
|
|
32
|
+
body?: string;
|
|
33
|
+
status: RecordStatus;
|
|
34
|
+
updated_at: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface SearchResult extends Record {
|
|
38
|
+
similarity: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface Edge {
|
|
42
|
+
id: number;
|
|
43
|
+
source_id: number;
|
|
44
|
+
source_table: EntityType;
|
|
45
|
+
target_id: number;
|
|
46
|
+
target_table: EntityType;
|
|
47
|
+
relationship: EdgeRelationship;
|
|
48
|
+
updated_at: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface WorkClassification {
|
|
52
|
+
kind: RecordKind;
|
|
53
|
+
status: RecordStatus;
|
|
54
|
+
title: string;
|
|
55
|
+
}
|