@openrig/cli 0.3.4 → 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/daemon/assets/plugins/openrig-core/hooks/claude.json +11 -0
- package/daemon/assets/plugins/openrig-core/hooks/codex.json +14 -3
- package/daemon/assets/plugins/openrig-core/hooks/scripts/activity-relay.cjs +34 -0
- package/daemon/assets/plugins/openrig-core/hooks/scripts/compaction-restore-bridge.cjs +28 -24
- package/daemon/assets/plugins/openrig-core/skills/claude-compaction-restore/scripts/precompact-hook.mjs +72 -11
- package/daemon/assets/plugins/openrig-core/skills/queue-handoff/SKILL.md +62 -29
- package/daemon/dist/adapters/codex-resume.d.ts +2 -1
- package/daemon/dist/adapters/codex-resume.d.ts.map +1 -1
- package/daemon/dist/adapters/codex-resume.js +18 -6
- package/daemon/dist/adapters/codex-resume.js.map +1 -1
- package/daemon/dist/adapters/codex-runtime-adapter.d.ts +37 -1
- package/daemon/dist/adapters/codex-runtime-adapter.d.ts.map +1 -1
- package/daemon/dist/adapters/codex-runtime-adapter.js +212 -6
- package/daemon/dist/adapters/codex-runtime-adapter.js.map +1 -1
- package/daemon/dist/adapters/tmux.d.ts +28 -14
- package/daemon/dist/adapters/tmux.d.ts.map +1 -1
- package/daemon/dist/adapters/tmux.js +65 -30
- package/daemon/dist/adapters/tmux.js.map +1 -1
- package/daemon/dist/db/migrations/043_resume_provenance.d.ts +3 -0
- package/daemon/dist/db/migrations/043_resume_provenance.d.ts.map +1 -0
- package/daemon/dist/db/migrations/043_resume_provenance.js +5 -0
- package/daemon/dist/db/migrations/043_resume_provenance.js.map +1 -0
- package/daemon/dist/db/migrations/044_queue_item_summary.d.ts +21 -0
- package/daemon/dist/db/migrations/044_queue_item_summary.d.ts.map +1 -0
- package/daemon/dist/db/migrations/044_queue_item_summary.js +25 -0
- package/daemon/dist/db/migrations/044_queue_item_summary.js.map +1 -0
- package/daemon/dist/domain/agent-activity-store.d.ts +11 -1
- package/daemon/dist/domain/agent-activity-store.d.ts.map +1 -1
- package/daemon/dist/domain/agent-activity-store.js +22 -2
- package/daemon/dist/domain/agent-activity-store.js.map +1 -1
- package/daemon/dist/domain/claude-compaction-enforcer.d.ts.map +1 -1
- package/daemon/dist/domain/claude-compaction-enforcer.js +69 -1
- package/daemon/dist/domain/claude-compaction-enforcer.js.map +1 -1
- package/daemon/dist/domain/daemon-version.d.ts +15 -0
- package/daemon/dist/domain/daemon-version.d.ts.map +1 -0
- package/daemon/dist/domain/daemon-version.js +28 -0
- package/daemon/dist/domain/daemon-version.js.map +1 -0
- package/daemon/dist/domain/native-resume-probe.d.ts +2 -1
- package/daemon/dist/domain/native-resume-probe.d.ts.map +1 -1
- package/daemon/dist/domain/native-resume-probe.js +21 -2
- package/daemon/dist/domain/native-resume-probe.js.map +1 -1
- package/daemon/dist/domain/node-cmux-service.d.ts +1 -0
- package/daemon/dist/domain/node-cmux-service.d.ts.map +1 -1
- package/daemon/dist/domain/node-cmux-service.js +29 -2
- package/daemon/dist/domain/node-cmux-service.js.map +1 -1
- package/daemon/dist/domain/node-inventory.d.ts.map +1 -1
- package/daemon/dist/domain/node-inventory.js +70 -46
- package/daemon/dist/domain/node-inventory.js.map +1 -1
- package/daemon/dist/domain/node-launcher.d.ts +7 -7
- package/daemon/dist/domain/node-launcher.d.ts.map +1 -1
- package/daemon/dist/domain/node-launcher.js +0 -22
- package/daemon/dist/domain/node-launcher.js.map +1 -1
- package/daemon/dist/domain/profile-resolver.d.ts +4 -5
- package/daemon/dist/domain/profile-resolver.d.ts.map +1 -1
- package/daemon/dist/domain/profile-resolver.js.map +1 -1
- package/daemon/dist/domain/queue-repository.d.ts +22 -0
- package/daemon/dist/domain/queue-repository.d.ts.map +1 -1
- package/daemon/dist/domain/queue-repository.js +39 -2
- package/daemon/dist/domain/queue-repository.js.map +1 -1
- package/daemon/dist/domain/restore-check-service.d.ts +14 -0
- package/daemon/dist/domain/restore-check-service.d.ts.map +1 -1
- package/daemon/dist/domain/restore-check-service.js +78 -8
- package/daemon/dist/domain/restore-check-service.js.map +1 -1
- package/daemon/dist/domain/restore-orchestrator.d.ts.map +1 -1
- package/daemon/dist/domain/restore-orchestrator.js +3 -3
- package/daemon/dist/domain/restore-orchestrator.js.map +1 -1
- package/daemon/dist/domain/resume-metadata-refresher.js +1 -1
- package/daemon/dist/domain/resume-metadata-refresher.js.map +1 -1
- package/daemon/dist/domain/resume-token-validation.d.ts +17 -0
- package/daemon/dist/domain/resume-token-validation.d.ts.map +1 -0
- package/daemon/dist/domain/resume-token-validation.js +46 -0
- package/daemon/dist/domain/resume-token-validation.js.map +1 -0
- package/daemon/dist/domain/rigspec-instantiator.d.ts.map +1 -1
- package/daemon/dist/domain/rigspec-instantiator.js +3 -6
- package/daemon/dist/domain/rigspec-instantiator.js.map +1 -1
- package/daemon/dist/domain/runtime-adapter.d.ts.map +1 -1
- package/daemon/dist/domain/runtime-adapter.js +1 -0
- package/daemon/dist/domain/runtime-adapter.js.map +1 -1
- package/daemon/dist/domain/scope/dot-id.d.ts +43 -0
- package/daemon/dist/domain/scope/dot-id.d.ts.map +1 -0
- package/daemon/dist/domain/scope/dot-id.js +165 -0
- package/daemon/dist/domain/scope/dot-id.js.map +1 -0
- package/daemon/dist/domain/scope/scope-audit.d.ts +38 -0
- package/daemon/dist/domain/scope/scope-audit.d.ts.map +1 -0
- package/daemon/dist/domain/scope/scope-audit.js +191 -0
- package/daemon/dist/domain/scope/scope-audit.js.map +1 -0
- package/daemon/dist/domain/scope/types.d.ts +67 -0
- package/daemon/dist/domain/scope/types.d.ts.map +1 -0
- package/daemon/dist/domain/scope/types.js +46 -0
- package/daemon/dist/domain/scope/types.js.map +1 -0
- package/daemon/dist/domain/seat-attention-reconciler.d.ts +12 -0
- package/daemon/dist/domain/seat-attention-reconciler.d.ts.map +1 -1
- package/daemon/dist/domain/seat-attention-reconciler.js +116 -88
- package/daemon/dist/domain/seat-attention-reconciler.js.map +1 -1
- package/daemon/dist/domain/session-registry.d.ts +15 -1
- package/daemon/dist/domain/session-registry.d.ts.map +1 -1
- package/daemon/dist/domain/session-registry.js +46 -4
- package/daemon/dist/domain/session-registry.js.map +1 -1
- package/daemon/dist/domain/session-transport.d.ts +10 -0
- package/daemon/dist/domain/session-transport.d.ts.map +1 -1
- package/daemon/dist/domain/session-transport.js +153 -19
- package/daemon/dist/domain/session-transport.js.map +1 -1
- package/daemon/dist/domain/skill-audit.d.ts +47 -0
- package/daemon/dist/domain/skill-audit.d.ts.map +1 -0
- package/daemon/dist/domain/skill-audit.js +218 -0
- package/daemon/dist/domain/skill-audit.js.map +1 -0
- package/daemon/dist/domain/skill-discovery.d.ts +15 -0
- package/daemon/dist/domain/skill-discovery.d.ts.map +1 -1
- package/daemon/dist/domain/skill-discovery.js +70 -0
- package/daemon/dist/domain/skill-discovery.js.map +1 -1
- package/daemon/dist/domain/skill-mirror-drift.d.ts +10 -0
- package/daemon/dist/domain/skill-mirror-drift.d.ts.map +1 -0
- package/daemon/dist/domain/skill-mirror-drift.js +24 -0
- package/daemon/dist/domain/skill-mirror-drift.js.map +1 -0
- package/daemon/dist/domain/slices/slice-detail-projector.d.ts.map +1 -1
- package/daemon/dist/domain/slices/slice-detail-projector.js +10 -3
- package/daemon/dist/domain/slices/slice-detail-projector.js.map +1 -1
- package/daemon/dist/domain/startup-orchestrator.js +1 -1
- package/daemon/dist/domain/startup-orchestrator.js.map +1 -1
- package/daemon/dist/domain/types.d.ts +48 -14
- package/daemon/dist/domain/types.d.ts.map +1 -1
- package/daemon/dist/domain/types.js.map +1 -1
- package/daemon/dist/domain/user-settings/settings-store.d.ts +1 -1
- package/daemon/dist/domain/user-settings/settings-store.d.ts.map +1 -1
- package/daemon/dist/domain/user-settings/settings-store.js +4 -0
- package/daemon/dist/domain/user-settings/settings-store.js.map +1 -1
- package/daemon/dist/domain/whoami-service.d.ts +1 -0
- package/daemon/dist/domain/whoami-service.d.ts.map +1 -1
- package/daemon/dist/domain/whoami-service.js +8 -4
- package/daemon/dist/domain/whoami-service.js.map +1 -1
- package/daemon/dist/domain/workspace/default-workspace-scaffold.d.ts +1 -0
- package/daemon/dist/domain/workspace/default-workspace-scaffold.d.ts.map +1 -1
- package/daemon/dist/domain/workspace/default-workspace-scaffold.js +25 -1
- package/daemon/dist/domain/workspace/default-workspace-scaffold.js.map +1 -1
- package/daemon/dist/index.d.ts.map +1 -1
- package/daemon/dist/index.js +25 -3
- package/daemon/dist/index.js.map +1 -1
- package/daemon/dist/routes/activity.d.ts.map +1 -1
- package/daemon/dist/routes/activity.js +29 -0
- package/daemon/dist/routes/activity.js.map +1 -1
- package/daemon/dist/routes/bundles.d.ts.map +1 -1
- package/daemon/dist/routes/bundles.js +1 -18
- package/daemon/dist/routes/bundles.js.map +1 -1
- package/daemon/dist/routes/health-summary.d.ts.map +1 -1
- package/daemon/dist/routes/health-summary.js +13 -2
- package/daemon/dist/routes/health-summary.js.map +1 -1
- package/daemon/dist/routes/queue.d.ts.map +1 -1
- package/daemon/dist/routes/queue.js +11 -0
- package/daemon/dist/routes/queue.js.map +1 -1
- package/daemon/dist/routes/restore-check.js +33 -2
- package/daemon/dist/routes/restore-check.js.map +1 -1
- package/daemon/dist/routes/scope-audit.d.ts +3 -0
- package/daemon/dist/routes/scope-audit.d.ts.map +1 -0
- package/daemon/dist/routes/scope-audit.js +175 -0
- package/daemon/dist/routes/scope-audit.js.map +1 -0
- package/daemon/dist/routes/sessions.d.ts.map +1 -1
- package/daemon/dist/routes/sessions.js +67 -3
- package/daemon/dist/routes/sessions.js.map +1 -1
- package/daemon/dist/routes/skills.d.ts.map +1 -1
- package/daemon/dist/routes/skills.js +43 -0
- package/daemon/dist/routes/skills.js.map +1 -1
- package/daemon/dist/routes/terminal-ws.d.ts +7 -0
- package/daemon/dist/routes/terminal-ws.d.ts.map +1 -0
- package/daemon/dist/routes/terminal-ws.js +132 -0
- package/daemon/dist/routes/terminal-ws.js.map +1 -0
- package/daemon/dist/routes/transport.d.ts +3 -1
- package/daemon/dist/routes/transport.d.ts.map +1 -1
- package/daemon/dist/routes/transport.js +26 -1
- package/daemon/dist/routes/transport.js.map +1 -1
- package/daemon/dist/routes/whoami.d.ts.map +1 -1
- package/daemon/dist/routes/whoami.js +5 -0
- package/daemon/dist/routes/whoami.js.map +1 -1
- package/daemon/dist/server.d.ts +6 -0
- package/daemon/dist/server.d.ts.map +1 -1
- package/daemon/dist/server.js +29 -2
- package/daemon/dist/server.js.map +1 -1
- package/daemon/dist/startup.d.ts +8 -0
- package/daemon/dist/startup.d.ts.map +1 -1
- package/daemon/dist/startup.js +41 -10
- package/daemon/dist/startup.js.map +1 -1
- package/daemon/dist/terminal/TerminalSessionBroker.d.ts +173 -0
- package/daemon/dist/terminal/TerminalSessionBroker.d.ts.map +1 -0
- package/daemon/dist/terminal/TerminalSessionBroker.js +570 -0
- package/daemon/dist/terminal/TerminalSessionBroker.js.map +1 -0
- package/daemon/specs/agents/shared/skills/core/openrig-user/SKILL.md +131 -2
- package/daemon/specs/agents/shared/skills/pods/orchestration-team/SKILL.md +29 -0
- package/dist/client.d.ts +1 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +23 -0
- package/dist/client.js.map +1 -1
- package/dist/commands/auth.d.ts +11 -0
- package/dist/commands/auth.d.ts.map +1 -0
- package/dist/commands/auth.js +145 -0
- package/dist/commands/auth.js.map +1 -0
- package/dist/commands/capture.d.ts.map +1 -1
- package/dist/commands/capture.js +6 -6
- package/dist/commands/capture.js.map +1 -1
- package/dist/commands/config-init-workspace.d.ts.map +1 -1
- package/dist/commands/config-init-workspace.js +7 -4
- package/dist/commands/config-init-workspace.js.map +1 -1
- package/dist/commands/context.d.ts.map +1 -1
- package/dist/commands/context.js +41 -5
- package/dist/commands/context.js.map +1 -1
- package/dist/commands/down.d.ts.map +1 -1
- package/dist/commands/down.js +27 -0
- package/dist/commands/down.js.map +1 -1
- package/dist/commands/launch.d.ts.map +1 -1
- package/dist/commands/launch.js +34 -0
- package/dist/commands/launch.js.map +1 -1
- package/dist/commands/ps.d.ts.map +1 -1
- package/dist/commands/ps.js +361 -53
- package/dist/commands/ps.js.map +1 -1
- package/dist/commands/queue.d.ts.map +1 -1
- package/dist/commands/queue.js +83 -3
- package/dist/commands/queue.js.map +1 -1
- package/dist/commands/restore-check.d.ts.map +1 -1
- package/dist/commands/restore-check.js +80 -2
- package/dist/commands/restore-check.js.map +1 -1
- package/dist/commands/scope.d.ts.map +1 -1
- package/dist/commands/scope.js +747 -5
- package/dist/commands/scope.js.map +1 -1
- package/dist/commands/seat.d.ts +3 -1
- package/dist/commands/seat.d.ts.map +1 -1
- package/dist/commands/seat.js +61 -1
- package/dist/commands/seat.js.map +1 -1
- package/dist/commands/send.d.ts.map +1 -1
- package/dist/commands/send.js +46 -13
- package/dist/commands/send.js.map +1 -1
- package/dist/commands/skill.d.ts +4 -0
- package/dist/commands/skill.d.ts.map +1 -0
- package/dist/commands/skill.js +77 -0
- package/dist/commands/skill.js.map +1 -0
- package/dist/commands/up.d.ts.map +1 -1
- package/dist/commands/up.js +27 -0
- package/dist/commands/up.js.map +1 -1
- package/dist/commands/whoami.d.ts.map +1 -1
- package/dist/commands/whoami.js +208 -20
- package/dist/commands/whoami.js.map +1 -1
- package/dist/cross-host-executor.d.ts +1 -1
- package/dist/cross-host-executor.d.ts.map +1 -1
- package/dist/cross-host-executor.js +3 -2
- package/dist/cross-host-executor.js.map +1 -1
- package/dist/cross-host-types.d.ts +2 -0
- package/dist/cross-host-types.d.ts.map +1 -0
- package/dist/cross-host-types.js +2 -0
- package/dist/cross-host-types.js.map +1 -0
- package/dist/host-registry.d.ts +27 -5
- package/dist/host-registry.d.ts.map +1 -1
- package/dist/host-registry.js +86 -19
- package/dist/host-registry.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/codex-auth.d.ts +124 -0
- package/dist/lib/codex-auth.d.ts.map +1 -0
- package/dist/lib/codex-auth.js +418 -0
- package/dist/lib/codex-auth.js.map +1 -0
- package/dist/lib/scope/progress-edit.d.ts +42 -0
- package/dist/lib/scope/progress-edit.d.ts.map +1 -0
- package/dist/lib/scope/progress-edit.js +171 -0
- package/dist/lib/scope/progress-edit.js.map +1 -0
- package/dist/lib/scope/scope-audit.d.ts +38 -0
- package/dist/lib/scope/scope-audit.d.ts.map +1 -0
- package/dist/lib/scope/scope-audit.js +191 -0
- package/dist/lib/scope/scope-audit.js.map +1 -0
- package/dist/lib/scope/templates.d.ts +11 -0
- package/dist/lib/scope/templates.d.ts.map +1 -1
- package/dist/lib/scope/templates.js +22 -1
- package/dist/lib/scope/templates.js.map +1 -1
- package/dist/lib/scope/trust.d.ts +30 -0
- package/dist/lib/scope/trust.d.ts.map +1 -0
- package/dist/lib/scope/trust.js +80 -0
- package/dist/lib/scope/trust.js.map +1 -0
- package/dist/lib/scope/types.d.ts +6 -0
- package/dist/lib/scope/types.d.ts.map +1 -1
- package/dist/lib/scope/types.js +8 -0
- package/dist/lib/scope/types.js.map +1 -1
- package/dist/lib/scope-templates/backlog-deprecation.md +1 -0
- package/dist/lib/scope-templates/backlog-tech-debt.md +1 -0
- package/dist/lib/scope-templates/bug-fix.md +1 -0
- package/dist/lib/scope-templates/mission-brief.md +20 -0
- package/dist/lib/scope-templates/mission-placeholder.md +1 -0
- package/dist/lib/scope-templates/mission-progress.md +12 -0
- package/dist/lib/scope-templates/mission-release.md +1 -0
- package/dist/lib/scope-templates/placeholder.md +9 -0
- package/dist/lib/scope-templates/proof.md +17 -0
- package/dist/lib/scope-templates/release-feature.md +1 -0
- package/dist/lib/scope-templates/research.md +1 -0
- package/dist/lib/scope-templates/slice-progress.md +11 -0
- package/dist/remote-host-ops.d.ts +24 -0
- package/dist/remote-host-ops.d.ts.map +1 -0
- package/dist/remote-host-ops.js +53 -0
- package/dist/remote-host-ops.js.map +1 -0
- package/package.json +2 -1
- package/ui/dist/assets/index-CnqRX7A3.css +32 -0
- package/ui/dist/assets/index-CtL9jXFt.js +582 -0
- package/ui/dist/index.html +2 -2
- package/ui/dist/assets/index-C_Q5FczU.css +0 -1
- package/ui/dist/assets/index-De6vv0yO.js +0 -552
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
// OPR.0.4.1.29 — rig auth secret-safe core (CLI-LOCAL / daemon-free).
|
|
2
|
+
//
|
|
3
|
+
// This module operates directly on the operator's Codex auth files under CODEX_HOME and is invoked
|
|
4
|
+
// only from the `rig auth` CLI command — it NEVER touches the daemon, so a token can never enter the
|
|
5
|
+
// daemon queue / SSE stream / SQLite / event log (never-queued/never-streamed is true BY CONSTRUCTION).
|
|
6
|
+
//
|
|
7
|
+
// SECRET INVARIANTS (non-negotiable): no auth/refresh/access token value is ever returned in, or used
|
|
8
|
+
// to build, any human-facing string. Functions return STRUCTURED, non-secret result objects
|
|
9
|
+
// (presence / mode / parseability / login-state / names / counts); the auth FILE is snapshotted as a
|
|
10
|
+
// file (mode-guarded byte copy), never read into a printed value. CODEX_HOME defaults to $HOME/.codex
|
|
11
|
+
// and is env-overridable (tests point it at a fixture); no personal/operator path is baked in.
|
|
12
|
+
import path from "node:path";
|
|
13
|
+
import fs from "node:fs";
|
|
14
|
+
import { spawnSync } from "node:child_process";
|
|
15
|
+
/** Strict profile-name whitelist: alnum-led, then [A-Za-z0-9._-], 1..64 chars. Excludes /, \, ~,
|
|
16
|
+
* leading dot, whitespace, control, and shell metacharacters. Fail closed. */
|
|
17
|
+
const PROFILE_NAME_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;
|
|
18
|
+
export function validateProfileName(name) {
|
|
19
|
+
return typeof name === "string" && name.length > 0 && name.length <= 64 && PROFILE_NAME_RE.test(name);
|
|
20
|
+
}
|
|
21
|
+
/** Resolve the Codex paths from an env map (default process.env). CODEX_HOME wins; else $HOME/.codex. */
|
|
22
|
+
export function resolveCodexHome(env = process.env) {
|
|
23
|
+
const codexHome = typeof env.CODEX_HOME === "string" && env.CODEX_HOME.length > 0
|
|
24
|
+
? env.CODEX_HOME
|
|
25
|
+
: path.join(env.HOME ?? "", ".codex");
|
|
26
|
+
return {
|
|
27
|
+
codexHome,
|
|
28
|
+
profileDir: path.join(codexHome, "auth-profiles"),
|
|
29
|
+
activeAuth: path.join(codexHome, "auth.json"),
|
|
30
|
+
registryPath: path.join(codexHome, "auth-seat-registry.tsv"),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
// --- secret-safe fs helpers (no contents ever read into a returned/printed value) ---
|
|
34
|
+
function lstatSafe(p) {
|
|
35
|
+
try {
|
|
36
|
+
return fs.lstatSync(p);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function isDir(p) {
|
|
43
|
+
const st = lstatSafe(p);
|
|
44
|
+
return st !== null && st.isDirectory();
|
|
45
|
+
}
|
|
46
|
+
function isFile(p) {
|
|
47
|
+
const st = lstatSafe(p);
|
|
48
|
+
return st !== null && st.isFile();
|
|
49
|
+
}
|
|
50
|
+
/** Octal permission string (e.g. "600") or null when the path is absent/unstatable. */
|
|
51
|
+
function fileModeOctal(p) {
|
|
52
|
+
const st = lstatSafe(p);
|
|
53
|
+
if (st === null)
|
|
54
|
+
return null;
|
|
55
|
+
return (st.mode & 0o777).toString(8).padStart(3, "0");
|
|
56
|
+
}
|
|
57
|
+
/** A profile file is safe iff it exists, is a regular file (not a symlink — which could redirect us
|
|
58
|
+
* out of the profile dir), has link count 1 (a hardlink shares an inode that may live outside the
|
|
59
|
+
* profile dir), and lives directly in profileDir. */
|
|
60
|
+
function isSafeProfileFile(p, profileDir) {
|
|
61
|
+
const st = lstatSafe(p);
|
|
62
|
+
if (st === null || st.isSymbolicLink() || !st.isFile() || st.nlink !== 1)
|
|
63
|
+
return false;
|
|
64
|
+
return path.dirname(p) === profileDir;
|
|
65
|
+
}
|
|
66
|
+
/** True iff `dir` really resolves INSIDE realpath(codexHome). realpath follows every symlink in the
|
|
67
|
+
* chain, so a symlinked parent (e.g. an auth-profiles dir pointing outside) resolves out and is
|
|
68
|
+
* rejected — a lexical startsWith would be fooled. Returns false if either path can't be resolved. */
|
|
69
|
+
function realDirContained(dir, codexHome) {
|
|
70
|
+
try {
|
|
71
|
+
const root = fs.realpathSync(codexHome);
|
|
72
|
+
const resolved = fs.realpathSync(dir);
|
|
73
|
+
return resolved === root || resolved.startsWith(root + path.sep);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/** A destination we are about to write SECRET bytes onto is safe to replace iff it is absent, or a
|
|
80
|
+
* regular file (not a symlink) with link count 1. A symlink redirects the write; a hardlink (nlink>1)
|
|
81
|
+
* shares an inode that may live outside CODEX_HOME — writing through either leaks secret bytes out. */
|
|
82
|
+
function destReplaceable(p) {
|
|
83
|
+
const st = lstatSafe(p);
|
|
84
|
+
if (st === null)
|
|
85
|
+
return true;
|
|
86
|
+
return !st.isSymbolicLink() && st.isFile() && st.nlink === 1;
|
|
87
|
+
}
|
|
88
|
+
/** Copy `source` onto `dest` so secret bytes (a) never enter JS memory [copyFileSync does the byte
|
|
89
|
+
* copy] and (b) are never written THROUGH a pre-existing inode at dest: we copy into a freshly
|
|
90
|
+
* created (COPYFILE_EXCL) temp in dest's dir, then atomically rename over dest. Rename swaps the
|
|
91
|
+
* directory entry — any pre-existing hardlink/symlink inode is unlinked, never written. Caller must
|
|
92
|
+
* have already verified dest's parent containment and that dest is replaceable. */
|
|
93
|
+
function copyOntoFresh(source, dest) {
|
|
94
|
+
const tmp = `${dest}.tmp-${process.pid}`;
|
|
95
|
+
try {
|
|
96
|
+
try {
|
|
97
|
+
fs.rmSync(tmp, { force: true });
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
/* ignore */
|
|
101
|
+
}
|
|
102
|
+
fs.copyFileSync(source, tmp, fs.constants.COPYFILE_EXCL); // fresh inode; never through an existing one
|
|
103
|
+
fs.chmodSync(tmp, 0o600);
|
|
104
|
+
fs.renameSync(tmp, dest); // atomic dir-entry swap; old inode unlinked, not written
|
|
105
|
+
fs.chmodSync(dest, 0o600);
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
try {
|
|
110
|
+
fs.rmSync(tmp, { force: true });
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
/* ignore */
|
|
114
|
+
}
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
function countProfiles(profileDir) {
|
|
119
|
+
try {
|
|
120
|
+
return fs.readdirSync(profileDir).filter((n) => n.endsWith(".json") && isFile(path.join(profileDir, n))).length;
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return 0;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/** True iff the string contains a control character (<=0x1f or 0x7f), incl. tab/newline/CR which would
|
|
127
|
+
* corrupt a TSV row. Printable chars (spaces, hyphens, '@', '/') are allowed. Regex-free on purpose. */
|
|
128
|
+
function hasControlChar(v) {
|
|
129
|
+
for (let i = 0; i < v.length; i++) {
|
|
130
|
+
const c = v.charCodeAt(i);
|
|
131
|
+
if (c <= 0x1f || c === 0x7f)
|
|
132
|
+
return true;
|
|
133
|
+
}
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
/** Default login-state probe: exit code only, output never captured (stdio: ignore = no leak path). */
|
|
137
|
+
function defaultLoginStatus(codexHome) {
|
|
138
|
+
const r = spawnSync("codex", ["login", "status"], {
|
|
139
|
+
stdio: "ignore",
|
|
140
|
+
env: { ...process.env, CODEX_HOME: codexHome },
|
|
141
|
+
});
|
|
142
|
+
if (r.error)
|
|
143
|
+
return "unavailable";
|
|
144
|
+
return r.status === 0 ? "logged_in" : "not_logged_in";
|
|
145
|
+
}
|
|
146
|
+
/** Report auth-file presence/mode/safety + profile count + login-state. NEVER reads token contents. */
|
|
147
|
+
export function authStatus(paths, deps = {}) {
|
|
148
|
+
const activeAuthPresent = isFile(paths.activeAuth);
|
|
149
|
+
const activeAuthMode = activeAuthPresent ? fileModeOctal(paths.activeAuth) : null;
|
|
150
|
+
return {
|
|
151
|
+
codexHome: paths.codexHome,
|
|
152
|
+
codexHomePresent: isDir(paths.codexHome),
|
|
153
|
+
profileDirPresent: isDir(paths.profileDir),
|
|
154
|
+
activeAuthPresent,
|
|
155
|
+
activeAuthMode,
|
|
156
|
+
activeAuthModeSafe: activeAuthMode === null ? "unknown" : activeAuthMode === "600",
|
|
157
|
+
profileCount: countProfiles(paths.profileDir),
|
|
158
|
+
loginStatus: (deps.loginStatus ?? defaultLoginStatus)(paths.codexHome),
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
/** Validate a saved profile: name whitelist -> safe regular file -> 0600 -> JSON parseable. The
|
|
162
|
+
* parse is in-memory and the result is discarded; on failure we return a FIXED reason and never the
|
|
163
|
+
* JSON.parse error (its message can include a snippet of the file = a secret). */
|
|
164
|
+
export function authValidate(paths, name) {
|
|
165
|
+
if (!validateProfileName(name))
|
|
166
|
+
return { ok: false, reason: "invalid_profile" };
|
|
167
|
+
const target = path.join(paths.profileDir, `${name}.json`);
|
|
168
|
+
if (lstatSafe(target) === null)
|
|
169
|
+
return { ok: false, reason: "missing_profile" };
|
|
170
|
+
// Safe regular file (no symlink/hardlink) AND a profile dir that really resolves inside CODEX_HOME.
|
|
171
|
+
if (!isSafeProfileFile(target, paths.profileDir) || !realDirContained(paths.profileDir, paths.codexHome)) {
|
|
172
|
+
return { ok: false, reason: "unsafe_path" };
|
|
173
|
+
}
|
|
174
|
+
if (fileModeOctal(target) !== "600")
|
|
175
|
+
return { ok: false, reason: "unsafe_permissions" };
|
|
176
|
+
let content;
|
|
177
|
+
try {
|
|
178
|
+
content = fs.readFileSync(target, "utf8");
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
return { ok: false, reason: "parse_check_unavailable" };
|
|
182
|
+
}
|
|
183
|
+
try {
|
|
184
|
+
JSON.parse(content);
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
// Intentionally ignore the error object — its message can echo file content (a secret).
|
|
188
|
+
return { ok: false, reason: "malformed_json" };
|
|
189
|
+
}
|
|
190
|
+
return { ok: true, name, path: target, mode: "600" };
|
|
191
|
+
}
|
|
192
|
+
/** Snapshot the active auth file into a named profile (0600 file in the 0700 profile dir). Byte-copy
|
|
193
|
+
* via copyFileSync — contents never enter JS memory; result reports name/path/mode only. */
|
|
194
|
+
export function authSave(paths, name) {
|
|
195
|
+
if (!validateProfileName(name))
|
|
196
|
+
return { ok: false, reason: "invalid_profile" };
|
|
197
|
+
if (!isFile(paths.activeAuth))
|
|
198
|
+
return { ok: false, reason: "not_configured" };
|
|
199
|
+
const target = path.join(paths.profileDir, `${name}.json`);
|
|
200
|
+
// Refuse a symlinked profile-dir BEFORE mkdir/chmod so we never follow it out of CODEX_HOME or
|
|
201
|
+
// mutate the outside target's mode.
|
|
202
|
+
const pdStat = lstatSafe(paths.profileDir);
|
|
203
|
+
if (pdStat !== null && pdStat.isSymbolicLink())
|
|
204
|
+
return { ok: false, reason: "unsafe_path" };
|
|
205
|
+
try {
|
|
206
|
+
fs.mkdirSync(paths.profileDir, { recursive: true });
|
|
207
|
+
fs.chmodSync(paths.profileDir, 0o700);
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
return { ok: false, reason: "io_error" };
|
|
211
|
+
}
|
|
212
|
+
// Parent must REALLY resolve inside CODEX_HOME (defeats a symlinked auth-profiles parent), and the
|
|
213
|
+
// existing target must not be a symlink/hardlink/non-regular file (defeats writing secret bytes
|
|
214
|
+
// through an inode that lives outside CODEX_HOME).
|
|
215
|
+
if (!realDirContained(paths.profileDir, paths.codexHome))
|
|
216
|
+
return { ok: false, reason: "unsafe_path" };
|
|
217
|
+
if (!destReplaceable(target))
|
|
218
|
+
return { ok: false, reason: "unsafe_path" };
|
|
219
|
+
if (!copyOntoFresh(paths.activeAuth, target))
|
|
220
|
+
return { ok: false, reason: "io_error" };
|
|
221
|
+
return { ok: true, name, path: target, mode: "600" };
|
|
222
|
+
}
|
|
223
|
+
/** Activate a saved profile (copy it onto the active auth at 0600). Refuses to widen perms over an
|
|
224
|
+
* existing unsafe active file. Byte-copy; no content echoed. */
|
|
225
|
+
export function authSwitch(paths, name) {
|
|
226
|
+
if (!validateProfileName(name))
|
|
227
|
+
return { ok: false, reason: "invalid_profile" };
|
|
228
|
+
const source = path.join(paths.profileDir, `${name}.json`);
|
|
229
|
+
if (lstatSafe(source) === null)
|
|
230
|
+
return { ok: false, reason: "missing_profile" };
|
|
231
|
+
if (!isSafeProfileFile(source, paths.profileDir))
|
|
232
|
+
return { ok: false, reason: "unsafe_path" };
|
|
233
|
+
// Destination guard: a symlink/non-regular OR hardlinked (nlink>1) active auth would let the copy
|
|
234
|
+
// write the selected profile's SECRET bytes THROUGH an inode living outside CODEX_HOME. Refuse it
|
|
235
|
+
// (isFile() is false for a symlink, so the old isFile-gated check silently missed both cases).
|
|
236
|
+
if (!destReplaceable(paths.activeAuth))
|
|
237
|
+
return { ok: false, reason: "unsafe_path" };
|
|
238
|
+
if (isFile(paths.activeAuth)) {
|
|
239
|
+
const m = fileModeOctal(paths.activeAuth);
|
|
240
|
+
if (m !== null && m !== "600")
|
|
241
|
+
return { ok: false, reason: "unsafe_permissions" };
|
|
242
|
+
}
|
|
243
|
+
try {
|
|
244
|
+
fs.mkdirSync(paths.codexHome, { recursive: true });
|
|
245
|
+
}
|
|
246
|
+
catch {
|
|
247
|
+
return { ok: false, reason: "io_error" };
|
|
248
|
+
}
|
|
249
|
+
if (!realDirContained(paths.codexHome, paths.codexHome))
|
|
250
|
+
return { ok: false, reason: "unsafe_path" };
|
|
251
|
+
if (!copyOntoFresh(source, paths.activeAuth))
|
|
252
|
+
return { ok: false, reason: "io_error" };
|
|
253
|
+
return {
|
|
254
|
+
ok: true,
|
|
255
|
+
name,
|
|
256
|
+
activePath: paths.activeAuth,
|
|
257
|
+
mode: "600",
|
|
258
|
+
note: "live Codex sessions do not switch accounts in place; restart the affected seats to pick up the new profile.",
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
/** List saved profile names (safe regular *.json files in the profile dir), sorted. No contents read.
|
|
262
|
+
* Refuses to list through a symlinked / out-of-tree profile dir (returns []), so a redirected parent
|
|
263
|
+
* never exposes file names from outside CODEX_HOME. */
|
|
264
|
+
export function authList(paths) {
|
|
265
|
+
if (!realDirContained(paths.profileDir, paths.codexHome))
|
|
266
|
+
return [];
|
|
267
|
+
try {
|
|
268
|
+
return fs
|
|
269
|
+
.readdirSync(paths.profileDir)
|
|
270
|
+
.filter((n) => n.endsWith(".json") && isSafeProfileFile(path.join(paths.profileDir, n), paths.profileDir))
|
|
271
|
+
.map((n) => n.slice(0, -".json".length))
|
|
272
|
+
.sort();
|
|
273
|
+
}
|
|
274
|
+
catch {
|
|
275
|
+
return [];
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
// --- Auth-B: seat -> profile METADATA registry (product-native; NO resume_token per orch D2) ---
|
|
279
|
+
/** Stated in command output + docs: a seat label is metadata, never proof of a live account. */
|
|
280
|
+
export const SEAT_REGISTRY_DISCLAIMER = "Seat labels are metadata only; they do NOT prove a running session is actually using that account/profile.";
|
|
281
|
+
// 6 columns; NO resume_token (a print surface is the worst place to hold a secret-class token).
|
|
282
|
+
const SEAT_COLUMNS = ["seat", "rig", "runtime", "cwd", "auth_profile", "updated_ts"];
|
|
283
|
+
const SEAT_HEADER = SEAT_COLUMNS.join("\t");
|
|
284
|
+
const SEAT_TAB_COUNT = SEAT_COLUMNS.length - 1;
|
|
285
|
+
function isSafeRegistryFile(p) {
|
|
286
|
+
const st = lstatSafe(p);
|
|
287
|
+
return st !== null && !st.isSymbolicLink() && st.isFile();
|
|
288
|
+
}
|
|
289
|
+
/** Reject empty + any control character (covers tab/newline/CR, which would corrupt the TSV). */
|
|
290
|
+
function validRegistryField(v) {
|
|
291
|
+
return v.length > 0 && !hasControlChar(v);
|
|
292
|
+
}
|
|
293
|
+
function rawRegistryLines(registryPath) {
|
|
294
|
+
let text;
|
|
295
|
+
try {
|
|
296
|
+
text = fs.readFileSync(registryPath, "utf8");
|
|
297
|
+
}
|
|
298
|
+
catch {
|
|
299
|
+
return [];
|
|
300
|
+
}
|
|
301
|
+
const out = [];
|
|
302
|
+
let first = true;
|
|
303
|
+
for (const line of text.split("\n")) {
|
|
304
|
+
if (line === "" || line.startsWith("#"))
|
|
305
|
+
continue;
|
|
306
|
+
if (first) {
|
|
307
|
+
first = false; // skip header
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
out.push(line);
|
|
311
|
+
}
|
|
312
|
+
return out;
|
|
313
|
+
}
|
|
314
|
+
function rowMalformed(line) {
|
|
315
|
+
const tabs = (line.match(/\t/g) ?? []).length;
|
|
316
|
+
if (tabs !== SEAT_TAB_COUNT)
|
|
317
|
+
return true;
|
|
318
|
+
return line.split("\t")[0] === "";
|
|
319
|
+
}
|
|
320
|
+
function parseRow(line) {
|
|
321
|
+
// Callers pre-filter via rowMalformed (guaranteed 6 fields); ?? "" satisfies strict indexing.
|
|
322
|
+
const f = line.split("\t");
|
|
323
|
+
return {
|
|
324
|
+
seat: f[0] ?? "",
|
|
325
|
+
rig: f[1] ?? "",
|
|
326
|
+
runtime: f[2] ?? "",
|
|
327
|
+
cwd: f[3] ?? "",
|
|
328
|
+
authProfile: f[4] ?? "",
|
|
329
|
+
updatedTs: f[5] ?? "",
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
/** Atomic upsert of a seat metadata row (tmp + rename). Drops pre-existing malformed rows rather than
|
|
333
|
+
* re-emitting fabricated metadata. `now` is injectable for deterministic tests. */
|
|
334
|
+
export function authSeatSet(paths, fields, now = () => new Date().toISOString()) {
|
|
335
|
+
if (!validRegistryField(fields.seat))
|
|
336
|
+
return { ok: false, reason: "invalid_seat" };
|
|
337
|
+
if (!validRegistryField(fields.rig))
|
|
338
|
+
return { ok: false, reason: "invalid_rig" };
|
|
339
|
+
if (fields.runtime !== "codex")
|
|
340
|
+
return { ok: false, reason: "invalid_runtime" }; // v0 whitelist
|
|
341
|
+
const cwd = fields.cwd && fields.cwd.length > 0 ? fields.cwd : "unknown";
|
|
342
|
+
if (!validRegistryField(cwd))
|
|
343
|
+
return { ok: false, reason: "invalid_cwd" };
|
|
344
|
+
const profile = fields.authProfile && fields.authProfile.length > 0 ? fields.authProfile : "unknown";
|
|
345
|
+
if (profile !== "unknown" && !validateProfileName(profile))
|
|
346
|
+
return { ok: false, reason: "invalid_profile" };
|
|
347
|
+
if (lstatSafe(paths.registryPath) !== null && !isSafeRegistryFile(paths.registryPath)) {
|
|
348
|
+
return { ok: false, reason: "unsafe_path" };
|
|
349
|
+
}
|
|
350
|
+
const kept = rawRegistryLines(paths.registryPath)
|
|
351
|
+
.filter((l) => !rowMalformed(l))
|
|
352
|
+
.filter((l) => l.split("\t")[0] !== fields.seat);
|
|
353
|
+
const newRow = [fields.seat, fields.rig, "codex", cwd, profile, now()].join("\t");
|
|
354
|
+
const body = [SEAT_HEADER, ...kept, newRow].join("\n") + "\n";
|
|
355
|
+
const tmp = `${paths.registryPath}.${process.pid}.tmp`;
|
|
356
|
+
try {
|
|
357
|
+
fs.mkdirSync(path.dirname(paths.registryPath), { recursive: true });
|
|
358
|
+
fs.writeFileSync(tmp, body, { mode: 0o600 });
|
|
359
|
+
fs.chmodSync(tmp, 0o600);
|
|
360
|
+
fs.renameSync(tmp, paths.registryPath);
|
|
361
|
+
fs.chmodSync(paths.registryPath, 0o600);
|
|
362
|
+
}
|
|
363
|
+
catch {
|
|
364
|
+
try {
|
|
365
|
+
fs.rmSync(tmp, { force: true });
|
|
366
|
+
}
|
|
367
|
+
catch {
|
|
368
|
+
/* ignore */
|
|
369
|
+
}
|
|
370
|
+
return { ok: false, reason: "io_error" };
|
|
371
|
+
}
|
|
372
|
+
return { ok: true, seat: fields.seat, registryPath: paths.registryPath, mode: "600", disclaimer: SEAT_REGISTRY_DISCLAIMER };
|
|
373
|
+
}
|
|
374
|
+
/** List well-formed seat rows (malformed rows skipped). */
|
|
375
|
+
export function authSeatsList(paths) {
|
|
376
|
+
return rawRegistryLines(paths.registryPath)
|
|
377
|
+
.filter((l) => !rowMalformed(l))
|
|
378
|
+
.map(parseRow);
|
|
379
|
+
}
|
|
380
|
+
export function authSeatShow(paths, seat) {
|
|
381
|
+
if (!validRegistryField(seat))
|
|
382
|
+
return { ok: false, reason: "invalid_seat" };
|
|
383
|
+
if (lstatSafe(paths.registryPath) !== null && !isSafeRegistryFile(paths.registryPath)) {
|
|
384
|
+
return { ok: false, reason: "unsafe_path" };
|
|
385
|
+
}
|
|
386
|
+
const row = authSeatsList(paths).find((r) => r.seat === seat);
|
|
387
|
+
return row ? { ok: true, row } : { ok: false, reason: "missing_seat" };
|
|
388
|
+
}
|
|
389
|
+
export function authSeatsReport(paths) {
|
|
390
|
+
const present = isFile(paths.registryPath);
|
|
391
|
+
const mode = present ? fileModeOctal(paths.registryPath) : null;
|
|
392
|
+
let total = 0;
|
|
393
|
+
let known = 0;
|
|
394
|
+
let unknown = 0;
|
|
395
|
+
let malformed = 0;
|
|
396
|
+
for (const line of rawRegistryLines(paths.registryPath)) {
|
|
397
|
+
if (rowMalformed(line)) {
|
|
398
|
+
malformed += 1;
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
total += 1;
|
|
402
|
+
const profile = line.split("\t")[4];
|
|
403
|
+
if (!profile || profile === "unknown")
|
|
404
|
+
unknown += 1;
|
|
405
|
+
else
|
|
406
|
+
known += 1;
|
|
407
|
+
}
|
|
408
|
+
return {
|
|
409
|
+
registryPresent: present,
|
|
410
|
+
registryMode: mode,
|
|
411
|
+
registryModeSafe: mode === null ? "unknown" : mode === "600",
|
|
412
|
+
total,
|
|
413
|
+
known,
|
|
414
|
+
unknown,
|
|
415
|
+
malformed,
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
//# sourceMappingURL=codex-auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-auth.js","sourceRoot":"","sources":["../../src/lib/codex-auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export type ProgressStatus = "active" | "done" | "blocked";
|
|
2
|
+
export declare const PROGRESS_STATUSES: ReadonlyArray<ProgressStatus>;
|
|
3
|
+
export declare const DEFAULT_PROGRESS_SECTION = "Rail";
|
|
4
|
+
/** Map a status word to the single indexer indicator character. */
|
|
5
|
+
export declare function statusIndicator(status: ProgressStatus): " " | "x" | "~";
|
|
6
|
+
/** Validate + narrow an arbitrary string to a ProgressStatus, or throw
|
|
7
|
+
* the 3-part error. The status vocabulary is the ONLY three the indexer
|
|
8
|
+
* understands. */
|
|
9
|
+
export declare function parseStatus(raw: string): ProgressStatus;
|
|
10
|
+
export interface ProgressEditResult {
|
|
11
|
+
content: string;
|
|
12
|
+
changed: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Append a `- [<indicator>] <text>` row under `## <section>`.
|
|
16
|
+
* - Creates the `## <section>` heading (appended after the last existing
|
|
17
|
+
* section) when it is absent.
|
|
18
|
+
* - Idempotent: an identical (section, text, status) row is a no-op.
|
|
19
|
+
* - Refuses to create a conflicting duplicate (same text, different
|
|
20
|
+
* status) — that is a `--set` operation, not an `--add`.
|
|
21
|
+
* - Never touches the frontmatter, the `# H1`, or unrelated lines.
|
|
22
|
+
*/
|
|
23
|
+
export declare function addProgressRow(content: string, opts: {
|
|
24
|
+
section: string;
|
|
25
|
+
text: string;
|
|
26
|
+
status: ProgressStatus;
|
|
27
|
+
}): ProgressEditResult;
|
|
28
|
+
/**
|
|
29
|
+
* Rewrite the indicator of the single row whose trimmed text EXACTLY
|
|
30
|
+
* matches `text`. Row selection is exact-trimmed-text (not line number,
|
|
31
|
+
* not a generated id — the indexer mints neither).
|
|
32
|
+
* - 0 matches → error (names the missing text).
|
|
33
|
+
* - >1 matches → error (ambiguous; v0 refuses rather than guess).
|
|
34
|
+
* - Idempotent: setting a row to its current status is a no-op.
|
|
35
|
+
* - Rewrites ONLY the matched line's indicator char; the rest is
|
|
36
|
+
* preserved byte-for-byte.
|
|
37
|
+
*/
|
|
38
|
+
export declare function setProgressRow(content: string, opts: {
|
|
39
|
+
text: string;
|
|
40
|
+
status: ProgressStatus;
|
|
41
|
+
}): ProgressEditResult;
|
|
42
|
+
//# sourceMappingURL=progress-edit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progress-edit.d.ts","sourceRoot":"","sources":["../../../src/lib/scope/progress-edit.ts"],"names":[],"mappings":"AAcA,MAAM,MAAM,cAAc,GAAG,QAAQ,GAAG,MAAM,GAAG,SAAS,CAAC;AAE3D,eAAO,MAAM,iBAAiB,EAAE,aAAa,CAAC,cAAc,CAAiC,CAAC;AAE9F,eAAO,MAAM,wBAAwB,SAAS,CAAC;AAE/C,mEAAmE;AACnE,wBAAgB,eAAe,CAAC,MAAM,EAAE,cAAc,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAMvE;AASD;;mBAEmB;AACnB,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CASvD;AAgBD,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,cAAc,CAAA;CAAE,GAC9D,kBAAkB,CAyDpB;AAED;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,cAAc,CAAA;CAAE,GAC7C,kBAAkB,CAiCpB"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
// OPR.0.4.0.33 — pure, surgical markdown editors for PROGRESS rails.
|
|
2
|
+
//
|
|
3
|
+
// These back `rig scope ... progress`. They consume the UI parser
|
|
4
|
+
// contract in packages/daemon/src/domain/progress/progress-indexer.ts:
|
|
5
|
+
// - title comes from the FIRST `# H1` only (frontmatter is skipped),
|
|
6
|
+
// - section hierarchy from `##`/`###`/`####` headings,
|
|
7
|
+
// - rows from `- [ ]` / `- [x]` / `- [~]` checkbox lines.
|
|
8
|
+
// So every edit preserves the `# H1` + the YAML frontmatter verbatim
|
|
9
|
+
// and writes rows in exactly that shape. The functions are pure (string
|
|
10
|
+
// in, string out) so the command layer stays thin and the behavior is
|
|
11
|
+
// unit-testable without a filesystem.
|
|
12
|
+
import { ScopeCliError } from "./types.js";
|
|
13
|
+
export const PROGRESS_STATUSES = ["active", "done", "blocked"];
|
|
14
|
+
export const DEFAULT_PROGRESS_SECTION = "Rail";
|
|
15
|
+
/** Map a status word to the single indexer indicator character. */
|
|
16
|
+
export function statusIndicator(status) {
|
|
17
|
+
switch (status) {
|
|
18
|
+
case "active": return " ";
|
|
19
|
+
case "done": return "x";
|
|
20
|
+
case "blocked": return "~";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function indicatorToStatus(indicator) {
|
|
24
|
+
const c = indicator.toLowerCase();
|
|
25
|
+
if (c === "x")
|
|
26
|
+
return "done";
|
|
27
|
+
if (c === "~")
|
|
28
|
+
return "blocked";
|
|
29
|
+
return "active";
|
|
30
|
+
}
|
|
31
|
+
/** Validate + narrow an arbitrary string to a ProgressStatus, or throw
|
|
32
|
+
* the 3-part error. The status vocabulary is the ONLY three the indexer
|
|
33
|
+
* understands. */
|
|
34
|
+
export function parseStatus(raw) {
|
|
35
|
+
if (PROGRESS_STATUSES.includes(raw)) {
|
|
36
|
+
return raw;
|
|
37
|
+
}
|
|
38
|
+
throw new ScopeCliError({
|
|
39
|
+
fact: `Unknown --status "${raw}".`,
|
|
40
|
+
consequence: "No progress row was written.",
|
|
41
|
+
action: `Use one of: ${PROGRESS_STATUSES.join(", ")}.`,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
// Indexer-aligned row matcher: optional indent, optional `- `/`* ` bullet,
|
|
45
|
+
// `[ x ~]` indicator, then the row text.
|
|
46
|
+
const ROW_RE = /^(\s*)(?:[-*]\s+)?\[([ xX~])\]\s+(.+?)\s*$/;
|
|
47
|
+
const HEADING_RE = /^(#{1,6})\s+(.+?)\s*$/;
|
|
48
|
+
/** Index of the first body line (after any leading YAML frontmatter). */
|
|
49
|
+
function bodyStartIndex(lines) {
|
|
50
|
+
if ((lines[0] ?? "").trim() !== "---")
|
|
51
|
+
return 0;
|
|
52
|
+
for (let i = 1; i < lines.length; i++) {
|
|
53
|
+
if (lines[i].trim() === "---")
|
|
54
|
+
return i + 1;
|
|
55
|
+
}
|
|
56
|
+
return 0; // unterminated frontmatter — treat as no frontmatter
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Append a `- [<indicator>] <text>` row under `## <section>`.
|
|
60
|
+
* - Creates the `## <section>` heading (appended after the last existing
|
|
61
|
+
* section) when it is absent.
|
|
62
|
+
* - Idempotent: an identical (section, text, status) row is a no-op.
|
|
63
|
+
* - Refuses to create a conflicting duplicate (same text, different
|
|
64
|
+
* status) — that is a `--set` operation, not an `--add`.
|
|
65
|
+
* - Never touches the frontmatter, the `# H1`, or unrelated lines.
|
|
66
|
+
*/
|
|
67
|
+
export function addProgressRow(content, opts) {
|
|
68
|
+
const section = opts.section.trim();
|
|
69
|
+
const text = opts.text.trim();
|
|
70
|
+
if (!text) {
|
|
71
|
+
throw new ScopeCliError({
|
|
72
|
+
fact: "The --add row text is empty.",
|
|
73
|
+
consequence: "No progress row was written.",
|
|
74
|
+
action: 'Pass a non-empty row, e.g. --add "Guard approved".',
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
const newRow = `- [${statusIndicator(opts.status)}] ${text}`;
|
|
78
|
+
const lines = content.split("\n");
|
|
79
|
+
const start = bodyStartIndex(lines);
|
|
80
|
+
// Locate the target section heading.
|
|
81
|
+
let sectionIdx = -1;
|
|
82
|
+
for (let i = start; i < lines.length; i++) {
|
|
83
|
+
const h = lines[i].match(HEADING_RE);
|
|
84
|
+
if (h && h[2].trim() === section) {
|
|
85
|
+
sectionIdx = i;
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (sectionIdx === -1) {
|
|
90
|
+
// Create the section, appended after the last existing content.
|
|
91
|
+
let end = lines.length;
|
|
92
|
+
while (end > start && lines[end - 1].trim() === "")
|
|
93
|
+
end--;
|
|
94
|
+
const head = lines.slice(0, end);
|
|
95
|
+
const rebuilt = [...head, "", `## ${section}`, "", newRow, ""].join("\n");
|
|
96
|
+
return { content: rebuilt, changed: true };
|
|
97
|
+
}
|
|
98
|
+
// Section block = [sectionIdx+1, nextHeadingOrEOF).
|
|
99
|
+
let blockEnd = lines.length;
|
|
100
|
+
for (let i = sectionIdx + 1; i < lines.length; i++) {
|
|
101
|
+
if (HEADING_RE.test(lines[i])) {
|
|
102
|
+
blockEnd = i;
|
|
103
|
+
break;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Idempotency / conflict scan within the section.
|
|
107
|
+
for (let i = sectionIdx + 1; i < blockEnd; i++) {
|
|
108
|
+
const cb = lines[i].match(ROW_RE);
|
|
109
|
+
if (cb && cb[3].trim() === text) {
|
|
110
|
+
const current = indicatorToStatus(cb[2]);
|
|
111
|
+
if (current === opts.status)
|
|
112
|
+
return { content, changed: false };
|
|
113
|
+
throw new ScopeCliError({
|
|
114
|
+
fact: `A row "${text}" already exists in section "${section}" with status ${current}.`,
|
|
115
|
+
consequence: "Refusing to add a conflicting duplicate row.",
|
|
116
|
+
action: `Use: rig scope ... progress --set "${text}" --status ${opts.status} to change its status.`,
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Insert after the last non-blank line in the section block.
|
|
121
|
+
let insertAt = sectionIdx + 1;
|
|
122
|
+
for (let i = sectionIdx + 1; i < blockEnd; i++) {
|
|
123
|
+
if (lines[i].trim() !== "")
|
|
124
|
+
insertAt = i + 1;
|
|
125
|
+
}
|
|
126
|
+
lines.splice(insertAt, 0, newRow);
|
|
127
|
+
return { content: lines.join("\n"), changed: true };
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Rewrite the indicator of the single row whose trimmed text EXACTLY
|
|
131
|
+
* matches `text`. Row selection is exact-trimmed-text (not line number,
|
|
132
|
+
* not a generated id — the indexer mints neither).
|
|
133
|
+
* - 0 matches → error (names the missing text).
|
|
134
|
+
* - >1 matches → error (ambiguous; v0 refuses rather than guess).
|
|
135
|
+
* - Idempotent: setting a row to its current status is a no-op.
|
|
136
|
+
* - Rewrites ONLY the matched line's indicator char; the rest is
|
|
137
|
+
* preserved byte-for-byte.
|
|
138
|
+
*/
|
|
139
|
+
export function setProgressRow(content, opts) {
|
|
140
|
+
const text = opts.text.trim();
|
|
141
|
+
const lines = content.split("\n");
|
|
142
|
+
const start = bodyStartIndex(lines);
|
|
143
|
+
const matches = [];
|
|
144
|
+
for (let i = start; i < lines.length; i++) {
|
|
145
|
+
const cb = lines[i].match(ROW_RE);
|
|
146
|
+
if (cb && cb[3].trim() === text)
|
|
147
|
+
matches.push(i);
|
|
148
|
+
}
|
|
149
|
+
if (matches.length === 0) {
|
|
150
|
+
throw new ScopeCliError({
|
|
151
|
+
fact: `No progress row matches the exact text "${text}".`,
|
|
152
|
+
consequence: "Nothing was changed.",
|
|
153
|
+
action: 'Check the row text (exact, trimmed match), or add it with --add. List rows with: rig scope ... show.',
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
if (matches.length > 1) {
|
|
157
|
+
throw new ScopeCliError({
|
|
158
|
+
fact: `${matches.length} rows match the text "${text}" (ambiguous).`,
|
|
159
|
+
consequence: "v0 refuses to guess which row to update; nothing was changed.",
|
|
160
|
+
action: "Make the row text unique, then retry.",
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
const i = matches[0];
|
|
164
|
+
const indMatch = lines[i].match(/\[([ xX~])\]/);
|
|
165
|
+
if (indicatorToStatus(indMatch[1]) === opts.status) {
|
|
166
|
+
return { content, changed: false };
|
|
167
|
+
}
|
|
168
|
+
lines[i] = lines[i].replace(/\[([ xX~])\]/, `[${statusIndicator(opts.status)}]`);
|
|
169
|
+
return { content: lines.join("\n"), changed: true };
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=progress-edit.js.map
|