project-tiny-context-harness 0.2.60 → 0.2.62

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,235 @@
1
+ export const SOURCE_PACK_EXPORT_HEADER = "Export artifact. Do not reference from project_context/context.toml.";
2
+ export function renderFullProjectContextArtifact(contexts, warnings, meta) {
3
+ return [
4
+ "# Full Project Context Export",
5
+ "",
6
+ `> ${SOURCE_PACK_EXPORT_HEADER}`,
7
+ "",
8
+ "## Export Metadata",
9
+ "",
10
+ `- generated_at: ${meta.generatedAt}`,
11
+ `- output_path: ${meta.outputPath}`,
12
+ `- command: ${meta.command}`,
13
+ `- source_context_count: ${contexts.filter((context) => context.relative.startsWith("project_context/")).length}`,
14
+ "- warnings:",
15
+ ...renderWarningList(warnings),
16
+ "",
17
+ "## Export Boundary",
18
+ "",
19
+ "- This temporary artifact is for external planning and handoff only.",
20
+ "- Do not register it in project_context/context.toml.",
21
+ "",
22
+ "## Context Sources",
23
+ "",
24
+ ...contexts.map(renderContextArtifact),
25
+ ""
26
+ ].join("\n");
27
+ }
28
+ export function renderCodeIndexArtifact(records, areas, warnings, meta) {
29
+ const totalLines = records.reduce((sum, record) => sum + record.lines, 0);
30
+ const totalCharacters = records.reduce((sum, record) => sum + record.characters, 0);
31
+ return [
32
+ "# Code Index Export",
33
+ "",
34
+ `> ${SOURCE_PACK_EXPORT_HEADER}`,
35
+ "",
36
+ "## Export Metadata",
37
+ "",
38
+ `- generated_at: ${meta.generatedAt}`,
39
+ `- output_path: ${meta.outputPath}`,
40
+ `- command: ${meta.command}`,
41
+ `- tool_version: ${meta.toolVersion}`,
42
+ `- source_file_count: ${records.length}`,
43
+ `- total_lines: ${totalLines}`,
44
+ `- total_characters: ${totalCharacters}`,
45
+ "- warnings:",
46
+ ...renderWarningList(warnings),
47
+ "",
48
+ "## Repository Shape",
49
+ "",
50
+ renderRepositoryShape(records),
51
+ "",
52
+ "## Context Area Mapping",
53
+ "",
54
+ "Inferred buckets below are export routing only; they are not durable architecture or product ownership facts.",
55
+ areas.length > 0 ? areas.map((area) => `- ${area.id}: root=${area.root}; context=${area.context}`).join("\n") : "- No Context area mappings found.",
56
+ "",
57
+ "## Key Entry Points",
58
+ "",
59
+ renderRecordList(records.filter((record) => record.tags.includes("entry")).slice(0, 30)),
60
+ "",
61
+ "## API / Route Index",
62
+ "",
63
+ renderRecordList(records.filter((record) => record.tags.includes("api")).slice(0, 30), true),
64
+ "",
65
+ "## UI Surface Index",
66
+ "",
67
+ renderRecordList(records.filter((record) => record.tags.includes("ui")).slice(0, 30)),
68
+ "",
69
+ "## CLI / Worker / Script Index",
70
+ "",
71
+ renderRecordList(records.filter((record) => record.tags.includes("cli") || record.tags.includes("worker")).slice(0, 30)),
72
+ "",
73
+ "## Test / Verification Index",
74
+ "",
75
+ renderRecordList(records.filter((record) => record.tags.includes("test")).slice(0, 30)),
76
+ "",
77
+ "## Oversized Files",
78
+ "",
79
+ renderRecordList(records.filter((record) => record.tags.includes("oversized")).slice(0, 30)),
80
+ "",
81
+ "## Source File Index",
82
+ "",
83
+ renderSourceFileIndex(records),
84
+ ""
85
+ ].join("\n");
86
+ }
87
+ export function renderBundleArtifact(title, records, contexts, omitted, warnings, meta, policy) {
88
+ return [
89
+ `# ${title}`,
90
+ "",
91
+ `> ${SOURCE_PACK_EXPORT_HEADER}`,
92
+ "",
93
+ "## Export Metadata",
94
+ "",
95
+ `- generated_at: ${meta.generatedAt}`,
96
+ `- output_path: ${meta.outputPath}`,
97
+ `- command: ${meta.command}`,
98
+ `- source_file_count: ${records.length}`,
99
+ "- warnings:",
100
+ ...renderWarningList(warnings),
101
+ "",
102
+ "## Bundle Selection Policy",
103
+ "",
104
+ policy,
105
+ "",
106
+ "## Bundle Index",
107
+ "",
108
+ renderSourceFileIndex(records),
109
+ "",
110
+ "## Related Context Paths",
111
+ "",
112
+ contexts.length > 0 ? contexts.map((context) => `- ${context.relative} (${context.lines} lines)`).join("\n") : "- No related Context files selected.",
113
+ "",
114
+ "## Source Files",
115
+ "",
116
+ records.map(renderSourceRecord).join("\n\n") || "- No source files selected for this bundle.",
117
+ "",
118
+ "## Omitted Files Summary",
119
+ "",
120
+ renderOmittedSummary(omitted),
121
+ ""
122
+ ].join("\n");
123
+ }
124
+ export function renderTaskContextArtifact(taskName, contexts, records, verification, omitted, warnings, meta) {
125
+ return [
126
+ `# Task Context: ${taskName}`,
127
+ "",
128
+ `> ${SOURCE_PACK_EXPORT_HEADER}`,
129
+ "",
130
+ "## Export Metadata",
131
+ "",
132
+ `- generated_at: ${meta.generatedAt}`,
133
+ `- output_path: ${meta.outputPath}`,
134
+ `- command: ${meta.command}`,
135
+ "- warnings:",
136
+ ...renderWarningList(warnings),
137
+ "",
138
+ "## Boundary",
139
+ "",
140
+ "- This task pack is a temporary export selector output, not a durable fact source.",
141
+ "- Profile verification commands are listed only; export does not execute them.",
142
+ "",
143
+ "## Selected Context",
144
+ "",
145
+ ...contexts.map(renderContextArtifact),
146
+ "",
147
+ "## Selected Source Index",
148
+ "",
149
+ renderSourceFileIndex(records),
150
+ "",
151
+ "## Selected Source Files",
152
+ "",
153
+ records.map(renderSourceRecord).join("\n\n") || "- No selected source files matched the task filters.",
154
+ "",
155
+ "## Verification Entry Points",
156
+ "",
157
+ verification.length > 0 ? verification.map((entry) => `- ${entry}`).join("\n") : "- No profile verification entries selected.",
158
+ "",
159
+ "## Omitted / Support Notes",
160
+ "",
161
+ renderOmittedSummary(omitted),
162
+ ""
163
+ ].join("\n");
164
+ }
165
+ function renderContextArtifact(context) {
166
+ const fence = fenceFor(context.content);
167
+ return [`### ${context.relative}`, "", `${fence}markdown`, context.content.trimEnd(), fence, ""].join("\n");
168
+ }
169
+ function renderSourceRecord(record) {
170
+ const fence = fenceFor(record.content);
171
+ return [
172
+ `### ${record.relative}`,
173
+ "",
174
+ `Summary: ${record.summary}`,
175
+ "",
176
+ "Metadata:",
177
+ `- type: ${record.language}`,
178
+ `- lines: ${record.lines}`,
179
+ `- characters: ${record.characters}`,
180
+ `- sha256: ${record.sha256}`,
181
+ `- tags: ${record.tags.join(", ") || "none"}`,
182
+ `- routing_bucket: ${record.bucket} (export routing only)`,
183
+ "",
184
+ `${fence}${record.language}`,
185
+ record.content.trimEnd(),
186
+ fence
187
+ ].join("\n");
188
+ }
189
+ function renderSourceFileIndex(records) {
190
+ if (records.length === 0) {
191
+ return "- No source files matched.";
192
+ }
193
+ return [
194
+ "| Path | Type | Lines | Characters | SHA256 | Summary | Bundle | Tags |",
195
+ "|---|---:|---:|---:|---|---|---|---|",
196
+ ...records.map((record) => `| ${escapeTableCell(record.relative)} | ${escapeTableCell(record.language)} | ${record.lines} | ${record.characters} | ${record.sha256.slice(0, 12)} | ${escapeTableCell(record.summary)} | ${record.bundle} | ${escapeTableCell(record.tags.join(", "))} |`)
197
+ ].join("\n");
198
+ }
199
+ function renderRepositoryShape(records) {
200
+ const counts = new Map();
201
+ for (const record of records) {
202
+ const top = record.relative.split("/")[0] || ".";
203
+ counts.set(top, (counts.get(top) ?? 0) + 1);
204
+ }
205
+ return [...counts.entries()]
206
+ .sort((left, right) => right[1] - left[1] || left[0].localeCompare(right[0]))
207
+ .map(([name, count]) => `- ${name}: ${count} source file(s)`)
208
+ .join("\n") || "- No source files matched.";
209
+ }
210
+ function renderRecordList(records, includeRoutes = false) {
211
+ if (records.length === 0) {
212
+ return "- None detected.";
213
+ }
214
+ return records
215
+ .map((record) => `- ${record.relative}: ${record.summary}${includeRoutes && record.routes.length > 0 ? ` Routes: ${record.routes.join(", ")}` : ""}`)
216
+ .join("\n");
217
+ }
218
+ function renderWarningList(warnings) {
219
+ return warnings.length > 0 ? warnings.map((warning) => ` - ${warning}`) : [" - none"];
220
+ }
221
+ function renderOmittedSummary(omitted) {
222
+ const reasons = Object.entries(omitted.reason_counts)
223
+ .sort((left, right) => left[0].localeCompare(right[0]))
224
+ .map(([reason, count]) => ` - ${reason}: ${count}`);
225
+ return [`- omitted_source_file_count: ${omitted.source_file_count}`, "- reason_counts:", ...(reasons.length > 0 ? reasons : [" - none: 0"])].join("\n");
226
+ }
227
+ function fenceFor(content) {
228
+ let fence = "```";
229
+ while (content.includes(fence))
230
+ fence += "`";
231
+ return fence;
232
+ }
233
+ function escapeTableCell(value) {
234
+ return value.replace(/\r?\n/g, " ").replace(/\|/g, "\\|");
235
+ }
@@ -0,0 +1,77 @@
1
+ export type SourcePackMode = "code-index" | "source-pack" | "code-bundles" | "task-context";
2
+ export interface SourcePackOptions {
3
+ mode: SourcePackMode;
4
+ check?: boolean;
5
+ now?: Date;
6
+ command?: string;
7
+ profile?: string;
8
+ includeContext?: string[];
9
+ includeCode?: string[];
10
+ bundleStrategy?: "auto" | "area" | "topdir" | "config";
11
+ maxPackFiles?: number;
12
+ maxBundleCharacters?: number;
13
+ redactionStrict?: boolean;
14
+ prune?: number;
15
+ taskName?: string;
16
+ }
17
+ export interface SourcePackArtifactReport {
18
+ kind: string;
19
+ name: string;
20
+ path: string;
21
+ sha256: string;
22
+ characters: number;
23
+ source_count: number;
24
+ source_line_count: number;
25
+ warning_count: number;
26
+ }
27
+ export interface SourcePackReport {
28
+ mode: SourcePackMode;
29
+ outputDirectory: string;
30
+ outputRelativePath: string;
31
+ artifacts: SourcePackArtifactReport[];
32
+ sourceFiles: string[];
33
+ sourceCodeCount: number;
34
+ totalLines: number;
35
+ totalCharacters: number;
36
+ redactionCount: number;
37
+ warnings: string[];
38
+ omitted: SourcePackOmitted;
39
+ recommendedUploadSets: Record<string, string[]>;
40
+ wrote: boolean;
41
+ }
42
+ export interface SourcePackOmitted {
43
+ source_file_count: number;
44
+ reason_counts: Record<string, number>;
45
+ }
46
+ export interface SourcePackRecord {
47
+ relative: string;
48
+ language: string;
49
+ lines: number;
50
+ characters: number;
51
+ sha256: string;
52
+ summary: string;
53
+ content: string;
54
+ tags: string[];
55
+ routes: string[];
56
+ score: number;
57
+ bucket: string;
58
+ bundle: "core" | "extended" | "task" | "task-support" | "omitted";
59
+ }
60
+ export interface SourcePackProfile {
61
+ context: string[];
62
+ code: string[];
63
+ exclude: string[];
64
+ verification: string[];
65
+ maxBundleCharacters?: number;
66
+ }
67
+ export interface ContextArtifact {
68
+ relative: string;
69
+ content: string;
70
+ lines: number;
71
+ characters: number;
72
+ }
73
+ export interface ContextAreaMapping {
74
+ id: string;
75
+ root: string;
76
+ context: string;
77
+ }
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "project-tiny-context-harness",
3
- "version": "0.2.60",
3
+ "version": "0.2.62",
4
4
  "description": "Minimal project memory and validation harness for AI coding agents.",
5
5
  "license": "MIT",
6
6
  "author": "Seven128",