trellis 2.0.13 → 2.1.2
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/dist/cli/index.js +1 -1
- package/dist/embeddings/index.js +1 -1
- package/dist/{index-7gvjxt27.js → index-2917tjd8.js} +1 -1
- package/package.json +2 -10
- package/dist/transformers.node-bx3q9d7k.js +0 -33130
- package/src/cli/index.ts +0 -3356
- package/src/core/agents/harness.ts +0 -380
- package/src/core/agents/index.ts +0 -18
- package/src/core/agents/types.ts +0 -90
- package/src/core/index.ts +0 -118
- package/src/core/kernel/middleware.ts +0 -44
- package/src/core/kernel/trellis-kernel.ts +0 -593
- package/src/core/ontology/builtins.ts +0 -248
- package/src/core/ontology/index.ts +0 -34
- package/src/core/ontology/registry.ts +0 -209
- package/src/core/ontology/types.ts +0 -124
- package/src/core/ontology/validator.ts +0 -382
- package/src/core/persist/backend.ts +0 -74
- package/src/core/persist/sqlite-backend.ts +0 -298
- package/src/core/plugins/index.ts +0 -17
- package/src/core/plugins/registry.ts +0 -322
- package/src/core/plugins/types.ts +0 -126
- package/src/core/query/datalog.ts +0 -188
- package/src/core/query/engine.ts +0 -370
- package/src/core/query/index.ts +0 -34
- package/src/core/query/parser.ts +0 -481
- package/src/core/query/types.ts +0 -200
- package/src/core/store/eav-store.ts +0 -467
- package/src/decisions/auto-capture.ts +0 -136
- package/src/decisions/hooks.ts +0 -163
- package/src/decisions/index.ts +0 -261
- package/src/decisions/types.ts +0 -103
- package/src/embeddings/auto-embed.ts +0 -248
- package/src/embeddings/chunker.ts +0 -327
- package/src/embeddings/index.ts +0 -48
- package/src/embeddings/model.ts +0 -112
- package/src/embeddings/search.ts +0 -305
- package/src/embeddings/store.ts +0 -313
- package/src/embeddings/types.ts +0 -92
- package/src/engine.ts +0 -1125
- package/src/garden/cluster.ts +0 -330
- package/src/garden/garden.ts +0 -306
- package/src/garden/index.ts +0 -29
- package/src/git/git-exporter.ts +0 -286
- package/src/git/git-importer.ts +0 -329
- package/src/git/git-reader.ts +0 -189
- package/src/git/index.ts +0 -22
- package/src/identity/governance.ts +0 -211
- package/src/identity/identity.ts +0 -224
- package/src/identity/index.ts +0 -30
- package/src/identity/signing-middleware.ts +0 -97
- package/src/index.ts +0 -29
- package/src/links/index.ts +0 -49
- package/src/links/lifecycle.ts +0 -400
- package/src/links/parser.ts +0 -484
- package/src/links/ref-index.ts +0 -186
- package/src/links/resolver.ts +0 -314
- package/src/links/types.ts +0 -108
- package/src/mcp/index.ts +0 -22
- package/src/mcp/server.ts +0 -1278
- package/src/semantic/csharp-parser.ts +0 -493
- package/src/semantic/go-parser.ts +0 -585
- package/src/semantic/index.ts +0 -34
- package/src/semantic/java-parser.ts +0 -456
- package/src/semantic/python-parser.ts +0 -659
- package/src/semantic/ruby-parser.ts +0 -446
- package/src/semantic/rust-parser.ts +0 -784
- package/src/semantic/semantic-merge.ts +0 -210
- package/src/semantic/ts-parser.ts +0 -681
- package/src/semantic/types.ts +0 -175
- package/src/sync/http-transport.ts +0 -144
- package/src/sync/index.ts +0 -43
- package/src/sync/memory-transport.ts +0 -66
- package/src/sync/multi-repo.ts +0 -200
- package/src/sync/reconciler.ts +0 -237
- package/src/sync/sync-engine.ts +0 -258
- package/src/sync/types.ts +0 -104
- package/src/sync/ws-transport.ts +0 -145
- package/src/ui/client.html +0 -695
- package/src/ui/server.ts +0 -419
- package/src/vcs/blob-store.ts +0 -124
- package/src/vcs/branch.ts +0 -150
- package/src/vcs/checkpoint.ts +0 -64
- package/src/vcs/decompose.ts +0 -469
- package/src/vcs/diff.ts +0 -409
- package/src/vcs/engine-context.ts +0 -26
- package/src/vcs/index.ts +0 -23
- package/src/vcs/issue.ts +0 -800
- package/src/vcs/merge.ts +0 -425
- package/src/vcs/milestone.ts +0 -124
- package/src/vcs/ops.ts +0 -59
- package/src/vcs/types.ts +0 -213
- package/src/vcs/vcs-middleware.ts +0 -81
- package/src/watcher/fs-watcher.ts +0 -255
- package/src/watcher/index.ts +0 -9
- package/src/watcher/ingestion.ts +0 -116
package/src/git/git-reader.ts
DELETED
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Git Reader
|
|
3
|
-
*
|
|
4
|
-
* Reads a Git repository's commit graph and file-level diffs
|
|
5
|
-
* by shelling out to `git`. No libgit2 dependency.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { execSync } from 'child_process';
|
|
9
|
-
import { existsSync } from 'fs';
|
|
10
|
-
import { join } from 'path';
|
|
11
|
-
|
|
12
|
-
// ---------------------------------------------------------------------------
|
|
13
|
-
// Types
|
|
14
|
-
// ---------------------------------------------------------------------------
|
|
15
|
-
|
|
16
|
-
export interface GitCommit {
|
|
17
|
-
hash: string;
|
|
18
|
-
authorName: string;
|
|
19
|
-
authorEmail: string;
|
|
20
|
-
timestamp: string; // ISO 8601
|
|
21
|
-
message: string;
|
|
22
|
-
parentHashes: string[];
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface GitFileChange {
|
|
26
|
-
status: 'A' | 'M' | 'D' | 'R'; // Added, Modified, Deleted, Renamed
|
|
27
|
-
path: string;
|
|
28
|
-
oldPath?: string; // only for renames
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface GitCommitWithChanges extends GitCommit {
|
|
32
|
-
changes: GitFileChange[];
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// ---------------------------------------------------------------------------
|
|
36
|
-
// Reader
|
|
37
|
-
// ---------------------------------------------------------------------------
|
|
38
|
-
|
|
39
|
-
export class GitReader {
|
|
40
|
-
private repoPath: string;
|
|
41
|
-
|
|
42
|
-
constructor(repoPath: string) {
|
|
43
|
-
this.repoPath = repoPath;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Verifies this is a valid Git repository.
|
|
48
|
-
*/
|
|
49
|
-
isGitRepo(): boolean {
|
|
50
|
-
return existsSync(join(this.repoPath, '.git'));
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Returns all commits in topological order (oldest first).
|
|
55
|
-
*/
|
|
56
|
-
readCommits(): GitCommit[] {
|
|
57
|
-
// Format: hash|authorName|authorEmail|isoTimestamp|parentHashes|subject
|
|
58
|
-
const SEP = '‖'; // unlikely to appear in commit messages
|
|
59
|
-
const format = `%H${SEP}%an${SEP}%ae${SEP}%aI${SEP}%P${SEP}%s`;
|
|
60
|
-
|
|
61
|
-
const raw = this.git(`log --all --reverse --format="${format}"`);
|
|
62
|
-
if (!raw.trim()) {
|
|
63
|
-
return [];
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return raw
|
|
67
|
-
.trim()
|
|
68
|
-
.split('\n')
|
|
69
|
-
.map((line) => {
|
|
70
|
-
const parts = line.split(SEP);
|
|
71
|
-
return {
|
|
72
|
-
hash: parts[0],
|
|
73
|
-
authorName: parts[1],
|
|
74
|
-
authorEmail: parts[2],
|
|
75
|
-
timestamp: parts[3],
|
|
76
|
-
parentHashes: parts[4] ? parts[4].split(' ').filter(Boolean) : [],
|
|
77
|
-
message: parts[5] ?? '',
|
|
78
|
-
};
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Returns file changes for a specific commit.
|
|
84
|
-
* For the root commit (no parents), diffs against empty tree.
|
|
85
|
-
*/
|
|
86
|
-
readChanges(commitHash: string, parentHash?: string): GitFileChange[] {
|
|
87
|
-
let raw: string;
|
|
88
|
-
|
|
89
|
-
if (parentHash) {
|
|
90
|
-
// Diff between parent and this commit
|
|
91
|
-
raw = this.git(
|
|
92
|
-
`diff-tree -r --name-status --no-commit-id -M ${parentHash} ${commitHash}`,
|
|
93
|
-
);
|
|
94
|
-
} else {
|
|
95
|
-
// Root commit: use --root flag to diff against empty tree
|
|
96
|
-
raw = this.git(
|
|
97
|
-
`diff-tree -r --root --name-status --no-commit-id -M ${commitHash}`,
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (!raw.trim()) {
|
|
102
|
-
return [];
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return raw
|
|
106
|
-
.trim()
|
|
107
|
-
.split('\n')
|
|
108
|
-
.map((line) => {
|
|
109
|
-
const parts = line.split('\t');
|
|
110
|
-
const statusCode = parts[0].charAt(0) as 'A' | 'M' | 'D' | 'R';
|
|
111
|
-
|
|
112
|
-
if (statusCode === 'R') {
|
|
113
|
-
// Rename: R100\toldPath\tnewPath
|
|
114
|
-
return { status: 'R', oldPath: parts[1], path: parts[2] };
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
return { status: statusCode, path: parts[1] };
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/**
|
|
122
|
-
* Returns the full content of a file at a specific commit.
|
|
123
|
-
*/
|
|
124
|
-
readFileContent(commitHash: string, filePath: string): Buffer | null {
|
|
125
|
-
try {
|
|
126
|
-
return Buffer.from(this.gitBuffer(`show ${commitHash}:${filePath}`));
|
|
127
|
-
} catch {
|
|
128
|
-
return null;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Reads all commits with their file changes in topological order.
|
|
134
|
-
* This is the main entry point for the import pipeline.
|
|
135
|
-
*/
|
|
136
|
-
readFullHistory(): GitCommitWithChanges[] {
|
|
137
|
-
const commits = this.readCommits();
|
|
138
|
-
|
|
139
|
-
return commits.map((commit) => {
|
|
140
|
-
const parentHash = commit.parentHashes[0]; // first parent for changes
|
|
141
|
-
const changes = this.readChanges(commit.hash, parentHash);
|
|
142
|
-
return { ...commit, changes };
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Returns the total number of commits.
|
|
148
|
-
*/
|
|
149
|
-
commitCount(): number {
|
|
150
|
-
const raw = this.git('rev-list --all --count');
|
|
151
|
-
return parseInt(raw.trim(), 10) || 0;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Returns the current branch name.
|
|
156
|
-
*/
|
|
157
|
-
currentBranch(): string {
|
|
158
|
-
try {
|
|
159
|
-
return this.git('rev-parse --abbrev-ref HEAD').trim();
|
|
160
|
-
} catch {
|
|
161
|
-
return 'main';
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* Returns all branch names.
|
|
167
|
-
*/
|
|
168
|
-
branches(): string[] {
|
|
169
|
-
const raw = this.git('branch --format="%(refname:short)"');
|
|
170
|
-
return raw.trim().split('\n').filter(Boolean);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// ---------------------------------------------------------------------------
|
|
174
|
-
// Internals
|
|
175
|
-
// ---------------------------------------------------------------------------
|
|
176
|
-
|
|
177
|
-
private git(args: string): string {
|
|
178
|
-
return execSync(`git -C "${this.repoPath}" ${args}`, {
|
|
179
|
-
encoding: 'utf-8',
|
|
180
|
-
maxBuffer: 100 * 1024 * 1024, // 100MB for large repos
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
private gitBuffer(args: string): Buffer {
|
|
185
|
-
return execSync(`git -C "${this.repoPath}" ${args}`, {
|
|
186
|
-
maxBuffer: 100 * 1024 * 1024,
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
}
|
package/src/git/index.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Git Bridge — Public Surface
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export { GitReader } from './git-reader.js';
|
|
6
|
-
export { importFromGit } from './git-importer.js';
|
|
7
|
-
export { exportToGit } from './git-exporter.js';
|
|
8
|
-
export type {
|
|
9
|
-
ImportOptions,
|
|
10
|
-
ImportResult,
|
|
11
|
-
ImportProgress,
|
|
12
|
-
} from './git-importer.js';
|
|
13
|
-
export type {
|
|
14
|
-
ExportOptions,
|
|
15
|
-
ExportResult,
|
|
16
|
-
ExportProgress,
|
|
17
|
-
} from './git-exporter.js';
|
|
18
|
-
export type {
|
|
19
|
-
GitCommit,
|
|
20
|
-
GitFileChange,
|
|
21
|
-
GitCommitWithChanges,
|
|
22
|
-
} from './git-reader.js';
|
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Governance Module
|
|
3
|
-
*
|
|
4
|
-
* DESIGN.md §6.3–6.4 — Policy nodes and governance enforcement.
|
|
5
|
-
*
|
|
6
|
-
* Policy rules are expressed as EAV entities. The governance engine evaluates
|
|
7
|
-
* ops against applicable policies before allowing them through.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import type { VcsOp } from '../vcs/types.js';
|
|
11
|
-
import type { IdentityResolver } from './signing-middleware.js';
|
|
12
|
-
import { verifySignature } from './identity.js';
|
|
13
|
-
|
|
14
|
-
// ---------------------------------------------------------------------------
|
|
15
|
-
// Types
|
|
16
|
-
// ---------------------------------------------------------------------------
|
|
17
|
-
|
|
18
|
-
export interface PolicyRule {
|
|
19
|
-
id: string;
|
|
20
|
-
/** What this policy protects. */
|
|
21
|
-
target: 'branch' | 'path' | 'entityType';
|
|
22
|
-
targetPattern: string;
|
|
23
|
-
/** What action requires authorization. */
|
|
24
|
-
action: 'push' | 'merge' | 'createMilestone' | 'deleteBranch';
|
|
25
|
-
/** Who is authorized (identity entity IDs). */
|
|
26
|
-
requiredSigners: string[];
|
|
27
|
-
/** Minimum number of valid signatures required. */
|
|
28
|
-
minSignatures: number;
|
|
29
|
-
/** Optional: require CI attestation. */
|
|
30
|
-
requireAttestation?: {
|
|
31
|
-
type: 'test-pass' | 'build-pass' | 'review-approved';
|
|
32
|
-
from: string;
|
|
33
|
-
};
|
|
34
|
-
/** Whether this policy is active. */
|
|
35
|
-
enabled: boolean;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export interface PolicyViolation {
|
|
39
|
-
policyId: string;
|
|
40
|
-
op: VcsOp;
|
|
41
|
-
reason: string;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export interface GovernanceResult {
|
|
45
|
-
allowed: boolean;
|
|
46
|
-
violations: PolicyViolation[];
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// ---------------------------------------------------------------------------
|
|
50
|
-
// Op → action mapping
|
|
51
|
-
// ---------------------------------------------------------------------------
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Determine which governance action an op corresponds to.
|
|
55
|
-
*/
|
|
56
|
-
function opToAction(op: VcsOp): string | null {
|
|
57
|
-
switch (op.kind) {
|
|
58
|
-
case 'vcs:branchDelete':
|
|
59
|
-
return 'deleteBranch';
|
|
60
|
-
case 'vcs:milestoneCreate':
|
|
61
|
-
return 'createMilestone';
|
|
62
|
-
case 'vcs:merge':
|
|
63
|
-
return 'merge';
|
|
64
|
-
case 'vcs:fileAdd':
|
|
65
|
-
case 'vcs:fileModify':
|
|
66
|
-
case 'vcs:fileDelete':
|
|
67
|
-
case 'vcs:fileRename':
|
|
68
|
-
case 'vcs:branchAdvance':
|
|
69
|
-
return 'push';
|
|
70
|
-
default:
|
|
71
|
-
return null;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Check if an op's target matches a policy's target pattern.
|
|
77
|
-
*/
|
|
78
|
-
function matchesTarget(op: VcsOp, policy: PolicyRule): boolean {
|
|
79
|
-
switch (policy.target) {
|
|
80
|
-
case 'branch': {
|
|
81
|
-
const branchName = op.vcs?.branchName ?? op.vcs?.sourceBranch;
|
|
82
|
-
if (!branchName) return false;
|
|
83
|
-
return matchGlob(branchName, policy.targetPattern);
|
|
84
|
-
}
|
|
85
|
-
case 'path': {
|
|
86
|
-
const filePath = op.vcs?.filePath;
|
|
87
|
-
if (!filePath) return false;
|
|
88
|
-
return matchGlob(filePath, policy.targetPattern);
|
|
89
|
-
}
|
|
90
|
-
case 'entityType': {
|
|
91
|
-
return op.kind.includes(policy.targetPattern.toLowerCase());
|
|
92
|
-
}
|
|
93
|
-
default:
|
|
94
|
-
return false;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// ---------------------------------------------------------------------------
|
|
99
|
-
// Policy evaluation
|
|
100
|
-
// ---------------------------------------------------------------------------
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Evaluate an op against a set of policies.
|
|
104
|
-
*/
|
|
105
|
-
export function evaluatePolicy(
|
|
106
|
-
op: VcsOp,
|
|
107
|
-
policies: PolicyRule[],
|
|
108
|
-
resolver: IdentityResolver,
|
|
109
|
-
): GovernanceResult {
|
|
110
|
-
const violations: PolicyViolation[] = [];
|
|
111
|
-
const action = opToAction(op);
|
|
112
|
-
|
|
113
|
-
if (!action) {
|
|
114
|
-
return { allowed: true, violations: [] };
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const applicable = policies.filter(
|
|
118
|
-
(p) => p.enabled && p.action === action && matchesTarget(op, p),
|
|
119
|
-
);
|
|
120
|
-
|
|
121
|
-
for (const policy of applicable) {
|
|
122
|
-
// Check signature requirements
|
|
123
|
-
if (policy.minSignatures > 0) {
|
|
124
|
-
const validSigners = countValidSigners(op, policy, resolver);
|
|
125
|
-
|
|
126
|
-
if (validSigners < policy.minSignatures) {
|
|
127
|
-
violations.push({
|
|
128
|
-
policyId: policy.id,
|
|
129
|
-
op,
|
|
130
|
-
reason:
|
|
131
|
-
`Policy '${policy.id}' requires ${policy.minSignatures} signature(s) ` +
|
|
132
|
-
`from [${policy.requiredSigners.join(', ')}], got ${validSigners}.`,
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
return {
|
|
139
|
-
allowed: violations.length === 0,
|
|
140
|
-
violations,
|
|
141
|
-
};
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Count how many valid required signers signed the op.
|
|
146
|
-
*/
|
|
147
|
-
function countValidSigners(
|
|
148
|
-
op: VcsOp,
|
|
149
|
-
policy: PolicyRule,
|
|
150
|
-
resolver: IdentityResolver,
|
|
151
|
-
): number {
|
|
152
|
-
if (!op.vcs?.signature || !op.vcs?.signedBy) return 0;
|
|
153
|
-
|
|
154
|
-
// Check if the signer is in the required signers list
|
|
155
|
-
if (!policy.requiredSigners.includes(op.vcs.signedBy)) return 0;
|
|
156
|
-
|
|
157
|
-
// Verify signature
|
|
158
|
-
const publicKey = resolver.resolvePublicKey(op.vcs.signedBy);
|
|
159
|
-
if (!publicKey) return 0;
|
|
160
|
-
|
|
161
|
-
const valid = verifySignature(op.hash, op.vcs.signature, publicKey);
|
|
162
|
-
return valid ? 1 : 0;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
// ---------------------------------------------------------------------------
|
|
166
|
-
// Policy CRUD helpers
|
|
167
|
-
// ---------------------------------------------------------------------------
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Create a new policy rule.
|
|
171
|
-
*/
|
|
172
|
-
export function createPolicy(opts: {
|
|
173
|
-
id: string;
|
|
174
|
-
target: PolicyRule['target'];
|
|
175
|
-
targetPattern: string;
|
|
176
|
-
action: PolicyRule['action'];
|
|
177
|
-
requiredSigners: string[];
|
|
178
|
-
minSignatures?: number;
|
|
179
|
-
}): PolicyRule {
|
|
180
|
-
return {
|
|
181
|
-
id: opts.id,
|
|
182
|
-
target: opts.target,
|
|
183
|
-
targetPattern: opts.targetPattern,
|
|
184
|
-
action: opts.action,
|
|
185
|
-
requiredSigners: opts.requiredSigners,
|
|
186
|
-
minSignatures: opts.minSignatures ?? 1,
|
|
187
|
-
enabled: true,
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
// ---------------------------------------------------------------------------
|
|
192
|
-
// Helpers
|
|
193
|
-
// ---------------------------------------------------------------------------
|
|
194
|
-
|
|
195
|
-
/**
|
|
196
|
-
* Simple glob matcher supporting * and ** patterns.
|
|
197
|
-
*/
|
|
198
|
-
function matchGlob(value: string, pattern: string): boolean {
|
|
199
|
-
if (pattern === '*' || pattern === '**') return true;
|
|
200
|
-
if (pattern === value) return true;
|
|
201
|
-
|
|
202
|
-
// Convert glob to regex
|
|
203
|
-
const escaped = pattern
|
|
204
|
-
.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
|
205
|
-
.replace(/\*\*/g, '{{DOUBLESTAR}}')
|
|
206
|
-
.replace(/\*/g, '[^/]*')
|
|
207
|
-
.replace(/\{\{DOUBLESTAR\}\}/g, '.*');
|
|
208
|
-
|
|
209
|
-
const regex = new RegExp(`^${escaped}$`);
|
|
210
|
-
return regex.test(value);
|
|
211
|
-
}
|
package/src/identity/identity.ts
DELETED
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Identity Module
|
|
3
|
-
*
|
|
4
|
-
* Ed25519 key pair generation, DID derivation, and local identity storage.
|
|
5
|
-
* DESIGN.md §6.1 — Every actor is an Identity entity with a cryptographic key pair.
|
|
6
|
-
*
|
|
7
|
-
* Private keys are stored locally in `.trellis/identity.json` (never synced).
|
|
8
|
-
* Public keys and DIDs are graph entities that get replicated to peers.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import {
|
|
12
|
-
generateKeyPairSync,
|
|
13
|
-
sign,
|
|
14
|
-
verify,
|
|
15
|
-
createPublicKey,
|
|
16
|
-
type KeyObject,
|
|
17
|
-
} from 'crypto';
|
|
18
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
19
|
-
import { join, dirname } from 'path';
|
|
20
|
-
|
|
21
|
-
// ---------------------------------------------------------------------------
|
|
22
|
-
// Types
|
|
23
|
-
// ---------------------------------------------------------------------------
|
|
24
|
-
|
|
25
|
-
export interface IdentityConfig {
|
|
26
|
-
displayName: string;
|
|
27
|
-
email?: string;
|
|
28
|
-
/** Ed25519 public key, base64-encoded. */
|
|
29
|
-
publicKey: string;
|
|
30
|
-
/** Ed25519 private key, base64-encoded (local only, never synced). */
|
|
31
|
-
privateKey: string;
|
|
32
|
-
/** did:key identifier derived from public key. */
|
|
33
|
-
did: string;
|
|
34
|
-
/** Entity ID for use in the EAV store. */
|
|
35
|
-
entityId: string;
|
|
36
|
-
/** ISO timestamp of creation. */
|
|
37
|
-
createdAt: string;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export interface PublicIdentity {
|
|
41
|
-
displayName: string;
|
|
42
|
-
email?: string;
|
|
43
|
-
publicKey: string;
|
|
44
|
-
did: string;
|
|
45
|
-
entityId: string;
|
|
46
|
-
createdAt: string;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// ---------------------------------------------------------------------------
|
|
50
|
-
// Key generation
|
|
51
|
-
// ---------------------------------------------------------------------------
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Generate a new Ed25519 identity.
|
|
55
|
-
*/
|
|
56
|
-
export function createIdentity(opts: {
|
|
57
|
-
displayName: string;
|
|
58
|
-
email?: string;
|
|
59
|
-
}): IdentityConfig {
|
|
60
|
-
const { publicKey, privateKey } = generateKeyPairSync('ed25519');
|
|
61
|
-
|
|
62
|
-
const pubDer = publicKey.export({ type: 'spki', format: 'der' });
|
|
63
|
-
const privDer = privateKey.export({ type: 'pkcs8', format: 'der' });
|
|
64
|
-
|
|
65
|
-
// Extract raw 32-byte public key from SPKI DER (last 32 bytes)
|
|
66
|
-
const rawPub = pubDer.subarray(pubDer.length - 32);
|
|
67
|
-
|
|
68
|
-
const did = deriveDid(rawPub);
|
|
69
|
-
const entityId = `identity:${did}`;
|
|
70
|
-
|
|
71
|
-
return {
|
|
72
|
-
displayName: opts.displayName,
|
|
73
|
-
email: opts.email,
|
|
74
|
-
publicKey: pubDer.toString('base64'),
|
|
75
|
-
privateKey: privDer.toString('base64'),
|
|
76
|
-
did,
|
|
77
|
-
entityId,
|
|
78
|
-
createdAt: new Date().toISOString(),
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Derive a did:key identifier from a raw Ed25519 public key.
|
|
84
|
-
* Format: did:key:z6Mk... (multicodec 0xed01 prefix + base58btc)
|
|
85
|
-
*/
|
|
86
|
-
function deriveDid(rawPublicKey: Buffer | Uint8Array): string {
|
|
87
|
-
// Multicodec prefix for Ed25519 public key: 0xed 0x01
|
|
88
|
-
const multicodec = Buffer.concat([
|
|
89
|
-
Buffer.from([0xed, 0x01]),
|
|
90
|
-
Buffer.from(rawPublicKey),
|
|
91
|
-
]);
|
|
92
|
-
// Base58btc encoding
|
|
93
|
-
const encoded = base58btcEncode(multicodec);
|
|
94
|
-
return `did:key:z${encoded}`;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// ---------------------------------------------------------------------------
|
|
98
|
-
// Op signing / verification
|
|
99
|
-
// ---------------------------------------------------------------------------
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Sign a message (typically an op hash) with a private key.
|
|
103
|
-
*/
|
|
104
|
-
export function signMessage(
|
|
105
|
-
message: string,
|
|
106
|
-
privateKeyBase64: string,
|
|
107
|
-
): string {
|
|
108
|
-
const privDer = Buffer.from(privateKeyBase64, 'base64');
|
|
109
|
-
const privateKey = createPrivateKeyFromDer(privDer);
|
|
110
|
-
const sig = sign(null, Buffer.from(message, 'utf-8'), privateKey);
|
|
111
|
-
return sig.toString('base64');
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Verify a signature against a message and public key.
|
|
116
|
-
*/
|
|
117
|
-
export function verifySignature(
|
|
118
|
-
message: string,
|
|
119
|
-
signatureBase64: string,
|
|
120
|
-
publicKeyBase64: string,
|
|
121
|
-
): boolean {
|
|
122
|
-
const pubDer = Buffer.from(publicKeyBase64, 'base64');
|
|
123
|
-
const publicKey = createPublicKey({
|
|
124
|
-
key: pubDer,
|
|
125
|
-
format: 'der',
|
|
126
|
-
type: 'spki',
|
|
127
|
-
});
|
|
128
|
-
const sig = Buffer.from(signatureBase64, 'base64');
|
|
129
|
-
return verify(null, Buffer.from(message, 'utf-8'), publicKey, sig);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// ---------------------------------------------------------------------------
|
|
133
|
-
// Local identity storage
|
|
134
|
-
// ---------------------------------------------------------------------------
|
|
135
|
-
|
|
136
|
-
const IDENTITY_FILE = 'identity.json';
|
|
137
|
-
|
|
138
|
-
/**
|
|
139
|
-
* Save an identity to the local .trellis directory.
|
|
140
|
-
*/
|
|
141
|
-
export function saveIdentity(trellisDir: string, identity: IdentityConfig): void {
|
|
142
|
-
const filePath = join(trellisDir, IDENTITY_FILE);
|
|
143
|
-
if (!existsSync(dirname(filePath))) {
|
|
144
|
-
mkdirSync(dirname(filePath), { recursive: true });
|
|
145
|
-
}
|
|
146
|
-
writeFileSync(filePath, JSON.stringify(identity, null, 2), 'utf-8');
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* Load the local identity from .trellis/identity.json.
|
|
151
|
-
*/
|
|
152
|
-
export function loadIdentity(trellisDir: string): IdentityConfig | null {
|
|
153
|
-
const filePath = join(trellisDir, IDENTITY_FILE);
|
|
154
|
-
if (!existsSync(filePath)) return null;
|
|
155
|
-
try {
|
|
156
|
-
return JSON.parse(readFileSync(filePath, 'utf-8')) as IdentityConfig;
|
|
157
|
-
} catch {
|
|
158
|
-
return null;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
/**
|
|
163
|
-
* Check if a local identity exists.
|
|
164
|
-
*/
|
|
165
|
-
export function hasIdentity(trellisDir: string): boolean {
|
|
166
|
-
return existsSync(join(trellisDir, IDENTITY_FILE));
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Extract the public (safe-to-share) portion of an identity.
|
|
171
|
-
*/
|
|
172
|
-
export function toPublicIdentity(identity: IdentityConfig): PublicIdentity {
|
|
173
|
-
return {
|
|
174
|
-
displayName: identity.displayName,
|
|
175
|
-
email: identity.email,
|
|
176
|
-
publicKey: identity.publicKey,
|
|
177
|
-
did: identity.did,
|
|
178
|
-
entityId: identity.entityId,
|
|
179
|
-
createdAt: identity.createdAt,
|
|
180
|
-
};
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
// ---------------------------------------------------------------------------
|
|
184
|
-
// Helpers
|
|
185
|
-
// ---------------------------------------------------------------------------
|
|
186
|
-
|
|
187
|
-
function createPrivateKeyFromDer(der: Buffer): KeyObject {
|
|
188
|
-
const { createPrivateKey } = require('crypto');
|
|
189
|
-
return createPrivateKey({
|
|
190
|
-
key: der,
|
|
191
|
-
format: 'der',
|
|
192
|
-
type: 'pkcs8',
|
|
193
|
-
});
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Base58btc encoding (Bitcoin alphabet).
|
|
198
|
-
*/
|
|
199
|
-
function base58btcEncode(buf: Buffer | Uint8Array): string {
|
|
200
|
-
const ALPHABET = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
|
|
201
|
-
|
|
202
|
-
let num = BigInt(0);
|
|
203
|
-
for (const byte of buf) {
|
|
204
|
-
num = num * 256n + BigInt(byte);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
let encoded = '';
|
|
208
|
-
while (num > 0n) {
|
|
209
|
-
const rem = Number(num % 58n);
|
|
210
|
-
num = num / 58n;
|
|
211
|
-
encoded = ALPHABET[rem] + encoded;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
// Preserve leading zeros
|
|
215
|
-
for (const byte of buf) {
|
|
216
|
-
if (byte === 0) {
|
|
217
|
-
encoded = '1' + encoded;
|
|
218
|
-
} else {
|
|
219
|
-
break;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
return encoded || '1';
|
|
224
|
-
}
|
package/src/identity/index.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Identity Module — Public Surface
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export {
|
|
6
|
-
createIdentity,
|
|
7
|
-
signMessage,
|
|
8
|
-
verifySignature,
|
|
9
|
-
saveIdentity,
|
|
10
|
-
loadIdentity,
|
|
11
|
-
hasIdentity,
|
|
12
|
-
toPublicIdentity,
|
|
13
|
-
} from './identity.js';
|
|
14
|
-
|
|
15
|
-
export type { IdentityConfig, PublicIdentity } from './identity.js';
|
|
16
|
-
|
|
17
|
-
export { signOp, verifyOp, verifyOpBatch } from './signing-middleware.js';
|
|
18
|
-
|
|
19
|
-
export type {
|
|
20
|
-
IdentityResolver,
|
|
21
|
-
SignatureVerificationResult,
|
|
22
|
-
} from './signing-middleware.js';
|
|
23
|
-
|
|
24
|
-
export { evaluatePolicy, createPolicy } from './governance.js';
|
|
25
|
-
|
|
26
|
-
export type {
|
|
27
|
-
PolicyRule,
|
|
28
|
-
PolicyViolation,
|
|
29
|
-
GovernanceResult,
|
|
30
|
-
} from './governance.js';
|