project-tiny-context-harness 0.2.57 → 0.2.58

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.
Files changed (33) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +496 -496
  3. package/assets/README.md +550 -550
  4. package/assets/README.zh-CN.md +133 -133
  5. package/assets/agents/.gitkeep +1 -1
  6. package/assets/agents/AGENTS_CORE.md +59 -59
  7. package/assets/context_templates/architecture.md +31 -31
  8. package/assets/context_templates/area.md +38 -38
  9. package/assets/context_templates/context.toml +27 -27
  10. package/assets/context_templates/deployment.md +35 -35
  11. package/assets/context_templates/global.md +53 -53
  12. package/assets/context_templates/product-surface-contract.md +60 -60
  13. package/assets/context_templates/verification.md +32 -32
  14. package/assets/github/.gitkeep +1 -1
  15. package/assets/github/harness.yml +41 -41
  16. package/assets/make/.gitkeep +1 -1
  17. package/assets/make/ty-context.mk +48 -48
  18. package/assets/skills/context_development_engineer/SKILL.md +108 -108
  19. package/assets/skills/context_full_project_export/SKILL.md +55 -55
  20. package/assets/skills/context_harness_upgrade/SKILL.md +60 -60
  21. package/assets/skills/context_product_plan/SKILL.md +89 -89
  22. package/assets/skills/context_surface_contract/SKILL.md +168 -168
  23. package/assets/skills/context_uiux_design/SKILL.md +113 -113
  24. package/assets/skills/plan_acceptance_checklist_compiler/SKILL.md +436 -394
  25. package/assets/tools/validate_context.py +276 -276
  26. package/dist/commands/check-modularity.js +8 -8
  27. package/dist/commands/export-context.js +9 -9
  28. package/dist/commands/index.js +16 -16
  29. package/dist/commands/package-source.js +2 -2
  30. package/dist/commands/upgrade.js +9 -9
  31. package/migrations/README.md +3 -3
  32. package/package.json +68 -68
  33. package/source-mappings.yaml +25 -25
@@ -1,276 +1,276 @@
1
- #!/usr/bin/env python3
2
- from pathlib import Path
3
- import re
4
- import sys
5
-
6
- ROOT = Path.cwd()
7
-
8
- GLOBAL_CHECKS = [
9
- ("project goal", ["project goal", "项目目标", "目标"]),
10
- ("boundaries", ["non-goals", "boundaries", "非目标", "边界"]),
11
- ("design rationale", ["design rationale", "设计思路", "设计原因"]),
12
- ("architecture context", ["architecture context", "架构上下文", "architecture.md"]),
13
- ("verification entry points", ["verification entry", "验证入口", "测试入口"]),
14
- ("current state", ["current state", "当前状态"]),
15
- ("next safe action", ["next safe action", "下一步安全动作"]),
16
- ("context index", ["context index", "module index", "上下文索引", "模块索引"]),
17
- ]
18
-
19
- ARCHITECTURE_CHECKS = [
20
- ("system boundary", ["system boundary", "系统边界", "边界"]),
21
- ("component map", ["component map", "组件", "模块关系"]),
22
- ("data or control flow", ["data / control flow", "data flow", "control flow", "数据流", "控制流"]),
23
- ("design rationale", ["design rationale", "设计思路", "设计原因"]),
24
- ("verification implications", ["verification implications", "验证影响", "验证入口"]),
25
- ]
26
-
27
- VALID_ROLES = {
28
- "global",
29
- "architecture",
30
- "area",
31
- "domain",
32
- "subdomain",
33
- "foundation",
34
- "archive",
35
- "contract",
36
- "verification",
37
- "deployment",
38
- "implementation-index",
39
- "decision-rationale",
40
- }
41
-
42
- ROLE_ALIASES = {
43
- "implementation_index": "implementation-index",
44
- "decision_rationale": "decision-rationale",
45
- }
46
-
47
- READ_POLICIES = {"default", "always", "optional", "on-demand", "never-default"}
48
- CONFIG_CANDIDATES = [
49
- ".agent/config.yaml",
50
- ".codex/config.yaml",
51
- ".harness/config.yaml",
52
- ".claude/config.yaml",
53
- ".cursor/config.yaml",
54
- ".cline/config.yaml",
55
- ".roo/config.yaml",
56
- ".gemini/config.yaml",
57
- ]
58
-
59
-
60
- def has_any(text, terms):
61
- lower = text.lower()
62
- return any(term.lower() in lower for term in terms)
63
-
64
-
65
- def normalize_role(value):
66
- role = ROLE_ALIASES.get(value.strip().lower(), value.strip().lower())
67
- return role if role in VALID_ROLES else None
68
-
69
-
70
- def parse_front_matter(text):
71
- lines = text.splitlines()
72
- if not lines or lines[0].strip() != "---":
73
- return {}
74
- result = {}
75
- for line in lines[1:]:
76
- if line.strip() == "---":
77
- return result
78
- match = re.match(r"^([A-Za-z0-9_-]+):\s*(.+?)\s*$", line.strip())
79
- if match:
80
- result[match.group(1)] = match.group(2).strip().strip("\"'")
81
- return result
82
-
83
-
84
- def strip_comment(line):
85
- quote = None
86
- for index, char in enumerate(line):
87
- if char in {"'", "\""} and (index == 0 or line[index - 1] != "\\"):
88
- quote = None if quote == char else quote or char
89
- if char == "#" and quote is None:
90
- return line[:index]
91
- return line
92
-
93
-
94
- def parse_toml_value(raw):
95
- value = raw.strip()
96
- if value == "true":
97
- return True
98
- if value == "false":
99
- return False
100
- if (value.startswith("\"") and value.endswith("\"")) or (value.startswith("'") and value.endswith("'")):
101
- return value[1:-1]
102
- if value.startswith("[") and value.endswith("]"):
103
- inner = value[1:-1].strip()
104
- if not inner:
105
- return []
106
- items = []
107
- for part in inner.split(","):
108
- item = part.strip()
109
- if not ((item.startswith("\"") and item.endswith("\"")) or (item.startswith("'") and item.endswith("'"))):
110
- return None
111
- items.append(item[1:-1])
112
- return items
113
- return None
114
-
115
-
116
- def parse_manifest(path, errors):
117
- manifest = {"areas": [], "context": []}
118
- current = None
119
- for line_number, raw in enumerate(path.read_text(encoding="utf-8").splitlines(), start=1):
120
- line = strip_comment(raw).strip()
121
- if not line:
122
- continue
123
- match = re.match(r"^\[\[(areas|context)\]\]$", line)
124
- if match:
125
- current = {"line": line_number}
126
- manifest[match.group(1)].append(current)
127
- continue
128
- if current is None:
129
- errors.append(f"project_context/context.toml line {line_number} must appear inside [[areas]] or [[context]]")
130
- continue
131
- assignment = re.match(r"^([A-Za-z0-9_-]+)\s*=\s*(.+)$", line)
132
- if not assignment:
133
- errors.append(f"project_context/context.toml line {line_number} is not a supported assignment")
134
- continue
135
- value = parse_toml_value(assignment.group(2))
136
- if value is None:
137
- errors.append(f"project_context/context.toml line {line_number} has an unsupported value")
138
- continue
139
- current[assignment.group(1)] = value
140
- return manifest
141
-
142
-
143
- def normalize_context_path(value):
144
- return value.replace("\\", "/").removeprefix("./")
145
-
146
-
147
- def add_manifest_role(entry, role, roles, errors):
148
- raw_path = entry.get("context") or entry.get("path")
149
- if not isinstance(raw_path, str):
150
- errors.append(f"project_context/context.toml line {entry['line']} must include a context/path string")
151
- return
152
- rel = normalize_context_path(raw_path)
153
- if not rel.startswith("project_context/") or not rel.endswith(".md"):
154
- errors.append(f"project_context/context.toml line {entry['line']} must reference a markdown file under project_context/")
155
- return
156
- existing = roles.get(rel)
157
- if existing and existing != role:
158
- errors.append(f"project_context/context.toml assigns conflicting roles to {rel}: {existing} and {role}")
159
- return
160
- roles[rel] = role
161
- if not (ROOT / rel).exists():
162
- errors.append(f"project_context/context.toml references missing context file: {rel}")
163
-
164
-
165
- def validate_manifest(errors):
166
- manifest_path = ROOT / "project_context/context.toml"
167
- roles = {}
168
- if not manifest_path.exists():
169
- if schema_requires_manifest():
170
- errors.append("missing project_context/context.toml; run ty-context upgrade to create the Schema v4 Context graph manifest")
171
- return roles
172
- manifest = parse_manifest(manifest_path, errors)
173
- if not manifest["areas"]:
174
- errors.append("project_context/context.toml must declare at least one [[areas]] entry")
175
- has_default_area = False
176
- for area in manifest["areas"]:
177
- for key in ["id", "root", "context"]:
178
- if not isinstance(area.get(key), str):
179
- errors.append(f"project_context/context.toml line {area['line']} must include string field {key}")
180
- default_area = area.get("default")
181
- if default_area is not None and not isinstance(default_area, bool):
182
- errors.append(f"project_context/context.toml line {area['line']} default must be a boolean")
183
- has_default_area = has_default_area or default_area is True
184
- deps = area.get("forbidden_runtime_dependencies")
185
- if deps is not None and not is_string_array(deps):
186
- errors.append(f"project_context/context.toml line {area['line']} forbidden_runtime_dependencies must be an array of strings")
187
- add_manifest_role(area, "area", roles, errors)
188
- if manifest["areas"] and not has_default_area:
189
- errors.append("project_context/context.toml must mark one [[areas]] entry with default = true")
190
- for context in manifest["context"]:
191
- role = normalize_role(context.get("role", "")) if isinstance(context.get("role"), str) else None
192
- if role is None:
193
- errors.append(f"project_context/context.toml line {context['line']} has unsupported context role")
194
- continue
195
- read_policy = context.get("read_policy")
196
- if read_policy is not None and read_policy not in READ_POLICIES:
197
- errors.append(f"project_context/context.toml line {context['line']} has unsupported read_policy: {read_policy}")
198
- for key in ["triggers", "default_children"]:
199
- value = context.get(key)
200
- if value is not None and not is_string_array(value):
201
- errors.append(f"project_context/context.toml line {context['line']} {key} must be an array of strings")
202
- add_manifest_role(context, role, roles, errors)
203
- return roles
204
-
205
-
206
- def is_string_array(value):
207
- return isinstance(value, list) and all(isinstance(item, str) for item in value)
208
-
209
-
210
- def schema_requires_manifest():
211
- schema_version = "4"
212
- for candidate in CONFIG_CANDIDATES:
213
- path = ROOT / candidate
214
- if not path.exists():
215
- continue
216
- match = re.search(r'schema_version:\s*["\']?([^"\'\s]+)', path.read_text(encoding="utf-8"))
217
- if match:
218
- schema_version = match.group(1)
219
- break
220
- try:
221
- return int(schema_version.split(".", 1)[0]) >= 4
222
- except ValueError:
223
- return True
224
-
225
-
226
- def validate_checks(rel, text, checks, errors):
227
- for label, terms in checks:
228
- if not has_any(text, terms):
229
- errors.append(f"{rel} must include {label}")
230
-
231
-
232
- def main():
233
- errors = []
234
- global_path = ROOT / "project_context/global.md"
235
- if not global_path.exists():
236
- errors.append("missing project_context/global.md")
237
- else:
238
- validate_checks("project_context/global.md", global_path.read_text(encoding="utf-8"), GLOBAL_CHECKS, errors)
239
-
240
- architecture_path = ROOT / "project_context/architecture.md"
241
- if not architecture_path.exists():
242
- errors.append("missing project_context/architecture.md")
243
- else:
244
- validate_checks("project_context/architecture.md", architecture_path.read_text(encoding="utf-8"), ARCHITECTURE_CHECKS, errors)
245
-
246
- manifest_roles = validate_manifest(errors)
247
- context_root = ROOT / "project_context"
248
- context_files = sorted(context_root.rglob("*.md")) if context_root.exists() else []
249
- checked = 0
250
- for path in context_files:
251
- rel = path.relative_to(ROOT).as_posix()
252
- if rel in {"project_context/global.md", "project_context/architecture.md"}:
253
- continue
254
- text = path.read_text(encoding="utf-8")
255
- front_matter = parse_front_matter(text)
256
- declared_role = front_matter.get("context_role")
257
- front_matter_role = normalize_role(declared_role) if declared_role else None
258
- if declared_role and front_matter_role is None:
259
- errors.append(f"{rel} has unsupported context_role: {declared_role}")
260
- read_policy = front_matter.get("read_policy")
261
- if read_policy and read_policy not in READ_POLICIES:
262
- errors.append(f"{rel} has unsupported read_policy: {read_policy}")
263
- role = manifest_roles.get(rel) or front_matter_role
264
- if role is not None and role not in {"global", "architecture"}:
265
- checked += 1
266
-
267
- if errors:
268
- for error in errors:
269
- print(f"error: {error}", file=sys.stderr)
270
- return 1
271
- print(f"Context OK: {2 + checked} context file(s)")
272
- return 0
273
-
274
-
275
- if __name__ == "__main__":
276
- raise SystemExit(main())
1
+ #!/usr/bin/env python3
2
+ from pathlib import Path
3
+ import re
4
+ import sys
5
+
6
+ ROOT = Path.cwd()
7
+
8
+ GLOBAL_CHECKS = [
9
+ ("project goal", ["project goal", "项目目标", "目标"]),
10
+ ("boundaries", ["non-goals", "boundaries", "非目标", "边界"]),
11
+ ("design rationale", ["design rationale", "设计思路", "设计原因"]),
12
+ ("architecture context", ["architecture context", "架构上下文", "architecture.md"]),
13
+ ("verification entry points", ["verification entry", "验证入口", "测试入口"]),
14
+ ("current state", ["current state", "当前状态"]),
15
+ ("next safe action", ["next safe action", "下一步安全动作"]),
16
+ ("context index", ["context index", "module index", "上下文索引", "模块索引"]),
17
+ ]
18
+
19
+ ARCHITECTURE_CHECKS = [
20
+ ("system boundary", ["system boundary", "系统边界", "边界"]),
21
+ ("component map", ["component map", "组件", "模块关系"]),
22
+ ("data or control flow", ["data / control flow", "data flow", "control flow", "数据流", "控制流"]),
23
+ ("design rationale", ["design rationale", "设计思路", "设计原因"]),
24
+ ("verification implications", ["verification implications", "验证影响", "验证入口"]),
25
+ ]
26
+
27
+ VALID_ROLES = {
28
+ "global",
29
+ "architecture",
30
+ "area",
31
+ "domain",
32
+ "subdomain",
33
+ "foundation",
34
+ "archive",
35
+ "contract",
36
+ "verification",
37
+ "deployment",
38
+ "implementation-index",
39
+ "decision-rationale",
40
+ }
41
+
42
+ ROLE_ALIASES = {
43
+ "implementation_index": "implementation-index",
44
+ "decision_rationale": "decision-rationale",
45
+ }
46
+
47
+ READ_POLICIES = {"default", "always", "optional", "on-demand", "never-default"}
48
+ CONFIG_CANDIDATES = [
49
+ ".agent/config.yaml",
50
+ ".codex/config.yaml",
51
+ ".harness/config.yaml",
52
+ ".claude/config.yaml",
53
+ ".cursor/config.yaml",
54
+ ".cline/config.yaml",
55
+ ".roo/config.yaml",
56
+ ".gemini/config.yaml",
57
+ ]
58
+
59
+
60
+ def has_any(text, terms):
61
+ lower = text.lower()
62
+ return any(term.lower() in lower for term in terms)
63
+
64
+
65
+ def normalize_role(value):
66
+ role = ROLE_ALIASES.get(value.strip().lower(), value.strip().lower())
67
+ return role if role in VALID_ROLES else None
68
+
69
+
70
+ def parse_front_matter(text):
71
+ lines = text.splitlines()
72
+ if not lines or lines[0].strip() != "---":
73
+ return {}
74
+ result = {}
75
+ for line in lines[1:]:
76
+ if line.strip() == "---":
77
+ return result
78
+ match = re.match(r"^([A-Za-z0-9_-]+):\s*(.+?)\s*$", line.strip())
79
+ if match:
80
+ result[match.group(1)] = match.group(2).strip().strip("\"'")
81
+ return result
82
+
83
+
84
+ def strip_comment(line):
85
+ quote = None
86
+ for index, char in enumerate(line):
87
+ if char in {"'", "\""} and (index == 0 or line[index - 1] != "\\"):
88
+ quote = None if quote == char else quote or char
89
+ if char == "#" and quote is None:
90
+ return line[:index]
91
+ return line
92
+
93
+
94
+ def parse_toml_value(raw):
95
+ value = raw.strip()
96
+ if value == "true":
97
+ return True
98
+ if value == "false":
99
+ return False
100
+ if (value.startswith("\"") and value.endswith("\"")) or (value.startswith("'") and value.endswith("'")):
101
+ return value[1:-1]
102
+ if value.startswith("[") and value.endswith("]"):
103
+ inner = value[1:-1].strip()
104
+ if not inner:
105
+ return []
106
+ items = []
107
+ for part in inner.split(","):
108
+ item = part.strip()
109
+ if not ((item.startswith("\"") and item.endswith("\"")) or (item.startswith("'") and item.endswith("'"))):
110
+ return None
111
+ items.append(item[1:-1])
112
+ return items
113
+ return None
114
+
115
+
116
+ def parse_manifest(path, errors):
117
+ manifest = {"areas": [], "context": []}
118
+ current = None
119
+ for line_number, raw in enumerate(path.read_text(encoding="utf-8").splitlines(), start=1):
120
+ line = strip_comment(raw).strip()
121
+ if not line:
122
+ continue
123
+ match = re.match(r"^\[\[(areas|context)\]\]$", line)
124
+ if match:
125
+ current = {"line": line_number}
126
+ manifest[match.group(1)].append(current)
127
+ continue
128
+ if current is None:
129
+ errors.append(f"project_context/context.toml line {line_number} must appear inside [[areas]] or [[context]]")
130
+ continue
131
+ assignment = re.match(r"^([A-Za-z0-9_-]+)\s*=\s*(.+)$", line)
132
+ if not assignment:
133
+ errors.append(f"project_context/context.toml line {line_number} is not a supported assignment")
134
+ continue
135
+ value = parse_toml_value(assignment.group(2))
136
+ if value is None:
137
+ errors.append(f"project_context/context.toml line {line_number} has an unsupported value")
138
+ continue
139
+ current[assignment.group(1)] = value
140
+ return manifest
141
+
142
+
143
+ def normalize_context_path(value):
144
+ return value.replace("\\", "/").removeprefix("./")
145
+
146
+
147
+ def add_manifest_role(entry, role, roles, errors):
148
+ raw_path = entry.get("context") or entry.get("path")
149
+ if not isinstance(raw_path, str):
150
+ errors.append(f"project_context/context.toml line {entry['line']} must include a context/path string")
151
+ return
152
+ rel = normalize_context_path(raw_path)
153
+ if not rel.startswith("project_context/") or not rel.endswith(".md"):
154
+ errors.append(f"project_context/context.toml line {entry['line']} must reference a markdown file under project_context/")
155
+ return
156
+ existing = roles.get(rel)
157
+ if existing and existing != role:
158
+ errors.append(f"project_context/context.toml assigns conflicting roles to {rel}: {existing} and {role}")
159
+ return
160
+ roles[rel] = role
161
+ if not (ROOT / rel).exists():
162
+ errors.append(f"project_context/context.toml references missing context file: {rel}")
163
+
164
+
165
+ def validate_manifest(errors):
166
+ manifest_path = ROOT / "project_context/context.toml"
167
+ roles = {}
168
+ if not manifest_path.exists():
169
+ if schema_requires_manifest():
170
+ errors.append("missing project_context/context.toml; run ty-context upgrade to create the Schema v4 Context graph manifest")
171
+ return roles
172
+ manifest = parse_manifest(manifest_path, errors)
173
+ if not manifest["areas"]:
174
+ errors.append("project_context/context.toml must declare at least one [[areas]] entry")
175
+ has_default_area = False
176
+ for area in manifest["areas"]:
177
+ for key in ["id", "root", "context"]:
178
+ if not isinstance(area.get(key), str):
179
+ errors.append(f"project_context/context.toml line {area['line']} must include string field {key}")
180
+ default_area = area.get("default")
181
+ if default_area is not None and not isinstance(default_area, bool):
182
+ errors.append(f"project_context/context.toml line {area['line']} default must be a boolean")
183
+ has_default_area = has_default_area or default_area is True
184
+ deps = area.get("forbidden_runtime_dependencies")
185
+ if deps is not None and not is_string_array(deps):
186
+ errors.append(f"project_context/context.toml line {area['line']} forbidden_runtime_dependencies must be an array of strings")
187
+ add_manifest_role(area, "area", roles, errors)
188
+ if manifest["areas"] and not has_default_area:
189
+ errors.append("project_context/context.toml must mark one [[areas]] entry with default = true")
190
+ for context in manifest["context"]:
191
+ role = normalize_role(context.get("role", "")) if isinstance(context.get("role"), str) else None
192
+ if role is None:
193
+ errors.append(f"project_context/context.toml line {context['line']} has unsupported context role")
194
+ continue
195
+ read_policy = context.get("read_policy")
196
+ if read_policy is not None and read_policy not in READ_POLICIES:
197
+ errors.append(f"project_context/context.toml line {context['line']} has unsupported read_policy: {read_policy}")
198
+ for key in ["triggers", "default_children"]:
199
+ value = context.get(key)
200
+ if value is not None and not is_string_array(value):
201
+ errors.append(f"project_context/context.toml line {context['line']} {key} must be an array of strings")
202
+ add_manifest_role(context, role, roles, errors)
203
+ return roles
204
+
205
+
206
+ def is_string_array(value):
207
+ return isinstance(value, list) and all(isinstance(item, str) for item in value)
208
+
209
+
210
+ def schema_requires_manifest():
211
+ schema_version = "4"
212
+ for candidate in CONFIG_CANDIDATES:
213
+ path = ROOT / candidate
214
+ if not path.exists():
215
+ continue
216
+ match = re.search(r'schema_version:\s*["\']?([^"\'\s]+)', path.read_text(encoding="utf-8"))
217
+ if match:
218
+ schema_version = match.group(1)
219
+ break
220
+ try:
221
+ return int(schema_version.split(".", 1)[0]) >= 4
222
+ except ValueError:
223
+ return True
224
+
225
+
226
+ def validate_checks(rel, text, checks, errors):
227
+ for label, terms in checks:
228
+ if not has_any(text, terms):
229
+ errors.append(f"{rel} must include {label}")
230
+
231
+
232
+ def main():
233
+ errors = []
234
+ global_path = ROOT / "project_context/global.md"
235
+ if not global_path.exists():
236
+ errors.append("missing project_context/global.md")
237
+ else:
238
+ validate_checks("project_context/global.md", global_path.read_text(encoding="utf-8"), GLOBAL_CHECKS, errors)
239
+
240
+ architecture_path = ROOT / "project_context/architecture.md"
241
+ if not architecture_path.exists():
242
+ errors.append("missing project_context/architecture.md")
243
+ else:
244
+ validate_checks("project_context/architecture.md", architecture_path.read_text(encoding="utf-8"), ARCHITECTURE_CHECKS, errors)
245
+
246
+ manifest_roles = validate_manifest(errors)
247
+ context_root = ROOT / "project_context"
248
+ context_files = sorted(context_root.rglob("*.md")) if context_root.exists() else []
249
+ checked = 0
250
+ for path in context_files:
251
+ rel = path.relative_to(ROOT).as_posix()
252
+ if rel in {"project_context/global.md", "project_context/architecture.md"}:
253
+ continue
254
+ text = path.read_text(encoding="utf-8")
255
+ front_matter = parse_front_matter(text)
256
+ declared_role = front_matter.get("context_role")
257
+ front_matter_role = normalize_role(declared_role) if declared_role else None
258
+ if declared_role and front_matter_role is None:
259
+ errors.append(f"{rel} has unsupported context_role: {declared_role}")
260
+ read_policy = front_matter.get("read_policy")
261
+ if read_policy and read_policy not in READ_POLICIES:
262
+ errors.append(f"{rel} has unsupported read_policy: {read_policy}")
263
+ role = manifest_roles.get(rel) or front_matter_role
264
+ if role is not None and role not in {"global", "architecture"}:
265
+ checked += 1
266
+
267
+ if errors:
268
+ for error in errors:
269
+ print(f"error: {error}", file=sys.stderr)
270
+ return 1
271
+ print(f"Context OK: {2 + checked} context file(s)")
272
+ return 0
273
+
274
+
275
+ if __name__ == "__main__":
276
+ raise SystemExit(main())
@@ -133,13 +133,13 @@ function parseLimit(value) {
133
133
  return limit;
134
134
  }
135
135
  function helpText() {
136
- return `ty-context check-modularity:
137
- check-modularity --touched [--limit 300] [--fail-on-warning]
138
- check-modularity --file <path> [--file <path> ...] [--limit 300] [--fail-on-warning]
139
- check-modularity --base <ref> [--limit 300] [--fail-on-warning]
140
-
141
- Audits selected handwritten source files for physical line-count risk.
142
- The default is warning-only; --fail-on-warning lets projects opt into CI enforcement.
143
- Generated configs default to modularity.policy: strict_except_generated; omitted policy is treated as scoped_waivers for compatibility.
136
+ return `ty-context check-modularity:
137
+ check-modularity --touched [--limit 300] [--fail-on-warning]
138
+ check-modularity --file <path> [--file <path> ...] [--limit 300] [--fail-on-warning]
139
+ check-modularity --base <ref> [--limit 300] [--fail-on-warning]
140
+
141
+ Audits selected handwritten source files for physical line-count risk.
142
+ The default is warning-only; --fail-on-warning lets projects opt into CI enforcement.
143
+ Generated configs default to modularity.policy: strict_except_generated; omitted policy is treated as scoped_waivers for compatibility.
144
144
  Over-limit files can be waived only through <harnessRoot>/config.yaml modularity.waivers when policy is scoped_waivers.`;
145
145
  }
@@ -136,14 +136,14 @@ function printWarnings(warnings) {
136
136
  }
137
137
  }
138
138
  function helpText() {
139
- return `ty-context export-context:
140
- export-context --full [--output tmp/ty-context/context-exports/<name>.md] [--check]
141
- export-context --code [--output tmp/ty-context/context-exports/<name>.md] [--check]
142
- export-context --all [--check]
143
-
144
- Creates temporary Markdown artifacts for copying or external-tool ingestion.
145
- --full exports the project Context summary as a full-project-context artifact.
146
- --code exports one current implementation snapshot as a code-level-implementation artifact.
147
- --all exports both default artifacts in one command.
139
+ return `ty-context export-context:
140
+ export-context --full [--output tmp/ty-context/context-exports/<name>.md] [--check]
141
+ export-context --code [--output tmp/ty-context/context-exports/<name>.md] [--check]
142
+ export-context --all [--check]
143
+
144
+ Creates temporary Markdown artifacts for copying or external-tool ingestion.
145
+ --full exports the project Context summary as a full-project-context artifact.
146
+ --code exports one current implementation snapshot as a code-level-implementation artifact.
147
+ --all exports both default artifacts in one command.
148
148
  The artifact must stay under tmp/ty-context/context-exports/** and must not be referenced from project_context/context.toml.`;
149
149
  }
@@ -21,21 +21,21 @@ export const commands = {
21
21
  package: packageSource
22
22
  };
23
23
  export function help() {
24
- console.log(`ty-context commands:
25
- init [--adopt] [--harness-folder <path>]
26
- Initialize/adopt a project; without --harness-folder, choose target agent first
27
- sync Refresh managed assets; does not run migrations
28
- upgrade [--check] [--json]
29
- Run safe migrations, sync managed assets and doctor
30
- doctor Diagnose project configuration and drift
31
- check-modularity --touched|--file <path>|--base <ref> [--limit 300] [--fail-on-warning]
32
- Warn when selected handwritten source files exceed a line-count limit
33
- export-context --full|--code|--all [--output <path>] [--check]
34
- Export a temporary Context summary or code implementation Markdown artifact
35
- validate <gate> Run a Harness validation gate
36
- validate-context Validate Minimal Context fact-source recoverability
37
- validate-code-modularity
38
- Enforce touched handwritten source file modularity
39
- validate-harness Run validate-context and validate-code-modularity
24
+ console.log(`ty-context commands:
25
+ init [--adopt] [--harness-folder <path>]
26
+ Initialize/adopt a project; without --harness-folder, choose target agent first
27
+ sync Refresh managed assets; does not run migrations
28
+ upgrade [--check] [--json]
29
+ Run safe migrations, sync managed assets and doctor
30
+ doctor Diagnose project configuration and drift
31
+ check-modularity --touched|--file <path>|--base <ref> [--limit 300] [--fail-on-warning]
32
+ Warn when selected handwritten source files exceed a line-count limit
33
+ export-context --full|--code|--all [--output <path>] [--check]
34
+ Export a temporary Context summary or code implementation Markdown artifact
35
+ validate <gate> Run a Harness validation gate
36
+ validate-context Validate Minimal Context fact-source recoverability
37
+ validate-code-modularity
38
+ Enforce touched handwritten source file modularity
39
+ validate-harness Run validate-context and validate-code-modularity
40
40
  package <subcommand> Maintain package canonical source`);
41
41
  }
@@ -18,7 +18,7 @@ export async function packageSource(args) {
18
18
  console.log("package source OK");
19
19
  return;
20
20
  }
21
- console.log(`ty-context package commands:
22
- sync-source Update package canonical assets from this source workspace
21
+ console.log(`ty-context package commands:
22
+ sync-source Update package canonical assets from this source workspace
23
23
  check-source Verify package canonical assets match this source workspace`);
24
24
  }