@backifydev/cli 0.2.1 → 0.2.2

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.
Files changed (3) hide show
  1. package/README.md +4 -2
  2. package/dist/index.js +67 -23
  3. package/package.json +3 -3
package/README.md CHANGED
@@ -13,6 +13,8 @@ npx @backifydev/cli login
13
13
 
14
14
  `init` installs `@backifydev/sdk`, writes `backify.json`, and maintains the Backify blocks in `AGENTS.md`, `CLAUDE.md`, and `.github/copilot-instructions.md`. It preserves other instructions in those files.
15
15
 
16
+ The app configuration stores `instructionVersion`, matching the version declared in each managed block and its immutable guide at `https://agent.backify.dev/v<number>`. The agent root always serves the latest guide as plain text. `doctor` detects version/content drift and malformed markers. Use `npx @backifydev/cli@latest sync` to explicitly upgrade all blocks and the configuration together; unrelated configuration and unmanaged instructions remain unchanged.
17
+
16
18
  You can start from an empty folder without a Git repository. `init` creates a minimal private `package.json` before installing the SDK, without choosing a framework. Add the application's framework and development/build scripts afterward. Existing manifests are preserved; in a non-empty application or monorepo, run `init` from the appropriate JavaScript/TypeScript package directory.
17
-
18
- See the [agent setup guide](https://docs.backify.dev/setup).
19
+
20
+ See the [agent setup guide](https://agent.backify.dev/).
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ import { basename, dirname, join, resolve } from "node:path";
14
14
  import { spawnSync } from "node:child_process";
15
15
 
16
16
  // ../platform/dist/index.js
17
- var INSTRUCTION_VERSION = 1;
17
+ var INSTRUCTION_VERSION = 2;
18
18
  var SDK_PACKAGE = "@backifydev/sdk";
19
19
  var DOCS_URL = "https://docs.backify.dev";
20
20
  var capability = (name, imp, description, stateful = false, provisioner = name) => ({ name, import: imp, version: 1, stateful, provisioner, docs: `${DOCS_URL}/capabilities/${name}`, description, destructiveRemovalRequiresApproval: stateful });
@@ -41,25 +41,62 @@ function managedInstructions() {
41
41
 
42
42
  # Backify Platform Instructions
43
43
 
44
- This application runs on Backify.
44
+ Instruction version: ${INSTRUCTION_VERSION}
45
+ Versioned guide: https://agent.backify.dev/v${INSTRUCTION_VERSION}
45
46
 
46
- Use \`@backifydev/sdk\` for application platform capabilities. Prefer Backify for authentication, database, storage, server functions, background and scheduled jobs, events, secrets, AI, external HTTP access, audit logging, application logging, and configuration.
47
+ ## Scope and platform policy
47
48
 
48
- Do not directly provision or integrate Azure, AWS, GCP, Supabase, Firebase, Auth0, database hosting, object storage, queues, schedulers, or infrastructure-as-code when an equivalent Backify capability exists.
49
+ This application runs on Backify. These rules govern application code targeting Backify, not the implementation of the Backify platform itself.
50
+ Use \`@backifydev/sdk\` for platform capabilities. Do not directly integrate or provision cloud infrastructure, hosted authentication, databases, storage, queues, or schedulers when an equivalent Backify capability exists. If a capability is missing, explain the gap and ask before adding an external platform dependency.
49
51
 
50
- The authoritative documentation is ${DOCS_URL}. If unsure, check it before adding an external platform dependency. Preserve all repository instructions outside this managed block.
52
+ ## SDK capability map
53
+
54
+ - Authentication and authorization: \`auth\`.
55
+ - Persistent data and files: \`db\` and \`storage\`.
56
+ - Server functions: \`defineFunction\`; background work and schedules: \`jobs\` and \`jobs.schedule\`.
57
+ - Events, outbound HTTP, and AI: \`events\`, \`http.fetch\`, and \`ai\`.
58
+ - Server-side secrets, configuration, audit, and logs: \`secrets\`, \`config\`, \`audit\`, and \`logs\`.
59
+
60
+ Verify API signatures against the installed SDK types and the relevant guide at ${DOCS_URL}/capabilities/. Never invent SDK methods. Use \`@backifydev/sdk/local\` for tests and local development; \`@backifydev/sdk/runtime\` is for runtime hosts, not application code.
61
+
62
+ ## Security and data safety
63
+
64
+ Keep secrets server-side. Never commit or log credentials, expose secrets to browser code, or place cloud-management credentials in applications. Enforce authorization in trusted server code and scope data access to the authenticated user or organization as required.
65
+ Scope cookies to the exact application hostname by omitting the \`Domain\` attribute. Never use a parent-domain cookie unless explicitly required.
66
+ Require explicit confirmation before destructive data operations or removing stateful resources. Removing a capability declaration does not authorize deleting its data.
67
+
68
+ ## Implementation workflow
69
+
70
+ Inspect the framework, lockfile, scripts, configuration, and applicable repository instructions before editing. Preserve the existing framework and unrelated work. Implement the requested application rather than stopping at SDK setup; ask what to build if requirements are missing.
71
+ Run relevant tests, typechecking, lint, and builds using the repository's scripts when available. Report changes, checks, and remaining blockers accurately; do not claim unverified success.
72
+
73
+ ## Instruction maintenance
74
+
75
+ The authoritative documentation is ${DOCS_URL}/. The root at https://agent.backify.dev/ always shows the latest guide; use the versioned guide above for this repository's installed instructions.
76
+ Keep \`backify.json\` \`instructionVersion\` aligned with this block. Run \`npx @backifydev/cli@latest doctor\` to check consistency and \`npx @backifydev/cli@latest sync\` to adopt a newer instruction version. Never silently upgrade instructions during an unrelated feature change.
77
+ Preserve all content outside this managed block and all more-specific repository instructions.
51
78
 
52
79
  ${MANAGED_END}`;
53
80
  }
81
+ function managedInstructionIssues(content) {
82
+ const normalized = content.replace(/\r\n/g, "\n"), starts = normalized.split(MANAGED_START).length - 1, ends = normalized.split(MANAGED_END).length - 1;
83
+ if (starts === 0 && ends === 0)
84
+ return ["does not contain Backify managed instructions"];
85
+ if (starts !== 1 || ends !== 1)
86
+ return ["contains duplicate or incomplete Backify managed markers"];
87
+ const start = normalized.indexOf(MANAGED_START), end = normalized.indexOf(MANAGED_END);
88
+ if (end < start)
89
+ return ["contains reversed Backify managed markers"];
90
+ return normalized.slice(start, end + MANAGED_END.length) === managedInstructions() ? [] : ["contains stale or inconsistent Backify managed instructions; run backify sync"];
91
+ }
54
92
  function updateManagedInstructions(content) {
93
+ const issues = managedInstructionIssues(content);
94
+ if (issues.some((issue) => issue.includes("markers")))
95
+ throw new Error(issues.join("; "));
55
96
  const block = managedInstructions(), start = content.indexOf(MANAGED_START), end = content.indexOf(MANAGED_END);
56
- if (start >= 0 && end >= start)
97
+ if (start >= 0)
57
98
  return content.slice(0, start) + block + content.slice(end + MANAGED_END.length);
58
- return content.trim() ? `${content.trimEnd()}
59
-
60
- ${block}
61
- ` : `${block}
62
- `;
99
+ return content.trim() ? content.trimEnd() + "\n\n" + block + "\n" : block + "\n";
63
100
  }
64
101
  function createConfig(appId) {
65
102
  return { $schema: `${DOCS_URL}/schema/backify.json`, platform: "backify", sdk: SDK_PACKAGE, appId, instructionVersion: INSTRUCTION_VERSION, docs: DOCS_URL, instructions: { preferBackifyCapabilities: true, allowDirectCloudInfrastructure: false } };
@@ -92,12 +129,25 @@ function detectPackageManager(root = process.cwd()) {
92
129
  return "npm";
93
130
  }
94
131
  function updateInstructions(root = process.cwd()) {
95
- for (const relative of instructionFiles) {
132
+ const updates = instructionFiles.map((relative) => {
96
133
  const path = join(root, relative);
134
+ return { path, content: updateManagedInstructions(existsSync(path) ? readFileSync(path, "utf8") : "") };
135
+ });
136
+ for (const { path, content } of updates) {
97
137
  mkdirSync(dirname(path), { recursive: true });
98
- writeFileSync(path, updateManagedInstructions(existsSync(path) ? readFileSync(path, "utf8") : ""));
138
+ writeFileSync(path, content);
99
139
  }
100
140
  }
141
+ function synchronize(root = process.cwd()) {
142
+ const path = join(root, "backify.json");
143
+ if (!existsSync(path)) throw new Error("backify.json is missing; run backify init --app app_xxxxx");
144
+ const value = JSON.parse(readFileSync(path, "utf8")), issues = validateConfig(value);
145
+ if (issues.length) throw new Error(issues.join("; "));
146
+ if (value.instructionVersion > INSTRUCTION_VERSION) throw new Error("This app uses newer instructions. Install a matching or newer CLI before syncing.");
147
+ updateInstructions(root);
148
+ value.instructionVersion = INSTRUCTION_VERSION;
149
+ writeFileSync(path, JSON.stringify(value, null, 2) + "\n");
150
+ }
101
151
  function writeConfig(appId, root = process.cwd()) {
102
152
  writeFileSync(join(root, "backify.json"), JSON.stringify(createConfig(appId), null, 2) + "\n");
103
153
  }
@@ -118,7 +168,7 @@ function ensurePackageManifest(root) {
118
168
  const path = join(root, "package.json");
119
169
  if (existsSync(path)) return;
120
170
  const setupFiles = /* @__PURE__ */ new Set([".git", ".gitignore", ".github", "AGENTS.md", "CLAUDE.md", "README.md", "LICENSE", "backify.json"]);
121
- if (readdirSync(root).some((file) => !setupFiles.has(file))) throw new Error("package.json is missing. Run backify init from the existing application's JavaScript/TypeScript package directory, or start in an empty folder. See https://docs.backify.dev/setup");
171
+ if (readdirSync(root).some((file) => !setupFiles.has(file))) throw new Error("package.json is missing. Run backify init from the existing application's JavaScript/TypeScript package directory, or start in an empty folder. See https://agent.backify.dev/");
122
172
  const name = basename(resolve(root)).toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "") || "backify-app";
123
173
  writeFileSync(path, JSON.stringify({ name, version: "0.0.0", private: true, type: "module" }, null, 2) + "\n", { flag: "wx" });
124
174
  }
@@ -139,15 +189,14 @@ function doctor(root = process.cwd()) {
139
189
  } catch {
140
190
  issues.push("backify.json is missing or invalid JSON");
141
191
  }
142
- if (config?.instructionVersion < INSTRUCTION_VERSION) warnings.push(`Repository instruction version ${config.instructionVersion}; current version ${INSTRUCTION_VERSION}. Run backify sync.`);
192
+ if (config && config.instructionVersion !== INSTRUCTION_VERSION) issues.push(`Repository instruction version ${config.instructionVersion}; CLI version ${INSTRUCTION_VERSION}. Use the matching CLI or run backify sync to upgrade.`);
143
193
  for (const relative of instructionFiles) {
144
194
  const path = join(root, relative);
145
195
  if (!existsSync(path)) {
146
196
  issues.push(`${relative} is missing`);
147
197
  continue;
148
198
  }
149
- const text = readFileSync(path, "utf8");
150
- if (!text.includes(MANAGED_START) || !text.includes(MANAGED_END)) issues.push(`${relative} does not contain Backify managed instructions`);
199
+ issues.push(...managedInstructionIssues(readFileSync(path, "utf8")).map((issue) => `${relative} ${issue}`));
151
200
  }
152
201
  let version = "unknown";
153
202
  try {
@@ -239,12 +288,7 @@ async function main() {
239
288
  console.log("Backify initialized. SDK, configuration, and agent instructions are ready.");
240
289
  break;
241
290
  case "sync": {
242
- const path = join2(process.cwd(), "backify.json");
243
- if (!existsSync2(path)) throw new Error("backify.json is missing; run backify init --app app_xxxxx");
244
- const value = JSON.parse(readFileSync2(path, "utf8"));
245
- value.instructionVersion = INSTRUCTION_VERSION;
246
- writeFileSync2(path, JSON.stringify(value, null, 2) + "\n");
247
- updateInstructions();
291
+ synchronize();
248
292
  console.log(`Backify instructions synchronized to version ${INSTRUCTION_VERSION}.`);
249
293
  break;
250
294
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backifydev/cli",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Command-line setup and diagnostics for Backify applications",
5
5
  "type": "module",
6
6
  "bin": { "backify": "dist/index.js" },
@@ -15,8 +15,8 @@
15
15
  "test": "vitest run"
16
16
  },
17
17
  "publishConfig": { "access": "public" },
18
- "repository": { "type": "git", "url": "git+https://github.com/frejnorling/backify.git", "directory": "packages/cli" },
19
- "homepage": "https://docs.backify.dev/setup",
18
+ "repository": { "type": "git", "url": "git+https://github.com/frejnorling/backify.git", "directory": "packages/cli" },
19
+ "homepage": "https://agent.backify.dev/",
20
20
  "license": "MIT",
21
21
  "engines": { "node": ">=20" },
22
22
  "devDependencies": {