@mmmbuto/masix 0.3.8 → 0.4.1
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.
- package/README.md +17 -15
- package/install.js +89 -26
- package/package.json +4 -3
- package/packages/plugin-base/codex-backend/0.1.4/SHA256SUMS +3 -0
- package/packages/plugin-base/codex-backend/0.1.4/codex-backend-android-aarch64-termux.pkg +0 -0
- package/packages/plugin-base/codex-backend/0.1.4/codex-backend-linux-x86_64.pkg +0 -0
- package/packages/plugin-base/codex-backend/0.1.4/codex-backend-macos-aarch64.pkg +0 -0
- package/packages/plugin-base/codex-backend/0.1.4/manifest.json +33 -0
- package/packages/plugin-base/codex-backend/CHANGELOG.md +17 -0
- package/packages/plugin-base/codex-backend/README.md +33 -0
- package/packages/plugin-base/codex-backend/source/Cargo.toml +25 -0
- package/packages/plugin-base/codex-backend/source/README-PACKAGE.txt +54 -0
- package/packages/plugin-base/codex-backend/source/plugin.manifest.json +103 -0
- package/packages/plugin-base/codex-backend/source/src/error.rs +60 -0
- package/packages/plugin-base/codex-backend/source/src/exec.rs +436 -0
- package/packages/plugin-base/codex-backend/source/src/http_backend.rs +1198 -0
- package/packages/plugin-base/codex-backend/source/src/lib.rs +328 -0
- package/packages/plugin-base/codex-backend/source/src/patch.rs +767 -0
- package/packages/plugin-base/codex-backend/source/src/policy.rs +297 -0
- package/packages/plugin-base/codex-backend/source/src/tools.rs +72 -0
- package/packages/plugin-base/codex-backend/source/src/workspace.rs +433 -0
- package/packages/plugin-base/codex-tools/0.1.3/SHA256SUMS +3 -0
- package/packages/plugin-base/codex-tools/0.1.3/codex-tools-android-aarch64-termux.pkg +0 -0
- package/packages/plugin-base/codex-tools/0.1.3/codex-tools-linux-x86_64.pkg +0 -0
- package/packages/plugin-base/codex-tools/0.1.3/codex-tools-macos-aarch64.pkg +0 -0
- package/packages/plugin-base/codex-tools/0.1.3/manifest.json +33 -0
- package/packages/plugin-base/codex-tools/CHANGELOG.md +17 -0
- package/packages/plugin-base/codex-tools/README.md +33 -0
- package/packages/plugin-base/codex-tools/source/Cargo.toml +23 -0
- package/packages/plugin-base/codex-tools/source/plugin.manifest.json +124 -0
- package/packages/plugin-base/codex-tools/source/src/main.rs +995 -0
- package/packages/plugin-base/discovery/0.2.4/SHA256SUMS +3 -0
- package/packages/plugin-base/discovery/0.2.4/discovery-android-aarch64-termux.pkg +0 -0
- package/packages/plugin-base/discovery/0.2.4/discovery-linux-x86_64.pkg +0 -0
- package/packages/plugin-base/discovery/0.2.4/discovery-macos-aarch64.pkg +0 -0
- package/packages/plugin-base/discovery/0.2.4/manifest.json +31 -0
- package/packages/plugin-base/discovery/CHANGELOG.md +17 -0
- package/packages/plugin-base/discovery/README.md +48 -0
- package/packages/plugin-base/discovery/source/Cargo.toml +14 -0
- package/packages/plugin-base/discovery/source/plugin.manifest.json +30 -0
- package/packages/plugin-base/discovery/source/src/main.rs +2570 -0
- package/prebuilt/masix +0 -0
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
pub mod error;
|
|
2
|
+
pub mod exec;
|
|
3
|
+
pub mod http_backend;
|
|
4
|
+
pub mod patch;
|
|
5
|
+
pub mod policy;
|
|
6
|
+
pub mod tools;
|
|
7
|
+
pub mod workspace;
|
|
8
|
+
|
|
9
|
+
pub use error::{CodingError, ExitStatus};
|
|
10
|
+
pub use exec::{
|
|
11
|
+
CommandExecutor, ExecRequest, ExecResult, DEFAULT_COMMAND_ALLOWLIST, DEFAULT_EXEC_TIMEOUT_SECS,
|
|
12
|
+
DEFAULT_MAX_OUTPUT_BYTES as EXEC_DEFAULT_MAX_OUTPUT_BYTES, MAX_EXEC_TIMEOUT_SECS,
|
|
13
|
+
};
|
|
14
|
+
pub use http_backend::HttpBackend;
|
|
15
|
+
pub use patch::{
|
|
16
|
+
apply_patch, preview_patch, rollback_patch, BackupEntry, BackupManifest, PatchApplyResult,
|
|
17
|
+
PatchPreview,
|
|
18
|
+
};
|
|
19
|
+
pub use policy::{AdminPolicy, PermissionLevel, PolicyContext};
|
|
20
|
+
pub use tools::{
|
|
21
|
+
get_read_tools, get_write_tools, tools_to_anthropic_format, tools_to_openai_format,
|
|
22
|
+
};
|
|
23
|
+
pub use workspace::{
|
|
24
|
+
default_workspace_root, resolve_relative_path, resolve_workspace, ExecutionProfile,
|
|
25
|
+
ResolvedWorkspace, WorkspaceConfig, WorkspaceSource,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
use async_trait::async_trait;
|
|
29
|
+
use std::path::PathBuf;
|
|
30
|
+
use std::time::Duration;
|
|
31
|
+
|
|
32
|
+
pub const DEFAULT_TIMEOUT_SECS: u64 = 300;
|
|
33
|
+
pub const DEFAULT_MAX_OUTPUT_BYTES: usize = 1024 * 1024;
|
|
34
|
+
pub const DEFAULT_MAX_TOKENS: u32 = 4096;
|
|
35
|
+
pub const MAX_LOG_ENTRIES: usize = 1000;
|
|
36
|
+
|
|
37
|
+
/// Module metadata for plugin registry
|
|
38
|
+
pub const MODULE_ID: &str = "codex-backend";
|
|
39
|
+
pub const MODULE_VERSION: &str = env!("CARGO_PKG_VERSION");
|
|
40
|
+
pub const MODULE_REQUIRES_ADMIN: bool = true;
|
|
41
|
+
|
|
42
|
+
/// Returns true if this module requires admin privileges
|
|
43
|
+
pub fn requires_admin() -> bool {
|
|
44
|
+
MODULE_REQUIRES_ADMIN
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/// Returns module metadata as JSON
|
|
48
|
+
pub fn module_info() -> serde_json::Value {
|
|
49
|
+
serde_json::json!({
|
|
50
|
+
"id": MODULE_ID,
|
|
51
|
+
"version": MODULE_VERSION,
|
|
52
|
+
"requires_admin": MODULE_REQUIRES_ADMIN,
|
|
53
|
+
"capabilities": ["http_client", "file_read", "file_write", "command_exec", "patch_apply"],
|
|
54
|
+
"trait": "CodingBackend"
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
#[derive(Debug, Clone)]
|
|
59
|
+
pub struct CodingTask {
|
|
60
|
+
pub repo_path: PathBuf,
|
|
61
|
+
pub instructions: String,
|
|
62
|
+
pub mode: CodingMode,
|
|
63
|
+
pub timeout: Option<Duration>,
|
|
64
|
+
pub max_steps: Option<u32>,
|
|
65
|
+
/// Policy context for admin checks (optional for backward compatibility)
|
|
66
|
+
pub policy: Option<PolicyContext>,
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
impl Default for CodingTask {
|
|
70
|
+
fn default() -> Self {
|
|
71
|
+
Self {
|
|
72
|
+
repo_path: PathBuf::new(),
|
|
73
|
+
instructions: String::new(),
|
|
74
|
+
mode: CodingMode::default(),
|
|
75
|
+
timeout: None,
|
|
76
|
+
max_steps: None,
|
|
77
|
+
policy: None,
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
#[derive(Debug, Clone, Copy, Default)]
|
|
83
|
+
pub enum CodingMode {
|
|
84
|
+
#[default]
|
|
85
|
+
ReadOnly,
|
|
86
|
+
WorkspaceWrite,
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
#[derive(Debug, Clone, serde::Serialize)]
|
|
90
|
+
pub struct CodingResult {
|
|
91
|
+
pub patch: Option<String>,
|
|
92
|
+
pub summary: String,
|
|
93
|
+
pub logs: Vec<String>,
|
|
94
|
+
pub exit_status: ExitStatus,
|
|
95
|
+
/// Structured event traces for machine-readable output
|
|
96
|
+
pub events: Vec<CodingEvent>,
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/// Structured event for runtime tracing
|
|
100
|
+
#[derive(Debug, Clone, serde::Serialize)]
|
|
101
|
+
pub struct CodingEvent {
|
|
102
|
+
/// Event type: start, tool_call, tool_result, iteration, final
|
|
103
|
+
pub event: String,
|
|
104
|
+
/// Iteration number (when applicable)
|
|
105
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
106
|
+
pub iteration: Option<u32>,
|
|
107
|
+
/// Tool name (for tool_call/tool_result)
|
|
108
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
109
|
+
pub tool: Option<String>,
|
|
110
|
+
/// Tool call ID
|
|
111
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
112
|
+
pub tool_call_id: Option<String>,
|
|
113
|
+
/// Result status
|
|
114
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
115
|
+
pub status: Option<String>,
|
|
116
|
+
/// Timestamp (ISO 8601)
|
|
117
|
+
pub timestamp: String,
|
|
118
|
+
/// Additional data
|
|
119
|
+
#[serde(skip_serializing_if = "Option::is_none")]
|
|
120
|
+
pub data: Option<serde_json::Value>,
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
impl CodingEvent {
|
|
124
|
+
pub fn start(repo_path: &std::path::Path) -> Self {
|
|
125
|
+
Self {
|
|
126
|
+
event: "start".into(),
|
|
127
|
+
iteration: None,
|
|
128
|
+
tool: None,
|
|
129
|
+
tool_call_id: None,
|
|
130
|
+
status: None,
|
|
131
|
+
timestamp: chrono_like_timestamp(),
|
|
132
|
+
data: Some(serde_json::json!({ "repo_path": repo_path.display().to_string() })),
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
pub fn iteration(n: u32) -> Self {
|
|
137
|
+
Self {
|
|
138
|
+
event: "iteration".into(),
|
|
139
|
+
iteration: Some(n),
|
|
140
|
+
tool: None,
|
|
141
|
+
tool_call_id: None,
|
|
142
|
+
status: None,
|
|
143
|
+
timestamp: chrono_like_timestamp(),
|
|
144
|
+
data: None,
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
pub fn tool_call(id: &str, name: &str, args: &str) -> Self {
|
|
149
|
+
Self {
|
|
150
|
+
event: "tool_call".into(),
|
|
151
|
+
iteration: None,
|
|
152
|
+
tool: Some(name.into()),
|
|
153
|
+
tool_call_id: Some(id.into()),
|
|
154
|
+
status: None,
|
|
155
|
+
timestamp: chrono_like_timestamp(),
|
|
156
|
+
data: Some(
|
|
157
|
+
serde_json::json!({ "args_preview": args.chars().take(200).collect::<String>() }),
|
|
158
|
+
),
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
pub fn tool_result(id: &str, name: &str, success: bool, output_preview: &str) -> Self {
|
|
163
|
+
Self {
|
|
164
|
+
event: "tool_result".into(),
|
|
165
|
+
iteration: None,
|
|
166
|
+
tool: Some(name.into()),
|
|
167
|
+
tool_call_id: Some(id.into()),
|
|
168
|
+
status: Some(if success { "success" } else { "error" }.into()),
|
|
169
|
+
timestamp: chrono_like_timestamp(),
|
|
170
|
+
data: Some(
|
|
171
|
+
serde_json::json!({ "output_preview": output_preview.chars().take(200).collect::<String>() }),
|
|
172
|
+
),
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
pub fn final_event(status: &str, summary: &str) -> Self {
|
|
177
|
+
Self {
|
|
178
|
+
event: "final".into(),
|
|
179
|
+
iteration: None,
|
|
180
|
+
tool: None,
|
|
181
|
+
tool_call_id: None,
|
|
182
|
+
status: Some(status.into()),
|
|
183
|
+
timestamp: chrono_like_timestamp(),
|
|
184
|
+
data: Some(serde_json::json!({ "summary": summary })),
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
fn chrono_like_timestamp() -> String {
|
|
190
|
+
let now = std::time::SystemTime::now()
|
|
191
|
+
.duration_since(std::time::UNIX_EPOCH)
|
|
192
|
+
.unwrap_or_default();
|
|
193
|
+
let secs = now.as_secs();
|
|
194
|
+
let datetime = time_to_iso8601(secs);
|
|
195
|
+
datetime
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
fn time_to_iso8601(secs: u64) -> String {
|
|
199
|
+
// Simple ISO 8601 format without chrono dependency
|
|
200
|
+
let days = secs / 86400;
|
|
201
|
+
let rem = secs % 86400;
|
|
202
|
+
let hours = rem / 3600;
|
|
203
|
+
let minutes = (rem % 3600) / 60;
|
|
204
|
+
let seconds = rem % 60;
|
|
205
|
+
|
|
206
|
+
// Calculate year/month/day (simplified, good enough for timestamps)
|
|
207
|
+
let (year, month, day) = days_to_ymd(days);
|
|
208
|
+
format!(
|
|
209
|
+
"{:04}-{:02}-{:02}T{:02}:{:02}:{:02}Z",
|
|
210
|
+
year, month, day, hours, minutes, seconds
|
|
211
|
+
)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
fn days_to_ymd(days: u64) -> (u64, u64, u64) {
|
|
215
|
+
// Howard Hinnant's civil_from_days algorithm (public domain)
|
|
216
|
+
// Handles all edge cases including leap years correctly
|
|
217
|
+
let z = days as i64 + 719468;
|
|
218
|
+
let era = if z >= 0 { z } else { z - 146096 } / 146097;
|
|
219
|
+
let doe = (z - era * 146097) as u64; // day of era [0, 146096]
|
|
220
|
+
let yoe = (doe - doe / 1460 + doe / 36524 - doe / 146096) / 365; // year of era [0, 399]
|
|
221
|
+
let y = (yoe as i64) + era * 400;
|
|
222
|
+
let doy = doe - (365 * yoe + yoe / 4 - yoe / 100); // day of year [0, 365]
|
|
223
|
+
let mp = (5 * doy + 2) / 153; // month offset [0, 11]
|
|
224
|
+
let d = doy - (153 * mp + 2) / 5 + 1; // day [1, 31]
|
|
225
|
+
let m = if mp < 10 { mp + 3 } else { mp - 9 };
|
|
226
|
+
let y = if m <= 2 { y + 1 } else { y };
|
|
227
|
+
(y as u64, m, d)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
#[async_trait]
|
|
231
|
+
pub trait CodingBackend: Send + Sync {
|
|
232
|
+
/// Execute a coding task. Returns error if policy check fails.
|
|
233
|
+
async fn run(&self, task: CodingTask) -> Result<CodingResult, CodingError>;
|
|
234
|
+
|
|
235
|
+
/// Preview task execution without making changes.
|
|
236
|
+
fn dry_run(&self, task: &CodingTask) -> DryRunInfo;
|
|
237
|
+
|
|
238
|
+
/// Check if task is allowed by policy
|
|
239
|
+
fn check_policy(&self, task: &CodingTask) -> Result<(), CodingError>;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
#[derive(Debug, Clone, serde::Serialize)]
|
|
243
|
+
pub struct DryRunInfo {
|
|
244
|
+
pub backend: &'static str,
|
|
245
|
+
pub provider_type: &'static str,
|
|
246
|
+
pub base_url: Option<String>,
|
|
247
|
+
pub model: Option<String>,
|
|
248
|
+
pub timeout_secs: u64,
|
|
249
|
+
pub mode: &'static str,
|
|
250
|
+
pub repo_path: PathBuf,
|
|
251
|
+
pub policy_allowed: bool,
|
|
252
|
+
pub requires_admin: bool,
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
#[derive(Debug, Clone)]
|
|
256
|
+
pub enum ProviderType {
|
|
257
|
+
OpenAI,
|
|
258
|
+
Anthropic,
|
|
259
|
+
OpenAICompatible,
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
impl ProviderType {
|
|
263
|
+
pub fn as_str(&self) -> &'static str {
|
|
264
|
+
match self {
|
|
265
|
+
ProviderType::OpenAI => "openai",
|
|
266
|
+
ProviderType::Anthropic => "anthropic",
|
|
267
|
+
ProviderType::OpenAICompatible => "openai-compatible",
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
pub fn from_str(s: &str) -> Option<Self> {
|
|
272
|
+
match s {
|
|
273
|
+
"openai" => Some(ProviderType::OpenAI),
|
|
274
|
+
"anthropic" => Some(ProviderType::Anthropic),
|
|
275
|
+
"openai-compatible" => Some(ProviderType::OpenAICompatible),
|
|
276
|
+
_ => None,
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
#[cfg(test)]
|
|
282
|
+
mod tests {
|
|
283
|
+
use super::*;
|
|
284
|
+
|
|
285
|
+
#[test]
|
|
286
|
+
fn test_module_metadata() {
|
|
287
|
+
assert_eq!(MODULE_ID, "codex-backend");
|
|
288
|
+
assert!(requires_admin());
|
|
289
|
+
let info = module_info();
|
|
290
|
+
assert_eq!(info["id"], "codex-backend");
|
|
291
|
+
assert_eq!(info["requires_admin"], true);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
#[test]
|
|
295
|
+
fn test_coding_task_default() {
|
|
296
|
+
let task = CodingTask::default();
|
|
297
|
+
assert!(task.policy.is_none());
|
|
298
|
+
assert!(task.repo_path.as_os_str().is_empty());
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
#[test]
|
|
302
|
+
fn test_days_to_ymd_epoch() {
|
|
303
|
+
let (y, m, d) = days_to_ymd(0);
|
|
304
|
+
assert_eq!((y, m, d), (1970, 1, 1));
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
#[test]
|
|
308
|
+
fn test_days_to_ymd_leap_year() {
|
|
309
|
+
// 2000-02-29 is day 11016 since epoch
|
|
310
|
+
// 2000-01-01 = day 10957, plus 31 (Jan) + 28 (Feb 1-28) = 10957+59 = 11016
|
|
311
|
+
let (y, m, d) = days_to_ymd(11016);
|
|
312
|
+
assert_eq!((y, m, d), (2000, 2, 29));
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
#[test]
|
|
316
|
+
fn test_days_to_ymd_2026() {
|
|
317
|
+
// 2026-03-02: days since epoch
|
|
318
|
+
// Using known value: 2026-01-01 = 20454 days, +31 (Jan) +28 (Feb) +1 = 20514
|
|
319
|
+
let (y, m, d) = days_to_ymd(20514);
|
|
320
|
+
assert_eq!((y, m, d), (2026, 3, 2));
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
#[test]
|
|
324
|
+
fn test_time_to_iso8601() {
|
|
325
|
+
let ts = time_to_iso8601(0);
|
|
326
|
+
assert_eq!(ts, "1970-01-01T00:00:00Z");
|
|
327
|
+
}
|
|
328
|
+
}
|