@kognai/build 0.6.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 +91 -0
- package/dist/bin/kognai-build.js +774 -0
- package/dist/bin/kognai.js +323 -0
- package/dist/lib/boot-env.js +30 -0
- package/dist/lib/cost-estimator.js +54 -0
- package/dist/lib/knowledge.js +256 -0
- package/dist/lib/mandate.js +360 -0
- package/dist/lib/memory.js +243 -0
- package/dist/lib/registry-overrides.js +40 -0
- package/dist/lib/router.js +119 -0
- package/dist/lib/skill-bank-stub.js +214 -0
- package/dist/lib/skill-bank.js +248 -0
- package/dist/lib/swarm-coder-prompt.js +39 -0
- package/dist/lib/swarm.js +89 -0
- package/dist/lib/tool-layer-stub.js +214 -0
- package/dist/lib/tool-layer.js +249 -0
- package/dist/lib/workspace.js +221 -0
- package/dist/templates/index.js +184 -0
- package/dist/templates/registry.js +82 -0
- package/package.json +45 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* workspace.ts — TICKET-203 Phase 1
|
|
4
|
+
*
|
|
5
|
+
* .kognai/ per-project convention: config + knowledge/ + memory/{user,kognai}/.
|
|
6
|
+
*
|
|
7
|
+
* Discovery:
|
|
8
|
+
* 1. Walk up from startDir looking for <dir>/.kognai/config.yaml
|
|
9
|
+
* 2. Fall back to ~/.kognai/config.yaml
|
|
10
|
+
* 3. Return null if neither exists
|
|
11
|
+
*
|
|
12
|
+
* Config format: minimal YAML subset (scalars, flat lists, flat nested objects).
|
|
13
|
+
* No external deps — Node 18+ built-ins only.
|
|
14
|
+
*
|
|
15
|
+
* Consumed by:
|
|
16
|
+
* - knowledge.ts (workspace.knowledge_refs → which docs to read before decompose)
|
|
17
|
+
* - memory.ts (workspace.memory_user_dir / memory_kognai_dir → context + summary writes)
|
|
18
|
+
* - mandate.ts (workspace field on signed mandate → autonomy envelope)
|
|
19
|
+
*/
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.DEFAULT_CONFIG = void 0;
|
|
22
|
+
exports.discoverWorkspace = discoverWorkspace;
|
|
23
|
+
exports.readWorkspace = readWorkspace;
|
|
24
|
+
const fs_1 = require("fs");
|
|
25
|
+
const path_1 = require("path");
|
|
26
|
+
const os_1 = require("os");
|
|
27
|
+
exports.DEFAULT_CONFIG = {
|
|
28
|
+
version: 1,
|
|
29
|
+
deliverable_root: './src',
|
|
30
|
+
knowledge_refs: ['./knowledge'],
|
|
31
|
+
memory: {
|
|
32
|
+
user_dir: './memory/user',
|
|
33
|
+
kognai_dir: './memory/kognai',
|
|
34
|
+
append_session_summary: true,
|
|
35
|
+
},
|
|
36
|
+
defaults: {
|
|
37
|
+
profile: 'maintainability',
|
|
38
|
+
task_target: 'cloud-code',
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
function discoverWorkspace(startDir = process.cwd()) {
|
|
42
|
+
// 1. Walk up from startDir looking for .kognai/config.yaml
|
|
43
|
+
let dir = (0, path_1.resolve)(startDir);
|
|
44
|
+
while (true) {
|
|
45
|
+
const candidate = (0, path_1.join)(dir, '.kognai');
|
|
46
|
+
if (hasConfig(candidate)) {
|
|
47
|
+
return readWorkspace(candidate);
|
|
48
|
+
}
|
|
49
|
+
const parent = (0, path_1.dirname)(dir);
|
|
50
|
+
if (parent === dir)
|
|
51
|
+
break; // hit filesystem root
|
|
52
|
+
dir = parent;
|
|
53
|
+
}
|
|
54
|
+
// 2. Home-level fallback: ~/.kognai/config.yaml
|
|
55
|
+
const homeKognai = (0, path_1.join)((0, os_1.homedir)(), '.kognai');
|
|
56
|
+
if (hasConfig(homeKognai)) {
|
|
57
|
+
return readWorkspace(homeKognai);
|
|
58
|
+
}
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
function readWorkspace(kognaiDir) {
|
|
62
|
+
const configPath = pickConfigPath(kognaiDir);
|
|
63
|
+
if (!configPath) {
|
|
64
|
+
throw new Error(`No config file found at ${kognaiDir} (expected config.yaml, config.yml, or config.json)`);
|
|
65
|
+
}
|
|
66
|
+
const raw = (0, fs_1.readFileSync)(configPath, 'utf-8');
|
|
67
|
+
const config = configPath.endsWith('.json')
|
|
68
|
+
? JSON.parse(raw)
|
|
69
|
+
: parseMinimalYaml(raw);
|
|
70
|
+
validateConfig(config, configPath);
|
|
71
|
+
const root = (0, path_1.dirname)(kognaiDir);
|
|
72
|
+
const resolveRel = (p, base) => (0, path_1.isAbsolute)(p) ? p : (0, path_1.resolve)(base, p);
|
|
73
|
+
return {
|
|
74
|
+
root,
|
|
75
|
+
kognai_dir: kognaiDir,
|
|
76
|
+
config,
|
|
77
|
+
deliverable_root: resolveRel(config.deliverable_root, root),
|
|
78
|
+
// knowledge/ lives INSIDE .kognai/ per TICKET-203 layout (alongside memory/),
|
|
79
|
+
// so knowledge_refs resolve against kognaiDir — NOT root. The default
|
|
80
|
+
// './knowledge' must reach .kognai/knowledge, and '../shared-docs/x.md'
|
|
81
|
+
// still resolves correctly relative to .kognai/. (Bug fix: was `root`,
|
|
82
|
+
// which silently looked in <project>/knowledge and never loaded anything.)
|
|
83
|
+
knowledge_refs: config.knowledge_refs.map(p => resolveRel(p, kognaiDir)),
|
|
84
|
+
memory_user_dir: resolveRel(config.memory.user_dir, kognaiDir),
|
|
85
|
+
memory_kognai_dir: resolveRel(config.memory.kognai_dir, kognaiDir),
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
// ─── Internals ──────────────────────────────────────────────────────────────
|
|
89
|
+
function hasConfig(kognaiDir) {
|
|
90
|
+
return pickConfigPath(kognaiDir) !== null;
|
|
91
|
+
}
|
|
92
|
+
function pickConfigPath(kognaiDir) {
|
|
93
|
+
for (const name of ['config.yaml', 'config.yml', 'config.json']) {
|
|
94
|
+
const p = (0, path_1.join)(kognaiDir, name);
|
|
95
|
+
if ((0, fs_1.existsSync)(p) && (0, fs_1.statSync)(p).isFile())
|
|
96
|
+
return p;
|
|
97
|
+
}
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
function validateConfig(c, path) {
|
|
101
|
+
if (typeof c.version !== 'number')
|
|
102
|
+
throw new Error(`${path}: 'version' must be a number`);
|
|
103
|
+
if (typeof c.deliverable_root !== 'string')
|
|
104
|
+
throw new Error(`${path}: 'deliverable_root' must be a string`);
|
|
105
|
+
if (!Array.isArray(c.knowledge_refs))
|
|
106
|
+
throw new Error(`${path}: 'knowledge_refs' must be an array`);
|
|
107
|
+
if (!c.memory || typeof c.memory.user_dir !== 'string' || typeof c.memory.kognai_dir !== 'string') {
|
|
108
|
+
throw new Error(`${path}: 'memory.user_dir' and 'memory.kognai_dir' are required`);
|
|
109
|
+
}
|
|
110
|
+
if (typeof c.memory.append_session_summary !== 'boolean') {
|
|
111
|
+
throw new Error(`${path}: 'memory.append_session_summary' must be a boolean`);
|
|
112
|
+
}
|
|
113
|
+
if (!c.defaults || typeof c.defaults !== 'object')
|
|
114
|
+
throw new Error(`${path}: 'defaults' must be an object`);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Minimal YAML parser for the .kognai/config.yaml subset.
|
|
118
|
+
*
|
|
119
|
+
* Supports:
|
|
120
|
+
* - Scalars: strings (quoted or bare), numbers, booleans (true/false), null
|
|
121
|
+
* - Comments (# to end of line; preserves # inside quoted strings)
|
|
122
|
+
* - Top-level keys with scalar / array / object values
|
|
123
|
+
* - One level of nesting (memory: { user_dir, kognai_dir, append_session_summary })
|
|
124
|
+
* - Block-style arrays of scalars (- item)
|
|
125
|
+
*
|
|
126
|
+
* Does NOT support: anchors/aliases, multiline strings, flow style, arrays of objects.
|
|
127
|
+
* That's enough for the config schema. Add deps later if richer needs emerge.
|
|
128
|
+
*/
|
|
129
|
+
function parseMinimalYaml(text) {
|
|
130
|
+
const result = {};
|
|
131
|
+
const lines = text.split(/\r?\n/);
|
|
132
|
+
let currentKey = null; // top-level key whose value is an array or object
|
|
133
|
+
let currentMode = null;
|
|
134
|
+
let currentIndent = -1;
|
|
135
|
+
for (let i = 0; i < lines.length; i++) {
|
|
136
|
+
const raw = lines[i];
|
|
137
|
+
const line = stripComment(raw);
|
|
138
|
+
if (!line.trim())
|
|
139
|
+
continue;
|
|
140
|
+
const indent = line.match(/^(\s*)/)[1].length;
|
|
141
|
+
const trimmed = line.trim();
|
|
142
|
+
// Top-level scalar/list/object opener at indent 0
|
|
143
|
+
if (indent === 0) {
|
|
144
|
+
const m = trimmed.match(/^([A-Za-z_][\w-]*)\s*:\s*(.*)$/);
|
|
145
|
+
if (!m)
|
|
146
|
+
throw new Error(`Malformed YAML at line ${i + 1}: ${raw}`);
|
|
147
|
+
const [, key, rest] = m;
|
|
148
|
+
if (rest === '') {
|
|
149
|
+
// Could be array (next non-empty line starts with '-') or object (indented k:v)
|
|
150
|
+
currentKey = key;
|
|
151
|
+
currentMode = null; // decide on first child line
|
|
152
|
+
currentIndent = -1;
|
|
153
|
+
result[key] = null; // placeholder
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
result[key] = parseScalar(rest);
|
|
157
|
+
currentKey = null;
|
|
158
|
+
currentMode = null;
|
|
159
|
+
}
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
// Inside an open block — first child decides array vs object
|
|
163
|
+
if (currentKey === null) {
|
|
164
|
+
throw new Error(`Unexpected indented line ${i + 1}: ${raw}`);
|
|
165
|
+
}
|
|
166
|
+
if (currentMode === null) {
|
|
167
|
+
currentMode = trimmed.startsWith('- ') ? 'array' : 'object';
|
|
168
|
+
currentIndent = indent;
|
|
169
|
+
result[currentKey] = currentMode === 'array' ? [] : {};
|
|
170
|
+
}
|
|
171
|
+
if (indent !== currentIndent) {
|
|
172
|
+
throw new Error(`Inconsistent indentation at line ${i + 1}: expected ${currentIndent}, got ${indent}`);
|
|
173
|
+
}
|
|
174
|
+
if (currentMode === 'array') {
|
|
175
|
+
const m = trimmed.match(/^-\s*(.*)$/);
|
|
176
|
+
if (!m)
|
|
177
|
+
throw new Error(`Expected list item at line ${i + 1}: ${raw}`);
|
|
178
|
+
result[currentKey].push(parseScalar(m[1]));
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
const m = trimmed.match(/^([A-Za-z_][\w-]*)\s*:\s*(.*)$/);
|
|
182
|
+
if (!m)
|
|
183
|
+
throw new Error(`Expected key:value at line ${i + 1}: ${raw}`);
|
|
184
|
+
const [, k, v] = m;
|
|
185
|
+
result[currentKey][k] = parseScalar(v);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return result;
|
|
189
|
+
}
|
|
190
|
+
function stripComment(line) {
|
|
191
|
+
// Preserve # inside double or single quotes
|
|
192
|
+
let inDouble = false, inSingle = false;
|
|
193
|
+
for (let i = 0; i < line.length; i++) {
|
|
194
|
+
const c = line[i];
|
|
195
|
+
if (c === '"' && !inSingle)
|
|
196
|
+
inDouble = !inDouble;
|
|
197
|
+
else if (c === "'" && !inDouble)
|
|
198
|
+
inSingle = !inSingle;
|
|
199
|
+
else if (c === '#' && !inDouble && !inSingle)
|
|
200
|
+
return line.slice(0, i).trimEnd();
|
|
201
|
+
}
|
|
202
|
+
return line;
|
|
203
|
+
}
|
|
204
|
+
function parseScalar(s) {
|
|
205
|
+
const t = s.trim();
|
|
206
|
+
if (t === '' || t === '~' || t === 'null')
|
|
207
|
+
return null;
|
|
208
|
+
if (t === 'true')
|
|
209
|
+
return true;
|
|
210
|
+
if (t === 'false')
|
|
211
|
+
return false;
|
|
212
|
+
if (/^-?\d+$/.test(t))
|
|
213
|
+
return parseInt(t, 10);
|
|
214
|
+
if (/^-?\d+\.\d+$/.test(t))
|
|
215
|
+
return parseFloat(t);
|
|
216
|
+
// Strip matched quotes
|
|
217
|
+
if ((t.startsWith('"') && t.endsWith('"')) || (t.startsWith("'") && t.endsWith("'"))) {
|
|
218
|
+
return t.slice(1, -1);
|
|
219
|
+
}
|
|
220
|
+
return t;
|
|
221
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Template Registry
|
|
4
|
+
*
|
|
5
|
+
* Hardcoded starter templates for the Kognai build system.
|
|
6
|
+
* Each template encodes intent matching keywords, default quality profile,
|
|
7
|
+
* agent composition, workflow shape, and required skills/tools.
|
|
8
|
+
*
|
|
9
|
+
* Source: TICKET-140 (template registry seed data)
|
|
10
|
+
* Profile axes per TICKET-135: security, reliability, performance,
|
|
11
|
+
* maintainability, compatibility, usability, portability, compliance,
|
|
12
|
+
* cost-efficiency, time-to-market, sovereignty, quality (composite).
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.STARTER_TEMPLATES = void 0;
|
|
16
|
+
exports.STARTER_TEMPLATES = [
|
|
17
|
+
{
|
|
18
|
+
id: 'research-synthesis-default',
|
|
19
|
+
name: 'Research Synthesis (Default)',
|
|
20
|
+
intent: ['literature review', 'research', 'synthesis', 'paper', 'citation'],
|
|
21
|
+
default_profile: {
|
|
22
|
+
primary: 'quality',
|
|
23
|
+
secondary: ['maintainability'],
|
|
24
|
+
},
|
|
25
|
+
composition: {
|
|
26
|
+
roles: [
|
|
27
|
+
{ role: 'researcher', count: 2 },
|
|
28
|
+
{ role: 'synthesizer', count: 1 },
|
|
29
|
+
{ role: 'reviewer', count: 1 },
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
workflow: 'gather sources → extract claims → cross-reference citations → synthesize narrative → peer-review for accuracy → ship if approved',
|
|
33
|
+
skills: ['citation-validation', 'source-credibility', 'claim-extraction'],
|
|
34
|
+
tools: ['web-search', 'pdf-reader', 'citation-manager'],
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
id: 'content-creation-default',
|
|
38
|
+
name: 'Content Creation (Default)',
|
|
39
|
+
intent: ['blog', 'post', 'article', 'content', 'copy'],
|
|
40
|
+
default_profile: {
|
|
41
|
+
primary: 'time-to-market',
|
|
42
|
+
secondary: ['quality'],
|
|
43
|
+
},
|
|
44
|
+
composition: {
|
|
45
|
+
roles: [
|
|
46
|
+
{ role: 'writer', count: 1 },
|
|
47
|
+
{ role: 'editor', count: 1 },
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
workflow: 'outline → draft → self-edit → editorial review → polish → ship',
|
|
51
|
+
skills: ['copywriting', 'tone-matching', 'seo-basics'],
|
|
52
|
+
tools: ['markdown-editor', 'grammar-checker', 'readability-scorer'],
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
id: 'webapp-standard-default',
|
|
56
|
+
name: 'Web App Standard (Default)',
|
|
57
|
+
intent: ['web app', 'dashboard', 'crud', 'frontend', 'react'],
|
|
58
|
+
default_profile: {
|
|
59
|
+
primary: 'time-to-market',
|
|
60
|
+
secondary: ['maintainability'],
|
|
61
|
+
},
|
|
62
|
+
composition: {
|
|
63
|
+
roles: [
|
|
64
|
+
{ role: 'coder', count: 2 },
|
|
65
|
+
{ role: 'reviewer', count: 1 },
|
|
66
|
+
],
|
|
67
|
+
},
|
|
68
|
+
workflow: 'decompose → atomic single-file tasks → implement components → review → integrate → ship',
|
|
69
|
+
skills: ['react-patterns', 'state-management', 'api-integration'],
|
|
70
|
+
tools: ['vite', 'typescript-checker', 'eslint'],
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
id: 'defi-security-first',
|
|
74
|
+
name: 'DeFi Security First',
|
|
75
|
+
intent: ['defi', 'smart contract', 'solidity', 'on-chain', 'financial primitive'],
|
|
76
|
+
default_profile: {
|
|
77
|
+
primary: 'security',
|
|
78
|
+
secondary: ['reliability', 'compliance'],
|
|
79
|
+
},
|
|
80
|
+
composition: {
|
|
81
|
+
roles: [
|
|
82
|
+
{ role: 'coder', count: 1 },
|
|
83
|
+
{ role: 'security-reviewer', count: 2 },
|
|
84
|
+
{ role: 'auditor', count: 1 },
|
|
85
|
+
],
|
|
86
|
+
},
|
|
87
|
+
workflow: 'threat-model → implement with invariants → dual-review with adversarial lens → static analysis → fuzz testing → ship only if all reviewers approve',
|
|
88
|
+
skills: ['invariant-analysis', 'reentrancy-detection', 'gas-optimization'],
|
|
89
|
+
tools: ['slither', 'foundry', 'echidna-fuzzer'],
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
id: 'healthcare-compliance-first',
|
|
93
|
+
name: 'Healthcare Compliance First',
|
|
94
|
+
intent: ['healthcare', 'medical', 'hipaa', 'patient', 'regulated'],
|
|
95
|
+
default_profile: {
|
|
96
|
+
primary: 'compliance',
|
|
97
|
+
secondary: ['security', 'maintainability'],
|
|
98
|
+
},
|
|
99
|
+
composition: {
|
|
100
|
+
roles: [
|
|
101
|
+
{ role: 'coder', count: 1 },
|
|
102
|
+
{ role: 'compliance-reviewer', count: 1 },
|
|
103
|
+
{ role: 'security-reviewer', count: 1 },
|
|
104
|
+
],
|
|
105
|
+
},
|
|
106
|
+
workflow: 'decompose → atomic single-file tasks → dual-review with compliance lens → audit-log every PHI touchpoint → ship if approved',
|
|
107
|
+
skills: ['schema-validation', 'audit-logging', 'phi-redaction'],
|
|
108
|
+
tools: ['postgres-encrypted', 'hipaa-bcc-checker', 'audit-trail-emitter'],
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
id: 'internal-tooling-default',
|
|
112
|
+
name: 'Internal Tooling (Default)',
|
|
113
|
+
intent: ['internal', 'tooling', 'script', 'cli', 'devtool'],
|
|
114
|
+
default_profile: {
|
|
115
|
+
primary: 'cost-efficiency',
|
|
116
|
+
secondary: ['maintainability'],
|
|
117
|
+
},
|
|
118
|
+
composition: {
|
|
119
|
+
roles: [
|
|
120
|
+
{ role: 'coder', count: 1 },
|
|
121
|
+
{ role: 'reviewer', count: 1 },
|
|
122
|
+
],
|
|
123
|
+
},
|
|
124
|
+
workflow: 'lightweight spec → implement → smoke test → ship to internal users',
|
|
125
|
+
skills: ['cli-design', 'argument-parsing', 'shell-scripting'],
|
|
126
|
+
tools: ['commander', 'bash', 'node-runtime'],
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
id: 'data-pipeline-reliability',
|
|
130
|
+
name: 'Data Pipeline Reliability',
|
|
131
|
+
intent: ['data pipeline', 'etl', 'ingestion', 'transform'],
|
|
132
|
+
default_profile: {
|
|
133
|
+
primary: 'reliability',
|
|
134
|
+
secondary: ['performance', 'maintainability'],
|
|
135
|
+
},
|
|
136
|
+
composition: {
|
|
137
|
+
roles: [
|
|
138
|
+
{ role: 'coder', count: 1 },
|
|
139
|
+
{ role: 'data-reviewer', count: 1 },
|
|
140
|
+
{ role: 'sre', count: 1 },
|
|
141
|
+
],
|
|
142
|
+
},
|
|
143
|
+
workflow: 'schema-first design → implement with retries + idempotency → backfill test → review for failure modes → ship with monitoring',
|
|
144
|
+
skills: ['schema-validation', 'idempotency-design', 'backpressure-handling'],
|
|
145
|
+
tools: ['airflow', 'dbt', 'great-expectations'],
|
|
146
|
+
},
|
|
147
|
+
{
|
|
148
|
+
id: 'realtime-performance-first',
|
|
149
|
+
name: 'Realtime Performance First',
|
|
150
|
+
intent: ['realtime', 'latency', 'websocket', 'streaming', 'low-latency'],
|
|
151
|
+
default_profile: {
|
|
152
|
+
primary: 'performance',
|
|
153
|
+
secondary: ['reliability'],
|
|
154
|
+
},
|
|
155
|
+
composition: {
|
|
156
|
+
roles: [
|
|
157
|
+
{ role: 'coder', count: 1 },
|
|
158
|
+
{ role: 'performance-reviewer', count: 1 },
|
|
159
|
+
],
|
|
160
|
+
},
|
|
161
|
+
workflow: 'benchmark baseline → implement hot path → profile → optimize → load-test → ship if p99 budget met',
|
|
162
|
+
skills: ['profiling', 'concurrency-patterns', 'memory-management'],
|
|
163
|
+
tools: ['k6', 'clinic-js', 'websocket-bench'],
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
id: 'video-production-default',
|
|
167
|
+
name: 'Video Production (Default)',
|
|
168
|
+
intent: ['video', 'pipeline', 'scorsese', 'render', 'hyperframes'],
|
|
169
|
+
default_profile: {
|
|
170
|
+
primary: 'quality',
|
|
171
|
+
secondary: ['time-to-market'],
|
|
172
|
+
},
|
|
173
|
+
composition: {
|
|
174
|
+
roles: [
|
|
175
|
+
{ role: 'director', count: 1 },
|
|
176
|
+
{ role: 'coder', count: 1 },
|
|
177
|
+
{ role: 'reviewer', count: 1 },
|
|
178
|
+
],
|
|
179
|
+
},
|
|
180
|
+
workflow: 'storyboard → scene composition → render preview → review → final render → ship',
|
|
181
|
+
skills: ['composition-design', 'timing-coordination', 'audio-sync'],
|
|
182
|
+
tools: ['hyperframes', 'ffmpeg', 'scorsese-renderer'],
|
|
183
|
+
},
|
|
184
|
+
];
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.selectTemplates = selectTemplates;
|
|
4
|
+
exports.getTemplateById = getTemplateById;
|
|
5
|
+
const index_1 = require("./index");
|
|
6
|
+
function countIntentMatches(intentKeywords, userGoal) {
|
|
7
|
+
const normalizedGoal = userGoal.toLowerCase();
|
|
8
|
+
const matched = [];
|
|
9
|
+
for (const keyword of intentKeywords) {
|
|
10
|
+
if (typeof keyword !== 'string' || keyword.length === 0) {
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
if (normalizedGoal.includes(keyword.toLowerCase())) {
|
|
14
|
+
matched.push(keyword);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return { matched, count: matched.length };
|
|
18
|
+
}
|
|
19
|
+
function selectTemplates(userGoal, profileOverride, topN = 3) {
|
|
20
|
+
if (typeof userGoal !== 'string') {
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
const limit = Number.isFinite(topN) && topN > 0 ? Math.floor(topN) : 3;
|
|
24
|
+
const candidates = [];
|
|
25
|
+
for (const template of index_1.STARTER_TEMPLATES) {
|
|
26
|
+
if (profileOverride !== undefined &&
|
|
27
|
+
profileOverride !== null &&
|
|
28
|
+
template.default_profile.primary !== profileOverride) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
const intentKeywords = template.intent ?? [];
|
|
32
|
+
const totalKeywords = intentKeywords.length;
|
|
33
|
+
if (totalKeywords === 0) {
|
|
34
|
+
candidates.push({
|
|
35
|
+
template,
|
|
36
|
+
score: 0,
|
|
37
|
+
matchedKeywords: [],
|
|
38
|
+
intentLength: 0,
|
|
39
|
+
});
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const { matched, count } = countIntentMatches(intentKeywords, userGoal);
|
|
43
|
+
const score = count / totalKeywords;
|
|
44
|
+
candidates.push({
|
|
45
|
+
template,
|
|
46
|
+
score,
|
|
47
|
+
matchedKeywords: matched,
|
|
48
|
+
intentLength: totalKeywords,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
candidates.sort((a, b) => {
|
|
52
|
+
if (b.score !== a.score) {
|
|
53
|
+
return b.score - a.score;
|
|
54
|
+
}
|
|
55
|
+
if (a.intentLength !== b.intentLength) {
|
|
56
|
+
return a.intentLength - b.intentLength;
|
|
57
|
+
}
|
|
58
|
+
return a.template.id.localeCompare(b.template.id);
|
|
59
|
+
});
|
|
60
|
+
const top = candidates.slice(0, limit);
|
|
61
|
+
return top.map((candidate) => {
|
|
62
|
+
const profileLabel = profileOverride !== undefined && profileOverride !== null
|
|
63
|
+
? profileOverride
|
|
64
|
+
: candidate.template.default_profile.primary;
|
|
65
|
+
const keywordList = candidate.matchedKeywords.length > 0
|
|
66
|
+
? candidate.matchedKeywords.join(', ')
|
|
67
|
+
: 'none';
|
|
68
|
+
const reason = `matched keywords: [${keywordList}]; profile: [${profileLabel}]`;
|
|
69
|
+
return {
|
|
70
|
+
template: candidate.template,
|
|
71
|
+
score: candidate.score,
|
|
72
|
+
reason,
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
function getTemplateById(id) {
|
|
77
|
+
if (typeof id !== 'string' || id.length === 0) {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
const found = index_1.STARTER_TEMPLATES.find((template) => template.id === id);
|
|
81
|
+
return found ?? null;
|
|
82
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kognai/build",
|
|
3
|
+
"version": "0.6.0",
|
|
4
|
+
"description": "Kognai sovereign orchestrator — interactive REPL (kognai) + one-shot CLI (kognai-build). Triple-supervisor + compliance review + TICKET-135 optimization profiles + TICKET-203/207 workspace integration.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "SkinGem",
|
|
7
|
+
"bin": {
|
|
8
|
+
"kognai": "./dist/bin/kognai.js",
|
|
9
|
+
"kognai-build": "./dist/bin/kognai-build.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist/",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc -p tsconfig.json && rm -f dist/tsconfig.tsbuildinfo && chmod +x dist/bin/kognai.js dist/bin/kognai-build.js",
|
|
17
|
+
"prepublishOnly": "npm run build"
|
|
18
|
+
},
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=18"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"kognai",
|
|
24
|
+
"agent",
|
|
25
|
+
"orchestrator",
|
|
26
|
+
"ai",
|
|
27
|
+
"claude",
|
|
28
|
+
"compliance",
|
|
29
|
+
"code-generation",
|
|
30
|
+
"sovereign"
|
|
31
|
+
],
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@anthropic-ai/sdk": "^0.65.0",
|
|
34
|
+
"@kognai/orchestrator-core": "^0.1.3"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/node": "^22.0.0",
|
|
38
|
+
"typescript": "^5.6.0"
|
|
39
|
+
},
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "https://github.com/SkinGem/kognai.git",
|
|
43
|
+
"directory": "packages/kognai-build"
|
|
44
|
+
}
|
|
45
|
+
}
|