@ibgib/web-gib 0.0.23 → 0.0.25
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/AUTO-GENERATED-version.d.mts +14 -0
- package/dist/AUTO-GENERATED-version.d.mts.map +1 -0
- package/dist/AUTO-GENERATED-version.mjs +14 -0
- package/dist/AUTO-GENERATED-version.mjs.map +1 -0
- package/package.json +4 -1
- package/src/AUTO-GENERATED-version.mts +14 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-add-core-engine/SKILL.md +81 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-add-core-engine/generate-id.js +9 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-add-core-engine/templates/bootstrap.mts.template +58 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-add-core-engine/templates/constants.mts.template +75 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-add-core-engine/templates/declarations.d.ts.template +9 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-add-core-engine/templates/helpers.web.mts.template +199 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-add-core-engine/templates/index.html.template +65 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-add-core-engine/templates/index.mts.template +61 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-add-core-engine/templates/types.mts.template +128 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-create-app-witness/SKILL.md +59 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-create-app-witness/templates/api/function-infos.web.mts.template +11 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-create-app-witness/templates/witness/app/app-v1.mts.template +124 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-create-app-witness/templates/witness/app/constants.mts.template +48 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-create-app-witness/templates/witness/app/helper.mts.template +72 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-create-app-witness/templates/witness/app/types.mts.template +38 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-create-component/SKILL.md +36 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-create-component/templates/components/component-name/component.css.template +26 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-create-component/templates/components/component-name/component.html.template +6 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-create-component/templates/components/component-name/component.mts.template +131 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-create-shell/SKILL.md +34 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-create-shell/templates/ui/shell/shell-constants.mts.template +10 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-create-shell/templates/ui/shell/shell-service.mts.template +139 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-create-shell/templates/ui/shell/shell-types.mts.template +6 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-enum-pattern/SKILL.md +153 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-get-pattern/SKILL.md +92 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-scaffold-app/SKILL.md +42 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-targeted-refactoring/SKILL.md +84 -0
- package/tools/auto-generated-agent-skills/skills/ibgib-targeted-refactoring/generate-id.js +9 -0
- package/tools/copy-agent-skills.js +51 -0
- package/{generate-version-file.js → tools/generate-version-file.js} +1 -1
- package/tools/init-agents.js +28 -14
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import thisCss from "./{{COMPONENT_NAME}}.css";
|
|
2
|
+
import thisHtml from "./{{COMPONENT_NAME}}.html";
|
|
3
|
+
|
|
4
|
+
import { extractErrorMsg } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
|
|
5
|
+
import { IbGibAddr } from "@ibgib/ts-gib/dist/types.mjs";
|
|
6
|
+
import { IbGib_V1 } from "@ibgib/ts-gib/dist/V1/types.mjs";
|
|
7
|
+
import { getIbGibAddr } from "@ibgib/ts-gib/dist/helper.mjs";
|
|
8
|
+
|
|
9
|
+
import { getComponentCtorArg } from "../../helpers.web.mjs";
|
|
10
|
+
import {
|
|
11
|
+
IbGibDynamicComponentMetaBase, IbGibDynamicComponentInstanceBase,
|
|
12
|
+
} from "@ibgib/web-gib/dist/ui/component/ibgib-dynamic-component-bases.mjs";
|
|
13
|
+
import {
|
|
14
|
+
ElementsBase, IbGibDynamicComponentInstance,
|
|
15
|
+
IbGibDynamicComponentInstanceInitOpts,
|
|
16
|
+
} from "@ibgib/web-gib/dist/ui/component/component-types.mjs";
|
|
17
|
+
|
|
18
|
+
export const {{COMPONENT_NAME_UPPER}}_COMPONENT_NAME = '{{COMPONENT_TAG_NAME}}';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Metadata for the {{COMPONENT_CLASS_PREFIX}} component.
|
|
22
|
+
* Handles custom element registration and instance creation.
|
|
23
|
+
*/
|
|
24
|
+
export class {{COMPONENT_CLASS_PREFIX}}ComponentMeta extends IbGibDynamicComponentMetaBase {
|
|
25
|
+
protected lc: string = `[{{COMPONENT_CLASS_PREFIX}}ComponentMeta]`;
|
|
26
|
+
|
|
27
|
+
routeRegExp?: RegExp = new RegExp(`^${ {{COMPONENT_NAME_UPPER}}_COMPONENT_NAME }$`);
|
|
28
|
+
componentName = {{COMPONENT_NAME_UPPER}}_COMPONENT_NAME;
|
|
29
|
+
|
|
30
|
+
constructor() {
|
|
31
|
+
super(getComponentCtorArg());
|
|
32
|
+
customElements.define(this.componentName, {{COMPONENT_CLASS_PREFIX}}ComponentInstance);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async createInstance({
|
|
36
|
+
path,
|
|
37
|
+
ibGibAddr
|
|
38
|
+
}: {
|
|
39
|
+
path: string;
|
|
40
|
+
ibGibAddr: IbGibAddr;
|
|
41
|
+
}): Promise<IbGibDynamicComponentInstance> {
|
|
42
|
+
const lc = `${this.lc}[${this.createInstance.name}]`;
|
|
43
|
+
const component = document.createElement(this.componentName) as {{COMPONENT_CLASS_PREFIX}}ComponentInstance;
|
|
44
|
+
await component.initialize({
|
|
45
|
+
ibGibAddr,
|
|
46
|
+
meta: this,
|
|
47
|
+
html: thisHtml,
|
|
48
|
+
css: [thisCss],
|
|
49
|
+
});
|
|
50
|
+
return component;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* References to DOM elements within the component's shadow root.
|
|
56
|
+
*/
|
|
57
|
+
interface {{COMPONENT_CLASS_PREFIX}}Elements extends ElementsBase {
|
|
58
|
+
containerEl: HTMLDivElement;
|
|
59
|
+
titleEl: HTMLHeadingElement;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Concrete implementation of the {{COMPONENT_CLASS_PREFIX}} component.
|
|
64
|
+
* Manages its own internal state and reacts to ibGib timeline updates.
|
|
65
|
+
*/
|
|
66
|
+
export class {{COMPONENT_CLASS_PREFIX}}ComponentInstance
|
|
67
|
+
extends IbGibDynamicComponentInstanceBase<IbGib_V1, {{COMPONENT_CLASS_PREFIX}}Elements>
|
|
68
|
+
implements IbGibDynamicComponentInstance<IbGib_V1, {{COMPONENT_CLASS_PREFIX}}Elements> {
|
|
69
|
+
|
|
70
|
+
protected lc: string = `[{{COMPONENT_CLASS_PREFIX}}ComponentInstance]`;
|
|
71
|
+
|
|
72
|
+
constructor() {
|
|
73
|
+
super();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
override async initialize(opts: IbGibDynamicComponentInstanceInitOpts): Promise<void> {
|
|
77
|
+
await super.initialize(opts);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
override async disconnected(): Promise<void> {
|
|
81
|
+
// Called when the element is removed from the DOM.
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Called when the element is added to the DOM.
|
|
86
|
+
* Use this to query elements and attach event listeners.
|
|
87
|
+
*/
|
|
88
|
+
override async created(): Promise<void> {
|
|
89
|
+
this.elements = {} as {{COMPONENT_CLASS_PREFIX}}Elements;
|
|
90
|
+
if (!this.elements) { throw new Error(`(UNEXPECTED) this.elements falsy? (E: genuuid)`); }
|
|
91
|
+
|
|
92
|
+
// Map shadow root elements
|
|
93
|
+
this.elements.containerEl = this.shadowRoot!.getElementById('container') as HTMLDivElement;
|
|
94
|
+
this.elements.titleEl = this.shadowRoot!.getElementById('title') as HTMLHeadingElement;
|
|
95
|
+
|
|
96
|
+
this.initHandlers();
|
|
97
|
+
|
|
98
|
+
if (this.ibGibAddr && !this.ibGib) {
|
|
99
|
+
await this.loadIbGib();
|
|
100
|
+
}
|
|
101
|
+
await this.renderUI();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private initHandlers() {
|
|
105
|
+
if (!this.elements) { throw new Error(`(UNEXPECTED) this.elements falsy? (E: genuuid)`); }
|
|
106
|
+
// Attach listeners here
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Updates the UI based on the current state of this.ibGib.
|
|
111
|
+
*/
|
|
112
|
+
protected override async renderUI(): Promise<void> {
|
|
113
|
+
const lc = `${this.lc}[${this.renderUI.name}]`;
|
|
114
|
+
if (!this.ibGib || !this.elements) return;
|
|
115
|
+
|
|
116
|
+
try {
|
|
117
|
+
this.elements.titleEl.textContent = `IbGib Component: ${this.ibGib.ib}`;
|
|
118
|
+
} catch (error) {
|
|
119
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Automatically called by the framework when the ibGib timeline updates.
|
|
125
|
+
*/
|
|
126
|
+
override async handleContextUpdated(): Promise<void> {
|
|
127
|
+
const lc = `${this.lc}[${this.handleContextUpdated.name}]`;
|
|
128
|
+
if (logalot) { console.log(`${lc} timeline updated.`); }
|
|
129
|
+
await this.renderUI();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ibgib-create-shell
|
|
3
|
+
description: Scaffolds the foundational UI Shell for an ibgib app. Generates the shell service, constants, and types required for UI management and component registration.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# ibgib-create-shell
|
|
7
|
+
|
|
8
|
+
This skill scaffolds the UI Shell architecture for an ibgib application. The Shell Service acts as a singleton on `globalThis` that manages DOM interactions, handles shell-specific events, and registers UI components with the `ibgib-component-service`.
|
|
9
|
+
|
|
10
|
+
## Goal
|
|
11
|
+
To provide a clean, decoupled foundation for application-level UI management, including the `onEngineReady` lifecycle hook called by the bootstrap process.
|
|
12
|
+
|
|
13
|
+
## Parameters
|
|
14
|
+
Wait for the user to provide or confirm these tokens:
|
|
15
|
+
- `{{APP_NAME}}`: e.g. `test-app`
|
|
16
|
+
- `{{APP_DIR_NAME}}`: e.g. `test-app`
|
|
17
|
+
- `{{APP_CLASSNAME_PREFIX}}`: e.g. `TestApp`
|
|
18
|
+
- `{{APP_CLASSNAME}}`: e.g. `TestAppApp_V1`
|
|
19
|
+
- `{{APP_HUMAN_NAME}}`: e.g. `Test App`
|
|
20
|
+
- `{{APP_VAR_NAME}}`: e.g. `testApp` (used for singleton naming)
|
|
21
|
+
|
|
22
|
+
## Output Files
|
|
23
|
+
The skill will generate:
|
|
24
|
+
1. `src/ui/shell/{{APP_DIR_NAME}}-shell-service.mts`
|
|
25
|
+
2. `src/ui/shell/{{APP_DIR_NAME}}-shell-constants.mts`
|
|
26
|
+
3. `src/ui/shell/{{APP_DIR_NAME}}-shell-types.mts`
|
|
27
|
+
|
|
28
|
+
## Usage Instructions
|
|
29
|
+
1. Ensure the `src/ui/shell` directory exists or the tool will create it.
|
|
30
|
+
2. Generate the three files from templates.
|
|
31
|
+
3. Update `src/bootstrap.mts` to import and call `get{{APP_CLASSNAME_PREFIX}}ShellSvc().onEngineReady()` in the `execFromArgs` function.
|
|
32
|
+
|
|
33
|
+
## Integration Note
|
|
34
|
+
The shell service provides an `onEngineReady()` hook. This is where you should put logic to "activate" the UI once the ibgib metaspace and app witness are fully initialized.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DOM Element IDs for the shell.
|
|
3
|
+
*/
|
|
4
|
+
export const ID_SHELL_CONTAINER = 'ibgib-shell-container';
|
|
5
|
+
export const ID_APP_ROOT = 'app-root';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Custom event names for shell-level communication.
|
|
9
|
+
*/
|
|
10
|
+
export const EVENT_SHELL_READY = 'ibgib-shell-ready';
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { extractErrorMsg } from "@ibgib/helper-gib/dist/helpers/utils-helper.mjs";
|
|
2
|
+
import { getComponentSvc } from "@ibgib/web-gib/dist/ui/component/ibgib-component-service.mjs";
|
|
3
|
+
import { IbGibDynamicComponentMeta } from "@ibgib/web-gib/dist/ui/component/component-types.mjs";
|
|
4
|
+
import { getIbGibAddr } from "@ibgib/ts-gib/dist/helper.mjs";
|
|
5
|
+
|
|
6
|
+
import { APP_CONFIG } from "../../constants.mjs";
|
|
7
|
+
import { getIbGibGlobalThis_{{APP_CLASSNAME_PREFIX}} } from "../../helpers.web.mjs";
|
|
8
|
+
import {
|
|
9
|
+
ID_SHELL_CONTAINER,
|
|
10
|
+
EVENT_SHELL_READY,
|
|
11
|
+
} from "./{{APP_DIR_NAME}}-shell-constants.mjs";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Singleton service for managing the {{APP_HUMAN_NAME}} UI shell.
|
|
15
|
+
* Coordinates component registration and high-level DOM interactions.
|
|
16
|
+
*/
|
|
17
|
+
export class {{APP_CLASSNAME_PREFIX}}ShellService {
|
|
18
|
+
private lc: string = `[{{APP_CLASSNAME_PREFIX}}ShellService]`;
|
|
19
|
+
|
|
20
|
+
// Elements
|
|
21
|
+
private shellContainer: HTMLElement | null = null;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Promise that resolves when the shell service has completed its
|
|
25
|
+
* asynchronous initialization (e.g. component registration).
|
|
26
|
+
*/
|
|
27
|
+
public initialized: Promise<void>;
|
|
28
|
+
|
|
29
|
+
constructor() {
|
|
30
|
+
this.initialized = this.initialize();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Orchestrates the synchronous and asynchronous initialization of the shell.
|
|
35
|
+
*/
|
|
36
|
+
private async initialize(): Promise<void> {
|
|
37
|
+
this.initElements();
|
|
38
|
+
this.initEventHandlers();
|
|
39
|
+
await this.registerComponents();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Registers application-specific components with the global component service.
|
|
44
|
+
*/
|
|
45
|
+
private async registerComponents(): Promise<void> {
|
|
46
|
+
const lc = `${this.lc}[${this.registerComponents.name}]`;
|
|
47
|
+
try {
|
|
48
|
+
const componentsMeta: IbGibDynamicComponentMeta[] = [
|
|
49
|
+
// Add your component metas here, e.g.:
|
|
50
|
+
// new MyAwesomeComponentMeta(),
|
|
51
|
+
];
|
|
52
|
+
const componentSvc = await getComponentSvc();
|
|
53
|
+
for (let componentMeta of componentsMeta) {
|
|
54
|
+
componentSvc.registerComponentMeta(componentMeta);
|
|
55
|
+
}
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
58
|
+
throw error;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private initElements(): void {
|
|
63
|
+
const lc = `${this.lc}[${this.initElements.name}]`;
|
|
64
|
+
try {
|
|
65
|
+
// Placeholder: this.shellContainer = document.getElementById(ID_SHELL_CONTAINER);
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private initEventHandlers(): void {
|
|
72
|
+
const lc = `${this.lc}[${this.initEventHandlers.name}]`;
|
|
73
|
+
try {
|
|
74
|
+
// Register global or shell-level event listeners here.
|
|
75
|
+
} catch (error) {
|
|
76
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Called by `bootstrap.mts` when the ibGib engine and metaspace are ready.
|
|
82
|
+
* Use this to reveal or activate interactive UI elements.
|
|
83
|
+
*/
|
|
84
|
+
public async onEngineReady(): Promise<void> {
|
|
85
|
+
const lc = `${this.lc}[${this.onEngineReady.name}]`;
|
|
86
|
+
try {
|
|
87
|
+
await this.initialized;
|
|
88
|
+
console.log(`${lc} {{APP_HUMAN_NAME}} Shell Service is ready.`);
|
|
89
|
+
|
|
90
|
+
// 1. Get the app context from global state
|
|
91
|
+
const ibGibGlobalThis = getIbGibGlobalThis_{{APP_CLASSNAME_PREFIX}}(APP_CONFIG);
|
|
92
|
+
const appIbGib = ibGibGlobalThis.initialCommentIbGib;
|
|
93
|
+
if (!appIbGib) {
|
|
94
|
+
throw new Error(`initialCommentIbGib not found on globalThis.`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// 2. Get the main component instance
|
|
98
|
+
const componentSvc = await getComponentSvc();
|
|
99
|
+
const component = await componentSvc.getComponentInstance({
|
|
100
|
+
path: '{{APP_DIR_NAME}}-main',
|
|
101
|
+
ibGibAddr: getIbGibAddr({ ibGib: appIbGib }),
|
|
102
|
+
useRegExpPrefilter: true,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
if (!component) {
|
|
106
|
+
throw new Error(`Failed to get component instance for app.`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// 3. Inject into the DOM
|
|
110
|
+
const appRoot = document.getElementById(ID_APP_ROOT);
|
|
111
|
+
if (appRoot) {
|
|
112
|
+
appRoot.innerHTML = ''; // Clear loading message
|
|
113
|
+
appRoot.appendChild(component as any);
|
|
114
|
+
} else {
|
|
115
|
+
console.warn(`${lc} #${ID_APP_ROOT} not found in DOM.`);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
window.dispatchEvent(new CustomEvent(EVENT_SHELL_READY));
|
|
119
|
+
} catch (error) {
|
|
120
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Returns the singleton instance of the Shell Service, initializing it on
|
|
127
|
+
* globalThis if necessary.
|
|
128
|
+
*/
|
|
129
|
+
export function get{{APP_CLASSNAME_PREFIX}}ShellSvc(): {{APP_CLASSNAME_PREFIX}}ShellService {
|
|
130
|
+
const lc = `[get{{APP_CLASSNAME_PREFIX}}ShellSvc]`;
|
|
131
|
+
const ibGibGlobalThis = getIbGibGlobalThis_{{APP_CLASSNAME_PREFIX}}(APP_CONFIG);
|
|
132
|
+
if (!ibGibGlobalThis.{{APP_VAR_NAME}}ShellSvc) {
|
|
133
|
+
if (typeof (console) !== 'undefined') {
|
|
134
|
+
console.log(`${lc} initializing {{APP_CLASSNAME_PREFIX}}ShellService singleton on globalThis... (I: genuuid)`);
|
|
135
|
+
}
|
|
136
|
+
ibGibGlobalThis.{{APP_VAR_NAME}}ShellSvc = new {{APP_CLASSNAME_PREFIX}}ShellService();
|
|
137
|
+
}
|
|
138
|
+
return ibGibGlobalThis.{{APP_VAR_NAME}}ShellSvc;
|
|
139
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: TypeScript enum pattern used in this codebase
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Ibgib Enum Pattern Skill
|
|
6
|
+
|
|
7
|
+
This codebase **never** uses TypeScript's built-in `enum` keyword (it has
|
|
8
|
+
problematic runtime semantics and poor tree-shaking). Instead, use the
|
|
9
|
+
following pattern for every enum-like type.
|
|
10
|
+
|
|
11
|
+
## When to use
|
|
12
|
+
|
|
13
|
+
- Three or more related string (or occasionally number) constants.
|
|
14
|
+
- The values are part of a discriminated union or are validated at runtime.
|
|
15
|
+
- A simple `'a' | 'b' | 'c'` union is fine for small, stable sets; promote
|
|
16
|
+
to the full pattern once the set starts to branch out or needs a guard/validator.
|
|
17
|
+
|
|
18
|
+
## Full pattern
|
|
19
|
+
|
|
20
|
+
```typescript
|
|
21
|
+
// #region MyEnum enum
|
|
22
|
+
|
|
23
|
+
// 1. One exported const per value.
|
|
24
|
+
// - Name: SCREAMING_SNAKE_CASE PREFIX_MEMBER
|
|
25
|
+
// - Value: kebab-case string literal
|
|
26
|
+
// - Hyphens in values → underscores in const names.
|
|
27
|
+
export const MY_ENUM_FOO_BAR = 'foo-bar';
|
|
28
|
+
export const MY_ENUM_BAZ = 'baz';
|
|
29
|
+
|
|
30
|
+
// 2. Union type — use typeof references so renaming a const propagates.
|
|
31
|
+
/**
|
|
32
|
+
* JSDoc describing the enum's purpose.
|
|
33
|
+
*/
|
|
34
|
+
export type MyEnum =
|
|
35
|
+
| typeof MY_ENUM_FOO_BAR
|
|
36
|
+
| typeof MY_ENUM_BAZ
|
|
37
|
+
;
|
|
38
|
+
|
|
39
|
+
// 3. Const enum object — keys are camelCase/underscore versions of the values
|
|
40
|
+
// (replace hyphens with underscores in the key).
|
|
41
|
+
// Satisfies the union type so TypeScript catches typos at declaration time.
|
|
42
|
+
export const MyEnum = {
|
|
43
|
+
/** Doc for foo-bar member. */
|
|
44
|
+
foo_bar: MY_ENUM_FOO_BAR,
|
|
45
|
+
/** Doc for baz member. */
|
|
46
|
+
baz: MY_ENUM_BAZ,
|
|
47
|
+
} satisfies { readonly [key: string]: MyEnum };
|
|
48
|
+
|
|
49
|
+
// 4. Valid-values array (derived from the object — stays in sync automatically).
|
|
50
|
+
export const MY_ENUM_VALID_VALUES: MyEnum[] = Object.values(MyEnum);
|
|
51
|
+
|
|
52
|
+
// 5. Type guard.
|
|
53
|
+
export function isMyEnum(value: any): value is MyEnum {
|
|
54
|
+
return MY_ENUM_VALID_VALUES.includes(value);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// #endregion MyEnum enum
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Consuming the enum
|
|
61
|
+
|
|
62
|
+
Callers should reference values via the **const object**, not the individual string constants:
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
// ✅ preferred — readable, refactor-safe
|
|
66
|
+
switch (strategy) {
|
|
67
|
+
case ParseMechanicalStrategy.markdown_heading: return splitByHeadings(text);
|
|
68
|
+
case ParseMechanicalStrategy.markdown_paragraph: return splitByParagraph(text);
|
|
69
|
+
case ParseMechanicalStrategy.custom_regexp: return splitByRegexp(text, opts.regexp);
|
|
70
|
+
default: throw new Error(`(UNEXPECTED) unhandled strategy: '${strategy}'`);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ⚠️ acceptable when the constant itself is needed (e.g. error messages, assertions)
|
|
74
|
+
if (strategy === PARSE_MECHANICAL_STRATEGY_CUSTOM_REGEXP && !opts.regexp) {
|
|
75
|
+
throw new Error(`strategy is '${PARSE_MECHANICAL_STRATEGY_CUSTOM_REGEXP}' but regexp is falsy`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ❌ avoid — brittle string literals scattered through call sites
|
|
79
|
+
if (strategy === 'markdown-heading') { ... }
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Rules
|
|
83
|
+
|
|
84
|
+
| Rule | Detail |
|
|
85
|
+
|---|---|
|
|
86
|
+
| **No `enum` keyword** | Use the pattern above. `enum` has footguns (reverse mapping, ambient vs const, isolatedModules). |
|
|
87
|
+
| **Kebab-case values** | String values use kebab-case (`'foo-bar'`). |
|
|
88
|
+
| **Const names** | `PREFIX_MEMBER` in SCREAMING_SNAKE_CASE; hyphens in value → underscores in name. |
|
|
89
|
+
| **Object keys** | Match the value with hyphens replaced by underscores (`foo_bar`). |
|
|
90
|
+
| **`satisfies`** | Always use `satisfies { readonly [key: string]: MyEnum }` on the const object. |
|
|
91
|
+
| **Start simple** | A plain string-literal union (`'foo-bar' | 'baz'`) is fine until the set grows or needs a guard. Promote to the full pattern at that point. |
|
|
92
|
+
| **`_VALID_VALUES`** | Always derive from `Object.values(MyEnum)`, never hardcode. |
|
|
93
|
+
| **Type guard** | Implement `isMyEnum` via `VALID_VALUES.includes(value)`. |
|
|
94
|
+
|
|
95
|
+
## Region comments
|
|
96
|
+
|
|
97
|
+
Wrap the entire block in:
|
|
98
|
+
```typescript
|
|
99
|
+
// #region MyEnum enum
|
|
100
|
+
// ...
|
|
101
|
+
// #endregion MyEnum enum
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Example from codebase
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
// #region ChromeAIAvailability enum
|
|
108
|
+
export const CHROME_AI_AVAILABILITY_UNAVAILABLE = 'unavailable';
|
|
109
|
+
export const CHROME_AI_AVAILABILITY_DOWNLOADABLE = 'downloadable';
|
|
110
|
+
export const CHROME_AI_AVAILABILITY_DOWNLOADING = 'downloading';
|
|
111
|
+
export const CHROME_AI_AVAILABILITY_AVAILABLE = 'available';
|
|
112
|
+
|
|
113
|
+
export type ChromeAIAvailability =
|
|
114
|
+
| typeof CHROME_AI_AVAILABILITY_UNAVAILABLE
|
|
115
|
+
| typeof CHROME_AI_AVAILABILITY_DOWNLOADABLE
|
|
116
|
+
| typeof CHROME_AI_AVAILABILITY_DOWNLOADING
|
|
117
|
+
| typeof CHROME_AI_AVAILABILITY_AVAILABLE
|
|
118
|
+
;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* The availability of a Chrome AI API.
|
|
122
|
+
*
|
|
123
|
+
* @see https://developer.chrome.com/docs/ai/built-in
|
|
124
|
+
*/
|
|
125
|
+
export const ChromeAIAvailability = {
|
|
126
|
+
/**
|
|
127
|
+
* The user's device or requested session options are not supported.
|
|
128
|
+
* The device may have insufficient power or disk space.
|
|
129
|
+
*/
|
|
130
|
+
unavailable: CHROME_AI_AVAILABILITY_UNAVAILABLE,
|
|
131
|
+
/**
|
|
132
|
+
* Additional downloads are needed to create a session, which may include
|
|
133
|
+
* an expert model, a language model, or fine-tuning. User activation may
|
|
134
|
+
* be required to call create().
|
|
135
|
+
*/
|
|
136
|
+
downloadable: CHROME_AI_AVAILABILITY_DOWNLOADABLE,
|
|
137
|
+
/**
|
|
138
|
+
* Downloads are ongoing and must complete before you can use a a session.
|
|
139
|
+
*/
|
|
140
|
+
downloading: CHROME_AI_AVAILABILITY_DOWNLOADING,
|
|
141
|
+
/**
|
|
142
|
+
* You can create a session immediately.
|
|
143
|
+
*/
|
|
144
|
+
available: CHROME_AI_AVAILABILITY_AVAILABLE,
|
|
145
|
+
} satisfies { readonly [key: string]: ChromeAIAvailability; };
|
|
146
|
+
|
|
147
|
+
export const CHROME_AI_AVAILABILITY_VALID_VALUES: ChromeAIAvailability[] = Object.values(ChromeAIAvailability);
|
|
148
|
+
|
|
149
|
+
export function isChromeAIAvailability(value: any): value is ChromeAIAvailability {
|
|
150
|
+
return CHROME_AI_AVAILABILITY_VALID_VALUES.includes(value);
|
|
151
|
+
}
|
|
152
|
+
// #endregion ChromeAIAvailability enum
|
|
153
|
+
```
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Patterns for robustly getting IbGibs from spaces
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# IbGib Get Pattern Skill
|
|
6
|
+
|
|
7
|
+
This skill documents the standard pattern for retrieving IbGib objects from a space. Use this pattern to ensure robust error handling, consistent logging, and correct space interaction.
|
|
8
|
+
|
|
9
|
+
## When to Use
|
|
10
|
+
|
|
11
|
+
- Whenever you need to `get` one or more IbGibs by their address(es).
|
|
12
|
+
|
|
13
|
+
## Core Pattern: try..catch..finally
|
|
14
|
+
|
|
15
|
+
Always wrap retrieval logic in a `try..catch..finally` block to ensure errors are logged and execution state is finalized correctly.
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
const lc = `[${myFunctionName.name}]`;
|
|
19
|
+
try {
|
|
20
|
+
if (logalot) { console.log(`${lc} starting... (I: genuuid)`); }
|
|
21
|
+
|
|
22
|
+
// ... retrieval logic ...
|
|
23
|
+
|
|
24
|
+
} catch (error) {
|
|
25
|
+
console.error(`${lc} ${extractErrorMsg(error)}`);
|
|
26
|
+
throw error;
|
|
27
|
+
} finally {
|
|
28
|
+
if (logalot) { console.log(`${lc} complete.`); }
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Space Retrieval Helpers
|
|
33
|
+
|
|
34
|
+
### Option A: Using `metaspace.get` (Preferred)
|
|
35
|
+
|
|
36
|
+
Use this when you have access to a `MetaspaceService` (It is often appropriate to provide a fallback to the default local user space, which is what the metaspace provides.)
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
// Ensure space is provided or fallback to local user space
|
|
40
|
+
space ??= await metaspace.getLocalUserSpace({ lock: false });
|
|
41
|
+
if (!space) {
|
|
42
|
+
throw new Error(`(UNEXPECTED) space falsy and we couldn't get default local user space from metaspace? (E: genuuid)`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const resGet = await metaspace.get({ addrs, space });
|
|
46
|
+
|
|
47
|
+
// Validate result
|
|
48
|
+
if (resGet.success && resGet.ibGibs && resGet.ibGibs.length === addrs.length) {
|
|
49
|
+
return resGet.ibGibs;
|
|
50
|
+
} else {
|
|
51
|
+
// Robust error handling using rawResultIbGib
|
|
52
|
+
const resIbGib = resGet.rawResultIbGib as IbGibSpaceResultIbGib<IbGib_V1, IbGibSpaceResultData, IbGibSpaceResultRel8ns>;
|
|
53
|
+
const addrsNotFound = resIbGib?.data?.addrsNotFound ?? 'unknown';
|
|
54
|
+
throw new Error(`couldn't find all addrs. addrsNotFound: ${addrsNotFound}? resGet.errorMsg: ${resGet.errorMsg} (E: genuuid)`);
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Option B: Using `getFromSpace` (Lower Level)
|
|
59
|
+
|
|
60
|
+
Use this when `metaspace` is not available, or when working in low-level helpers.
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import { getFromSpace } from "@ibgib/core-gib/dist/witness/space/space-helper.mjs";
|
|
64
|
+
|
|
65
|
+
// ... inside try block ...
|
|
66
|
+
const resGet = await getFromSpace({ space, addrs });
|
|
67
|
+
|
|
68
|
+
if (resGet.success && resGet.ibGibs?.length === addrs.length) {
|
|
69
|
+
return resGet.ibGibs!;
|
|
70
|
+
} else {
|
|
71
|
+
// Examine rawResultIbGib for more context
|
|
72
|
+
const resIbGib = resGet.rawResultIbGib as IbGibSpaceResultIbGib<IbGib_V1, IbGibSpaceResultData, IbGibSpaceResultRel8ns>;
|
|
73
|
+
if (!resIbGib?.data) {
|
|
74
|
+
throw new Error(`(UNEXPECTED) resGet.rawResultIbGib.data falsy? (E: genuuid)`);
|
|
75
|
+
}
|
|
76
|
+
throw new Error(`(UNEXPECTED) couldn't find addrs? addrsNotFound: ${resIbGib.data.addrsNotFound}? space.ib: ${space.ib} (E: genuuid)`);
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Key Requirements
|
|
81
|
+
|
|
82
|
+
| Requirement | Detail |
|
|
83
|
+
|---|---|
|
|
84
|
+
| **Logging** | Define `const lc = \`[\${fn.name}]\`;\` at the start. Log starting/finishing if `logalot` is true. |
|
|
85
|
+
| **Error Handling** | Use `extractErrorMsg(error)` in the catch block. Re-throw after logging. |
|
|
86
|
+
| **Result Validation** | Always check `resGet.success` AND that the returned `ibGibs` array matches the expected length. |
|
|
87
|
+
| **Debugging Context** | When a fetch fails, cast `resGet.rawResultIbGib` to `IbGibSpaceResultIbGib` and include `addrsNotFound` in the error message. |
|
|
88
|
+
| **Space Fallback** | When using `metaspace`, consider falling back to `metaspace.getLocalUserSpace({ lock: false })` if no space is provided. |
|
|
89
|
+
|
|
90
|
+
## Real-World Example
|
|
91
|
+
|
|
92
|
+
See `apps/learning/src/common/parse/parse-helper.mts` -> `fetchLayer` for the reference implementation of this pattern.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ibgib-scaffold-app
|
|
3
|
+
description: The master coordinator skill for scaffolding a complete "Hello World" ibgib application. Orchestrates sub-skills for core engine, app witness, and UI shell.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# ibgib-scaffold-app
|
|
7
|
+
|
|
8
|
+
This is a Meta-Skill that coordinates multiple sub-skills to create a functional, buildable ibgib application from scratch (Greenfield) or to add ibgib to an existing project (Brownfield).
|
|
9
|
+
|
|
10
|
+
## Goal
|
|
11
|
+
To orchestrate the modular sub-skills so the final application is type-safe, buildable, and consistent.
|
|
12
|
+
|
|
13
|
+
## Sub-Skills
|
|
14
|
+
This coordinator uses:
|
|
15
|
+
1. `ibgib-add-core-engine`: FOUNDATION (Bootstrap, Global State, Types).
|
|
16
|
+
2. `ibgib-create-app-witness`: LOGIC (App Witness class, commands, helpers).
|
|
17
|
+
3. `ibgib-create-shell`: UI (Shell service, event handlers).
|
|
18
|
+
4. `ibgib-create-component`: COMPONENT (Initial main app component - optional but recommended).
|
|
19
|
+
|
|
20
|
+
## Parameters (Shared State)
|
|
21
|
+
The agent must generate and maintain these tokens across sub-skill executions:
|
|
22
|
+
- `{{APP_NAME}}`: kebab-case (e.g. `test-app`)
|
|
23
|
+
- `{{APP_DIR_NAME}}`: folder name (e.g. `test-app`)
|
|
24
|
+
- `{{APP_CLASSNAME_PREFIX}}`: PascalCase (e.g. `TestApp`)
|
|
25
|
+
- `{{APP_CLASSNAME}}`: Full class name (e.g. `TestAppApp_V1`)
|
|
26
|
+
- `{{APP_HUMAN_NAME}}`: Natural language (e.g. `Test App`)
|
|
27
|
+
- `{{APP_VAR_NAME}}`: camelCase (e.g. `testApp`)
|
|
28
|
+
- `{{APP_NAME_UPPER}}`: SCREAMING_SNAKE_CASE (e.g. `TEST_APP`)
|
|
29
|
+
|
|
30
|
+
## Workflow for Greenfield (Fresh App)
|
|
31
|
+
1. **Prepare Tokens**: Generate/confirm all tokens. Generate UUIDs for IDs in templates.
|
|
32
|
+
2. **Core Engine**: Call `ibgib-add-core-engine` to scaffold the 7 foundational files.
|
|
33
|
+
3. **App Witness**: Call `ibgib-create-app-witness` to scaffold the witness logic.
|
|
34
|
+
4. **UI Shell**: Call `ibgib-create-shell` to scaffold the shell service.
|
|
35
|
+
5. **Main Component**: Call `ibgib-create-component` to create the initial app component.
|
|
36
|
+
6. **Hook Up**:
|
|
37
|
+
- Update `bootstrap.mts` to use the shell service and register the component.
|
|
38
|
+
- Create `package.json` and `tsconfig.json` (if in a new directory).
|
|
39
|
+
|
|
40
|
+
## Workflow for Brownfield (Existing Project)
|
|
41
|
+
1. Determine the source root.
|
|
42
|
+
2. Follow the Greenfield steps but skip `package.json` and `tsconfig.json` creation; instead, integrate with existing ones.
|