Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "data-monorepo",
"version": "0.10.22",
"version": "0.10.23",
"private": true,
"engines": {
"node": ">=24"
Expand Down
2 changes: 1 addition & 1 deletion packages/data-ai/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "adobe-data-ai",
"version": "0.10.22",
"version": "0.10.23",
"description": "Architecture skills for @adobe/data — data-oriented modelling, archetype iteration, hot-path performance, and related conventions.",
"author": {
"name": "Adobe"
Expand Down
8 changes: 8 additions & 0 deletions packages/data-ai/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,14 @@ self-update**, editing your `package.json` and `.gitignore` to:
scripts, so a `postinstall` shipped inside the package would silently not fire;
3. gitignore the managed bundle folders.

Each managed folder also gets a short "externally managed — do not edit" notice so
an agent that opens it is warned before touching the regenerated files. The notice
follows your repo's instruction convention: it is written as `AGENTS.md` by default
(the cross-agent standard, which Claude Code also reads) and only as `CLAUDE.md` for a
repo that is still CLAUDE.md-only. `install` never drops a `CLAUDE.md` into a repo that
uses `AGENTS.md` — a stray `CLAUDE.md` anywhere makes Claude Code ignore every
`AGENTS.md` project-wide.

The copied files are regenerated artifacts — never committed, never edited in
place. The wiring is idempotent, so re-running is harmless; with `--global` or in a
directory with no `package.json`, `install` just copies (no wiring).
Expand Down
32 changes: 24 additions & 8 deletions packages/data-ai/bin/cli.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,13 @@ const { name: PKG_NAME, version: VERSION } = pkg;
// each agent root.
const BUNDLE = "adobe-data-ai";

// A do-not-edit notice dropped at each bundle root. Claude Code loads nested
// CLAUDE.md files when working in a subtree, so an agent that opens one of these
// folders sees the notice before touching anything. `extra` adds a pointer to
// the companion bundle.
// A do-not-edit notice dropped at each bundle root so an agent that opens one of
// these managed folders sees it before touching anything. The file is named for the
// project's instruction convention (see `noticeFilename`) — never unconditionally
// `CLAUDE.md`: Claude Code treats any CLAUDE.md in the tree as switching the whole
// project into CLAUDE.md mode and then ignores every AGENTS.md project-wide (observed
// on Claude Code 2.1.286), which would silently blank out instructions in an
// AGENTS.md-based repo. `extra` adds a pointer to the companion bundle.
function notice(extra) {
return `# Externally managed — do not edit

Expand All @@ -58,11 +61,23 @@ version, then reinstall — do not modify these files in place.
${extra ? `\n${extra}\n` : ""}`;
}

function writeMeta(bundleDir, noticeBody, extraMeta) {
writeFileSync(join(bundleDir, "CLAUDE.md"), noticeBody);
// Choose the managed notice's filename from the project's instruction convention.
// Preference is AGENTS.md (the cross-agent standard, which Claude Code also reads); we
// fall back to CLAUDE.md only for a repo still on the CLAUDE.md convention (a root
// CLAUDE.md and no AGENTS.md), so the notice keeps auto-loading there. An AGENTS.md
// repo (and a greenfield one) therefore never receives a data-ai CLAUDE.md — a stray
// CLAUDE.md anywhere flips Claude Code out of AGENTS.md mode for the whole project.
function noticeFilename(base) {
const hasClaude = existsSync(join(base, "CLAUDE.md"));
const hasAgents = existsSync(join(base, "AGENTS.md"));
return hasClaude && !hasAgents ? "CLAUDE.md" : "AGENTS.md";
}

function writeMeta(bundleDir, noticeBody, extraMeta, noticeFile) {
writeFileSync(join(bundleDir, noticeFile), noticeBody);
writeFileSync(
join(bundleDir, ".data-ai.json"),
JSON.stringify({ package: PKG_NAME, version: VERSION, ...extraMeta }, null, 2) + "\n",
JSON.stringify({ package: PKG_NAME, version: VERSION, notice: noticeFile, ...extraMeta }, null, 2) + "\n",
);
}

Expand Down Expand Up @@ -107,6 +122,7 @@ function installSkills(base, skills) {
bundleDir,
notice("The architecture rules these skills follow are installed at\n`.claude/rules/adobe-data-ai/` (referenced by name from each SKILL.md)."),
{ skills },
noticeFilename(base),
);
return bundleDir;
}
Expand All @@ -118,7 +134,7 @@ function installRules(base) {
// Copy the whole rules tree, minus the top-level README.md meta doc.
const readme = join(rulesSrc, "README.md");
cpSync(rulesSrc, bundleDir, { recursive: true, filter: (src) => src !== readme });
writeMeta(bundleDir, notice(), { rules: countRules(rulesSrc) });
writeMeta(bundleDir, notice(), { rules: countRules(rulesSrc) }, noticeFilename(base));
return bundleDir;
}

Expand Down
2 changes: 1 addition & 1 deletion packages/data-ai/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@adobe/data-ai",
"version": "0.10.22",
"version": "0.10.23",
"description": "Cross-agent architecture skills for @adobe/data — installable as a Claude Code plugin or copied into any Agent-Skills-compatible agent (Cursor, Codex).",
"type": "module",
"private": false,
Expand Down
68 changes: 68 additions & 0 deletions packages/data-ai/test/install.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// © 2026 Adobe. MIT License. See /LICENSE for details.
//
// The managed notice must follow the project's instruction convention. In
// particular it must NEVER drop a CLAUDE.md into an AGENTS.md repo: on Claude Code
// 2.1.286 any CLAUDE.md in the tree switches the whole project into CLAUDE.md mode
// and suppresses AGENTS.md discovery, blanking out the repo's instructions.

import { afterEach, beforeEach, describe, expect, it } from "vitest";
import { execFileSync } from "node:child_process";
import { existsSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";

const cli = join(dirname(fileURLToPath(import.meta.url)), "..", "bin", "cli.mjs");

function install(dir) {
execFileSync(process.execPath, [cli, "install", `--dir=${dir}`], { stdio: "pipe" });
}

// The two managed bundle folders that each receive a notice.
function bundleDirs(dir) {
return [
join(dir, ".claude", "rules", "adobe-data-ai"),
join(dir, ".agents", "skills", "adobe-data-ai"),
];
}

function expectNotice(dir, present, absent) {
for (const bundle of bundleDirs(dir)) {
expect(existsSync(join(bundle, present)), `${present} in ${bundle}`).toBe(true);
expect(existsSync(join(bundle, absent)), `${absent} in ${bundle}`).toBe(false);
}
}

describe("data-ai install — managed notice filename", () => {
let dir;
beforeEach(() => {
dir = mkdtempSync(join(tmpdir(), "data-ai-install-"));
});
afterEach(() => {
rmSync(dir, { recursive: true, force: true });
});

it("writes AGENTS.md (never CLAUDE.md) in an AGENTS.md repo", () => {
writeFileSync(join(dir, "AGENTS.md"), "# root instructions\n");
install(dir);
expectNotice(dir, "AGENTS.md", "CLAUDE.md");
});

it("writes CLAUDE.md in a CLAUDE.md-only repo so the notice still auto-loads", () => {
writeFileSync(join(dir, "CLAUDE.md"), "# root instructions\n");
install(dir);
expectNotice(dir, "CLAUDE.md", "AGENTS.md");
});

it("prefers AGENTS.md when neither marker exists (greenfield)", () => {
install(dir);
expectNotice(dir, "AGENTS.md", "CLAUDE.md");
});

it("prefers AGENTS.md when both markers exist (mid-migration)", () => {
writeFileSync(join(dir, "CLAUDE.md"), "# root instructions\n");
writeFileSync(join(dir, "AGENTS.md"), "# root instructions\n");
install(dir);
expectNotice(dir, "AGENTS.md", "CLAUDE.md");
});
});
2 changes: 1 addition & 1 deletion packages/data-gpu/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@adobe/data-gpu",
"version": "0.10.22",
"version": "0.10.23",
"description": "Adobe data WebGPU plugins and types for graphics and compute",
"type": "module",
"private": false,
Expand Down
2 changes: 1 addition & 1 deletion packages/data-lit/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@adobe/data-lit",
"version": "0.10.22",
"version": "0.10.23",
"description": "Adobe data Lit bindings - hooks, elements, decorators",
"type": "module",
"private": false,
Expand Down
2 changes: 1 addition & 1 deletion packages/data-persistence/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@adobe/data-persistence",
"version": "0.10.22",
"version": "0.10.23",
"description": "Worker-based incremental persistence layer for @adobe/data ECS over OPFS (browser) and node:fs (server).",
"type": "module",
"sideEffects": false,
Expand Down
2 changes: 1 addition & 1 deletion packages/data-react/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@adobe/data-react",
"version": "0.10.22",
"version": "0.10.23",
"description": "Adobe data React bindings — hooks and context for ECS database",
"type": "module",
"private": false,
Expand Down
6 changes: 3 additions & 3 deletions packages/data-rpc-iframe/src/shared/main-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ export namespace MainService {
properties: {
time: { type: "observe", value: { type: "number" } },
logs: { type: "observe", value: { type: "array", items: { type: "string" } } },
echo: { type: "function", signature: { parameters: [{ type: "string" }], returns: { type: "promise", value: { type: "string" } } } },
countUp: { type: "function", signature: { parameters: [{ type: "number" }], returns: { type: "generator", value: { type: "number" } } } },
log: { type: "function", signature: { parameters: [{ type: "string" }] } },
echo: { type: "function", signature: { parameters: [{ name: "arg0", schema: { type: "string" } }], returns: { type: "promise", value: { type: "string" } } } },
countUp: { type: "function", signature: { parameters: [{ name: "arg0", schema: { type: "number" } }], returns: { type: "generator", value: { type: "number" } } } },
log: { type: "function", signature: { parameters: [{ name: "arg0", schema: { type: "string" } }] } },
},
required: ["time", "logs", "echo", "countUp", "log"],
additionalProperties: false,
Expand Down
8 changes: 4 additions & 4 deletions packages/data-rpc-iframe/src/shared/sub-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ export namespace SubService {
properties: {
status: { type: "observe", value: { type: "string" } },
inbox: { type: "observe", value: { type: "array", items: { type: "string" } } },
echo: { type: "function", signature: { parameters: [{ type: "string" }], returns: { type: "promise", value: { type: "string" } } } },
countUp: { type: "function", signature: { parameters: [{ type: "number" }], returns: { type: "generator", value: { type: "number" } } } },
notify: { type: "function", signature: { parameters: [{ type: "string" }] } },
echo: { type: "function", signature: { parameters: [{ name: "arg0", schema: { type: "string" } }], returns: { type: "promise", value: { type: "string" } } } },
countUp: { type: "function", signature: { parameters: [{ name: "arg0", schema: { type: "number" } }], returns: { type: "generator", value: { type: "number" } } } },
notify: { type: "function", signature: { parameters: [{ name: "arg0", schema: { type: "string" } }] } },
calc: {
type: "object",
properties: {
total: { type: "observe", value: { type: "number" } },
add: { type: "function", signature: { parameters: [{ type: "number" }], returns: { type: "promise", value: { type: "number" } } } },
add: { type: "function", signature: { parameters: [{ name: "arg0", schema: { type: "number" } }], returns: { type: "promise", value: { type: "number" } } } },
reset: { type: "function" },
},
required: ["total", "add", "reset"],
Expand Down
2 changes: 1 addition & 1 deletion packages/data-rpc/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@adobe/data-rpc",
"version": "0.10.22",
"version": "0.10.23",
"description": "Schema-driven, bidirectional projection of @adobe/data async data services across a boundary (iframe / MessagePort / Worker). Only Data crosses the wire.",
"type": "module",
"sideEffects": false,
Expand Down
17 changes: 10 additions & 7 deletions packages/data-rpc/src/arg-async.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,21 @@ namespace AsyncArgService {
export const schema = {
type: "object",
properties: {
awaitAndDouble: { type: "function", signature: { parameters: [promiseNum], returns: promiseNum } },
sumStream: { type: "function", signature: { parameters: [genNum], returns: promiseNum } },
first: { type: "function", signature: { parameters: [genNum], returns: promiseNum } },
awaitAndDouble: { type: "function", signature: { parameters: [{ name: "arg0", schema: promiseNum }], returns: promiseNum } },
sumStream: { type: "function", signature: { parameters: [{ name: "arg0", schema: genNum }], returns: promiseNum } },
first: { type: "function", signature: { parameters: [{ name: "arg0", schema: genNum }], returns: promiseNum } },
combine: {
type: "function",
signature: {
parameters: [
{
type: "object",
properties: { label: { type: "promise", value: { type: "string" } }, nums: genNum },
required: ["label", "nums"],
additionalProperties: false,
name: "arg0",
schema: {
type: "object",
properties: { label: { type: "promise", value: { type: "string" } }, nums: genNum },
required: ["label", "nums"],
additionalProperties: false,
},
},
],
returns: { type: "promise", value: { type: "string" } },
Expand Down
15 changes: 9 additions & 6 deletions packages/data-rpc/src/arg-observe.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@ namespace DisplayService {
signature: {
parameters: [
{
type: "object",
properties: {
alpha: { type: "observe", value: { type: "number" } },
beta: { type: "observe", value: { type: "string" } },
name: "arg0",
schema: {
type: "object",
properties: {
alpha: { type: "observe", value: { type: "number" } },
beta: { type: "observe", value: { type: "string" } },
},
required: ["alpha", "beta"],
additionalProperties: false,
},
required: ["alpha", "beta"],
additionalProperties: false,
},
],
returns: { type: "observe", value: { type: "string" } },
Expand Down
2 changes: 1 addition & 1 deletion packages/data-rpc/src/consume/synthesize-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ function buildMembers(
const memberPath = [...path, key];
if (member.type === "observe" || member.type === "function") {
const kind = AsyncDataService.memberKind(member);
const params = member.signature?.parameters;
const params = member.signature?.parameters?.map((p) => p.schema);
switch (kind) {
case "observe":
out[key] = makeObserve(ctx, service, memberPath, []);
Expand Down
2 changes: 1 addition & 1 deletion packages/data-rpc/src/host/register-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ function resolve(
}
memberSchema = props[key];
}
const params = memberSchema.signature?.parameters;
const params = memberSchema.signature?.parameters?.map((p) => p.schema);
if (params !== undefined) {
const errors: string[] = [];
params.forEach((p, i) => {
Expand Down
6 changes: 3 additions & 3 deletions packages/data-rpc/src/nested.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ namespace ParentService {
type: "object",
properties: {
value: { type: "observe", value: { type: "number" } },
add: { type: "function", signature: { parameters: [{ type: "number" }, { type: "number" }], returns: { type: "promise", value: { type: "number" } } } },
stream: { type: "function", signature: { parameters: [{ type: "number" }], returns: { type: "generator", value: { type: "number" } } } },
add: { type: "function", signature: { parameters: [{ name: "arg0", schema: { type: "number" } }, { name: "arg1", schema: { type: "number" } }], returns: { type: "promise", value: { type: "number" } } } },
stream: { type: "function", signature: { parameters: [{ name: "arg0", schema: { type: "number" } }], returns: { type: "generator", value: { type: "number" } } } },
bump: { type: "function" },
deep: {
type: "object",
properties: {
greet: { type: "function", signature: { parameters: [{ type: "string" }], returns: { type: "promise", value: { type: "string" } } } },
greet: { type: "function", signature: { parameters: [{ name: "arg0", schema: { type: "string" } }], returns: { type: "promise", value: { type: "string" } } } },
},
required: ["greet"],
additionalProperties: false,
Expand Down
10 changes: 5 additions & 5 deletions packages/data-rpc/src/review-fixes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ interface IgnoreService extends Service {
const ignoreSchema = {
type: "object",
properties: {
ignoreArg: { type: "function", signature: { parameters: [{ type: "promise", value: { type: "number" } }], returns: { type: "promise" } } },
ignoreArg: { type: "function", signature: { parameters: [{ name: "arg0", schema: { type: "promise", value: { type: "number" } } }], returns: { type: "promise" } } },
},
required: ["ignoreArg"],
additionalProperties: false,
Expand Down Expand Up @@ -73,9 +73,9 @@ interface LateService extends Service {
const lateSchema = {
type: "object",
properties: {
lateAwait: { type: "function", signature: { parameters: [{ type: "promise", value: { type: "number" } }], returns: { type: "promise" } } },
lateAwait: { type: "function", signature: { parameters: [{ name: "arg0", schema: { type: "promise", value: { type: "number" } } }], returns: { type: "promise" } } },
result: { type: "observe", value: { type: "string" } },
lateDrain: { type: "function", signature: { parameters: [{ type: "generator", value: { type: "number" } }], returns: { type: "promise" } } },
lateDrain: { type: "function", signature: { parameters: [{ name: "arg0", schema: { type: "generator", value: { type: "number" } } }], returns: { type: "promise" } } },
drained: { type: "observe", value: { type: "string" } },
},
required: ["lateAwait", "result", "lateDrain", "drained"],
Expand Down Expand Up @@ -201,7 +201,7 @@ interface VoidArgService extends Service {
const voidArgSchema = {
type: "object",
properties: {
logObs: { type: "function", signature: { parameters: [{ type: "observe", value: { type: "number" } }] } },
logObs: { type: "function", signature: { parameters: [{ name: "arg0", schema: { type: "observe", value: { type: "number" } } }] } },
},
required: ["logObs"],
additionalProperties: false,
Expand Down Expand Up @@ -235,7 +235,7 @@ interface AwaitService extends Service {
const awaitSchema = {
type: "object",
properties: {
awaitIt: { type: "function", signature: { parameters: [{ type: "promise", value: { type: "number" } }], returns: { type: "promise", value: { type: "number" } } } },
awaitIt: { type: "function", signature: { parameters: [{ name: "arg0", schema: { type: "promise", value: { type: "number" } } }], returns: { type: "promise", value: { type: "number" } } } },
},
required: ["awaitIt"],
additionalProperties: false,
Expand Down
Loading
Loading