@deftai/directive-content 0.59.0 → 0.61.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.
Files changed (190) hide show
  1. package/.githooks/pre-commit +10 -128
  2. package/.githooks/pre-push +8 -108
  3. package/Taskfile.yml +48 -58
  4. package/UPGRADING.md +19 -3
  5. package/docs/assets/directive-lifecycle-diagram.png +0 -0
  6. package/docs/directive-lifecycle.md +73 -0
  7. package/docs/getting-started.md +5 -1
  8. package/package.json +3 -3
  9. package/packs/skills/skills-pack-0.1.json +1 -1
  10. package/packs/strategies/strategies-pack-0.1.json +19 -19
  11. package/scm/github.md +37 -6
  12. package/skills/deft-directive-setup/SKILL.md +24 -15
  13. package/strategies/speckit.md +14 -14
  14. package/strategies/v0-20-contract.md +12 -1
  15. package/tasks/change.yml +16 -31
  16. package/tasks/ci.yml +8 -0
  17. package/tasks/commit.yml +12 -19
  18. package/tasks/core.yml +10 -0
  19. package/tasks/engine.yml +42 -0
  20. package/tasks/framework.yml +3 -0
  21. package/tasks/install.yml +20 -19
  22. package/tasks/migrate.yml +26 -15
  23. package/tasks/project.yml +26 -0
  24. package/tasks/toolchain.yml +15 -5
  25. package/tasks/vbrief.yml +4 -3
  26. package/tasks/verify.yml +12 -14
  27. package/templates/agents-entry.md +1 -1
  28. package/scripts/_agents_md.py +0 -494
  29. package/scripts/_cache_fetch.py +0 -635
  30. package/scripts/_cache_quota.py +0 -529
  31. package/scripts/_cache_refresh.py +0 -163
  32. package/scripts/_cache_validate.py +0 -209
  33. package/scripts/_content_root.py +0 -42
  34. package/scripts/_doctor_state.py +0 -277
  35. package/scripts/_event_detect.py +0 -305
  36. package/scripts/_events.py +0 -514
  37. package/scripts/_lifecycle_hygiene.py +0 -568
  38. package/scripts/_pathspec.py +0 -91
  39. package/scripts/_policy_show_cli.py +0 -266
  40. package/scripts/_precutover.py +0 -92
  41. package/scripts/_project_context.py +0 -224
  42. package/scripts/_project_definition_io.py +0 -164
  43. package/scripts/_relocate_snapshot.py +0 -209
  44. package/scripts/_relocate_states.py +0 -343
  45. package/scripts/_resolve_preflight_path.py +0 -152
  46. package/scripts/_safe_subprocess.py +0 -167
  47. package/scripts/_session_start_hook.py +0 -205
  48. package/scripts/_sor_gate_diff.py +0 -365
  49. package/scripts/_stdio_utf8.py +0 -59
  50. package/scripts/_triage_bootstrap_gitignore.py +0 -904
  51. package/scripts/_triage_classify_cli.py +0 -122
  52. package/scripts/_triage_queue_cli.py +0 -625
  53. package/scripts/_triage_scope_cli.py +0 -343
  54. package/scripts/_triage_scope_drift_cli.py +0 -121
  55. package/scripts/_triage_scope_ignores.py +0 -286
  56. package/scripts/_triage_scope_milestone.py +0 -432
  57. package/scripts/_triage_scope_mutations.py +0 -337
  58. package/scripts/_triage_scope_renderers.py +0 -207
  59. package/scripts/_triage_smoketest_stages.py +0 -674
  60. package/scripts/_triage_subscribe_cli.py +0 -140
  61. package/scripts/_triage_welcome_cli.py +0 -421
  62. package/scripts/_vbrief_build.py +0 -239
  63. package/scripts/_vbrief_fidelity.py +0 -479
  64. package/scripts/_vbrief_legacy.py +0 -589
  65. package/scripts/_vbrief_reconciliation.py +0 -883
  66. package/scripts/_vbrief_routing.py +0 -277
  67. package/scripts/_vbrief_safety.py +0 -778
  68. package/scripts/_vbrief_sources.py +0 -312
  69. package/scripts/_vbrief_speckit.py +0 -262
  70. package/scripts/_vbrief_story_quality.py +0 -353
  71. package/scripts/_vbrief_validation.py +0 -299
  72. package/scripts/build_dist.py +0 -412
  73. package/scripts/cache.py +0 -1078
  74. package/scripts/cache_scanner.py +0 -745
  75. package/scripts/candidates_log.py +0 -432
  76. package/scripts/capacity_backfill.py +0 -680
  77. package/scripts/capacity_show.py +0 -653
  78. package/scripts/ci_local.py +0 -689
  79. package/scripts/code_structure_validate.py +0 -765
  80. package/scripts/codebase_default_extractor.py +0 -495
  81. package/scripts/codebase_map.py +0 -304
  82. package/scripts/codebase_map_fresh.py +0 -104
  83. package/scripts/codebase_projection_registry.py +0 -94
  84. package/scripts/codebase_provider.py +0 -582
  85. package/scripts/doctor.py +0 -2552
  86. package/scripts/framework_commands.py +0 -505
  87. package/scripts/gh_rest.py +0 -882
  88. package/scripts/github_auth_modes.py +0 -437
  89. package/scripts/github_body.py +0 -292
  90. package/scripts/ip_risk.py +0 -531
  91. package/scripts/issue_emit.py +0 -670
  92. package/scripts/issue_ingest.py +0 -1064
  93. package/scripts/migrate_preflight.py +0 -418
  94. package/scripts/migrate_vbrief.py +0 -2677
  95. package/scripts/monitor_pr.py +0 -401
  96. package/scripts/pack_migrate_lessons.py +0 -336
  97. package/scripts/pack_migrate_patterns.py +0 -254
  98. package/scripts/pack_migrate_rules.py +0 -350
  99. package/scripts/pack_migrate_skills.py +0 -423
  100. package/scripts/pack_migrate_strategies.py +0 -311
  101. package/scripts/pack_migrate_swarm_spec.py +0 -250
  102. package/scripts/pack_render.py +0 -434
  103. package/scripts/packs_slice.py +0 -712
  104. package/scripts/platform_capabilities.py +0 -336
  105. package/scripts/policy.py +0 -2826
  106. package/scripts/policy_set.py +0 -324
  107. package/scripts/pr_check_closing_keywords.py +0 -524
  108. package/scripts/pr_check_protected_issues.py +0 -267
  109. package/scripts/pr_merge_readiness.py +0 -1004
  110. package/scripts/pr_wait_mergeable.py +0 -669
  111. package/scripts/prd_render.py +0 -159
  112. package/scripts/preflight_architecture_sor.py +0 -974
  113. package/scripts/preflight_branch.py +0 -289
  114. package/scripts/preflight_cache.py +0 -974
  115. package/scripts/preflight_gh.py +0 -721
  116. package/scripts/preflight_implementation.py +0 -272
  117. package/scripts/preflight_story_start.py +0 -838
  118. package/scripts/preflight_wip_cap.py +0 -149
  119. package/scripts/probe_session.py +0 -545
  120. package/scripts/project_render.py +0 -293
  121. package/scripts/quarantine_ext.py +0 -237
  122. package/scripts/reconcile_issues.py +0 -1442
  123. package/scripts/refresh-path.ps1 +0 -107
  124. package/scripts/release.py +0 -2030
  125. package/scripts/release_e2e.py +0 -1011
  126. package/scripts/release_publish.py +0 -486
  127. package/scripts/release_rollback.py +0 -980
  128. package/scripts/relocate.py +0 -1034
  129. package/scripts/resolve_changelog_unreleased.py +0 -667
  130. package/scripts/resolve_version.py +0 -490
  131. package/scripts/resume_conditions.py +0 -706
  132. package/scripts/ritual_sentinel.py +0 -609
  133. package/scripts/roadmap_render.py +0 -635
  134. package/scripts/rule_ownership_lint.py +0 -325
  135. package/scripts/scm.py +0 -591
  136. package/scripts/scope_audit_log.py +0 -387
  137. package/scripts/scope_decompose.py +0 -654
  138. package/scripts/scope_demote.py +0 -509
  139. package/scripts/scope_lifecycle.py +0 -1126
  140. package/scripts/scope_undo.py +0 -772
  141. package/scripts/session_start.py +0 -406
  142. package/scripts/setup_ghx.py +0 -339
  143. package/scripts/setup_windows.ps1 +0 -220
  144. package/scripts/slice_audit.py +0 -585
  145. package/scripts/slice_record.py +0 -530
  146. package/scripts/slice_record_existing.py +0 -692
  147. package/scripts/slug_normalize.py +0 -178
  148. package/scripts/spec_render.py +0 -477
  149. package/scripts/spec_validate.py +0 -238
  150. package/scripts/subagent_monitor.py +0 -658
  151. package/scripts/swarm_complete_cohort.py +0 -644
  152. package/scripts/swarm_launch.py +0 -1206
  153. package/scripts/swarm_readiness.py +0 -554
  154. package/scripts/swarm_verify_review_clean.py +0 -438
  155. package/scripts/swarm_worktrees.py +0 -497
  156. package/scripts/toolchain-check.py +0 -52
  157. package/scripts/triage_actions.py +0 -871
  158. package/scripts/triage_bootstrap.py +0 -1153
  159. package/scripts/triage_bulk.py +0 -630
  160. package/scripts/triage_classify.py +0 -932
  161. package/scripts/triage_help.py +0 -1685
  162. package/scripts/triage_queue.py +0 -1944
  163. package/scripts/triage_reconcile.py +0 -581
  164. package/scripts/triage_refresh.py +0 -643
  165. package/scripts/triage_scope.py +0 -999
  166. package/scripts/triage_scope_drift.py +0 -575
  167. package/scripts/triage_smoketest.py +0 -396
  168. package/scripts/triage_subscribe.py +0 -399
  169. package/scripts/triage_summary.py +0 -1011
  170. package/scripts/triage_welcome.py +0 -1178
  171. package/scripts/ts_check_lane.py +0 -86
  172. package/scripts/validate-links.py +0 -64
  173. package/scripts/validate_strategy_output.py +0 -212
  174. package/scripts/vbrief_activate.py +0 -228
  175. package/scripts/vbrief_migrate_conformance.py +0 -368
  176. package/scripts/vbrief_reconcile_graph.py +0 -306
  177. package/scripts/vbrief_reconcile_labels.py +0 -460
  178. package/scripts/vbrief_reconcile_umbrellas.py +0 -741
  179. package/scripts/vbrief_validate.py +0 -1144
  180. package/scripts/verify-stubs.py +0 -61
  181. package/scripts/verify_capacity.py +0 -160
  182. package/scripts/verify_encoding.py +0 -699
  183. package/scripts/verify_hooks_installed.py +0 -206
  184. package/scripts/verify_investigation.py +0 -360
  185. package/scripts/verify_judgment_gates.py +0 -827
  186. package/scripts/verify_no_task_runtime.py +0 -171
  187. package/scripts/verify_scm_boundary.py +0 -509
  188. package/scripts/verify_session_ritual.py +0 -389
  189. package/scripts/verify_tools.py +0 -426
  190. package/scripts/verify_vbrief_conformance.py +0 -478
@@ -1,336 +0,0 @@
1
- #!/usr/bin/env python3
2
- """platform_capabilities.py -- read-only worker runtime capability probe (#1557a).
3
-
4
- Classifies the execution envelope a swarm worker will actually run in:
5
-
6
- - ``local-unsandboxed`` -- interactive local shell without Cursor native sandbox.
7
- - ``cursor-native-sandbox`` -- Cursor native sandbox with UID remap to the host user.
8
- - ``cloud-headless`` -- cloud or headless agent runtimes without local host context.
9
-
10
- The probe is intentionally read-only: it inspects environment variables,
11
- ``/proc/self/uid_map`` (when available), process identity, and basic cwd
12
- ownership facts. It does not mutate credentials, shell out to ``gh``, or
13
- touch vBRIEF lifecycle files.
14
- """
15
-
16
- from __future__ import annotations
17
-
18
- import argparse
19
- import contextlib
20
- import dataclasses
21
- import getpass
22
- import json
23
- import os
24
- import sys
25
- from collections.abc import Mapping, Sequence
26
- from dataclasses import dataclass
27
- from pathlib import Path
28
- from typing import Any
29
-
30
- sys.path.insert(0, str(Path(__file__).resolve().parent))
31
-
32
- from _stdio_utf8 import reconfigure_stdio # noqa: E402
33
-
34
- reconfigure_stdio()
35
-
36
- RUNTIME_MODE_LOCAL_UNSANDBOXED = "local-unsandboxed"
37
- RUNTIME_MODE_CURSOR_NATIVE_SANDBOX = "cursor-native-sandbox"
38
- RUNTIME_MODE_CLOUD_HEADLESS = "cloud-headless"
39
-
40
- KNOWN_RUNTIME_MODES: frozenset[str] = frozenset(
41
- {
42
- RUNTIME_MODE_LOCAL_UNSANDBOXED,
43
- RUNTIME_MODE_CURSOR_NATIVE_SANDBOX,
44
- RUNTIME_MODE_CLOUD_HEADLESS,
45
- }
46
- )
47
-
48
- IDENTITY_REAL_ROOT = "real-root"
49
- IDENTITY_SANDBOX_REMAPPED_LOCAL_USER = "sandbox-remapped-local-user"
50
- IDENTITY_LOCAL_USER = "local-user"
51
- IDENTITY_UNKNOWN = "unknown"
52
-
53
- _TRUTHY = frozenset({"1", "true", "yes", "on"})
54
-
55
- # Env vars surfaced in the report (values only; never treated as secrets here).
56
- _CURSOR_SIGNAL_VARS = (
57
- "CURSOR_SANDBOX",
58
- "CURSOR_SANDBOX_LANDLOCK_STATUS",
59
- "CURSOR_ORIG_UID",
60
- "CURSOR_ORIG_GID",
61
- "CURSOR_AGENT",
62
- "CURSOR_COMPOSER",
63
- )
64
-
65
- _CLOUD_SIGNAL_VARS = (
66
- "CURSOR_AGENT",
67
- "GROK_BUILD",
68
- "DEFT_AGENT_RUNTIME",
69
- "CI",
70
- "GITHUB_ACTIONS",
71
- "BUILDKITE",
72
- )
73
-
74
-
75
- @dataclass(frozen=True)
76
- class UidMapEntry:
77
- """One row from ``/proc/self/uid_map``."""
78
-
79
- inside_id: int
80
- outside_id: int
81
- length: int
82
-
83
-
84
- @dataclass(frozen=True)
85
- class OwnershipFacts:
86
- """Basic ownership interpretation for a path (typically cwd)."""
87
-
88
- path: str
89
- uid: int
90
- gid: int
91
- interpreted_as_sandbox_view: bool
92
-
93
-
94
- @dataclass(frozen=True)
95
- class RuntimeCapabilityReport:
96
- """Structured runtime capability probe output."""
97
-
98
- runtime_mode: str
99
- identity_kind: str
100
- effective_uid: int | None
101
- effective_username: str | None
102
- uid_map: tuple[UidMapEntry, ...]
103
- cursor_orig_uid: int | None
104
- cursor_orig_gid: int | None
105
- sandbox_uid_remap: bool
106
- ownership: OwnershipFacts | None
107
- signals: dict[str, str]
108
-
109
- def to_dict(self) -> dict[str, Any]:
110
- payload = dataclasses.asdict(self)
111
- if self.ownership is not None:
112
- payload["ownership"] = dataclasses.asdict(self.ownership)
113
- payload["uid_map"] = [dataclasses.asdict(entry) for entry in self.uid_map]
114
- return payload
115
-
116
-
117
- def _env_truthy(environ: Mapping[str, str], name: str) -> bool:
118
- return environ.get(name, "").strip().lower() in _TRUTHY
119
-
120
-
121
- def _parse_int(value: str | None) -> int | None:
122
- if value is None:
123
- return None
124
- text = value.strip()
125
- if not text:
126
- return None
127
- try:
128
- return int(text)
129
- except ValueError:
130
- return None
131
-
132
-
133
- def read_uid_map(path: Path) -> tuple[UidMapEntry, ...]:
134
- """Parse a uid_map file (typically ``/proc/self/uid_map``)."""
135
- if not path.is_file():
136
- return ()
137
- entries: list[UidMapEntry] = []
138
- for raw_line in path.read_text(encoding="utf-8").splitlines():
139
- line = raw_line.strip()
140
- if not line or line.startswith("#"):
141
- continue
142
- parts = line.split()
143
- if len(parts) != 3:
144
- continue
145
- try:
146
- inside_id, outside_id, length = (int(parts[0]), int(parts[1]), int(parts[2]))
147
- except ValueError:
148
- continue
149
- entries.append(
150
- UidMapEntry(inside_id=inside_id, outside_id=outside_id, length=length)
151
- )
152
- return tuple(entries)
153
-
154
-
155
- def detect_sandbox_uid_remap(
156
- uid_map: Sequence[UidMapEntry],
157
- *,
158
- effective_uid: int | None,
159
- cursor_orig_uid: int | None,
160
- ) -> bool:
161
- """True when sandbox UID 0 is remapped to the host user, not real root."""
162
- if effective_uid != 0:
163
- return False
164
- if cursor_orig_uid is None:
165
- return False
166
- return any(
167
- entry.inside_id == 0 and entry.outside_id == cursor_orig_uid
168
- for entry in uid_map
169
- )
170
-
171
-
172
- def classify_identity_kind(
173
- *,
174
- effective_uid: int | None,
175
- sandbox_uid_remap: bool,
176
- ) -> str:
177
- if effective_uid is None:
178
- return IDENTITY_UNKNOWN
179
- if effective_uid == 0:
180
- if sandbox_uid_remap:
181
- return IDENTITY_SANDBOX_REMAPPED_LOCAL_USER
182
- return IDENTITY_REAL_ROOT
183
- return IDENTITY_LOCAL_USER
184
-
185
-
186
- def _is_cloud_headless(environ: Mapping[str, str]) -> bool:
187
- if _env_truthy(environ, "CURSOR_AGENT"):
188
- return True
189
- if _env_truthy(environ, "GROK_BUILD"):
190
- return True
191
- runtime = environ.get("DEFT_AGENT_RUNTIME", "").strip().lower()
192
- if runtime in {"grok-build", "cloud", "headless"}:
193
- return True
194
- if _env_truthy(environ, "GITHUB_ACTIONS") or _env_truthy(environ, "BUILDKITE"):
195
- return True
196
- return _env_truthy(environ, "CI") and not _env_truthy(environ, "CURSOR_COMPOSER")
197
-
198
-
199
- def _is_cursor_native_sandbox(
200
- environ: Mapping[str, str],
201
- *,
202
- sandbox_uid_remap: bool,
203
- ) -> bool:
204
- if sandbox_uid_remap:
205
- return True
206
- if _env_truthy(environ, "CURSOR_SANDBOX"):
207
- return True
208
- return bool(environ.get("CURSOR_SANDBOX_LANDLOCK_STATUS", "").strip())
209
-
210
-
211
- def classify_runtime_mode(
212
- environ: Mapping[str, str],
213
- *,
214
- sandbox_uid_remap: bool,
215
- ) -> str:
216
- if _is_cloud_headless(environ):
217
- return RUNTIME_MODE_CLOUD_HEADLESS
218
- if _is_cursor_native_sandbox(environ, sandbox_uid_remap=sandbox_uid_remap):
219
- return RUNTIME_MODE_CURSOR_NATIVE_SANDBOX
220
- return RUNTIME_MODE_LOCAL_UNSANDBOXED
221
-
222
-
223
- def _read_ownership(path: Path, *, sandbox_uid_remap: bool) -> OwnershipFacts | None:
224
- try:
225
- stat_result = path.stat()
226
- except OSError:
227
- return None
228
- return OwnershipFacts(
229
- path=str(path),
230
- uid=stat_result.st_uid,
231
- gid=stat_result.st_gid,
232
- interpreted_as_sandbox_view=sandbox_uid_remap,
233
- )
234
-
235
-
236
- def _collect_signals(environ: Mapping[str, str]) -> dict[str, str]:
237
- names = sorted(set(_CURSOR_SIGNAL_VARS + _CLOUD_SIGNAL_VARS))
238
- return {name: environ[name] for name in names if name in environ}
239
-
240
-
241
- def probe_runtime_capabilities(
242
- *,
243
- environ: Mapping[str, str] | None = None,
244
- uid_map_path: Path | str | None = None,
245
- cwd: Path | str | None = None,
246
- effective_uid_override: int | None = None,
247
- ) -> RuntimeCapabilityReport:
248
- """Probe the current (or injected) worker runtime envelope."""
249
- env = dict(os.environ if environ is None else environ)
250
-
251
- effective_uid: int | None
252
- if effective_uid_override is not None:
253
- effective_uid = effective_uid_override
254
- elif hasattr(os, "getuid"):
255
- effective_uid = os.getuid()
256
- else:
257
- effective_uid = None
258
-
259
- effective_username = env.get("USER") or env.get("USERNAME")
260
- if not effective_username:
261
- with contextlib.suppress(Exception):
262
- effective_username = getpass.getuser()
263
-
264
- cursor_orig_uid = _parse_int(env.get("CURSOR_ORIG_UID"))
265
- cursor_orig_gid = _parse_int(env.get("CURSOR_ORIG_GID"))
266
-
267
- uid_map_file = (
268
- Path(uid_map_path)
269
- if uid_map_path is not None
270
- else Path("/proc/self/uid_map")
271
- )
272
- uid_map = read_uid_map(uid_map_file)
273
-
274
- sandbox_uid_remap = detect_sandbox_uid_remap(
275
- uid_map,
276
- effective_uid=effective_uid,
277
- cursor_orig_uid=cursor_orig_uid,
278
- )
279
- identity_kind = classify_identity_kind(
280
- effective_uid=effective_uid,
281
- sandbox_uid_remap=sandbox_uid_remap,
282
- )
283
- runtime_mode = classify_runtime_mode(
284
- env,
285
- sandbox_uid_remap=sandbox_uid_remap,
286
- )
287
-
288
- cwd_path = Path(cwd) if cwd is not None else Path.cwd()
289
- ownership = _read_ownership(cwd_path, sandbox_uid_remap=sandbox_uid_remap)
290
-
291
- return RuntimeCapabilityReport(
292
- runtime_mode=runtime_mode,
293
- identity_kind=identity_kind,
294
- effective_uid=effective_uid,
295
- effective_username=effective_username,
296
- uid_map=uid_map,
297
- cursor_orig_uid=cursor_orig_uid,
298
- cursor_orig_gid=cursor_orig_gid,
299
- sandbox_uid_remap=sandbox_uid_remap,
300
- ownership=ownership,
301
- signals=_collect_signals(env),
302
- )
303
-
304
-
305
- def get_platform_capabilities() -> RuntimeCapabilityReport:
306
- """Return runtime capabilities for the live worker environment."""
307
- return probe_runtime_capabilities()
308
-
309
-
310
- def main(argv: Sequence[str] | None = None) -> int:
311
- parser = argparse.ArgumentParser(
312
- description="Read-only worker runtime capability probe (#1557a)."
313
- )
314
- parser.add_argument(
315
- "--json",
316
- action="store_true",
317
- help="Emit structured JSON on stdout.",
318
- )
319
- args = parser.parse_args(list(argv) if argv is not None else None)
320
-
321
- report = get_platform_capabilities()
322
- if args.json:
323
- print(json.dumps(report.to_dict(), indent=2, sort_keys=True))
324
- else:
325
- print(f"runtime_mode={report.runtime_mode}")
326
- print(f"identity_kind={report.identity_kind}")
327
- if report.sandbox_uid_remap:
328
- print(
329
- "sandbox_uid_remap=true "
330
- f"(host_uid={report.cursor_orig_uid})"
331
- )
332
- return 0
333
-
334
-
335
- if __name__ == "__main__":
336
- raise SystemExit(main())