@guanlin4924/devflow-pi 0.1.72 → 0.1.73
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/package.json +1 -1
- package/src/constants.ts +1 -1
- package/src/initialization-store.ts +13 -3
- package/src/project-initializer.ts +25 -0
package/package.json
CHANGED
package/src/constants.ts
CHANGED
|
@@ -402,11 +402,21 @@ export class InitializationStore {
|
|
|
402
402
|
this.assertWritableRun(runId, leaseToken);
|
|
403
403
|
const transaction = this.db.transaction(() => {
|
|
404
404
|
const repository = input.repository ?? "";
|
|
405
|
-
|
|
406
|
-
|
|
405
|
+
if (repository) {
|
|
406
|
+
this.db.query("DELETE FROM evidence WHERE fact_id IN (SELECT id FROM facts WHERE run_id=? AND repository=? AND kind=?)").run(runId, repository, input.kind);
|
|
407
|
+
this.db.query("DELETE FROM facts WHERE run_id=? AND repository=? AND kind=?").run(runId, repository, input.kind);
|
|
408
|
+
} else {
|
|
409
|
+
this.db.query("DELETE FROM evidence WHERE fact_id IN (SELECT id FROM facts WHERE run_id=? AND kind=?)").run(runId, input.kind);
|
|
410
|
+
this.db.query("DELETE FROM facts WHERE run_id=? AND kind=?").run(runId, input.kind);
|
|
411
|
+
}
|
|
407
412
|
this.db.query("INSERT INTO collection_results(id,run_id,repository,kind,status,adapter,capability_json,diagnostics_json,created_at) VALUES (?,?,?,?,?,?,?,?,?) ON CONFLICT(run_id,repository,kind) DO UPDATE SET status=excluded.status,adapter=excluded.adapter,capability_json=excluded.capability_json,diagnostics_json=excluded.diagnostics_json,created_at=excluded.created_at").run(randomUUID(), runId, repository, input.kind, input.status, input.adapter, canonicalJson(input.capability ?? {}), canonicalJson(input.diagnostics ?? []), now());
|
|
408
|
-
|
|
413
|
+
const uniqueFacts = new Map<string, FactInput>();
|
|
414
|
+
for (const fact of input.facts ?? []) uniqueFacts.set(`${fact.repository ?? repository}\0${fact.objectKey}`, fact);
|
|
415
|
+
for (const fact of uniqueFacts.values()) {
|
|
409
416
|
if (fact.kind !== input.kind) throw new Error(`Fact kind ${fact.kind} does not match collection ${input.kind}`);
|
|
417
|
+
if (repository && fact.repository !== undefined && fact.repository !== repository) {
|
|
418
|
+
throw new Error(`Fact repository ${fact.repository} does not match collection repository ${repository}`);
|
|
419
|
+
}
|
|
410
420
|
if (!fact.objectKey || !fact.extractor) throw new Error("Facts require objectKey and extractor");
|
|
411
421
|
if (fact.evidenceLevel === "observed" && !fact.sourcePath) throw new Error("Observed facts require source evidence");
|
|
412
422
|
validateFactShape(fact);
|
|
@@ -165,6 +165,31 @@ function collect(files: SourceFile[], context: ProjectContext, config: ScanConfi
|
|
|
165
165
|
facts.get("evidence")!.push({ kind: "evidence", repository: repository.name, objectKey: "input-policy", value: { source: "local-static", discoveredCommandsExecuted: false, gitMetadataRead: true, secretsStored: false }, evidenceLevel: "explicit_rule", extractor: "initializer@1", confidence: "exact" });
|
|
166
166
|
facts.get("capability")!.push({ kind: "capability", repository: repository.name, objectKey: "collector:static@1", value: { supported: ["asset", "technology", "api", "page", "data_model", "integration", "rule", "toolchain"], limitations: ["static declarations only", "dynamic behavior unresolved", "no environment enablement inference"], project: context.manifest.name }, evidenceLevel: "explicit_rule", extractor: "initializer@1", confidence: "exact" });
|
|
167
167
|
}
|
|
168
|
+
// A repository can declare the same route/model/page through more than one
|
|
169
|
+
// scanner (or declare it twice). The control-plane key is intentionally
|
|
170
|
+
// unique per run/kind/repository/object_key, so collapse duplicates before
|
|
171
|
+
// handing facts to the store while retaining the richest value/evidence.
|
|
172
|
+
for (const [kind, entries] of facts) {
|
|
173
|
+
const deduped = new Map<string, FactInput>();
|
|
174
|
+
for (const entry of entries) {
|
|
175
|
+
const key = `${entry.repository ?? ""}\0${entry.objectKey}`;
|
|
176
|
+
const previous = deduped.get(key);
|
|
177
|
+
if (!previous) {
|
|
178
|
+
deduped.set(key, entry);
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
deduped.set(key, {
|
|
182
|
+
...previous,
|
|
183
|
+
...entry,
|
|
184
|
+
repository: entry.repository ?? previous.repository,
|
|
185
|
+
value: { ...(previous.value ?? {}), ...(entry.value ?? {}) },
|
|
186
|
+
sourcePath: entry.sourcePath ?? previous.sourcePath,
|
|
187
|
+
sourceLine: entry.sourceLine ?? previous.sourceLine,
|
|
188
|
+
sourceFingerprint: entry.sourceFingerprint ?? previous.sourceFingerprint,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
facts.set(kind, [...deduped.values()]);
|
|
192
|
+
}
|
|
168
193
|
return facts;
|
|
169
194
|
}
|
|
170
195
|
|