@geraldmaron/construct 1.0.15 → 1.0.16
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 +15 -2
- package/bin/construct +144 -81
- package/db/schema/010_cx_scores.sql +51 -0
- package/lib/cli-commands.mjs +280 -146
- package/lib/contracts/validate.mjs +20 -10
- package/lib/contracts/violation-log.mjs +27 -12
- package/lib/hooks/stop-notify.mjs +7 -0
- package/lib/install/first-invocation.mjs +5 -1
- package/lib/intake/prepare.mjs +22 -4
- package/lib/integrations/intake-integrations.mjs +28 -2
- package/lib/mcp/tools/telemetry.mjs +30 -0
- package/lib/orchestration-policy.mjs +15 -0
- package/lib/roles/gateway.mjs +30 -1
- package/lib/scheduler/index.mjs +24 -4
- package/lib/server/insights.mjs +12 -0
- package/lib/setup.mjs +54 -9
- package/lib/update.mjs +31 -3
- package/lib/upgrade.mjs +31 -4
- package/package.json +1 -1
- package/personas/construct.md +2 -0
- package/platforms/claude/CLAUDE.md +43 -15
- package/scripts/sync-specialists.mjs +20 -2
package/lib/upgrade.mjs
CHANGED
|
@@ -10,6 +10,8 @@ import path from 'node:path';
|
|
|
10
10
|
import { spawnSync } from 'node:child_process';
|
|
11
11
|
import { fileURLToPath } from 'node:url';
|
|
12
12
|
|
|
13
|
+
import { writeVersionStamp } from './maintenance/cleanup.mjs';
|
|
14
|
+
|
|
13
15
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
14
16
|
const ROOT_DIR = path.resolve(__dirname, '..');
|
|
15
17
|
const PACKAGE_NAME = '@geraldmaron/construct';
|
|
@@ -97,7 +99,7 @@ export function runUpgrade({ cwd = process.cwd(), env = process.env, stdout = pr
|
|
|
97
99
|
}
|
|
98
100
|
|
|
99
101
|
stdout.write('Upgrading...\n\n');
|
|
100
|
-
|
|
102
|
+
|
|
101
103
|
const steps = [
|
|
102
104
|
{
|
|
103
105
|
label: 'Fetching latest from npm',
|
|
@@ -109,6 +111,15 @@ export function runUpgrade({ cwd = process.cwd(), env = process.env, stdout = pr
|
|
|
109
111
|
command: 'construct',
|
|
110
112
|
args: ['sync', '--no-docs'],
|
|
111
113
|
},
|
|
114
|
+
// Sweep legacy cx-*.md/.toml/.prompt.md left behind by older releases at
|
|
115
|
+
// user scope. Without this the user gets a doctor warning every session
|
|
116
|
+
// until they manually run `construct doctor --fix-legacy-agents`.
|
|
117
|
+
{
|
|
118
|
+
label: 'Sweeping legacy agents at user scope',
|
|
119
|
+
command: 'construct',
|
|
120
|
+
args: ['doctor', '--fix-legacy-agents'],
|
|
121
|
+
optional: true,
|
|
122
|
+
},
|
|
112
123
|
{
|
|
113
124
|
label: 'Running health checks',
|
|
114
125
|
command: 'construct',
|
|
@@ -123,18 +134,34 @@ export function runUpgrade({ cwd = process.cwd(), env = process.env, stdout = pr
|
|
|
123
134
|
env,
|
|
124
135
|
stdio: 'inherit',
|
|
125
136
|
});
|
|
126
|
-
|
|
137
|
+
|
|
127
138
|
if (result.error) {
|
|
139
|
+
if (step.optional) {
|
|
140
|
+
stdout.write(` (skipped: ${result.error.message})\n`);
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
128
143
|
stdout.write(`\n✗ ${step.label} failed: ${result.error.message}\n`);
|
|
129
144
|
return { success: false, reason: 'step_failed', step: step.label };
|
|
130
145
|
}
|
|
131
|
-
|
|
146
|
+
|
|
132
147
|
if (result.status !== 0) {
|
|
148
|
+
if (step.optional) {
|
|
149
|
+
stdout.write(` (skipped: exit ${result.status})\n`);
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
133
152
|
stdout.write(`\n✗ ${step.label} failed with exit code ${result.status}\n`);
|
|
134
153
|
return { success: false, reason: 'step_failed', step: step.label };
|
|
135
154
|
}
|
|
136
155
|
}
|
|
137
|
-
|
|
156
|
+
|
|
157
|
+
// Advance the cleanup stamp so the next CLI invocation doesn't re-run a
|
|
158
|
+
// full cleanup pass under the assumption that the user just upgraded.
|
|
159
|
+
// Without this, every command pays the cleanup cost until something
|
|
160
|
+
// else writes the stamp.
|
|
161
|
+
try {
|
|
162
|
+
writeVersionStamp({ version: latestVersion, summary: { freedBytes: 0, durationMs: 0 } });
|
|
163
|
+
} catch { /* stamp write is best-effort */ }
|
|
164
|
+
|
|
138
165
|
stdout.write('\n');
|
|
139
166
|
stdout.write(`✓ Upgraded to ${latestVersion}\n`);
|
|
140
167
|
return { success: true, upgraded: true, from: currentVersion, to: latestVersion };
|
package/package.json
CHANGED
package/personas/construct.md
CHANGED
|
@@ -34,6 +34,8 @@ Execution model:
|
|
|
34
34
|
|
|
35
35
|
Devil's advocate is mandatory for new architectural directions, AI/agent workflow changes, security or data-integrity changes, and promoting a temporary capability to persistent.
|
|
36
36
|
|
|
37
|
+
Orchestrated dispatches emit a task-packet with `goal`, `intent`, `workCategory`, `riskFlags`, `acceptanceCriteria` before naming specialists (`specialists/contracts.json:construct-to-orchestrator`).
|
|
38
|
+
|
|
37
39
|
## Gates and contracts (org-in-a-box)
|
|
38
40
|
|
|
39
41
|
`routeRequest` returns three artifacts; honor all three:
|
|
@@ -1,30 +1,58 @@
|
|
|
1
1
|
# Construct: Claude Code Integration
|
|
2
2
|
|
|
3
|
-
This
|
|
3
|
+
This file ships as a reference template alongside the Construct npm package. The canonical project-instructions file is `/CLAUDE.md` at your repo root — that's the file Claude Code actually reads at session start. The structure here mirrors that canonical file so users know what shape their own `/CLAUDE.md` should take after `construct init` scaffolds a project.
|
|
4
|
+
|
|
5
|
+
Personas and specialists are defined in `specialists/registry.json` and rendered into Claude Code agents on every `construct sync`. The single user-facing persona is `construct`; the 28 specialists (cx-engineer, cx-security, cx-devil-advocate, …) are routed internally — you address Construct, Construct dispatches.
|
|
6
|
+
|
|
7
|
+
## Critical rules (mirror in your project /CLAUDE.md)
|
|
8
|
+
|
|
9
|
+
- **Never fabricate.** Every load-bearing claim cites a verifiable source. When a fact isn't in the source, write `unknown` or `[unverified]`. See `rules/common/no-fabrication.md`.
|
|
10
|
+
- **Confirm the working branch every session.** Session-start surfaces `## Working branch: <name>` at the top of the injected context.
|
|
11
|
+
- **Never commit, push, or merge without asking first.** State the branch, state the action, wait for explicit yes.
|
|
12
|
+
- **Never edit running hook files** without testing them in isolation. A broken hook blocks all tool use.
|
|
13
|
+
- **Hooks fire unconditionally. No skip env vars on quality gates.** If a check fires wrong, repair the check — do not re-introduce `CONSTRUCT_SKIP_*` / `CONSTRUCT_ALLOW_*`.
|
|
14
|
+
- **Never commit directly to main.** Branch, test, then merge.
|
|
15
|
+
- **Run `construct doctor`** after structural changes.
|
|
4
16
|
|
|
5
17
|
## Workflow roles
|
|
6
18
|
|
|
7
|
-
|
|
19
|
+
| Role | What it covers |
|
|
20
|
+
|---|---|
|
|
21
|
+
| **Planning** | Requirements, strategy, architecture, framing challenges |
|
|
22
|
+
| **Implementation** | Builds features and fixes bugs |
|
|
23
|
+
| **Validation** | Quality gates, code review, security, accessibility |
|
|
24
|
+
| **Research** | Docs, debugging, codebase exploration, external research |
|
|
25
|
+
| **Operations** | Releases, dev servers, health checks, observability |
|
|
26
|
+
|
|
27
|
+
Construct routes complex work through the full pipeline (plan → implement → validate → operate). For simple tasks, Construct acts directly without exposing the internal routing.
|
|
28
|
+
|
|
29
|
+
## Beads issue tracker
|
|
30
|
+
|
|
31
|
+
This project uses **bd (beads)** for issue tracking. Run `bd prime` for the full workflow context.
|
|
8
32
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
33
|
+
```bash
|
|
34
|
+
bd ready # Find available work
|
|
35
|
+
bd show <id> # View issue details
|
|
36
|
+
bd update <id> --claim # Claim work
|
|
37
|
+
bd close <id> # Complete work
|
|
38
|
+
```
|
|
14
39
|
|
|
15
|
-
|
|
40
|
+
Use `bd` for all task tracking. Do NOT use TodoWrite, TaskCreate, or markdown TODO lists.
|
|
16
41
|
|
|
17
|
-
|
|
18
|
-
plan → implement → validate → operate
|
|
42
|
+
## Session completion
|
|
19
43
|
|
|
20
|
-
|
|
44
|
+
When ending a work session, **work is not complete until `git push` succeeds.**
|
|
21
45
|
|
|
22
|
-
|
|
46
|
+
```bash
|
|
47
|
+
git pull --rebase
|
|
48
|
+
git push
|
|
49
|
+
git status # MUST show "up to date with origin"
|
|
50
|
+
```
|
|
23
51
|
|
|
24
|
-
## Tool
|
|
52
|
+
## Tool calls
|
|
25
53
|
|
|
26
54
|
When using Bash, always provide both `command` and `description` string fields. Do not emit XML-style fallback tool calls.
|
|
27
55
|
|
|
28
|
-
## Cross-
|
|
56
|
+
## Cross-tool memory
|
|
29
57
|
|
|
30
|
-
Construct uses cass-memory for cross-tool memory. Start the local HTTP server with `cm serve`, then
|
|
58
|
+
Construct uses cass-memory for cross-tool memory. Start the local HTTP server with `cm serve`, then `memory_search` to find prior context. Memory and beads are complementary: memory holds knowledge, beads hold tasks.
|
|
@@ -950,7 +950,16 @@ function getVSCodeSettingsPaths() {
|
|
|
950
950
|
path.join(appData, "Code - Insiders", "User", "settings.json"),
|
|
951
951
|
);
|
|
952
952
|
}
|
|
953
|
-
|
|
953
|
+
// settings.json present → ready to merge. settings.json absent but the
|
|
954
|
+
// VS Code User dir exists → installed without ever opening Preferences,
|
|
955
|
+
// and global sync still needs to write the MCP block. The User dir is
|
|
956
|
+
// the installation signal; bootstrap a minimal settings.json there.
|
|
957
|
+
|
|
958
|
+
return candidates.filter((candidate) => {
|
|
959
|
+
if (fs.existsSync(candidate)) return true;
|
|
960
|
+
const userDir = path.dirname(candidate);
|
|
961
|
+
return fs.existsSync(userDir);
|
|
962
|
+
});
|
|
954
963
|
}
|
|
955
964
|
|
|
956
965
|
function syncVSCode(targetDir = null) {
|
|
@@ -991,7 +1000,16 @@ function syncVSCode(targetDir = null) {
|
|
|
991
1000
|
let synced = false;
|
|
992
1001
|
for (const settingsPath of settingsPaths) {
|
|
993
1002
|
try {
|
|
994
|
-
|
|
1003
|
+
let settings;
|
|
1004
|
+
if (fs.existsSync(settingsPath)) {
|
|
1005
|
+
settings = JSON.parse(fs.readFileSync(settingsPath, "utf8"));
|
|
1006
|
+
} else {
|
|
1007
|
+
// VS Code installed (User dir present) but never opened → seed an
|
|
1008
|
+
// empty settings.json. Single object literal, no other keys, so
|
|
1009
|
+
// a later launch of VS Code finds it valid and writes user prefs
|
|
1010
|
+
// alongside.
|
|
1011
|
+
settings = {};
|
|
1012
|
+
}
|
|
995
1013
|
if (!settings["github.copilot.mcpServers"]) settings["github.copilot.mcpServers"] = {};
|
|
996
1014
|
const mcpServers = settings["github.copilot.mcpServers"];
|
|
997
1015
|
for (const [id, mcpDef] of Object.entries(registryMcp)) {
|