mindforge-cc 11.4.0 → 11.5.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/.agent/CLAUDE.md +13 -0
- package/.agent/hooks/lib/hook-flags.js +78 -0
- package/.agent/hooks/lib/pretooluse-visible-output.js +46 -0
- package/.agent/hooks/mindforge-block-no-verify.js +552 -0
- package/.agent/hooks/mindforge-config-protection.js +144 -0
- package/.agent/hooks/run-with-flags.js +207 -0
- package/.agent/mindforge/checkpoint.md +76 -0
- package/.agent/mindforge/harness-audit.md +59 -0
- package/.agent/mindforge/instinct.md +46 -0
- package/.agent/mindforge/orch-add-feature.md +43 -0
- package/.agent/mindforge/orch-build-mvp.md +48 -0
- package/.agent/mindforge/orch-change-feature.md +45 -0
- package/.agent/mindforge/orch-fix-defect.md +43 -0
- package/.agent/mindforge/orch-refine-code.md +43 -0
- package/.claude/CLAUDE.md +13 -0
- package/.claude/commands/mindforge/checkpoint.md +76 -0
- package/.claude/commands/mindforge/execute-phase.md +47 -6
- package/.claude/commands/mindforge/harness-audit.md +59 -0
- package/.claude/commands/mindforge/instinct.md +46 -0
- package/.claude/commands/mindforge/orch-add-feature.md +43 -0
- package/.claude/commands/mindforge/orch-build-mvp.md +48 -0
- package/.claude/commands/mindforge/orch-change-feature.md +45 -0
- package/.claude/commands/mindforge/orch-fix-defect.md +43 -0
- package/.claude/commands/mindforge/orch-refine-code.md +43 -0
- package/.claude/commands/mindforge/plan-write.md +11 -0
- package/.claude/commands/mindforge/product-spec.md +76 -0
- package/.mindforge/config.json +2 -2
- package/.mindforge/engine/instincts/instinct-schema.md +17 -9
- package/.mindforge/imported-agents.jsonl +10 -0
- package/.mindforge/manifests/install-components.json +36 -0
- package/.mindforge/manifests/install-modules.json +193 -0
- package/.mindforge/manifests/install-profiles.json +57 -0
- package/.mindforge/memory/sync-manifest.json +1 -1
- package/.mindforge/personas/gan-evaluator.md +226 -0
- package/.mindforge/personas/gan-generator.md +151 -0
- package/.mindforge/personas/gan-planner.md +118 -0
- package/.mindforge/personas/harness-optimizer.md +55 -0
- package/.mindforge/personas/loop-operator.md +58 -0
- package/.mindforge/schemas/hooks.schema.json +199 -0
- package/.mindforge/schemas/install-modules.schema.json +44 -0
- package/.mindforge/schemas/install-state.schema.json +95 -0
- package/.mindforge/schemas/plugin.schema.json +75 -0
- package/.mindforge/schemas/provenance.schema.json +31 -0
- package/.mindforge/skills/agent-architecture-audit/SKILL.md +272 -0
- package/.mindforge/skills/continuous-learning/SKILL.md +16 -0
- package/.mindforge/skills/orch-pipeline/SKILL.md +284 -0
- package/.mindforge/skills/writing-plans/SKILL.md +76 -0
- package/CHANGELOG.md +75 -0
- package/MINDFORGE.md +3 -3
- package/RELEASENOTES.md +86 -0
- package/SECURITY.md +16 -0
- package/bin/autonomous/auto-runner.js +46 -5
- package/bin/autonomous/handoff-schema.js +114 -0
- package/bin/autonomous/session-guardian.sh +138 -0
- package/bin/autonomous/supervisor.js +98 -0
- package/bin/change-classifier.js +19 -5
- package/bin/governance/approve.js +61 -28
- package/bin/governance/config-manager.js +3 -1
- package/bin/governance/rbac-manager.js +14 -6
- package/bin/harness-audit.js +520 -0
- package/bin/hooks/instinct-capture-hook.js +16 -1
- package/bin/hooks/lib/detect-project.js +72 -0
- package/bin/installer/harness-adapter-compliance.js +321 -0
- package/bin/installer/install-manifests.js +200 -0
- package/bin/installer/install-state.js +243 -0
- package/bin/installer-core.js +1 -1
- package/bin/learning/instinct-cli.js +359 -0
- package/bin/learning/lib/ssrf-guard.js +252 -0
- package/bin/memory/eis-client.js +31 -10
- package/bin/models/llm-errors.js +79 -0
- package/bin/models/model-client.js +39 -4
- package/bin/models/ollama-provider.js +115 -0
- package/bin/models/openai-provider.js +40 -9
- package/bin/models/profiles-loader.js +147 -0
- package/bin/models/provider-registry.js +59 -0
- package/bin/revops/market-evaluator.js +23 -2
- package/bin/revops/router-steering-v2.js +17 -2
- package/bin/security/trust-boundaries.js +15 -3
- package/bin/utils/readiness-gate.js +169 -0
- package/bin/worktree/engine.js +497 -0
- package/package.json +8 -2
- package/subagents/categories/04-quality-security/.claude-plugin/plugin.json +10 -0
- package/subagents/categories/04-quality-security/go-build-resolver.md +105 -0
- package/subagents/categories/04-quality-security/go-reviewer.md +87 -0
- package/subagents/categories/04-quality-security/python-reviewer.md +109 -0
- package/subagents/categories/04-quality-security/react-build-resolver.md +215 -0
- package/subagents/categories/04-quality-security/react-reviewer.md +167 -0
- package/subagents/categories/04-quality-security/rust-build-resolver.md +159 -0
- package/subagents/categories/04-quality-security/rust-reviewer.md +105 -0
- package/subagents/categories/04-quality-security/silent-failure-hunter.md +67 -0
- package/subagents/categories/04-quality-security/type-design-analyzer.md +58 -0
- package/subagents/categories/04-quality-security/typescript-reviewer.md +126 -0
|
@@ -12,14 +12,9 @@ const os = require('os');
|
|
|
12
12
|
const crypto = require('crypto');
|
|
13
13
|
const { execFileSync } = require('child_process');
|
|
14
14
|
|
|
15
|
-
const REASON = process.argv[2] || 'Manual approval for sensitive changes.';
|
|
16
15
|
const ROOT = path.resolve(__dirname, '../../');
|
|
17
16
|
const APPROVALS_DIR = path.join(ROOT, '.planning/approvals');
|
|
18
17
|
|
|
19
|
-
if (!fs.existsSync(APPROVALS_DIR)) {
|
|
20
|
-
fs.mkdirSync(APPROVALS_DIR, { recursive: true });
|
|
21
|
-
}
|
|
22
|
-
|
|
23
18
|
/**
|
|
24
19
|
* Attempts to retrieve the GPG signing key configured in git.
|
|
25
20
|
* Returns null if no key is configured or git is unavailable.
|
|
@@ -34,35 +29,65 @@ function getGPGSigningKey() {
|
|
|
34
29
|
}
|
|
35
30
|
|
|
36
31
|
/**
|
|
37
|
-
* Verifies the identity of the approver using GPG
|
|
38
|
-
*
|
|
32
|
+
* Verifies the identity of the approver using GPG.
|
|
33
|
+
*
|
|
34
|
+
* FAIL-CLOSED (Wave 6): a Tier 3 approval is a security gate. If no GPG signing
|
|
35
|
+
* key is configured, identity cannot be cryptographically attributed — git
|
|
36
|
+
* identity comes from spoofable env (USER / git config), so it is NOT a
|
|
37
|
+
* verification. We therefore REFUSE to mint an approval unless the operator
|
|
38
|
+
* explicitly opts into the weaker git-identity mode via
|
|
39
|
+
* MINDFORGE_ALLOW_UNVERIFIED_APPROVAL=1 (audited as unverified). Previously this
|
|
40
|
+
* returned {verified:false} but the record was written anyway and no consumer
|
|
41
|
+
* checked the flag — a cosmetic gate.
|
|
42
|
+
*
|
|
39
43
|
* @param {string} approver - The approver identity string
|
|
44
|
+
* @returns {{verified:boolean, method:string, identity:string, keyId?:string}}
|
|
45
|
+
* @throws if no GPG key AND the unverified-approval opt-in is not set.
|
|
40
46
|
*/
|
|
41
47
|
function verifyApproverIdentity(approver) {
|
|
42
48
|
const gpgKey = getGPGSigningKey();
|
|
43
49
|
|
|
44
50
|
if (!gpgKey) {
|
|
45
|
-
|
|
46
|
-
|
|
51
|
+
const allowUnverified = process.env.MINDFORGE_ALLOW_UNVERIFIED_APPROVAL === '1';
|
|
52
|
+
if (!allowUnverified) {
|
|
53
|
+
throw new Error(
|
|
54
|
+
'No GPG signing key configured (git config user.signingkey is empty). ' +
|
|
55
|
+
'A Tier 3 approval requires a verifiable identity. Either configure GPG signing, ' +
|
|
56
|
+
'or explicitly accept an UNVERIFIED approval by setting ' +
|
|
57
|
+
'MINDFORGE_ALLOW_UNVERIFIED_APPROVAL=1 (the record will be marked verified:false).'
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
console.warn('[GOVERNANCE] No GPG key — minting an UNVERIFIED approval (MINDFORGE_ALLOW_UNVERIFIED_APPROVAL=1). ' +
|
|
61
|
+
'git identity is spoofable; this approval is NOT cryptographically attributed.');
|
|
62
|
+
return { verified: false, method: 'git_identity_unverified', identity: approver };
|
|
47
63
|
}
|
|
48
64
|
|
|
49
65
|
return { verified: true, method: 'gpg_key', identity: approver, keyId: gpgKey };
|
|
50
66
|
}
|
|
51
67
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
68
|
+
/**
|
|
69
|
+
* Mint a Tier 3 approval record. Throws (fail-closed) if identity cannot be
|
|
70
|
+
* verified and the unverified-approval opt-in is not set — the record is NOT
|
|
71
|
+
* written in that case.
|
|
72
|
+
* @param {{reason?:string, approvalsDir?:string, root?:string}} [opts]
|
|
73
|
+
* @returns {{filePath:string, record:object}}
|
|
74
|
+
*/
|
|
75
|
+
function approve(opts = {}) {
|
|
76
|
+
const reason = opts.reason || 'Manual approval for sensitive changes.';
|
|
77
|
+
const root = opts.root || ROOT;
|
|
78
|
+
const approvalsDir = opts.approvalsDir || APPROVALS_DIR;
|
|
79
|
+
|
|
80
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
|
|
55
81
|
|
|
56
82
|
const id = `MF-AUTH-${Date.now().toString(36).toUpperCase()}`;
|
|
57
83
|
const timestamp = new Date().toISOString();
|
|
58
84
|
const approver = process.env.USER || 'MindForge User';
|
|
59
85
|
|
|
60
|
-
// Verify approver identity
|
|
86
|
+
// Verify approver identity — THROWS fail-closed if unverifiable (before any write).
|
|
61
87
|
const identityVerification = verifyApproverIdentity(approver);
|
|
62
88
|
|
|
63
|
-
// Calculate a signature based on current state
|
|
64
89
|
const signature = crypto.createHash('sha256')
|
|
65
|
-
.update(`${id}:${
|
|
90
|
+
.update(`${id}:${reason}:${timestamp}:${os.hostname()}`)
|
|
66
91
|
.digest('hex');
|
|
67
92
|
|
|
68
93
|
const record = {
|
|
@@ -72,25 +97,33 @@ async function approve() {
|
|
|
72
97
|
tier: 3,
|
|
73
98
|
approved_by: approver,
|
|
74
99
|
timestamp,
|
|
75
|
-
reason
|
|
100
|
+
reason,
|
|
76
101
|
signature: `sha256:${signature}`,
|
|
77
102
|
identity_verification: identityVerification
|
|
78
103
|
};
|
|
79
104
|
|
|
105
|
+
if (!fs.existsSync(approvalsDir)) fs.mkdirSync(approvalsDir, { recursive: true });
|
|
80
106
|
const filename = `approval-${id.toLowerCase()}.json`;
|
|
81
|
-
const filePath = path.join(
|
|
82
|
-
|
|
107
|
+
const filePath = path.join(approvalsDir, filename);
|
|
83
108
|
fs.writeFileSync(filePath, JSON.stringify(record, null, 2));
|
|
84
109
|
|
|
85
|
-
|
|
86
|
-
console.log(`ID: ${id}`);
|
|
87
|
-
console.log(`Reason: ${REASON}`);
|
|
88
|
-
console.log(`Verified: ${identityVerification.verified ? 'GPG (' + identityVerification.keyId + ')' : 'git identity only (no GPG key)'}`);
|
|
89
|
-
console.log(`File: .planning/approvals/${filename}`);
|
|
90
|
-
console.log('\nCommit this file to unblock Tier 3 gates in CI.\n');
|
|
110
|
+
return { filePath, record, filename };
|
|
91
111
|
}
|
|
92
112
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
113
|
+
module.exports = { verifyApproverIdentity, getGPGSigningKey, approve };
|
|
114
|
+
|
|
115
|
+
if (require.main === module) {
|
|
116
|
+
try {
|
|
117
|
+
const { filename, record } = approve({ reason: process.argv[2] });
|
|
118
|
+
const iv = record.identity_verification;
|
|
119
|
+
console.log('\n✅ Governance approval generated!\n');
|
|
120
|
+
console.log(`ID: ${record.id}`);
|
|
121
|
+
console.log(`Reason: ${record.reason}`);
|
|
122
|
+
console.log(`Verified: ${iv.verified ? 'GPG (' + iv.keyId + ')' : 'git identity only — UNVERIFIED'}`);
|
|
123
|
+
console.log(`File: .planning/approvals/${filename}`);
|
|
124
|
+
console.log('\nCommit this file to unblock Tier 3 gates in CI.\n');
|
|
125
|
+
} catch (err) {
|
|
126
|
+
console.error(`❌ Approval failed: ${err.message}`);
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
@@ -21,7 +21,9 @@ class ConfigManager {
|
|
|
21
21
|
if (fs.existsSync(this.configPath)) {
|
|
22
22
|
const raw = fs.readFileSync(this.configPath, 'utf8');
|
|
23
23
|
this.config = JSON.parse(raw);
|
|
24
|
-
|
|
24
|
+
// Diagnostic goes to stderr (not stdout) so it never pollutes JSON that a
|
|
25
|
+
// consumer parses from this process's stdout. Matches the warn/error lines below.
|
|
26
|
+
console.error(`[ConfigManager] Loaded configuration from ${this.configPath}`);
|
|
25
27
|
} else {
|
|
26
28
|
console.warn(`[ConfigManager] Config file not found at ${this.configPath}. Using defaults.`);
|
|
27
29
|
this.config = { env: 'default' };
|
|
@@ -40,18 +40,26 @@ class RBACManager {
|
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
/**
|
|
43
|
-
* [HARDEN] Dynamically binds roles based on ZTAI trust tiers
|
|
44
|
-
*
|
|
43
|
+
* [HARDEN] Dynamically binds roles based on ZTAI trust tiers on top of the
|
|
44
|
+
* agent's explicit/default roles. High-trust agents automatically gain
|
|
45
|
+
* architect-level visibility.
|
|
46
|
+
*
|
|
47
|
+
* ztai-manager is a SINGLETON instance (not a constructor), and exposes no
|
|
48
|
+
* getIdentity(); the agent's tier lives in the trust registry, read via
|
|
49
|
+
* getAgent(did). Fails SAFE: an unregistered/unknown DID has no resolvable
|
|
50
|
+
* tier, so it receives only its base roles (no tier-based elevation) rather
|
|
51
|
+
* than throwing. (Wave 6: the previous `new ztai().getIdentity()` threw on
|
|
52
|
+
* every call — "ztai is not a constructor".)
|
|
45
53
|
*/
|
|
46
54
|
async getRolesByTier(did) {
|
|
47
|
-
const manager = new ztai();
|
|
48
|
-
const identity = await manager.getIdentity();
|
|
49
55
|
const explicit = this.getRoles(did);
|
|
56
|
+
const agent = ztai.getAgent(did);
|
|
57
|
+
const tier = agent && typeof agent.tier === 'number' ? agent.tier : 0;
|
|
50
58
|
|
|
51
|
-
if (
|
|
59
|
+
if (tier >= 3) {
|
|
52
60
|
return [...new Set([...explicit, 'lead-architect'])];
|
|
53
61
|
}
|
|
54
|
-
if (
|
|
62
|
+
if (tier >= 2) {
|
|
55
63
|
return [...new Set([...explicit, 'developer'])];
|
|
56
64
|
}
|
|
57
65
|
return explicit;
|