@bluestep-systems/bspecs 0.10.0
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 +129 -0
- package/cli.js +74 -0
- package/package.json +30 -0
- package/src/prompts.js +74 -0
- package/src/scaffold.js +152 -0
- package/src/sync.js +123 -0
- package/src/utils.js +95 -0
- package/templates/claude/agents/b6p-code-review.md +81 -0
- package/templates/claude/agents/b6p-commenter.md +59 -0
- package/templates/claude/agents/b6p-task-implementer.md +77 -0
- package/templates/claude/hooks/block-generated-files.sh +16 -0
- package/templates/claude/hooks/block-tsc.sh +16 -0
- package/templates/claude/hooks/prettier-on-save.sh +21 -0
- package/templates/claude/instructions/b6p-platform.md.template +185 -0
- package/templates/claude/instructions/bsjs-development.md.template +430 -0
- package/templates/claude/instructions/conventions/always-snapshot.md.template +25 -0
- package/templates/claude/instructions/conventions/blueiq-no-ai-branding.md.template +11 -0
- package/templates/claude/instructions/conventions/date-format.md.template +27 -0
- package/templates/claude/instructions/conventions/endpoint-approach.md.template +9 -0
- package/templates/claude/instructions/conventions/formula-patterns.md.template +71 -0
- package/templates/claude/instructions/conventions/no-global-dollar.md.template +9 -0
- package/templates/claude/instructions/conventions/push-inner-draft.md.template +21 -0
- package/templates/claude/instructions/conventions/separate-files.md.template +17 -0
- package/templates/claude/instructions/conventions/single-script.md.template +28 -0
- package/templates/claude/instructions/conventions/snapshot-integrity.md.template +23 -0
- package/templates/claude/instructions/conventions/top-level-const-tdz.md.template +33 -0
- package/templates/claude/instructions/conventions/ts-in-template-literal.md.template +48 -0
- package/templates/claude/instructions/conventions/tsc-rootdir.md.template +17 -0
- package/templates/claude/instructions/gotchas/common-gotchas.md.template +91 -0
- package/templates/claude/instructions/gotchas/fetched-resource-code.md.template +9 -0
- package/templates/claude/instructions/index.md.template +82 -0
- package/templates/claude/instructions/reference/api-patterns.md.template +487 -0
- package/templates/claude/instructions/reference/blueiq-credit-integration-playbook.md.template +31 -0
- package/templates/claude/instructions/reference/chronounit-months.md.template +37 -0
- package/templates/claude/instructions/reference/code-patterns.md.template +265 -0
- package/templates/claude/instructions/reference/component-library.md.template +217 -0
- package/templates/claude/instructions/reference/crm-dashboard-inspo.md.template +17 -0
- package/templates/claude/instructions/reference/csv-parsing.md.template +18 -0
- package/templates/claude/instructions/reference/dashboard-design-system.md.template +38 -0
- package/templates/claude/instructions/reference/datetime-field-write.md.template +27 -0
- package/templates/claude/instructions/reference/design-system.md.template +150 -0
- package/templates/claude/instructions/reference/dpn-dashboard-framework.md.template +29 -0
- package/templates/claude/instructions/reference/endpoint-method-call.md.template +10 -0
- package/templates/claude/instructions/reference/endpoint-no-delete-method.md.template +9 -0
- package/templates/claude/instructions/reference/endpoint-output-channel.md.template +23 -0
- package/templates/claude/instructions/reference/endpoint-urls.md.template +15 -0
- package/templates/claude/instructions/reference/entry-delete.md.template +40 -0
- package/templates/claude/instructions/reference/file-execution.md.template +113 -0
- package/templates/claude/instructions/reference/http-requester.md.template +37 -0
- package/templates/claude/instructions/reference/id-full-vs-short.md.template +15 -0
- package/templates/claude/instructions/reference/internal-loopback-fetch.md.template +24 -0
- package/templates/claude/instructions/reference/localdate-parse.md.template +16 -0
- package/templates/claude/instructions/reference/merge-report-memo-json.md.template +25 -0
- package/templates/claude/instructions/reference/merge-report-static-index.md.template +29 -0
- package/templates/claude/instructions/reference/merge-report-urls.md.template +67 -0
- package/templates/claude/instructions/reference/multi-entry-in-multi-entry.md.template +21 -0
- package/templates/claude/instructions/reference/named-controls-submit.md.template +11 -0
- package/templates/claude/instructions/reference/new-entry-id.md.template +30 -0
- package/templates/claude/instructions/reference/relationship-field-set.md.template +37 -0
- package/templates/claude/instructions/reference/send-message-abort.md.template +37 -0
- package/templates/claude/instructions/reference/session-cookie-forwarding.md.template +31 -0
- package/templates/claude/instructions/reference/singleselect-null-copy.md.template +21 -0
- package/templates/claude/instructions/reference/staff-query-permission-gating.md.template +27 -0
- package/templates/claude/instructions/reference/timefield-vs-datetimefield.md.template +13 -0
- package/templates/claude/instructions/reference/user-zone-id.md.template +16 -0
- package/templates/claude/settings.json.template +46 -0
- package/templates/claude/skills/b6p-audit/SKILL.md +82 -0
- package/templates/claude/skills/b6p-pull/SKILL.md +123 -0
- package/templates/claude/skills/b6p-push/SKILL.md +70 -0
- package/templates/claude/skills/bug-fix/SKILL.md +28 -0
- package/templates/claude/skills/spec-create/SKILL.md +60 -0
- package/templates/claude/skills/spec-execute/SKILL.md +51 -0
- package/templates/claude/skills/spec-status/SKILL.md +20 -0
- package/templates/claude/skills/task-comment/SKILL.md +96 -0
- package/templates/claude/spec-templates/design.template.md +36 -0
- package/templates/claude/spec-templates/requirements.template.md +26 -0
- package/templates/claude/spec-templates/tasks.template.md +37 -0
- package/templates/module/README.md.template +46 -0
- package/templates/root/.gitignore.template +14 -0
- package/templates/root/.prettierrc.template +8 -0
- package/templates/root/CLAUDE.md.template +157 -0
- package/templates/root/README.md.template +58 -0
- package/templates/root/package.json.template +15 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "BlueStep snapshots register cleanly only when push.js sends locally-compiled .build/* alongside source — otherwise the user has to re-snapshot manually"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
For BlueStep snapshots to register cleanly in the web UI without a manual re-snapshot, include the locally-compiled `.build/*.js` (and `.build/scripts/*.js`) files alongside the source `.ts`/`.html`/`.css` in the `saveState` that `push.js`'s `recordHistory` mutation records.
|
|
6
|
+
|
|
7
|
+
**Why:** `push.js`'s `buildSaveState(localFolder, files)` reads files from `walkDir`, which respects `SKIP_DIRS`. If `.build` is in `SKIP_DIRS`, the `saveState` is source-only. BlueStep's snapshot UI compares the recorded `saveState` against the live filesystem (which has `.build/*.js` from server-side compilation), sees a mismatch, and flags the snapshot as incomplete — surfaced to the user as the familiar "go re-snapshot manually" pattern. When `.build/` IS included, source ↔ compiled match, the snapshot finalizes cleanly, and there is no need to touch the BlueStep UI to finish the operation.
|
|
8
|
+
|
|
9
|
+
**How to apply:**
|
|
10
|
+
|
|
11
|
+
- `~/.bluestep/push.js`'s `SKIP_DIRS` MUST be `new Set(['declarations', 'info'])` — NOT `new Set(['.build', 'declarations', 'info'])`. (`declarations/` and `info/` are genuinely server-generated and should stay excluded; `.build/` is locally compiled and should be included.) Changed 2026-05-01.
|
|
12
|
+
- ALWAYS run `tsc` locally in each folder containing a `tsconfig.json` BEFORE invoking `push.js --snapshot`. Multi-tsconfig projects (e.g. root + `static/`) need a separate `tsc` per directory. Skipping the compile uploads a stale `.build/` that doesn't reflect current source, and the runtime silently diverges from what the snapshot's `.ts` says.
|
|
13
|
+
- A second, independent reason to compile locally: BlueStep's server-side TS recompile after a `.ts` push has been observed to be unreliable. Pushing the locally-compiled `.build/*.js` directly bypasses any server-side compile lag or failure (the `export {};` `SyntaxError` saga from 2026-05-01 was caused by exactly this).
|
|
14
|
+
- Verified empirically across many edits to `alpineacademy/1513841` and `1513859` (chatbot project) on 2026-05-01: with `.build/` included, every snapshot finalized cleanly in the BlueStep UI.
|
|
15
|
+
|
|
16
|
+
**The pattern in shorthand:**
|
|
17
|
+
|
|
18
|
+
1. Edit source.
|
|
19
|
+
2. `cd <folder-with-tsconfig> && tsc` (repeat for each tsconfig in the project).
|
|
20
|
+
3. `node ~/.bluestep/push.js --snapshot --comment "..." <folder>`.
|
|
21
|
+
4. Done. No BlueStep UI interaction needed.
|
|
22
|
+
|
|
23
|
+
Related: [always snapshot](always-snapshot.md), [tsc rootdir](tsc-rootdir.md), [push inner draft](push-inner-draft.md).
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "BlueStep endpoint/merge-report scripts run top-down — declare every const/let ABOVE the entry try block or they are in TDZ when the request handler fires"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
In BlueStep endpoint / merge-report scripts, declare every `const` and `let` ABOVE the top-level entry block (the `try { ... }` that runs the request handler). Do not interleave constants with helper functions further down the file.
|
|
6
|
+
|
|
7
|
+
**Why:** A typical BlueStep endpoint looks like:
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
const A = 1; // initialized
|
|
11
|
+
const B = "x"; // initialized
|
|
12
|
+
try { // runs synchronously at load time
|
|
13
|
+
handleChat(...); // → calls persistAuditTurn() → reads C
|
|
14
|
+
} catch (...) { ... }
|
|
15
|
+
|
|
16
|
+
function handleChat() { ... persistAuditTurn() ... }
|
|
17
|
+
function persistAuditTurn() { return { v: C }; } // C is read here
|
|
18
|
+
|
|
19
|
+
const C = 1; // ← TDZ: not yet initialized when handleChat ran above
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The function declarations hoist, so `handleChat` and `persistAuditTurn` are *callable* from the try block. But `const`/`let` initializations execute in source order. By the time `handleChat` runs (during the try block), any `const` below the try is still in its temporal dead zone — referencing it throws `ReferenceError: C is not defined` (BSJS surfaces this exact wording).
|
|
23
|
+
|
|
24
|
+
Hit on summitridge/1470299 audit-log endpoint, 2026-05-01: `AUDIT_DATA_VERSION` was declared next to `persistAuditTurn` (mid-file) instead of with the other top-of-file constants. Symptom: the assistant response succeeded but `auditError: AUDIT_DATA_VERSION is not defined`.
|
|
25
|
+
|
|
26
|
+
**How to apply:**
|
|
27
|
+
|
|
28
|
+
- Group all `const`/`let` declarations at the top of the file, above the entry `try { ... }` block — even ones that are conceptually "module-scoped helpers."
|
|
29
|
+
- Function declarations are fine wherever — they hoist with their body.
|
|
30
|
+
- If you must declare a constant near a related function for readability, inline its value at the call site instead, or wrap it in a getter `function VERSION() { return 1; }`.
|
|
31
|
+
- This isn't BlueStep-specific JS semantics — it's standard ES2015 TDZ. But it bites BlueStep specifically because the entry-point pattern is "top-of-file try block runs immediately on load," which is unusual outside this platform.
|
|
32
|
+
|
|
33
|
+
**Merge-report client-bundle variant (havenwoodacademy/1523600 claim generator, 2026-06-03):** The same trap applies in `static/script.ts` because the file initializes `let state: ClaimData = createEmptyState();` at top level. `createEmptyState` is a function declaration (hoisted), but anything its body reads must already be initialized. Putting `CLEARINGHOUSES` / `DEFAULT_CLEARINGHOUSE` ~1600 lines below the state initializer broke the whole merge report — the script threw `ReferenceError` at module load, the `#claim-app` div was never mounted, and the raw `dataJSON` memo field showed through underneath. Symptom: "the entire merge report is not there and I can see the raw json in the memo field." Fix: move any `const` referenced by `createEmptyState` (or anything else that runs at module load) ABOVE the `let state = createEmptyState()` line.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "BlueStep merge reports emit HTML+CSS+JS via a B.out template literal; the inline <script> inside that string must be plain JS — any TypeScript syntax ships verbatim to the browser and breaks parsing"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
BlueStep merge reports emit their entire frontend as a single template literal:
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
B.out = `
|
|
9
|
+
<style>...</style>
|
|
10
|
+
<div>...</div>
|
|
11
|
+
<script>
|
|
12
|
+
(function() {
|
|
13
|
+
// ← this code is a STRING; the TS compiler does NOT process it
|
|
14
|
+
})();
|
|
15
|
+
</script>
|
|
16
|
+
`;
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Use plain ES2015+ JavaScript only inside the template literal. The TypeScript compiler only processes code *outside* the literal. Anything between the opening backtick and closing backtick is treated as a plain string and shipped to the browser verbatim, so TS syntax there fails to parse as JavaScript.
|
|
20
|
+
|
|
21
|
+
**Common leaks that break the inline script:**
|
|
22
|
+
|
|
23
|
+
- Type annotations: `var parts: string[] = [];` → `:` is invalid in JS at that position → `SyntaxError`.
|
|
24
|
+
- `as` casts: `(x as any).foo` → invalid here.
|
|
25
|
+
- Generics: `Foo<T>` → parsed as a `<` comparison, then garbage.
|
|
26
|
+
- `interface`/`enum` declarations.
|
|
27
|
+
|
|
28
|
+
**Symptom:** the dashboard sits forever on the initial "Loading…" because the bootstrap script never executes. `tsc` passes clean because the *source* file's TS is valid. No console error from the fetch — it never started.
|
|
29
|
+
|
|
30
|
+
**How to apply:** When writing or editing the `B.out` template-literal block, keep the inline `<script>` JS-only — type your helper functions and outer code in TS all you want:
|
|
31
|
+
|
|
32
|
+
- No `: Type` annotations on variables or params.
|
|
33
|
+
- No `as Type` casts.
|
|
34
|
+
- No `interface`/`enum`/`type` declarations.
|
|
35
|
+
- Use `var` (or `let`/`const`) without type info.
|
|
36
|
+
- Be especially careful when porting helper code that was originally TS.
|
|
37
|
+
|
|
38
|
+
Quick lint after big edits:
|
|
39
|
+
|
|
40
|
+
```js
|
|
41
|
+
const inner = txt.slice(txt.indexOf('B.out = `'), txt.lastIndexOf('`;'));
|
|
42
|
+
[...inner.matchAll(/\b(var|let|const)\s+\w+\s*:\s*[A-Za-z\[\]<>{}|]+\s*=/g)];
|
|
43
|
+
// empty = clean; any match = a TS leak in the inline script
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Discovered 2026-05-20 on the RISES Dashboard merge report (`alpineacademy/1515299`): a `var parts: string[] = [];` in the Protocols Gantt code froze the entire dashboard.
|
|
47
|
+
|
|
48
|
+
Related: [single script](single-script.md) — BlueStep only compiles root `static/script.ts`, not subdirs. Merge reports inline their JS into `scripts/app.ts`'s string output instead — a different file but the same class of "TS doesn't process this content" problem.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Compile BlueStep endpoints with --rootDir . so output mirrors scripts/app.ts → .build/scripts/app.js; --rootDir ./scripts emits to .build/app.js which the runtime ignores"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
When compiling a BlueStep endpoint locally, use:
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
tsc --rootDir . --ignoreDeprecations 6.0 --skipLibCheck
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
NOT `tsc --rootDir ./scripts ...`.
|
|
12
|
+
|
|
13
|
+
**Why:** The BlueStep runtime loads `.build/scripts/app.js` (mirroring `scripts/app.ts`). With `--rootDir ./scripts`, tsc emits to `.build/app.js` (one level too high). The push succeeds and the snapshot succeeds, but the runtime keeps serving the old `.build/scripts/app.js`. Symptom: code edits appear to have no effect after pushing and snapshotting — silent staleness, no error, just wrong output.
|
|
14
|
+
|
|
15
|
+
**How to apply:** Always run tsc from the `draft/` folder with `--rootDir .` (or omit `rootDir` entirely — tsc infers it from `tsconfig`). After compile, verify `.build/scripts/app.js` was updated, not `.build/app.js`. If a stale `.build/app.js` orphan exists from a past mistake, it can be left in place — the runtime ignores it.
|
|
16
|
+
|
|
17
|
+
Confirmed on alpineacademy `/b/greatHair`, May 2026.
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Common Gotchas
|
|
2
|
+
|
|
3
|
+
A quick anti-pattern checklist for BlueStep.js. Each entry is the sharp edge plus a pointer to the file that owns the full pattern — scan it when debugging a silent failure or before writing new component code. The detailed patterns live in the linked reference files (reachable from `index.md`); this file is the warning list, not a second copy.
|
|
4
|
+
|
|
5
|
+
## Field access — Java optionals, not JS
|
|
6
|
+
|
|
7
|
+
JavaScript optional chaining (`?.`) does **not** work against Java optionals, and `field.val()` may throw when the field is empty. Use `field.opt().orElse(default)` (or `.opt().isPresent()` / `.get()`). Java collections (query results) have **no** `.filter` / `.map` — use `.forEach`, or convert to an array first.
|
|
8
|
+
|
|
9
|
+
→ Full optional and collection patterns: [api-patterns](../reference/api-patterns.md#working-with-java-optionals).
|
|
10
|
+
|
|
11
|
+
## Server vs client separation
|
|
12
|
+
|
|
13
|
+
`scripts/app.ts` runs on the server (has `B`, no DOM); `static/script.js` runs in the browser (has the DOM, no `B`). DOM access in server code, or `B` in client code, throws `not defined`. A file only runs if it is an automatic entry point or is explicitly imported — an unimported file never executes.
|
|
14
|
+
|
|
15
|
+
→ Full execution model and entry points: [file-execution](../reference/file-execution.md).
|
|
16
|
+
|
|
17
|
+
## Merge report HTML structure
|
|
18
|
+
|
|
19
|
+
A merge report's `static/index.html` is embedded into an existing page — never emit `<!DOCTYPE html>` / `<html>` / `<head>` / `<body>`, only the content plus `<link>` / `<script>` references. Use `<script type="module">` when the client script uses ES imports, or it throws `Cannot use import statement outside a module`.
|
|
20
|
+
|
|
21
|
+
→ Detail: [file-execution](../reference/file-execution.md#html-structure).
|
|
22
|
+
|
|
23
|
+
## Merge report script timing race
|
|
24
|
+
|
|
25
|
+
`DOMContentLoaded` fires *before* the inline `<script>` that `B.out` emits runs, so client code that reads a `window` global set by that inline script sees `undefined`. Push the value to a queue server-side and drain it from a lazy-init function client-side instead of relying on `DOMContentLoaded`.
|
|
26
|
+
|
|
27
|
+
→ Full queue / lazy-init pattern: [code-patterns](../reference/code-patterns.md#passing-per-row-data-queue--lazy-init-pattern).
|
|
28
|
+
|
|
29
|
+
## Query access
|
|
30
|
+
|
|
31
|
+
A query is only a top-level variable in `app.ts` if it is in the component's platform form-import config (regenerated into `declarations/index.d.ts` on pull); otherwise the variable is `not defined` — configure it on the platform and `b6p pull`. The hand-written `objects/imports.ts` registration is legacy and not used in current modules. For an ad-hoc, read-only query use `B.queries.byFID['fid'].query()`.
|
|
32
|
+
|
|
33
|
+
→ Full query patterns: [api-patterns](../reference/api-patterns.md#query-access-patterns), [file-execution](../reference/file-execution.md#query-access-pattern).
|
|
34
|
+
|
|
35
|
+
## Component library
|
|
36
|
+
|
|
37
|
+
Use the generic component library (`tableF`, `svgF`, …) instead of hand-writing HTML for tables, icons, and other components that already exist.
|
|
38
|
+
|
|
39
|
+
→ Catalog, registration, and the CSS anti-pattern: [component-library](../reference/component-library.md).
|
|
40
|
+
|
|
41
|
+
## SweetAlert2 Version Differences
|
|
42
|
+
|
|
43
|
+
⚠️ **We use SweetAlert2 v8.18.4, NOT v11.** Use the v8 API.
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
// ✅ Correct - v8.18.4 API
|
|
47
|
+
Swal.fire({
|
|
48
|
+
onOpen: () => { ... }, // v8 uses onOpen
|
|
49
|
+
// ...
|
|
50
|
+
}).then((result) => {
|
|
51
|
+
if (result.value) { ... } // v8 uses value
|
|
52
|
+
if (result.dismiss) { ... } // v8 uses dismiss for cancellation
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
<details>
|
|
57
|
+
<summary>SweetAlert2 v11 API — we do NOT use this (reference only)</summary>
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
// ❌ Wrong - v11 API (we don't use this version)
|
|
61
|
+
Swal.fire({
|
|
62
|
+
didOpen: () => { ... }, // v11 uses didOpen
|
|
63
|
+
// ...
|
|
64
|
+
}).then((result) => {
|
|
65
|
+
if (result.isConfirmed) { ... } // v11 uses isConfirmed
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
</details>
|
|
70
|
+
|
|
71
|
+
## NPM packages
|
|
72
|
+
|
|
73
|
+
Arbitrary npm packages are not available — use what the platform provides. Server-side: the `B` object and the Java standard library. Client-side: jQuery, Bootstrap, SweetAlert2 (v8), and the other libraries the platform already ships.
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
// ❌ Wrong - can't use arbitrary npm packages
|
|
77
|
+
import axios from 'axios';
|
|
78
|
+
import lodash from 'lodash';
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## TypeScript & Graal limits
|
|
82
|
+
|
|
83
|
+
`tsconfig.json` runs with `"strict": false`, so the compiler will not catch every null/type error — lean on `.opt().orElse()` and explicit annotations. Server-side runs on GraalVM (not Node), so avoid the newest ECMAScript proposals; test before relying on a new language feature.
|
|
84
|
+
|
|
85
|
+
→ tsconfig and Graal compatibility: [bsjs-development](../bsjs-development.md#typescript-configuration--graal-compatibility).
|
|
86
|
+
|
|
87
|
+
## Error handling
|
|
88
|
+
|
|
89
|
+
Always catch errors and surface a user-friendly message rather than letting the failure propagate silently.
|
|
90
|
+
|
|
91
|
+
→ Try-catch-with-feedback and validation patterns: [code-patterns](../reference/code-patterns.md#error-handling-patterns).
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Bluestep.Net.FetchedResource.code() returns 0 on success, not the upstream HTTP status — only code >= 400 reliably indicates failure"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
`Bluestep.Net.FetchedResource.code()` is documented in `declarations/B.d.ts` as "the response code," but in practice it returns `0` on successful API calls rather than the upstream HTTP status (200, etc.).
|
|
6
|
+
|
|
7
|
+
- **Rule:** only `code >= 400` reliably indicates failure. Treat anything else (0, 200, 2xx) as "trust the body."
|
|
8
|
+
- **Why:** detecting non-2xx with `code < 200 || code >= 300` synthesized a fake QBO `Fault` envelope on a valid 200 response, surfacing a bogus 422 "HandledError" to the caller.
|
|
9
|
+
- **How to apply:** branch on `code >= 400` only; for success/validation detection, inspect the parsed body (e.g. QBO returns `{ Fault: ... }` on HTTP 200 for validation errors), not the status code.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Manifest of on-demand BlueStep instruction files (reference/, conventions/, gotchas/) with a one-line "load when" trigger for each. Read first when a task needs platform or BsJs detail, to pick the right file.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# BlueStep Instruction Index
|
|
6
|
+
|
|
7
|
+
This is the navigation hub for the on-demand BlueStep rules. It is read when needed, not auto-loaded — Tier-1 critical rules stay in `CLAUDE.md`, and the Tier-2 overviews (`b6p-platform.md`, `bsjs-development.md`) cover the high-frequency platform and BsJs material. Consult an entry below when a task needs deeper, single-topic detail; each file is self-contained and is reached in one hop from here.
|
|
8
|
+
|
|
9
|
+
Entries read: `path — what it covers. Load when <trigger>.` Match the trigger keywords to the task at hand, then open that one file.
|
|
10
|
+
|
|
11
|
+
## reference/ — single-topic platform and API detail
|
|
12
|
+
|
|
13
|
+
- [reference/api-patterns.md](reference/api-patterns.md) — B API usage: Java optionals (`.opt()/.orElse()`), field types and access, `mergeTag()` L/F/I/H codes, multi-entry-form (MEF) entries, query access, Java collections, writing date/datetime fields, `B.commit()` and formula triggers, endpoint request/response, base64, user/session. Load when calling the `B` API, reading or writing fields, or wiring an endpoint's request/response.
|
|
14
|
+
- [reference/blueiq-credit-integration-playbook.md](reference/blueiq-credit-integration-playbook.md) — step-by-step playbook for wiring a new OpenAI/AI feature into the BlueIQ credit gate and ledger. Load when adding an AI feature that must consume BlueIQ credits.
|
|
15
|
+
- [reference/chronounit-months.md](reference/chronounit-months.md) — `ChronoUnit.MONTHS.between` counts elapsed (day-aware) months, not calendar-month boundaries. Load when computing a month difference or porting SQL `DATEDIFF(MONTH)`.
|
|
16
|
+
- [reference/code-patterns.md](reference/code-patterns.md) — working BsJs skeletons: queries, MergeReport server/client bridge, endpoints, error handling, performance (per-row queue, lazy init), component import, debugging. Load when starting a query, MergeReport, or endpoint and you want a known-good pattern.
|
|
17
|
+
- [reference/component-library.md](reference/component-library.md) — BlueStep generic components (`moduleF`, `headF`, `svgF`, `tableF`), Bootstrap 3.3.7 fallback, `config.json` registration with short import, CSS anti-pattern, and when not to use components. Load when building MergeReport UI or generating HTML.
|
|
18
|
+
- [reference/crm-dashboard-inspo.md](reference/crm-dashboard-inspo.md) — the CRM Intelligence Dashboard (`beh/1433876`), a 12-page sales SPA used as design inspiration. Load when designing a sales/CRM dashboard or the Behavioral Team Scorecard.
|
|
19
|
+
- [reference/csv-parsing.md](reference/csv-parsing.md) — MergeReports can read and parse uploaded CSVs via the built-in `B.csv()` parser plus DocumentLinkField/Document/fetch. Load when parsing an uploaded CSV in a MergeReport.
|
|
20
|
+
- [reference/dashboard-design-system.md](reference/dashboard-design-system.md) — the house design language (palette, type, cards, tabs) for dashboard MergeReports; do not use Material/rounded-tonal styling. Load when building any new dashboard UI.
|
|
21
|
+
- [reference/datetime-field-write.md](reference/datetime-field-write.md) — set a DateTimeField with `field.val(zonedDateTime)`; `.dateTimeVal()` has Graal-ambiguous overloads. Load when writing a DateTimeField.
|
|
22
|
+
- [reference/design-system.md](reference/design-system.md) — overview of the BlueStep Design System: component source priority, design standards, color palette, and the link to the interactive reference. Load when you need design standards or the canonical design-system URL.
|
|
23
|
+
- [reference/dpn-dashboard-framework.md](reference/dpn-dashboard-framework.md) — parameterized data-endpoint + dashboard framework: endpoint serves per-client/date-range JSON via URL params, dashboard fans out throttled parallel fetches. Load when building a client-fed analytics dashboard.
|
|
24
|
+
- [reference/endpoint-method-call.md](reference/endpoint-method-call.md) — `B.net.request.method` is a method (call it); without parens it type-checks but returns the Function. Load when reading the HTTP method inside an endpoint.
|
|
25
|
+
- [reference/endpoint-no-delete-method.md](reference/endpoint-no-delete-method.md) — endpoints don't route DELETE (or other non-GET/POST/PUT methods); use a PUT/POST action discriminator. Load when designing endpoint routing or a delete action.
|
|
26
|
+
- [reference/endpoint-output-channel.md](reference/endpoint-output-channel.md) — `/b/` endpoints write the body via `B.net.response.out()`, not `B.out` (the MergeReport channel, which yields a blank Error page). Load when an endpoint returns a blank or Error page.
|
|
27
|
+
- [reference/endpoint-urls.md](reference/endpoint-urls.md) — endpoints are reached at `/b/<alias>`, not the `/files/{id}/draft/` path; the alias is per-endpoint. Load when testing an endpoint or giving a user its URL.
|
|
28
|
+
- [reference/entry-delete.md](reference/entry-delete.md) — delete a multi-entry-form entry with `entry.entry().delete()`, not `entry.delete()` (the outer typed declaration lies). Load when deleting an MEF entry.
|
|
29
|
+
- [reference/file-execution.md](reference/file-execution.md) — which files execute and when: `scripts/app.ts` (server) vs `static/index.html` (client), Workspace Sync, common mistakes. Load when a file isn't running or you're unsure of the server/client split.
|
|
30
|
+
- [reference/http-requester.md](reference/http-requester.md) — method names on `B.net.httpRequester` (`.method()`, `.responseCode()`) use overloaded getter/setter style, not Java-bean `.setMethod`/`.getResponseCode`. Load when making a non-GET external HTTP call.
|
|
31
|
+
- [reference/id-full-vs-short.md](reference/id-full-vs-short.md) — `Id.toString()` is the full `ClassID___ShortID`; `shortId()` is just the trailing number; `optById` needs the full form. Load when round-tripping an entry id or calling `optById`.
|
|
32
|
+
- [reference/internal-loopback-fetch.md](reference/internal-loopback-fetch.md) — endpoint-to-endpoint loopback within an org uses `B.net.fetch` on a relative path with `credentials:true`, not the external `httpRequester`. Load when one endpoint calls another in the same org.
|
|
33
|
+
- [reference/localdate-parse.md](reference/localdate-parse.md) — `Java.Time.LocalDate` is a TypeScript namespace only; use `B.time.LocalDate` for runtime `parse()`/`now()`. Load when parsing or creating a LocalDate.
|
|
34
|
+
- [reference/merge-report-memo-json.md](reference/merge-report-memo-json.md) — the "MergeReport + memo field JSON" framework: embed a custom interactive widget on a form that persists its state as JSON in a hidden memo field. Load when building a stateful custom widget on a form.
|
|
35
|
+
- [reference/merge-report-static-index.md](reference/merge-report-static-index.md) — with a `static/` bundle, `static/index.html` is the page and `app.ts` `B.out` is NOT injected; put the mount + config island in `index.html` and run the client on `DOMContentLoaded`. Load when a MergeReport has a `static/` bundle.
|
|
36
|
+
- [reference/merge-report-urls.md](reference/merge-report-urls.md) — BSJS equivalents of relatescript `lookupMergeReport`/`lookupMergeReportScript`, and how to get `viewUrl`/`printUrl`. Load when looking up a MergeReport URL in code.
|
|
37
|
+
- [reference/multi-entry-in-multi-entry.md](reference/multi-entry-in-multi-entry.md) — the "multi entry in a multi entry" pattern: many notes/updates against one MEF entry, stored as JSON in one memo field. Load when users need repeated sub-entries under a single form entry.
|
|
38
|
+
- [reference/named-controls-submit.md](reference/named-controls-submit.md) — any HTML control with a `name` attribute inside a MergeReport form gets submitted and breaks the save. Load when adding form controls to a MergeReport settings UI.
|
|
39
|
+
- [reference/new-entry-id.md](reference/new-entry-id.md) — pre-commit `shortId()` returns `"0"` (`id.isValid()` is false); commit before reading a new entry's id. Load when reading the id of a freshly-created entry.
|
|
40
|
+
- [reference/relationship-field-set.md](reference/relationship-field-set.md) — `RelationshipField.set()` needs the target form-entry id, not a Record id, or the formula silently aborts; watch for `as any` casts hiding the bug. Load when setting a RelationshipField.
|
|
41
|
+
- [reference/send-message-abort.md](reference/send-message-abort.md) — `B.net.sendMessage(msg, abort)` aborts saves, but in pre-delete formulas the message does not surface in the UI. Load when aborting a save or delete from a formula.
|
|
42
|
+
- [reference/session-cookie-forwarding.md](reference/session-cookie-forwarding.md) — `request.cookies()` filters HttpOnly cookies; use `optHeader("Cookie")` to grab `JSESSIONID` for authenticated loopback calls. Load when forwarding the session cookie to a loopback call.
|
|
43
|
+
- [reference/singleselect-null-copy.md](reference/singleselect-null-copy.md) — copying an empty SingleSelectField via `val(other.val())` throws `set(null.id())`; guard with `opt().isPresent()`/`clear()`. Load when copying a SingleSelectField value.
|
|
44
|
+
- [reference/staff-query-permission-gating.md](reference/staff-query-permission-gating.md) — permission-gating concept: match the current user to a staff record via a query, read a per-staff SingleSelect permission, emit capability flags (fail-closed, super-user override). Load when gating a MergeReport UI by per-user permission.
|
|
45
|
+
- [reference/timefield-vs-datetimefield.md](reference/timefield-vs-datetimefield.md) — `zonedDateTimeParts` works on a DateTimeField (ZonedDateTime); for a TimeField (LocalTime) use a separate `HH:mm` extractor. Load when extracting parts from a TimeField vs a DateTimeField.
|
|
46
|
+
- [reference/user-zone-id.md](reference/user-zone-id.md) — `B.time.userZoneId()` returns the user/system ZoneId; `B.userZoneId()` does not type-check. Load when getting the user or system time zone.
|
|
47
|
+
|
|
48
|
+
## conventions/ — build, deploy, and workflow directives
|
|
49
|
+
|
|
50
|
+
- [conventions/always-snapshot.md](conventions/always-snapshot.md) — pull/push/snapshot workflow: use the CLI scripts (never fetch manually) and snapshot after every change via push → pull → snapshot. Load when syncing a component or unsure of the snapshot routine.
|
|
51
|
+
- [conventions/blueiq-no-ai-branding.md](conventions/blueiq-no-ai-branding.md) — never put "AI" in front-facing BlueIQ text; the brand is always "BlueIQ". Load when writing user-visible BlueIQ copy.
|
|
52
|
+
- [conventions/date-format.md](conventions/date-format.md) — `addSearch` needs `MM/DD/YYYY` for date fields; `YYYY/MM/DD` passes validation but silently fails to filter, and raw Java `LocalDate` objects also fail. Load when filtering a query by a date field.
|
|
53
|
+
- [conventions/endpoint-approach.md](conventions/endpoint-approach.md) — research-first: gather API docs, read type declarations, and study existing examples before writing an endpoint. Load when starting a new endpoint.
|
|
54
|
+
- [conventions/formula-patterns.md](conventions/formula-patterns.md) — correct BSJS formula patterns: form access, field reads/writes, HTTP, error handling, `B.*` utilities, DocumentLinkField. Load when writing a Formula or Post-Save script.
|
|
55
|
+
- [conventions/no-global-dollar.md](conventions/no-global-dollar.md) — never define a global `$` in MergeReport scripts; pages use jQuery and you will silently break Save and all page interactivity. Load when adding client JS to a MergeReport.
|
|
56
|
+
- [conventions/push-inner-draft.md](conventions/push-inner-draft.md) — pass the inner `draft/` folder (not the component root) to `push.js`, or files land in a `draft/draft/*` dead zone. Load when pushing a component with `push.js`.
|
|
57
|
+
- [conventions/separate-files.md](conventions/separate-files.md) — don't pile CSS/HTML/JS into `app.ts`; use the `styles.css`/`index.html`/`script.ts` files the pulled folder already has. Load when structuring MergeReport files.
|
|
58
|
+
- [conventions/single-script.md](conventions/single-script.md) — the server-side build compiles only root `static/script.ts` to `.build/script.js`; subdirectory `.ts` files are NOT compiled. Load when splitting client scripts into multiple files.
|
|
59
|
+
- [conventions/snapshot-integrity.md](conventions/snapshot-integrity.md) — snapshots register cleanly only when `push.js` sends locally-compiled `.build/*` alongside source, otherwise a manual re-snapshot is needed. Load when a push leaves the snapshot needing manual re-registration.
|
|
60
|
+
- [conventions/top-level-const-tdz.md](conventions/top-level-const-tdz.md) — endpoint/MergeReport scripts run top-down; declare every `const`/`let` above the entry `try` block or they are in TDZ when the handler fires. Load when ordering declarations in an endpoint or MergeReport.
|
|
61
|
+
- [conventions/ts-in-template-literal.md](conventions/ts-in-template-literal.md) — the inline `<script>` inside a `B.out` template literal must be plain JS; any TypeScript syntax ships verbatim to the browser and breaks parsing. Load when emitting client JS through a `B.out` string.
|
|
62
|
+
- [conventions/tsc-rootdir.md](conventions/tsc-rootdir.md) — compile endpoints with `--rootDir .` so output mirrors `scripts/app.ts` → `.build/scripts/app.js`; `--rootDir ./scripts` emits to `.build/app.js`, which the runtime ignores. Load when configuring the local TypeScript build for an endpoint.
|
|
63
|
+
|
|
64
|
+
## gotchas/ — sharp edges
|
|
65
|
+
|
|
66
|
+
- [gotchas/common-gotchas.md](gotchas/common-gotchas.md) — anti-pattern roundup: Java optionals vs JS null checks, Java collections vs JS arrays, server/client separation, MergeReport HTML structure, SweetAlert2 v8 vs v11, ES feature limits, strict mode, query access, script-timing race. Load when debugging a silent failure or before writing new component code.
|
|
67
|
+
- [gotchas/fetched-resource-code.md](gotchas/fetched-resource-code.md) — `FetchedResource.code()` returns `0` on success, not the upstream HTTP status; only `code >= 400` reliably indicates failure. Load when checking the result of a fetched resource.
|
|
68
|
+
|
|
69
|
+
## Term-level discovery
|
|
70
|
+
|
|
71
|
+
When no entry above matches, grep the tree for the exact symbol or term:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
grep -ri "<term>" .claude/instructions/
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Unresolved conflicts
|
|
78
|
+
|
|
79
|
+
Cross-source disagreements left for human resolution. Each is flagged inline with a `<!-- CONFLICT: … -->` comment at the point of disagreement; grep with `grep -rn "CONFLICT" .claude/instructions/`.
|
|
80
|
+
|
|
81
|
+
- [reference/api-patterns.md](reference/api-patterns.md) — client-ID field key: `sysId` (01-Platform-Reference) vs `systemID` (bluestep-knowledge merge-report examples). May be form/org-specific; needs confirmation of the canonical key.
|
|
82
|
+
- [b6p-platform.md](b6p-platform.md) — `U######` identity: treated here as the Unit folder created by `b6p pull` vs. Brandon's platform-overview labeling it the Organization's own ID.
|