@eddacraft/anvil-core 0.1.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/LICENSE +14 -0
- package/dist/antipattern/index.d.ts +11 -0
- package/dist/antipattern/index.d.ts.map +1 -0
- package/dist/antipattern/index.js +31 -0
- package/dist/antipattern/patterns-css.d.ts +17 -0
- package/dist/antipattern/patterns-css.d.ts.map +1 -0
- package/dist/antipattern/patterns-css.js +72 -0
- package/dist/antipattern/patterns-html.d.ts +21 -0
- package/dist/antipattern/patterns-html.d.ts.map +1 -0
- package/dist/antipattern/patterns-html.js +139 -0
- package/dist/antipattern/patterns.d.ts +72 -0
- package/dist/antipattern/patterns.d.ts.map +1 -0
- package/dist/antipattern/patterns.js +301 -0
- package/dist/antipattern/scanner.d.ts +32 -0
- package/dist/antipattern/scanner.d.ts.map +1 -0
- package/dist/antipattern/scanner.js +89 -0
- package/dist/antipattern/types.d.ts +318 -0
- package/dist/antipattern/types.d.ts.map +1 -0
- package/dist/antipattern/types.js +278 -0
- package/dist/architecture/analyzer.d.ts +123 -0
- package/dist/architecture/analyzer.d.ts.map +1 -0
- package/dist/architecture/analyzer.js +321 -0
- package/dist/architecture/baseline.d.ts +112 -0
- package/dist/architecture/baseline.d.ts.map +1 -0
- package/dist/architecture/baseline.js +245 -0
- package/dist/architecture/compiler.d.ts +24 -0
- package/dist/architecture/compiler.d.ts.map +1 -0
- package/dist/architecture/compiler.js +57 -0
- package/dist/architecture/context.d.ts +129 -0
- package/dist/architecture/context.d.ts.map +1 -0
- package/dist/architecture/context.js +116 -0
- package/dist/architecture/dc-generator.d.ts +9 -0
- package/dist/architecture/dc-generator.d.ts.map +1 -0
- package/dist/architecture/dc-generator.js +220 -0
- package/dist/architecture/definition-schema.d.ts +128 -0
- package/dist/architecture/definition-schema.d.ts.map +1 -0
- package/dist/architecture/definition-schema.js +94 -0
- package/dist/architecture/edge-detector-html.d.ts +6 -0
- package/dist/architecture/edge-detector-html.d.ts.map +1 -0
- package/dist/architecture/edge-detector-html.js +5 -0
- package/dist/architecture/edge-detector-web.d.ts +32 -0
- package/dist/architecture/edge-detector-web.d.ts.map +1 -0
- package/dist/architecture/edge-detector-web.js +133 -0
- package/dist/architecture/edge-detector.d.ts +116 -0
- package/dist/architecture/edge-detector.d.ts.map +1 -0
- package/dist/architecture/edge-detector.js +229 -0
- package/dist/architecture/entry-detector.d.ts +44 -0
- package/dist/architecture/entry-detector.d.ts.map +1 -0
- package/dist/architecture/entry-detector.js +263 -0
- package/dist/architecture/index.d.ts +21 -0
- package/dist/architecture/index.d.ts.map +1 -0
- package/dist/architecture/index.js +48 -0
- package/dist/architecture/layer-detector.d.ts +60 -0
- package/dist/architecture/layer-detector.d.ts.map +1 -0
- package/dist/architecture/layer-detector.js +331 -0
- package/dist/architecture/rego-generator.d.ts +25 -0
- package/dist/architecture/rego-generator.d.ts.map +1 -0
- package/dist/architecture/rego-generator.js +229 -0
- package/dist/architecture/templates/index.d.ts +39 -0
- package/dist/architecture/templates/index.d.ts.map +1 -0
- package/dist/architecture/templates/index.js +124 -0
- package/dist/architecture/types.d.ts +280 -0
- package/dist/architecture/types.d.ts.map +1 -0
- package/dist/architecture/types.js +269 -0
- package/dist/architecture/yaml-parser.d.ts +13 -0
- package/dist/architecture/yaml-parser.d.ts.map +1 -0
- package/dist/architecture/yaml-parser.js +234 -0
- package/dist/config/constants.d.ts +9 -0
- package/dist/config/constants.d.ts.map +1 -0
- package/dist/config/constants.js +20 -0
- package/dist/config/index.d.ts +9 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +8 -0
- package/dist/config/loader.d.ts +41 -0
- package/dist/config/loader.d.ts.map +1 -0
- package/dist/config/loader.js +76 -0
- package/dist/config/nudge-config.d.ts +35 -0
- package/dist/config/nudge-config.d.ts.map +1 -0
- package/dist/config/nudge-config.js +34 -0
- package/dist/config/types.d.ts +30 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +4 -0
- package/dist/contracts/index.d.ts +14 -0
- package/dist/contracts/index.d.ts.map +1 -0
- package/dist/contracts/index.js +13 -0
- package/dist/contracts/schemas/aps.schema.d.ts +269 -0
- package/dist/contracts/schemas/aps.schema.d.ts.map +1 -0
- package/dist/contracts/schemas/aps.schema.js +183 -0
- package/dist/contracts/schemas/index.d.ts +12 -0
- package/dist/contracts/schemas/index.d.ts.map +1 -0
- package/dist/contracts/schemas/index.js +14 -0
- package/dist/contracts/schemas/json-schema.d.ts +14 -0
- package/dist/contracts/schemas/json-schema.d.ts.map +1 -0
- package/dist/contracts/schemas/json-schema.js +31 -0
- package/dist/contracts/schemas/warning.schema.d.ts +171 -0
- package/dist/contracts/schemas/warning.schema.d.ts.map +1 -0
- package/dist/contracts/schemas/warning.schema.js +123 -0
- package/dist/contracts/types/gate.types.d.ts +194 -0
- package/dist/contracts/types/gate.types.d.ts.map +1 -0
- package/dist/contracts/types/gate.types.js +19 -0
- package/dist/contracts/types/index.d.ts +9 -0
- package/dist/contracts/types/index.d.ts.map +1 -0
- package/dist/contracts/types/index.js +8 -0
- package/dist/crypto/hash.d.ts +47 -0
- package/dist/crypto/hash.d.ts.map +1 -0
- package/dist/crypto/hash.js +110 -0
- package/dist/crypto/index.d.ts +7 -0
- package/dist/crypto/index.d.ts.map +1 -0
- package/dist/crypto/index.js +6 -0
- package/dist/drift/index.d.ts +6 -0
- package/dist/drift/index.d.ts.map +1 -0
- package/dist/drift/index.js +5 -0
- package/dist/drift/report-generator.d.ts +21 -0
- package/dist/drift/report-generator.d.ts.map +1 -0
- package/dist/drift/report-generator.js +240 -0
- package/dist/drift/snapshot-capture.d.ts +26 -0
- package/dist/drift/snapshot-capture.d.ts.map +1 -0
- package/dist/drift/snapshot-capture.js +195 -0
- package/dist/drift/snapshot-compare.d.ts +50 -0
- package/dist/drift/snapshot-compare.d.ts.map +1 -0
- package/dist/drift/snapshot-compare.js +142 -0
- package/dist/drift/snapshot-schema.d.ts +197 -0
- package/dist/drift/snapshot-schema.d.ts.map +1 -0
- package/dist/drift/snapshot-schema.js +193 -0
- package/dist/drift/snapshot-storage.d.ts +25 -0
- package/dist/drift/snapshot-storage.d.ts.map +1 -0
- package/dist/drift/snapshot-storage.js +179 -0
- package/dist/explain/antipattern-explainer.d.ts +4 -0
- package/dist/explain/antipattern-explainer.d.ts.map +1 -0
- package/dist/explain/antipattern-explainer.js +196 -0
- package/dist/explain/boundary-explainer.d.ts +5 -0
- package/dist/explain/boundary-explainer.d.ts.map +1 -0
- package/dist/explain/boundary-explainer.js +261 -0
- package/dist/explain/explain-service.d.ts +19 -0
- package/dist/explain/explain-service.d.ts.map +1 -0
- package/dist/explain/explain-service.js +106 -0
- package/dist/explain/index.d.ts +7 -0
- package/dist/explain/index.d.ts.map +1 -0
- package/dist/explain/index.js +5 -0
- package/dist/explain/template-loader.d.ts +9 -0
- package/dist/explain/template-loader.d.ts.map +1 -0
- package/dist/explain/template-loader.js +51 -0
- package/dist/explain/types.d.ts +46 -0
- package/dist/explain/types.d.ts.map +1 -0
- package/dist/explain/types.js +31 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/provenance/collector.d.ts +86 -0
- package/dist/provenance/collector.d.ts.map +1 -0
- package/dist/provenance/collector.js +425 -0
- package/dist/provenance/git-ai-standard/git-notes.d.ts +85 -0
- package/dist/provenance/git-ai-standard/git-notes.d.ts.map +1 -0
- package/dist/provenance/git-ai-standard/git-notes.js +292 -0
- package/dist/provenance/git-ai-standard/index.d.ts +44 -0
- package/dist/provenance/git-ai-standard/index.d.ts.map +1 -0
- package/dist/provenance/git-ai-standard/index.js +47 -0
- package/dist/provenance/git-ai-standard/serializer.d.ts +54 -0
- package/dist/provenance/git-ai-standard/serializer.d.ts.map +1 -0
- package/dist/provenance/git-ai-standard/serializer.js +224 -0
- package/dist/provenance/git-ai-standard/session.d.ts +51 -0
- package/dist/provenance/git-ai-standard/session.d.ts.map +1 -0
- package/dist/provenance/git-ai-standard/session.js +118 -0
- package/dist/provenance/git-ai-standard/types.d.ts +173 -0
- package/dist/provenance/git-ai-standard/types.d.ts.map +1 -0
- package/dist/provenance/git-ai-standard/types.js +109 -0
- package/dist/provenance/index.d.ts +5 -0
- package/dist/provenance/index.d.ts.map +1 -0
- package/dist/provenance/index.js +6 -0
- package/dist/provenance/store.d.ts +83 -0
- package/dist/provenance/store.d.ts.map +1 -0
- package/dist/provenance/store.js +248 -0
- package/dist/provenance/types.d.ts +160 -0
- package/dist/provenance/types.d.ts.map +1 -0
- package/dist/provenance/types.js +112 -0
- package/dist/suppression/index.d.ts +4 -0
- package/dist/suppression/index.d.ts.map +1 -0
- package/dist/suppression/index.js +3 -0
- package/dist/suppression/parser.d.ts +31 -0
- package/dist/suppression/parser.d.ts.map +1 -0
- package/dist/suppression/parser.js +219 -0
- package/dist/suppression/service.d.ts +29 -0
- package/dist/suppression/service.d.ts.map +1 -0
- package/dist/suppression/service.js +132 -0
- package/dist/suppression/store.d.ts +61 -0
- package/dist/suppression/store.d.ts.map +1 -0
- package/dist/suppression/store.js +169 -0
- package/dist/utils/debug.d.ts +48 -0
- package/dist/utils/debug.d.ts.map +1 -0
- package/dist/utils/debug.js +100 -0
- package/dist/utils/index.d.ts +4 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +3 -0
- package/dist/utils/path-safety.d.ts +21 -0
- package/dist/utils/path-safety.d.ts.map +1 -0
- package/dist/utils/path-safety.js +49 -0
- package/dist/utils/severity.d.ts +37 -0
- package/dist/utils/severity.d.ts.map +1 -0
- package/dist/utils/severity.js +22 -0
- package/dist/validation/aps-validator.d.ts +66 -0
- package/dist/validation/aps-validator.d.ts.map +1 -0
- package/dist/validation/aps-validator.js +173 -0
- package/dist/validation/errors.d.ts +52 -0
- package/dist/validation/errors.d.ts.map +1 -0
- package/dist/validation/errors.js +115 -0
- package/dist/validation/index.d.ts +8 -0
- package/dist/validation/index.d.ts.map +1 -0
- package/dist/validation/index.js +13 -0
- package/dist/warnings/index.d.ts +2 -0
- package/dist/warnings/index.d.ts.map +1 -0
- package/dist/warnings/index.js +1 -0
- package/dist/warnings/warning-id.d.ts +180 -0
- package/dist/warnings/warning-id.d.ts.map +1 -0
- package/dist/warnings/warning-id.js +257 -0
- package/package.json +79 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { AITool, Environment, GitContext, CheckSummary, ProvenanceRecord } from './types.js';
|
|
2
|
+
import type { GateRunResult } from '../contracts/index.js';
|
|
3
|
+
import { type AuthorshipLog } from './git-ai-standard/index.js';
|
|
4
|
+
/**
|
|
5
|
+
* Collects environment information
|
|
6
|
+
*/
|
|
7
|
+
export declare function collectEnvironment(workspaceRoot: string): Promise<Environment>;
|
|
8
|
+
/**
|
|
9
|
+
* Collects git context information
|
|
10
|
+
*/
|
|
11
|
+
export declare function collectGitContext(workspaceRoot: string): Promise<GitContext | undefined>;
|
|
12
|
+
/**
|
|
13
|
+
* Detects which AI coding tool might have been used
|
|
14
|
+
*/
|
|
15
|
+
export declare function detectAITool(workspaceRoot: string): Promise<AITool | undefined>;
|
|
16
|
+
/**
|
|
17
|
+
* Converts gate results to check summaries
|
|
18
|
+
*/
|
|
19
|
+
export declare function summariseChecks(results: GateRunResult): CheckSummary[];
|
|
20
|
+
/**
|
|
21
|
+
* Creates a full provenance record from a gate run
|
|
22
|
+
*/
|
|
23
|
+
export declare function createProvenanceRecord(params: {
|
|
24
|
+
workspaceRoot: string;
|
|
25
|
+
filesChecked: string[];
|
|
26
|
+
scope: ProvenanceRecord['scope'];
|
|
27
|
+
results: GateRunResult;
|
|
28
|
+
trigger: ProvenanceRecord['trigger'];
|
|
29
|
+
startTime: number;
|
|
30
|
+
planId?: string;
|
|
31
|
+
parentId?: string;
|
|
32
|
+
}): Promise<ProvenanceRecord>;
|
|
33
|
+
/**
|
|
34
|
+
* Formats a provenance record for display
|
|
35
|
+
*/
|
|
36
|
+
export declare function formatProvenanceRecord(record: ProvenanceRecord): string;
|
|
37
|
+
/**
|
|
38
|
+
* Create an AuthorshipLog from provenance context
|
|
39
|
+
*
|
|
40
|
+
* This bridges the Anvil provenance system with the Git AI Standard v3.0.0,
|
|
41
|
+
* enabling AI-generated code to be tracked in Git Notes.
|
|
42
|
+
*
|
|
43
|
+
* @param params - Parameters for creating the authorship log
|
|
44
|
+
* @param params.commitSha - Full 40-character commit SHA (use `git rev-parse` to resolve short refs)
|
|
45
|
+
* @returns AuthorshipLog if AI tool is detected, null otherwise
|
|
46
|
+
* @throws Error if commitSha is not a valid 40-character hex SHA
|
|
47
|
+
*/
|
|
48
|
+
export declare function createAuthorshipLog(params: {
|
|
49
|
+
commitSha: string;
|
|
50
|
+
fileLineMap: Record<string, string>;
|
|
51
|
+
messages: Array<{
|
|
52
|
+
type: 'user' | 'assistant';
|
|
53
|
+
text: string;
|
|
54
|
+
}>;
|
|
55
|
+
humanAuthor?: string;
|
|
56
|
+
totalAdditions?: number;
|
|
57
|
+
totalDeletions?: number;
|
|
58
|
+
}): AuthorshipLog | null;
|
|
59
|
+
/**
|
|
60
|
+
* Attach an AuthorshipLog to a commit via Git Notes
|
|
61
|
+
*
|
|
62
|
+
* @param log - The authorship log to attach
|
|
63
|
+
* @param workspaceRoot - The repository root directory
|
|
64
|
+
*/
|
|
65
|
+
export declare function attachAuthorshipToCommit(log: AuthorshipLog, workspaceRoot: string): Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* Create and attach an AuthorshipLog in one operation
|
|
68
|
+
*
|
|
69
|
+
* Convenience function that combines createAuthorshipLog and attachAuthorshipToCommit.
|
|
70
|
+
*
|
|
71
|
+
* @param params - Parameters for creating the authorship log
|
|
72
|
+
* @param workspaceRoot - The repository root directory
|
|
73
|
+
* @returns true if log was created and attached, false if no AI agent detected
|
|
74
|
+
*/
|
|
75
|
+
export declare function recordAIAuthorship(params: {
|
|
76
|
+
commitSha: string;
|
|
77
|
+
fileLineMap: Record<string, string>;
|
|
78
|
+
messages: Array<{
|
|
79
|
+
type: 'user' | 'assistant';
|
|
80
|
+
text: string;
|
|
81
|
+
}>;
|
|
82
|
+
humanAuthor?: string;
|
|
83
|
+
totalAdditions?: number;
|
|
84
|
+
totalDeletions?: number;
|
|
85
|
+
}, workspaceRoot: string): Promise<boolean>;
|
|
86
|
+
//# sourceMappingURL=collector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collector.d.ts","sourceRoot":"","sources":["../../src/provenance/collector.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAClG,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAE3D,OAAO,EAKL,KAAK,aAAa,EAGnB,MAAM,4BAA4B,CAAC;AAUpC;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAsBpF;AAiCD;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAmE9F;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAqGrF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,aAAa,GAAG,YAAY,EAAE,CAStE;AAED;;GAEG;AACH,wBAAsB,sBAAsB,CAAC,MAAM,EAAE;IACnD,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,KAAK,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACjC,OAAO,EAAE,aAAa,CAAC;IACvB,OAAO,EAAE,gBAAgB,CAAC,SAAS,CAAC,CAAC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA8C5B;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CAqDvE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,GAAG,aAAa,GAAG,IAAI,CA0DvB;AAED;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC5C,GAAG,EAAE,aAAa,EAClB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CAIf;AAED;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE;IACN,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,EACD,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,OAAO,CAAC,CAMlB"}
|
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { randomUUID } from 'node:crypto';
|
|
6
|
+
import { createDebugger } from '../utils/debug.js';
|
|
7
|
+
import { generateSessionHash, detectCurrentAgent, writeAuthorshipNote, SCHEMA_VERSION, } from './git-ai-standard/index.js';
|
|
8
|
+
const debug = createDebugger('provenance');
|
|
9
|
+
const execFileAsync = promisify(execFile);
|
|
10
|
+
function generateProvenanceId() {
|
|
11
|
+
return `prov-${randomUUID()}`;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Collects environment information
|
|
15
|
+
*/
|
|
16
|
+
export async function collectEnvironment(workspaceRoot) {
|
|
17
|
+
let anvilVersion = '0.0.0';
|
|
18
|
+
// Try to get Anvil version from package.json
|
|
19
|
+
try {
|
|
20
|
+
const pkgPath = join(workspaceRoot, 'node_modules', '@anvil', 'cli', 'package.json');
|
|
21
|
+
if (existsSync(pkgPath)) {
|
|
22
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
23
|
+
anvilVersion = pkg.version || '0.0.0';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
debug('Failed to read Anvil CLI package.json for version', error);
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
os: `${process.platform}-${process.arch}`,
|
|
31
|
+
node_version: process.version,
|
|
32
|
+
anvil_version: anvilVersion,
|
|
33
|
+
cwd: workspaceRoot,
|
|
34
|
+
ci: detectCIEnvironment(),
|
|
35
|
+
ci_provider: detectCIProvider(),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Detects if running in a CI environment
|
|
40
|
+
*/
|
|
41
|
+
function detectCIEnvironment() {
|
|
42
|
+
return !!(process.env.CI ||
|
|
43
|
+
process.env.CONTINUOUS_INTEGRATION ||
|
|
44
|
+
process.env.BUILD_NUMBER ||
|
|
45
|
+
process.env.GITHUB_ACTIONS ||
|
|
46
|
+
process.env.GITLAB_CI ||
|
|
47
|
+
process.env.CIRCLECI ||
|
|
48
|
+
process.env.JENKINS_URL ||
|
|
49
|
+
process.env.TRAVIS);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Detects the CI provider
|
|
53
|
+
*/
|
|
54
|
+
function detectCIProvider() {
|
|
55
|
+
if (process.env.GITHUB_ACTIONS)
|
|
56
|
+
return 'github-actions';
|
|
57
|
+
if (process.env.GITLAB_CI)
|
|
58
|
+
return 'gitlab-ci';
|
|
59
|
+
if (process.env.CIRCLECI)
|
|
60
|
+
return 'circleci';
|
|
61
|
+
if (process.env.JENKINS_URL)
|
|
62
|
+
return 'jenkins';
|
|
63
|
+
if (process.env.TRAVIS)
|
|
64
|
+
return 'travis-ci';
|
|
65
|
+
if (process.env.BUILDKITE)
|
|
66
|
+
return 'buildkite';
|
|
67
|
+
if (process.env.AZURE_PIPELINES)
|
|
68
|
+
return 'azure-pipelines';
|
|
69
|
+
if (process.env.BITBUCKET_PIPELINE)
|
|
70
|
+
return 'bitbucket-pipelines';
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Collects git context information
|
|
75
|
+
*/
|
|
76
|
+
export async function collectGitContext(workspaceRoot) {
|
|
77
|
+
// Check if this is a git repository
|
|
78
|
+
if (!existsSync(join(workspaceRoot, '.git'))) {
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
const [branch, commit, commitMessage, author, status, stagedFiles] = await Promise.all([
|
|
83
|
+
execFileAsync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { cwd: workspaceRoot })
|
|
84
|
+
.then((r) => r.stdout.trim())
|
|
85
|
+
.catch(() => undefined),
|
|
86
|
+
execFileAsync('git', ['rev-parse', 'HEAD'], { cwd: workspaceRoot })
|
|
87
|
+
.then((r) => r.stdout.trim())
|
|
88
|
+
.catch(() => undefined),
|
|
89
|
+
execFileAsync('git', ['log', '-1', '--format=%s'], { cwd: workspaceRoot })
|
|
90
|
+
.then((r) => r.stdout.trim())
|
|
91
|
+
.catch(() => undefined),
|
|
92
|
+
execFileAsync('git', ['log', '-1', '--format=%an <%ae>'], { cwd: workspaceRoot })
|
|
93
|
+
.then((r) => r.stdout.trim())
|
|
94
|
+
.catch(() => undefined),
|
|
95
|
+
execFileAsync('git', ['status', '--porcelain'], { cwd: workspaceRoot })
|
|
96
|
+
.then((r) => r.stdout.trim())
|
|
97
|
+
.catch(() => ''),
|
|
98
|
+
execFileAsync('git', ['diff', '--name-only', '--cached'], { cwd: workspaceRoot })
|
|
99
|
+
.then((r) => r.stdout
|
|
100
|
+
.trim()
|
|
101
|
+
.split('\n')
|
|
102
|
+
.filter((f) => f))
|
|
103
|
+
.catch(() => []),
|
|
104
|
+
]);
|
|
105
|
+
// Parse modified files from git status --porcelain
|
|
106
|
+
// Format is "XY filename" where X and Y are status chars (may be spaces)
|
|
107
|
+
// Use regex to extract filename after the 2-char status + space
|
|
108
|
+
const modifiedFiles = status
|
|
109
|
+
.split('\n')
|
|
110
|
+
.filter((line) => line.trim())
|
|
111
|
+
.map((line) => line.replace(/^.{0,2}\s/, '').trim())
|
|
112
|
+
.filter((f) => f);
|
|
113
|
+
// Try to get repository URL
|
|
114
|
+
let repository;
|
|
115
|
+
try {
|
|
116
|
+
const { stdout } = await execFileAsync('git', ['remote', 'get-url', 'origin'], {
|
|
117
|
+
cwd: workspaceRoot,
|
|
118
|
+
});
|
|
119
|
+
repository = stdout.trim();
|
|
120
|
+
}
|
|
121
|
+
catch (error) {
|
|
122
|
+
debug('No git remote configured or failed to get remote URL', error);
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
repository,
|
|
126
|
+
branch,
|
|
127
|
+
commit,
|
|
128
|
+
commit_message: commitMessage,
|
|
129
|
+
author,
|
|
130
|
+
dirty: status.length > 0,
|
|
131
|
+
staged_files: stagedFiles.length > 0 ? stagedFiles : undefined,
|
|
132
|
+
modified_files: modifiedFiles.length > 0 ? modifiedFiles : undefined,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
debug('Failed to collect git context', error);
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Detects which AI coding tool might have been used
|
|
142
|
+
*/
|
|
143
|
+
export async function detectAITool(workspaceRoot) {
|
|
144
|
+
const indicators = [];
|
|
145
|
+
let name = 'unknown';
|
|
146
|
+
let confidence = 'low';
|
|
147
|
+
// Check for Cursor
|
|
148
|
+
if (existsSync(join(workspaceRoot, '.cursor'))) {
|
|
149
|
+
indicators.push('.cursor directory present');
|
|
150
|
+
name = 'cursor';
|
|
151
|
+
confidence = 'high';
|
|
152
|
+
}
|
|
153
|
+
// Check for Copilot
|
|
154
|
+
if (existsSync(join(workspaceRoot, '.github', 'copilot'))) {
|
|
155
|
+
indicators.push('.github/copilot directory present');
|
|
156
|
+
name = 'copilot';
|
|
157
|
+
confidence = 'medium';
|
|
158
|
+
}
|
|
159
|
+
// Check VS Code settings for AI tools
|
|
160
|
+
const vscodePath = join(workspaceRoot, '.vscode', 'settings.json');
|
|
161
|
+
if (existsSync(vscodePath)) {
|
|
162
|
+
try {
|
|
163
|
+
const settings = readFileSync(vscodePath, 'utf-8');
|
|
164
|
+
if (settings.includes('github.copilot')) {
|
|
165
|
+
indicators.push('VS Code Copilot settings found');
|
|
166
|
+
if (name === 'unknown') {
|
|
167
|
+
name = 'copilot';
|
|
168
|
+
confidence = 'medium';
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
if (settings.includes('cursor')) {
|
|
172
|
+
indicators.push('VS Code Cursor settings found');
|
|
173
|
+
if (name === 'unknown') {
|
|
174
|
+
name = 'cursor';
|
|
175
|
+
confidence = 'medium';
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
debug('Failed to parse VS Code settings.json for AI tool detection', error);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
// Check for Claude Code (CLAUDE.md)
|
|
184
|
+
if (existsSync(join(workspaceRoot, 'CLAUDE.md'))) {
|
|
185
|
+
indicators.push('CLAUDE.md present');
|
|
186
|
+
if (name === 'unknown') {
|
|
187
|
+
name = 'claude-code';
|
|
188
|
+
confidence = 'high';
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// Check environment variables
|
|
192
|
+
if (process.env.CURSOR_SESSION) {
|
|
193
|
+
indicators.push('CURSOR_SESSION env var present');
|
|
194
|
+
name = 'cursor';
|
|
195
|
+
confidence = 'high';
|
|
196
|
+
}
|
|
197
|
+
if (process.env.GITHUB_COPILOT_TOKEN) {
|
|
198
|
+
indicators.push('GITHUB_COPILOT_TOKEN env var present');
|
|
199
|
+
name = 'copilot';
|
|
200
|
+
confidence = 'high';
|
|
201
|
+
}
|
|
202
|
+
// Check recent git commits for AI indicators
|
|
203
|
+
try {
|
|
204
|
+
const { stdout } = await execFileAsync('git', ['log', '-5', '--format=%s'], {
|
|
205
|
+
cwd: workspaceRoot,
|
|
206
|
+
});
|
|
207
|
+
const messages = stdout.toLowerCase();
|
|
208
|
+
if (messages.includes('generated by cursor') || messages.includes('cursor:')) {
|
|
209
|
+
indicators.push('Recent commit mentions Cursor');
|
|
210
|
+
name = 'cursor';
|
|
211
|
+
confidence = 'medium';
|
|
212
|
+
}
|
|
213
|
+
if (messages.includes('copilot') || messages.includes('generated by github')) {
|
|
214
|
+
indicators.push('Recent commit mentions Copilot');
|
|
215
|
+
name = 'copilot';
|
|
216
|
+
confidence = 'medium';
|
|
217
|
+
}
|
|
218
|
+
if (messages.includes('claude') || messages.includes('anthropic')) {
|
|
219
|
+
indicators.push('Recent commit mentions Claude');
|
|
220
|
+
name = 'claude-code';
|
|
221
|
+
confidence = 'medium';
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
debug('Git log command failed while detecting AI tool from commits', error);
|
|
226
|
+
}
|
|
227
|
+
// If no indicators found, return undefined
|
|
228
|
+
if (indicators.length === 0) {
|
|
229
|
+
return undefined;
|
|
230
|
+
}
|
|
231
|
+
return {
|
|
232
|
+
name,
|
|
233
|
+
confidence,
|
|
234
|
+
indicators,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Converts gate results to check summaries
|
|
239
|
+
*/
|
|
240
|
+
export function summariseChecks(results) {
|
|
241
|
+
return results.checks.map((check) => ({
|
|
242
|
+
name: check.check,
|
|
243
|
+
passed: check.passed,
|
|
244
|
+
score: check.score,
|
|
245
|
+
issues_count: check.details?.findings
|
|
246
|
+
? check.details.findings.length
|
|
247
|
+
: undefined,
|
|
248
|
+
}));
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Creates a full provenance record from a gate run
|
|
252
|
+
*/
|
|
253
|
+
export async function createProvenanceRecord(params) {
|
|
254
|
+
const { workspaceRoot, filesChecked, scope, results, trigger, startTime, planId, parentId } = params;
|
|
255
|
+
const endTime = Date.now();
|
|
256
|
+
// Collect all context in parallel
|
|
257
|
+
const [environment, gitContext, aiTool] = await Promise.all([
|
|
258
|
+
collectEnvironment(workspaceRoot),
|
|
259
|
+
collectGitContext(workspaceRoot),
|
|
260
|
+
detectAITool(workspaceRoot),
|
|
261
|
+
]);
|
|
262
|
+
// Get current user
|
|
263
|
+
let user;
|
|
264
|
+
try {
|
|
265
|
+
const { stdout } = await execFileAsync('git', ['config', 'user.name']);
|
|
266
|
+
user = stdout.trim() || undefined;
|
|
267
|
+
}
|
|
268
|
+
catch (error) {
|
|
269
|
+
debug('Failed to get git user.name, falling back to env vars', error);
|
|
270
|
+
user = process.env.USER || process.env.USERNAME;
|
|
271
|
+
}
|
|
272
|
+
return {
|
|
273
|
+
id: generateProvenanceId(),
|
|
274
|
+
timestamp: new Date().toISOString(),
|
|
275
|
+
scope,
|
|
276
|
+
files_checked: filesChecked.map((f) => f.replace(workspaceRoot, '').replace(/^\//, '')),
|
|
277
|
+
files_count: filesChecked.length,
|
|
278
|
+
overall_passed: results.overall,
|
|
279
|
+
overall_score: results.score,
|
|
280
|
+
checks: summariseChecks(results),
|
|
281
|
+
environment,
|
|
282
|
+
git: gitContext,
|
|
283
|
+
ai_tool: aiTool,
|
|
284
|
+
plan_id: planId,
|
|
285
|
+
parent_id: parentId,
|
|
286
|
+
trigger,
|
|
287
|
+
duration_ms: endTime - startTime,
|
|
288
|
+
user,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Formats a provenance record for display
|
|
293
|
+
*/
|
|
294
|
+
export function formatProvenanceRecord(record) {
|
|
295
|
+
const lines = [];
|
|
296
|
+
lines.push(`Provenance Record: ${record.id}`);
|
|
297
|
+
lines.push(`${'─'.repeat(50)}`);
|
|
298
|
+
lines.push(`Timestamp: ${record.timestamp}`);
|
|
299
|
+
lines.push(`Duration: ${record.duration_ms}ms`);
|
|
300
|
+
lines.push(`Trigger: ${record.trigger}`);
|
|
301
|
+
lines.push('');
|
|
302
|
+
lines.push('Scope:');
|
|
303
|
+
lines.push(` Type: ${record.scope}`);
|
|
304
|
+
lines.push(` Files: ${record.files_count}`);
|
|
305
|
+
lines.push('');
|
|
306
|
+
lines.push('Results:');
|
|
307
|
+
lines.push(` Overall: ${record.overall_passed ? '✓ PASSED' : '✗ FAILED'}`);
|
|
308
|
+
lines.push(` Score: ${record.overall_score}/100`);
|
|
309
|
+
lines.push(' Checks:');
|
|
310
|
+
for (const check of record.checks) {
|
|
311
|
+
const status = check.passed ? '✓' : '✗';
|
|
312
|
+
const score = check.score !== undefined ? ` (${check.score})` : '';
|
|
313
|
+
lines.push(` ${status} ${check.name}${score}`);
|
|
314
|
+
}
|
|
315
|
+
lines.push('');
|
|
316
|
+
if (record.git) {
|
|
317
|
+
lines.push('Git Context:');
|
|
318
|
+
if (record.git.branch)
|
|
319
|
+
lines.push(` Branch: ${record.git.branch}`);
|
|
320
|
+
if (record.git.commit)
|
|
321
|
+
lines.push(` Commit: ${record.git.commit.substring(0, 8)}`);
|
|
322
|
+
if (record.git.dirty)
|
|
323
|
+
lines.push(` Status: dirty (uncommitted changes)`);
|
|
324
|
+
lines.push('');
|
|
325
|
+
}
|
|
326
|
+
if (record.ai_tool) {
|
|
327
|
+
lines.push('AI Tool Detected:');
|
|
328
|
+
lines.push(` Tool: ${record.ai_tool.name}`);
|
|
329
|
+
lines.push(` Confidence: ${record.ai_tool.confidence}`);
|
|
330
|
+
if (record.ai_tool.indicators) {
|
|
331
|
+
lines.push(` Indicators: ${record.ai_tool.indicators.join(', ')}`);
|
|
332
|
+
}
|
|
333
|
+
lines.push('');
|
|
334
|
+
}
|
|
335
|
+
lines.push('Environment:');
|
|
336
|
+
lines.push(` OS: ${record.environment.os}`);
|
|
337
|
+
lines.push(` Node: ${record.environment.node_version}`);
|
|
338
|
+
lines.push(` Anvil: ${record.environment.anvil_version}`);
|
|
339
|
+
if (record.environment.ci) {
|
|
340
|
+
lines.push(` CI: ${record.environment.ci_provider || 'yes'}`);
|
|
341
|
+
}
|
|
342
|
+
return lines.join('\n');
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Create an AuthorshipLog from provenance context
|
|
346
|
+
*
|
|
347
|
+
* This bridges the Anvil provenance system with the Git AI Standard v3.0.0,
|
|
348
|
+
* enabling AI-generated code to be tracked in Git Notes.
|
|
349
|
+
*
|
|
350
|
+
* @param params - Parameters for creating the authorship log
|
|
351
|
+
* @param params.commitSha - Full 40-character commit SHA (use `git rev-parse` to resolve short refs)
|
|
352
|
+
* @returns AuthorshipLog if AI tool is detected, null otherwise
|
|
353
|
+
* @throws Error if commitSha is not a valid 40-character hex SHA
|
|
354
|
+
*/
|
|
355
|
+
export function createAuthorshipLog(params) {
|
|
356
|
+
const { commitSha, fileLineMap, messages, humanAuthor, totalAdditions = 0, totalDeletions = 0, } = params;
|
|
357
|
+
// Validate commit SHA is a full 40-character hex string
|
|
358
|
+
if (!/^[a-f0-9]{40}$/.test(commitSha)) {
|
|
359
|
+
throw new Error(`commitSha must be a full 40-character hex SHA, got: "${commitSha}". ` +
|
|
360
|
+
'Use `git rev-parse <ref>` to resolve short refs or branch names.');
|
|
361
|
+
}
|
|
362
|
+
// Try to detect the current AI agent
|
|
363
|
+
const agent = detectCurrentAgent();
|
|
364
|
+
if (!agent) {
|
|
365
|
+
debug('No AI agent detected, skipping authorship log creation');
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
const sessionHash = generateSessionHash(agent.tool, agent.id);
|
|
369
|
+
// Build attestations from file→line map
|
|
370
|
+
const attestations = {};
|
|
371
|
+
for (const [file, ranges] of Object.entries(fileLineMap)) {
|
|
372
|
+
attestations[file] = [{ sessionHash, lineRanges: ranges }];
|
|
373
|
+
}
|
|
374
|
+
// Build prompt record
|
|
375
|
+
const promptRecord = {
|
|
376
|
+
agent_id: agent,
|
|
377
|
+
messages: messages.map((m) => ({
|
|
378
|
+
type: m.type,
|
|
379
|
+
text: m.text,
|
|
380
|
+
timestamp: new Date().toISOString(),
|
|
381
|
+
})),
|
|
382
|
+
total_additions: totalAdditions,
|
|
383
|
+
total_deletions: totalDeletions,
|
|
384
|
+
accepted_lines: totalAdditions, // Assume all lines accepted initially
|
|
385
|
+
overridden_lines: 0,
|
|
386
|
+
human_author: humanAuthor,
|
|
387
|
+
};
|
|
388
|
+
return {
|
|
389
|
+
attestations,
|
|
390
|
+
metadata: {
|
|
391
|
+
schema_version: SCHEMA_VERSION,
|
|
392
|
+
base_commit_sha: commitSha,
|
|
393
|
+
prompts: {
|
|
394
|
+
[sessionHash]: promptRecord,
|
|
395
|
+
},
|
|
396
|
+
},
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Attach an AuthorshipLog to a commit via Git Notes
|
|
401
|
+
*
|
|
402
|
+
* @param log - The authorship log to attach
|
|
403
|
+
* @param workspaceRoot - The repository root directory
|
|
404
|
+
*/
|
|
405
|
+
export async function attachAuthorshipToCommit(log, workspaceRoot) {
|
|
406
|
+
const commitSha = log.metadata.base_commit_sha;
|
|
407
|
+
await writeAuthorshipNote(commitSha, log, workspaceRoot);
|
|
408
|
+
debug(`Attached authorship log to commit ${commitSha.slice(0, 8)}`);
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Create and attach an AuthorshipLog in one operation
|
|
412
|
+
*
|
|
413
|
+
* Convenience function that combines createAuthorshipLog and attachAuthorshipToCommit.
|
|
414
|
+
*
|
|
415
|
+
* @param params - Parameters for creating the authorship log
|
|
416
|
+
* @param workspaceRoot - The repository root directory
|
|
417
|
+
* @returns true if log was created and attached, false if no AI agent detected
|
|
418
|
+
*/
|
|
419
|
+
export async function recordAIAuthorship(params, workspaceRoot) {
|
|
420
|
+
const log = createAuthorshipLog(params);
|
|
421
|
+
if (!log)
|
|
422
|
+
return false;
|
|
423
|
+
await attachAuthorshipToCommit(log, workspaceRoot);
|
|
424
|
+
return true;
|
|
425
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import type { AuthorshipLog } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Git Notes namespace for AI authorship logs
|
|
4
|
+
* Per Git AI Standard v3.0.0
|
|
5
|
+
*/
|
|
6
|
+
export declare const NOTES_REF = "refs/notes/ai";
|
|
7
|
+
/**
|
|
8
|
+
* Write an authorship log to Git Notes for a commit
|
|
9
|
+
*
|
|
10
|
+
* @param commitSha - The commit SHA to attach the note to
|
|
11
|
+
* @param log - The authorship log to write
|
|
12
|
+
* @param workspaceRoot - The repository root directory
|
|
13
|
+
*/
|
|
14
|
+
export declare function writeAuthorshipNote(commitSha: string, log: AuthorshipLog, workspaceRoot: string): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Read an authorship log from Git Notes for a commit
|
|
17
|
+
*
|
|
18
|
+
* @param commitSha - The commit SHA to read the note from (or 'HEAD')
|
|
19
|
+
* @param workspaceRoot - The repository root directory
|
|
20
|
+
* @returns The parsed AuthorshipLog, or null if no note exists
|
|
21
|
+
*/
|
|
22
|
+
export declare function readAuthorshipNote(commitSha: string, workspaceRoot: string): Promise<AuthorshipLog | null>;
|
|
23
|
+
/**
|
|
24
|
+
* List all commits with authorship notes
|
|
25
|
+
*
|
|
26
|
+
* @param workspaceRoot - The repository root directory
|
|
27
|
+
* @returns Array of commit SHAs that have authorship notes
|
|
28
|
+
*/
|
|
29
|
+
export declare function listAuthorshipNotes(workspaceRoot: string): Promise<string[]>;
|
|
30
|
+
/**
|
|
31
|
+
* Remove an authorship note from a commit
|
|
32
|
+
*
|
|
33
|
+
* @param commitSha - The commit SHA to remove the note from
|
|
34
|
+
* @param workspaceRoot - The repository root directory
|
|
35
|
+
* @returns true if the note was removed, false if it didn't exist
|
|
36
|
+
*/
|
|
37
|
+
export declare function removeAuthorshipNote(commitSha: string, workspaceRoot: string): Promise<boolean>;
|
|
38
|
+
/**
|
|
39
|
+
* Copy authorship note when rebasing (from old SHA to new SHA)
|
|
40
|
+
*
|
|
41
|
+
* Updates the base_commit_sha in metadata to point to the new commit.
|
|
42
|
+
*
|
|
43
|
+
* @param fromSha - The original commit SHA
|
|
44
|
+
* @param toSha - The new commit SHA after rebase
|
|
45
|
+
* @param workspaceRoot - The repository root directory
|
|
46
|
+
* @returns true if the note was copied, false if source note didn't exist
|
|
47
|
+
*/
|
|
48
|
+
export declare function copyAuthorshipNote(fromSha: string, toSha: string, workspaceRoot: string): Promise<boolean>;
|
|
49
|
+
/**
|
|
50
|
+
* Push authorship notes to remote
|
|
51
|
+
*
|
|
52
|
+
* @param remote - Remote name (e.g., 'origin')
|
|
53
|
+
* @param workspaceRoot - The repository root directory
|
|
54
|
+
*/
|
|
55
|
+
export declare function pushAuthorshipNotes(remote: string, workspaceRoot: string): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Fetch authorship notes from remote
|
|
58
|
+
*
|
|
59
|
+
* @param remote - Remote name (e.g., 'origin')
|
|
60
|
+
* @param workspaceRoot - The repository root directory
|
|
61
|
+
*/
|
|
62
|
+
export declare function fetchAuthorshipNotes(remote: string, workspaceRoot: string): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Check if a commit has an authorship note
|
|
65
|
+
*
|
|
66
|
+
* @param commitSha - The commit SHA to check
|
|
67
|
+
* @param workspaceRoot - The repository root directory
|
|
68
|
+
* @returns true if the commit has an authorship note
|
|
69
|
+
*/
|
|
70
|
+
export declare function hasAuthorshipNote(commitSha: string, workspaceRoot: string): Promise<boolean>;
|
|
71
|
+
/**
|
|
72
|
+
* Get summary statistics of AI authorship in a range of commits
|
|
73
|
+
*
|
|
74
|
+
* @param range - Git revision range (e.g., 'main..HEAD', 'HEAD~10..HEAD')
|
|
75
|
+
* @param workspaceRoot - The repository root directory
|
|
76
|
+
* @returns Summary object with counts
|
|
77
|
+
*/
|
|
78
|
+
export declare function getAuthorshipStats(range: string, workspaceRoot: string): Promise<{
|
|
79
|
+
totalCommits: number;
|
|
80
|
+
commitsWithAI: number;
|
|
81
|
+
totalAdditions: number;
|
|
82
|
+
totalDeletions: number;
|
|
83
|
+
tools: Record<string, number>;
|
|
84
|
+
}>;
|
|
85
|
+
//# sourceMappingURL=git-notes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-notes.d.ts","sourceRoot":"","sources":["../../../src/provenance/git-ai-standard/git-notes.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AA8BhD;;;GAGG;AACH,eAAO,MAAM,SAAS,kBAAkB,CAAC;AAEzC;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,aAAa,EAClB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,IAAI,CAAC,CAsCf;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC,CAoB/B;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAiBlF;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,OAAO,CAAC,CAelB;AAED;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,OAAO,CAAC,CA+BlB;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAc9F;AAED;;;;;GAKG;AACH,wBAAsB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAc/F;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,OAAO,CAAC,CAalB;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EACb,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC;IACT,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B,CAAC,CA+CD"}
|