@north-light/crouter 0.3.164 → 0.3.166
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/build-root.d.ts +6 -6
- package/dist/build-root.js +12 -13
- package/dist/builtin-memory/00-runtime-base.md +3 -4
- package/dist/builtin-memory/01-spine/01-no-manager.md +1 -1
- package/dist/builtin-memory/02-lifecycle/00-terminal.md +2 -0
- package/dist/builtin-memory/04-orchestration-kernel.md +16 -18
- package/dist/builtin-memory/05-kinds/advisor/00-base.md +0 -2
- package/dist/builtin-memory/05-kinds/advisor/01-orchestrator.md +3 -9
- package/dist/builtin-memory/05-kinds/developer/00-base.md +1 -3
- package/dist/builtin-memory/05-kinds/developer/01-orchestrator.md +2 -10
- package/dist/builtin-memory/05-kinds/explore/00-base.md +2 -2
- package/dist/builtin-memory/05-kinds/explore/01-orchestrator.md +0 -2
- package/dist/builtin-memory/05-kinds/general/00-base.md +3 -5
- package/dist/builtin-memory/05-kinds/general/01-orchestrator.md +0 -4
- package/dist/builtin-memory/05-kinds/plan/01-orchestrator.md +1 -3
- package/dist/builtin-memory/05-kinds/plan/reviewers/00-base.md +12 -0
- package/dist/builtin-memory/05-kinds/plan/reviewers/architecture-fit.md +0 -2
- package/dist/builtin-memory/05-kinds/plan/reviewers/code-smells.md +0 -2
- package/dist/builtin-memory/05-kinds/plan/reviewers/pattern-consistency.md +0 -2
- package/dist/builtin-memory/05-kinds/plan/reviewers/requirements-coverage.md +1 -1
- package/dist/builtin-memory/05-kinds/plan/reviewers/security.md +0 -2
- package/dist/builtin-memory/05-kinds/review/00-base.md +0 -2
- package/dist/builtin-memory/05-kinds/review/01-orchestrator.md +1 -3
- package/dist/builtin-memory/05-kinds/spec/00-base.md +1 -1
- package/dist/builtin-memory/05-kinds/spec/01-orchestrator.md +2 -4
- package/dist/builtin-memory/05-kinds/spec/requirements.md +1 -1
- package/dist/builtin-memory/advisor/council.md +40 -0
- package/dist/builtin-memory/design.md +8 -11
- package/dist/builtin-memory/development.md +6 -9
- package/dist/builtin-memory/internal/INDEX.md +4 -5
- package/dist/builtin-memory/internal/agent-shaping.md +5 -7
- package/dist/builtin-memory/internal/examples/imessage-assistant.md +3 -3
- package/dist/builtin-memory/internal/marketplaces.md +13 -14
- package/dist/builtin-memory/internal/nodes-and-canvas.md +4 -4
- package/dist/builtin-memory/internal/plugins.md +61 -45
- package/dist/builtin-memory/planning.md +4 -7
- package/dist/builtin-memory/spec.md +9 -12
- package/dist/builtin-memory/wedged-child-on-runaway-bash.md +8 -22
- package/dist/cli.js +1 -1
- package/dist/clients/attach/__tests__/attach-keybindings.test.js +17 -4
- package/dist/clients/attach/__tests__/context-message.test.js +62 -22
- package/dist/clients/attach/__tests__/crtr-output.test.js +39 -30
- package/dist/clients/attach/render/chat-view.d.ts +20 -20
- package/dist/clients/attach/render/chat-view.js +40 -54
- package/dist/clients/attach/render/{frozen-history.d.ts → condensed-history.d.ts} +1 -18
- package/dist/clients/attach/render/condensed-history.js +60 -0
- package/dist/clients/attach/render/context-message.d.ts +1 -1
- package/dist/clients/attach/render/context-message.js +18 -41
- package/dist/clients/attach/session/bindings.d.ts +5 -3
- package/dist/clients/attach/session/bindings.js +7 -13
- package/dist/clients/attach/session/keys.d.ts +2 -0
- package/dist/clients/attach/session/keys.js +36 -37
- package/dist/clients/attach/session/profile-files.d.ts +8 -0
- package/dist/clients/attach/session/profile-files.js +157 -0
- package/dist/clients/attach/viewer.js +528 -529
- package/dist/commands/node-context.js +3 -2
- package/dist/commands/node.js +2 -2
- package/dist/commands/pkg/plugin-inspect.js +6 -7
- package/dist/commands/pkg/plugin-manage.d.ts +1 -1
- package/dist/commands/pkg/plugin-manage.js +131 -19
- package/dist/commands/pkg/plugin.js +2 -2
- package/dist/commands/pkg.js +6 -11
- package/dist/commands/profile/env.js +3 -3
- package/dist/commands/sys/config.js +17 -76
- package/dist/commands/sys/doctor.js +5 -91
- package/dist/commands/sys/setup-wizard.d.ts +9 -11
- package/dist/commands/sys/setup-wizard.js +47 -81
- package/dist/core/__tests__/base-worker-prompt.test.js +18 -21
- package/dist/core/__tests__/command-plugins-surfaces.test.js +39 -5
- package/dist/core/__tests__/command-plugins.test.js +75 -16
- package/dist/core/__tests__/review-model-floor.test.js +2 -2
- package/dist/core/__tests__/tmux-surface.test.js +10 -1
- package/dist/core/command-manifests/manifest.d.ts +24 -0
- package/dist/core/{configured-clis → command-manifests}/manifest.js +28 -25
- package/dist/core/command-manifests/registry.d.ts +1 -2
- package/dist/core/command-manifests/registry.js +2 -2
- package/dist/core/command-manifests/schema.d.ts +11 -13
- package/dist/core/command-manifests/schema.js +53 -192
- package/dist/core/command-plugins/compose.d.ts +0 -6
- package/dist/core/command-plugins/compose.js +32 -75
- package/dist/core/command-plugins/discovery.d.ts +25 -58
- package/dist/core/command-plugins/discovery.js +171 -261
- package/dist/core/command-plugins/endpoint.d.ts +24 -0
- package/dist/core/command-plugins/endpoint.js +48 -0
- package/dist/core/command-plugins/store.d.ts +16 -0
- package/dist/core/command-plugins/store.js +64 -0
- package/dist/core/command-plugins/{adapter.d.ts → transport/exec-invoke.d.ts} +3 -3
- package/dist/core/command-plugins/{adapter.js → transport/exec-invoke.js} +4 -4
- package/dist/core/{configured-clis/fetch.d.ts → command-plugins/transport/http-fetch.d.ts} +9 -18
- package/dist/core/{configured-clis/fetch.js → command-plugins/transport/http-fetch.js} +15 -35
- package/dist/core/{configured-clis/invoker.d.ts → command-plugins/transport/http-invoke.d.ts} +7 -7
- package/dist/core/{configured-clis/invoker.js → command-plugins/transport/http-invoke.js} +21 -23
- package/dist/core/command.d.ts +8 -9
- package/dist/core/command.js +6 -9
- package/dist/core/config.js +6 -10
- package/dist/core/env-name.d.ts +6 -0
- package/dist/core/env-name.js +9 -0
- package/dist/core/io.d.ts +1 -1
- package/dist/core/keybindings/__tests__/resolve.test.js +40 -3
- package/dist/core/keybindings/attach-control.d.ts +37 -0
- package/dist/core/keybindings/attach-control.js +38 -0
- package/dist/core/keybindings/catalog.d.ts +5 -4
- package/dist/core/keybindings/catalog.js +16 -8
- package/dist/core/keybindings/index.d.ts +1 -0
- package/dist/core/keybindings/index.js +1 -0
- package/dist/core/keybindings/types.d.ts +1 -1
- package/dist/core/preview-registry.js +41 -74
- package/dist/core/runtime/bearings.d.ts +2 -5
- package/dist/core/runtime/bearings.js +2 -5
- package/dist/core/runtime/broker.js +3 -2
- package/dist/core/runtime/front-door.d.ts +1 -1
- package/dist/core/runtime/front-door.js +2 -2
- package/dist/core/runtime/kickoff.d.ts +3 -3
- package/dist/core/runtime/kickoff.js +4 -3
- package/dist/core/runtime/lifecycle.js +2 -2
- package/dist/core/runtime/situational-context.d.ts +1 -1
- package/dist/core/runtime/situational-context.js +1 -1
- package/dist/core/runtime/spawn.js +9 -9
- package/dist/core/runtime/tmux.js +29 -2
- package/dist/core/scope.d.ts +0 -5
- package/dist/core/scope.js +0 -10
- package/dist/core/user-settings.d.ts +193 -0
- package/dist/core/user-settings.js +252 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/pi-extensions/canvas-stophook.js +3 -2
- package/dist/prompts/review.js +4 -2
- package/dist/shared/generated-context.d.ts +34 -0
- package/dist/shared/generated-context.js +98 -0
- package/dist/types.d.ts +23 -16
- package/dist/types.js +3 -14
- package/dist/web-client/assets/index-BgLGlZ3D.css +2 -0
- package/dist/web-client/assets/{index-NIuSCOHM.js → index-CmoNqcCv.js} +19 -19
- package/dist/web-client/index.html +2 -2
- package/dist/web-client/sw.js +1 -1
- package/docs/public-api.md +1 -0
- package/package.json +1 -1
- package/runtime.lock.json +2 -2
- package/dist/builtin-memory/05-kinds/product/00-base.md +0 -25
- package/dist/builtin-memory/05-kinds/product/01-orchestrator.md +0 -15
- package/dist/builtin-memory/05-kinds/product/teardown.md +0 -15
- package/dist/builtin-memory/internal/workflow-codification.md +0 -82
- package/dist/builtin-memory/product.md +0 -80
- package/dist/clients/attach/render/frozen-history.js +0 -100
- package/dist/commands/pkg/cli-inspect.d.ts +0 -17
- package/dist/commands/pkg/cli-inspect.js +0 -190
- package/dist/commands/pkg/cli-manage.d.ts +0 -3
- package/dist/commands/pkg/cli-manage.js +0 -206
- package/dist/commands/pkg/cli.d.ts +0 -1
- package/dist/commands/pkg/cli.js +0 -14
- package/dist/core/configured-clis/cache.d.ts +0 -16
- package/dist/core/configured-clis/cache.js +0 -57
- package/dist/core/configured-clis/compose.d.ts +0 -14
- package/dist/core/configured-clis/compose.js +0 -60
- package/dist/core/configured-clis/discovery.d.ts +0 -47
- package/dist/core/configured-clis/discovery.js +0 -173
- package/dist/core/configured-clis/manifest.d.ts +0 -24
- package/dist/core/configured-clis/registration.d.ts +0 -40
- package/dist/core/configured-clis/registration.js +0 -201
- package/dist/web-client/assets/index-CqLKj8Xu.css +0 -2
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
<link rel="apple-touch-icon" href="/apple-touch-icon.png" />
|
|
9
9
|
<link rel="icon" href="/icon-192.png" />
|
|
10
10
|
<title>crouter</title>
|
|
11
|
-
<script type="module" crossorigin src="/assets/index-
|
|
12
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
11
|
+
<script type="module" crossorigin src="/assets/index-CmoNqcCv.js"></script>
|
|
12
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BgLGlZ3D.css">
|
|
13
13
|
<link rel="manifest" href="/manifest.webmanifest"></head>
|
|
14
14
|
<body>
|
|
15
15
|
<div id="root"></div>
|
package/dist/web-client/sw.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
try{self[`workbox:core:7.4.0`]&&_()}catch{}var e=(e,...t)=>{let n=e;return t.length>0&&(n+=` :: ${JSON.stringify(t)}`),n},t=class extends Error{constructor(t,n){let r=e(t,n);super(r),this.name=t,this.details=n}},n={googleAnalytics:`googleAnalytics`,precache:`precache-v2`,prefix:`workbox`,runtime:`runtime`,suffix:typeof registration<`u`?registration.scope:``},r=e=>[n.prefix,e,n.suffix].filter(e=>e&&e.length>0).join(`-`),i=e=>{for(let t of Object.keys(n))e(t)},a={updateDetails:e=>{i(t=>{typeof e[t]==`string`&&(n[t]=e[t])})},getGoogleAnalyticsName:e=>e||r(n.googleAnalytics),getPrecacheName:e=>e||r(n.precache),getPrefix:()=>n.prefix,getRuntimeName:e=>e||r(n.runtime),getSuffix:()=>n.suffix};function o(e,t){let n=t();return e.waitUntil(n),n}try{self[`workbox:precaching:7.4.0`]&&_()}catch{}var s=`__WB_REVISION__`;function c(e){if(!e)throw new t(`add-to-cache-list-unexpected-type`,{entry:e});if(typeof e==`string`){let t=new URL(e,location.href);return{cacheKey:t.href,url:t.href}}let{revision:n,url:r}=e;if(!r)throw new t(`add-to-cache-list-unexpected-type`,{entry:e});if(!n){let e=new URL(r,location.href);return{cacheKey:e.href,url:e.href}}let i=new URL(r,location.href),a=new URL(r,location.href);return i.searchParams.set(s,n),{cacheKey:i.href,url:a.href}}var l=class{constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.handlerWillStart=async({request:e,state:t})=>{t&&(t.originalRequest=e)},this.cachedResponseWillBeUsed=async({event:e,state:t,cachedResponse:n})=>{if(e.type===`install`&&t&&t.originalRequest&&t.originalRequest instanceof Request){let e=t.originalRequest.url;n?this.notUpdatedURLs.push(e):this.updatedURLs.push(e)}return n}}},u=class{constructor({precacheController:e}){this.cacheKeyWillBeUsed=async({request:e,params:t})=>{let n=t?.cacheKey||this._precacheController.getCacheKeyForURL(e.url);return n?new Request(n,{headers:e.headers}):e},this._precacheController=e}},d;function f(){if(d===void 0){let e=new Response(``);if(`body`in e)try{new Response(e.body),d=!0}catch{d=!1}d=!1}return d}async function p(e,n){let r=null;if(e.url&&(r=new URL(e.url).origin),r!==self.location.origin)throw new t(`cross-origin-copy-response`,{origin:r});let i=e.clone(),a={headers:new Headers(i.headers),status:i.status,statusText:i.statusText},o=n?n(a):a,s=f()?i.body:await i.blob();return new Response(s,o)}var m=e=>new URL(String(e),location.href).href.replace(RegExp(`^${location.origin}`),``);function h(e,t){let n=new URL(e);for(let e of t)n.searchParams.delete(e);return n.href}async function g(e,t,n,r){let i=h(t.url,n);if(t.url===i)return e.match(t,r);let a=Object.assign(Object.assign({},r),{ignoreSearch:!0}),o=await e.keys(t,a);for(let t of o)if(i===h(t.url,n))return e.match(t,r)}var v=class{constructor(){this.promise=new Promise((e,t)=>{this.resolve=e,this.reject=t})}},y=new Set;async function b(){for(let e of y)await e()}function x(e){return new Promise(t=>setTimeout(t,e))}try{self[`workbox:strategies:7.4.0`]&&_()}catch{}function S(e){return typeof e==`string`?new Request(e):e}var C=class{constructor(e,t){this._cacheKeys={},Object.assign(this,t),this.event=t.event,this._strategy=e,this._handlerDeferred=new v,this._extendLifetimePromises=[],this._plugins=[...e.plugins],this._pluginStateMap=new Map;for(let e of this._plugins)this._pluginStateMap.set(e,{});this.event.waitUntil(this._handlerDeferred.promise)}async fetch(e){let{event:n}=this,r=S(e);if(r.mode===`navigate`&&n instanceof FetchEvent&&n.preloadResponse){let e=await n.preloadResponse;if(e)return e}let i=this.hasCallback(`fetchDidFail`)?r.clone():null;try{for(let e of this.iterateCallbacks(`requestWillFetch`))r=await e({request:r.clone(),event:n})}catch(e){if(e instanceof Error)throw new t(`plugin-error-request-will-fetch`,{thrownErrorMessage:e.message})}let a=r.clone();try{let e;e=await fetch(r,r.mode===`navigate`?void 0:this._strategy.fetchOptions);for(let t of this.iterateCallbacks(`fetchDidSucceed`))e=await t({event:n,request:a,response:e});return e}catch(e){throw i&&await this.runCallbacks(`fetchDidFail`,{error:e,event:n,originalRequest:i.clone(),request:a.clone()}),e}}async fetchAndCachePut(e){let t=await this.fetch(e),n=t.clone();return this.waitUntil(this.cachePut(e,n)),t}async cacheMatch(e){let t=S(e),n,{cacheName:r,matchOptions:i}=this._strategy,a=await this.getCacheKey(t,`read`),o=Object.assign(Object.assign({},i),{cacheName:r});n=await caches.match(a,o);for(let e of this.iterateCallbacks(`cachedResponseWillBeUsed`))n=await e({cacheName:r,matchOptions:i,cachedResponse:n,request:a,event:this.event})||void 0;return n}async cachePut(e,n){let r=S(e);await x(0);let i=await this.getCacheKey(r,`write`);if(!n)throw new t(`cache-put-with-no-response`,{url:m(i.url)});let a=await this._ensureResponseSafeToCache(n);if(!a)return!1;let{cacheName:o,matchOptions:s}=this._strategy,c=await self.caches.open(o),l=this.hasCallback(`cacheDidUpdate`),u=l?await g(c,i.clone(),[`__WB_REVISION__`],s):null;try{await c.put(i,l?a.clone():a)}catch(e){if(e instanceof Error)throw e.name===`QuotaExceededError`&&await b(),e}for(let e of this.iterateCallbacks(`cacheDidUpdate`))await e({cacheName:o,oldResponse:u,newResponse:a.clone(),request:i,event:this.event});return!0}async getCacheKey(e,t){let n=`${e.url} | ${t}`;if(!this._cacheKeys[n]){let r=e;for(let e of this.iterateCallbacks(`cacheKeyWillBeUsed`))r=S(await e({mode:t,request:r,event:this.event,params:this.params}));this._cacheKeys[n]=r}return this._cacheKeys[n]}hasCallback(e){for(let t of this._strategy.plugins)if(e in t)return!0;return!1}async runCallbacks(e,t){for(let n of this.iterateCallbacks(e))await n(t)}*iterateCallbacks(e){for(let t of this._strategy.plugins)if(typeof t[e]==`function`){let n=this._pluginStateMap.get(t);yield r=>{let i=Object.assign(Object.assign({},r),{state:n});return t[e](i)}}}waitUntil(e){return this._extendLifetimePromises.push(e),e}async doneWaiting(){for(;this._extendLifetimePromises.length;){let e=this._extendLifetimePromises.splice(0),t=(await Promise.allSettled(e)).find(e=>e.status===`rejected`);if(t)throw t.reason}}destroy(){this._handlerDeferred.resolve(null)}async _ensureResponseSafeToCache(e){let t=e,n=!1;for(let e of this.iterateCallbacks(`cacheWillUpdate`))if(t=await e({request:this.request,response:t,event:this.event})||void 0,n=!0,!t)break;return n||t&&t.status!==200&&(t=void 0),t}},w=class{constructor(e={}){this.cacheName=a.getRuntimeName(e.cacheName),this.plugins=e.plugins||[],this.fetchOptions=e.fetchOptions,this.matchOptions=e.matchOptions}handle(e){let[t]=this.handleAll(e);return t}handleAll(e){e instanceof FetchEvent&&(e={event:e,request:e.request});let t=e.event,n=typeof e.request==`string`?new Request(e.request):e.request,r=`params`in e?e.params:void 0,i=new C(this,{event:t,request:n,params:r}),a=this._getResponse(i,n,t);return[a,this._awaitComplete(a,i,n,t)]}async _getResponse(e,n,r){await e.runCallbacks(`handlerWillStart`,{event:r,request:n});let i;try{if(i=await this._handle(n,e),!i||i.type===`error`)throw new t(`no-response`,{url:n.url})}catch(t){if(t instanceof Error){for(let a of e.iterateCallbacks(`handlerDidError`))if(i=await a({error:t,event:r,request:n}),i)break}if(!i)throw t}for(let t of e.iterateCallbacks(`handlerWillRespond`))i=await t({event:r,request:n,response:i});return i}async _awaitComplete(e,t,n,r){let i,a;try{i=await e}catch{}try{await t.runCallbacks(`handlerDidRespond`,{event:r,request:n,response:i}),await t.doneWaiting()}catch(e){e instanceof Error&&(a=e)}if(await t.runCallbacks(`handlerDidComplete`,{event:r,request:n,response:i,error:a}),t.destroy(),a)throw a}},T=class e extends w{constructor(t={}){t.cacheName=a.getPrecacheName(t.cacheName),super(t),this._fallbackToNetwork=t.fallbackToNetwork!==!1,this.plugins.push(e.copyRedirectedCacheableResponsesPlugin)}async _handle(e,t){return await t.cacheMatch(e)||(t.event&&t.event.type===`install`?await this._handleInstall(e,t):await this._handleFetch(e,t))}async _handleFetch(e,n){let r,i=n.params||{};if(this._fallbackToNetwork){let t=i.integrity,a=e.integrity,o=!a||a===t;r=await n.fetch(new Request(e,{integrity:e.mode===`no-cors`?void 0:a||t})),t&&o&&e.mode!==`no-cors`&&(this._useDefaultCacheabilityPluginIfNeeded(),await n.cachePut(e,r.clone()))}else throw new t(`missing-precache-entry`,{cacheName:this.cacheName,url:e.url});return r}async _handleInstall(e,n){this._useDefaultCacheabilityPluginIfNeeded();let r=await n.fetch(e);if(!await n.cachePut(e,r.clone()))throw new t(`bad-precaching-response`,{url:e.url,status:r.status});return r}_useDefaultCacheabilityPluginIfNeeded(){let t=null,n=0;for(let[r,i]of this.plugins.entries())i!==e.copyRedirectedCacheableResponsesPlugin&&(i===e.defaultPrecacheCacheabilityPlugin&&(t=r),i.cacheWillUpdate&&n++);n===0?this.plugins.push(e.defaultPrecacheCacheabilityPlugin):n>1&&t!==null&&this.plugins.splice(t,1)}};T.defaultPrecacheCacheabilityPlugin={async cacheWillUpdate({response:e}){return!e||e.status>=400?null:e}},T.copyRedirectedCacheableResponsesPlugin={async cacheWillUpdate({response:e}){return e.redirected?await p(e):e}};var E=class{constructor({cacheName:e,plugins:t=[],fallbackToNetwork:n=!0}={}){this._urlsToCacheKeys=new Map,this._urlsToCacheModes=new Map,this._cacheKeysToIntegrities=new Map,this._strategy=new T({cacheName:a.getPrecacheName(e),plugins:[...t,new u({precacheController:this})],fallbackToNetwork:n}),this.install=this.install.bind(this),this.activate=this.activate.bind(this)}get strategy(){return this._strategy}precache(e){this.addToCacheList(e),this._installAndActiveListenersAdded||=(self.addEventListener(`install`,this.install),self.addEventListener(`activate`,this.activate),!0)}addToCacheList(e){let n=[];for(let r of e){typeof r==`string`?n.push(r):r&&r.revision===void 0&&n.push(r.url);let{cacheKey:e,url:i}=c(r),a=typeof r!=`string`&&r.revision?`reload`:`default`;if(this._urlsToCacheKeys.has(i)&&this._urlsToCacheKeys.get(i)!==e)throw new t(`add-to-cache-list-conflicting-entries`,{firstEntry:this._urlsToCacheKeys.get(i),secondEntry:e});if(typeof r!=`string`&&r.integrity){if(this._cacheKeysToIntegrities.has(e)&&this._cacheKeysToIntegrities.get(e)!==r.integrity)throw new t(`add-to-cache-list-conflicting-integrities`,{url:i});this._cacheKeysToIntegrities.set(e,r.integrity)}if(this._urlsToCacheKeys.set(i,e),this._urlsToCacheModes.set(i,a),n.length>0){let e=`Workbox is precaching URLs without revision info: ${n.join(`, `)}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(e)}}}install(e){return o(e,async()=>{let t=new l;this.strategy.plugins.push(t);for(let[t,n]of this._urlsToCacheKeys){let r=this._cacheKeysToIntegrities.get(n),i=this._urlsToCacheModes.get(t),a=new Request(t,{integrity:r,cache:i,credentials:`same-origin`});await Promise.all(this.strategy.handleAll({params:{cacheKey:n},request:a,event:e}))}let{updatedURLs:n,notUpdatedURLs:r}=t;return{updatedURLs:n,notUpdatedURLs:r}})}activate(e){return o(e,async()=>{let e=await self.caches.open(this.strategy.cacheName),t=await e.keys(),n=new Set(this._urlsToCacheKeys.values()),r=[];for(let i of t)n.has(i.url)||(await e.delete(i),r.push(i.url));return{deletedURLs:r}})}getURLsToCacheKeys(){return this._urlsToCacheKeys}getCachedURLs(){return[...this._urlsToCacheKeys.keys()]}getCacheKeyForURL(e){let t=new URL(e,location.href);return this._urlsToCacheKeys.get(t.href)}getIntegrityForCacheKey(e){return this._cacheKeysToIntegrities.get(e)}async matchPrecache(e){let t=e instanceof Request?e.url:e,n=this.getCacheKeyForURL(t);if(n)return(await self.caches.open(this.strategy.cacheName)).match(n)}createHandlerBoundToURL(e){let n=this.getCacheKeyForURL(e);if(!n)throw new t(`non-precached-url`,{url:e});return t=>(t.request=new Request(e),t.params=Object.assign({cacheKey:n},t.params),this.strategy.handle(t))}},D,O=()=>(D||=new E,D);try{self[`workbox:routing:7.4.0`]&&_()}catch{}var k=e=>e&&typeof e==`object`?e:{handle:e},A=class{constructor(e,t,n=`GET`){this.handler=k(t),this.match=e,this.method=n}setCatchHandler(e){this.catchHandler=k(e)}},j=class extends A{constructor(e,t,n){super(({url:t})=>{let n=e.exec(t.href);if(n&&(t.origin===location.origin||n.index===0))return n.slice(1)},t,n)}},M=class{constructor(){this._routes=new Map,this._defaultHandlerMap=new Map}get routes(){return this._routes}addFetchListener(){self.addEventListener(`fetch`,(e=>{let{request:t}=e,n=this.handleRequest({request:t,event:e});n&&e.respondWith(n)}))}addCacheListener(){self.addEventListener(`message`,(e=>{if(e.data&&e.data.type===`CACHE_URLS`){let{payload:t}=e.data,n=Promise.all(t.urlsToCache.map(t=>{typeof t==`string`&&(t=[t]);let n=new Request(...t);return this.handleRequest({request:n,event:e})}));e.waitUntil(n),e.ports&&e.ports[0]&&n.then(()=>e.ports[0].postMessage(!0))}}))}handleRequest({request:e,event:t}){let n=new URL(e.url,location.href);if(!n.protocol.startsWith(`http`))return;let r=n.origin===location.origin,{params:i,route:a}=this.findMatchingRoute({event:t,request:e,sameOrigin:r,url:n}),o=a&&a.handler,s=e.method;if(!o&&this._defaultHandlerMap.has(s)&&(o=this._defaultHandlerMap.get(s)),!o)return;let c;try{c=o.handle({url:n,request:e,event:t,params:i})}catch(e){c=Promise.reject(e)}let l=a&&a.catchHandler;return c instanceof Promise&&(this._catchHandler||l)&&(c=c.catch(async r=>{if(l)try{return await l.handle({url:n,request:e,event:t,params:i})}catch(e){e instanceof Error&&(r=e)}if(this._catchHandler)return this._catchHandler.handle({url:n,request:e,event:t});throw r})),c}findMatchingRoute({url:e,sameOrigin:t,request:n,event:r}){let i=this._routes.get(n.method)||[];for(let a of i){let i,o=a.match({url:e,sameOrigin:t,request:n,event:r});if(o)return i=o,(Array.isArray(i)&&i.length===0||o.constructor===Object&&Object.keys(o).length===0||typeof o==`boolean`)&&(i=void 0),{route:a,params:i}}return{}}setDefaultHandler(e,t=`GET`){this._defaultHandlerMap.set(t,k(e))}setCatchHandler(e){this._catchHandler=k(e)}registerRoute(e){this._routes.has(e.method)||this._routes.set(e.method,[]),this._routes.get(e.method).push(e)}unregisterRoute(e){if(!this._routes.has(e.method))throw new t(`unregister-route-but-not-found-with-method`,{method:e.method});let n=this._routes.get(e.method).indexOf(e);if(n>-1)this._routes.get(e.method).splice(n,1);else throw new t(`unregister-route-route-not-registered`)}},N,P=()=>(N||(N=new M,N.addFetchListener(),N.addCacheListener()),N);function F(e,n,r){let i;if(typeof e==`string`){let t=new URL(e,location.href);i=new A(({url:e})=>e.href===t.href,n,r)}else if(e instanceof RegExp)i=new j(e,n,r);else if(typeof e==`function`)i=new A(e,n,r);else if(e instanceof A)i=e;else throw new t(`unsupported-route-type`,{moduleName:`workbox-routing`,funcName:`registerRoute`,paramName:`capture`});return P().registerRoute(i),i}function I(e,t=[]){for(let n of[...e.searchParams.keys()])t.some(e=>e.test(n))&&e.searchParams.delete(n);return e}function*L(e,{ignoreURLParametersMatching:t=[/^utm_/,/^fbclid$/],directoryIndex:n=`index.html`,cleanURLs:r=!0,urlManipulation:i}={}){let a=new URL(e,location.href);a.hash=``,yield a.href;let o=I(a,t);if(yield o.href,n&&o.pathname.endsWith(`/`)){let e=new URL(o.href);e.pathname+=n,yield e.href}if(r){let e=new URL(o.href);e.pathname+=`.html`,yield e.href}if(i){let e=i({url:a});for(let t of e)yield t.href}}var R=class extends A{constructor(e,t){super(({request:n})=>{let r=e.getURLsToCacheKeys();for(let i of L(n.url,t)){let t=r.get(i);if(t)return{cacheKey:t,integrity:e.getIntegrityForCacheKey(t)}}},e.strategy)}};function z(e){F(new R(O(),e))}var B=`-precache-`,V=async(e,t=B)=>{let n=(await self.caches.keys()).filter(n=>n.includes(t)&&n.includes(self.registration.scope)&&n!==e);return await Promise.all(n.map(e=>self.caches.delete(e))),n};function H(){self.addEventListener(`activate`,(e=>{let t=a.getPrecacheName();e.waitUntil(V(t).then(e=>{}))}))}function U(e){return O().createHandlerBoundToURL(e)}function W(e){O().precache(e)}function G(e,t){W(e),z(t)}var K=class extends A{constructor(e,{allowlist:t=[/./],denylist:n=[]}={}){super(e=>this._match(e),e),this._allowlist=t,this._denylist=n}_match({url:e,request:t}){if(t&&t.mode!==`navigate`)return!1;let n=e.pathname+e.search;for(let e of this._denylist)if(e.test(n))return!1;return!!this._allowlist.some(e=>e.test(n))}},q=class extends w{constructor(e={}){super(e),this._networkTimeoutSeconds=e.networkTimeoutSeconds||0}async _handle(e,n){let r,i;try{let t=[n.fetch(e)];if(this._networkTimeoutSeconds){let e=x(this._networkTimeoutSeconds*1e3);t.push(e)}if(i=await Promise.race(t),!i)throw Error(`Timed out the network response after ${this._networkTimeoutSeconds} seconds.`)}catch(e){e instanceof Error&&(r=e)}if(!i)throw new t(`no-response`,{url:e.url,error:r});return i}};function J(e,t,n){let r=new URLSearchParams;t!==void 0&&t!==``&&r.set(`ask`,t),n!==void 0&&n!==``&&r.set(`token`,n);let i=r.toString();return`/c/${encodeURIComponent(e)}${i===``?``:`?${i}`}`}var Y=`crtr-push-token-v1`,X=`/__push-token`;async function Z(){if(typeof caches>`u`)return;let e=await(await caches.open(Y)).match(X);if(e===void 0)return;let t=await e.text();return t===``?void 0:t}self.addEventListener(`message`,e=>{e.data?.type===`SKIP_WAITING`&&self.skipWaiting()}),G([{"revision":"45cf634ce64c3099fa616d018e590961","url":"index.html"},{"revision":"d1609f5483f95b4a260d09d0ab185c33","url":"icon-maskable-512.png"},{"revision":"b275ba8590c62c4dd8459e88e911e4b2","url":"icon-512.png"},{"revision":"b1b16d2a1130ca68196bf7ada05ab5bd","url":"icon-192.png"},{"revision":"943e387ec5184bd044444386ecf60b48","url":"apple-touch-icon.png"},{"revision":null,"url":"assets/workbox-window.prod.es5-Bd17z0YL.js"},{"revision":null,"url":"assets/martian-mono-latin-wght-normal-5W32yIyr.woff2"},{"revision":null,"url":"assets/martian-mono-latin-ext-wght-normal-DlL6xMw5.woff2"},{"revision":null,"url":"assets/martian-mono-cyrillic-wght-normal-B84CD5C_.woff2"},{"revision":null,"url":"assets/index-NIuSCOHM.js"},{"revision":null,"url":"assets/index-CqLKj8Xu.css"},{"revision":null,"url":"assets/fragment-mono-latin-ext-400-normal-CT4YFKeK.woff"},{"revision":null,"url":"assets/fragment-mono-latin-ext-400-normal-BbKYyvR9.woff2"},{"revision":null,"url":"assets/fragment-mono-latin-400-normal-yxdJ5AmL.woff2"},{"revision":null,"url":"assets/fragment-mono-latin-400-normal-BYwT3kSJ.woff"},{"revision":"943e387ec5184bd044444386ecf60b48","url":"apple-touch-icon.png"},{"revision":"b1b16d2a1130ca68196bf7ada05ab5bd","url":"icon-192.png"},{"revision":"b275ba8590c62c4dd8459e88e911e4b2","url":"icon-512.png"},{"revision":"d1609f5483f95b4a260d09d0ab185c33","url":"icon-maskable-512.png"},{"revision":"660a37964e8a469ae61a2cfad652cc5a","url":"manifest.webmanifest"}]),H(),F(new K(U(`index.html`),{denylist:[/^\/__crtr\//,/^\/node\//,/[?&]token=/]})),F(({url:e})=>e.pathname.startsWith(`/__crtr/`),new q,`GET`),F(({url:e})=>e.pathname.startsWith(`/node/`),new q,`GET`);function Q(e){if(typeof e!=`object`||!e)return!1;let t=e;return!(typeof t.conversationId!=`string`||t.conversationId===``||t.kind!==`needs-you`&&t.kind!==`done`||typeof t.title!=`string`||typeof t.snippet!=`string`||t.askId!==void 0&&typeof t.askId!=`string`)}self.addEventListener(`push`,e=>{let t;try{t=e.data?.json()}catch{return}if(!Q(t))return;let n={body:t.snippet,tag:`crtr:${t.conversationId}`,renotify:!0,icon:`/icon-192.png`,badge:`/icon-192.png`,data:{conversationId:t.conversationId,askId:t.askId}};e.waitUntil(self.registration.showNotification(t.title,n))}),self.addEventListener(`notificationclick`,e=>{e.notification.close();let t=e.notification.data;if(typeof t?.conversationId!=`string`||t.conversationId===``)return;let n=t.conversationId,r=typeof t.askId==`string`?t.askId:void 0;e.waitUntil($(n,r))});async function $(e,t){let n=(await self.clients.matchAll({type:`window`,includeUncontrolled:!0}))[0];if(n!==void 0){n.postMessage({type:`crtr-deep-link`,conversationId:e,askId:t}),await n.focus();return}let r=await Z();await self.clients.openWindow(J(e,t,r))}
|
|
1
|
+
try{self[`workbox:core:7.4.0`]&&_()}catch{}var e=(e,...t)=>{let n=e;return t.length>0&&(n+=` :: ${JSON.stringify(t)}`),n},t=class extends Error{constructor(t,n){let r=e(t,n);super(r),this.name=t,this.details=n}},n={googleAnalytics:`googleAnalytics`,precache:`precache-v2`,prefix:`workbox`,runtime:`runtime`,suffix:typeof registration<`u`?registration.scope:``},r=e=>[n.prefix,e,n.suffix].filter(e=>e&&e.length>0).join(`-`),i=e=>{for(let t of Object.keys(n))e(t)},a={updateDetails:e=>{i(t=>{typeof e[t]==`string`&&(n[t]=e[t])})},getGoogleAnalyticsName:e=>e||r(n.googleAnalytics),getPrecacheName:e=>e||r(n.precache),getPrefix:()=>n.prefix,getRuntimeName:e=>e||r(n.runtime),getSuffix:()=>n.suffix};function o(e,t){let n=t();return e.waitUntil(n),n}try{self[`workbox:precaching:7.4.0`]&&_()}catch{}var s=`__WB_REVISION__`;function c(e){if(!e)throw new t(`add-to-cache-list-unexpected-type`,{entry:e});if(typeof e==`string`){let t=new URL(e,location.href);return{cacheKey:t.href,url:t.href}}let{revision:n,url:r}=e;if(!r)throw new t(`add-to-cache-list-unexpected-type`,{entry:e});if(!n){let e=new URL(r,location.href);return{cacheKey:e.href,url:e.href}}let i=new URL(r,location.href),a=new URL(r,location.href);return i.searchParams.set(s,n),{cacheKey:i.href,url:a.href}}var l=class{constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.handlerWillStart=async({request:e,state:t})=>{t&&(t.originalRequest=e)},this.cachedResponseWillBeUsed=async({event:e,state:t,cachedResponse:n})=>{if(e.type===`install`&&t&&t.originalRequest&&t.originalRequest instanceof Request){let e=t.originalRequest.url;n?this.notUpdatedURLs.push(e):this.updatedURLs.push(e)}return n}}},u=class{constructor({precacheController:e}){this.cacheKeyWillBeUsed=async({request:e,params:t})=>{let n=t?.cacheKey||this._precacheController.getCacheKeyForURL(e.url);return n?new Request(n,{headers:e.headers}):e},this._precacheController=e}},d;function f(){if(d===void 0){let e=new Response(``);if(`body`in e)try{new Response(e.body),d=!0}catch{d=!1}d=!1}return d}async function p(e,n){let r=null;if(e.url&&(r=new URL(e.url).origin),r!==self.location.origin)throw new t(`cross-origin-copy-response`,{origin:r});let i=e.clone(),a={headers:new Headers(i.headers),status:i.status,statusText:i.statusText},o=n?n(a):a,s=f()?i.body:await i.blob();return new Response(s,o)}var m=e=>new URL(String(e),location.href).href.replace(RegExp(`^${location.origin}`),``);function h(e,t){let n=new URL(e);for(let e of t)n.searchParams.delete(e);return n.href}async function g(e,t,n,r){let i=h(t.url,n);if(t.url===i)return e.match(t,r);let a=Object.assign(Object.assign({},r),{ignoreSearch:!0}),o=await e.keys(t,a);for(let t of o)if(i===h(t.url,n))return e.match(t,r)}var v=class{constructor(){this.promise=new Promise((e,t)=>{this.resolve=e,this.reject=t})}},y=new Set;async function b(){for(let e of y)await e()}function x(e){return new Promise(t=>setTimeout(t,e))}try{self[`workbox:strategies:7.4.0`]&&_()}catch{}function S(e){return typeof e==`string`?new Request(e):e}var C=class{constructor(e,t){this._cacheKeys={},Object.assign(this,t),this.event=t.event,this._strategy=e,this._handlerDeferred=new v,this._extendLifetimePromises=[],this._plugins=[...e.plugins],this._pluginStateMap=new Map;for(let e of this._plugins)this._pluginStateMap.set(e,{});this.event.waitUntil(this._handlerDeferred.promise)}async fetch(e){let{event:n}=this,r=S(e);if(r.mode===`navigate`&&n instanceof FetchEvent&&n.preloadResponse){let e=await n.preloadResponse;if(e)return e}let i=this.hasCallback(`fetchDidFail`)?r.clone():null;try{for(let e of this.iterateCallbacks(`requestWillFetch`))r=await e({request:r.clone(),event:n})}catch(e){if(e instanceof Error)throw new t(`plugin-error-request-will-fetch`,{thrownErrorMessage:e.message})}let a=r.clone();try{let e;e=await fetch(r,r.mode===`navigate`?void 0:this._strategy.fetchOptions);for(let t of this.iterateCallbacks(`fetchDidSucceed`))e=await t({event:n,request:a,response:e});return e}catch(e){throw i&&await this.runCallbacks(`fetchDidFail`,{error:e,event:n,originalRequest:i.clone(),request:a.clone()}),e}}async fetchAndCachePut(e){let t=await this.fetch(e),n=t.clone();return this.waitUntil(this.cachePut(e,n)),t}async cacheMatch(e){let t=S(e),n,{cacheName:r,matchOptions:i}=this._strategy,a=await this.getCacheKey(t,`read`),o=Object.assign(Object.assign({},i),{cacheName:r});n=await caches.match(a,o);for(let e of this.iterateCallbacks(`cachedResponseWillBeUsed`))n=await e({cacheName:r,matchOptions:i,cachedResponse:n,request:a,event:this.event})||void 0;return n}async cachePut(e,n){let r=S(e);await x(0);let i=await this.getCacheKey(r,`write`);if(!n)throw new t(`cache-put-with-no-response`,{url:m(i.url)});let a=await this._ensureResponseSafeToCache(n);if(!a)return!1;let{cacheName:o,matchOptions:s}=this._strategy,c=await self.caches.open(o),l=this.hasCallback(`cacheDidUpdate`),u=l?await g(c,i.clone(),[`__WB_REVISION__`],s):null;try{await c.put(i,l?a.clone():a)}catch(e){if(e instanceof Error)throw e.name===`QuotaExceededError`&&await b(),e}for(let e of this.iterateCallbacks(`cacheDidUpdate`))await e({cacheName:o,oldResponse:u,newResponse:a.clone(),request:i,event:this.event});return!0}async getCacheKey(e,t){let n=`${e.url} | ${t}`;if(!this._cacheKeys[n]){let r=e;for(let e of this.iterateCallbacks(`cacheKeyWillBeUsed`))r=S(await e({mode:t,request:r,event:this.event,params:this.params}));this._cacheKeys[n]=r}return this._cacheKeys[n]}hasCallback(e){for(let t of this._strategy.plugins)if(e in t)return!0;return!1}async runCallbacks(e,t){for(let n of this.iterateCallbacks(e))await n(t)}*iterateCallbacks(e){for(let t of this._strategy.plugins)if(typeof t[e]==`function`){let n=this._pluginStateMap.get(t);yield r=>{let i=Object.assign(Object.assign({},r),{state:n});return t[e](i)}}}waitUntil(e){return this._extendLifetimePromises.push(e),e}async doneWaiting(){for(;this._extendLifetimePromises.length;){let e=this._extendLifetimePromises.splice(0),t=(await Promise.allSettled(e)).find(e=>e.status===`rejected`);if(t)throw t.reason}}destroy(){this._handlerDeferred.resolve(null)}async _ensureResponseSafeToCache(e){let t=e,n=!1;for(let e of this.iterateCallbacks(`cacheWillUpdate`))if(t=await e({request:this.request,response:t,event:this.event})||void 0,n=!0,!t)break;return n||t&&t.status!==200&&(t=void 0),t}},w=class{constructor(e={}){this.cacheName=a.getRuntimeName(e.cacheName),this.plugins=e.plugins||[],this.fetchOptions=e.fetchOptions,this.matchOptions=e.matchOptions}handle(e){let[t]=this.handleAll(e);return t}handleAll(e){e instanceof FetchEvent&&(e={event:e,request:e.request});let t=e.event,n=typeof e.request==`string`?new Request(e.request):e.request,r=`params`in e?e.params:void 0,i=new C(this,{event:t,request:n,params:r}),a=this._getResponse(i,n,t);return[a,this._awaitComplete(a,i,n,t)]}async _getResponse(e,n,r){await e.runCallbacks(`handlerWillStart`,{event:r,request:n});let i;try{if(i=await this._handle(n,e),!i||i.type===`error`)throw new t(`no-response`,{url:n.url})}catch(t){if(t instanceof Error){for(let a of e.iterateCallbacks(`handlerDidError`))if(i=await a({error:t,event:r,request:n}),i)break}if(!i)throw t}for(let t of e.iterateCallbacks(`handlerWillRespond`))i=await t({event:r,request:n,response:i});return i}async _awaitComplete(e,t,n,r){let i,a;try{i=await e}catch{}try{await t.runCallbacks(`handlerDidRespond`,{event:r,request:n,response:i}),await t.doneWaiting()}catch(e){e instanceof Error&&(a=e)}if(await t.runCallbacks(`handlerDidComplete`,{event:r,request:n,response:i,error:a}),t.destroy(),a)throw a}},T=class e extends w{constructor(t={}){t.cacheName=a.getPrecacheName(t.cacheName),super(t),this._fallbackToNetwork=t.fallbackToNetwork!==!1,this.plugins.push(e.copyRedirectedCacheableResponsesPlugin)}async _handle(e,t){return await t.cacheMatch(e)||(t.event&&t.event.type===`install`?await this._handleInstall(e,t):await this._handleFetch(e,t))}async _handleFetch(e,n){let r,i=n.params||{};if(this._fallbackToNetwork){let t=i.integrity,a=e.integrity,o=!a||a===t;r=await n.fetch(new Request(e,{integrity:e.mode===`no-cors`?void 0:a||t})),t&&o&&e.mode!==`no-cors`&&(this._useDefaultCacheabilityPluginIfNeeded(),await n.cachePut(e,r.clone()))}else throw new t(`missing-precache-entry`,{cacheName:this.cacheName,url:e.url});return r}async _handleInstall(e,n){this._useDefaultCacheabilityPluginIfNeeded();let r=await n.fetch(e);if(!await n.cachePut(e,r.clone()))throw new t(`bad-precaching-response`,{url:e.url,status:r.status});return r}_useDefaultCacheabilityPluginIfNeeded(){let t=null,n=0;for(let[r,i]of this.plugins.entries())i!==e.copyRedirectedCacheableResponsesPlugin&&(i===e.defaultPrecacheCacheabilityPlugin&&(t=r),i.cacheWillUpdate&&n++);n===0?this.plugins.push(e.defaultPrecacheCacheabilityPlugin):n>1&&t!==null&&this.plugins.splice(t,1)}};T.defaultPrecacheCacheabilityPlugin={async cacheWillUpdate({response:e}){return!e||e.status>=400?null:e}},T.copyRedirectedCacheableResponsesPlugin={async cacheWillUpdate({response:e}){return e.redirected?await p(e):e}};var E=class{constructor({cacheName:e,plugins:t=[],fallbackToNetwork:n=!0}={}){this._urlsToCacheKeys=new Map,this._urlsToCacheModes=new Map,this._cacheKeysToIntegrities=new Map,this._strategy=new T({cacheName:a.getPrecacheName(e),plugins:[...t,new u({precacheController:this})],fallbackToNetwork:n}),this.install=this.install.bind(this),this.activate=this.activate.bind(this)}get strategy(){return this._strategy}precache(e){this.addToCacheList(e),this._installAndActiveListenersAdded||=(self.addEventListener(`install`,this.install),self.addEventListener(`activate`,this.activate),!0)}addToCacheList(e){let n=[];for(let r of e){typeof r==`string`?n.push(r):r&&r.revision===void 0&&n.push(r.url);let{cacheKey:e,url:i}=c(r),a=typeof r!=`string`&&r.revision?`reload`:`default`;if(this._urlsToCacheKeys.has(i)&&this._urlsToCacheKeys.get(i)!==e)throw new t(`add-to-cache-list-conflicting-entries`,{firstEntry:this._urlsToCacheKeys.get(i),secondEntry:e});if(typeof r!=`string`&&r.integrity){if(this._cacheKeysToIntegrities.has(e)&&this._cacheKeysToIntegrities.get(e)!==r.integrity)throw new t(`add-to-cache-list-conflicting-integrities`,{url:i});this._cacheKeysToIntegrities.set(e,r.integrity)}if(this._urlsToCacheKeys.set(i,e),this._urlsToCacheModes.set(i,a),n.length>0){let e=`Workbox is precaching URLs without revision info: ${n.join(`, `)}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(e)}}}install(e){return o(e,async()=>{let t=new l;this.strategy.plugins.push(t);for(let[t,n]of this._urlsToCacheKeys){let r=this._cacheKeysToIntegrities.get(n),i=this._urlsToCacheModes.get(t),a=new Request(t,{integrity:r,cache:i,credentials:`same-origin`});await Promise.all(this.strategy.handleAll({params:{cacheKey:n},request:a,event:e}))}let{updatedURLs:n,notUpdatedURLs:r}=t;return{updatedURLs:n,notUpdatedURLs:r}})}activate(e){return o(e,async()=>{let e=await self.caches.open(this.strategy.cacheName),t=await e.keys(),n=new Set(this._urlsToCacheKeys.values()),r=[];for(let i of t)n.has(i.url)||(await e.delete(i),r.push(i.url));return{deletedURLs:r}})}getURLsToCacheKeys(){return this._urlsToCacheKeys}getCachedURLs(){return[...this._urlsToCacheKeys.keys()]}getCacheKeyForURL(e){let t=new URL(e,location.href);return this._urlsToCacheKeys.get(t.href)}getIntegrityForCacheKey(e){return this._cacheKeysToIntegrities.get(e)}async matchPrecache(e){let t=e instanceof Request?e.url:e,n=this.getCacheKeyForURL(t);if(n)return(await self.caches.open(this.strategy.cacheName)).match(n)}createHandlerBoundToURL(e){let n=this.getCacheKeyForURL(e);if(!n)throw new t(`non-precached-url`,{url:e});return t=>(t.request=new Request(e),t.params=Object.assign({cacheKey:n},t.params),this.strategy.handle(t))}},D,O=()=>(D||=new E,D);try{self[`workbox:routing:7.4.0`]&&_()}catch{}var k=e=>e&&typeof e==`object`?e:{handle:e},A=class{constructor(e,t,n=`GET`){this.handler=k(t),this.match=e,this.method=n}setCatchHandler(e){this.catchHandler=k(e)}},j=class extends A{constructor(e,t,n){super(({url:t})=>{let n=e.exec(t.href);if(n&&(t.origin===location.origin||n.index===0))return n.slice(1)},t,n)}},M=class{constructor(){this._routes=new Map,this._defaultHandlerMap=new Map}get routes(){return this._routes}addFetchListener(){self.addEventListener(`fetch`,(e=>{let{request:t}=e,n=this.handleRequest({request:t,event:e});n&&e.respondWith(n)}))}addCacheListener(){self.addEventListener(`message`,(e=>{if(e.data&&e.data.type===`CACHE_URLS`){let{payload:t}=e.data,n=Promise.all(t.urlsToCache.map(t=>{typeof t==`string`&&(t=[t]);let n=new Request(...t);return this.handleRequest({request:n,event:e})}));e.waitUntil(n),e.ports&&e.ports[0]&&n.then(()=>e.ports[0].postMessage(!0))}}))}handleRequest({request:e,event:t}){let n=new URL(e.url,location.href);if(!n.protocol.startsWith(`http`))return;let r=n.origin===location.origin,{params:i,route:a}=this.findMatchingRoute({event:t,request:e,sameOrigin:r,url:n}),o=a&&a.handler,s=e.method;if(!o&&this._defaultHandlerMap.has(s)&&(o=this._defaultHandlerMap.get(s)),!o)return;let c;try{c=o.handle({url:n,request:e,event:t,params:i})}catch(e){c=Promise.reject(e)}let l=a&&a.catchHandler;return c instanceof Promise&&(this._catchHandler||l)&&(c=c.catch(async r=>{if(l)try{return await l.handle({url:n,request:e,event:t,params:i})}catch(e){e instanceof Error&&(r=e)}if(this._catchHandler)return this._catchHandler.handle({url:n,request:e,event:t});throw r})),c}findMatchingRoute({url:e,sameOrigin:t,request:n,event:r}){let i=this._routes.get(n.method)||[];for(let a of i){let i,o=a.match({url:e,sameOrigin:t,request:n,event:r});if(o)return i=o,(Array.isArray(i)&&i.length===0||o.constructor===Object&&Object.keys(o).length===0||typeof o==`boolean`)&&(i=void 0),{route:a,params:i}}return{}}setDefaultHandler(e,t=`GET`){this._defaultHandlerMap.set(t,k(e))}setCatchHandler(e){this._catchHandler=k(e)}registerRoute(e){this._routes.has(e.method)||this._routes.set(e.method,[]),this._routes.get(e.method).push(e)}unregisterRoute(e){if(!this._routes.has(e.method))throw new t(`unregister-route-but-not-found-with-method`,{method:e.method});let n=this._routes.get(e.method).indexOf(e);if(n>-1)this._routes.get(e.method).splice(n,1);else throw new t(`unregister-route-route-not-registered`)}},N,P=()=>(N||(N=new M,N.addFetchListener(),N.addCacheListener()),N);function F(e,n,r){let i;if(typeof e==`string`){let t=new URL(e,location.href);i=new A(({url:e})=>e.href===t.href,n,r)}else if(e instanceof RegExp)i=new j(e,n,r);else if(typeof e==`function`)i=new A(e,n,r);else if(e instanceof A)i=e;else throw new t(`unsupported-route-type`,{moduleName:`workbox-routing`,funcName:`registerRoute`,paramName:`capture`});return P().registerRoute(i),i}function I(e,t=[]){for(let n of[...e.searchParams.keys()])t.some(e=>e.test(n))&&e.searchParams.delete(n);return e}function*L(e,{ignoreURLParametersMatching:t=[/^utm_/,/^fbclid$/],directoryIndex:n=`index.html`,cleanURLs:r=!0,urlManipulation:i}={}){let a=new URL(e,location.href);a.hash=``,yield a.href;let o=I(a,t);if(yield o.href,n&&o.pathname.endsWith(`/`)){let e=new URL(o.href);e.pathname+=n,yield e.href}if(r){let e=new URL(o.href);e.pathname+=`.html`,yield e.href}if(i){let e=i({url:a});for(let t of e)yield t.href}}var R=class extends A{constructor(e,t){super(({request:n})=>{let r=e.getURLsToCacheKeys();for(let i of L(n.url,t)){let t=r.get(i);if(t)return{cacheKey:t,integrity:e.getIntegrityForCacheKey(t)}}},e.strategy)}};function z(e){F(new R(O(),e))}var B=`-precache-`,V=async(e,t=B)=>{let n=(await self.caches.keys()).filter(n=>n.includes(t)&&n.includes(self.registration.scope)&&n!==e);return await Promise.all(n.map(e=>self.caches.delete(e))),n};function H(){self.addEventListener(`activate`,(e=>{let t=a.getPrecacheName();e.waitUntil(V(t).then(e=>{}))}))}function U(e){return O().createHandlerBoundToURL(e)}function W(e){O().precache(e)}function G(e,t){W(e),z(t)}var K=class extends A{constructor(e,{allowlist:t=[/./],denylist:n=[]}={}){super(e=>this._match(e),e),this._allowlist=t,this._denylist=n}_match({url:e,request:t}){if(t&&t.mode!==`navigate`)return!1;let n=e.pathname+e.search;for(let e of this._denylist)if(e.test(n))return!1;return!!this._allowlist.some(e=>e.test(n))}},q=class extends w{constructor(e={}){super(e),this._networkTimeoutSeconds=e.networkTimeoutSeconds||0}async _handle(e,n){let r,i;try{let t=[n.fetch(e)];if(this._networkTimeoutSeconds){let e=x(this._networkTimeoutSeconds*1e3);t.push(e)}if(i=await Promise.race(t),!i)throw Error(`Timed out the network response after ${this._networkTimeoutSeconds} seconds.`)}catch(e){e instanceof Error&&(r=e)}if(!i)throw new t(`no-response`,{url:e.url,error:r});return i}};function J(e,t,n){let r=new URLSearchParams;t!==void 0&&t!==``&&r.set(`ask`,t),n!==void 0&&n!==``&&r.set(`token`,n);let i=r.toString();return`/c/${encodeURIComponent(e)}${i===``?``:`?${i}`}`}var Y=`crtr-push-token-v1`,X=`/__push-token`;async function Z(){if(typeof caches>`u`)return;let e=await(await caches.open(Y)).match(X);if(e===void 0)return;let t=await e.text();return t===``?void 0:t}self.addEventListener(`message`,e=>{e.data?.type===`SKIP_WAITING`&&self.skipWaiting()}),G([{"revision":"cddd5f0fbdf7c73390df5f7338aa75aa","url":"index.html"},{"revision":"d1609f5483f95b4a260d09d0ab185c33","url":"icon-maskable-512.png"},{"revision":"b275ba8590c62c4dd8459e88e911e4b2","url":"icon-512.png"},{"revision":"b1b16d2a1130ca68196bf7ada05ab5bd","url":"icon-192.png"},{"revision":"943e387ec5184bd044444386ecf60b48","url":"apple-touch-icon.png"},{"revision":null,"url":"assets/workbox-window.prod.es5-Bd17z0YL.js"},{"revision":null,"url":"assets/martian-mono-latin-wght-normal-5W32yIyr.woff2"},{"revision":null,"url":"assets/martian-mono-latin-ext-wght-normal-DlL6xMw5.woff2"},{"revision":null,"url":"assets/martian-mono-cyrillic-wght-normal-B84CD5C_.woff2"},{"revision":null,"url":"assets/index-CmoNqcCv.js"},{"revision":null,"url":"assets/index-BgLGlZ3D.css"},{"revision":null,"url":"assets/fragment-mono-latin-ext-400-normal-CT4YFKeK.woff"},{"revision":null,"url":"assets/fragment-mono-latin-ext-400-normal-BbKYyvR9.woff2"},{"revision":null,"url":"assets/fragment-mono-latin-400-normal-yxdJ5AmL.woff2"},{"revision":null,"url":"assets/fragment-mono-latin-400-normal-BYwT3kSJ.woff"},{"revision":"943e387ec5184bd044444386ecf60b48","url":"apple-touch-icon.png"},{"revision":"b1b16d2a1130ca68196bf7ada05ab5bd","url":"icon-192.png"},{"revision":"b275ba8590c62c4dd8459e88e911e4b2","url":"icon-512.png"},{"revision":"d1609f5483f95b4a260d09d0ab185c33","url":"icon-maskable-512.png"},{"revision":"660a37964e8a469ae61a2cfad652cc5a","url":"manifest.webmanifest"}]),H(),F(new K(U(`index.html`),{denylist:[/^\/__crtr\//,/^\/node\//,/[?&]token=/]})),F(({url:e})=>e.pathname.startsWith(`/__crtr/`),new q,`GET`),F(({url:e})=>e.pathname.startsWith(`/node/`),new q,`GET`);function Q(e){if(typeof e!=`object`||!e)return!1;let t=e;return!(typeof t.conversationId!=`string`||t.conversationId===``||t.kind!==`needs-you`&&t.kind!==`done`||typeof t.title!=`string`||typeof t.snippet!=`string`||t.askId!==void 0&&typeof t.askId!=`string`)}self.addEventListener(`push`,e=>{let t;try{t=e.data?.json()}catch{return}if(!Q(t))return;let n={body:t.snippet,tag:`crtr:${t.conversationId}`,renotify:!0,icon:`/icon-192.png`,badge:`/icon-192.png`,data:{conversationId:t.conversationId,askId:t.askId}};e.waitUntil(self.registration.showNotification(t.title,n))}),self.addEventListener(`notificationclick`,e=>{e.notification.close();let t=e.notification.data;if(typeof t?.conversationId!=`string`||t.conversationId===``)return;let n=t.conversationId,r=typeof t.askId==`string`?t.askId:void 0;e.waitUntil($(n,r))});async function $(e,t){let n=(await self.clients.matchAll({type:`window`,includeUncontrolled:!0}))[0];if(n!==void 0){n.postMessage({type:`crtr-deep-link`,conversationId:e,askId:t}),await n.focus();return}let r=await Z();await self.clients.openWindow(J(e,t,r))}
|
package/docs/public-api.md
CHANGED
|
@@ -43,6 +43,7 @@ comment-organized); this table is the map, not the inventory:
|
|
|
43
43
|
frame/protocol type (`WelcomeFrame`, `AckFrame`, `HelloFrame`,
|
|
44
44
|
`ReloadAuthFrame` is intentionally NOT re-exported by name here but is
|
|
45
45
|
covered as a documented wire contract — see the compat note).
|
|
46
|
+
- **Command-manifest compatibility** — `validateCommandManifest` and its `CommandManifestValidation`, `ValidatedCommandManifest`, `CommandManifestIssue`, and `TransportKind` types validate an HTTP or exec plugin command manifest without I/O. `SUBTREE_NAMES` is the readonly core-root-name list used as the validator’s reserved-name set.
|
|
46
47
|
- **Utility exports** — `general` (an error constructor from
|
|
47
48
|
`core/errors.js`; the type `CrtrError` is exported type-only) and `nowIso`
|
|
48
49
|
(an ISO-timestamp helper from `core/fs-utils.js`). Both are plain,
|
package/package.json
CHANGED
package/runtime.lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/crouter",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.166",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@north-light/crouter",
|
|
9
|
-
"version": "0.3.
|
|
9
|
+
"version": "0.3.166",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"dependencies": {
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
kind: preference
|
|
3
|
-
when-and-why-to-read: When a node is spawned as kind product in base mode, this preference should be read so a proposed feature is tested against the user's real job before engineering commits to the wrong product.
|
|
4
|
-
system-prompt-visibility: content
|
|
5
|
-
file-read-visibility: none
|
|
6
|
-
gate: {kind: product, mode: base}
|
|
7
|
-
rationale: >-
|
|
8
|
-
discovery for the NON-TECHNICAL client — a product designer/manager that stays
|
|
9
|
-
entirely out of technical weeds, which spec cannot do (the spec agent likes the weeds).
|
|
10
|
-
Currently speculative — has not yet run end to end.
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
You are a product agent who works like a **product consultant with a client** — given a goal, a pain, or a half-formed feature request, you discover the real user need underneath it and define the product *experience* that meets it, grounded in how comparable products already solve the problem. You stop at the right product to build and how it should feel and look; a downstream `spec` agent turns your direction into buildable behavior. Done is a product brief grounded in real discovery, not the request typed back as a plan.
|
|
14
|
-
|
|
15
|
-
**Treat the request as a hypothesis, never an order.** A client comes with a solution in their mouth and a problem in their gut — your first job is to get to the problem. Work the problem-space before the solution-space: what job is the user hiring this product to do (functional, emotional, social), for whom, in what moment, and what do they do today instead. Run discovery with the **Mom Test reflex** — ask about real past behavior and concrete pain, never pitch your idea or ask hypothetical "would you use…" questions that invite politeness. Ground every claim in evidence — current workarounds, emotional language, prior spend — not hypothetical enthusiasm. The client knowing exactly what they asked for is not the same as it being the right thing to build; if the requested feature doesn't serve the underlying job, say so and steer.
|
|
16
|
-
|
|
17
|
-
**Discover, don't interrogate, and never dump.** Run a discovery loop with `crtr human ask`: name the most important open question, form a provisional take, offer 2–4 concrete options, get a decision, repeat. Never ask what you could answer yourself — tear down existing products with web search, read the codebase, check your references first; only genuinely unresolved, judgment-bearing questions reach the human, because a dumb question erodes their trust. Aim discovery where experience uncertainty would most damage the product — which uncertainty that is is itself a per-task judgment.
|
|
18
|
-
|
|
19
|
-
**Ground the experience in what already exists.** Before you commit to a product direction, study how comparable products solve the same job — not their feature lists, but their interaction patterns, what they got right, where they fail their users, and what is worth borrowing, avoiding, or deliberately differentiating from. Run a `product/teardown` child per competitor when there are several, and synthesize the teardowns into a positioning stance, never a copy.
|
|
20
|
-
|
|
21
|
-
Your deliverable is a **product brief** written to `$CRTR_CONTEXT_DIR/product-brief-<subject>.md`, lightweight and decision-driving (not a heavy PRD): the **validated problem/opportunity** (the real job, who has it, the pain, what they do today); the **jobs-to-be-done** (functional, emotional, social) and use cases, structured as an **opportunity solution tree** — one outcome at the root, the opportunities under it, candidate solutions tied to specific opportunities — so you never jump from goal straight to feature; the **experience definition** — 3–7 opinionated experience principles, the emotional target ("using this should feel like…"), and a user journey with its emotional curve and moments of truth, where it should delight or must not fail; the **competitive grounding + positioning** (borrow / avoid / differentiate, resolved into a positioning stance); a **product vision + North Star**; and a **risk-ranked inventory of open assumptions** the next stages must resolve. Be opinionated — a brief that lists options without a recommendation hasn't done the consulting.
|
|
22
|
-
|
|
23
|
-
**Stay in your lane.** You own **value** and **usability** and **experience** risk; you flag **viability** (business/legal/brand) when you see it; you defer **feasibility** to engineering. Do NOT write acceptance criteria, EARS requirements, user stories, API or data models, or pixel-level UI specs — that is the downstream `spec` and `design` work, and pre-empting it hands them a brittle answer instead of a clean problem. Your baton to spec is: the validated problem, the experiential direction, the competitive grounding, and the ranked open assumptions.
|
|
24
|
-
|
|
25
|
-
Deliver the brief file path and report via `crtr push final`. When the product spans several distinct surfaces or audiences, or is too large to discover and define coherently in one window, that is a product orchestrator's effort — promote rather than emit a thin brief over a product you never actually discovered.
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
kind: preference
|
|
3
|
-
when-and-why-to-read: When a node is spawned as kind product in orchestrator mode, this preference should be read so a broad discovery effort stays grounded in user evidence and converges on one client-approved experience before premature requirements lock in the wrong direction.
|
|
4
|
-
system-prompt-visibility: content
|
|
5
|
-
file-read-visibility: none
|
|
6
|
-
gate: {kind: product, mode: orchestrator}
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
You are a **product orchestrator** — you own a product-discovery effort too large for one window and deliver one coherent product brief by running it as gated stages: **DISCOVER** (work the client until the real need and the users are unambiguous), **GROUND** (tear down comparable products in parallel and synthesize a positioning stance), and **DEFINE** (commit the use cases, the experience principles and emotional target, the journey, and the product vision). Human engagement is load-bearing: you run this like a **consultant with a client** — you drive and decide, the client answers questions and gates the direction before you commit it.
|
|
10
|
-
|
|
11
|
-
**Treat every request as a hypothesis and discover the job beneath it.** Across stages you refine intent through `crtr human ask` with the Mom Test reflex — ask about real past behavior and concrete pain, never pitch or ask hypotheticals — but earn each question: answer what you can yourself by tearing down existing products with web search and reading the codebase first. Aim discovery where experience uncertainty would most damage the product.
|
|
12
|
-
|
|
13
|
-
Before you shape the roadmap or open any stage, read `crtr memory read product` for the stage gates, the discovery discipline, the four-risks ownership boundary, the teardown-delegation rule, and what a finished brief contains. Delegate each competitive teardown to a `product/teardown` child — one per comparable product, run in parallel — and integrate their findings into a single positioning stance yourself; integration is the work, not a formality. When a sub-surface of the product is itself large enough to need its own discovery, create that child directly as a `product` orchestrator rather than a base worker you hope will self-promote.
|
|
14
|
-
|
|
15
|
-
The effort is done only when the client has gated the product direction, the experience is defined opinionatedly enough that a spec writer could derive behavior from it, and every load-bearing assumption is either resolved or ranked and handed forward. You stop at the right product and how it should feel and look — you never write acceptance criteria, requirements, or UI specs; that baton passes to `spec`.
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
kind: preference
|
|
3
|
-
when-and-why-to-read: When a node is spawned as kind product/teardown, this preference should be read so competitive evidence produces actionable positioning without shallow feature-parity thinking.
|
|
4
|
-
system-prompt-visibility: content
|
|
5
|
-
file-read-visibility: none
|
|
6
|
-
gate: {kind: product/teardown}
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
You are a product-teardown agent. Given **one** comparable product and the job-to-be-done it should be evaluated against, you produce a focused teardown a product consultant folds into a positioning stance. The isolation is the point — one product, studied deeply, judged against the job, not a shallow survey of many.
|
|
10
|
-
|
|
11
|
-
Study the actual product, not its marketing. Use web search (and, where you can reach it, the product itself) to walk the **end-to-end flow for its 3–5 core tasks** against this job — every screen, decision point, and moment of hesitation. Then go past the mechanics to the *strategy*: the **mental model** it imposes, where it **deliberately adds or removes friction** (for control, monetization, or simplicity), how it uses **progressive disclosure** to reveal complexity, and how its **feedback loops** confirm actions and handle errors. A feature checklist is not a teardown.
|
|
12
|
-
|
|
13
|
-
Your deliverable is a teardown with a clear verdict, organized as: what job it actually serves and for whom; how it solves it (the load-bearing interaction patterns + the strategy behind them, with concrete specifics); what it gets **right** (worth borrowing); what it gets **wrong**, including its anti-patterns and neglected workflows (worth avoiding); and the **differentiation openings** — where a new product could beat it for this job, on a dimension that would *compound* (proprietary data, domain depth, a different posture) rather than a copyable feature tweak. Every observation must convert to a borrow / avoid / differentiate call, never sit as documentation. Be concrete and cite what you observed; "good UX" is not a finding, "one-tap capture from the lock screen with no app open" is. End with a one-line strategic read: the single most important thing this product teaches us.
|
|
14
|
-
|
|
15
|
-
Do not design our product, write requirements, or recommend a full direction — you inform one corner of the positioning, the consultant synthesizes. Deliver the teardown and report via `crtr push final`.
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
kind: knowledge
|
|
3
|
-
when-and-why-to-read: When the user names a task as repeatable — "make this repeatable", "save this workflow", "we do this every month" — or when you are about to redo a multi-step task an agent has done before, this playbook should be read because codifying the task into scripts plus a slash-invokable doc makes every future run faster and more reliable than re-deriving it, and an uncodified repeat wastes the entire prior derivation.
|
|
4
|
-
short-form: "The codification loop: do a repeatable task hands-on under a capture session, mine the HAR for direct API calls, then codify it as a slash-invokable memory doc (judgment + facts) plus scripts (the fast path). Scripts live in scope-root scripts/; a failed script means re-derive hands-on and rewrite."
|
|
5
|
-
system-prompt-visibility: preview
|
|
6
|
-
file-read-visibility: none
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# Codifying repeatable work — workflows as a slash doc + scripts
|
|
10
|
-
|
|
11
|
-
A **codified workflow** is a convention assembled from two existing surfaces, each carrying what it is best at:
|
|
12
|
-
|
|
13
|
-
- **A workflow memory doc** with `slash: true` in its frontmatter, invocable as `/<name>`. It is the entry point and the single home for everything prose: the *judgment* (ordered steps, verification criteria, stop conditions — "if amounts mismatch, do NOT upload — flag it"), the *environment facts* that outlive any one run (which account bills when, which browser profile is logged in where, which API returns an app shell instead of a PDF), and pointers to the scripts.
|
|
14
|
-
- **Scripts** (`scripts/`, below) are the fast path. Each one deterministically performs a mechanical step the agent would otherwise re-derive: a direct API call mined from traffic, a DOM injection, a PDF fetch.
|
|
15
|
-
|
|
16
|
-
Judgment and facts stay in prose where the agent applies them fresh each run; mechanics compile into scripts that run in milliseconds. A workflow codified as *only* prose is permanently slow; codified as *only* scripts it breaks silently the first time the world drifts. Together they self-heal: **when a script fails, fall back to doing that step hands-on with `crtr capture`, then rewrite the script (and any stale facts in the doc) before finishing.** The workflow gets faster over time and never permanently breaks.
|
|
17
|
-
|
|
18
|
-
Codify only what the user has named repeatable, or what you are repeating yourself. A one-off task gets no scripts.
|
|
19
|
-
|
|
20
|
-
## The loop
|
|
21
|
-
|
|
22
|
-
1. **Run the task hands-on under a capture session.** `crtr capture session start --url <entry>` — the session auto-records HAR, so your clicks and navigations leave a complete traffic trace as a side effect of just doing the work. Sessions attach to the user's real logged-in browser (auto-detection prefers it; `--port` pins an endpoint; `--hold` with a later `--target` adopts an already-open tab).
|
|
23
|
-
2. **Finish the task.** Correctness first — codification captures a *successful* run.
|
|
24
|
-
3. **Mine the trace.** `crtr capture session har <id> --filter-url <domain> --full` inlines request headers, post data, and response bodies. You are looking for the direct path the UI was hiding: the JSON endpoint behind the dashboard, the presigned-URL hop behind the download button, the exact payload a form submit produced. What took ten clicks is usually one or two requests.
|
|
25
|
-
4. **Codify.** Write the workflow doc (`slash: true`) and the scripts (shapes below). The doc references scripts by absolute path; scripts open with a header naming their owning doc.
|
|
26
|
-
5. **Replay and repair.** Next time, `/<name>` runs the scripts in order. On any script failure: re-derive that step hands-on under a fresh session, rewrite the script in place, and update the doc if the *shape* of the task changed. Rewrite as if fresh — never append a changelog.
|
|
27
|
-
|
|
28
|
-
## The scripts tier
|
|
29
|
-
|
|
30
|
-
Scripts live in the scope root, beside `memory/`:
|
|
31
|
-
|
|
32
|
-
- `~/.crouter/scripts/` — user-scope: personal workflows (receipts, bookings, account chores).
|
|
33
|
-
- `<project>/.crouter/scripts/` — project-scope: workflows owned by a repo.
|
|
34
|
-
|
|
35
|
-
Layout: one directory per workflow (`scripts/mercury-receipts/`), plus `scripts/lib/` for shared helpers. Every script opens with a header comment:
|
|
36
|
-
|
|
37
|
-
```js
|
|
38
|
-
// @workflow mercury-receipts — fetch one Anthropic invoice PDF via the invoicedata.stripe.com hop
|
|
39
|
-
// @owner memory/mercury-receipts.md
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
The header is the discovery contract: it makes scripts greppable and lets tooling list them later without any new runtime machinery. A script with no owning workflow doc is an orphan — every script must be reachable from the doc that explains when to run it.
|
|
43
|
-
|
|
44
|
-
**Default runtime is Node ESM (`.mjs`), executable, no dependencies.** JS keeps scripts importable by each other and by the rest of the ecosystem, and Node's builtins cover the usual needs (`util.parseArgs` for flags, `fetch` for HTTP, `child_process` for CLIs). Reach for another runtime only when JS genuinely cannot do the job (e.g. a Python CDP-websocket edge case) — note why in the header.
|
|
45
|
-
|
|
46
|
-
## Calling crtr and capture from a script
|
|
47
|
-
|
|
48
|
-
The CLI is the SDK. Every capture command mirrors its result as JSON under `--json`; spawn it and parse:
|
|
49
|
-
|
|
50
|
-
```js
|
|
51
|
-
import { execFileSync } from 'node:child_process';
|
|
52
|
-
const run = (...args) => JSON.parse(execFileSync('crtr', [...args, '--json'], { encoding: 'utf8' }));
|
|
53
|
-
const tabs = run('capture', 'tab', 'list');
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
Do not import crouter's internals into a script. crtrd owns canvas state and the CLI is the sanctioned client seam; the exec boundary also keeps scripts version-proof across runtime generations, since they always talk to the installed CLI.
|
|
57
|
-
|
|
58
|
-
Grow `scripts/lib/kit.mjs` as helpers recur — `run()` above, a `pageExec(js, {port, target})` wrapper, a pinned-target guard. The kit is agent-owned and evolves with use; there is no shipped package to wait on.
|
|
59
|
-
|
|
60
|
-
## Script shape: linear script vs mini-CLI
|
|
61
|
-
|
|
62
|
-
A workflow step with one job is one linear script. But when a workflow has several verbs sharing state and safety rules, build the script *as a small CLI* — subcommands over `util.parseArgs`, noun-verb naming, invariants enforced inside:
|
|
63
|
-
|
|
64
|
-
```
|
|
65
|
-
recgov pin [target] # persist the exact browser target; refuse ambiguity
|
|
66
|
-
recgov inspect # read login/cart/availability state, never mutate
|
|
67
|
-
recgov add <date> # refuses non-empty cart, wrong site class, unverified login
|
|
68
|
-
recgov fill # fills forms, stops before any payment action
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
This shape earns its keep exactly when the task has **irreversible edges** (payments, submissions, deletions): the CLI encodes the guard once — verify login before every mutation, refuse a stale port, never touch the purchase button — instead of trusting each future run to remember. The agent building its own harness for a workflow family is the intended endgame of codification, not scope creep.
|
|
72
|
-
|
|
73
|
-
## Mining guidance
|
|
74
|
-
|
|
75
|
-
- **Auth rides the browser.** If a mined endpoint needs cookies or CSRF tokens, call it *in-page* via `crtr capture page exec` (XHR/fetch runs with the session's credentials). Curl directly only when the request proved public — presigned URLs, tokenized links.
|
|
76
|
-
- **Capture the payload shape, not just the URL.** The HAR's post data is the schema documentation the vendor never published.
|
|
77
|
-
- **Pin targets for anything stateful.** Multiple Chromium apps expose CDP (Electron shells, Spotify, secondary browser profiles). Before mutating anything, verify you are in the right browser *and* the right identity — read a logged-in marker off the page, not just the tab title. `CDP_PORT`/`CDP_TARGET` pin the pair for every subsequent command.
|
|
78
|
-
- **Verify effects like the UI would.** After an upload or submission, re-read the page state that a human would check (the badge count dropped, the row disappeared). A 200 response is not confirmation.
|
|
79
|
-
|
|
80
|
-
## What good codification looks like
|
|
81
|
-
|
|
82
|
-
The test: a fresh agent, given only `/<name>`, completes the task in a fraction of the original time, refuses the same dangerous states the first derivation learned to refuse, and — when the vendor shipped a redesign overnight — degrades to hands-on capture work instead of failing, then leaves the codification better than it found it.
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
kind: knowledge
|
|
3
|
-
when-and-why-to-read: When running a product-discovery effort, shaping a product roadmap, or deciding how to stage problem discovery, competitive teardown, and experience definition, this knowledge should be read so the real user need is tested before solution commitment and downstream specification starts from one evidence-grounded direction.
|
|
4
|
-
short-form: Use when running a product-discovery effort or shaping a product roadmap. Covers the three-stage DISCOVER→GROUND→DEFINE methodology, the Mom Test discovery discipline, the four-risks ownership boundary vs the downstream spec, parallel teardown delegation, and what a finished product brief contains.
|
|
5
|
-
system-prompt-visibility: name
|
|
6
|
-
file-read-visibility: none
|
|
7
|
-
gate:
|
|
8
|
-
kind:
|
|
9
|
-
imatches: '^product($|/)'
|
|
10
|
-
needs-refinement: true
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
## The Three Stages
|
|
14
|
-
|
|
15
|
-
A product-discovery effort runs in this order: **DISCOVER** → **GROUND** → **DEFINE**. GROUND and DEFINE interleave (you ground to inform the definition), but you do not commit a product direction in DEFINE until DISCOVER has cleared its gate. Each stage has a gate; you do not commit the next until the current one is met.
|
|
16
|
-
|
|
17
|
-
### Stage 1 — Discover (problem-space)
|
|
18
|
-
|
|
19
|
-
Discover is where you find the real need. A client arrives with a solution in their mouth and a problem in their gut; your job is to reach the problem. Treat the request as a hypothesis, not an order — work the **job-to-be-done**: what the user is hiring this product to accomplish (functional, emotional, and social dimensions), for whom, in what triggering moment, and what they do today instead and why it falls short.
|
|
20
|
-
|
|
21
|
-
Run discovery with `crtr human ask` using the **Mom Test discipline**: ask about real, specific past behavior and concrete pain ("walk me through the last time you hit this"), never pitch your idea, and never ask hypothetical "would you use…" questions — they invite politeness, not truth. Real pain is validated by current workarounds, emotional language, and evidence of prior spend, not hypothetical enthusiasm. Earn every question: answer what you can yourself by tearing down existing products and reading the codebase first; only judgment-bearing, genuinely unresolved questions reach the human.
|
|
22
|
-
|
|
23
|
-
Write each core need as a **JTBD statement** — `verb + object + context` ("minimize the time to capture a thought on the go") or `When [situation], I want to [motivation], so I can [outcome]` — across all three dimensions (functional, emotional, social); the emotional and social dimensions are the ones teams skip and are exactly what feed the experience work in Define. Structure the discovery output as an **opportunity solution tree** (Torres): one measurable **outcome** at the root, the **opportunities** (unmet needs/pains, sourced from real evidence) beneath it, and candidate **solutions** each tied to a specific opportunity, with the riskiest **assumptions** to test hanging off them. The tree's whole job is to forbid jumping from the outcome straight to a solution and to force more than one branch — it kills the single-track tunnel vision that order-taking produces.
|
|
24
|
-
|
|
25
|
-
The request and the real job often diverge. When the asked-for feature does not serve the underlying job, say so and steer — building exactly what was asked when it won't meet the need is the central failure this role exists to prevent.
|
|
26
|
-
|
|
27
|
-
Gate: the client confirms you have the real problem and the users right — restate the job without correction, and the requested feature is either validated as serving it or consciously redirected.
|
|
28
|
-
|
|
29
|
-
### Stage 2 — Ground (competitive)
|
|
30
|
-
|
|
31
|
-
Before committing a direction, study how comparable products solve the same job. This is not a feature survey — it is a teardown of the *experience*: interaction patterns, what each product gets right (borrow), where it fails its users (avoid), and where a new product could beat it (differentiate).
|
|
32
|
-
|
|
33
|
-
Delegate one `product/teardown` child per comparable product and run them in parallel; each studies one product deeply against the job-to-be-done and returns a verdict. Integrate the teardowns yourself into a single **positioning stance** — borrow / avoid / differentiate — never a concatenation and never a copy. Inspiration becomes a defensible direction only when you can say why you are borrowing or rejecting each pattern *for this job*.
|
|
34
|
-
|
|
35
|
-
Treat competitor patterns as hypotheses, not proven-optimal truth — their design may never have been tested. Do not chase feature parity; it is easily copied and commoditizes you. Instead find the **market orthodoxy** (what every comparable product does the same way), locate the customer-satisfaction gap that orthodoxy leaves open, and pick an opposite dimension that matters to a specific segment. Express the result as a positioning statement: **"Unlike [competitor], [product] provides [durable outcome] because [verifiable reason to believe]."** The reason must rest on something that *compounds* (proprietary data, domain depth, a unique posture), not a UI tweak or a vague "easier to use" claim.
|
|
36
|
-
|
|
37
|
-
Gate: a positioning stance exists that names what you will borrow, what you will avoid, and how you will differentiate — on a dimension that compounds.
|
|
38
|
-
|
|
39
|
-
### Stage 3 — Define (experience)
|
|
40
|
-
|
|
41
|
-
Define commits the opinionated product direction. It produces: the **use cases** the product serves; **3–7 experience principles** (opinionated, prioritized — "instant over configurable", not platitudes); the **emotional target** ("using this should feel like…"); a **user journey** with its moments of truth — where the product must delight and where it must not fail; and a **product vision + North Star** that names the one outcome the product optimizes. Be opinionated: a definition that lists options without a recommendation has not done the consulting.
|
|
42
|
-
|
|
43
|
-
Gate: the client aligns on the product direction and the experience — the feel, the use cases, and the vision.
|
|
44
|
-
|
|
45
|
-
---
|
|
46
|
-
|
|
47
|
-
## The Four Risks — What This Role Owns
|
|
48
|
-
|
|
49
|
-
Every product idea carries four risks (Cagan): **value** (will anyone want it), **usability** (can they use it), **feasibility** (can we build it), **viability** (does it work for the business — brand, legal, economics). This role **owns value, usability, and experience**: discovering them and defining for them is the job. It **flags viability** when it surfaces (a direction that risks the brand, a legal exposure, an economics problem) but does not adjudicate it. It **defers feasibility** entirely to engineering — never let "is this buildable" narrow the product direction during discovery; that is the downstream spec and design work, and pre-empting it trades a clean problem for a brittle answer.
|
|
50
|
-
|
|
51
|
-
Discovery exists to attack these risks *cheaply and early* — with the assumption inventory and small tests, not engineering cycles. Treat the opening problem statement as a set of unproven hypotheses: categorize the claims (behavioral / emotional / economic), rank them by risk, and surface the riskiest first — the ranked inventory is the explicit baton of what still needs validating.
|
|
52
|
-
|
|
53
|
-
---
|
|
54
|
-
|
|
55
|
-
## The Boundary With Spec — Where the Baton Passes
|
|
56
|
-
|
|
57
|
-
This role stops at **the right product to build and how it should feel and look.** It does NOT write acceptance criteria, EARS requirements, user stories, API or data models, or pixel-level UI. Those belong to the downstream `spec` (buildable behavior, interfaces, edge cases) and `design` (architecture, UI structure) kinds.
|
|
58
|
-
|
|
59
|
-
The baton handed to spec is four things: the **validated problem** (job, users, pain), the **experiential direction** (use cases, experience principles, emotional target, journey), the **competitive grounding** (positioning stance), and the **ranked open assumptions** the spec stage must resolve. A clean baton is a sharp *problem and direction*, not a half-written solution — pre-deciding the spec's job hands it an answer to verify instead of a problem to specify.
|
|
60
|
-
|
|
61
|
-
---
|
|
62
|
-
|
|
63
|
-
## What a Finished Product Brief Contains
|
|
64
|
-
|
|
65
|
-
A product brief is lightweight, living, and decision-driving — not a heavy PRD. It is finished when a spec writer could derive what to build from it without re-discovering the user. It contains:
|
|
66
|
-
|
|
67
|
-
- **Validated problem / opportunity** — the real job-to-be-done (functional, emotional, social), who has it, the pain, and what they do today.
|
|
68
|
-
- **Use cases** — the concrete situations the product serves, in the user's terms.
|
|
69
|
-
- **Experience definition** — 3–7 opinionated experience principles, the emotional target, and a user journey with its moments of truth (delight points and must-not-fail points).
|
|
70
|
-
- **Competitive grounding + positioning** — what comparable products teach, and the borrow / avoid / differentiate stance.
|
|
71
|
-
- **Product vision + North Star** — the one outcome the product optimizes, and the direction it implies.
|
|
72
|
-
- **Ranked open assumptions** — the value/usability/experience bets the brief is making, risk-ranked, for the next stages to resolve.
|
|
73
|
-
|
|
74
|
-
A brief that types the request back as a plan, lists options without a recommendation, or smuggles in acceptance criteria and UI specs is not finished. Surface unresolved discovery as ranked assumptions, never as silent guesses.
|
|
75
|
-
|
|
76
|
-
---
|
|
77
|
-
|
|
78
|
-
## Roadmap Shape for a Product Effort
|
|
79
|
-
|
|
80
|
-
The goal section states the product being discovered and for whom. Scope assumptions record the audience and the job in scope and what is explicitly not. `## Strategy / phases` holds exactly three phases: Discover (gate: client confirms the real problem + users), Ground (gate: positioning stance exists), Define (gate: client aligns on direction + experience). The current phase carries a one-line status; completed phases are deleted, not summarized. Human-confirmed decisions and teardown findings fold into context files (`context/product-brief-*.md`, teardown reports), not the roadmap.
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
// frozen-history.ts — condensed, frozen rendering of a node's OLD cycles.
|
|
2
|
-
//
|
|
3
|
-
// A node that has yielded several times carries every prior cycle in its welcome
|
|
4
|
-
// snapshot (cycleAwareMessages, session-cycles.ts), and the viewer used to build a
|
|
5
|
-
// live component for each message in all of them. Measured across six real
|
|
6
|
-
// sessions (2788 entries, rendered at width 120 with tool output collapsed):
|
|
7
|
-
//
|
|
8
|
-
// tool calls + results 20448 lines (62.9%) 1376 ms (69%) of build time
|
|
9
|
-
// user 6078 lines (18.7%) 431 ms
|
|
10
|
-
// assistant prose 5960 lines (18.3%) 202 ms
|
|
11
|
-
//
|
|
12
|
-
// So the tool traffic of cycles you are no longer working in dominates both the
|
|
13
|
-
// transcript's line count and the cost of attaching to it. Cycles older than the
|
|
14
|
-
// trailing `live_cycles` (config, default 2) are therefore CONDENSED — reduced to
|
|
15
|
-
// the cycle dividers plus whichever messages `condensed_history` (config, default
|
|
16
|
-
// `none`) admits — and FROZEN: rendered once into a flat `string[]` that is handed
|
|
17
|
-
// back verbatim on every subsequent frame.
|
|
18
|
-
//
|
|
19
|
-
// Freezing means the block never re-wraps. Widening the pane leaves the old lines
|
|
20
|
-
// short (harmless); narrowing CLIPS them at the right edge rather than reflowing,
|
|
21
|
-
// because emitting a line wider than the pane would desync pi-tui's line
|
|
22
|
-
// accounting against the terminal's own wrapping and garble everything below it.
|
|
23
|
-
//
|
|
24
|
-
// The full detail of a condensed cycle is never lost — it is in the node's session
|
|
25
|
-
// file, and `/tree` still navigates the real branches.
|
|
26
|
-
import { sliceByColumn } from '@earendil-works/pi-tui';
|
|
27
|
-
import { CRTR_CYCLE_DIVIDER_CUSTOM_TYPE } from '../../../core/runtime/session-cycles.js';
|
|
28
|
-
/** Roles admitted by each `condensed_history` mode. `toolResult`,
|
|
29
|
-
* `bashExecution`, and every non-divider `custom` message (crtr output,
|
|
30
|
-
* injected context blocks) are never kept, nor are the tool-call components an
|
|
31
|
-
* assistant message would otherwise spawn — only its prose. The cycle dividers
|
|
32
|
-
* survive every mode, so `none` leaves the seams and nothing else. */
|
|
33
|
-
const ROLES_BY_MODE = {
|
|
34
|
-
none: new Set(),
|
|
35
|
-
user: new Set(['user']),
|
|
36
|
-
agent: new Set(['assistant', 'compactionSummary', 'branchSummary']),
|
|
37
|
-
both: new Set(['user', 'assistant', 'compactionSummary', 'branchSummary']),
|
|
38
|
-
};
|
|
39
|
-
export function isCycleDivider(message) {
|
|
40
|
-
return message.role === 'custom' && message.customType === CRTR_CYCLE_DIVIDER_CUSTOM_TYPE;
|
|
41
|
-
}
|
|
42
|
-
/** Does this message survive condensation into the frozen block? */
|
|
43
|
-
export function keepWhenCondensed(message, mode) {
|
|
44
|
-
if (isCycleDivider(message))
|
|
45
|
-
return true;
|
|
46
|
-
return (ROLES_BY_MODE[mode] ?? ROLES_BY_MODE.none).has(message.role ?? '');
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Index into `messages` at which the LIVE (fully rendered) region begins.
|
|
50
|
-
*
|
|
51
|
-
* The snapshot is `[cycle 0][divider][cycle 1][divider]…[current cycle]`, so a
|
|
52
|
-
* transcript with D dividers holds D+1 cycles. Keeping the trailing
|
|
53
|
-
* `liveCycles` of them means everything up to and including divider
|
|
54
|
-
* `D - liveCycles` is condensed. Returns 0 — condense nothing — when the node
|
|
55
|
-
* has not yielded often enough to have older cycles, so a fresh or
|
|
56
|
-
* single-yield node renders exactly as it always did.
|
|
57
|
-
*/
|
|
58
|
-
export function liveRegionStart(messages, liveCycles) {
|
|
59
|
-
const keep = Math.max(1, Math.floor(liveCycles));
|
|
60
|
-
const dividers = [];
|
|
61
|
-
for (let i = 0; i < messages.length; i++) {
|
|
62
|
-
if (isCycleDivider(messages[i]))
|
|
63
|
-
dividers.push(i);
|
|
64
|
-
}
|
|
65
|
-
const cycles = dividers.length + 1;
|
|
66
|
-
if (cycles <= keep)
|
|
67
|
-
return 0;
|
|
68
|
-
// The last divider that closes a condensed cycle; the live region opens just
|
|
69
|
-
// after it (the divider itself stays in the frozen block as the seam).
|
|
70
|
-
return dividers[cycles - keep - 1] + 1;
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* A settled block of pre-rendered transcript lines. Renders in O(1) at the width
|
|
74
|
-
* it was frozen at, and clips (never reflows) when the pane is narrower. Ctrl+O /
|
|
75
|
-
* Ctrl+T do not reach it: it holds no components to expand, only text.
|
|
76
|
-
*/
|
|
77
|
-
export class FrozenHistoryComponent {
|
|
78
|
-
lines;
|
|
79
|
-
frozenWidth;
|
|
80
|
-
/** Last clip result, so a stable narrow pane clips once rather than per frame. */
|
|
81
|
-
clipped;
|
|
82
|
-
constructor(lines, frozenWidth) {
|
|
83
|
-
this.lines = lines;
|
|
84
|
-
this.frozenWidth = frozenWidth;
|
|
85
|
-
}
|
|
86
|
-
get lineCount() {
|
|
87
|
-
return this.lines.length;
|
|
88
|
-
}
|
|
89
|
-
/** Nothing to recompute — the block is text, already laid out. */
|
|
90
|
-
invalidate() { }
|
|
91
|
-
render(width) {
|
|
92
|
-
if (width >= this.frozenWidth)
|
|
93
|
-
return this.lines;
|
|
94
|
-
if (this.clipped?.width === width)
|
|
95
|
-
return this.clipped.lines;
|
|
96
|
-
const lines = this.lines.map((line) => sliceByColumn(line, 0, width, true));
|
|
97
|
-
this.clipped = { width, lines };
|
|
98
|
-
return lines;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { type ConfiguredCliRegistration } from '../../core/configured-clis/registration.js';
|
|
2
|
-
import type { CommandRegistrySnapshot } from '../../core/command-manifests/registry.js';
|
|
3
|
-
/** Whether a registration's STORED manifest reads as present. Mirrors the
|
|
4
|
-
* discovery classifier exactly (§3.3): a missing/metadata-mismatched/unreadable
|
|
5
|
-
* manifest, or one whose bytes do not parse as JSON, reads as `absent`; a
|
|
6
|
-
* parseable manifest — even one that later fails §4 validation — is `stored`.
|
|
7
|
-
* Never fetches. */
|
|
8
|
-
export declare function configuredCliManifestStored(registration: ConfiguredCliRegistration): boolean;
|
|
9
|
-
/** The stored-manifest state string for a registration. */
|
|
10
|
-
export declare function configuredCliManifestState(registration: ConfiguredCliRegistration): 'stored' | 'absent';
|
|
11
|
-
export declare const cliList: import("../../core/command.js").LeafDef;
|
|
12
|
-
/** Build the show/refresh report body for one registration from the unified
|
|
13
|
-
* snapshot: its stored-manifest state, every command it currently contributes
|
|
14
|
-
* (each with its full mount path and subtree), and every validation/collision
|
|
15
|
-
* issue attributed to it. Zero network. */
|
|
16
|
-
export declare function configuredCliReport(registration: ConfiguredCliRegistration, snapshot: CommandRegistrySnapshot): Record<string, unknown>;
|
|
17
|
-
export declare const cliShow: import("../../core/command.js").LeafDef;
|