@aacombarro89/praxis 0.1.8 → 0.1.10
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 +26 -19
- package/dist/codex-marketplace.d.ts +19 -0
- package/dist/codex-marketplace.js +113 -0
- package/dist/codex-marketplace.js.map +1 -0
- package/dist/codex-security.d.ts +11 -0
- package/dist/codex-security.js +144 -0
- package/dist/codex-security.js.map +1 -0
- package/dist/emit.d.ts +24 -10
- package/dist/emit.js +149 -70
- package/dist/emit.js.map +1 -1
- package/dist/init.d.ts +16 -6
- package/dist/init.js +47 -10
- package/dist/init.js.map +1 -1
- package/dist/manifest.d.ts +2 -2
- package/dist/manifest.js +1 -1
- package/dist/manifest.js.map +1 -1
- package/dist/packages.d.ts +20 -2
- package/dist/packages.js +54 -5
- package/dist/packages.js.map +1 -1
- package/dist/permissions.d.ts +17 -2
- package/dist/permissions.js +5 -14
- package/dist/permissions.js.map +1 -1
- package/dist/plugins.d.ts +16 -2
- package/dist/plugins.js +15 -15
- package/dist/plugins.js.map +1 -1
- package/dist/program.d.ts +3 -0
- package/dist/program.js +77 -31
- package/dist/program.js.map +1 -1
- package/dist/shared-instructions.d.ts +21 -0
- package/dist/shared-instructions.js +63 -0
- package/dist/shared-instructions.js.map +1 -0
- package/dist/sync.js +103 -7
- package/dist/sync.js.map +1 -1
- package/package.json +1 -1
- package/packages/external/ponytail/plugins.yaml +4 -1
- package/packages/layer1/capture-codebase-patterns/commands/capture-codebase-patterns.md +68 -0
- package/packages/layer1/capture-codebase-patterns/package.yaml +14 -0
- package/packages/layer1/instruction-upkeep/commands/instructions.md +14 -5
- package/packages/layer1/instruction-upkeep/rules.md +7 -3
- package/packages/layer1/onboarding/commands/onboard.md +42 -24
- package/packages/layer1/onboarding/rules.md +4 -4
- package/packages/layer1/safe-permissions/permissions.yaml +2 -2
- package/packages/layer1/session-handoff/commands/handoff.md +5 -5
- package/packages/layer1/session-handoff/rules.md +2 -2
- package/packages/layer1/upkeep/commands/upkeep.md +8 -5
- package/packages/layer1/upkeep/rules.md +8 -4
- package/packages/layer1/wiki-memory/commands/wiki.md +6 -6
- package/packages/layer1/wiki-memory/rules.md +4 -4
- package/packages/layer2/node-recipes/rules.md +18 -19
- package/packages/layer2/node-testing/rules.md +21 -26
- package/packages/layer2/python-backend-recipes/rules.md +18 -22
- package/packages/layer2/python-testing/rules.md +20 -26
- package/packages/layer2/react-components/rules.md +31 -26
- package/packages/layer2/react-testing/rules.md +19 -28
package/README.md
CHANGED
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
meta-development rules and authoring recipes that make AI coding agents produce
|
|
5
5
|
correct, conformant work.
|
|
6
6
|
|
|
7
|
-
Praxis is **not** implementation scaffolding and **not**
|
|
8
|
-
generator. It writes _only_ the methodology layer — agent
|
|
9
|
-
|
|
10
|
-
code, dependencies, or runtime
|
|
7
|
+
Praxis is **not** implementation scaffolding and **not** an application config
|
|
8
|
+
generator. It writes _only_ the methodology layer — agent instructions,
|
|
9
|
+
native workflows, methodology permissions and plugin metadata, and its own
|
|
10
|
+
manifest. It never touches your application code, dependencies, or runtime
|
|
11
|
+
infrastructure.
|
|
11
12
|
|
|
12
13
|
```bash
|
|
13
14
|
npx @aacombarro89/praxis
|
|
@@ -22,8 +23,8 @@ Running `praxis` in a project:
|
|
|
22
23
|
a `react` dependency → both `node` and `react`.
|
|
23
24
|
2. **Offers a first-run fork** — _Quick start_ (recommended defaults, preview
|
|
24
25
|
the diff, confirm) or _Customize_ (choose stacks, packages, and targets).
|
|
25
|
-
3. **Composes the methodology into your repo** — it
|
|
26
|
-
|
|
26
|
+
3. **Composes the methodology into your repo** — it emits Claude Code rules,
|
|
27
|
+
Codex skills, and managed `AGENTS.md` blocks without clobbering your own content, and records what
|
|
27
28
|
it did in a visible, committed, hand-editable manifest: `praxis.yaml`.
|
|
28
29
|
|
|
29
30
|
It always previews a single diff before writing. Git is your undo.
|
|
@@ -36,10 +37,13 @@ Other tools _generate_ agent instructions once; Praxis **manages** them:
|
|
|
36
37
|
packages pinned in `praxis.yaml`, and `praxis check` fails CI when the
|
|
37
38
|
installed files drift — think Renovate/Dependabot, for your agent
|
|
38
39
|
instruction layer.
|
|
40
|
+
- **Peer-native project facts.** When Claude Code and Codex coexist, project-owned
|
|
41
|
+
shared sections live in both native instruction files. `praxis check` verifies
|
|
42
|
+
parity and upkeep fixes factual drift; neither tool depends on Praxis at runtime.
|
|
39
43
|
- **A composition / merge step** that folds methodology into an _existing_
|
|
40
44
|
project without overwriting project-specific content.
|
|
41
|
-
- **One neutral source, per-tool outputs** — Claude Code and
|
|
42
|
-
|
|
45
|
+
- **One neutral source, per-tool outputs** — first-class Claude Code and OpenAI
|
|
46
|
+
Codex support, plus a generic `AGENTS.md` target.
|
|
43
47
|
|
|
44
48
|
The curated methodology — Layer 1 behavioral rules plus Layer 2 stack recipes
|
|
45
49
|
— is the starting payload that rides this machinery.
|
|
@@ -67,7 +71,7 @@ sync`**. There is no `add`/`remove` — one obvious way to change things.
|
|
|
67
71
|
version: 1
|
|
68
72
|
methodology: "0.1.0" # pinned; `sync` offers to bump
|
|
69
73
|
stacks: [node, react] # detection-seeded, user-editable
|
|
70
|
-
targets: [claude-code,
|
|
74
|
+
targets: [claude-code, codex] # which agent tools to support
|
|
71
75
|
packages:
|
|
72
76
|
- karpathy-claude # behavioral rules (Layer 1)
|
|
73
77
|
- wiki-memory # the knowledge-wiki command (Layer 1)
|
|
@@ -86,24 +90,26 @@ pinned version — never behind your back.
|
|
|
86
90
|
| `praxis sync` | Reconcile the repo to `praxis.yaml`; offer newer methodology; diff + confirm. |
|
|
87
91
|
| `praxis check` | Dry-run; report drift; non-zero exit for CI. |
|
|
88
92
|
|
|
89
|
-
`--yes` skips prompts
|
|
93
|
+
`--yes` skips prompts for non-interactive/CI use. Repeat `--target`, for example
|
|
94
|
+
`praxis --yes --target codex --target agents-md`, to override target detection.
|
|
90
95
|
|
|
91
96
|
## Tool-neutral by construction
|
|
92
97
|
|
|
93
98
|
The methodology source is singular; Praxis _emits_ per-tool variants from it.
|
|
94
|
-
**Claude Code** (`.claude/rules/`,
|
|
95
|
-
|
|
99
|
+
**Claude Code** (`.claude/rules/`, commands, `settings.json`), **OpenAI Codex**
|
|
100
|
+
(`AGENTS.md`, `.agents/skills/`, permission profiles/rules, plugin marketplace), and the
|
|
101
|
+
generic **`agents-md`** flat-file convention are built today. Cursor is a
|
|
96
102
|
planned target; Copilot/Windsurf/Roo are deferred until they land.
|
|
97
103
|
|
|
98
104
|
## "Memory" means the agent's memory, not the app's
|
|
99
105
|
|
|
100
106
|
In Praxis, _memory_ always refers to the **AI coding tool's** curated,
|
|
101
|
-
file-based instruction layer (`CLAUDE.md`, the knowledge wiki,
|
|
102
|
-
notes) — not a runtime memory backend for your application
|
|
103
|
-
etc.). Wiring a persistence backend into your app is
|
|
104
|
-
scope. The most Praxis ships on that topic is a
|
|
105
|
-
guidance on whether you need runtime memory and how
|
|
106
|
-
backend itself.
|
|
107
|
+
file-based instruction layer (`CLAUDE.md` or `AGENTS.md`, the knowledge wiki,
|
|
108
|
+
skills, decision notes) — not a runtime memory backend for your application
|
|
109
|
+
(Mem0, Zep, Letta, etc.). Wiring a persistence backend into your app is
|
|
110
|
+
implementation, and out of scope. The most Praxis ships on that topic is a
|
|
111
|
+
Layer 2 _decision recipe_: guidance on whether you need runtime memory and how
|
|
112
|
+
to choose — never the backend itself.
|
|
107
113
|
|
|
108
114
|
## Developing Praxis
|
|
109
115
|
|
|
@@ -130,4 +136,5 @@ lands on a feature branch and merges via PR — no direct pushes to `main`.
|
|
|
130
136
|
- `docs/wiki/` — the durable, in-repo knowledge wiki and canonical design doc;
|
|
131
137
|
start at [`docs/wiki/index.md`](docs/wiki/index.md).
|
|
132
138
|
|
|
133
|
-
See [`CLAUDE.md`](CLAUDE.md)
|
|
139
|
+
See the peer-native [`CLAUDE.md`](CLAUDE.md) and [`AGENTS.md`](AGENTS.md) for
|
|
140
|
+
the project's non-negotiable rails.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const CODEX_MARKETPLACE_PATH = ".agents/plugins/marketplace.json";
|
|
2
|
+
export declare const CODEX_MARKETPLACE_STATE_PATH = ".praxis/codex-marketplace-state.json";
|
|
3
|
+
export interface CodexPluginEntry {
|
|
4
|
+
name: string;
|
|
5
|
+
source: Record<string, string>;
|
|
6
|
+
policy: {
|
|
7
|
+
installation: string;
|
|
8
|
+
authentication: string;
|
|
9
|
+
};
|
|
10
|
+
category: string;
|
|
11
|
+
}
|
|
12
|
+
export interface MarketplaceReconcileResult {
|
|
13
|
+
marketplaceText: string;
|
|
14
|
+
stateText: string;
|
|
15
|
+
marketplaceChanged: boolean;
|
|
16
|
+
stateChanged: boolean;
|
|
17
|
+
conflicts: string[];
|
|
18
|
+
}
|
|
19
|
+
export declare function reconcileCodexMarketplace(marketplaceText: string, stateText: string, desired: CodexPluginEntry[]): MarketplaceReconcileResult;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
export const CODEX_MARKETPLACE_PATH = ".agents/plugins/marketplace.json";
|
|
3
|
+
export const CODEX_MARKETPLACE_STATE_PATH = ".praxis/codex-marketplace-state.json";
|
|
4
|
+
/** Deeply sorts object keys so hashing is insensitive to cosmetic key
|
|
5
|
+
* reordering (e.g. a formatter running `jq -S` over marketplace.json). */
|
|
6
|
+
function canonicalize(value) {
|
|
7
|
+
if (Array.isArray(value))
|
|
8
|
+
return value.map(canonicalize);
|
|
9
|
+
if (value && typeof value === "object") {
|
|
10
|
+
const sorted = {};
|
|
11
|
+
for (const key of Object.keys(value).sort()) {
|
|
12
|
+
sorted[key] = canonicalize(value[key]);
|
|
13
|
+
}
|
|
14
|
+
return sorted;
|
|
15
|
+
}
|
|
16
|
+
return value;
|
|
17
|
+
}
|
|
18
|
+
function hashEntry(entry) {
|
|
19
|
+
return createHash("sha256").update(JSON.stringify(canonicalize(entry))).digest("hex");
|
|
20
|
+
}
|
|
21
|
+
function parseJson(text, label) {
|
|
22
|
+
if (!text.trim())
|
|
23
|
+
return {};
|
|
24
|
+
const parsed = JSON.parse(text);
|
|
25
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
26
|
+
throw new Error(`${label} must contain a JSON object.`);
|
|
27
|
+
}
|
|
28
|
+
return parsed;
|
|
29
|
+
}
|
|
30
|
+
function parseState(text) {
|
|
31
|
+
if (!text.trim())
|
|
32
|
+
return { version: 1, entries: {} };
|
|
33
|
+
const parsed = parseJson(text, CODEX_MARKETPLACE_STATE_PATH);
|
|
34
|
+
if (parsed.version !== 1 || !parsed.entries || typeof parsed.entries !== "object" || Array.isArray(parsed.entries)) {
|
|
35
|
+
throw new Error(`${CODEX_MARKETPLACE_STATE_PATH} has an unsupported ownership-state shape.`);
|
|
36
|
+
}
|
|
37
|
+
const entries = {};
|
|
38
|
+
for (const [name, value] of Object.entries(parsed.entries)) {
|
|
39
|
+
if (typeof value !== "string")
|
|
40
|
+
throw new Error(`${CODEX_MARKETPLACE_STATE_PATH} has a non-string hash for ${name}.`);
|
|
41
|
+
entries[name] = value;
|
|
42
|
+
}
|
|
43
|
+
return { version: 1, entries };
|
|
44
|
+
}
|
|
45
|
+
function render(value) {
|
|
46
|
+
return `${JSON.stringify(value, null, 2)}\n`;
|
|
47
|
+
}
|
|
48
|
+
export function reconcileCodexMarketplace(marketplaceText, stateText, desired) {
|
|
49
|
+
const root = parseJson(marketplaceText, CODEX_MARKETPLACE_PATH);
|
|
50
|
+
const state = parseState(stateText);
|
|
51
|
+
const rawPlugins = root.plugins ?? [];
|
|
52
|
+
if (!Array.isArray(rawPlugins))
|
|
53
|
+
throw new Error(`${CODEX_MARKETPLACE_PATH} field "plugins" must be an array.`);
|
|
54
|
+
const plugins = [...rawPlugins];
|
|
55
|
+
const conflicts = [];
|
|
56
|
+
const desiredByName = new Map(desired.map((entry) => [entry.name, entry]));
|
|
57
|
+
const nextHashes = {};
|
|
58
|
+
const findIndex = (name) => plugins.findIndex((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry) && entry.name === name));
|
|
59
|
+
for (const [name, recordedHash] of Object.entries(state.entries)) {
|
|
60
|
+
const index = findIndex(name);
|
|
61
|
+
const wanted = desiredByName.get(name);
|
|
62
|
+
if (index === -1)
|
|
63
|
+
continue;
|
|
64
|
+
if (hashEntry(plugins[index]) !== recordedHash) {
|
|
65
|
+
conflicts.push(name);
|
|
66
|
+
nextHashes[name] = recordedHash;
|
|
67
|
+
desiredByName.delete(name);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (!wanted) {
|
|
71
|
+
plugins.splice(index, 1);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
for (const entry of desired) {
|
|
75
|
+
if (!desiredByName.has(entry.name))
|
|
76
|
+
continue;
|
|
77
|
+
const index = findIndex(entry.name);
|
|
78
|
+
const desiredHash = hashEntry(entry);
|
|
79
|
+
if (index === -1) {
|
|
80
|
+
plugins.push(entry);
|
|
81
|
+
nextHashes[entry.name] = desiredHash;
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const recordedHash = state.entries[entry.name];
|
|
85
|
+
if (recordedHash || hashEntry(plugins[index]) === desiredHash) {
|
|
86
|
+
plugins[index] = entry;
|
|
87
|
+
nextHashes[entry.name] = desiredHash;
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
conflicts.push(entry.name);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
for (const [name, recordedHash] of Object.entries(state.entries)) {
|
|
94
|
+
if (conflicts.includes(name))
|
|
95
|
+
nextHashes[name] = recordedHash;
|
|
96
|
+
}
|
|
97
|
+
if (!("name" in root))
|
|
98
|
+
root.name = "praxis";
|
|
99
|
+
if (!("interface" in root))
|
|
100
|
+
root.interface = { displayName: "Praxis" };
|
|
101
|
+
root.plugins = plugins;
|
|
102
|
+
const nextState = { version: 1, entries: nextHashes };
|
|
103
|
+
const nextMarketplaceText = render(root);
|
|
104
|
+
const nextStateText = render(nextState);
|
|
105
|
+
return {
|
|
106
|
+
marketplaceText: nextMarketplaceText,
|
|
107
|
+
stateText: nextStateText,
|
|
108
|
+
marketplaceChanged: nextMarketplaceText !== marketplaceText,
|
|
109
|
+
stateChanged: nextStateText !== stateText,
|
|
110
|
+
conflicts,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=codex-marketplace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-marketplace.js","sourceRoot":"","sources":["../src/codex-marketplace.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Capability, Policy } from "./permissions.js";
|
|
2
|
+
export declare const CODEX_CONFIG_BODY = "default_permissions = \"praxis-safe-permissions\"\n\n[permissions.praxis-safe-permissions]\ndescription = \"Workspace editing with Praxis secret-file protections and no sandbox network access.\"\nextends = \":workspace\"\n\n[permissions.praxis-safe-permissions.filesystem]\nglob_scan_max_depth = 12\n\n[permissions.praxis-safe-permissions.filesystem.\":workspace_roots\"]\n\".env\" = \"deny\"\n\"**/.env*\" = \"deny\"\n\"**/*.pem\" = \"deny\"\n\"**/credentials*\" = \"deny\"\n\n[permissions.praxis-safe-permissions.network]\nenabled = false";
|
|
3
|
+
export declare function reconcileCodexConfig(existing: string, enabled: boolean): {
|
|
4
|
+
text: string;
|
|
5
|
+
changed: boolean;
|
|
6
|
+
conflicts: string[];
|
|
7
|
+
};
|
|
8
|
+
/** Every neutral capability is handled by command rules or explicitly delegated
|
|
9
|
+
* to the permission profile. Exported as the Codex conformance seam. */
|
|
10
|
+
export declare function codexCapabilityMode(capability: Capability): "profile" | "rules" | undefined;
|
|
11
|
+
export declare function renderCodexRules(policy: Policy): string;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
const BLOCK_ID = "safe-permissions";
|
|
3
|
+
const BEGIN = /^# praxis:begin safe-permissions sha256=([a-f0-9]{64})$/m;
|
|
4
|
+
const END = /^# praxis:end safe-permissions$/m;
|
|
5
|
+
function hash(text) {
|
|
6
|
+
return createHash("sha256").update(text).digest("hex");
|
|
7
|
+
}
|
|
8
|
+
export const CODEX_CONFIG_BODY = `default_permissions = "praxis-safe-permissions"
|
|
9
|
+
|
|
10
|
+
[permissions.praxis-safe-permissions]
|
|
11
|
+
description = "Workspace editing with Praxis secret-file protections and no sandbox network access."
|
|
12
|
+
extends = ":workspace"
|
|
13
|
+
|
|
14
|
+
[permissions.praxis-safe-permissions.filesystem]
|
|
15
|
+
glob_scan_max_depth = 12
|
|
16
|
+
|
|
17
|
+
[permissions.praxis-safe-permissions.filesystem.":workspace_roots"]
|
|
18
|
+
".env" = "deny"
|
|
19
|
+
"**/.env*" = "deny"
|
|
20
|
+
"**/*.pem" = "deny"
|
|
21
|
+
"**/credentials*" = "deny"
|
|
22
|
+
|
|
23
|
+
[permissions.praxis-safe-permissions.network]
|
|
24
|
+
enabled = false`;
|
|
25
|
+
function managedBlock(body) {
|
|
26
|
+
return `# praxis:begin ${BLOCK_ID} sha256=${hash(body)}\n${body}\n# praxis:end ${BLOCK_ID}`;
|
|
27
|
+
}
|
|
28
|
+
function locate(text) {
|
|
29
|
+
const begin = BEGIN.exec(text);
|
|
30
|
+
if (!begin || begin.index === undefined)
|
|
31
|
+
return undefined;
|
|
32
|
+
END.lastIndex = 0;
|
|
33
|
+
const afterBegin = begin.index + begin[0].length;
|
|
34
|
+
const end = END.exec(text.slice(afterBegin));
|
|
35
|
+
if (!end || end.index === undefined)
|
|
36
|
+
return undefined;
|
|
37
|
+
const bodyStart = afterBegin + 1;
|
|
38
|
+
const endStart = afterBegin + end.index;
|
|
39
|
+
return {
|
|
40
|
+
start: begin.index,
|
|
41
|
+
end: endStart + end[0].length,
|
|
42
|
+
body: text.slice(bodyStart, endStart).replace(/\n$/, ""),
|
|
43
|
+
recordedHash: begin[1],
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
function withoutBlock(text, block) {
|
|
47
|
+
if (!block)
|
|
48
|
+
return text;
|
|
49
|
+
return `${text.slice(0, block.start)}${text.slice(block.end)}`;
|
|
50
|
+
}
|
|
51
|
+
function externalConflicts(text) {
|
|
52
|
+
const conflicts = [];
|
|
53
|
+
if (/^\s*default_permissions\s*=/m.test(text))
|
|
54
|
+
conflicts.push("default_permissions");
|
|
55
|
+
if (/^\s*sandbox_mode\s*=/m.test(text))
|
|
56
|
+
conflicts.push("sandbox_mode");
|
|
57
|
+
if (/^\s*\[sandbox_workspace_write\]/m.test(text))
|
|
58
|
+
conflicts.push("sandbox_workspace_write");
|
|
59
|
+
if (/^\s*\[permissions\.praxis-safe-permissions(?:\.|\])/m.test(text)) {
|
|
60
|
+
conflicts.push("permissions.praxis-safe-permissions");
|
|
61
|
+
}
|
|
62
|
+
return conflicts;
|
|
63
|
+
}
|
|
64
|
+
export function reconcileCodexConfig(existing, enabled) {
|
|
65
|
+
const block = locate(existing);
|
|
66
|
+
if (block && hash(block.body) !== block.recordedHash) {
|
|
67
|
+
return { text: existing, changed: false, conflicts: [BLOCK_ID] };
|
|
68
|
+
}
|
|
69
|
+
const outside = withoutBlock(existing, block);
|
|
70
|
+
if (enabled) {
|
|
71
|
+
const conflicts = externalConflicts(outside);
|
|
72
|
+
if (conflicts.length > 0)
|
|
73
|
+
return { text: existing, changed: false, conflicts };
|
|
74
|
+
const rest = outside.trim();
|
|
75
|
+
// Inserted first, not appended: a bare `key = value` line in TOML belongs
|
|
76
|
+
// to whatever `[table]` precedes it, so placing our block after user
|
|
77
|
+
// content risks default_permissions being silently absorbed into a table
|
|
78
|
+
// the user's file happens to end inside. Leading in the file guarantees
|
|
79
|
+
// root-table scope regardless of what follows.
|
|
80
|
+
const text = `${managedBlock(CODEX_CONFIG_BODY)}\n${rest ? `\n${rest}\n` : ""}`;
|
|
81
|
+
return { text, changed: text !== existing, conflicts: [] };
|
|
82
|
+
}
|
|
83
|
+
if (!block)
|
|
84
|
+
return { text: existing, changed: false, conflicts: [] };
|
|
85
|
+
const rest = outside.trim();
|
|
86
|
+
const text = rest ? `${rest}\n` : "";
|
|
87
|
+
return { text, changed: text !== existing, conflicts: [] };
|
|
88
|
+
}
|
|
89
|
+
const COMMAND_PATTERNS = {
|
|
90
|
+
"run-dev-scripts": [
|
|
91
|
+
["npm", "run", "test"],
|
|
92
|
+
["npm", "run", "lint"],
|
|
93
|
+
["npm", "run", "typecheck"],
|
|
94
|
+
["npm", "run", "build"],
|
|
95
|
+
],
|
|
96
|
+
"read-only-git": [["git", "status"], ["git", "diff"], ["git", "log"]],
|
|
97
|
+
"git-commit": [["git", "commit"]],
|
|
98
|
+
"git-push": [["git", "push"]],
|
|
99
|
+
"install-deps": [["npm", "install"], ["npm", "i"], ["npm", "ci"]],
|
|
100
|
+
"destructive-delete": [["rm", "-rf"]],
|
|
101
|
+
"force-push": [["git", "push", "--force"], ["git", "push", "-f"]],
|
|
102
|
+
"global-install": [
|
|
103
|
+
["npm", "install", "-g"],
|
|
104
|
+
["npm", "install", "--global"],
|
|
105
|
+
["npm", "i", "-g"],
|
|
106
|
+
["npm", "i", "--global"],
|
|
107
|
+
["pnpm", "add", "-g"],
|
|
108
|
+
["pnpm", "add", "--global"],
|
|
109
|
+
],
|
|
110
|
+
};
|
|
111
|
+
const PROFILE_CAPABILITIES = new Set(["read-repo", "edit-repo", "read-secrets"]);
|
|
112
|
+
/** Every neutral capability is handled by command rules or explicitly delegated
|
|
113
|
+
* to the permission profile. Exported as the Codex conformance seam. */
|
|
114
|
+
export function codexCapabilityMode(capability) {
|
|
115
|
+
if (PROFILE_CAPABILITIES.has(capability))
|
|
116
|
+
return "profile";
|
|
117
|
+
if (COMMAND_PATTERNS[capability])
|
|
118
|
+
return "rules";
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
function starlarkString(value) {
|
|
122
|
+
return JSON.stringify(value);
|
|
123
|
+
}
|
|
124
|
+
export function renderCodexRules(policy) {
|
|
125
|
+
const decisions = [
|
|
126
|
+
["allow", "allow"],
|
|
127
|
+
["ask", "prompt"],
|
|
128
|
+
["deny", "forbidden"],
|
|
129
|
+
];
|
|
130
|
+
const lines = [
|
|
131
|
+
"# Generated by Praxis. Project rules load only after this repository is trusted.",
|
|
132
|
+
"# Filesystem capabilities are enforced by the praxis-safe-permissions profile in ../config.toml.",
|
|
133
|
+
"",
|
|
134
|
+
];
|
|
135
|
+
for (const [bucket, decision] of decisions) {
|
|
136
|
+
for (const capability of policy[bucket]) {
|
|
137
|
+
for (const pattern of COMMAND_PATTERNS[capability] ?? []) {
|
|
138
|
+
lines.push(`prefix_rule(pattern = [${pattern.map(starlarkString).join(", ")}], decision = ${starlarkString(decision)}, justification = ${starlarkString(`Praxis capability: ${capability}`)})`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return `${lines.join("\n").trimEnd()}\n`;
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=codex-security.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex-security.js","sourceRoot":"","sources":["../src/codex-security.ts"],"names":[],"mappings":"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"}
|
package/dist/emit.d.ts
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
import type { Manifest, Target } from "./manifest.js";
|
|
2
2
|
import { type PluginsDesired, type RuleSet } from "./merge-json.js";
|
|
3
|
+
import { CODEX_MARKETPLACE_PATH, CODEX_MARKETPLACE_STATE_PATH, type CodexPluginEntry } from "./codex-marketplace.js";
|
|
3
4
|
export declare const BLOCK_FILE: Partial<Record<Target, string>>;
|
|
4
5
|
/** The neutral methodology source for a content package, or undefined if the
|
|
5
|
-
* package has no rules.md (e.g. skills, Layer 2 recipes handled by other phases).
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
* package has no rules.md (e.g. skills, Layer 2 recipes handled by other phases).
|
|
7
|
+
* `dir` is the package's own directory (`ResolvedPackage.dir`) — shipped or
|
|
8
|
+
* project-local, resolved identically either way. */
|
|
9
|
+
export declare function loadPackageSource(dir: string): string | undefined;
|
|
10
|
+
/** A package's workflow sources: one file per workflow, named for its target-native invocation. */
|
|
9
11
|
export interface CommandSource {
|
|
10
12
|
name: string;
|
|
11
13
|
content: string;
|
|
12
14
|
}
|
|
13
15
|
/** A content package's commands, or [] if it has none. Scans
|
|
14
|
-
*
|
|
15
|
-
export declare function loadCommandSources(
|
|
16
|
+
* `<dir>/commands/*.md` — mirrors loadPackageSource. */
|
|
17
|
+
export declare function loadCommandSources(dir: string): CommandSource[];
|
|
16
18
|
/** A planned write. "owned" files are placed/replaced wholesale; "block" files
|
|
17
19
|
* have their managed blocks reconciled into existing text; "settings" carries
|
|
18
20
|
* whichever of permissions/plugins this target emits — always exactly one op
|
|
@@ -34,10 +36,22 @@ export type EmitOp = {
|
|
|
34
36
|
path: string;
|
|
35
37
|
rules?: RuleSet;
|
|
36
38
|
plugins?: PluginsDesired;
|
|
39
|
+
} | {
|
|
40
|
+
kind: "codex-config";
|
|
41
|
+
target: "codex";
|
|
42
|
+
path: ".codex/config.toml";
|
|
43
|
+
enabled: boolean;
|
|
44
|
+
} | {
|
|
45
|
+
kind: "codex-marketplace";
|
|
46
|
+
target: "codex";
|
|
47
|
+
path: typeof CODEX_MARKETPLACE_PATH;
|
|
48
|
+
statePath: typeof CODEX_MARKETPLACE_STATE_PATH;
|
|
49
|
+
plugins: CodexPluginEntry[];
|
|
37
50
|
};
|
|
38
51
|
/** Build the emit plan from a manifest: the file operations needed to install
|
|
39
|
-
* the selected methodology for each target.
|
|
40
|
-
|
|
52
|
+
* the selected methodology for each target. `cwd` resolves any project-local
|
|
53
|
+
* (`./`-prefixed) packages the manifest names; defaults to process.cwd(). */
|
|
54
|
+
export declare function planEmit(manifest: Manifest, cwd?: string): EmitOp[];
|
|
41
55
|
export interface MethodologySize {
|
|
42
56
|
/** Total content lines across the counted rule artifacts. */
|
|
43
57
|
totalLines: number;
|
|
@@ -53,7 +67,7 @@ export interface MethodologySize {
|
|
|
53
67
|
*
|
|
54
68
|
* Counts the claude-code target's owned `.claude/rules/*` files (one per rules
|
|
55
69
|
* package). If claude-code isn't a manifest target, falls back to the
|
|
56
|
-
* agents-md managed block content, one artifact per block, so the
|
|
70
|
+
* Codex/agents-md managed block content, one artifact per block, so the targets'
|
|
57
71
|
* shared source is never double-counted. Commands, permissions/plugins JSON,
|
|
58
72
|
* and the wiki are never counted — none are loaded at session start.
|
|
59
73
|
*
|
|
@@ -61,7 +75,7 @@ export interface MethodologySize {
|
|
|
61
75
|
* unknown package) — callers in check mode should catch and omit the line
|
|
62
76
|
* rather than let it mask the sync error (D40's degrade-by-omission model).
|
|
63
77
|
*/
|
|
64
|
-
export declare function computeMethodologySize(manifest: Manifest): MethodologySize;
|
|
78
|
+
export declare function computeMethodologySize(manifest: Manifest, cwd?: string): MethodologySize;
|
|
65
79
|
export interface ApplyResult {
|
|
66
80
|
text: string;
|
|
67
81
|
changed: boolean;
|