@geraldmaron/construct 1.2.0 → 1.2.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/README.md +2 -1
- package/bin/construct +180 -10
- package/lib/artifact-manifest.mjs +150 -4
- package/lib/artifact-workflow.mjs +252 -0
- package/lib/auto-docs.mjs +3 -1
- package/lib/chat/present.mjs +1 -0
- package/lib/cli-commands.mjs +20 -3
- package/lib/cli-service-inventory.mjs +42 -0
- package/lib/config/intake-policy.mjs +209 -0
- package/lib/config/project-config.mjs +11 -2
- package/lib/config/schema.mjs +50 -1
- package/lib/config/source-targets.mjs +311 -0
- package/lib/doctor/source-checkout.mjs +16 -0
- package/lib/document-export.mjs +38 -16
- package/lib/embed/auto-sources.mjs +44 -0
- package/lib/embed/cli.mjs +2 -1
- package/lib/embed/demand-fetch.mjs +50 -19
- package/lib/embed/inbox.mjs +6 -10
- package/lib/embed/worker.mjs +2 -1
- package/lib/embedded-contract/index.mjs +11 -0
- package/lib/export-branding.mjs +32 -0
- package/lib/hooks/session-start.mjs +14 -11
- package/lib/init-unified.mjs +24 -23
- package/lib/intake/constants.mjs +29 -0
- package/lib/intake/intake-config.mjs +52 -105
- package/lib/intake/legacy-paths.mjs +5 -0
- package/lib/mcp/server.mjs +19 -1
- package/lib/mcp/tools/embedded-contract.mjs +14 -0
- package/lib/playwright-demo.mjs +2 -0
- package/lib/server/index.mjs +31 -2
- package/lib/server/rate-limit.mjs +5 -3
- package/lib/server/webhook.mjs +3 -2
- package/package.json +1 -1
- package/specialists/artifact-manifest.json +11 -2
- package/specialists/artifact-manifest.schema.json +31 -1
- package/templates/distribution/construct-reference.docx +0 -0
package/lib/mcp/server.mjs
CHANGED
|
@@ -58,7 +58,7 @@ import {
|
|
|
58
58
|
profileCreate, profileArchive, sandboxList, learningStatus,
|
|
59
59
|
knowledgeGraphAsk,
|
|
60
60
|
} from './tools/profile.mjs';
|
|
61
|
-
import { modelResolve, triageRecommend, workflowInvoke, capabilityDescribe, executionResolve } from './tools/embedded-contract.mjs';
|
|
61
|
+
import { modelResolve, triageRecommend, workflowInvoke, capabilityDescribe, executionResolve, artifactWorkflow } from './tools/embedded-contract.mjs';
|
|
62
62
|
|
|
63
63
|
const DEFAULT_ROOT_DIR = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..');
|
|
64
64
|
const ROOT_DIR = resolve(process.env.CX_TOOLKIT_DIR || DEFAULT_ROOT_DIR);
|
|
@@ -1134,6 +1134,23 @@ const ALL_TOOL_DEFS = [
|
|
|
1134
1134
|
},
|
|
1135
1135
|
},
|
|
1136
1136
|
},
|
|
1137
|
+
{
|
|
1138
|
+
name: 'artifact_workflow',
|
|
1139
|
+
description: 'Plan a manifest-backed document artifact workflow and return a truthful provenance report. It separates planned steps from locally executed validation/export and never claims a host-planned specialist review or rewrite was completed. Durable local export requires approval_mode=allow-durable-write.',
|
|
1140
|
+
inputSchema: {
|
|
1141
|
+
type: 'object',
|
|
1142
|
+
properties: {
|
|
1143
|
+
input: { type: 'string', description: 'Natural-language artifact request.' },
|
|
1144
|
+
artifact_type: { type: 'string', description: 'Registered manifest document class.' },
|
|
1145
|
+
file_path: { type: 'string', description: 'Optional existing source document for local validation/export.' },
|
|
1146
|
+
format: { type: 'string', description: 'Distribution format such as pdf, docx, html, deck, or pptx.' },
|
|
1147
|
+
output_path: { type: 'string', description: 'Optional output destination when locally exporting.' },
|
|
1148
|
+
branding: { type: 'string', enum: ['construct', 'plain'], description: 'Construct is default; plain is an explicit opt-out.' },
|
|
1149
|
+
overrides: { type: 'object', description: 'Per-invocation manifest workflow overrides.' },
|
|
1150
|
+
approval_mode: { type: 'string', enum: ['proposal-only', 'requires-human-approval', 'allow-durable-write'], description: 'Only allow-durable-write performs local validation/export.' },
|
|
1151
|
+
},
|
|
1152
|
+
},
|
|
1153
|
+
},
|
|
1137
1154
|
{
|
|
1138
1155
|
name: 'model_resolve',
|
|
1139
1156
|
description: 'Resolve which model an embedded Construct workflow should use given the host/IDE provider context. Precedence: host model → same-provider-family fallback → Construct tier default → structured config error. Never reads or returns credential values (requiresCredential is a boolean) and never claims unverified provider health. Read-only; performs no writes.',
|
|
@@ -1421,6 +1438,7 @@ export async function dispatchToolByName(name, args = {}) {
|
|
|
1421
1438
|
else if (name === 'workflow_invoke') result = await workflowInvoke(args);
|
|
1422
1439
|
else if (name === 'capability_describe') result = capabilityDescribe(args);
|
|
1423
1440
|
else if (name === 'construct_execution_resolve') result = executionResolve(args);
|
|
1441
|
+
else if (name === 'artifact_workflow') result = artifactWorkflow(args);
|
|
1424
1442
|
else if (name === 'orchestration_run') { const m = await import('./tools/orchestration-run.mjs'); result = await m.orchestrationRun(args); }
|
|
1425
1443
|
else if (name === 'orchestration_status') { const m = await import('./tools/orchestration-run.mjs'); result = await m.orchestrationStatus(args); }
|
|
1426
1444
|
else if (name === 'construct_call') {
|
|
@@ -14,6 +14,7 @@ import { invokeWorkflow as invokeWorkflowCore } from '../../embedded-contract/wo
|
|
|
14
14
|
import { buildCapabilityContract } from '../../embedded-contract/capability.mjs';
|
|
15
15
|
import { resolveExecution as resolveExecutionCore } from '../../embedded-contract/execution.mjs';
|
|
16
16
|
import { resolveInput } from '../../embedded-contract/ingest.mjs';
|
|
17
|
+
import { runArtifactWorkflow as runArtifactWorkflowCore } from '../../artifact-workflow.mjs';
|
|
17
18
|
|
|
18
19
|
async function ingestArgs(args) {
|
|
19
20
|
if (args.input || !args.file_path) return { input: args.input, ingestion: undefined };
|
|
@@ -91,3 +92,16 @@ export function executionResolve(args = {}) {
|
|
|
91
92
|
};
|
|
92
93
|
return wrapContractResult(resolveExecutionCore(request), { surface: 'mcp' });
|
|
93
94
|
}
|
|
95
|
+
|
|
96
|
+
export function artifactWorkflow(args = {}) {
|
|
97
|
+
return wrapContractResult(runArtifactWorkflowCore({
|
|
98
|
+
input: args.input || args.request,
|
|
99
|
+
artifactType: args.artifact_type,
|
|
100
|
+
filePath: args.file_path,
|
|
101
|
+
format: args.format,
|
|
102
|
+
outputPath: args.output_path,
|
|
103
|
+
branding: args.branding,
|
|
104
|
+
overrides: args.overrides,
|
|
105
|
+
approvalMode: args.approval_mode,
|
|
106
|
+
}), { surface: 'mcp' });
|
|
107
|
+
}
|
package/lib/playwright-demo.mjs
CHANGED
package/lib/server/index.mjs
CHANGED
|
@@ -704,7 +704,9 @@ const server = createServer(async (req, res) => {
|
|
|
704
704
|
const rateTier = url.pathname === '/api/chat/stream' || url.pathname === '/api/chat'
|
|
705
705
|
|| url.pathname === '/api/chat/loop/stream'
|
|
706
706
|
? 'chat'
|
|
707
|
-
:
|
|
707
|
+
: url.pathname === '/api/chat/loop/command'
|
|
708
|
+
? 'command'
|
|
709
|
+
: (req.method !== 'GET' && req.method !== 'HEAD' ? 'write' : 'read');
|
|
708
710
|
if (checkRateLimit) {
|
|
709
711
|
const limit = checkRateLimit(req, rateTier, { env: process.env });
|
|
710
712
|
if (!limit.allowed) {
|
|
@@ -1580,6 +1582,32 @@ const server = createServer(async (req, res) => {
|
|
|
1580
1582
|
return;
|
|
1581
1583
|
}
|
|
1582
1584
|
|
|
1585
|
+
if (url.pathname === '/api/sources' && req.method === 'GET') {
|
|
1586
|
+
try {
|
|
1587
|
+
const { loadProjectConfig } = await import('../config/project-config.mjs');
|
|
1588
|
+
const {
|
|
1589
|
+
resolveEffectiveSourceTargetsFromConfig,
|
|
1590
|
+
legacyEnvSourceTargets,
|
|
1591
|
+
normalizeConfigTarget,
|
|
1592
|
+
} = await import('../config/source-targets.mjs');
|
|
1593
|
+
const loaded = loadProjectConfig(ROOT_DIR, process.env);
|
|
1594
|
+
const configTargets = (loaded.config.sources?.targets ?? []).map(normalizeConfigTarget);
|
|
1595
|
+
const envTargets = legacyEnvSourceTargets(process.env);
|
|
1596
|
+
const effective = resolveEffectiveSourceTargetsFromConfig(loaded.config, process.env);
|
|
1597
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
1598
|
+
res.end(JSON.stringify({
|
|
1599
|
+
path: loaded.path,
|
|
1600
|
+
configTargets,
|
|
1601
|
+
envTargets,
|
|
1602
|
+
effective,
|
|
1603
|
+
}));
|
|
1604
|
+
} catch (err) {
|
|
1605
|
+
res.writeHead(500, { 'Content-Type': 'application/json' });
|
|
1606
|
+
res.end(JSON.stringify({ error: err.message }));
|
|
1607
|
+
}
|
|
1608
|
+
return;
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1583
1611
|
if (url.pathname === '/api/intake/config' && req.method === 'GET') {
|
|
1584
1612
|
try {
|
|
1585
1613
|
const { loadIntakeConfig, INTAKE_DEPTH_GUIDANCE, INTAKE_HARD_MAX_DEPTH } = await import('../intake/intake-config.mjs');
|
|
@@ -1592,7 +1620,7 @@ const server = createServer(async (req, res) => {
|
|
|
1592
1620
|
rootDir: ROOT_DIR,
|
|
1593
1621
|
guidance: INTAKE_DEPTH_GUIDANCE,
|
|
1594
1622
|
hardMaxDepth: INTAKE_HARD_MAX_DEPTH,
|
|
1595
|
-
defaults: { projectInbox: '.cx/inbox', docsIntake: 'docs/intake' },
|
|
1623
|
+
defaults: { projectInbox: '.cx/inbox', docsIntake: 'docs/intake', rootInbox: 'inbox/' },
|
|
1596
1624
|
label: rebrand.intakeQueueLabel,
|
|
1597
1625
|
itemNoun: rebrand.signalNoun,
|
|
1598
1626
|
}));
|
|
@@ -2341,6 +2369,7 @@ const server = createServer(async (req, res) => {
|
|
|
2341
2369
|
maxDepth: data.maxDepth,
|
|
2342
2370
|
includeProjectInbox: data.includeProjectInbox,
|
|
2343
2371
|
includeDocsIntake: data.includeDocsIntake,
|
|
2372
|
+
includeRootInbox: data.includeRootInbox ?? data.includeArchetypeInbox,
|
|
2344
2373
|
});
|
|
2345
2374
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
2346
2375
|
res.end(JSON.stringify({ success: true, config: next }));
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Three tiers, configurable via env:
|
|
5
5
|
*
|
|
6
|
-
* read
|
|
7
|
-
* chat
|
|
8
|
-
*
|
|
6
|
+
* read 60 req/min/key (dashboard polling, list endpoints)
|
|
7
|
+
* chat 10 req/min/key (/api/chat/stream — bursty + expensive)
|
|
8
|
+
* command 120 req/min/key (/api/chat/loop/command — slash cmds, no LLM)
|
|
9
|
+
* write 5 req/min/key (state-mutating endpoints — approvals, config)
|
|
9
10
|
*
|
|
10
11
|
* `key` is by default the request's source IP, with the active session id
|
|
11
12
|
* mixed in when present so two users behind the same NAT get separate
|
|
@@ -18,6 +19,7 @@
|
|
|
18
19
|
const DEFAULT_TIERS = {
|
|
19
20
|
read: { capacity: 60, refillPerMs: 60 / 60_000 },
|
|
20
21
|
chat: { capacity: 10, refillPerMs: 10 / 60_000 },
|
|
22
|
+
command: { capacity: 120, refillPerMs: 120 / 60_000 },
|
|
21
23
|
write: { capacity: 5, refillPerMs: 5 / 60_000 },
|
|
22
24
|
};
|
|
23
25
|
|
package/lib/server/webhook.mjs
CHANGED
|
@@ -306,8 +306,9 @@ async function runSnapshotForSlack() {
|
|
|
306
306
|
const { SnapshotEngine, renderMarkdown } = await import('../embed/snapshot.mjs');
|
|
307
307
|
const { EMPTY_CONFIG } = await import('../embed/config.mjs');
|
|
308
308
|
|
|
309
|
-
const registry = ProviderRegistry.fromEnv(env);
|
|
310
|
-
const
|
|
309
|
+
const registry = await ProviderRegistry.fromEnv(env);
|
|
310
|
+
const { resolveAutoEmbedSources } = await import('../embed/auto-sources.mjs');
|
|
311
|
+
const sources = resolveAutoEmbedSources({ cwd: process.cwd(), env, registry });
|
|
311
312
|
if (!sources.length) return '⚠️ No embed sources configured. Add credentials to config.env.';
|
|
312
313
|
|
|
313
314
|
const config = { ...EMPTY_CONFIG, sources, snapshot: { maxItems: 10 } };
|
package/package.json
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "./artifact-manifest.schema.json",
|
|
3
|
-
"version":
|
|
4
|
-
"description": "Single source of truth for document
|
|
3
|
+
"version": 2,
|
|
4
|
+
"description": "Single source of truth for registered document classes: template, author and reviewer chains, workflow skill, validation, output capability, tone, structure, visuals, and release gates.",
|
|
5
|
+
"workflowDefaults": {
|
|
6
|
+
"validation": {
|
|
7
|
+
"releaseGate": true
|
|
8
|
+
},
|
|
9
|
+
"outputs": {
|
|
10
|
+
"formats": ["pdf", "docx", "doc", "deck", "pptx", "html", "rtf", "odt", "epub", "tex", "txt", "md", "mdx"],
|
|
11
|
+
"branding": "construct"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
5
14
|
"artifacts": {
|
|
6
15
|
"prd": {
|
|
7
16
|
"template": "templates/docs/prd.md",
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"properties": {
|
|
9
9
|
"version": { "type": "integer", "minimum": 1 },
|
|
10
10
|
"description": { "type": "string" },
|
|
11
|
+
"workflowDefaults": { "$ref": "#/$defs/workflowDefaults" },
|
|
11
12
|
"artifacts": {
|
|
12
13
|
"type": "object",
|
|
13
14
|
"additionalProperties": { "$ref": "#/$defs/artifactEntry" }
|
|
@@ -34,6 +35,29 @@
|
|
|
34
35
|
"optionalReviewers": { "type": "array", "items": { "type": "string" } }
|
|
35
36
|
}
|
|
36
37
|
},
|
|
38
|
+
"workflowDefaults": {
|
|
39
|
+
"type": "object",
|
|
40
|
+
"properties": {
|
|
41
|
+
"authorChain": { "type": "array", "items": { "type": "string" } },
|
|
42
|
+
"reviewerChain": { "type": "array", "items": { "type": "string" } },
|
|
43
|
+
"validation": { "$ref": "#/$defs/validation" },
|
|
44
|
+
"outputs": { "$ref": "#/$defs/outputs" }
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"validation": {
|
|
48
|
+
"type": "object",
|
|
49
|
+
"properties": {
|
|
50
|
+
"releaseGate": { "type": "boolean" },
|
|
51
|
+
"requiredChecks": { "type": "array", "items": { "type": "string" } }
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"outputs": {
|
|
55
|
+
"type": "object",
|
|
56
|
+
"properties": {
|
|
57
|
+
"formats": { "type": "array", "items": { "type": "string" }, "minItems": 1 },
|
|
58
|
+
"branding": { "type": "string", "enum": ["construct", "plain"] }
|
|
59
|
+
}
|
|
60
|
+
},
|
|
37
61
|
"artifactEntry": {
|
|
38
62
|
"type": "object",
|
|
39
63
|
"required": ["template", "primaryOwners", "toneDefault", "releaseGate"],
|
|
@@ -46,7 +70,13 @@
|
|
|
46
70
|
"structureRequirements": { "type": "array", "items": { "type": "string" } },
|
|
47
71
|
"visualRequirements": { "type": "array", "items": { "$ref": "#/$defs/visualRequirement" } },
|
|
48
72
|
"researchProfile": { "type": ["string", "null"] },
|
|
49
|
-
"releaseGate": { "$ref": "#/$defs/releaseGate" }
|
|
73
|
+
"releaseGate": { "$ref": "#/$defs/releaseGate" },
|
|
74
|
+
"documentClass": { "type": "string" },
|
|
75
|
+
"aliases": { "type": "array", "items": { "type": "string" } },
|
|
76
|
+
"authorChain": { "type": "array", "items": { "type": "string" } },
|
|
77
|
+
"reviewerChain": { "type": "array", "items": { "type": "string" } },
|
|
78
|
+
"validation": { "$ref": "#/$defs/validation" },
|
|
79
|
+
"outputs": { "$ref": "#/$defs/outputs" }
|
|
50
80
|
}
|
|
51
81
|
}
|
|
52
82
|
}
|
|
Binary file
|