@aiwg/cli 2026.10.5 → 2026.10.7
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/agentic/code/addons/composition-engine/lib/runtime.mjs +1401 -0
- package/agentic/code/addons/composition-engine/lib/validator.mjs +513 -0
- package/agentic/code/addons/composition-engine/schemas/flow-graph.schema.json +372 -0
- package/agentic/code/providers/model-capabilities.v1.json +74 -50
- package/bin/aiwg.mjs +7 -3
- package/dist/src/a2a/agent-card.js +11 -0
- package/dist/src/api/index.d.ts +1 -0
- package/dist/src/api/index.js +1 -0
- package/dist/src/artifacts/browser-export.js +1 -0
- package/dist/src/artifacts/citation-parser.js +8 -1
- package/dist/src/artifacts/cli.js +57 -6
- package/dist/src/artifacts/fortemi-core-query-adapter.js +2 -0
- package/dist/src/artifacts/fortemi-core-sync.js +26 -8
- package/dist/src/artifacts/fortemi-shard-contract/2.2.0/contract.json +103 -0
- package/dist/src/artifacts/fortemi-shard-contract/2.2.0/full-v1-embedding-config.schema.json +212 -0
- package/dist/src/artifacts/fortemi-shard-contract/2.2.0/full-v1-embedding-set.schema.json +240 -0
- package/dist/src/artifacts/fortemi-shard-contract/2.2.0/full-v1-manifest.schema.json +451 -0
- package/dist/src/artifacts/fortemi-shard-export.js +284 -0
- package/dist/src/artifacts/graph-query.js +18 -8
- package/dist/src/artifacts/index-adapters.js +339 -0
- package/dist/src/artifacts/index-builder.js +143 -14
- package/dist/src/artifacts/index-files.js +15 -4
- package/dist/src/artifacts/index-preparation.js +2 -0
- package/dist/src/artifacts/index-reader.js +44 -0
- package/dist/src/artifacts/index-refresh.js +114 -55
- package/dist/src/artifacts/index-status.js +20 -5
- package/dist/src/artifacts/memory-maintenance.js +503 -0
- package/dist/src/artifacts/prebuilt-relations.js +3 -1
- package/dist/src/artifacts/query-engine.js +263 -108
- package/dist/src/artifacts/relations-builder.js +2 -2
- package/dist/src/artifacts/source-graph.js +2 -2
- package/dist/src/artifacts/types.js +9 -1
- package/dist/src/auth/client.js +5 -1
- package/dist/src/auth/credential-store.js +5 -1
- package/dist/src/auth/sensitive-input.js +151 -0
- package/dist/src/channel/manager.mjs +3 -0
- package/dist/src/cli/handlers/agentcard.js +47 -25
- package/dist/src/cli/handlers/auth.js +22 -2
- package/dist/src/cli/handlers/decision.js +22 -3
- package/dist/src/cli/handlers/effect.js +4 -84
- package/dist/src/cli/handlers/guided-setup.js +470 -0
- package/dist/src/cli/handlers/help.js +2 -2
- package/dist/src/cli/handlers/housekeeper.js +1110 -0
- package/dist/src/cli/handlers/index.js +4 -2
- package/dist/src/cli/handlers/init.js +41 -6
- package/dist/src/cli/handlers/install.js +6 -0
- package/dist/src/cli/handlers/local-executor.js +5 -3
- package/dist/src/cli/handlers/marketplace.js +15 -4
- package/dist/src/cli/handlers/mc.js +509 -53
- package/dist/src/cli/handlers/models.js +32 -2
- package/dist/src/cli/handlers/ralph-launcher.js +76 -4
- package/dist/src/cli/handlers/rules.js +1 -1
- package/dist/src/cli/handlers/script-runner.js +73 -2
- package/dist/src/cli/handlers/serve.js +5 -3
- package/dist/src/cli/handlers/sessions.js +1 -0
- package/dist/src/cli/handlers/setup.js +432 -1
- package/dist/src/cli/handlers/skill-lint.js +1 -1
- package/dist/src/cli/handlers/subcommands.js +118 -8
- package/dist/src/cli/handlers/use.js +335 -107
- package/dist/src/cli/handlers/workspace.js +3 -1
- package/dist/src/cli/prompt-utils.js +81 -0
- package/dist/src/cli/router.js +16 -1
- package/dist/src/config/aiwg-config.js +42 -0
- package/dist/src/config/cli.js +7 -3
- package/dist/src/config/decision-config.js +14 -1
- package/dist/src/config/gitignore.js +4 -0
- package/dist/src/config/native-sandbox-warnings.js +25 -0
- package/dist/src/config/workspace.js +2 -1
- package/dist/src/contributors/validation.js +6 -5
- package/dist/src/decision/adapters/jev.js +20 -31
- package/dist/src/decision/admission.js +7 -3
- package/dist/src/decision/ask.js +6 -1
- package/dist/src/decision/benchmark.js +482 -0
- package/dist/src/decision/ledger.js +22 -3
- package/dist/src/decision/pricing.js +147 -0
- package/dist/src/decision/qualification/gate-evidence.js +23 -18
- package/dist/src/decision/qualification/load-staged.js +576 -0
- package/dist/src/decision/qualification/load.js +109 -33
- package/dist/src/decision/qualification/runner.js +12 -5
- package/dist/src/decision/review/service.js +6 -4
- package/dist/src/decision/review/validate.js +23 -2
- package/dist/src/decision/savings.js +8 -3
- package/dist/src/discovery/index.js +492 -0
- package/dist/src/discovery/interview.js +238 -0
- package/dist/src/discovery/plan-apply.js +567 -0
- package/dist/src/discovery/plan-store.js +171 -0
- package/dist/src/discovery/plan-types.js +2 -0
- package/dist/src/discovery/plan-validation.js +139 -0
- package/dist/src/discovery/types.js +2 -0
- package/dist/src/effects/host.js +91 -0
- package/dist/src/extensions/commands/definitions.js +49 -9
- package/dist/src/extensions/manifest.js +71 -44
- package/dist/src/extensions/project-local-discovery.js +1 -1
- package/dist/src/extensions/project-local-gitignore.js +2 -0
- package/dist/src/extensions/project-quickref.js +18 -17
- package/dist/src/extensions/validation.js +32 -29
- package/dist/src/housekeeper/daemon-config.js +148 -0
- package/dist/src/housekeeper/ipc.js +84 -0
- package/dist/src/housekeeper/lifecycle.js +148 -0
- package/dist/src/housekeeper/platform.js +35 -0
- package/dist/src/housekeeper/status.js +70 -0
- package/dist/src/housekeeper/units.js +114 -0
- package/dist/src/issues/cli.js +16 -5
- package/dist/src/issues/live.js +44 -12
- package/dist/src/jobs/flow.js +22 -21
- package/dist/src/lint/rule-activation.js +20 -5
- package/dist/src/lint/runner.js +1 -1
- package/dist/src/marketplace/exchange.js +18 -6
- package/dist/src/marketplace/provenance.js +3 -2
- package/dist/src/mcp/adapters/codex-runtime.js +46 -76
- package/dist/src/mcp/cli.mjs +22 -96
- package/dist/src/mcp/config-file.mjs +6 -2
- package/dist/src/mcp/config-layers.mjs +23 -7
- package/dist/src/mcp/grok-build-config.mjs +2 -1
- package/dist/src/mcp/muse-native-config.mjs +2 -1
- package/dist/src/mcp/profiles.js +18 -31
- package/dist/src/mcp/profiles.mjs +18 -32
- package/dist/src/mcp/registry.js +7 -27
- package/dist/src/mcp/registry.mjs +7 -28
- package/dist/src/mcp/server.mjs +34 -1
- package/dist/src/mcp/tools/agentic-sandbox.mjs +8 -7
- package/dist/src/mcp/tools/command-run.mjs +3 -2
- package/dist/src/mcp/tools/decision.mjs +49 -48
- package/dist/src/mcp/tools/discovery.mjs +46 -21
- package/dist/src/mcp/tools/orchestration.mjs +22 -22
- package/dist/src/mcp/tools/subsystems.mjs +9 -8
- package/dist/src/mcp/tools/worker-invoke.mjs +30 -6
- package/dist/src/mcp/tools/writer-profiles.mjs +1 -1
- package/dist/src/memory/audit.js +719 -0
- package/dist/src/memory/canonical-context.js +392 -13
- package/dist/src/memory/canonical-maintenance.js +95 -0
- package/dist/src/memory/cli-result.js +22 -0
- package/dist/src/memory/cli.js +176 -0
- package/dist/src/memory/context-pack.js +57 -6
- package/dist/src/memory/cost.js +512 -0
- package/dist/src/memory/firewall-classification.d.mts +7 -0
- package/dist/src/memory/firewall-classification.mjs +32 -0
- package/dist/src/memory/index.js +8 -0
- package/dist/src/memory/line-maintenance.js +68 -0
- package/dist/src/memory/maintenance-cli.js +286 -0
- package/dist/src/memory/maintenance-contract.js +136 -0
- package/dist/src/memory/maintenance-index.js +18 -0
- package/dist/src/memory/maintenance-owner.js +2 -0
- package/dist/src/memory/maintenance-record.js +138 -0
- package/dist/src/memory/maintenance.js +254 -0
- package/dist/src/memory/project-registry.js +2 -1
- package/dist/src/memory/provider-memory-adapter.js +154 -0
- package/dist/src/memory/recommend-cli.js +83 -0
- package/dist/src/memory/recommend.js +269 -0
- package/dist/src/memory/scheduled.js +81 -0
- package/dist/src/memory/taxonomy.js +44 -0
- package/dist/src/mission-protocol/codecs.js +19 -9
- package/dist/src/mission-protocol/worker-status.js +91 -1
- package/dist/src/models/config-loader.js +11 -1
- package/dist/src/models/model-capabilities.v1.json +74 -50
- package/dist/src/models/provider-policy.js +125 -62
- package/dist/src/models/resolver.js +45 -8
- package/dist/src/models/worker-installation.d.mts +8 -1
- package/dist/src/models/worker-installation.mjs +231 -38
- package/dist/src/models/wrapper-route.js +1 -1
- package/dist/src/output-modes/registry.js +8 -7
- package/dist/src/packages/adapters/git.js +99 -23
- package/dist/src/packages/adapters/gitea.js +8 -27
- package/dist/src/packages/adapters/github.js +7 -25
- package/dist/src/packages/registry.js +4 -4
- package/dist/src/plugin/metadata-validator.js +1 -1
- package/dist/src/process/cli-command.d.mts +5 -0
- package/dist/src/process/cli-command.mjs +42 -0
- package/dist/src/providers/deploy-version.d.mts +1 -0
- package/dist/src/providers/deploy-version.mjs +17 -0
- package/dist/src/providers/provider-definitions.js +19 -16
- package/dist/src/providers/skill-ownership.d.mts +11 -2
- package/dist/src/providers/skill-ownership.mjs +35 -17
- package/dist/src/rules/activation.d.mts +11 -2
- package/dist/src/rules/activation.mjs +82 -6
- package/dist/src/rules/inventory.js +1 -1
- package/dist/src/rules/rule-frontmatter.schema.json +2 -0
- package/dist/src/schema/zod-validation.d.mts +6 -0
- package/dist/src/schema/zod-validation.mjs +50 -0
- package/dist/src/serve/executor-registry.js +297 -20
- package/dist/src/serve/executor-token.d.mts +1 -0
- package/dist/src/serve/executor-token.mjs +8 -0
- package/dist/src/serve/shared-host-scheduler.js +1102 -31
- package/dist/src/serve/worker-invocation.js +124 -15
- package/dist/src/sessions/adapters/claude.js +19 -18
- package/dist/src/sessions/adapters/codex.js +10 -9
- package/dist/src/sessions/adapters/copilot.js +14 -13
- package/dist/src/sessions/adapters/cursor.js +19 -18
- package/dist/src/sessions/adapters/deepseek-harness.js +9 -8
- package/dist/src/sessions/adapters/factory.js +11 -10
- package/dist/src/sessions/adapters/generic.js +32 -23
- package/dist/src/sessions/adapters/grokbot.js +35 -35
- package/dist/src/sessions/adapters/hermes.js +20 -19
- package/dist/src/sessions/adapters/muse.js +50 -49
- package/dist/src/sessions/adapters/omp.js +5 -4
- package/dist/src/sessions/adapters/openclaw.js +30 -29
- package/dist/src/sessions/adapters/opencode.js +26 -26
- package/dist/src/sessions/adapters/openhuman.js +24 -23
- package/dist/src/sessions/adapters/pi.js +5 -4
- package/dist/src/sessions/adapters/windsurf.js +8 -8
- package/dist/src/sessions/analytics.js +10 -9
- package/dist/src/sessions/candidates.js +7 -6
- package/dist/src/sessions/contracts.js +63 -53
- package/dist/src/sessions/output-registration.js +11 -10
- package/dist/src/sessions/workspace-discovery.js +3 -4
- package/dist/src/smiths/context-pipeline/aiwg-md.js +18 -1
- package/dist/src/smiths/context-pipeline/claude-hook.js +46 -10
- package/dist/src/smiths/context-pipeline/context-file-safety.js +330 -9
- package/dist/src/smiths/context-pipeline/finalization.js +3 -2
- package/dist/src/smiths/context-pipeline/generator.js +7 -19
- package/dist/src/smiths/context-pipeline/legacy-inject.js +3 -10
- package/dist/src/smiths/context-pipeline/managed-hook.js +5 -5
- package/dist/src/smiths/context-pipeline/parallelism-section.js +72 -5
- package/dist/src/smiths/context-pipeline/workspace-context.js +110 -22
- package/dist/src/tracker/project-inputs.js +2 -0
- package/dist/src/update/checker.d.mts +4 -0
- package/dist/src/update/checker.mjs +14 -0
- package/dist/src/update/notifier.mjs +2 -4
- package/dist/src/writing/exemplar-selection.js +6 -6
- package/dist/src/writing/voice-evaluation.js +24 -23
- package/dist/src/writing/writer-migration.js +14 -13
- package/dist/src/writing/writer-profile.js +19 -18
- package/dist/src/writing/writing-brief.js +18 -17
- package/dist/src/writing/writing-receipt.js +47 -46
- package/package.json +5 -2
- package/schemas/decision/DecisionReview.schema.json +78 -1
- package/schemas/mission-v1.schema.json +3 -0
- package/tools/agents/deploy-agents.mjs +67 -39
- package/tools/agents/providers/antigravity.mjs +6 -1
- package/tools/agents/providers/base.mjs +24 -14
- package/tools/agents/providers/claude.mjs +6 -3
- package/tools/agents/providers/codex.mjs +54 -57
- package/tools/agents/providers/context-write.mjs +28 -0
- package/tools/agents/providers/copilot.mjs +13 -4
- package/tools/agents/providers/cursor.mjs +1 -1
- package/tools/agents/providers/deepseek-harness.mjs +1 -1
- package/tools/agents/providers/factory.mjs +7 -1
- package/tools/agents/providers/grok-build.mjs +18 -2
- package/tools/agents/providers/grokbot.mjs +1 -1
- package/tools/agents/providers/hermes.mjs +12 -15
- package/tools/agents/providers/muse-hooks.mjs +21 -14
- package/tools/agents/providers/muse.mjs +7 -2
- package/tools/agents/providers/omp.mjs +31 -5
- package/tools/agents/providers/opencode.mjs +14 -5
- package/tools/agents/providers/openhuman.mjs +1 -1
- package/tools/agents/providers/pi.mjs +1 -1
- package/tools/agents/providers/provider-prepare-coordinator.mjs +29 -9
- package/tools/agents/providers/rule-delivery.mjs +289 -80
- package/tools/agents/providers/warp.mjs +4 -1
- package/tools/agents/providers/windsurf.mjs +13 -3
- package/tools/cli/workspace-status.mjs +5 -0
- package/tools/commands/deploy-prompts-codex.mjs +11 -8
- package/tools/ralph-external/lib/codex-adapter.mjs +6 -2
- package/tools/ralph-external/lib/consecutive-failure-circuit-breaker.mjs +26 -0
- package/tools/ralph-external/lib/launcher-recovery-evidence.mjs +7 -1
- package/tools/ralph-external/lib/muse-adapter.mjs +12 -2
- package/tools/ralph-external/lib/recovery-probe.mjs +14 -4
- package/tools/ralph-external/lib/worker-health.mjs +1 -1
- package/tools/ralph-external/lib/worker-isolation.mjs +65 -9
- package/tools/ralph-external/process-monitor.mjs +49 -8
- package/tools/ralph-external/session-launcher.mjs +405 -35
- package/tools/skills/deploy-skills-codex.mjs +11 -7
- package/vscode-extension/schemas/aiwg.config.v1.json +11 -1
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
|
+
import { createHash } from "node:crypto";
|
|
4
|
+
import { isDeepStrictEqual } from "node:util";
|
|
5
|
+
import Ajv2020 from "ajv/dist/2020.js";
|
|
6
|
+
import addFormats from "ajv-formats";
|
|
7
|
+
import { exportShardWithReport, importShard, packTarGz, unpackTarGz, validateChecksums, validateFullV1ShardArchive, verifyShardSignature, } from "@fortemi/core";
|
|
3
8
|
import { buildAiwgFortemiIndexExport, } from "./browser-export.js";
|
|
4
9
|
const SUPPORTED_SHARD_TUPLES = new Set([
|
|
5
10
|
"1.2.0/core-v1",
|
|
@@ -130,4 +135,283 @@ export function diagnoseAiwgFortemiShardMigration(cwd, inputPath) {
|
|
|
130
135
|
+ "--schema-version 2.0.0 --profile full-v1; retain the legacy shard for rollback.",
|
|
131
136
|
};
|
|
132
137
|
}
|
|
138
|
+
/** Qualified reader tuples; this is a local candidate result, not a release receipt. */
|
|
139
|
+
export const AIWG_FULL_V1_SHARD_READER_VERSIONS = ["2.0.0", "2.1.0", "2.2.0"];
|
|
140
|
+
const SHARD_CONTRACT_COMMIT = "b88084407751153e67a9279fff9303cc3db70474";
|
|
141
|
+
const encoder = new TextEncoder();
|
|
142
|
+
const decoder = new TextDecoder();
|
|
143
|
+
const digest = (bytes) => createHash("sha256").update(bytes).digest("hex");
|
|
144
|
+
const encodeJson = (value) => encoder.encode(JSON.stringify(value));
|
|
145
|
+
const parseJson = (bytes) => JSON.parse(decoder.decode(bytes));
|
|
146
|
+
const extendedFields = {
|
|
147
|
+
embedding_sets: ["query_template", "vector_source"],
|
|
148
|
+
embedding_configs: ["provider_dimension", "space_contract", "space_id", "vector_type"],
|
|
149
|
+
};
|
|
150
|
+
const contractRoot = new URL("./fortemi-shard-contract/2.2.0/", import.meta.url);
|
|
151
|
+
const contractBytes = fs.readFileSync(new URL("contract.json", contractRoot));
|
|
152
|
+
const contract = JSON.parse(contractBytes.toString("utf8"));
|
|
153
|
+
const contractAjv = new Ajv2020({ strict: true, allErrors: true });
|
|
154
|
+
addFormats(contractAjv);
|
|
155
|
+
const extendedValidators = Object.fromEntries(["manifest", "embedding-set", "embedding-config"].map((name) => [name, contractAjv.compile(JSON.parse(fs.readFileSync(new URL(`full-v1-${name}.schema.json`, contractRoot), "utf8")))]));
|
|
156
|
+
function projectedRecord(component, record) {
|
|
157
|
+
const projected = { ...record };
|
|
158
|
+
for (const field of extendedFields[component] ?? [])
|
|
159
|
+
delete projected[field];
|
|
160
|
+
return projected;
|
|
161
|
+
}
|
|
162
|
+
function projectedFiles(original) {
|
|
163
|
+
const files = new Map(original);
|
|
164
|
+
const manifest = parseJson(files.get("manifest.json"));
|
|
165
|
+
manifest.version = "2.0.0";
|
|
166
|
+
manifest.min_reader_version = "2.0.0";
|
|
167
|
+
for (const component of Object.keys(extendedFields)) {
|
|
168
|
+
const filename = `${component}.json`;
|
|
169
|
+
if (!files.has(filename))
|
|
170
|
+
continue;
|
|
171
|
+
const records = parseJson(files.get(filename));
|
|
172
|
+
const bytes = encodeJson(records.map(record => projectedRecord(component, record)));
|
|
173
|
+
files.set(filename, bytes);
|
|
174
|
+
manifest.checksums[filename] = digest(bytes);
|
|
175
|
+
}
|
|
176
|
+
files.set("manifest.json", encodeJson(manifest));
|
|
177
|
+
// The publisher envelope is verified against the original bytes before import.
|
|
178
|
+
files.delete("signature.json");
|
|
179
|
+
return files;
|
|
180
|
+
}
|
|
181
|
+
/** Validate the candidate additions, then reuse Core's complete structure/reference/blob checks. */
|
|
182
|
+
export async function validateAiwgFortemiKnowledgeShard(archive) {
|
|
183
|
+
try {
|
|
184
|
+
const files = unpackTarGz(archive);
|
|
185
|
+
const manifest = parseJson(files.get("manifest.json"));
|
|
186
|
+
if (manifest.version !== "2.2.0" && manifest.version !== "2.1.0") {
|
|
187
|
+
return validateFullV1ShardArchive(archive);
|
|
188
|
+
}
|
|
189
|
+
if (manifest.profile !== "full-v1") {
|
|
190
|
+
return { valid: false, errors: [`Unsupported ${manifest.version}/${manifest.profile} reader tuple`] };
|
|
191
|
+
}
|
|
192
|
+
const errors = [];
|
|
193
|
+
const manifestValidator = extendedValidators.manifest;
|
|
194
|
+
const candidateManifest = manifest.version === "2.1.0"
|
|
195
|
+
? { ...manifest, version: "2.2.0", min_reader_version: "2.2.0" } : manifest;
|
|
196
|
+
if (manifest.version === "2.1.0" && manifest.min_reader_version !== "2.1.0") {
|
|
197
|
+
errors.push("manifest.json unsupported min_reader_version");
|
|
198
|
+
}
|
|
199
|
+
if (!manifestValidator(candidateManifest))
|
|
200
|
+
errors.push(`manifest.json ${contractAjv.errorsText(manifestValidator.errors)}`);
|
|
201
|
+
for (const [component, name] of [["embedding_sets", "embedding-set"], ["embedding_configs", "embedding-config"]]) {
|
|
202
|
+
const records = parseJson(files.get(`${component}.json`));
|
|
203
|
+
if (!Array.isArray(records))
|
|
204
|
+
throw new Error(`${component} must be a JSON array`);
|
|
205
|
+
for (const [index, record] of records.entries()) {
|
|
206
|
+
const validate = extendedValidators[name];
|
|
207
|
+
if (!validate(record))
|
|
208
|
+
errors.push(`${component}[${index}] ${contractAjv.errorsText(validate.errors)}`);
|
|
209
|
+
if (typeof record.query_template === "string" && Buffer.byteLength(record.query_template, "utf8") > 2048) {
|
|
210
|
+
errors.push(`${component}[${index}].query_template exceeds 2048 UTF-8 bytes`);
|
|
211
|
+
}
|
|
212
|
+
if (typeof record.provider_dimension === "number" && record.provider_dimension < Number(record.dimension)) {
|
|
213
|
+
errors.push(`${component}[${index}].provider_dimension is below dimension`);
|
|
214
|
+
}
|
|
215
|
+
if (manifest.version === "2.1.0" && ["query_template", "vector_source", "provider_dimension"].some(field => field in record)) {
|
|
216
|
+
errors.push(`${component}[${index}] requires schema 2.2.0`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
if (errors.length)
|
|
221
|
+
return { valid: false, errors };
|
|
222
|
+
const checksums = await validateChecksums(manifest.checksums, files);
|
|
223
|
+
if (!checksums.valid)
|
|
224
|
+
return { valid: false, errors: checksums.failures.map(file => `${file} checksum mismatch`) };
|
|
225
|
+
const view = projectedFiles(files);
|
|
226
|
+
if (files.has("signature.json"))
|
|
227
|
+
view.set("signature.json", files.get("signature.json"));
|
|
228
|
+
return validateFullV1ShardArchive(view);
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
return { valid: false, errors: [error instanceof Error ? error.message : String(error)] };
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Core 2026.7.15 owns the snapshot transaction, conflict and blob handling. Its
|
|
236
|
+
* validation view uses 2.0.0; only the existing snapshot-table parameters change.
|
|
237
|
+
* Stored files/records always retain the original authority tuple and fields.
|
|
238
|
+
*/
|
|
239
|
+
function snapshotDatabaseView(db, version, originalFiles, originalArchive) {
|
|
240
|
+
const originalManifest = originalFiles.get("manifest.json");
|
|
241
|
+
const projected = originalManifest ? projectedFiles(originalFiles) : undefined;
|
|
242
|
+
const projectedArchiveDigest = projected ? digest(packTarGz(projected)) : undefined;
|
|
243
|
+
const wrap = (executor) => ({
|
|
244
|
+
exec: sql => executor.exec(sql),
|
|
245
|
+
async query(sql, params) {
|
|
246
|
+
if (!sql.includes("knowledge_shard_"))
|
|
247
|
+
return executor.query(sql, params);
|
|
248
|
+
const mapped = params ? [...params] : undefined;
|
|
249
|
+
if (mapped?.[0] === "2.0.0")
|
|
250
|
+
mapped[0] = version;
|
|
251
|
+
if (mapped && sql.includes("INSERT INTO knowledge_shard_snapshot")) {
|
|
252
|
+
mapped[2] = digest(originalArchive);
|
|
253
|
+
mapped[3] = decoder.decode(originalManifest);
|
|
254
|
+
}
|
|
255
|
+
else if (mapped && sql.includes("INSERT INTO knowledge_shard_file")) {
|
|
256
|
+
mapped[3] = originalFiles.get(String(mapped[2]));
|
|
257
|
+
}
|
|
258
|
+
else if (mapped && sql.includes("INSERT INTO knowledge_shard_component_record")) {
|
|
259
|
+
const component = String(mapped[2]);
|
|
260
|
+
if (component in extendedFields) {
|
|
261
|
+
mapped[5] = JSON.stringify(parseJson(originalFiles.get(`${component}.json`))[Number(mapped[3])]);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
const result = await executor.query(sql.replaceAll("schema_version = '2.0.0'", `schema_version = '${version}'`), mapped);
|
|
265
|
+
if (mapped && sql.includes("INSERT INTO knowledge_shard_file") && mapped[2] === "manifest.json" && originalFiles.has("signature.json")) {
|
|
266
|
+
await executor.query(sql, [version, "full-v1", "signature.json", originalFiles.get("signature.json")]);
|
|
267
|
+
}
|
|
268
|
+
const rows = result.rows.map(row => {
|
|
269
|
+
if ("archive_sha256" in row && originalArchive && row.archive_sha256 === digest(originalArchive)) {
|
|
270
|
+
return { ...row, archive_sha256: projectedArchiveDigest };
|
|
271
|
+
}
|
|
272
|
+
if ("path" in row && "bytes" in row) {
|
|
273
|
+
originalFiles.set(String(row.path), new Uint8Array(row.bytes));
|
|
274
|
+
return row;
|
|
275
|
+
}
|
|
276
|
+
return row;
|
|
277
|
+
});
|
|
278
|
+
// Export must validate the same 2.0.0 view while retaining original files.
|
|
279
|
+
if (rows.some(row => "path" in row && "bytes" in row)) {
|
|
280
|
+
const view = projectedFiles(originalFiles);
|
|
281
|
+
return { ...result, rows: rows.filter(row => row.path !== "signature.json").map(row => ({ ...row, bytes: view.get(String(row.path)) })) };
|
|
282
|
+
}
|
|
283
|
+
return { ...result, rows: rows.map(row => {
|
|
284
|
+
if ("manifest_json" in row) {
|
|
285
|
+
const manifest = structuredClone(row.manifest_json);
|
|
286
|
+
manifest.version = "2.0.0";
|
|
287
|
+
manifest.min_reader_version = "2.0.0";
|
|
288
|
+
return { ...row, manifest_json: manifest };
|
|
289
|
+
}
|
|
290
|
+
if ("record_json" in row)
|
|
291
|
+
return { ...row, record_json: projectedRecord(String(row.component), row.record_json) };
|
|
292
|
+
return row;
|
|
293
|
+
}) };
|
|
294
|
+
},
|
|
295
|
+
});
|
|
296
|
+
return { ...wrap(db), transaction: callback => db.transaction(tx => callback(wrap(tx))) };
|
|
297
|
+
}
|
|
298
|
+
function readerCapability(version, base) {
|
|
299
|
+
return {
|
|
300
|
+
...base,
|
|
301
|
+
requested_profile: "full-v1",
|
|
302
|
+
requested_schema_version: version,
|
|
303
|
+
authority_status: "candidate",
|
|
304
|
+
backend_supported: true,
|
|
305
|
+
portable: true,
|
|
306
|
+
authority: {
|
|
307
|
+
repository: "Fortemi/fortemi",
|
|
308
|
+
commit: SHARD_CONTRACT_COMMIT,
|
|
309
|
+
contract_sha256: digest(contractBytes),
|
|
310
|
+
contract_revision: "23",
|
|
311
|
+
schema_version: version,
|
|
312
|
+
schema_bundle_sha256: digest(encodeJson(contract.schemaBundle.files)),
|
|
313
|
+
},
|
|
314
|
+
advertised_profiles: ["full-v1"],
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
export async function importAiwgFortemiKnowledgeShard(db, archive, options) {
|
|
318
|
+
let files;
|
|
319
|
+
let manifest;
|
|
320
|
+
try {
|
|
321
|
+
files = unpackTarGz(archive);
|
|
322
|
+
manifest = parseJson(files.get("manifest.json"));
|
|
323
|
+
}
|
|
324
|
+
catch {
|
|
325
|
+
return importShard(db, archive, options);
|
|
326
|
+
}
|
|
327
|
+
if (manifest.version === "2.2.0" && manifest.profile !== "full-v1") {
|
|
328
|
+
throw new Error(`Unsupported 2.2.0/${manifest.profile} reader tuple`);
|
|
329
|
+
}
|
|
330
|
+
if (manifest.profile !== "full-v1" || !["2.1.0", "2.2.0"].includes(manifest.version)) {
|
|
331
|
+
return importShard(db, archive, options);
|
|
332
|
+
}
|
|
333
|
+
const validation = await validateAiwgFortemiKnowledgeShard(archive);
|
|
334
|
+
if (!validation.valid)
|
|
335
|
+
throw new Error(`Canonical full-v1 validation failed: ${validation.errors.join("; ")}`);
|
|
336
|
+
const policy = options?.verifySignature ?? (options?.trustStore ? "require" : undefined);
|
|
337
|
+
if (policy && policy !== "trusted-local-only") {
|
|
338
|
+
if (!options?.trustStore)
|
|
339
|
+
throw new Error(`verifySignature: '${policy}' requires a trustStore`);
|
|
340
|
+
const verdict = await verifyShardSignature({ files, trustStore: options.trustStore });
|
|
341
|
+
if (!verdict.ok && !(policy === "prefer" && verdict.reason === "unsigned")) {
|
|
342
|
+
throw new Error(`Full-v1 publisher verification failed: ${verdict.reason}`);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
const result = await importShard(snapshotDatabaseView(db, manifest.version, files, archive), packTarGz(projectedFiles(files)), { ...options, verifySignature: "trusted-local-only" });
|
|
346
|
+
return { ...result, capability_report: readerCapability(manifest.version, result.capability_report) };
|
|
347
|
+
}
|
|
348
|
+
export async function exportAiwgFortemiKnowledgeShardWithReport(db, options) {
|
|
349
|
+
const version = options.schemaVersion;
|
|
350
|
+
if (options.profile === "full-v1" && version !== "2.2.0") {
|
|
351
|
+
const snapshots = await db.query("SELECT schema_version FROM knowledge_shard_snapshot WHERE profile = 'full-v1'");
|
|
352
|
+
if (snapshots.rows.some(row => row.schema_version === "2.2.0") && !snapshots.rows.some(row => row.schema_version === version)) {
|
|
353
|
+
throw new Error("A 2.2.0/full-v1 snapshot requires schemaVersion: 2.2.0; refusing a lossy downgrade");
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
if (version !== "2.1.0" && version !== "2.2.0")
|
|
357
|
+
return exportShardWithReport(db, options);
|
|
358
|
+
if (options.profile !== "full-v1")
|
|
359
|
+
throw new Error(`Unsupported ${version}/${options.profile} reader tuple`);
|
|
360
|
+
const originals = new Map();
|
|
361
|
+
const exists = await db.query("SELECT schema_version FROM knowledge_shard_snapshot WHERE schema_version = $1 AND profile = 'full-v1'", [version]);
|
|
362
|
+
if (exists.rows.length === 0)
|
|
363
|
+
throw new Error(`No persisted ${version}/full-v1 snapshot`);
|
|
364
|
+
const result = await exportShardWithReport(snapshotDatabaseView(db, version, originals), { ...options, profile: "full-v1", schemaVersion: "2.0.0" });
|
|
365
|
+
if (!result.success || !result.archive)
|
|
366
|
+
return { ...result, capability_report: readerCapability(version, result.capability_report) };
|
|
367
|
+
// Core checks current snapshot records and retrieves/verifies mandatory blobs.
|
|
368
|
+
// Rebuild from the original record view so nullable/absent extension fields
|
|
369
|
+
// survive even edits that change only those fields.
|
|
370
|
+
const persisted = await db.query("SELECT component, record_json FROM knowledge_shard_component_record WHERE schema_version = $1 AND profile = 'full-v1' ORDER BY component, ordinal", [version]);
|
|
371
|
+
const records = new Map();
|
|
372
|
+
for (const row of persisted.rows)
|
|
373
|
+
records.set(row.component, [...(records.get(row.component) ?? []), row.record_json]);
|
|
374
|
+
const manifest = parseJson(originals.get("manifest.json"));
|
|
375
|
+
let changed = false;
|
|
376
|
+
for (const component of manifest.components) {
|
|
377
|
+
const filename = originals.has(`${component}.json`) ? `${component}.json` : `${component}.jsonl`;
|
|
378
|
+
const bytes = originals.get(filename);
|
|
379
|
+
const source = filename.endsWith(".json") ? parseJson(bytes)
|
|
380
|
+
: decoder.decode(bytes).split("\n").filter(Boolean).map(line => JSON.parse(line));
|
|
381
|
+
const current = records.get(component) ?? [];
|
|
382
|
+
if (JSON.stringify(source) === JSON.stringify(current))
|
|
383
|
+
continue;
|
|
384
|
+
// JSONB changes key order. Compare structurally before rewriting bytes.
|
|
385
|
+
if (isDeepStrictEqual(source, current))
|
|
386
|
+
continue;
|
|
387
|
+
const updated = filename.endsWith(".json") ? encodeJson(current)
|
|
388
|
+
: encoder.encode(current.map(record => JSON.stringify(record)).join("\n"));
|
|
389
|
+
originals.set(filename, updated);
|
|
390
|
+
manifest.checksums[filename] = digest(updated);
|
|
391
|
+
if (component === "communities") {
|
|
392
|
+
manifest.counts.community_sets = current.length;
|
|
393
|
+
manifest.counts.communities = current.reduce((total, set) => total + set.communities.length, 0);
|
|
394
|
+
}
|
|
395
|
+
else
|
|
396
|
+
manifest.counts[component] = current.length;
|
|
397
|
+
changed = true;
|
|
398
|
+
}
|
|
399
|
+
if (changed) {
|
|
400
|
+
originals.delete("signature.json");
|
|
401
|
+
originals.set("manifest.json", encodeJson(manifest));
|
|
402
|
+
}
|
|
403
|
+
for (const [filename, bytes] of unpackTarGz(result.archive)) {
|
|
404
|
+
if (filename.startsWith("blobs/"))
|
|
405
|
+
originals.set(filename, bytes);
|
|
406
|
+
}
|
|
407
|
+
const archive = packTarGz(originals);
|
|
408
|
+
const validation = await validateAiwgFortemiKnowledgeShard(archive);
|
|
409
|
+
return {
|
|
410
|
+
...result,
|
|
411
|
+
success: validation.valid,
|
|
412
|
+
archive: validation.valid ? archive : null,
|
|
413
|
+
errors: validation.errors,
|
|
414
|
+
capability_report: readerCapability(version, result.capability_report),
|
|
415
|
+
};
|
|
416
|
+
}
|
|
133
417
|
//# sourceMappingURL=fortemi-shard-export.js.map
|
|
@@ -9,8 +9,17 @@
|
|
|
9
9
|
* @tests @test/unit/artifacts/graph-query.test.ts
|
|
10
10
|
*/
|
|
11
11
|
import { normalizeEdges } from './types.js';
|
|
12
|
-
import { buildFortemiCoreDependencyGraph } from './fortemi-core-query-adapter.js';
|
|
12
|
+
import { buildFortemiCoreDependencyGraph, loadFortemiCoreMetadataEntries } from './fortemi-core-query-adapter.js';
|
|
13
13
|
import { closeGraphBackend, openGraphBackend } from './backend-runtime.js';
|
|
14
|
+
import { loadGraphIndexFile } from './index-reader.js';
|
|
15
|
+
import { isOrdinaryMemoryEntry } from './query-engine.js';
|
|
16
|
+
function graphMemoryMetadata(cwd, graph, backend) {
|
|
17
|
+
const local = loadGraphIndexFile(cwd, 'metadata.json', graph)?.entries ?? {};
|
|
18
|
+
if (backend === 'fortemi-core') {
|
|
19
|
+
return { ...Object.fromEntries(loadFortemiCoreMetadataEntries(cwd, graph).entries.map(entry => [entry.path, entry])), ...local };
|
|
20
|
+
}
|
|
21
|
+
return local;
|
|
22
|
+
}
|
|
14
23
|
/**
|
|
15
24
|
* Get neighbors of a node in a dependency graph.
|
|
16
25
|
*
|
|
@@ -20,15 +29,15 @@ import { closeGraphBackend, openGraphBackend } from './backend-runtime.js';
|
|
|
20
29
|
* @param edgeType - Optional filter by edge type
|
|
21
30
|
* @returns Array of neighbor paths
|
|
22
31
|
*/
|
|
23
|
-
export function getNeighbors(graph, node, direction = 'both', edgeType) {
|
|
32
|
+
export function getNeighbors(graph, node, direction = 'both', edgeType, metadata = {}) {
|
|
24
33
|
const entry = graph[node];
|
|
25
|
-
if (!entry)
|
|
34
|
+
if (!entry || (metadata[node] && !isOrdinaryMemoryEntry(metadata[node])))
|
|
26
35
|
return [];
|
|
27
36
|
const results = new Set();
|
|
28
37
|
if (direction === 'in' || direction === 'both') {
|
|
29
38
|
const edges = normalizeEdges(entry.upstream);
|
|
30
39
|
for (const edge of edges) {
|
|
31
|
-
if (!edgeType || edge.type === edgeType) {
|
|
40
|
+
if ((!edgeType || edge.type === edgeType) && (!metadata[edge.path] || isOrdinaryMemoryEntry(metadata[edge.path]))) {
|
|
32
41
|
results.add(edge.path);
|
|
33
42
|
}
|
|
34
43
|
}
|
|
@@ -36,7 +45,7 @@ export function getNeighbors(graph, node, direction = 'both', edgeType) {
|
|
|
36
45
|
if (direction === 'out' || direction === 'both') {
|
|
37
46
|
const edges = normalizeEdges(entry.downstream);
|
|
38
47
|
for (const edge of edges) {
|
|
39
|
-
if (!edgeType || edge.type === edgeType) {
|
|
48
|
+
if ((!edgeType || edge.type === edgeType) && (!metadata[edge.path] || isOrdinaryMemoryEntry(metadata[edge.path]))) {
|
|
40
49
|
results.add(edge.path);
|
|
41
50
|
}
|
|
42
51
|
}
|
|
@@ -134,7 +143,7 @@ export async function showNeighbors(cwd, options) {
|
|
|
134
143
|
}
|
|
135
144
|
process.exit(1);
|
|
136
145
|
}
|
|
137
|
-
const neighbors = getNeighbors(graph, resolved, direction, edgeType);
|
|
146
|
+
const neighbors = getNeighbors(graph, resolved, direction, edgeType, graphMemoryMetadata(cwd, graphType, backend));
|
|
138
147
|
if (json) {
|
|
139
148
|
console.log(JSON.stringify({
|
|
140
149
|
graph: graphType,
|
|
@@ -208,8 +217,9 @@ export async function executeSetQuery(cwd, options) {
|
|
|
208
217
|
console.error(`Error: Node '${nodeB}' not found in graph '${graphType}'.`);
|
|
209
218
|
process.exit(1);
|
|
210
219
|
}
|
|
211
|
-
const
|
|
212
|
-
const
|
|
220
|
+
const metadata = graphMemoryMetadata(cwd, graphType, backend);
|
|
221
|
+
const neighborsA = getNeighbors(graph, resolvedA, direction, edgeType, metadata);
|
|
222
|
+
const neighborsB = getNeighbors(graph, resolvedB, direction, edgeType, metadata);
|
|
213
223
|
let result;
|
|
214
224
|
switch (op) {
|
|
215
225
|
case 'intersection':
|