terry-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.
@@ -0,0 +1,199 @@
1
+ export type PermissionLevel = "disabled" | "enabled" | "ask";
2
+ export type AgentMode = "general" | "focus" | "builder";
3
+ export type ExecutionMode = "plan" | "safe" | "autonomous";
4
+ export type ToolName = "listDirectory" | "readFile" | "writeFile" | "searchInFiles" | "gitStatus" | "gitDiff" | "runCommand";
5
+ export type ToolArgsMap = {
6
+ listDirectory: {
7
+ pathRelativeToWorkspace?: string;
8
+ };
9
+ readFile: {
10
+ pathRelativeToWorkspace: string;
11
+ };
12
+ writeFile: {
13
+ pathRelativeToWorkspace: string;
14
+ content: string;
15
+ };
16
+ searchInFiles: {
17
+ query: string;
18
+ };
19
+ gitStatus: Record<string, never>;
20
+ gitDiff: {
21
+ path?: string;
22
+ };
23
+ runCommand: {
24
+ cmd: string;
25
+ args?: string[];
26
+ cwdRelativeToWorkspace?: string;
27
+ };
28
+ };
29
+ export type ToolResult = {
30
+ ok: boolean;
31
+ output?: string;
32
+ files?: string[];
33
+ error?: string;
34
+ patchProposalId?: string;
35
+ };
36
+ export type AuditEntry = {
37
+ timestamp: string;
38
+ workspace: string;
39
+ tool: ToolName;
40
+ args: unknown;
41
+ affectedFiles: string[];
42
+ dryRun: boolean;
43
+ ok: boolean;
44
+ error?: string;
45
+ };
46
+ export type ToolPolicy = Record<ToolName, PermissionLevel>;
47
+ export type WorkspaceSettings = {
48
+ workspacePath: string;
49
+ dryRun: boolean;
50
+ mode: AgentMode;
51
+ executionMode: ExecutionMode;
52
+ tools: ToolPolicy;
53
+ goal?: string;
54
+ };
55
+ export type AgentMessage = {
56
+ role: "user" | "assistant" | "system";
57
+ content: string;
58
+ };
59
+ export type PlannedAction = {
60
+ kind: "ask_permission";
61
+ tool: ToolName;
62
+ args: unknown;
63
+ reason: string;
64
+ } | {
65
+ kind: "summarize";
66
+ summary: string;
67
+ };
68
+ export type DecideNextAction = (messages: AgentMessage[], tools: ToolName[]) => PlannedAction;
69
+ export type PatchRiskLevel = "low" | "medium" | "high";
70
+ export type PatchStatus = "pending" | "applied" | "rejected";
71
+ export type PatchHunk = {
72
+ id: string;
73
+ header: string;
74
+ before: string[];
75
+ after: string[];
76
+ approved: boolean;
77
+ };
78
+ export type PatchProposal = {
79
+ id: string;
80
+ filePath: string;
81
+ unifiedDiff: string;
82
+ hunks: PatchHunk[];
83
+ riskLevel: PatchRiskLevel;
84
+ status: PatchStatus;
85
+ createdAt: string;
86
+ updatedAt: string;
87
+ originalContent: string;
88
+ updatedContent: string;
89
+ };
90
+ export type ActionExplanation = {
91
+ id: string;
92
+ timestamp: string;
93
+ task: string;
94
+ mode: AgentMode;
95
+ executionMode: ExecutionMode;
96
+ reason: string;
97
+ chosenTool?: ToolName;
98
+ toolArgs?: unknown;
99
+ changedFiles: string[];
100
+ risks: string[];
101
+ summary: string;
102
+ };
103
+ export type SessionStepType = "plan" | "approval" | "tool" | "summary" | "status";
104
+ export type SessionStep = {
105
+ at: string;
106
+ type: SessionStepType;
107
+ input?: string;
108
+ output?: string;
109
+ tool?: ToolName | "cloud-chat";
110
+ approval?: boolean;
111
+ durationMs?: number;
112
+ };
113
+ export type SessionRecord = {
114
+ id: string;
115
+ workspaceHash: string;
116
+ workspacePath: string;
117
+ task: string;
118
+ startedAt: string;
119
+ finishedAt?: string;
120
+ mode: AgentMode;
121
+ executionMode: ExecutionMode;
122
+ steps: SessionStep[];
123
+ result?: "success" | "failure" | "cancelled";
124
+ };
125
+ export type RepoGraphNode = {
126
+ id: string;
127
+ path: string;
128
+ kind: "file";
129
+ };
130
+ export type RepoGraphEdge = {
131
+ from: string;
132
+ to: string;
133
+ type: "import" | "reference" | "dependency";
134
+ };
135
+ export type RepoProfile = {
136
+ language: string;
137
+ framework: string;
138
+ buildSystem: string;
139
+ testRunner: string;
140
+ packageManager: string;
141
+ };
142
+ export type RepoGraph = {
143
+ nodes: RepoGraphNode[];
144
+ edges: RepoGraphEdge[];
145
+ metadata: {
146
+ generatedAt: string;
147
+ workspacePath: string;
148
+ profile: RepoProfile;
149
+ };
150
+ };
151
+ export type ImpactResult = {
152
+ target: string;
153
+ affectedFiles: string[];
154
+ confidence: number;
155
+ rationale: string;
156
+ };
157
+ export type HealthCheck = {
158
+ name: string;
159
+ status: "pass" | "warn" | "fail";
160
+ detail: string;
161
+ };
162
+ export type HealthReport = {
163
+ score: number;
164
+ checks: HealthCheck[];
165
+ recommendations: string[];
166
+ generatedAt: string;
167
+ };
168
+ export type UsageEntry = {
169
+ timestamp: string;
170
+ workspaceHash: string;
171
+ model: string;
172
+ promptTokens: number;
173
+ completionTokens: number;
174
+ requests: number;
175
+ estimatedCost: number;
176
+ };
177
+ export type UsageReport = {
178
+ period: string;
179
+ requests: number;
180
+ promptTokens: number;
181
+ completionTokens: number;
182
+ estimatedCost: number;
183
+ };
184
+ export type CloudSyncConfig = {
185
+ enabled: boolean;
186
+ updatedAt: string;
187
+ };
188
+ export type WorkspaceStatus = {
189
+ workspacePath: string;
190
+ mode: AgentMode;
191
+ executionMode: ExecutionMode;
192
+ pendingPatchCount: number;
193
+ unresolvedApprovals: number;
194
+ lastActionAt?: string;
195
+ lastSummary?: string;
196
+ repoProfile?: RepoProfile;
197
+ repoIndexFreshAt?: string;
198
+ nextSuggestedTarget?: string;
199
+ };
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,3 @@
1
+ import type { UsageReport } from "./types.js";
2
+ export declare function appendUsage(workspacePath: string, model: string, promptTokens: number, completionTokens: number, estimatedCost: number): Promise<void>;
3
+ export declare function getUsageReport(period?: string): Promise<UsageReport>;
package/dist/usage.js ADDED
@@ -0,0 +1,41 @@
1
+ import path from "node:path";
2
+ import { readJsonFile, writeJsonFile } from "./workspace-data.js";
3
+ import { usageDir } from "./config.js";
4
+ import { workspaceHash } from "./workspace-data.js";
5
+ function usageFile(period) {
6
+ return path.join(usageDir(), `monthly-${period}.json`);
7
+ }
8
+ function currentPeriod() {
9
+ const now = new Date();
10
+ const yyyy = now.getFullYear();
11
+ const mm = `${now.getMonth() + 1}`.padStart(2, "0");
12
+ return `${yyyy}-${mm}`;
13
+ }
14
+ function sum(entries) {
15
+ return {
16
+ period: entries[0]?.timestamp.slice(0, 7) ?? currentPeriod(),
17
+ requests: entries.reduce((n, e) => n + e.requests, 0),
18
+ promptTokens: entries.reduce((n, e) => n + e.promptTokens, 0),
19
+ completionTokens: entries.reduce((n, e) => n + e.completionTokens, 0),
20
+ estimatedCost: Number(entries.reduce((n, e) => n + e.estimatedCost, 0).toFixed(6))
21
+ };
22
+ }
23
+ export async function appendUsage(workspacePath, model, promptTokens, completionTokens, estimatedCost) {
24
+ const period = currentPeriod();
25
+ const file = usageFile(period);
26
+ const entries = await readJsonFile(file, []);
27
+ entries.push({
28
+ timestamp: new Date().toISOString(),
29
+ workspaceHash: workspaceHash(workspacePath),
30
+ model,
31
+ promptTokens: Math.max(0, promptTokens),
32
+ completionTokens: Math.max(0, completionTokens),
33
+ requests: 1,
34
+ estimatedCost: Math.max(0, estimatedCost)
35
+ });
36
+ await writeJsonFile(file, entries);
37
+ }
38
+ export async function getUsageReport(period = currentPeriod()) {
39
+ const entries = await readJsonFile(usageFile(period), []);
40
+ return sum(entries);
41
+ }
@@ -0,0 +1,8 @@
1
+ export declare function workspaceHash(workspacePath: string): string;
2
+ export declare function workspaceDataDir(workspacePath: string): string;
3
+ export declare function workspaceSubdir(workspacePath: string, name: string): string;
4
+ export declare function workspaceDataFile(workspacePath: string, name: string): string;
5
+ export declare function ensureWorkspaceDataDirs(workspacePath: string): Promise<void>;
6
+ export declare function readJsonFile<T>(filePath: string, fallback: T): Promise<T>;
7
+ export declare function writeJsonFile(filePath: string, value: unknown): Promise<void>;
8
+ export declare function listJsonFiles(dirPath: string): Promise<string[]>;
@@ -0,0 +1,45 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { createHash } from "node:crypto";
4
+ import { terryHomeDir } from "./config.js";
5
+ export function workspaceHash(workspacePath) {
6
+ return createHash("sha256").update(path.resolve(workspacePath)).digest("hex").slice(0, 16);
7
+ }
8
+ export function workspaceDataDir(workspacePath) {
9
+ return path.join(terryHomeDir(), "workspaces", workspaceHash(workspacePath));
10
+ }
11
+ export function workspaceSubdir(workspacePath, name) {
12
+ return path.join(workspaceDataDir(workspacePath), name);
13
+ }
14
+ export function workspaceDataFile(workspacePath, name) {
15
+ return path.join(workspaceDataDir(workspacePath), name);
16
+ }
17
+ export async function ensureWorkspaceDataDirs(workspacePath) {
18
+ const base = workspaceDataDir(workspacePath);
19
+ await fs.mkdir(base, { recursive: true });
20
+ await fs.mkdir(path.join(base, "pending-patches"), { recursive: true });
21
+ await fs.mkdir(path.join(base, "sessions"), { recursive: true });
22
+ await fs.mkdir(path.join(base, "templates"), { recursive: true });
23
+ }
24
+ export async function readJsonFile(filePath, fallback) {
25
+ try {
26
+ const raw = await fs.readFile(filePath, "utf8");
27
+ return JSON.parse(raw);
28
+ }
29
+ catch {
30
+ return fallback;
31
+ }
32
+ }
33
+ export async function writeJsonFile(filePath, value) {
34
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
35
+ await fs.writeFile(filePath, JSON.stringify(value, null, 2), "utf8");
36
+ }
37
+ export async function listJsonFiles(dirPath) {
38
+ try {
39
+ const names = await fs.readdir(dirPath);
40
+ return names.filter((name) => name.endsWith(".json")).sort();
41
+ }
42
+ catch {
43
+ return [];
44
+ }
45
+ }
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "terry-core",
3
+ "version": "0.1.0",
4
+ "description": "Core policy, tooling, and orchestration modules for Terry Agent.",
5
+ "license": "MIT",
6
+ "author": "ELEVAREL",
7
+ "homepage": "https://github.com/ELEVAREL/terry-agent",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/ELEVAREL/terry-agent.git",
11
+ "directory": "packages/terry-core"
12
+ },
13
+ "type": "module",
14
+ "main": "dist/index.js",
15
+ "types": "dist/index.d.ts",
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "default": "./dist/index.js"
23
+ }
24
+ },
25
+ "scripts": {
26
+ "build": "tsc -p tsconfig.json",
27
+ "lint": "tsc -p tsconfig.json --noEmit",
28
+ "prepack": "npm run build"
29
+ },
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "engines": {
34
+ "node": ">=20"
35
+ },
36
+ "keywords": [
37
+ "terry",
38
+ "agent",
39
+ "cli",
40
+ "ai",
41
+ "developer-tools"
42
+ ],
43
+ "dependencies": {
44
+ "diff": "^5.2.0",
45
+ "fast-glob": "^3.3.3"
46
+ },
47
+ "devDependencies": {
48
+ "@types/diff": "^5.2.3",
49
+ "@types/node": "^22.13.4",
50
+ "typescript": "^5.7.3"
51
+ }
52
+ }