millforge 0.1.0__py3-none-any.whl
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.
- millforge/__init__.py +1174 -0
- millforge/_forge/LICENSE +21 -0
- millforge/_forge/PROVENANCE.json +295 -0
- millforge/_forge/UPDATE_POLICY.md +24 -0
- millforge/_forge/__init__.py +14 -0
- millforge/_forge/adapter.py +2232 -0
- millforge/_forge/base_runner.py +121 -0
- millforge/_forge/clients/__init__.py +10 -0
- millforge/_forge/clients/base.py +200 -0
- millforge/_forge/context/__init__.py +23 -0
- millforge/_forge/context/manager.py +178 -0
- millforge/_forge/context/strategies.py +335 -0
- millforge/_forge/core/__init__.py +16 -0
- millforge/_forge/core/inference.py +433 -0
- millforge/_forge/core/messages.py +119 -0
- millforge/_forge/core/runner.py +479 -0
- millforge/_forge/core/steps.py +108 -0
- millforge/_forge/core/workflow.py +400 -0
- millforge/_forge/errors.py +222 -0
- millforge/_forge/guardrails/__init__.py +21 -0
- millforge/_forge/guardrails/error_tracker.py +71 -0
- millforge/_forge/guardrails/guardrails.py +194 -0
- millforge/_forge/guardrails/nudge.py +47 -0
- millforge/_forge/guardrails/response_validator.py +119 -0
- millforge/_forge/guardrails/step_enforcer.py +183 -0
- millforge/_forge/prompts/__init__.py +16 -0
- millforge/_forge/prompts/nudges.py +95 -0
- millforge/_forge/prompts/templates.py +285 -0
- millforge/_version.py +3 -0
- millforge/artifacts.py +570 -0
- millforge/base/__init__.py +97 -0
- millforge/base/composition.py +402 -0
- millforge/base/context.py +285 -0
- millforge/base/harness.py +138 -0
- millforge/base/identity.py +465 -0
- millforge/base/options.py +34 -0
- millforge/base/platform.py +17 -0
- millforge/base/prompt.py +317 -0
- millforge/base/runner.py +546 -0
- millforge/compiled_plan.py +970 -0
- millforge/compiler/__init__.py +231 -0
- millforge/compiler/artifact_validation.py +257 -0
- millforge/compiler/canonicalization.py +169 -0
- millforge/compiler/capabilities.py +66 -0
- millforge/compiler/catalogs.py +500 -0
- millforge/compiler/diagnostics.py +491 -0
- millforge/compiler/graph.py +678 -0
- millforge/compiler/lowering.py +198 -0
- millforge/compiler/output.py +692 -0
- millforge/compiler/parsing.py +1424 -0
- millforge/compiler/requests.py +1180 -0
- millforge/compiler/schema_validation.py +272 -0
- millforge/compiler/semantic.py +490 -0
- millforge/compiler/service.py +448 -0
- millforge/compiler/source.py +375 -0
- millforge/compiler/validators.py +184 -0
- millforge/connectors/__init__.py +95 -0
- millforge/connectors/admission.py +801 -0
- millforge/connectors/broker.py +202 -0
- millforge/connectors/contracts.py +1159 -0
- millforge/connectors/diagnostics.py +189 -0
- millforge/connectors/fake.py +66 -0
- millforge/connectors/runtime.py +236 -0
- millforge/contracts.py +2860 -0
- millforge/custom_tools/__init__.py +67 -0
- millforge/custom_tools/compiler.py +724 -0
- millforge/custom_tools/contracts.py +1093 -0
- millforge/custom_tools/diagnostics.py +205 -0
- millforge/eval_artifacts.py +952 -0
- millforge/eval_boundary.py +2435 -0
- millforge/eval_fixtures/__init__.py +1 -0
- millforge/eval_fixtures/default_pack/__init__.py +1 -0
- millforge/eval_fixtures/default_pack/fixtures/fixture.08a.bug_diagnosis.traceback.v1.json +52 -0
- millforge/eval_fixtures/default_pack/fixtures/fixture.08a.direct_edit.import_sort.v1.json +52 -0
- millforge/eval_fixtures/default_pack/fixtures/fixture.08a.evidence_discipline.no_source_change.v1.json +51 -0
- millforge/eval_fixtures/default_pack/fixtures/fixture.08a.false_closure.visible_green.v1.json +52 -0
- millforge/eval_fixtures/default_pack/fixtures/fixture.08a.multi_file.api_contract.v1.json +54 -0
- millforge/eval_fixtures/default_pack/fixtures/fixture.08a.recovery.malformed_artifact.v1.json +54 -0
- millforge/eval_fixtures/default_pack/manifest.json +12 -0
- millforge/eval_modes.py +1282 -0
- millforge/eval_presets.py +1398 -0
- millforge/eval_reports.py +2517 -0
- millforge/eval_suite.py +2429 -0
- millforge/eval_trials.py +2632 -0
- millforge/eval_workflow.py +794 -0
- millforge/exceptions.py +122 -0
- millforge/model_backend.py +2098 -0
- millforge/protocols.py +340 -0
- millforge/py.typed +0 -0
- millforge/runtime.py +1791 -0
- millforge/testing/__init__.py +1089 -0
- millforge/tools/__init__.py +83 -0
- millforge/tools/builtin_runtime.py +1339 -0
- millforge/tools/builtins.py +773 -0
- millforge/tools/execution.py +1545 -0
- millforge/tools/path_policy.py +155 -0
- millforge/tools/pi_compat/PI_LICENSE +21 -0
- millforge/tools/pi_compat/PROVENANCE.json +55 -0
- millforge/tools/pi_compat/UPDATE_POLICY.md +36 -0
- millforge/tools/pi_compat/__init__.py +34 -0
- millforge/tools/pi_compat/contracts.py +49 -0
- millforge/tools/pi_compat/editing.py +390 -0
- millforge/tools/pi_compat/mutations.py +57 -0
- millforge/tools/pi_compat/operations.py +401 -0
- millforge/tools/pi_compat/paths.py +155 -0
- millforge/tools/pi_compat/process.py +1375 -0
- millforge/tools/pi_compat/search.py +738 -0
- millforge/tools/pi_compat/truncation.py +267 -0
- millforge/tools/pi_compat_catalog.py +396 -0
- millforge/tools/pi_compat_runtime.py +460 -0
- millforge/tools/registry.py +553 -0
- millforge/tools/results.py +533 -0
- millforge-0.1.0.dist-info/METADATA +844 -0
- millforge-0.1.0.dist-info/RECORD +116 -0
- millforge-0.1.0.dist-info/WHEEL +4 -0
- millforge-0.1.0.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""Contained logical path policy for built-in runtime tools."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import re
|
|
7
|
+
import tempfile
|
|
8
|
+
from pathlib import Path, PurePosixPath
|
|
9
|
+
|
|
10
|
+
_WINDOWS_DRIVE_RE = re.compile(r"^[a-zA-Z]:")
|
|
11
|
+
_WINDOWS_DEVICE_PREFIXES = ("\\\\?\\", "\\\\.\\", "//?/", "//./")
|
|
12
|
+
_UNC_PREFIXES = ("\\\\", "//")
|
|
13
|
+
_WINDOWS_RESERVED_DEVICE_NAMES = frozenset(
|
|
14
|
+
{
|
|
15
|
+
"aux",
|
|
16
|
+
"con",
|
|
17
|
+
"conin$",
|
|
18
|
+
"conout$",
|
|
19
|
+
"nul",
|
|
20
|
+
"prn",
|
|
21
|
+
*{f"com{i}" for i in range(1, 10)},
|
|
22
|
+
*{f"lpt{i}" for i in range(1, 10)},
|
|
23
|
+
}
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class PathPolicyError(ValueError):
|
|
28
|
+
"""Raised when a model-provided logical path is outside policy."""
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def validate_logical_path(value: str, *, allow_dot: bool = False) -> PurePosixPath:
|
|
32
|
+
"""Validate a model-visible logical path before host resolution."""
|
|
33
|
+
if not isinstance(value, str) or not value.strip():
|
|
34
|
+
raise PathPolicyError("path must be a non-empty logical relative path")
|
|
35
|
+
if "\x00" in value:
|
|
36
|
+
raise PathPolicyError("path contains a NUL byte")
|
|
37
|
+
if "\\" in value:
|
|
38
|
+
raise PathPolicyError("path must use POSIX separators")
|
|
39
|
+
if ":" in value:
|
|
40
|
+
raise PathPolicyError("path must not contain Windows drive or ADS syntax")
|
|
41
|
+
if value.startswith(_WINDOWS_DEVICE_PREFIXES) or value.startswith(_UNC_PREFIXES):
|
|
42
|
+
raise PathPolicyError("path must not use Windows device or UNC syntax")
|
|
43
|
+
if _WINDOWS_DRIVE_RE.match(value):
|
|
44
|
+
raise PathPolicyError("path must not use a Windows drive prefix")
|
|
45
|
+
path = PurePosixPath(value)
|
|
46
|
+
if path.is_absolute() or value.startswith("/"):
|
|
47
|
+
raise PathPolicyError("path must not be absolute")
|
|
48
|
+
if value.startswith("~"):
|
|
49
|
+
raise PathPolicyError("path must not use home-directory syntax")
|
|
50
|
+
parts = path.parts
|
|
51
|
+
if any(part in ("", "..") for part in parts):
|
|
52
|
+
raise PathPolicyError("path must not contain traversal components")
|
|
53
|
+
if not allow_dot and any(part == "." for part in parts):
|
|
54
|
+
raise PathPolicyError("path must not contain current-directory components")
|
|
55
|
+
if parts == (".",) and not allow_dot:
|
|
56
|
+
raise PathPolicyError("path must not be current directory")
|
|
57
|
+
_reject_windows_reserved_device_names(parts)
|
|
58
|
+
return path
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def resolve_existing_contained(
|
|
62
|
+
root: Path, logical: str, *, allow_dot: bool = False
|
|
63
|
+
) -> Path:
|
|
64
|
+
"""Resolve an existing logical path under a trusted root."""
|
|
65
|
+
path = validate_logical_path(logical, allow_dot=allow_dot)
|
|
66
|
+
root_resolved = root.resolve(strict=True)
|
|
67
|
+
candidate = (root_resolved / Path(*path.parts)).resolve(strict=True)
|
|
68
|
+
_ensure_contained(root_resolved, candidate)
|
|
69
|
+
return candidate
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def resolve_write_contained(root: Path, logical: str) -> Path:
|
|
73
|
+
"""Resolve a writable logical file path under a trusted root."""
|
|
74
|
+
path = validate_logical_path(logical)
|
|
75
|
+
root_resolved = root.resolve(strict=True)
|
|
76
|
+
candidate = root_resolved / Path(*path.parts)
|
|
77
|
+
parent = candidate.parent.resolve(strict=True)
|
|
78
|
+
_ensure_contained(root_resolved, parent)
|
|
79
|
+
if candidate.exists() or candidate.is_symlink():
|
|
80
|
+
resolved = candidate.resolve(strict=True)
|
|
81
|
+
_ensure_contained(root_resolved, resolved)
|
|
82
|
+
if resolved.is_dir():
|
|
83
|
+
raise PathPolicyError("path resolves to a directory")
|
|
84
|
+
return resolved
|
|
85
|
+
return parent / candidate.name
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def atomic_write_contained(root: Path, logical: str, content: bytes) -> str:
|
|
89
|
+
"""Atomically write bytes to a contained logical path and return sha256."""
|
|
90
|
+
target = resolve_write_contained(root, logical)
|
|
91
|
+
digest = canonical_sha256_bytes(content)
|
|
92
|
+
fd: int | None = None
|
|
93
|
+
tmp_path: str | None = None
|
|
94
|
+
try:
|
|
95
|
+
fd, tmp_path = tempfile.mkstemp(
|
|
96
|
+
dir=str(target.parent),
|
|
97
|
+
prefix=f".{target.name}.tmp.",
|
|
98
|
+
)
|
|
99
|
+
with os.fdopen(fd, "wb") as handle:
|
|
100
|
+
fd = None
|
|
101
|
+
handle.write(content)
|
|
102
|
+
handle.flush()
|
|
103
|
+
os.fsync(handle.fileno())
|
|
104
|
+
os.replace(tmp_path, target)
|
|
105
|
+
tmp_path = None
|
|
106
|
+
finally:
|
|
107
|
+
if fd is not None:
|
|
108
|
+
try:
|
|
109
|
+
os.close(fd)
|
|
110
|
+
except OSError:
|
|
111
|
+
pass
|
|
112
|
+
if tmp_path is not None:
|
|
113
|
+
try:
|
|
114
|
+
os.unlink(tmp_path)
|
|
115
|
+
except OSError:
|
|
116
|
+
pass
|
|
117
|
+
return digest
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def canonical_sha256_bytes(content: bytes) -> str:
|
|
121
|
+
"""Hash raw bytes using the same lowercase SHA-256 format as JSON results."""
|
|
122
|
+
import hashlib
|
|
123
|
+
|
|
124
|
+
return hashlib.sha256(content).hexdigest()
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def logical_from_resolved(root: Path, target: Path) -> str:
|
|
128
|
+
"""Return a POSIX logical path after containment has already been enforced."""
|
|
129
|
+
root_resolved = root.resolve(strict=True)
|
|
130
|
+
resolved = target.resolve(strict=True)
|
|
131
|
+
_ensure_contained(root_resolved, resolved)
|
|
132
|
+
return resolved.relative_to(root_resolved).as_posix()
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _ensure_contained(root: Path, candidate: Path) -> None:
|
|
136
|
+
try:
|
|
137
|
+
candidate.relative_to(root)
|
|
138
|
+
except ValueError as exc:
|
|
139
|
+
raise PathPolicyError("path resolves outside the trusted root") from exc
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _reject_windows_reserved_device_names(parts: tuple[str, ...]) -> None:
|
|
143
|
+
for part in parts:
|
|
144
|
+
if part in (".", ".."):
|
|
145
|
+
continue
|
|
146
|
+
if _is_windows_reserved_device_name(part):
|
|
147
|
+
raise PathPolicyError("path must not use a reserved Windows device name")
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _is_windows_reserved_device_name(part: str) -> bool:
|
|
151
|
+
trimmed = part.rstrip(" .")
|
|
152
|
+
if not trimmed:
|
|
153
|
+
return False
|
|
154
|
+
base = trimmed.split(".", 1)[0].rstrip(" .").casefold()
|
|
155
|
+
return base in _WINDOWS_RESERVED_DEVICE_NAMES
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Mario Zechner
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": 1,
|
|
3
|
+
"upstream": {
|
|
4
|
+
"repository": "https://github.com/earendil-works/pi",
|
|
5
|
+
"package": "@earendil-works/pi-coding-agent",
|
|
6
|
+
"version": "0.79.6",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"copyright": "Copyright (c) 2025 Mario Zechner"
|
|
9
|
+
},
|
|
10
|
+
"source_snapshot": "reference/pi/",
|
|
11
|
+
"source_history": "The approved reference copy is history-free. No upstream commit hash is recorded or inferred.",
|
|
12
|
+
"adaptations": [
|
|
13
|
+
"Python filesystem and process APIs replace Node APIs.",
|
|
14
|
+
"`pathspec` and the exact Section 7 ignore rules replace `fd`/`rg` discovery.",
|
|
15
|
+
"Python regex/glob, binary detection, decoding, traversal, and error rules are the exact Section 7 search adaptation.",
|
|
16
|
+
"supported image reads return the exact successful text-only result in Spec 11 Section 6 instead of multimodal image content; non-image bytes retain Pi's UTF-8 replacement-decoding behavior.",
|
|
17
|
+
"the poll/wait cancellation protocol replaces Pi's abort signal.",
|
|
18
|
+
"Windows uses COMSPEC/cmd.exe while POSIX preserves Pi's Bash-first order.",
|
|
19
|
+
"the inherited environment omits Pi's private bin-directory PATH mutation.",
|
|
20
|
+
"the 11A-owned async timer enforces the caller-supplied strictly positive finite timeout; expiry after spawn performs the specified process-tree cleanup and returns `process_timeout` with `completion_unknown`."
|
|
21
|
+
],
|
|
22
|
+
"pinned_paths": [
|
|
23
|
+
{"path": "LICENSE", "sha256": "0457f5bcec3b3b211605dfb5d1a49042fd638f3686a410fe099c24a25af13c48", "classification": "ported"},
|
|
24
|
+
{"path": "packages/coding-agent/package.json", "sha256": "76919365cc55f94e79a27583ec2f36c917c0312e529f6b83f71c7817b6774f55", "classification": "excluded"},
|
|
25
|
+
{"path": "packages/coding-agent/src/core/tools/index.ts", "sha256": "afeb406e0f5edde143aaac51b9c928cb497bfb8216c04ac9242bfd0f9241ffe1", "classification": "adapted"},
|
|
26
|
+
{"path": "packages/coding-agent/src/core/tools/read.ts", "sha256": "954419870e12b9e82e45a37bd3f9e6dda5bd80aa44ea56fbcdac0f976676d03e", "classification": "adapted"},
|
|
27
|
+
{"path": "packages/coding-agent/src/core/tools/ls.ts", "sha256": "0cd36018b68f08c98e615c761d6c3af19842537cd500d7be9912f932cd2b1b22", "classification": "ported"},
|
|
28
|
+
{"path": "packages/coding-agent/src/core/tools/grep.ts", "sha256": "9737dcfd27ae56a33fd934c0b336b9f1cb64eaab6b6378a91270dde4b505ba47", "classification": "adapted"},
|
|
29
|
+
{"path": "packages/coding-agent/src/core/tools/find.ts", "sha256": "f6f2d780df007af22d67101dc17ffae7c9d670893be168628eeebb01345b97df", "classification": "adapted"},
|
|
30
|
+
{"path": "packages/coding-agent/src/core/tools/write.ts", "sha256": "7f7f1425e2a7cdffe48b190033189fd03dffc5756708b12775dddb0acfe90c6c", "classification": "ported"},
|
|
31
|
+
{"path": "packages/coding-agent/src/core/tools/edit.ts", "sha256": "373083e70b8f58dc49b213a4046e4095e1acc5fb0bea1925185e09e0d3c00618", "classification": "ported"},
|
|
32
|
+
{"path": "packages/coding-agent/src/core/tools/edit-diff.ts", "sha256": "b76fab8a2868b1e65970286928e996e76918ba8b8dbfdefe9ab0fe34420f9c90", "classification": "ported"},
|
|
33
|
+
{"path": "packages/coding-agent/src/core/tools/bash.ts", "sha256": "9d932837466dee1f8fd84cae3b180363aa523118ff8c84a992eeab18dcd3be29", "classification": "adapted"},
|
|
34
|
+
{"path": "packages/coding-agent/src/core/tools/truncate.ts", "sha256": "104e61ea602c7f7894097b2771dad8c68de75c5a10ea6222e615c4ad144451c7", "classification": "ported"},
|
|
35
|
+
{"path": "packages/coding-agent/src/core/tools/output-accumulator.ts", "sha256": "c601ddd8e10934be6f3db30696eacba7b9544f2dd1648a5ec3c9935f0d4625c3", "classification": "adapted"},
|
|
36
|
+
{"path": "packages/coding-agent/src/core/tools/path-utils.ts", "sha256": "ab6f420d2388a41366113c17a25e356867820b87b02a169d044cfcf83e1997d3", "classification": "ported"},
|
|
37
|
+
{"path": "packages/coding-agent/src/core/tools/file-mutation-queue.ts", "sha256": "33cb06ac9bcdf32c8b84d9d12e33be44c503a7670f668e003a3262cd34294d11", "classification": "adapted"},
|
|
38
|
+
{"path": "packages/coding-agent/src/core/tools/render-utils.ts", "sha256": "38913e15575b7c314687c1a7d53b2763eecb8e7a86b0b58d7b5532c900503cf3", "classification": "excluded"},
|
|
39
|
+
{"path": "packages/coding-agent/src/utils/shell.ts", "sha256": "7a74bb1f3809fa62771827a9c814636b9742760f6deddc517a84ae237dc4fbef", "classification": "adapted"},
|
|
40
|
+
{"path": "packages/coding-agent/src/utils/child-process.ts", "sha256": "cd324f5b9a1abadd85ab5a331750d475c8bd51ec65cae091ad9b416245ec85d4", "classification": "adapted"},
|
|
41
|
+
{"path": "packages/coding-agent/src/utils/mime.ts", "sha256": "b562303ba7bbf27432bd310891fe656a8473995a4a1f8ba2e00a79b56400605c", "classification": "ported"},
|
|
42
|
+
{"path": "packages/coding-agent/src/utils/paths.ts", "sha256": "c433bd9f98744aa9a373282fd50ab3657b6e2a366feecbfb177fe648746d1944", "classification": "ported"},
|
|
43
|
+
{"path": "packages/coding-agent/test/tools.test.ts", "sha256": "0360d773cfef2e08f23490b9c83d4bb5b88ce070bf79c57d227c5fd2fcd121e9", "classification": "test-derived"},
|
|
44
|
+
{"path": "packages/coding-agent/test/path-utils.test.ts", "sha256": "08bb88574596a43e2364ee3b2655e071593822417ef8937693744174e9615f3e", "classification": "test-derived"},
|
|
45
|
+
{"path": "packages/coding-agent/test/bash-close-hang-windows.test.ts", "sha256": "1d2230b25129a365cbae417269b65c1724772104328f584ee521cb5c255b49fb", "classification": "test-derived"},
|
|
46
|
+
{"path": "packages/coding-agent/test/suite/regressions/3302-find-path-glob.test.ts", "sha256": "d8816a5ed1f3033439e7866dc9c7b87b7e7a265caf186bae3817443b597e1d02", "classification": "test-derived"},
|
|
47
|
+
{"path": "packages/coding-agent/test/suite/regressions/3303-find-nested-gitignore.test.ts", "sha256": "bcc7517366d11bf9cc3b8dade9d54bfbe6cd482a23deb9d6d966d1b2e09c6982", "classification": "test-derived"},
|
|
48
|
+
{"path": "packages/coding-agent/test/suite/regressions/5208-late-bash-output.test.ts", "sha256": "9d6fc0d457e6d7470246d821deec9937d428e86fdad6858d05e7d5c956802f8c", "classification": "test-derived"},
|
|
49
|
+
{"path": "packages/coding-agent/test/suite/regressions/5303-bash-output-truncation.test.ts", "sha256": "d690fdad5de2bd82f016892972395d49d3b83570d5223f4f473626d34af10136", "classification": "test-derived"},
|
|
50
|
+
{"path": "packages/coding-agent/src/core/system-prompt.ts", "sha256": "49cd7166a7f1eb8d088b7d8b8f2c38642de827ac2ff7a327ec4b7549b543d8d1", "classification": "adapted"},
|
|
51
|
+
{"path": "packages/coding-agent/src/core/resource-loader.ts", "sha256": "9e339467f3c5997ec363ad96ff18e1850cff71e2ab37dfeca7b4e8782926a2ff", "classification": "adapted"},
|
|
52
|
+
{"path": "packages/coding-agent/test/system-prompt.test.ts", "sha256": "6443dbc77ee1c39ca14c89652079e0907f47a4efae2bf9ce08323442983e2981", "classification": "test-derived"},
|
|
53
|
+
{"path": "packages/coding-agent/test/resource-loader.test.ts", "sha256": "98b343646e389f87743ef548f9c23e329ccf1eb0bb6945a66016884ec515b45e", "classification": "test-derived"}
|
|
54
|
+
]
|
|
55
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Pi Compatibility Update Policy
|
|
2
|
+
|
|
3
|
+
This source-attributed behavioral port may be updated only as an isolated,
|
|
4
|
+
reviewable change against a new approved Pi snapshot.
|
|
5
|
+
|
|
6
|
+
1. Record the upstream package name, version, license, repository URL, and
|
|
7
|
+
approved snapshot location. Do not invent a commit hash when the snapshot
|
|
8
|
+
has no history.
|
|
9
|
+
2. Recompute SHA-256 values for every path in PROVENANCE.json before copying
|
|
10
|
+
or translating behavior. Stop the update when a pinned source differs until
|
|
11
|
+
the source version and manifest are explicitly reconciled.
|
|
12
|
+
3. Review Pi's tool sources, utility sources, and source-derived tests together.
|
|
13
|
+
Preserve model-visible text unless a documented Spec 11 adaptation requires
|
|
14
|
+
a divergence.
|
|
15
|
+
4. Reassess the complete adaptation list, including Python filesystem/process
|
|
16
|
+
APIs, text-only image results, search implementation, mutation locking, and
|
|
17
|
+
Windows shell behavior. Document any newly required divergence in the
|
|
18
|
+
accepted specification, provenance, tests, and public documentation.
|
|
19
|
+
5. Copy the upstream MIT notice unmodified, update every path hash and
|
|
20
|
+
classification, and keep the package-data rules in sync.
|
|
21
|
+
6. Run the source-derived focused tests, the full relevant Millforge tests,
|
|
22
|
+
Ruff, MyPy, dependency checks, and package-content verification before
|
|
23
|
+
accepting the update.
|
|
24
|
+
|
|
25
|
+
No Pi runtime, Node package, downloaded search binary, or unreviewed source
|
|
26
|
+
snapshot is an acceptable substitute for this procedure.
|
|
27
|
+
|
|
28
|
+
## Current Platform Validation
|
|
29
|
+
|
|
30
|
+
The POSIX shell path, timeout, cancellation, process-group cleanup, output
|
|
31
|
+
ordering, and persistence behavior are covered by the bundled Python 3.12
|
|
32
|
+
tests. The Windows `COMSPEC`/`cmd.exe` and `taskkill /F /T` implementation is
|
|
33
|
+
source-reviewed and has platform-gated contract tests, but native Windows
|
|
34
|
+
process-tree stress behavior was not locally verified for the 0.79.6 port.
|
|
35
|
+
Run those gated tests in a controlled Windows CI environment before claiming
|
|
36
|
+
native Windows process-tree parity.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Source-attributed Pi 0.79.6 coding-tool compatibility operations."""
|
|
2
|
+
|
|
3
|
+
from .contracts import (
|
|
4
|
+
PiCompatErrorKind,
|
|
5
|
+
PiCompatOperationResult,
|
|
6
|
+
PiCompatSideEffectState,
|
|
7
|
+
)
|
|
8
|
+
from .editing import execute_edit
|
|
9
|
+
from .operations import execute_ls, execute_read, execute_write
|
|
10
|
+
from .process import (
|
|
11
|
+
PiCompatCancellation,
|
|
12
|
+
PiCompatShellConfig,
|
|
13
|
+
PiCompatShellResolutionError,
|
|
14
|
+
execute_bash,
|
|
15
|
+
resolve_pi_compat_shell,
|
|
16
|
+
)
|
|
17
|
+
from .search import execute_find, execute_grep
|
|
18
|
+
|
|
19
|
+
__all__ = [
|
|
20
|
+
"PiCompatCancellation",
|
|
21
|
+
"PiCompatErrorKind",
|
|
22
|
+
"PiCompatOperationResult",
|
|
23
|
+
"PiCompatShellConfig",
|
|
24
|
+
"PiCompatShellResolutionError",
|
|
25
|
+
"PiCompatSideEffectState",
|
|
26
|
+
"execute_bash",
|
|
27
|
+
"execute_edit",
|
|
28
|
+
"execute_find",
|
|
29
|
+
"execute_grep",
|
|
30
|
+
"execute_ls",
|
|
31
|
+
"execute_read",
|
|
32
|
+
"execute_write",
|
|
33
|
+
"resolve_pi_compat_shell",
|
|
34
|
+
]
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"""Shared contracts for the Pi 0.79.6 compatibility operation pack."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import dataclass
|
|
6
|
+
from enum import Enum
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"PiCompatErrorKind",
|
|
11
|
+
"PiCompatOperationResult",
|
|
12
|
+
"PiCompatSideEffectState",
|
|
13
|
+
]
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class PiCompatErrorKind(str, Enum):
|
|
17
|
+
"""Closed operation errors translated by the unrestricted tool adapter."""
|
|
18
|
+
|
|
19
|
+
INVALID_ARGUMENTS = "invalid_arguments"
|
|
20
|
+
NOT_FOUND = "not_found"
|
|
21
|
+
PERMISSION_DENIED = "permission_denied"
|
|
22
|
+
CONFLICT = "conflict"
|
|
23
|
+
IO_ERROR = "io_error"
|
|
24
|
+
PROCESS_EXIT_NONZERO = "process_exit_nonzero"
|
|
25
|
+
PROCESS_TIMEOUT = "process_timeout"
|
|
26
|
+
CANCELLED = "cancelled"
|
|
27
|
+
PROCESS_LAUNCH_ERROR = "process_launch_error"
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class PiCompatSideEffectState(str, Enum):
|
|
31
|
+
"""The operation's explicit side-effect certainty."""
|
|
32
|
+
|
|
33
|
+
NOT_ATTEMPTED = "not_attempted"
|
|
34
|
+
CONFIRMED_ABSENT = "confirmed_absent"
|
|
35
|
+
CONFIRMED_COMPLETE = "confirmed_complete"
|
|
36
|
+
ROLLED_BACK = "rolled_back"
|
|
37
|
+
COMPLETION_UNKNOWN = "completion_unknown"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass(frozen=True)
|
|
41
|
+
class PiCompatOperationResult:
|
|
42
|
+
"""The complete model-visible result of one Pi-compatible operation."""
|
|
43
|
+
|
|
44
|
+
model_text: str
|
|
45
|
+
truncated: bool
|
|
46
|
+
error_kind: PiCompatErrorKind | None
|
|
47
|
+
exit_code: int | None
|
|
48
|
+
changed_path: Path | None
|
|
49
|
+
side_effect_state: PiCompatSideEffectState
|