@rubytech/create-maxy-code 0.1.223 → 0.1.225
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/dist/__tests__/installer-settings-permissions.test.js +112 -0
- package/dist/index.js +13 -0
- package/dist/permissions-seed.js +76 -0
- package/package.json +1 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js +1 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/skills/file-presentation/SKILL.md +9 -7
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +18 -4
- package/payload/platform/plugins/admin/skills/professional-document/SKILL.md +1 -1
- package/payload/platform/plugins/docs/references/admin-ui.md +11 -1
- package/payload/platform/plugins/docs/references/deployment.md +1 -1
- package/payload/platform/plugins/docs/references/platform.md +4 -0
- package/payload/platform/plugins/docs/references/troubleshooting.md +1 -1
- package/payload/platform/plugins/graph-viewer/mcp/dist/index.js +1 -1
- package/payload/platform/plugins/graph-viewer/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/graph-viewer/mcp/dist/tools/graph-render.d.ts.map +1 -1
- package/payload/platform/plugins/graph-viewer/mcp/dist/tools/graph-render.js +7 -5
- package/payload/platform/plugins/graph-viewer/mcp/dist/tools/graph-render.js.map +1 -1
- package/payload/platform/plugins/graph-viewer/skills/render-graph/SKILL.md +6 -6
- package/payload/platform/plugins/scheduling/PLUGIN.md +2 -2
- package/payload/platform/plugins/scheduling/mcp/dist/index.js +2 -2
- package/payload/platform/plugins/scheduling/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-export-ics.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-export-ics.js +3 -2
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-export-ics.js.map +1 -1
- package/payload/platform/scripts/check-plugin-references.mjs +256 -0
- package/payload/platform/scripts/logs-read-jsonl.test.sh +307 -0
- package/payload/platform/scripts/logs-read.sh +435 -32
- package/payload/platform/scripts/setup-account.sh +20 -8
- package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts +0 -1
- package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/system-prompt.js +11 -10
- package/payload/platform/services/claude-session-manager/dist/system-prompt.js.map +1 -1
- package/payload/platform/templates/specialists/agents/content-producer.md +1 -1
- package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
- package/payload/premium-plugins/teaching/PLUGIN.md +7 -7
- package/payload/premium-plugins/venture-studio/skills/brand-pack/SKILL.md +1 -1
- package/payload/server/public/assets/data-BzRzOKWv.js +1 -0
- package/payload/server/public/data.html +1 -1
- package/payload/server/server.js +13 -6
- package/payload/server/public/assets/data-CHdaTjgn.js +0 -1
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// Task 583 — Installer must seed permissions.defaultMode=bypassPermissions
|
|
2
|
+
// and permissions.allow=["*"] into the brand-scoped settings.json so
|
|
3
|
+
// claude.ai/code sessions never fall through to the Anthropic remote
|
|
4
|
+
// auto-classifier. Existing top-level keys must be preserved; an
|
|
5
|
+
// already-correct file must be a true no-op (mtime unchanged).
|
|
6
|
+
import test from "node:test";
|
|
7
|
+
import assert from "node:assert/strict";
|
|
8
|
+
import { mkdtempSync, readFileSync, writeFileSync, statSync, rmSync } from "node:fs";
|
|
9
|
+
import { tmpdir } from "node:os";
|
|
10
|
+
import { join } from "node:path";
|
|
11
|
+
import { seedBypassPermissionsSettings, assertBypassPermissionsSeed, BYPASS_PERMISSIONS_BLOCK } from "../permissions-seed.js";
|
|
12
|
+
function freshDir() {
|
|
13
|
+
return mkdtempSync(join(tmpdir(), "t583-"));
|
|
14
|
+
}
|
|
15
|
+
test("empty target: creates settings.json with the permissions block", () => {
|
|
16
|
+
const dir = freshDir();
|
|
17
|
+
try {
|
|
18
|
+
const result = seedBypassPermissionsSettings(dir);
|
|
19
|
+
assert.equal(result.action, "seeded");
|
|
20
|
+
assert.equal(result.path, join(dir, "settings.json"));
|
|
21
|
+
const parsed = JSON.parse(readFileSync(result.path, "utf-8"));
|
|
22
|
+
assert.deepEqual(parsed, { permissions: { defaultMode: "bypassPermissions", allow: ["*"], deny: [] } });
|
|
23
|
+
assert.equal(assertBypassPermissionsSeed(dir).status, "ok");
|
|
24
|
+
}
|
|
25
|
+
finally {
|
|
26
|
+
rmSync(dir, { recursive: true, force: true });
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
test("existing keys preserved verbatim; permissions added", () => {
|
|
30
|
+
const dir = freshDir();
|
|
31
|
+
try {
|
|
32
|
+
const settingsPath = join(dir, "settings.json");
|
|
33
|
+
const existing = {
|
|
34
|
+
enabledPlugins: { "memory@claude-plugins-official": true },
|
|
35
|
+
extraKnownMarketplaces: { "claude-plugins-official": { source: { source: "github", repo: "anthropics/claude-plugins-official" } } },
|
|
36
|
+
inputNeededNotifEnabled: false,
|
|
37
|
+
agentPushNotifEnabled: false,
|
|
38
|
+
model: "opus",
|
|
39
|
+
};
|
|
40
|
+
writeFileSync(settingsPath, JSON.stringify(existing, null, 2));
|
|
41
|
+
const result = seedBypassPermissionsSettings(dir);
|
|
42
|
+
assert.equal(result.action, "seeded");
|
|
43
|
+
const parsed = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
44
|
+
assert.deepEqual(parsed.enabledPlugins, existing.enabledPlugins);
|
|
45
|
+
assert.deepEqual(parsed.extraKnownMarketplaces, existing.extraKnownMarketplaces);
|
|
46
|
+
assert.equal(parsed.inputNeededNotifEnabled, false);
|
|
47
|
+
assert.equal(parsed.agentPushNotifEnabled, false);
|
|
48
|
+
assert.equal(parsed.model, "opus");
|
|
49
|
+
assert.deepEqual(parsed.permissions, { defaultMode: "bypassPermissions", allow: ["*"], deny: [] });
|
|
50
|
+
assert.equal(assertBypassPermissionsSeed(dir).status, "ok");
|
|
51
|
+
}
|
|
52
|
+
finally {
|
|
53
|
+
rmSync(dir, { recursive: true, force: true });
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
test("idempotent: already-correct block triggers no write", () => {
|
|
57
|
+
const dir = freshDir();
|
|
58
|
+
try {
|
|
59
|
+
const settingsPath = join(dir, "settings.json");
|
|
60
|
+
writeFileSync(settingsPath, JSON.stringify({ model: "opus", permissions: { defaultMode: "bypassPermissions", allow: ["*"], deny: [] } }, null, 2));
|
|
61
|
+
const before = statSync(settingsPath).mtimeMs;
|
|
62
|
+
// Small busy-wait so a same-millisecond write would be detectable on
|
|
63
|
+
// filesystems with millisecond mtime granularity.
|
|
64
|
+
const target = Date.now() + 15;
|
|
65
|
+
while (Date.now() < target) { /* spin */ }
|
|
66
|
+
const result = seedBypassPermissionsSettings(dir);
|
|
67
|
+
assert.equal(result.action, "noop");
|
|
68
|
+
const after = statSync(settingsPath).mtimeMs;
|
|
69
|
+
assert.equal(after, before, "mtime must not change on noop");
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
rmSync(dir, { recursive: true, force: true });
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
test("malformed JSON: overwrites with the seeded block", () => {
|
|
76
|
+
const dir = freshDir();
|
|
77
|
+
try {
|
|
78
|
+
const settingsPath = join(dir, "settings.json");
|
|
79
|
+
writeFileSync(settingsPath, "{ not json");
|
|
80
|
+
const result = seedBypassPermissionsSettings(dir);
|
|
81
|
+
assert.equal(result.action, "seeded");
|
|
82
|
+
assert.equal(assertBypassPermissionsSeed(dir).status, "ok");
|
|
83
|
+
}
|
|
84
|
+
finally {
|
|
85
|
+
rmSync(dir, { recursive: true, force: true });
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
test("assert: missing file reports missing", () => {
|
|
89
|
+
const dir = freshDir();
|
|
90
|
+
try {
|
|
91
|
+
assert.equal(assertBypassPermissionsSeed(dir).status, "missing");
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
rmSync(dir, { recursive: true, force: true });
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
test("assert: partial block (no wildcard) reports missing", () => {
|
|
98
|
+
const dir = freshDir();
|
|
99
|
+
try {
|
|
100
|
+
writeFileSync(join(dir, "settings.json"), JSON.stringify({ permissions: { defaultMode: "default", allow: [], deny: [] } }));
|
|
101
|
+
assert.equal(assertBypassPermissionsSeed(dir).status, "missing");
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
rmSync(dir, { recursive: true, force: true });
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
test("BYPASS_PERMISSIONS_BLOCK frozen literal matches expected shape", () => {
|
|
108
|
+
assert.equal(BYPASS_PERMISSIONS_BLOCK.defaultMode, "bypassPermissions");
|
|
109
|
+
assert.deepEqual([...BYPASS_PERMISSIONS_BLOCK.allow], ["*"]);
|
|
110
|
+
assert.deepEqual([...BYPASS_PERMISSIONS_BLOCK.deny], []);
|
|
111
|
+
assert.ok(Object.isFrozen(BYPASS_PERMISSIONS_BLOCK));
|
|
112
|
+
});
|
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { execFileSync, spawn, spawnSync } from "node:child_process";
|
|
3
3
|
import { existsSync, mkdirSync, writeFileSync, cpSync, readFileSync, rmSync, readdirSync, appendFileSync, openSync, closeSync, chmodSync, statSync, realpathSync } from "node:fs";
|
|
4
4
|
import { registerSpecialistAgentsAt, SpecialistSymlinkCollision } from "./specialist-registration.js";
|
|
5
|
+
import { seedBypassPermissionsSettings, assertBypassPermissionsSeed } from "./permissions-seed.js";
|
|
5
6
|
import { resolve, join, dirname } from "node:path";
|
|
6
7
|
import { randomBytes } from "node:crypto";
|
|
7
8
|
import { resolveInstallPortFromFs, buildMaxyUnitFile, buildClaudeSessionManagerUnitFile, buildClaudePtysSliceUnitFile } from "./port-resolution.js";
|
|
@@ -953,6 +954,12 @@ function installClaudeCode() {
|
|
|
953
954
|
// pre-create the per-brand CLAUDE_CONFIG_DIR so the first
|
|
954
955
|
// `claude plugin marketplace add` has a directory to write into.
|
|
955
956
|
mkdirSync(CLAUDE_CONFIG_DIR, { recursive: true });
|
|
957
|
+
// Task 583 — seed the brand-scoped permissions block so claude.ai/code
|
|
958
|
+
// sessions short-circuit Stage 1 of the local matcher and never fall
|
|
959
|
+
// through to the Anthropic remote auto-classifier (which routes Agent
|
|
960
|
+
// dispatch to `ask` and surfaces a prompt no unattended operator clicks).
|
|
961
|
+
const permissionsSeed = seedBypassPermissionsSettings(CLAUDE_CONFIG_DIR);
|
|
962
|
+
logFile(`[install-permissions] action=${permissionsSeed.action} path=${permissionsSeed.path}`);
|
|
956
963
|
const marketplaceList = spawnSync("claude", ["plugin", "marketplace", "list"], { stdio: "pipe", encoding: "utf-8", env: claudePluginEnv() });
|
|
957
964
|
if (marketplaceList.stderr)
|
|
958
965
|
process.stderr.write(marketplaceList.stderr);
|
|
@@ -2053,6 +2060,12 @@ function registerLocalAndExternalPlugins() {
|
|
|
2053
2060
|
throw new Error(`Plugin registration incomplete: expected marketplaces ${JSON.stringify([...expectedMarketplaces])} but \`claude plugin marketplace list\` returned ${JSON.stringify(actualMarketplaces)}. Missing: ${JSON.stringify(missing)}. Check setup.log for [plugin-marketplace] ERROR lines.`);
|
|
2054
2061
|
}
|
|
2055
2062
|
logFile(`[plugin-marketplace] assertion-source=claude-plugin-marketplace-list count=${actualMarketplaces.length} marketplaces=${JSON.stringify(actualMarketplaces)} CLAUDE_CONFIG_DIR=${CLAUDE_CONFIG_DIR}`);
|
|
2063
|
+
// Task 583 — post-install assertion that the brand-scoped permissions
|
|
2064
|
+
// block survived install. Warn-only: a missing block does not abort the
|
|
2065
|
+
// install (consistent with the marketplace ERROR path that logs and
|
|
2066
|
+
// continues per-entry), but surfaces in setup.log for diagnosis.
|
|
2067
|
+
const permissionsAssert = assertBypassPermissionsSeed(CLAUDE_CONFIG_DIR);
|
|
2068
|
+
logFile(`[install-permissions] brand-settings=${permissionsAssert.status} path=${permissionsAssert.path}`);
|
|
2056
2069
|
}
|
|
2057
2070
|
function buildPlatform() {
|
|
2058
2071
|
log("9", TOTAL, "Installing dependencies and building...");
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// Task 583 — Seed Claude Code's two-stage permission classifier with a
|
|
2
|
+
// wildcard allow so claude.ai/code sessions never fall through to the
|
|
3
|
+
// Anthropic remote auto-classifier. The classifier routes `Agent`/`Task`
|
|
4
|
+
// to `ask`, which surfaces as a permission prompt that an unattended
|
|
5
|
+
// operator never clicks — observed as 4-minute dead-air hangs on
|
|
6
|
+
// realagent-code.
|
|
7
|
+
//
|
|
8
|
+
// This module is the single writer for the brand-scoped settings.json
|
|
9
|
+
// permissions block. Account-scoped settings.json is written by
|
|
10
|
+
// platform/scripts/setup-account.sh in lockstep with the same shape.
|
|
11
|
+
import { readFileSync, writeFileSync, renameSync, existsSync, mkdirSync } from "node:fs";
|
|
12
|
+
import { join, dirname } from "node:path";
|
|
13
|
+
export const BYPASS_PERMISSIONS_BLOCK = Object.freeze({
|
|
14
|
+
defaultMode: "bypassPermissions",
|
|
15
|
+
allow: ["*"],
|
|
16
|
+
deny: [],
|
|
17
|
+
});
|
|
18
|
+
function isAlreadyCorrect(permissions) {
|
|
19
|
+
if (!permissions || typeof permissions !== "object")
|
|
20
|
+
return false;
|
|
21
|
+
const p = permissions;
|
|
22
|
+
if (p.defaultMode !== "bypassPermissions")
|
|
23
|
+
return false;
|
|
24
|
+
if (!Array.isArray(p.allow) || !p.allow.includes("*"))
|
|
25
|
+
return false;
|
|
26
|
+
if (!Array.isArray(p.deny) || p.deny.length !== 0)
|
|
27
|
+
return false;
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
export function seedBypassPermissionsSettings(configDir) {
|
|
31
|
+
const settingsPath = join(configDir, "settings.json");
|
|
32
|
+
let existing = {};
|
|
33
|
+
if (existsSync(settingsPath)) {
|
|
34
|
+
const text = readFileSync(settingsPath, "utf-8");
|
|
35
|
+
if (text.trim().length > 0) {
|
|
36
|
+
try {
|
|
37
|
+
const parsed = JSON.parse(text);
|
|
38
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
39
|
+
existing = parsed;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// Malformed JSON: treat as empty and overwrite with a well-formed
|
|
44
|
+
// file containing only the permissions block. Any keys the prior
|
|
45
|
+
// file carried are unrecoverable from invalid JSON anyway.
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (isAlreadyCorrect(existing.permissions)) {
|
|
50
|
+
return { action: "noop", path: settingsPath };
|
|
51
|
+
}
|
|
52
|
+
mkdirSync(dirname(settingsPath), { recursive: true });
|
|
53
|
+
const merged = { ...existing, permissions: { ...BYPASS_PERMISSIONS_BLOCK, allow: [...BYPASS_PERMISSIONS_BLOCK.allow], deny: [] } };
|
|
54
|
+
const tmpPath = `${settingsPath}.task583.tmp`;
|
|
55
|
+
writeFileSync(tmpPath, JSON.stringify(merged, null, 2) + "\n");
|
|
56
|
+
renameSync(tmpPath, settingsPath);
|
|
57
|
+
return { action: "seeded", path: settingsPath };
|
|
58
|
+
}
|
|
59
|
+
export function assertBypassPermissionsSeed(configDir) {
|
|
60
|
+
const settingsPath = join(configDir, "settings.json");
|
|
61
|
+
if (!existsSync(settingsPath))
|
|
62
|
+
return { status: "missing", path: settingsPath };
|
|
63
|
+
let parsed;
|
|
64
|
+
try {
|
|
65
|
+
parsed = JSON.parse(readFileSync(settingsPath, "utf-8"));
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return { status: "missing", path: settingsPath };
|
|
69
|
+
}
|
|
70
|
+
if (!parsed || typeof parsed !== "object")
|
|
71
|
+
return { status: "missing", path: settingsPath };
|
|
72
|
+
const permissions = parsed.permissions;
|
|
73
|
+
return isAlreadyCorrect(permissions)
|
|
74
|
+
? { status: "ok", path: settingsPath }
|
|
75
|
+
: { status: "missing", path: settingsPath };
|
|
76
|
+
}
|
package/package.json
CHANGED
|
@@ -1969,7 +1969,7 @@ eagerTool(server, "skill-load", "Load a plugin skill's SKILL.md body by skill na
|
|
|
1969
1969
|
// sentinel that read like a successful render to the agent while the
|
|
1970
1970
|
// chat surface saw nothing. Admin flows now use plain markdown for
|
|
1971
1971
|
// reviewable artefacts and the `file-presentation` skill for downloadable
|
|
1972
|
-
// artefacts (
|
|
1972
|
+
// artefacts (written under output/ and delivered by stating their location).
|
|
1973
1973
|
// The :Component / :KnowledgeDocument
|
|
1974
1974
|
// persistence pipeline is preserved for historical conversations that
|
|
1975
1975
|
// already carry the rows; no new conversations write to it.
|